ghost4301

Category
Reverse Engineering
Points
350
Tags

Walkthrough

Diberikan sebuah binary .ko (kernel), langsung gw decompile

ssize_t __pfx_ghost_read(struct file* file, char* buf, size_t len, loff_t* ppos)
{
    /* tailcall */
    return ghost_exit(file, buf, len, ppos);
}

ssize_t ghost_exit(struct file* file, char* buf, size_t len, loff_t* ppos)
{
    int64_t rcx_1;
    int64_t rdx_2;
    int64_t rsi_2;
    rcx_1 = __fentry__();
    simple_read_from_buffer(rsi_2, rdx_2, rcx_1, &ghost_buf, ghost_len);
    /* tailcall */
    return __x86_return_thunk(0, 0, 0, 0, 0);
}

int64_t __pfx_ghost_init()
{
    /* tailcall */
    return ghost_init();
}

int64_t ghost_init()
{
    __fentry__();
    int32_t i_1 = scnprintf(&ghost_buf, 0x200, "[ghost4301] telemetry frames:\n");
    int32_t i = i_1;
    
    if (i_1 <= 0x1fe)
    {
        int32_t r12_1 = 0;
        
        do
        {
            int64_t r14_1 = r12_1;
            
            if (r14_1 >= 5)
                __ubsan_handle_out_of_bounds(&data_400680, r14_1);
            
            uint64_t rcx_1 = r12_1;
            r12_1 += 1;
            i += scnprintf(i + &ghost_buf, 0x200 - i, "frame[%d] = 0x%016llx\n", rcx_1, 
                *((r14_1 << 3) + &ghost_blob));
            
            if (r12_1 > 4)
                break;
        } while (i <= 0x1fe);
    }
    
    ghost_len = i;
    uint64_t rax_1 = proc_create("ghost4301", 0x124, 0, &ghost_fops);
    ghost_entry = rax_1;
    
    if (!rax_1)
        _printk(0x400210, "ghost4301");
    else
    {
        _printk(0x4002b1, 
            "ghost4301_telemetry\nz[i] = rotl8((flag[i]^key[i%7] + poly(i)), (3*i)%8)\npoly(i) = i^3 + "
        "7*i^2 + 13*i + 37 (mod 256)\n");
        _printk(0x4002b1, "key[7] = {0x13,0x37,0x42,0xA5,0x5C,0x9E,0x11}\n");
        _printk(0x400238, "ghost4301");
    }
    
    /* tailcall */
    return __x86_return_thunk(0, 0, 0, 0, 0);
}

int64_t __pfx_cleanup_module()
{
    /* tailcall */
    return cleanup_module();
}

int64_t cleanup_module()
{
    if (ghost_entry)
        remove_proc_entry("ghost4301", 0);
    
    _printk(0x4002c1);
    /* tailcall */
    return __x86_return_thunk(0, 0);
}

Dari dump kita menemukan array key

key[7] = {0x13,0x37,0x42,0xA5,0x5C,0x9E,0x11}

dan juga rumus encryption nya

tmp = flag[i] ^ key[i%7]
tmp = (tmp + poly(i)) & 0xFF
cipher[i] = rotl8(tmp, (3*i) % 8)

Dan dari ciphertext yang kita ekstrak dari .rodata, di bawah string-string itu ada blok 40 byte:

709A2CC13B5EF477
F2411264BA4C5DB1
906DCA2D3FAD1F66
9ED42542F6E19417
AAAAAAA A AADB4D31

Yauds tinggal buat solver

z_raw = bytes.fromhex("""
70 9A 2C C1 3B 5E F4 77
F2 41 12 64 BA 4C 5D B1
90 6D CA 2D 3F AD 1F 66
9E D4 25 42 F6 E1 94 17
AA AA AA AA AA DB 4D 31
""")
key = [0x13,0x37,0x42,0xA5,0x5C,0x9E,0x11]

def poly(i):
    return (i**3 + 7*i**2 + 13*i + 37) % 256

def rotr8(x, r):
    r &= 7
    return ((x >> r) | (x << (8-r))) & 0xFF

flag = []
for i, c in enumerate(z):
    x = rotr8(c, (3*i) % 8)
    x = (x - poly(i)) & 0xFF
    x ^= key[i % 7]
    flag.append(x)

print(bytes(flag))

Tetapi outputnya masi anomali (ga segampang itu ternyata), dan gw memutuskan untuk mencoba dengan reverse tapi per frame

z = b''.join(
    z_raw[i:i+8][::-1]
    for i in range(0, len(z_raw), 8)
)

Jadi kayak gini final solver nya

z_raw = bytes.fromhex("""
70 9A 2C C1 3B 5E F4 77
F2 41 12 64 BA 4C 5D B1
90 6D CA 2D 3F AD 1F 66
9E D4 25 42 F6 E1 94 17
AA AA AA AA AA DB 4D 31
""")

z = b''.join(
    z_raw[i:i+8][::-1]
    for i in range(0, len(z_raw), 8)
)

key = [0x13,0x37,0x42,0xA5,0x5C,0x9E,0x11]

def poly(i):
    return (i**3 + 7*i**2 + 13*i + 37) % 256

def rotr8(x, r):
    r &= 7
    return ((x >> r) | (x << (8-r))) & 0xFF

flag = []
for i, c in enumerate(z):
    x = rotr8(c, (3*i) % 8)
    x = (x - poly(i)) & 0xFF
    x ^= key[i % 7]
    flag.append(x)

print(bytes(flag))

ghost4301 Flag: ASTROXNFSCC{K3rn3l_Gh0st_Tr4p_4301}