This blog post has been created for completing the requirements for the SecurityTube Linux Assembly Expert certification: http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert
Student ID: SLAE-824
Requirements
- Choose at least 3 shellcode samples created using Msfvenom for linux/x86
- Use GDB/Ndisasm/Libemu to dissect the functionality of the shellcode
- Present your analysis
Source code for this assignment can be found here
Analysis
The next shellcode I would like to look at is linux/x86/adduser. My prediction
for this shellcode is that it essentially just runs execve with
/usr/sbin/adduser
and the arguments that it would require. Lets analyze the
assembly to find out!
Running:
We see:
The username and password both default to metasploit
and
the shell the user will be assigned will be /bin/sh. We will
most likely find these values as arguments to execve if our
prediction is correct. Lets export the shellcode:
Running msfvenom --payload linux/x86/adduser R > adduser.bin
we
create our shellcode to analyze. Using ndisasm -u adduser.bin
we get
the following assembly for analysis:
/linux/x86/adduser Shellcode ASM
As illustrated in the comments, the above chunk of assembly sets the real and effective user id of of the process to be 0 which elevates the privileges.
The next chunk of assembly calls open. This opens the /etc/passwd
file with the flags of 0x0401. What does 0x0401 stand for? Well,
looking in /usr/include/asm-generic/fcntl.h
we see:
The values specified in this header file are defined in octal. Our assembly is using hex so we do a bit of conversion using gdb:
This tells us that our hex value actually equals 02001 in octal of which doing 00000001 | 00002000 = 00002001 or O_WRONLY | O_APPEND. This indicates that we have opened the file for reading and writing and in append mode. This will ensure that the cursor is placed at the end of the file.
The next chunk of code gets interesting. We need the memory offsets to help us a bit:
The xchg is our usual saving of the file descriptor
returned in eax. We then see a call dword 0x53
and then
things start to get messy. We know about the jump call pop
technique from our SLAE course, maybe this call is leveraging
the fact that the next address will be popped on the stack. Looking
at the offsets in our disassembly and checking out the bytes from
0x53 on, we see 59 8B 51 fC 6A 04 58 CD 80
. Leveraging this
wonderful online https://defuse.ca/online-x86-assembler.htm#disassembly2
we learn what those bytes represent:
Sure enough the address of the next instruction that was placed on the stack
from our call
instruction is popped into ecx. An offset from that value
is placed in edx which we will need to investigate a bit and then the
0x4 system call. Looking in /usr/include/i386-linux-gnu/asm/unistd_32.h
we see
that this is #define __NR_write 4
.
This makes sense. We just opened the /etc/passwd file and now we want to add stuff to it. The write syscall signature looks like:
This means edx is the length of what is being written, ecx is the string we want to write, ebx is the file descriptor to /etc/passwd and eax is our write sys call number. So what would that offset from ecx equate to? Zooming in on those bytes:
Moving backward 4 bytes from the 0x6D puts us at 0x28. This is the value that is being used as the length of the buffer in the write syscall.
Converting 0x28 to decimal using gdb:
We see that 40 bytes is going to be written. Using GDB again: Note: 0x2B is the beginning of the gibberish, 0x28 is the 40 bytes we just calculated.
We see that 0x53 is 40 bytes after our call instruction and is exactly the byte that was referenced in the call command:
Ok… Lets checkout the bytes of that gibberish and see what they might translate to as ascii:
Ok. That makes sense. This is the line that will be appended to the /etc/passwd
file in the format that linux would expect, e.g
username:passwd:UID:GID:full_name:directory:shell
. The user, shell, and
presumably password all match up with the configuration that the payload
defaults to.
Finally we call exit to exit gracefully. So it turns out that my prediction was
completely inaccurate. Execve was not used to execute the adduser
command.
¯\(ツ)/¯