Thread: shellcodes

  1. #1
    Registered User
    Join Date
    Aug 2009
    Posts
    39

    shellcodes

    I decided to follow the steps of a book entitled "Shellcoder's handbook" in Ubuntu for educational purposes, but I am facing some problems. This is a basic code I tested it on.

    Code:
    void return_input (void)
    {
       char array[6];
       gets(array);
       printf("%s\n", array);
    }
    int main()
    {
       return_input();
       return 0;
    }
    Running it on debugger with -fno-stack-protector compile parameter, I put AAAAAAAAAAAA\x23\x84\x04\x08. The eight first A fill the entire array plus the padding, the next four characters overwrite the saved ebp on stack and finally the last ones are supposed to overwrite the return address with the address that the string contains and corresponds to line "gets(array)". However, I then get the result
    Code:
    Program received signal SIGSEGV, Segmentation fault.
    0x785c4141 in ??
    So, how is the address different from 0x08048423?

  2. #2
    Registered User
    Join Date
    Jun 2009
    Posts
    486
    gets() is generally a bad idea.

    %s keeps printing until it finds \0 at the end of the array. I don't think gets puts one there, so %s will walk off the end of your character array and segfault.

  3. #3
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    @KBriggs: not necessarily, which is the point of the experiment.

    Not sure if this is the problem, but you will want to read this:

    CodeDump: stack smashing detected

    [edit] you are using -fno-stack-protector so I guess you are aware of that, sorry.

    Have you tried removing the printf() line?
    Last edited by MK27; 08-13-2009 at 11:17 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  4. #4
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Well, I think the point is to see how bad gets() really is. I don't know internals of linux or ubuntu, so I don't know how the number 0x08048423 was chosen.

  5. #5
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by tabstop View Post
    Well, I think the point is to see how bad gets() really is. I don't know internals of linux or ubuntu, so I don't know how the number 0x08048423 was chosen.
    0x8048423 is a code address somewhere near the beginning of the code segment. That instruction might be anything. Suppose it was "ret". Then it would return again to somewhere else, possibly to this random 0x785c4141 address.

    As a sanity check, use a huge string of 0x03 instead. This will result in a return address of 0x03030303 which is almost certainly NOT mapped, and then you should get a SIGSEGV from that address. If that's not working, your stack overwrite must not be working. At that point, start single-stepping in the debugger to see what's going on
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  6. #6
    1337
    Join Date
    Jul 2008
    Posts
    135
    First off, inject a shellcode into an address somewhere in the memory. Then place the address of the shellcode in the 'ret' location where you are going to overwrite. eg. AAAAAAAAAAAA\x23\x84\x04\x08 , so 13 bytes after esp will be the return address in this case.

    Overwrite those 4 bytes with the shellcode's address. If this (AAAAAAAAAAAA\x23\x84\x04\x08) is the working code, then 0x08048423 is the shellcode's address. Make sure you have aslr disabled to test this, else it wont work. A shell should be prompted after accomplishing this ( if your shellcode is coded to return a shell).

  7. #7
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by valthyx View Post
    Make sure you have aslr disabled to test this, else it wont work. A shell should be prompted after accomplishing this ( if your shellcode is coded to return a shell).
    0x8048XXX is a code segment address. On Linux, the main program code segment is NOT subjected to ASLR. This is because normal program code is almost never compiled with -fPIC, and even if it were, the linker and kernel ELF loader would both have to be changed in order to support it. (There might be some Linux distro out there that does this, but your out-of-box distro does not)
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  8. #8
    Registered User
    Join Date
    Aug 2009
    Posts
    39
    Thanks everyone for the feedback, but I got confused by the conflicting answers. What I will keep is trying an alternative command to gets. Would scanf be a nice option?
    As somebodies did not understand the particular address in the shellcode, like I clarified in the first post, it corresponded to line gets(array).

  9. #9
    1337
    Join Date
    Jul 2008
    Posts
    135
    Code:

    Program received signal SIGSEGV, Segmentation fault.
    0x785c4141 in ??

    So, how is the address different from 0x08048423?
    0x785c4141 is not the address, but they are values in HEX.

    41 = A
    78 = x
    5c = \

    so the value is AA\x

    The eight first A fill the entire array plus the padding, the next four characters overwrite the saved ebp on stack and finally the last ones are supposed to overwrite the return address
    It supposed to be "the first 6" as the array size is 6, not 8. So, you should enter "AAAAAAAAAA\x23\x84\x04\x08"

    The first 6 A's are for filling up the array, the next 4 are to overwrite the oldebp and the next 4 bytes are to replace the return address.

    And you know what, shellcoder's handbook has a lot of mistakes and typos (I am not sure if they are mistakenly made or purposely made)
    Last edited by valthyx; 08-13-2009 at 12:23 PM.

  10. #10
    Registered User
    Join Date
    Aug 2009
    Posts
    39
    Quote Originally Posted by valthyx View Post
    0x785c4141 is not the address, but they are values in HEX.

    41 = A
    78 = x
    5c = \

    so the value is AA\x
    Thanks, I got it. Is there a way around, so as to give the desirable hex value, not through ascii code?

    Quote Originally Posted by valthyx View Post
    It supposed to be "the first 6" as the array size is 6, not 8. So, you should enter "AAAAAAAAAA\x23\x84\x04\x08"

    The first 6 A's are for filling up the array, the next 4 are to overwrite the oldebp and the next 4 bytes are to replace the return address.
    According to the book, two more characters are needed to fill up the padding as well (I suppose the terminal character(s) after the string).

    Quote Originally Posted by valthyx View Post
    And you know what, shellcoder's handbook has a lot of mistakes and typos (I am not sure if they are mistakenly made or purposely made)
    I did not know that. Could you recommend another more valid instead?

  11. #11
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by vril View Post
    According to the book, two more characters are needed to fill up the padding as well (I suppose the terminal character(s) after the string).
    Play around with the amount of padding, from 0-4 maybe. I don't think the book could exactly predict that. 6 is a word boundary, so there might be no padding at all.

    You could stick with gets() for this, BTW, just don't use it in normal programming.

    "x23\x84\x04\x08" is a hex value used to access memory, that's the way to do it.

    But look at this closely: "0x785c4141" That's two 0x41's at the end. 0x41 is ascii hex for CAPITAL A. That's not the address, it's the value at ??

    Surprise surprise. I don't understand why it wouldn't then be "0x84234141", tho. But you probably are two bytes off, I guess.
    Last edited by MK27; 08-14-2009 at 08:33 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  12. #12
    Registered User
    Join Date
    Aug 2009
    Posts
    39
    Quote Originally Posted by MK27 View Post
    I don't understand why it wouldn't then be "0x84234141", tho.
    Read valthyx's post. "\x" is read as two asciis, not as an escape character.
    Last edited by vril; 08-14-2009 at 08:55 AM.

  13. #13
    Registered User
    Join Date
    Oct 2008
    Posts
    1,262
    You can't just use \xXX in input. There are several ways to do it, but easiest is probably to use printf like:
    Code:
    printf "AA....AA\xXX\xXX\xXX\xXX" | ./application
    Which will send the specified input to the application. Printf will fix the hexadecimal values for you. People are right to think that you had two too many A's in the first try. So drop two of them. Then it should jump to the address as you expected.

  14. #14
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by vril View Post
    Read valthyx's post. "\x" is read as two asciis, not as an escape character.
    5c & 78! Is that after you switched to scanf() for the input? Probably that doesn't matter.

    When I did this, I fed the input this way, which will save you writing a C program just to printf()* the data:

    perl -e 'print "AAAAAAA\x80"' | testprog

    Which if you do that (perl -e) without the pipe it does transliterate the hex. Obviously you have to use ascii codes because there is no character for 0x80 and you want a single byte value.

    * [EDIT] sorry I wasn't aware there was a shell version of printf. huh.
    Last edited by MK27; 08-14-2009 at 09:20 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  15. #15
    Registered User
    Join Date
    Aug 2009
    Posts
    39
    Quote Originally Posted by EVOEx View Post
    You can't just use \xXX in input. There are several ways to do it, but easiest is probably to use printf like:
    Code:
    printf "AA....AA\xXX\xXX\xXX\xXX" | ./application
    Which will send the specified input to the application. Printf will fix the hexadecimal values for you.
    Well, this is what I tried at first unsuccessfully and I ended up typing them for simplification.

    Quote Originally Posted by MK27 View Post
    5c & 78! Is that after you switched to scanf() for the input? Probably that doesn't matter.

    When I did this, I fed the input this way:

    perl -e 'print "AAAAAAA\x80"' | testprog

    Which if you do that without the pipe it does transliterate the hex, but you have to use ascii codes because there is no character for 0x80 and you want a single byte value.
    I haven't replaced it with scanf() yet. Maybe I 'll switch to Ubuntu later for one more attempt and to repeat the piping.

Popular pages Recent additions subscribe to a feed