LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   Can't inject x00 value with bash-printf using string format vulnerability in x64 (http://www.linuxquestions.org/questions/programming-9/cant-inject-x00-value-with-bash-printf-using-string-format-vulnerability-in-x64-898306/)

kaos_npc 08-19-2011 12:33 PM

Can't inject x00 value with bash-printf using string format vulnerability in x64
 
Hello! This is my first post here! So, here's the problem: I'm following a nice book called Hacking - The Art Of Exploitation. I'm at the point in wich the string format vulnerability is being explained. I've learned how to do it and on a x32 system of mine: it worked flawlessly. But on my x64 Ubuntu, I can't make it work.

This is the code of the program wich I need to exploit:
Code:

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

int main(int argc, char *argv[]) { 

 char text[1024];
 static int test_val = -72;
 
    if(argc < 2) {
 
      printf("Usage: %s <text to print>\n", argv[0]);
      exit(0);
 
    } 

 strcpy(text, argv[1]);

 printf("The right way to print user-controlled input:\n");
 printf("%s", text);

 printf("\nThe wrong way to print user-controlled input:\n");
 printf(text); // HERE IS THE VULNERABILITY

 printf("\n"); 

 // Debug output 
 printf("[*] test_val @ 0x%08x = %d 0x%08x\n", &test_val, test_val, test_val); 

 exit(0);

}

I have to input a string witch begins with the memory location of test_val, then some %08x. that reads the shit in the stack of main, then a %n parameter where I find the written address which on the inputed string to change the value of test_val to the number of writen bytes.

Normaly i would have to input this to make it work:

kaos@ubuntu$ ./a.out $(printf "\x40\x56\x5f\x6a")%08x.%08x.%08x.%08x.%08x%n


The problem in the x64 system is that test_val is located at 0x601080 (3 bytes) and when I input $(printf "\x80\x10\x60\x00"), it seems that \x00 doesn't input anything, because I think it's related to NULL as a string end.
Thus, I got a segmentation error all the times that I try because the address isn't valid.

How can I inject that 00? Or how can I write the address to make it readable to the %n parameter? It's just impossible? Hope I've made myself understood!

If there's anything unclear I can answer all the questions!

Thanks! :)

ta0kira 08-19-2011 01:45 PM

Quote:

Originally Posted by kaos_npc (Post 4447913)
The problem in the x64 system is that test_val is located at 0x601080 (3 bytes) and when I input $(printf "\x80\x10\x60\x00"), it seems that \x00 doesn't input anything, because I think it's related to NULL as a string end.
Thus, I got a segmentation error all the times that I try because the address isn't valid.

Fortunately vulnerabilities aren't meant to be reliable. I'm also wondering how printing the address to standard output results in it being written to the stack right after printf's first argument, unless printf always has a stack-allocated output buffer at the beginning of the function.
Kevin Barry

PS It would be easier to just use an argument that's 1028 bytes long and overwrite test_val with strcpy, or if you're dead-set on %n use a string that writes past printf(text/*<--here*/); on the stack and write the address there (which could incidentally compromise the operation of strcpy, probably defeating your own effort).

kaos_npc 08-19-2011 02:07 PM

Quote:

Originally Posted by ta0kira (Post 4447962)
Fortunately vulnerabilities aren't meant to be reliable. I'm also wondering how printing the address to standard output results in it being written to the stack right after printf's first argument, unless printf always has a stack-allocated output buffer at the beginning of the function.
Kevin Barry

PS It would be easier to just use an argument that's 1028 bytes long and overwrite test_val with strcpy, or if you're dead-set on %n use a string that writes past printf(text/*<--here*/); on the stack and write the address there (which could incidentally compromise the operation of strcpy, probably defeating your own effort).

Yo thx for the answer! :D I tought there was a method to print x00 with printf. No, I don't care about owning the program with the other overflows, because this was just an example. =) I'm just a little worried about all the times when I'll find adresses that start with 00.

