Intro

We have a network traffic capture and we have to figure out the files being transferred.

Write-Up

We see that there are 2 streams in this capture. It is network traffic between the following devices.

xn--zn8hscq4eeafedhjjkl.flare-on.com = 🐈😸😻😹😺🐱😼🙀😿😾😽😻.flare-on.com
xn--zn8hrcq4eeadihijjk.flare-on.com  = 😺😸😹😻😼😽🙀😿😾🐱🐈.flare-on.com

The first stream is something like below

00000000  4d 45 30 57 32 00 00 00  32 00 00 00 7e 6d 65 6f   ME0W2... 2...~meo
00000010  77 7e 20 28 3d 5e 2e 5e  3d 29 20 7e 6d 65 6f 77   w~ (=^.^ =) ~meow
00000020  7e 2e 2e 2e 2e 20 63 61  6e 20 68 61 7a 20 4d 65   ~.... ca n haz Me
00000030  65 6f 6f 6f 77 77 77 4d  65 6d 65 3f 3f 3f         eooowwwM eme???
    00000000  4d 45 30 57 d0 24 0a 00  d0 24 0a 00 89 50 4e 47   ME0W.$.. .$...PNG
    00000010  0d 0a 1a 0a 00 00 00 0d  49 48 44 52 00 00 05 d8   ........ IHDR....
    00000020  00 00 04 62 08 06 00 00  00 b7 69 95 af 00 00 0c   ...b.... ..i.....
    00000030  63 69 43 43 50 49 43 43  20 50 72 6f 66 69 6c 65   ciCCPICC  Profile
    00000040  00 00 48 89 95 57 07 5c  93 47 1b bf 77 64 92 b0   ..H..W.\ .G..wd..

If we extract the reply, we get the cat picture. We analyze the PNG file but it doesn’t have anything extraordinary. We check the second stream and we see the following.

00000000  4d 45 30 57 8b 00 00 00  b4 00 00 00 50 41 33 30   ME0W.... ....PA30
00000010  f0 5e 21 03 77 a0 d7 01  18 23 c0 b2 9f 0b 01 01   .^!.w... .#......
00000020  7a 02 96 07 13 26 5c 39  70 63 c4 90 b3 7a 49 4c   z....&\9 pc...zIL
00000030  68 32 e6 c0 89 9d 72 31  3c 19 b0 e7 42 8f 03 6d   h2....r1 <...B..m
00000040  b9 1a 65 ca 93 ad 4a a3  76 79 22 0c e8 15 c2 81   ..e...J. vy".....
00000050  2b 17 ae f4 58 d0 65 a9  5c 3e 1b 39 72 b5 6a 97   +...X.e. \>.9r.j.
00000060  af 46 2e 2f 7a 6c b8 33  e2 42 83 25 47 b9 42 68   .F./zl.3 .B.%G.Bh
00000070  d0 e5 ca 88 2b 33 da 74  18 d1 94 a9 5e 29 1f da   ....+3.t ....^)..
00000080  b4 d5 73 67 c2 80 3e 6d  6e 72 2f 9a ce 47 cd 91   ..sg..>m nr/..G..
00000090  11 6b d9 1f a1 2e ab c2  b4 8b 96 74 6a 2e a2 69   .k...... ...tj..i
000000A0  71 a3 c1 55 b4 68 06 ec  e8 70 fe 58 25 4a e1 44   q..U.h.. .p.X%J.D
000000B0  ff 22 a5 30 fa a8 69 70  56 d9 01 00 80 d2 3e 03   .".0..ip V.....>.
    00000000  4d 45 30 57 09 00 00 00  27 00 00 00 50 41 33 30   ME0W.... '...PA30
    00000010  d0 84 49 07 77 a0 d7 01  18 23 c0 b2 9f 0b 01 01   ..I.w... .#......
    00000020  46 00 94 13 53 1a cc 38  d1 31 a0 d7 78 07 00 00   F...S..8 .1..x...
    00000030  52 fd 0c                                           R..

So we see that server and client communicates with PA30 header. When we google this string we see that this is a format to distribute Microsoft Delta patches.

When we Google this format, we can find this repository Let’s apply our first patch with delta_patch.py to our png file.

We get our first DLL file. When we decompile this DLL, we can see that after it sends or receives packages, it xors the result.

