DISCLAIMER: I do not want that code to be in wrong hands. Please respect my decision to not fully show all of its content. Thank you very much!
Getting the raw code
Okay, since I am working in a webhosting environment, I have to deal with a hacked wordpress instance every now and then. It was always fascinating looking at the code of the malware and just… don’t understand anything. This file was loaded via the PHP function “include” in a hacked index.php in a WordPress directory. The files extension was “.ico”, so that the inexperienced WordPress user could possibly think: “Hey, this just loads a favicon” or some other icon.
It was time to take a further look at this monster of decoding and obfuscation. Take a ride with me on my first ever malware analysis.
Stage0: Using unPHP
Well, this obviously looks like PHP, but what does this script exactly do? Looks like it “dies” when specific $_GET parameters are being set (1).
It also has a lot of “goto”s to blur the flow of the script (2) In PHP, the command “goto” lets you continue the code-execution at another line, like “jump to line 123” for example.
The variable $SGuBMYFP6885 stores some weird hex string (3). Hard to find any more clues, right? In my approach, I felt like I really needed some formatting. I enjoy visiting https://www.unphp.net/ for exact this purpose. This user friendly tool gave me a well structured code and even decoded/de-obfuscated some stuff for me!
Stage1: More formatting and structure
Thanks to unPHP, I see a lot more information. We still see the “goto” commands (1), a function “mp8Gs” (2) and much more. UnPHP decoded some of the hex strings for us, so we can see, that the parameters “checkword” and “checked” stop the further execution of this script(3).
Stage2: Sorting the “goto”s, hiding the big variable
Okay, this is the code we get after reconstructing the flow of the script. I cleared all “goto”s since we now have the correct structure. It starts with the two checks we discovered before (1).
Then we have a function called “mp8Gs”, but for now I have no idea what it does (2).
After that we declare some variables ($hffQgGYq9480, $SGuBMYFP6885, $sbtUuUuc5986, $NgTSNyye5958) where “$SGuBMYFP6885” has the long hex(?)/char(?)-code seen in the pictures before. For the sake of clarity, I just edited this line with a comment (3).
Alright, next we have two foreach-loops filling the two variables ($sbtUuUuc5986 & $NgTSNyye5958) we declared before. In addition to that, $NgTSNyye5958 seems to be a call for a command now as it is assigned to a new variable $D (4) I guess, it reverses the string given as parameter in the command call, since the string “n” . ” . “o” . ” . “i” . “t” . “c” . “n” . “u” . ” . “f” . ” . “_” . ” . “e” . ” . ” . ” . “t” . ” . ” . ” . “a” . “e” . ” . ” . ” . “r” . ” . “c” . ” . ” . ” reverses to “create function”, referring to the PHP command: “create_function — Create an anonymous (lambda-style) function” https://www.php.net/manual/en/function.create-function.php.
Last but not least the variable $d is declared and executed. It seems to be a function, too (5). Hey, look! We found our function from (2) again.
Stage3: De-Obfuscating the variables and functions
So what’s next on the table? The variables seem to be set by the foreach-loops. Who’s gonna stop me from just executing them? I copied the code from the malware script and put it into a test file, where I echo the values of the variables. This is what I got:
(I am aware of the fact, that you should ABSOLUTELY NEVER execute a script, not knowing what it does, as “root”! I tested it before in a sandbox environment!)
Well, now we see, that the variables only contain some PHP function names (base64_decode, strrev & create_function). Attackers obfuscate these functions, because there are lots of security tools detecting the usage of those functions as a hint for unwanted actions.
After that, we can edit our script to make things more clear and directly replace the occurrences of the variables with the function names. The new code looks like this:
Stage4: De-Obfuscating the function “mp8Gs”
We are almost done. The only things left are the function “mp8Gs” and the execution of the functions stored in variable “$d”. Let’s start by trying to understand what the function “mp8Gs” does:
Let’s give the run variables and parameters relatable names, trying to understand the whole point of this function. This looks really weird.
The function contains two for-loops, running through all bits of the given parameters (green), comparing the bits at the given index using the XOR-operator (^) in PHP (blue). Okay, I got it. This runs through all bits of the big string we hid in stage 2 and the string (second parameter) given in the call of the function. It writes the result of the XOR-comparison (“^ = bits, that are set in $a or $b but not both, are set.”) into the $result-variable.
Stage5: Okay, let’s just run this!
Since we know, the big string is double base64 and XOR encoded, let’s just use the built-in function to decode the string. Once again I copied the parts of the malware code into an own test file, seen in the pictures above. In the next step, I just run this decryption and hope, we get a satisfying result! I cannot wait to see this nasty thing!
When executing the test script, I piped the output generated by the “echo”-command directly into a new file. So let me check if it worked as expected:
Wow! That looks like the treasure we hunted for! This is just the beginning of the script, but it has some interesting information:
I added the “<?php” at the start to make this one executable (for later), this was not in the code originally (green).
There is a check for the HTTP_USER_AGENT, which tells common web crawlers “404 Not found”, so this “thing” should not be indexed.
This script deactivates error-logging to stay hidden in the logs (red). It also sets some PHP ini values basically to infinite runtime.
Furthermore there is this authentication check at the bottom of this screenshot. You kinda need a password, which md5-hash value is seen in line 5, otherwise you get that login form seen in line 33 (“wsoLogin()”). Keep that in mind for later!
Now it starts getting interesting! These aliases-arrays for windows and UNIX servers just give us a quick overview, what this attack tool kit has to offer. It can list directories and users, find sensitive files, show open ports, show open processes / running services and much more. All “features” in this snippet are just a part of a lot more stuff to discover. I am really hyped right now! So, let’s leave all the boring script stuff behind and just set up a PHP server on localhost and start it!
Bonus: Run this script on localhost
Ehm, so… I need a password, remember? At the beginning of the script we had this md5 hash stored in the variable “$auth_pass” : 9aa9b6d702d54e3b55d7f2331b9c6ac7 . But it is hashed, so it won’t work copying it into the password field. Since we got the source code, this should be no problem for us. I just need to remove the hash function (md5) from the authentication part of the script:
So just reload the login form, paste the value from $auth_pass and voilà:
This looks like a nice file manager, but there are more things to discover, like the “Sec Info”-tab:
Lots of useful information for an attacker! In addition to the file manager (Files), which let’s you up- & download files and this security information tab (Sec Info), this toolkit also includes a shell (Console), you can try to connect to the local database (Sql), you can execute some PHP code if you want (Php). But there’s more to come! An almost full script for encoding, decoding, hashing strings and much more (String tools), a brute force helper (Bruteforce) and some network stuff (Network). Oh, and you can logout! So you can stay safe! It also has an self remove function (Self remove), but yeah, why would you remove it?
I hope you enjoyed my first PHP WordPress Malware de-obfuscation, maybe it is helpful for some of you. Stay tuned for more content!