In the previous post, we saw how we can encode the shellcode with our customized encoding schemes. In this post, we will see how some of the famous shellcodes from the metasploit framework work. We will analyze three different shellcodes using different techniques and tools in this mini shellcode analysis series. In this post, we will examine linux/x86/adduser shellcode with ndisasm and will see how the stuff works behind the scene.

The adduser shellcode adds a specified user to the linux system. Let’s see how we can create this shellcode using msfvenom:

    Let’s copy the shellcode from the ‘shellcode’ file and analyze it using ndisasm as follows:

We have the complete disassembly of the code here:

Having a look at the disassembly, we will see that we have four primary system calls here which are setreuid, open, write and exit system call. I know things may not be clear here and you might be wondering how exactly i can say this? Let’s break the code down and see it ourselves:


xor ecx,ecx
mov ebx,ecx
push byte +0x46
pop eax
int 0x80


Clearing out ECX, we move the obtained 0 to EBX. Next, we put 0x46 in EAX using a PUSH-POP operation. The 0x46 in hexadecimal corresponds to 70 in decimal and denotes setreuid() syscall. The setreuid syscall takes two parameters, i.e., int setreuid(uid_t ruid, uid_t euid); The parameters ruid and euid are real and effective user ids. The setreuid set the real and effective user ids of the current process to the values provided in setreuid. Since we have 0 in EBX and 0 in ECX, this means that setreuid will be called as setreuid(0,0) and 0 corresponds to the user id root.

push byte +0x5
pop eax
xor ecx,ecx
push ecx
push dword 0x64777373
push dword 0x61702f2f
push dword 0x6374652f
mov ebx,esp
inc ecx
mov ch,0x4
int 0x80

The above piece of code puts 0x5 in EAX which is nothing but sys_open(int open(const char *pathname, int flags);)  system call. Next, we clear out ECX and push it to the stack. The value to be pushed into the stack is 0 since we cleared out ECX using XOR operation. The next three instructions put the string /etc//passwd on the stack, and since they are at the top of the stack, we move ESP to EBX. Next, we increment ECX to 1 and then move 0x4 to CH register which is HIGH bytes of CX register. We already have a value in CL which is 1. Therefore, this operation will make the value in ECX as 0x401 which is nothing but a bitmask representing a combination of  O_WRONLY | O_APPEND flags. Using this combination of registers, we will be opening /etc/passwd file in write-only append mode. Upon successful execution, it will return the descriptor for the file. The next two lines exchange the descriptor with EBX register and call
xchg eax,ebx
call dword 0x4e**

Here is the trick of this shellcode. Since we issue a call instruction, the data after the call instruction is pushed onto the stack. Confused? After the call instruction we have:

0000002B  6E                outsb
0000002C  6970756E3A417A    imul esi,[eax+0x75],dword 0x7a413a6e
00000033  627242            bound esi,[edx+0x42]
00000036  334B30            xor ecx,[ebx+0x30]
00000039  7072              jo 0xad
0000003B  52                push edx
0000003C  41                inc ecx
0000003D  59                pop ecx
0000003E  3A30              cmp dh,[eax]
00000040  3A30              cmp dh,[eax]
00000042  3A3A              cmp bh,[edx]
00000044  2F                das
00000045  3A2F              cmp ch,[edi]
00000047  62696E            bound ebp,[ecx+0x6e]
0000004A  2F                das
0000004B  7368              jnc 0xb5
0000004D  0A598B            or bl,[ecx-0x75]

These may look like instructions, but they are not. In fact, this is the data. Let’s analyze it as follows:

From 6E to 68(Second Last Line, 0A is line feed):

6e 69 70 75 6e 3a 41 7a 62 72 42 33 4b 30 70 72 52 41 59 3a 30 3a 30 3a 3a 2f 3a 2f 62 69 6e 2f 73 68

Transforms to:

The above string is the data to be written into the file we opened using SYS_OPEN call. Coming back to the call instruction it will land us at the at the byte 59 (Last line) after 0A:


We can see the value in EIP which points to byte 59. Let’s reconfirm it:

Now, the POP ECX command will put the data to be written into the ECX register, and the next instruction puts the length of this data onto the EDX register. Rest of the code is straightforward it pushes the value 0x4 on the stack and pops it to EAX register. This is nothing but the WRITE system call. This means we have the following arrangement of registers:

EAX: 0x4 Write System Call
EBX: File Descriptor (From the XCHG Operation)
ECX: The data itself
EDX: Length of data

We simply issue the interrupt, and the data gets written to the /etc/passwd file. Next, we just issue an exit system call by putting 0x1 to EAX using a PUSH-POP operation


The shellcode appends the specified user credentials to /etc/passwd file and exits.

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:

Student-ID: SLAE-1080