loc_10001155:
xor     edx, edx
mov     [ebp+Dst], 5
mov     eax, ecx
div     [ebp+Dst]
mov     al, byte ptr ds:aMeoow[edx] ; "meoow"
xor     [ebx+ecx], al
inc     ecx
cmp     ecx, esi
jb      short loc_10001155

We can either emulate the traffic between the host and client or we can just apply the patches, xor the result and search for the flag. I will do the second one. I exported pcapng file to JSON file with Wireshark and analyzed the traffic.

from ctypes import (windll, wintypes, c_uint64, cast, POINTER, Union, c_ubyte,
                    LittleEndianStructure, byref, c_size_t)
import zlib
import json
import struct

# types and flags
DELTA_FLAG_TYPE             = c_uint64
DELTA_FLAG_NONE             = 0x00000000
DELTA_APPLY_FLAG_ALLOW_PA19 = 0x00000001

# structures
class DELTA_INPUT(LittleEndianStructure):
    class U1(Union):
        _fields_ = [('lpcStart', wintypes.LPVOID),
                    ('lpStart', wintypes.LPVOID)]
    _anonymous_ = ('u1',)
    _fields_ = [('u1', U1),
                ('uSize', c_size_t),
                ('Editable', wintypes.BOOL)]


class DELTA_OUTPUT(LittleEndianStructure):
    _fields_ = [('lpStart', wintypes.LPVOID),
                ('uSize', c_size_t)]


# functions
ApplyDeltaB = windll.msdelta.ApplyDeltaB
ApplyDeltaB.argtypes = [DELTA_FLAG_TYPE, DELTA_INPUT, DELTA_INPUT,
                        POINTER(DELTA_OUTPUT)]
ApplyDeltaB.rettype = wintypes.BOOL
DeltaFree = windll.msdelta.DeltaFree
DeltaFree.argtypes = [wintypes.LPVOID]
DeltaFree.rettype = wintypes.BOOL

#xor the traffic
def xor(data):
    key = bytearray('meoow','utf-8')
    l = len(key)
    result =  bytearray((
        (data[i] ^ key[i % l]) for i in range(0,len(data))
    ))
    return result

def apply_patchfile_to_file(inbuf, patch_contents):
    buf = cast(bytes(inbuf), wintypes.LPVOID)
    buflen = len(inbuf)
    # some patches (Windows Update MSU) come with a CRC32 prepended to the file
    # if the file doesn't start with the signature (PA) then check it
    if patch_contents[:2] != b"PA":
        paoff = patch_contents.find(b"PA")
        if paoff != 4:
            raise Exception("Patch is invalid")
        crc = int.from_bytes(patch_contents[:4], 'little')
        patch_contents = patch_contents[4:]
        if zlib.crc32(patch_contents) != crc:
            raise Exception("CRC32 check failed. Patch corrupted or invalid")

    applyflags = DELTA_FLAG_NONE
    dd = DELTA_INPUT()
    ds = DELTA_INPUT()
    dout = DELTA_OUTPUT()

    ds.lpcStart = buf
    ds.uSize = buflen
    ds.Editable = False
    dd.lpcStart = cast(patch_contents, wintypes.LPVOID)
    dd.uSize = len(patch_contents)
    dd.Editable = False
    status = ApplyDeltaB(applyflags, ds, dd, byref(dout))
    if status == 0:
        raise Exception("Patch failed")
    buf = dout.lpStart
    n = dout.uSize
    outbuf = bytes((c_ubyte*n).from_address(buf))
    DeltaFree(buf)
    return outbuf

with open('dump.json') as r:
    packets = json.load(r)
    for packet in packets:
        layers = packet['_source']['layers']
        if 'data_raw' in layers:
            raw_bytes =  layers['data_raw'][0]
            data_bytes = bytes.fromhex(raw_bytes)
            patch_bytes = data_bytes[12:]
            empty_bytes = bytearray(4096)
            patched_bytes = apply_patchfile_to_file(empty_bytes,patch_bytes)
            xored_bytes = xor(patched_bytes)
            search = xored_bytes.find(bytes('@flare-on.com','utf-8'))
            if (search != -1):
                result = xored_bytes[search-50:search+50].decode('utf-8')
                print(result)
                break

When we run this script, we get the following flag

1m_H3RE_Liv3_1m_n0t_a_C4t@Flare-on.com

Flare-On 2021 Write-ups

I am available for new work
Interested? Feel free to reach