We continue to publish our analysis report of Stealc, an information stealer promoted by its supposed developer Plymouth on Russian-language underground forums and sold as malware as a service since January 9, 2023.
In this part we are analyse exfiltration system information and downloader logic of stealer.
Download Browsers Configurations:
inside sub_0x403D5F()
→ renamed to mw_Download_1()
, Stealc again will ask C2 to feed it with some configuration to be used in stealth behavior, it will do the same steps done before in the first connection but this time will ask for a different data, and if we look at the TCP stream.
but before that, if you remember the last decoded data in the first stream was like this
“aa36b6d1c34621ab9876080e89e62c526f27572fa74ad766587fc1e832822fbc85b96f8f”
This stream of hexa values will be used in all communication tunnels and acts like a reference for the victim ID obtained before, so C2 receives the Victim ID which was the calculated “C” drive serial number, and then does some equation on this calculated serial and then send the new ID in the first packet received by the victim which will be used repeatedly in all the connection.
If we manually decode the above stream will result in another configuration data related to the browser’s paths where Application User Data is saved
Google Chrome|\Google\Chrome\User Data |chrome|
Google Chrome Canary|\Google\Chrome SxS\User Data|chrome|
Chromium|\Chromium\User Data|chrome|
Amigo|\Amigo\User Data|chrome|
Torch|\Torch\User Data|chrome|
Vivaldi|\Vivaldi\User Data|chrome|
Comodo Dragon|\Comodo\Dragon\User Data|chrome|
EpicPrivacyBrowser|\Epic Privacy Browser\User Data|chrome|
CocCoc|\CocCoc\Browser\User Data|chrome|
Brave|\BraveSoftware\Brave-Browser\User Data|chrome|
Cent Browser|\CentBrowser\User Data|chrome|
7Star|\7Star\7Star\User Data|chrome|
Chedot Browser|\Chedot\User Data|chrome|
Microsoft Edge|\Microsoft\Edge\UserData|
chrome|360 Browser|\360Browser\Browser\User Data|chrome|
QQBrowser|\Tencent\QQBrowser\User Data|chrome|
CryptoTab|\CryptoTab Browser\User Data|chrome|
Opera Stable|\Opera Software|opera|
Opera GX Stable|\Opera Software|opera|
Mozilla Firefox|\Mozilla\Firefox\Profiles|firefox|
Pale Moon|\Moonchild Productions\Pale Moon\Profiles|firefox|
Opera Crypto Stable|\Opera Software|opera|
Thunderbird|\Thunderbird\Profiles|firefox|
Just like you see this config will be used to steal the browser’s databases and it will try for all Chromium-based browsers that share the same structure of databases and also will explore Mozilla-based web engines and “Thunderbird” mail client which is based on Mozilla also, finally, Opera web engine is on its consideration, also if you observed that for every web-engine at the end of the path it appends |chrome| or |firefox| as I have said that every engine will be treated differently in exfiltration process, so it calls mw_parse_configuration after decoding the stream to enable Stealc to separate.
and here is how this configuration is parsed in a format that enables it to be used later.
00000000 00000000 00000000
| | |--> BrowserName length
| |-->4 null bytes
|--> pointer to BroswerName or path
Download Browsers Extensions
then the agent will ask C2 to feed it with plugins that will be used and I observed that it appends a string in the communication request that specifies which content will be retrieved from C2.
so again if we take a look at how our request and response look in our sniffer, it will confirm our previous analysis that the agent will ask for a plugin as a configuration request type.
the response is also base64 stream, I will decode it as past to reveal its secrets and also give us an indication about what will be done next.
Extenstion Name | Extenstion ID | flags or something | | | | | |
MetaMask |djclckkglechooblngghdinmeemkbgci|1|0|0|
MetaMask |ejbalbakoplchlghecdalmeeeajnimhm|1|0|0|
MetaMask |nkbihfbeogaeaoehlefnkodbefgpgknn|1|0|0|
TronLink |ibnejdfjmmkpcnlpebklmnkoeoihofec|1|0|0|
Binance Wallet |fhbohimaelbohpjbbldcngcnapndodjp|1|0|0|
Yoroi |ffnbelfdoeiohenkjibnmadjiehjhajb|1|0|0|
Coinbase Wallet extension |hnfanknocfeofbddgcijnmhnfnkdnaad|1|0|1|
Guarda |hpglfhgfnhbgpjdenjgmdgoeiappafln|1|0|0|
Jaxx Liberty |cjelfplplebdjjenllpjcblmjkfcffne|1|0|0|
iWallet |kncchdigobghenbbaddojjnnaogfppfj|1|0|0|
MEW CX |nlbmnnijcnlegkjjpcfjclmcfggfefdm|1|0|0|
GuildWallet |nanjmdknhkinifnkgdcggcfnhdaammmj|1|0|0|
Ronin Wallet |fnjhmkhhmkbjkkabndcnnogagogbneec|1|0|0|
NeoLine |cphhlgmgameodnhkjdmkpanlelnlohao|1|0|0|
CLV Wallet |nhnkbkgjikgcigadomkphalanndcapjk|1|0|0|
Liquality Wallet |kpfopkelmapcoipemfendmdcghnegimn|1|0|0|
Terra Station Wallet |aiifbnbfobpmeekipheeijimdpnlpgpp|1|0|0|
Keplr |dmkamcknogkgcdfhhbddcghachkejeap|1|0|0|
Sollet |fhmfendgdocmcbmfikdcogofphimnkno|1|0|0|
Auro Wallet(Mina Protocol) |cnmamaachppnkjgnildpdmkaakejnhae|1|0|0|
Polymesh Wallet |jojhfeoedkpkglbfimdfabpdfjaoolaf|1|0|0|
ICONex |flpiciilemghbmfalicajoolhkkenfel|1|0|0|
Coin98 Wallet |aeachknmefphepccionboohckonoeemg|1|0|0|
EVER Wallet |cgeeodpfagjceefieflmdfphplkenlfk|1|0|0|
KardiaChain Wallet |pdadjkfkgcafgbceimcpbkalnfnepbnk|1|0|0|
Rabby |acmacodkjbdgmoleebolmdjonilkdbch|1|0|0|
Phantom |bfnaelmomeimhlpmgjnjophhpkkoljpa|1|0|0|
Brave Wallet |odbfpeeihdkbihmopkbjmoonfanlbfcl|1|0|0|
Oxygen |fhilaheimglignddkjgofkcbgekhenbh|1|0|0|
Pali Wallet |mgffkfbidihjpoaomajlbgchddlicgpn|1|0|0|
BOLT X |aodkkagnadcbobfpggfnjeongemjbjca|1|0|0|
XDEFI Wallet |hmeobnfnfcmdkdcmlblgagmfpfboieaf|1|0|0|
Nami |lpfcbjknijpeeillifnkikgncikgfhdo|1|0|0
|Maiar DeFi Wallet |dngmlblcodfobpdpecaadgfbcggfjfnm|1|0|0|
Keeper Wallet |lpilbniiabackdjcionkobglmddfbcjo|1|0|0|
Solflare Wallet |bhhhlbepdkbapadjdnnojkbgioiodbic|1|0|0|
Cyano Wallet |dkdedlpgdmmkkfjabffeganieamfklkm|1|0|0|
KHC |hcflpincpppdclinealmandijcmnkbgn|1|0|0|
TezBox |mnfifefkajgofkcjkemidiaecocnkjeh|1|0|0|
Temple |ookjlbkiijinhpmnjffcofjonbfbgaoc|1|0|0|
Goby |jnkelfanjkeadonecabehalmbgpfodjm|1|0|0|
Ronin Wallet |kjmoohlgokccodicjjfebfomlbljgfhk|1|0|0|
Byone |nlgbhdfgdhgbiamfdfmbikcdghidoadd|1|0|0|
OneKey |jnmbobjmhlngoefaiojfljckilhhlhcj|1|0|0|
DAppPlay |lodccjjbdhfakaekdiahmedfbieldgik|1|0|0|
SteemKeychain |jhgnbkkipaallpehbohjmkbjofjdmeid|1|0|0|
Braavos Wallet |jnlgamecbpmbajjfhmmmlhejkemejdma|1|0|0|
Enkrypt |kkpllkodjeloidieedojogacfhpaihoh|1|1|1|
OKX Wallet |mcohilncbfahbmgdjkbpemcciiolgcge|1|0|0|
Sender Wallet |epapihdplajcdnnkdeiahlgigofloibg|1|0|0|
Hashpack |gjagmgiddbbciopjhllkdnddhcglnemk|1|0|0|
Eternl |kmhcihpebfmpgmihbkipmjlmmioameka|1|0|0|
Pontem Aptos Wallet |phkbamefinggmakgklpkljjmgibohnba|1|0|0|
Petra Aptos Wallet |ejjladinnckdgjemekebdpeokbikhfci|1|0|0|
Martian Aptos Wallet |efbglgofoippbgcjepnhiblaibcnclgk|1|0|0|
Finnie |cjmkndjhnagcfbpiemnkdpomccnjblmj|1|0|0|
Leap Terra Wallet |aijcbedoijmgnlmjeegjaglmepbmpkpi|1|0|0|
Trezor Password Manager |imloifkgjagghnncjkhggdhalmcnfklk|1|0|0|
Authenticator |bhghoamapcdpbohphigoooaddinpkbai|1|0|0|
Authy |gaedmjdfmmahhbjefcbgaolhhanlaolb|1|0|0|
EOS Authenticator |oeljdldpnmdbchonielidgobddffflal|1|0|0|
GAuth Authenticator |ilgcnhelpchnceeipipijaljkblbcobl|1|0|0|
Bitwarden |nngceckbapebfimnlniiiahkandclblb|1|0|0|
KeePassXC |oboonakemofpalcgghocfoadofidjkkk|1|0|0|
Dashlane |fdjamakpfbbddfjaooikfcpapjohcfmg|1|0|0|
NordPass |fooolghllnmhmmndgjiamiiodkpenpbb|1|0|0|
Keeper |bfogiafebfohielmmehodmfbbebbbpei|1|0|0|
RoboForm |pnlccmojcmeohlpggmfnbbiapkmbliob|1|0|0|
LastPass |hdokiejnpimakedhajhdlcegeplioahd|1|0|0|
BrowserPass |naepdomgkenhinolocfifgehidddafch|1|0|0|
MYKI |bmikpgodpkclnkgmnpphehdgcimmided|1|0|0|
Splikity |jhfjfclepacoldmjmkmdlmganfaalklb|1|0|0|
CommonKey |chgfefjpcobfbnpmiokfjjaglahmnded|1|0|0|
Zoho Vault |igkpcodhieompeloncfnbekccinhapdb|1|0|0|
Opera Wallet |gojhcdgcpbpfigcaejpfhfegekdgiblk|0|0|1|
it’s a collection of browser extensions that Stealc will search for in the browser’s DB using the ID provided which adds more stealthy capabilities, the same operation of storing configuration is done with these plugins as browsers did.
Exfiltrate System Information
after that Stealc starts gathering system and hardware information like,
ip address
country
processor name
operating system
arch 32 or 64
pc or laptob
UserName
computerName
Screenshot
installed apps
running process
etc.....
and after allocating this data it saves it in a format that is understandable by C2.
then the Collected Data is base64 encoded before transferring to C2
and here is the stream of the fully allocated data
System Summary: - HWID: 8658E8B4266B114684123 - OS: Windows 10 Enterprise - Architecture: x64 - UserName: - Computer Name: DESKTOP-2C3IQHO - Local Time: 2023/9/14 18:47:27 - UTC: -5 - Language: en-US - Keyboards: English (United States) - Laptop: FALSE - CPU: Intel(R) Core(TM) i7-4600M CPU @ 2.90GHz - Cores: 1 - Threads: 1 - RAM: 4095 MB - Display Resolution: 1536x864 - GPU: -VMware SVGA 3D -VMware SVGA 3D User Agents: Installed Apps: All Users: HxD Hex Editor version 1.7.7.0 - 1.7.7.0 Npcap - 1.55 VB Decompiler Lite WinSCP 5.13 - 5.13 Wireshark 3.6.0 64-bit - 3.6.0 Microsoft Visual C++ 2010 x86 Redistributable - 10.0.30319 - 10.0.30319 Microsoft Visual C++ 2008 Redistributable - x86 9.0.30729.4148 - 9.0.30729.4148 Microsoft Visual C++ 2015-2022 Redistributable (x64) - 14.32.31326 - 14.32.31326.0 Current User: Progress Telerik Fiddler - 5.0.20173.50948 Microsoft OneDrive - 18.025.0204.0009 Opera Stable 91.0.4516.77 - 91.0.4516.77 Python 3.9.9 (64-bit) - 3.9.9150.0
Process List:
System
smss.exe
csrss.exe
wininit.exe
csrss.ex
SearchIndexer.exe
SearchUI.exe
RuntimeBroker.exe
RuntimeBroker.exe
svchost.exe
SettingSyncHost.exe
svchost.exe
svchost.exe
vmtoolsd.exe
msdsrv.exe
svchost.exe
svchost.exe
svchost.exe
ApplicationFrameHost.exe
svchost.exe
svchost.exe
Downloader
after exfiltrating system info, Stealc will download Sqlite3 Dll which will be used to execute some queries to retrieve data from Ghrome Application data, so I will not skip this and try to explain it in detail.
first, it asks for Sqlite3.dll
after downloading the file it starts checking if the file is correct by checking some magic byte related to the dos header and PE header, and after that, it will not copy the whole file just from the start of section headers till the end of the file.
Stealc does all of that just to get addresses of some APIs that will assist in retrieving data from Chrome databases which Chrome itself uses
sqlite3_open
sqlite3_prepare_v2
sqlite3_step
sqlite3_column_text
sqlite3_finalize
sqlite3_close
sqlite3_column_bytes
sqlite3_column_blob
after that, it will start to check the browser structure built before and check the web engine then it will start to iterate over all browsers and if it hits any browser that exists on the victim machine it will then get a handle to db files which I will explain next…….
first, it will resolve
%USER%AppData\Local\Google\Chrome\User Data\LocalState
that exists in Chrome folders, but why this file exactly because it is used to store some more technical information about Chrome
The user’s preferred language
The user’s theme and font settings
The user’s startup settings (e.g., whether to open Chrome maximized)
The user’s privacy settings (e.g., whether to enable cookies)
The user’s extensions and their settings
The user’s bookmarks and history
after getting a handle on the file it will read file data and save a pointer to it into the first passed argument.
after that, it will search for the “encrypted_key “ string on the buffer, then it will try to retrieve the key from the file buffer because the key is saved in a format that I will show in the next figure.
until that, it will iterate over the buffer until it hits the end of the key which is marked by the “}” symbol
after retrieving the key it will base64 decode it, at the first 5 bytes of the decoded stream the word “DPAPI” indicates a DPAPI decrypted stream, after that, it will use the decoded key to decrypt the AES key using CryptUnprotectData, and the result is an AES key which will be used to decrypt cookies and credentials that because chrome(v80+) is encrypting data using AES and the AES key is encrypted with DPAPI,
then it will AES decrypted key to generate a symmetric key which will be used for the decryption operation, this is done in 3 steps
1- call BCryptOpenAlgorithmProvider to handle a cryptographic algorithm provider which in this case is AES.
2-call BCryptSetProperty to set the mode to ChainingModeGCM, It specifies that the Galois/Counter Mode (GCM) chaining mode should be used. GCM is a mode of operation for block ciphers that provides both encryption and authentication (with the help of Bard chat)
3- call BCryptGenerateSymmetricKey, used to generate a symmetric key for cryptographic operations and save a handle for it in Phkey var.
after that, it will retrieve the browser path that was received from C2, and in our case the first folder path is
%USER%AppData\Local\Google\Chrome\User Data
so it will iterate over all folders on this path looking for some Browser DB files, these files are
AppData\Local\Google\Chrome\User Data\Default\Network\Cookies
AppData\Local\Google\Chrome\User Data\Default\Login Data
AppData\Local\Google\Chrome\User Data\Default\Web Data
AppData\Local\Google\Chrome\User Data\Default\History
which enables it to steal history and web sessions also autofill data will be exfiltrated.
We hope this post spreads awareness to the blue teamers of this interesting malware techniques, and adds a weapon to the red teamers arsenal.
Big thanks to @farghlymal for this detailed report.
By Cyber Threat Hunters from MSSPLab:
References
https://malpedia.caad.fkie.fraunhofer.de/details/win.stealc
https://farghlymal.github.io/Stealc-Stealer-Analysis/
https://twitter.com/farghlymal
Stealc config decryptor
Malware Analysis Stealc - part 1
Thanks for your time happy hacking and good bye!
All drawings and screenshots are from farghlymal blog
Article Link: Malware analysis report: Stealc stealer - part 2 - MSSP Lab