ta0kira 08-19-2011 05:35 PM

Quote:

Originally Posted by kaos_npc (Post 4447981)
Yo thx for the answer! :D I tought there was a method to print x00 with printf. No, I don't care about owning the program with the other overflows, because this was just an example. =) I'm just a little worried about all the times when I'll find adresses that start with 00.

You've got at least 3 things working against your attempt to pass 0x00 directly:
  1. The shell (bash, anyway) will discard null characters:
    Code:

    $ value="$(printf '12\x0034')"
    $ echo ${#value} "$value"
    4 1234

  2. execve will only read argument characters up until a null character:
    Code:

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


    static void show(char *oOne, char *tTwo)
    {
            fprintf(stderr, "%p:\t'%s'\n", oOne, oOne);
            fprintf(stderr, "%p:\t'%s'\n", tTwo, tTwo);
            fprintf(stderr, "[offset %i]\n", (int) (tTwo - oOne));
    }


    int main(int argc, char *argv[], char *envp[])
    {
            if (argc == 3)
            {
            show(argv[1], argv[2]);
            return 0;
            }

            char  arg1[] = "12\00034\000hello";
            char *arg2  = arg1 + 6;

            show(arg1, arg2);

            char *new_argv[] = { argv[0], arg1, arg2, NULL };

            execve(argv[0], new_argv, envp);
            return 1;
    }

    Code:

    $ ./a.out
    0x7fff23b85ae0: '12'
    0x7fff23b85ae6: 'hello'
    [offset 6]
    <-- 12\00034\000
    0x7fffb7406146: '12'
    0x7fffb7406149: 'hello'
    [offset 3]
    <-- not far enough apart for \00034\000 to be present

  3. strcpy and printf will stop reading the string upon encountering a null character.
Kevin Barry

PS Ubuntu 64-bit uses 32-bit addresses, in case it wasn't obvious.

kaos_npc 08-20-2011 07:50 AM

Quote:

Originally Posted by ta0kira (Post 4448116)
You've got at least 3 things working against your attempt to pass 0x00 directly:
  1. The shell (bash, anyway) will discard null characters:
    Code:

    $ value="$(printf '12\x0034')"
    $ echo ${#value} "$value"
    4 1234

  2. execve will only read argument characters up until a null character:
    Code:

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


    static void show(char *oOne, char *tTwo)
    {
            fprintf(stderr, "%p:\t'%s'\n", oOne, oOne);
            fprintf(stderr, "%p:\t'%s'\n", tTwo, tTwo);
            fprintf(stderr, "[offset %i]\n", (int) (tTwo - oOne));
    }


    int main(int argc, char *argv[], char *envp[])
    {
            if (argc == 3)
            {
            show(argv[1], argv[2]);
            return 0;
            }

            char  arg1[] = "12\00034\000hello";
            char *arg2  = arg1 + 6;

            show(arg1, arg2);

            char *new_argv[] = { argv[0], arg1, arg2, NULL };

            execve(argv[0], new_argv, envp);
            return 1;
    }

    Code:

    $ ./a.out
    0x7fff23b85ae0: '12'
    0x7fff23b85ae6: 'hello'
    [offset 6]
    <-- 12\00034\000
    0x7fffb7406146: '12'
    0x7fffb7406149: 'hello'
    [offset 3]
    <-- not far enough apart for \00034\000 to be present

  3. strcpy and printf will stop reading the string upon encountering a null character.
Kevin Barry

PS Ubuntu 64-bit uses 32-bit addresses, in case it wasn't obvious.

Thanks a lot for the proof! ^^ I'm glad I've been clarified!

phulse 05-27-2014 02:14 PM

Resurrection
 
Resurreting this thread because I too am going through this book and have become stuck on this problem. My setup is exactly the same and wanted to know if this was solved?


All times are GMT -5. The time now is 10:23 AM.