Got bored and decided to break the new website of the company I work for.
Throughout I'll be dropping two new exploits that were chained to allow the
changing of the administrative password of a default mod-x install. This is
not a full review of mod-x, my main goal was just to break something, so I
went with the first exploit I found.
If you know me, you know I don't disclose unless you can exploit without
user interaction. However, I thought it was a cool writeup on how security
mechanisms were bypassed that I thought I would share.
Did not discover much input that can be manipulated until I ran across a
modx extension called ditto. Through ditto, I was able to discover a full
path disclosure:
http://www.victim.com/archives?myDittoCall_year=2009&myDittoCall_month=false&myDittoCall_day=false&myDittoCall_start[]=0
Error message:
« MODx Parse Error »
MODx encountered the following error while attempting to parse the requested
resource:
« PHP Parse Error »
PHP error debug
Error: htmlspecialchars() expects parameter 1 to be string, array
given
Error type/ Nr.: Warning - 2
File: /var/www/vhosts/
victim.com/httpdocs/assets/snippets/ditto/classes/ditto.class.inc.php
Line: 1077
Line 1077 source: $query[htmlspecialchars($param, ENT_QUOTES)] =
htmlspecialchars($value, ENT_QUOTES);
Parser timing
MySQL: 0.0022 s (19 Requests)
PHP: 0.1612 s
Total: 0.1633 s
Effected Code (even though error is pretty verbose):
foreach ($_GET as $param=>$value) {
if ($param != 'id' && $param != 'q') {
$query[htmlspecialchars($param, ENT_QUOTES)] =
htmlspecialchars($value, ENT_QUOTES);
}
}
First things first, htmlspecialchars with ENT_QUOTES seems to be messing
with all of our injections. No charset appears to be specified, let's take
a look at their default charset, perhaps one was specially set.
UTF-8 is default charset, no special reflective injection point.
However, we do have a full path disclosure and we now know that
victim.comis running modx, let's go download that!
*After fscking around, found that they use Evolution and not Revolution
version of mod-x*
http://www.victim.com/manager/ - Our login entry point.
Looks like there's no nonce checking so csrf is a viable option after some
modification. First, let's acquire some sort of username we can use to
manipulate/create users (or something of equal fun).
http://www.victim.com/manager/index.php?action=show_form
Very nice! The forgot password form is happy to verify if the user exists
via the email or not. Good chances that the email will be user@victim.com.
This information can be used to advance our attack.
After a lot of looking around and guessing names I finally ran across a
valid user by looking around the site for contact emails and other
usernames. Turns out it was a marketing person (+1 SE aid).
After finding a valid user email, I was able to now work on crafting the
exploit and using spear social engineering to exponentially increase the
likelihood of an attack (spear phishing is very successful).
Now, there are all sorts of valid CSRF around. However, we have a problem.
victim.com/manager/index.php checks referrers. index.php includes/requires
the actions that we want to have fun with.
a.) Attack vector 1: See how strenuous the checks are for the referrer.
Possibly attack a hosted sub-domain or another application (blog? Open
source apps seem to work together.).
if (!empty($referer)) {
if (!preg_match('/^'.preg_quote(MODX_SITE_URL, '/').'/i',
$referer)) {
b.) Attack vector 2: Find a CSRF outside of index.php or directly access
included/required files so referrer check is never executed. Problem is
direct includes don't work on most of the fun scripts because of:
if (IN_MANAGER_MODE != "true")
die("INCLUDE_ORDERING_ERROR
Please use the MODx
Content Manager instead of accessing this file directly.");
c.) Attack vector 3: Somehow get the script on the site. Not likely
otherwise this would probably never be needed.
d.) Attack vector 4: Find an xss to reflect a self-submitting form.
However, protect.inc.php seems to have basic xss protection and is included
in most scripts.
'@@si',
'@(\d+);@e',
'@\[\[(.*?)\]\]@si',
'@\[!(.*?)!\]@si',
'@\[\~(.*?)\~\]@si',
'@\[\((.*?)\)\]@si',
'@{{(.*?)}}@si',
'@\[\+(.*?)\+\]@si',
'@\[\*(.*?)\*\]@si'
After a bit of digging around (<30 minutes) in the scripts, I found a simple
injection point in /manager/media/ImageEditor/editor.php.