1

I'm exercising with ROP. In a vulnerable program I control the RIP, use "ropeme" and search for gadgets I find many references to 32 bits long registers, but not a single extended register.

I need a simple "pop rdi; ret;" to pass the /bin/sh string to the system() function (I disabled alsr and stack-protector).

I tried using asm() to directly incorporate the gadget but of course it crashes the program, and when I enclose the function inside an if(0){} or another function that we don't call, the gadget doesn't appear inside ropme.

Is this standard that a small program will not have any code that references extended registers ? What shall I do to make the exploit possible using rop and return to libc ?

Yvain
  • 89
  • 10

1 Answers1

1

I assume you are compiling your program in x86-64 mode, otherwise there would be no chance (nor need) for popping rdi. Generally speaking, smaller programs have fewer gadgets. Particularly very simple programs tend not to have many gadgets that begin in the middle of long instructions, as longer programs/libraries may have.

Blocks compiled in if(0){} will never appear in the output of the program, even when optimization is disabled, this is likely to be completely ignored by the compiler. Instead, you can use a global variable because it is hard for an optimizer to reason about the value of a global.

#include <stdio.h>

int foo = 0;

void callme() {
  asm volatile ("pop %%rdi\n\t"
      "ret"
      :
      :
      : "rdi");
}

int main(int argc, char **argv) {
  printf("Hello world!\n");
  if (foo == 0x55) {
    callme();
  }
}

The assembly in the function callme performs a pop rdi;ret sequence. Because it is in GCC, AT&T syntax is expected, so registers require a %. Unfortunately, the asm macro uses % as a meta-character, requiring the doubling up to escape a single %. asm takes several arguments separated by colons (I do not know why they chose colons instead of commas). The first is the assembly template, which can include auto-assigned registers if the programmer does not require control of their own registers. The 2nd and 3rd are the destination (output) and source (input) registers. The final one is a list of other registers that are overwritten by the assembly. In normal use, this will tell the compiler how to allocate registers for this function. Given that this function is not actually being used normally, but only for shellcoding, all of this is mostly optional, but I went with the long version for demonstration purposes here.

If you compile this code with gcc -O0 -o sample sample.c, and then dump the disassembly via objdump -d sample, you will see the function callme is included, and contains the gadget you are looking for.

David
  • 15,814
  • 3
  • 48
  • 73
  • thank you, I have tested with objdump and this confirms my misusing "ropeme". I have one last question though I'd like to know why you use `%` twice before the symbol rdi and what are the `:` (column) and the last "rdi" reference. – Yvain Feb 03 '18 at 22:30
  • Yvain, I have added an explanation of the `asm` call to the answer that I hope answers your questions. – David Feb 03 '18 at 23:53
  • I am starting to understand, I saw this syntax in /sys/io.h and others. I will release the bounty in 11 hours by the way. – Yvain Feb 04 '18 at 09:13