TL;DR if you didn’t test your “off the shelf” web application, then there is a good chance you’ll get hacked.
Had a long break over the Xmas period, during which I set about to improve my use of Burp Suite as a security testing tool for finding security holes in websites.
I tested multiple web applications (all open source). One application was still in development, I sent some fixes to make it do what it should, but it is not included below.
I set out with the aim of finding one significant security hole each day, at which I succeeded (in aggregate at least). The smallest application in the list claims to have 1000 deployments, and had its own internal market for plugins, so this claim seems reasonable.
One was a customer relationship management product (e.g. tracks sales leads) I’d examined before which uses the YII PHP framework 1.1 branch but the version shipped was out of date, one was a real-estate application that uses the current release of the 1.1 branch of the YII PHP framework which was checked to see how it compares. The others were content management systems, CRMs, or specialist business applications, picked largely for being on lists of popular open source software and that I hadn’t previously tested (except for one).
As regards databases, one used SQLite, two used Postgres, and the rest used MySQL (one app had a choice, but Postgres was the default). Several used ORMs of various complexity. None of the applications attempted to have more than one database user.
Only two applications explicitly wanted the bulk of their code installed outside of the web servers document root. The Node.js application was tested using the Express web server built in lacks a concept of document root. The rest of the applications are installed into the web root, meaning for example any included PHP files might be loaded independently.
Eight (almost) random applications tested, of which 3 were found to have exploitable command injection or SQL injection (e.g. it is likely someone could download all the data stored on the server, or worse), although only one of these was exploitable without an account of some kind. The adage that if you see SQL related error messages you can probably get the database held true.
In terms of testing I learnt some practical aspects of using Burp Suite Pro. Couple of occasions I had to save and restore state as my scanning was hitting resource limits (possibly some sort of thread leak), but generally Burp Suite and SQLmap were both impressive. The value of enabling MySQL query logging when looking for SQL injection is obvious in hindsight.
Many of the applications tested used PBKDF2 (or used the PHP password API and got BCRYPT) for password hashing. The message that one round of a high speed hash is not good enough is slowly getting home to software authors. Somewhat concerned that people have cut and pasted PBKDF2 code around the place, and some applications have clearly switched to PHP Password API but not cleaned up what they use to do, but at least the passwords are hashed well.
Whilst all open source several of the applications have commercial companies standing behind them, offering hosted versions, and/or paid support. One piece of software studied and found vulnerable has at least two books about it published. There isn’t enough data to generalise, but in these applications commercial support didn’t help, and could even be negative in this study. (Security doesn’t sell, features sell?!).
It is noted no significant vulnerabilities were found in the non-PHP applications, this plays into my personal biases too strongly for me to be objective here. Of the other languages only Go offers significantly stricter type model, which is my bugbear issue, so my intuition as to why this might be is wrong, perhaps programmer experience? At least one large PHP app had no issues found, although I note the authors of that application did a LOT of work producing the database model (it used an MVC architecture), so something of a swan (paddling furiously under the water whilst progressing majestically). It is not clear the testing was fully framework neutral.
Hundreds of less severe finding are omitted, a fair few can only be exploited in older versions of Internet Explorer (just no….).
Several applications were using CSRF Tokens (although some of those still had CSRF issues), only one application had any sort of attempt to automatically mitigate bad requests switched on out of the box that was potent enough to need switching off for testing (it spotted repeated errors logging in and blocked my IP address). Framework makers, please make that part of your framework.
One SQL injection was assisted in exploitation by the applications being freely available, but I sent patches to two applications who made it easy to send patches (read as use github or similar), availability of the application, not the source code, was a factor in this testing. I didn’t use automated source code inspection tools (I did peek to see how passwords were handled if they didn’t use the standard prefixes ($2y$ etc), nor “Taint” testing, both of which might find more holes when source code is available.
The command injection was found in an application shipping a dependency known to contain a command injection, and tracked in the CVE dictionary (read public). The newer version had been released 17 months before testing took place, there were subsequent less serious vulnerabilities also listed in the CVE for the YII framework, and fixed in the current releases.
Note that the testing won’t find every vulnerability, at least 3 in 8 apps had SQL injection (or worse), there could be more.
The UK government mandate the sort of testing done here against all new websites deployed under “.gov.uk”, seems a necessary but not sufficient condition to ensure confidentiality of data. Private companies would do well to emulate the government in this regard.
SQL Injection, XSS, CSRF are still common enough that other mitigations should be considered when deploying Internet facing applications.
Don’t use old versions of Internet Explorer.
If you use 3rd party code update it when they fix security holes.
My employers, Surevine (“thoughtful advocates of open source” ), supplied software and hardware used in this testing.
Application 1, PHP (YII Framework) and MySQL
I believe I rediscovered CVE-2014-4672 in that I found a command injection in a YII Framework component in version 1.1.13 due to the use of “eval” in PHP. Exploitable by authenticated users only.
The application also had a couple of XSS vulnerabilities, clearly in a section that was added separately.
By shipping older version of YII Framework, the application also include versions of JQuery with known issues, but I didn’t look to see if these were exploitable.
In my view the YII framework should validate its CSRF token on reading it from the cookie, as cookie poisoning would open up more XSS in this, and in application 2.
Application 2, PHP (YII Framework) and MySQL
Having rediscovered an old YII framework bug, I looked at an application with currently maintained version of YII Framework 1.1 branch (which was due to go out of support this Xmas). No issues specific to the YII framework were found other than concern over the aforementioned CSRF cookie.
Found a SQL Injection which was exploitable without authentication.
Found XSS issues on the same parameter, and on unrelated parameter.
This system also stored passwords for users using a function of the form: md5(salt.password.salt.staticString), this allows brute forcing for the static string with known password, and then brute forcing of the other users passwords.
Application 3, Node.js and SQLite
Burp Suite didn’t handle the storage of authentication token in browser local storage automatically, so the testing was more limited, and possibly less effective (perils of black box testing). The relative merits of browser storage versus cookies are interesting, however should be noted than any XSS issue would permit the token to be stolen, something which may be somewhat mitigated with HTTPOnly option on cookies.
No security findings of note.
Application 4, PHP and MySQL
In this application there are two types of users; end users, and admins. I found stored XSS and other issues which could be exploited by admin users, but these users are all trusted (e.g. they could install their own code onto the server by dint of being an admin), as such none of the findings allows any user to escalate their privileges or take information they couldn’t already have. I submitted some patches to stop admins messing up the user interface by accidentally inserting mark-up into the page.
The application also had a section vulnerable to CSRF, but again the results of this were no exploitable.
The application also used 4 remote, and 4 local copies of the JQuery library, all at different versions, loading multiple copies of jQuery is not such an uncommon thing, but this extreme example of the common practice where each included third party component includes or links its own copy of jQuery, does highlight it might create unmaintainable and inefficient website. In this case none of the versions had known security issues.
The overall impression was of luck in not having more major security issues, and in having a relaxed security model where all administrative users have full access to the application.
Application 5, Python and Postgres
This was the largest and most complex of the applications tested.
No serious issues noted, although it was noted the session cookie is not protected with HTTPOnly.
Application 6, PHP and MySQL
No serious issues of note, but application lacks CSRF protection which might make any issues easier to exploit.
Application 7, Golang and Postgres
No issues of note.
Application 8, PHP and MySQL
Found two blind SQL injection vulnerabilities that could be exploited by authenticated users. Both of these were blind SQL injections.
One of the blind SQL injections was in the “ORDER BY” clause, which means it would not be trivially addressable by using parameterised queries.
Interestingly the other one could be detected by SQLmap, but SQLmap was then unable to exploit it, but it is clearly exploitable since one can inject a “SELECT” into a “LIKE” clause.