SQL Injection exists in the ThinkPHP framework architecture

Source: Internet
Author: User
Tags mongodb injection

SQL Injection exists in the ThinkPHP framework architecture

Many people believe that SQL injection can be perfectly avoided without splicing SQL statements by using the database query method provided by the framework. Then you are wrong. Sometimes the framework becomes the person who brings you into the trap.


We open the latest thinkphp framework documentation, where "expression query" Chapter: http://document.thinkphp.cn/manual_3_2.html#express_query
 



WTF: If the where statement is an array and the first value of the array is 'exp ', then the second value can be directly written into the SQL statement?

WTF, isn't it a perfect SQL injection?

Some may not understand. To be more specific, many webmasters write query statements like this:

$data = array();$data['user'] = $_POST['username'];$data['pass'] = md5($_POST['password']);M('user')->where($data)->find();



This should be a basic method for ThinkPHP to query databases. If the input parameters are as follows:

Username [0] = exp & username [1] = aa 'or 1 = 1% 23 & password = 1, is it a perfect universal password?

This feature exists in thinkphp3.1 and 3.2, and is widely used and harmful.



Some may find some limitations, because the thinkphp I function has the following code:

} Elseif (isset ($ input [$ name]) {// value operation $ data = $ input [$ name]; is_array ($ data) & array_walk_recursive ($ data, 'filter _ exp '); $ filters = isset ($ filter )? $ Filter: C ('default _ filter'); if ($ filters) {if (is_string ($ filters) {$ filters = explode (',', $ filters);} elseif (is_int ($ filters) {$ filters = array ($ filters);} foreach ($ filters as $ filter) {if (function_exists ($ filter) {$ data = is_array ($ data )? Array_map_recursive ($ filter, $ data): $ filter ($ data); // parameter filtering} else {$ data = filter_var ($ data, is_int ($ filter )? $ Filter: filter_id ($ filter); if (false ===$ data) {return isset ($ default )? $ Default: NULL; }}}} else {// default value of the variable $ data = isset ($ default )? $ Default: NULL ;}



Is_array ($ data) & array_assist_recursive ($ data, 'filter _ exp '); There is a simple filter. Let's look at the filter_exp function:

function filter_exp(&$value){    if (in_array(strtolower($value),array('exp','or'))){        $value .= ' ';    }}



A space is added after exp. However, there are several serious problems:

1. filter_exp is before the fiter of the I function, so if the developer writes I ('get. school ', '', 'trim'), the space after exp is cleared directly, leading to invalid filtering. This writing method is quite common, including I often write it like this.

II. In the MVC Architecture of thinkphp, the Controller function variables are also used as the method for passing parameters through GET/POST, such as http: // serverName/index. php/Home/Blog/archive/year/2013/month/11 we can access public function archive ($ year = '20160901', $ month = '01 '). This URL can also be written as http: // serverName/index. php? C = Blog & a = archive & year = 2013 & month = 11, you can also enter http: // serverName/index. php? C = Blog & a = archive & year = 2013 & month [0] = exp & month [1] = sqli

This is an example in the document: Example. The OneThink in the vulnerability proof is injected for this reason.

III. The old thinkphp version does not use the I function to obtain variables, but the exp feature does exist all the time. In thinksns, the variable value obtained by using $ _ POST [xxx] directly, so this security risk will always exist. I also found instance verification in Thinksns.

 

OneThink is a self-developed Content Management System of ThinkPHP, which facilitates developers to perform secondary development.

After installation, you can directly POST the following data packets to the background logon location to find an error (for convenience, I commented on the verification code check section. In actual operations, I can send a data packet with the verification code ):

 



Database username exposed:
 



The reason is that we can see the code in login,/Application/Admin/Controller/PublicController. class. php:

Public function login ($ username = null, $ password = null, $ verify = null) {if (IS_POST) {/* Check the verification code TODO: */if (! Check_verify ($ verify) {// $ this-> error ('verification code input error! ');}/* Call the UC logon interface to log on */$ User = new UserApi; $ uid = $ User-> login ($ username, $ password ); if (0 <$ uid) {// UC logon succeeded/* logon user */$ Member = D ('member '); if ($ Member-> login ($ uid) {// logon user // TODO: Jump to the pre-Logon page $ this-> success ('logon successful! ', U ('index/Index');} else {$ this-> error ($ Member-> getError ());}} else {// logon Failure switch ($ uid) {case-1: $ error = 'the user does not exist or is disabled! '; Break; // disable case-2: $ error = 'incorrect password! '; Break; default: $ error =' Unknown error! '; Break; // 0-interface parameter error (used during debugging)} $ this-> error ($ error) ;}} else {if (is_login ()) {$ this-> redirect ('index/Index');} else {/* read Database Configuration */$ config = S ('db _ CONFIG_DATA '); if (! $ Config) {$ config = D ('config')-> lists (); S ('db _ CONFIG_DATA ', $ Config);} C ($ config ); // Add configuration $ this-> display ();}}}



After obtaining $ username and $ password, input the login function and follow up:

public function login($username, $password, $type = 1){        return $this->model->login($username, $password, $type);    }



Input the $ this-> model-> login function to follow up:

Public function login ($ username, $ password, $ type = 1) {$ map = array (); switch ($ type) {case 1: $ map ['username'] = $ username; break; case 2: $ map ['email '] = $ username; break; case 3: $ map ['mobile'] = $ username; break; case 4: $ map ['id'] = $ username; break; default: return 0; // parameter error}/* Get user data */$ user = $ this-> where ($ map)-> find (); if (is_array ($ user) & $ user ['status']) {/* Verify the user password */if (think_ucenter_md5 ($ password, UC_AUTH_KEY) ===$ user ['Password']) {$ this-> updateLogin ($ user ['id']); // update user logon information return $ user ['id']; // login successful, returned user ID} else {return-2; // incorrect password} else {return-1; // the user does not exist or is disabled }}



As I mentioned earlier, the where statement is directly included. So we only need to make username an array, the first value is exp, and the second value is the injection statement.

This injection of thinkphp is similar to mongodb injection. Although it is in the Framework, injection is generated due to unreasonable framework design.

Solution:Enhanced Filtering

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.