Concrete5 Reflected XSS
Posted by Rory M on Thursday, July 25 2019
It’s fun working in this industry. I get paid to break things, like every day. What more could you want?
On a related note, I found myself on a test last week. The client was launching a website, wanted to make sure they weren’t missing anything hilariously obvious. Pretty standard stuff. We did happen to find them leaving a phpinfo file laying around, but that’s besides the point.
I discovered they’re using a CMS called ‘Concrete5’. This was new to me; so, naturally, my ears pricked up. I discovered that it’s open source and actually in fairly wide use (if their website is to be believed..): I decided to dig in with some source code analysis.
Reading through source code can sometimes be quite a pleasant experience. This application is written in PHP. This was not one of those times. Wrapping my head around how requests are routed took me longer than I care to admit, but my trusty sidekicks ripgrep and
echo "<!-- HERE -->"; saved my bacon.
So. I hacked together, printf-debugging style, some routing information. Got my head around how URLs pair up with Controllers and Views. I’ve not dug into Symfony much before and I hope never to again.
After figuring out how to match a URL request to a specific View, I started grepping for some basic
$_GET stuff. It took me a good fifteen minutes to realise Symfony has it’s own wrappers for
$_REQUEST, because REASONS. After adjusting my regex, in one of the views I found this gem:
[..] src="<?= URL::to('/ccm/system/panels/page/preview_as_user/render') . '?&cID=' . Request::request('cID') ?> [..]
Which is a very basic reflected XSS. I spent a bit more time rooting around for an SQL injection or an auth bypass… but other jobs began to clamour for my attention. For fun, here is my printf-debugging patchset.
If anyone finds another XSS with
rg 'Request::(post|get|request)\(' then I claim all credit and I want a share of the bounty.
Vegans offended: 26
Found: 12 July 2019
Reported on hackerone: 15 July 2019
Fixed: 17 July 2019
Bounty received: 0.00 GBP
Time wasted: a lot