This Writeup follows the SEED Lab (Lab) and references code supplied in the SEED setup files.
Task 1.a - Understand the process
In order to compile the provided assembly code sample into object C code, we utilise the x86 assembler NASM. The following command accomplishes this:
nasm -f elf32 mysh.s -o mysh.o
To generate the executable binary, we need to link the object C using the LD binary. This will produce a dynamically linked library executable. Execute the following command for this purpose:
ld -m elf_i386 mysh.o -o mysh
It is crucial to ensure that the resulting machine code does not contain any zeroes. Zeroes can cause issues with buffer overflow exploits caused by insecure usage of the strcpy() function. This is because strcpy() interprets a zero as the end of the string. To verify the assembly code, we can employ objdump with the following command:
objdump -Mintel --disassemble mysh.o
To obtain a hexadecimal output of the assembly code, which can be converted into shellcode, we utilise the xxd binary and search for the correct string. Execute the following command: hex dump machine code:
xxd -p -c 20 mysh.o
The provided Python code snippet converts the ori_sh variable into escaped shellcode suitable for injection into a vulnerable binary.
Python ShellCode Converter
|
|
Additional tips:
- Use echo $0 to obtain the current shell binary.
- Use echo $$ to print the PID (Process ID) of the shell.
1.b - Modifying to Execute /bin/bash
To modify the mysh.s code and execute /bin/bash without producing any zeroes in the final shellcode, we need to adjust the push commands to handle the 9-character string properly. We can use a combination of bit shifting and blanking characters to achieve this.
The original mysh.s
|
|
In order to modify the push commands and push “/bin/bash” to the stack, we encounter a complication related to the structure of the push commands. These commands operate in groups of 4 bytes, where each character corresponds to a single byte. Since the string we need to push is 9 characters long, a straightforward approach would result in an unintended outcome:
push "h"
push "/bas"
push "/bin"
The command “push “h” would actually push h000 to the stack, introducing three additional zeros in the final shellcode.
To address this issue, we can employ a workaround that involves writing our string to a registry with blanking characters. By subsequently bitshifting the blanking characters out of the string, any gaps will be filled with zeros in memory without appearing in our shellcode payload.
The comments in the following code snippet demonstrate the value of ebx, which you may observe using a decompiler and running step by step, for example with ghidra:
mov ebx, "h###" ; ebx=0x23232368
shl ebx, 24 ; ebx=0x68000000
shr ebx, 24 ; 0x68
push ebx
push "/bas"
push "/bin"
By employing this approach, we can effectively modify the push commands to push “/bin/bash” to the stack while avoiding unintended zeros in the resulting shellcode.
After tracing the code using Ghidra, it became clear how to achieve the same result by removing a command. The modified code snippet is as follows:
mov ebx, "###h" ; ebx=0x68232323
shr ebx, 24 ; 0x68
push ebx
push "/bas"
push "/bin"
By incorporating these changes (lines 5 to 7) int the original mysh.h, we can create the mysh1b.h.
mysh1b.h
|
|
In order to compile and link the library, the following commands can be used:
nasm -f elf32 mysh1b.s -o mysh1b.o
ld -m elf_i386 mysh1b.o -o mysh1b
After executing the compiled binary and obtaining a new shell, you can verify that you are indeed in a Bash shell by running the command echo $0. This command will display the name of the current shell.
Task 1.c Modifying the Code to Execute ’ls -la’ Using sh
In this task, we will modify the code to utilize execve with the sh command to execute ls -la
. The command /bin/sh -c ls -la
will be called. It is worth noting that redundant slashes are permitted.
First, we construct each part of the argv array and store them as pointers. Before calling execve, we push the pointer to each part onto the stack, terminating with a 0. It is essential that ebx holds a pointer to our command string when ebc is invoked.
mysh1c.h
|
|
By following the above modifications, the code will execute the command ls -la
using the sh shell. The execve system call is utilised to achieve this functionality.
Task 1.d - call /usr/bin/eb with env variables to print
- The task example file is named
myenv.s
- The command to execute is
/usr /bin /env
- We must construct an environment array on the stack with the following elements::
env[3] = 0
env[2] = "cccc=1234"
env[1] = "bbb=5678"
env[0] = "aaa=1234"
- The pointer to the environment array is stored in the edx register. To accomplish this task, we will follow a similar approach as the previous one, but this time we will also construct the environment array. This will provide us with additional registers that we can utilize for this purpose.
myenv.h
|
|
Task 2 - Reviewing the Code: Direct Code Segment Manipulation
In this task, we will carefully examine the provided code line by line, which utilizes direct code segment manipulation. Our first step is to link the library using the ld –omagic command. This command is necessary to enable the code segment to be writable.
nasm -f elf32 mysh2.s -o mysh2.o
ld --omagic -m elf_i386 mysh2.o -o mysh2
./mysh2
Let’s review the code line by line
_start:
- label _startBITS 32
- working in 32 bit landjmp short two
- same module (short) jump to label twoone:
- label onepop ebx
- get top value from the stack which points to/bin/sh*AAAABBBB
and write to ebxxor eax, eax
- writes 0 to eax equivmov [ebx+7], al
- writes lower 8 bits of eax to the memory pointed to at ebx 7 bytes forward. ebx now points to null terminated string/bin/sh
constructing argv[0] and overwriting the *mov [ebx+8], ebx
- writes ebx to the memory pointed to by ebx then 8 bytes forward constructing argv[1] and overwriting the AAAAmov [ebx+12], eax
- writes 0s to the address pointed to by ebx 12 bytes forward, constructing argv[2] and overwriting the BBBBlea ecx, [ebx+8]
- write the memory pointed to by ebx, 8 bytes forward, as a pointer to ecxxor edx, edx
- zeroes off edx - i.e. no env varsmov al, 0x0b
- next two lines invoke exceveint 0x80
two:
- this is only called to get the function address on the stack, so we may use it as reference to the string below, which is directly assigned and never needs to be actually called - it lives in memory simply due to its inclusion on the assembly.call one
db '/bin/sh*AAAABBBB'
Task 2b - call /usr/bin/en using code segment manipulation
In this task, we will modify Task 2 to call /usr/bin/env with a=11 and b=22 loaded using similar memory manipulation techniques. First, let’s reconstruct the argv before addressing the env array.
mysh2b.h with reconstructed argv to /usr/bin/env
|
|
To simplify the process, we will add the environment variables using a new function call:
mysh2b.h with reconstructed argv to /usr/bin/env and environment variables
|
|
In the updated code, we introduce a new label three and call the function four from it. The four function manipulates memory to add the environment variables a=11 and b=22. We zero-terminate both variables and set up the env array accordingly. Finally, we load the necessary pointers and invoke the system call to execute /usr/bin/env with the modified arguments and environment.
The modified code provides a solution to Task 2b, effectively calling /usr/bin/env with a=11 and b=22 loaded through memory manipulation techniques.
Task 3 - Executing /bin/bash in 64-bit Assembly
To compile the code for 64-bit commands, use the following commands:
nasm -f elf64 mysh_64b.s -o mysh_64b.o
ld mysh_64b.o -o mysh_64b
Examining the code, we can see for our purposes this si extremely similar to make the modifcations for as it was for task 1b. We just need to modify line 7 to point to the new binary and perform adjustments to ensure we don’t introduce any 0’s in the final shellcode with the new 9 byte string, keeping in mind 84 bit works in 8 byte segments.
original mysh_64.s
|
|
Now, let’s modify the example according to Task 1b. Our objective is to execute /bin/bash without using any additional forward slashes (”/") and without generating any zeros in the final shellcode.
mysh_643.s
|
|
In the modified code, we have achieved the objective of executing /bin/bash without using additional forward slashes and avoiding the generation of any zeros in the final shellcode.