Format Stringz

How to pwn a printf

fgets(hello, 256, stdin);

printf(hello);
fgets(hello, 256, stdin);

printf(hello);

NOPE

Fonctionnement de printf

  • Format String
  • Structure de la stack

Format String

  • %x : Print first argument as hex
  • %08x : Pad hex with 0
  • %3$x : Print third argument as hex
  • %s : Print string at memory location from argument
  • %n : Write string length into the memory location from argument as an `int`
  • %hhn : Like %n, but store value as a 8 bit char

Regular printf call

fn(){
  int a = 42;
  char* b = "Hello world";
  printf("%s and %x", b, a);
}

Regular printf

Expected result:

"Hello world and 42"

Printf exploited

void fn(char* input){
  int password = 0x12345678;
  printf(input);
}

Printf exploited

Given input = "%x\n%x\n%x"

Expected output:

<top_secret>

<fn's ebp>

<fn's return>

Print all the thing

void fn(){
  char buffer[1024];
  gets(buffer);
  printf(buffer);
}

Print all the things

Buffer = "\x12\x34\x56\x78 %3$s"

Print string located at 0x78563412

Write all the thing

  • Insert target address in format string (Like the "Read all the thing")
  • Pad string with %NNx
  • Write length of the string with %hhn
  • 1 byte at a time
  • eg: To write 0x44 at 0x12345678
    • "\x78\x56\x34\x12%40x%7$hhn
    • \x78\x56\x34\x12
      • Target address
    • %40x
      • Add an additional 0x40 bytes to the output string
    • %7$hhn
      • Write output length (0x44)

Write all the thing

  • Can write many bytes in the same format string:
  • Example for a 32 bits integer:
    • <addr><addr+1><addr+2><addr+3>
    • <pad1>%<N>$hhn
    • <pad2>%<n+1>$hhn
    • <pad3>%<n+1>$hhn
    • <pad4>%<n+1>$hhn
  • Remember that the written value is the output string length. If the first byte is 0xf0, and the second byte is 0x10, <pad2> should be %20x.

Limitation

  • Format string are used by all printf family function and often by logging function
  • To read and write everywhere, an attacker must control a value on the stack to put the target address. For this reason, a format string in the Heap might be harder to exploit.

Exploit through .GOT

  • Global Offset Table
  • Located at the end of the program
  • Address known
  • Table mapping imported function to their real address
  • Ex: exit(0)
    • A stub function is called
    • Lookup the exit GOT entry
    • Jump to exit location
  • Rewrite printf() address to system()?
Made with Slides.com