In October 2023 neonprimetime user reported on X (I hate this name) a possible new Redline stealer variant masquerading as a PDF converter named PdfConverters.exe (74b6039660be3eda726a4eee209679ba). This sample presents pretty interesting and unusual installation routine so I decided to take a closer look at it.
WebView2 application dropper
WebView2 allows you to embed web technologies (HTML, CSS, and JavaScript) in your native apps. It has been already proved this vector could be used in malicious purposes, however it is not popular among attackers.
The sample is dropping such application in %TEMP%\.net\PdfConverters directory. It also creates another folder in %TEMP%\PdfConverters.WebView2 which is used as a user data directory by the app. Then it loads the application through msedgewebview2.exe
As already described by Noch Lab on his blog post, the main code of the application is written in C# and resides in app.dll (2e92db69ebdab1e5250985fc08ca87df) file. However, in my case dnSpy properly parsed the methods from the sample. Once executed, it initializes the WebView2 window with Visible flag set to false to avoid displaying anything to the user. Then it adds api class to the script running in the WebView2 and navigates to hXXps://www.pdfconvertercompare[.]com/main.
InitializeAsync() function |
The URL was responding (it's not at the time of writing this article) with a HTML code with embedded <script src = "/main.js"></script> tag which was leading to downloading and executing JavaScript code by the WebView2 application.
main.js content |
The neonprimetime's tweet (should I still call it a tweet or maybe xeet?) and blog post by Security Magic mentioned it leads to downloading PDFunk-Setup.exe binary but, in my case, the sample just sent 5 POST requests with some base64 encoded and encrypted data to the pdfconvertercompare[.]com domain and terminated itself.
Closer look at the main.js
As you can see on the previous screenshot, the script is highly obfuscated. My first choice for deobfuscation is synchrony. It didn't disappoint me again and produced readable 5406 lines of spaghetti monster code. Key takeaways from the code:
- It has 7 hardcoded domains which can be used for the C2 communication
- pdfconvertercompare[.]com
- createmygif[.]com
- screen-records[.]com
- videownload[.]com
- pdfconverterz[.]com
- zipextractors[.]com
- econenectedithc[.]net
- It generates .NET code which can be executed by this JS script through the api class of the app.dll.
- ~3500 lines of the script are just implementation of multiple cryptography related algorithms (AES, SHA-256, SHA-224, SHA-512, SHA-384, RIPEMD160, MD5, SHA1, DES, 3DES, RC4, RC4Drop, Rabbit, RabbitLegacy, all padding schemes and modes for block ciphers)
- It defines 7 functions which are responsible for posting some data in JSON format to one of the C2 domains.
A function responsible for sending "log" type message
.NET code analysis
Main capabilities:
- It is checking if any of the processes listed below are running on the system. If yes, it terminates the whole infection chain.
Blacklisted processes |
- Reading, writing and copying files.
Write file function - Executing processes.
Start a process function - Setting mouse and keyboard event hooks
Set Windows Hooks function - Sending key strokes and clipboard manipulation
Clipboard manipulation - Modification of Edge and Chrome Preferences and Secure Preferences entries.
Edge Preferences modification.
All of the functions are being invoked by the JavaScript in some specific order which is quite easy to follow thanks to the log messages the script is supposed to send to the C2 server.
Example log messages |
Payload encryption routine
As I mentioned before, I was able to observe just 5 POST requests to the C2 domain and then the sample terminated itself. The only option to push the analysis further was to decrypt the data sent to the C2.
After putting together all the pieces it turned out the whole routine is quite simple:
- Take the JSON as a string and encrypt it with RC4 algorithm with a hardcoded key.
- Generate 20-30 random bytes and use them to XOR the RC4 encrypted data.
- Add length of the key and the XOR key to the XORed data.
- Base64 encode the data and send.
Payload decryption |
With that, I was able to write a python script to simulate behaviour of the sample and see if I can get some additional stuff from the C2 server. After a little bit of playing the server finally replied to me with some Base64 data!
Response from the server |
After decrypting I got something looking like a config.
searchers-three[.]com domain was not previously reported |
Unfortunately at this point I still didn't have the PDFunk-Setup.exe file. Looking at the JavaScript, there is one particular request type which is responsible for getting this file, so I started playing with it as well.
fe (fetch?) request type |
JSON fields description:
- wv - always true.
- t - type of request. To get the file it must be fe.
- jv - constant 4.5.
- iv - constant 1.0.
- sid - session id. Random 18 digits.
- rid - request id. Random 18 digits.
- is - value taken from the config received previously.
- did - value taken from the config received previously.
- ts - timestamp.
- d - debug flag? - false.
After sending a packet with the above payload to pdfconvertercompare[.]com I got the PDFunk-Setup.exe
PDFunk analysis
During the installation the file copies itself to %LocalAppData%\pdfunk-updater\installer.exe and drops the files to %LocalAppData%\Programs\PDFunk\. It also sets up a persistence by adding LNK file to the Startup folder pointing to %LocalAppData%\Programs\PDFunk\PDFunk.exe.
Finally the installer launches the main PDFunk.exe app which then spawns couple of child processes.
Some of them are executed with --app-path parameter pointing to %LocalAppData%\Programs\PDFunk\resources\app.asar file.
ASAR files are just Electron applications bundled into an archive format. The full application structure can be retrieved using npx (npx asar extract app.asar <destfolder>).
Our app looks like a fork of Electron PDF Viewer with additional obfuscated (of course) code inside main.js and index.js. Deobfuscating it reveals that the code is responsible for loading V8 bytecode as a cachedData into a Script object.
The bytecode is stored as a Base64 encoded string encrypted with RC4. Unfortunately I don't know how to statically analyze such bytecode so behavioral analysis is the only thing I could do at this point.
Every time the app is launched it sends a POST request to one of the domains:
- haitingshospical[.]com
- weiledstever[.]com
- reatmenttoget[.]com
- ndingcouncern[.]com
- andingswon[.]com
Fun fact is that, the payload is being encrypted exactly the same way as in the main.js file (even the same RC4 key lol). By decrypting the payload you can get something similar to this:
Without further static analysis of the Electron V8 bytecode I'm at the dead end.
Key takeaways for Blue Teams
There are couple of things you can search for in your environment to hunt for such threat:
- General
- msedgewebview2.exe created by a suspicious process,
- msedgewebview2.exe created with unusual --user-data-dir or --webview-exe-name parameters,
- Suspicious remote connections initiated by msedgewebview2.exe,
- Suspicious Electron (.asar) applications making remote connections,
- Processes other than Chrome or Edge modifying Secure Preferences.
- PdfConverters/PDFunk specific
- Search for any connections to the mentioned domains.
- User-Agent containing PDFunk keyword.
- Presence of %TEMP%\.net\PdfConverters and %LocalAppData%\Programs\PDFunk\ directories.
- Presence of PDFunk.lnk in the Startup folder.
Depending on the size of your environment filtering out all the noise might be tricky, but the hunting is about looking for anomalies (the famous needle in a haystack). Happy hunting!
Appendix
It seems that the attackers, to gain some credibility, created pdfunk[.]com where you can download the application. The main difference is that this variant does not contain the malicious V8 bytecode included.
Update 16 Nov 2023
Luke Acha posted new set of C2 servers PDFunk is communicating with.
Comments
Post a Comment