Skip to content

Commit

Permalink
Implement Exploit::Remote::LDAP::Server
Browse files Browse the repository at this point in the history
In order for Framework to properly utlize Rex' internal services,
they should be exposed into the namespace using a ServiceManager
instance. Concurrently, called options need to be presented as
configurable to modules mixing in the Ruby module.

This commit implements the Exploit::Remote::LDAP::Server namespace
with options for the TCP & UDP services along with an optional path
for reading an LDIF file like the one provided in the testserver
directory of the net-ldap source tree.

Testing: None

TODO:
  Test the code
  Integrate into @zeroSteiner's efforts
  • Loading branch information
RageLtMan committed Dec 15, 2021
1 parent 37db90b commit 9fc6e40
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 1 deletion.
127 changes: 127 additions & 0 deletions lib/msf/core/exploit/remote/ldap/server.rb
@@ -0,0 +1,127 @@
# -*- coding: binary -*-

module Msf

###
#
# This module exposes methods for querying a remote LDAP service
#
###
module Exploit::Remote::LDAP
module Server
include Exploit::Remote::SocketServer

#
# Initializes an exploit module that serves LDAP requests
#
def initialize(info = {})
super

register_options(
[
OptPort.new('SRVPORT', [true, 'The local port to listen on.', 389]),
OptPath.new('LDIF_FILE', [ false, "Directory LDIF file path"]),
], Exploit::Remote::LDAP::Server
)

register_advanced_options(
[
OptBool.new('LdapServerUdp', [true, "Serve UDP LDAP requests", true]),
OptBool.new('LdapServerTcp', [true, "Serve TCP LDAP requests", true])
], Exploit::Remote::LDAP::Server
)
end

attr_accessor :service # :nodoc:

#
# Read LDIF file - from net-ldap ldapserver.rb#L162
#
# @ return [Hash] parsed ldif file
def read_ldif
if File.exists?(datastore['LDIF_FILE'])
ary = File.readlines(datastore['LDIF_FILE'])
ldif = {}
while (line = ary.shift) && line.chomp!
if line =~ /^dn:[\s]*/i
dn = $'
ldif[dn] = {}
while (attrib = ary.shift) && attrib.chomp! && attrib =~ /^([\w]+)[\s]*:[\s]*/
ldif[dn][$1.downcase] ||= []
ldif[dn][$1.downcase] << $'
end
end
end
return ldif
else
nil
end
end

#
# Handle incoming requests
# Override this method in modules to take flow control
#
def on_dispatch_request(cli, data)
service.default_dispatch_request(cli,data)
end

#
# Handle incoming requests
# Override this method in modules to take flow control
#
def on_send_response(cli, data)
cli.write(data)
end

#
# Starts the server
#
def start_service
begin
comm = _determine_server_comm(datastore['SRVHOST'])
self.service = Rex::ServiceManager.start(
Rex::Proto::LDAP::Server,
datastore['SRVHOST'],
datastore['SRVPORT'],
datastore['LdapServerUdp'],
datastore['LdapServerTcp'],
read_ldif,
comm,
{'Msf' => framework, 'MsfExploit' => self}
)

self.service.dispatch_request_proc = Proc.new do |cli, data|
on_dispatch_request(cli,data)
end
self.service.send_response_proc = Proc.new do |cli, data|
on_send_response(cli,data)
end
self.service.start

rescue ::Errno::EACCES => e
raise Rex::BindFailed.new(e.message)
end
end

#
# Stops the server
# @param destroy [TrueClass,FalseClass] Dereference the server object
def stop_service(destroy = false)
Rex::ServiceManager.stop_service(self.service) if self.service
if destroy
self.service = nil if self.service
end
end

#
# Resets the LDAP server
#
def reset_service
stop_service(true)
start_service
end

end
end
end
1 change: 0 additions & 1 deletion lib/rex/proto/ldap/server.rb
Expand Up @@ -61,7 +61,6 @@ def write(data)
# @return [Rex::Proto::LDAP::Server] LDAP Server object
attr_reader :serve_udp, :serve_tcp, :sock_options, :udp_sock, :tcp_sock, :syntax, :ldif
def initialize(lhost = '0.0.0.0', lport = 389, udp = true, tcp = true, ldif = nil, comm = nil, ctx = {}, dblock = nil, sblock = nil)

@serve_udp = udp
@serve_tcp = tcp
@sock_options = {
Expand Down

0 comments on commit 9fc6e40

Please sign in to comment.