LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 08-19-2011, 12:33 PM   #1
kaos_npc
LQ Newbie
 
Registered: Aug 2011
Posts: 3

Rep: Reputation: Disabled
Unhappy 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!

Last edited by kaos_npc; 08-19-2011 at 12:35 PM.
 
Old 08-19-2011, 01:45 PM   #2
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by kaos_npc View Post
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).

Last edited by ta0kira; 08-19-2011 at 01:53 PM.
 
Old 08-19-2011, 02:07 PM   #3
kaos_npc
LQ Newbie
 
Registered: Aug 2011
Posts: 3

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by ta0kira View Post
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! 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.
 
Old 08-19-2011, 05:35 PM   #4
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by kaos_npc View Post
Yo thx for the answer! 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.

Last edited by ta0kira; 08-19-2011 at 05:59 PM. Reason: made execve example more instructive, added comment
 
Old 08-20-2011, 07:50 AM   #5
kaos_npc
LQ Newbie
 
Registered: Aug 2011
Posts: 3

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by ta0kira View Post
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!
 
Old 05-27-2014, 02:14 PM   #6
phulse
LQ Newbie
 
Registered: May 2014
Posts: 1

Rep: Reputation: Disabled
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?
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] Inject value to bash input Tux-Slack Linux - General 6 10-15-2009 03:38 AM
Minus sign in printf format string doesn't work. zebela Linux - Newbie 4 06-13-2008 01:32 AM
C string and printf question exvor Programming 7 12-10-2005 10:53 AM
std string class and printf The_Nerd Programming 3 06-28-2004 10:46 PM
NullLogic Null Webmail Format String Vulnerability Aivukazz Linux - Security 1 10-09-2002 02:47 PM


All times are GMT -5. The time now is 12:48 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration