本文已首發i春秋論壇ThinkPHP框架 < 5.0.16 sql注入漏洞分析_白帽子技術/思路_i春秋社區-分享你的技術,為安全加點溫度.

0x01 前言

前天在公眾號看到石大神發的一篇審計thinkphp的文章,就想寫一個分析流程,delay到了今天。昨天在先知也看到了chybeta發的一篇分析文章感覺也不錯。分析過程,我也會做thinkphp部分功能的解析。 廢話不多說,開始吧!

0x02 環境搭建和漏洞復現

程序下載地址:thinkphp.cn/down/1126.h PHPstudy:Apache+php5.6+MySQL 工具:PHPstorm

  1. 首先建立一個資料庫名為:thinkphp
  2. 建立一個表名為:user
  3. 添加三個欄位:id,name,password

  1. 在thinkphp的資料庫文件填上剛才我們建立的資料庫信息: 文件位置: hinkphpapplicationdatabase.php

  1. 打開thinkphp的調試模式: 文件位置: hinkphpapplicationconfig.php

  1. 簡單寫一個update功能,石大神用到了模型,這裡就簡單寫一個例子就行了。 文件位置: hinkphpapplicationindexcontrollerIndex.php

<?php
namespace appindexcontroller;

class Index
{
public function index()
{
$password = input(get.password/a);
db(user)->where([id=> 1])->update([password=>$password]);
}
}

這裡用到了thinkphp的助手函數input(),是專用來接收get,post等的值。具體可以看:kancloud.cn/manual/thin

還有就是thinkphp的資料庫操作,框架本身寫好了我們調用就比較方便。所以為什麼那麼多人用框架去開發程序,快捷而且安全,不過也會有安全問題,就像今天這個sql漏洞,不過如果是新手的話總比自己寫的好對吧哈。 具體可以看鏈接:kancloud.cn/manual/thin

7. 現在就可以訪問我們的payload了:

http://thinkphp.test/thinkphp/public/index.php?password[0]=inc&password[1]=updatexml(2,concat(0x7e,user()),0)&password[2]=1

0x03 漏洞分析

  1. 這裡用phpstorm+debug來動態分析,有不懂配置的可以訪問我寫一篇配置文章:利用phpstorm+xdebug進行斷點調試 我們在主函數下一斷點:

然後訪問我們payload,它會跳到入口文件,我們只要分析的是sql執行的地方,所以我們直接F8跳到執行sql地方:

2. 我們繼續跟進到loader.php它會包含thinkphp的Db.php文件,

接下還會包 hinkphplibrary hinkdbconnectorMysql.php文件,主要是連接資料庫的操作,這裡就直接跳過了。別分析分析把自己繞進去了,我只是在這裡講訴下過程,我們還是直接分析sql執行的部分吧。 3. 我們跳到update執行的部分,文件位置: hinkphplibrary hinkdbQuery.php

繼續往下看,這句是執行我們sql的地方:

4. 我們F7跟進去,跳到文件位置 hinkphplibrary hinkdbBuilder.php parseTable函數直接F8往下執行了,這函數是處理table分析的,主要還是parseData函數,我們繼續F7跟進

5. 我們繼續往下跟進

我們看到了這裡如果傳入的值為數組形式的話,並且第一個參數為inc就執行switch所對應的的語句。

可以看到這裡函數對我們傳入的值沒有做任何處理,返回內容仍然是我們的語句:

跟到後面返回的執行sql語句:

執行完,我們跟進到報錯的地方,說明我的語句執行成功:

6.到這裡就差不多結束了,有人問,為什麼要這樣給數組三個欄位? 我們可以看到我們剛才傳入數組的地方,分別有三個數組

到後面返回$result的時候就組合在一起了:

下面是parseData的代碼:

protected function parseData($data, $options)
{
if (empty($data)) {
return [];
}

// 獲取綁定信息
$bind = $this->query->getFieldsBind($options[table]);
if (* == $options[field]) {
$fields = array_keys($bind);
} else {
$fields = $options[field];
}

$result = [];
foreach ($data as $key => $val) {
$item = $this->parseKey($key, $options);
if (is_object($val) && method_exists($val, __toString)) {
// 對象數據寫入
$val = $val->__toString();
}
if (false === strpos($key, .) && !in_array($key, $fields, true)) {
if ($options[strict]) {
throw new Exception(fields not exists:[ . $key . ]);
}
} elseif (is_null($val)) {
$result[$item] = NULL;
} elseif (is_array($val) && !empty($val)) {
switch ($val[0]) {
case exp:
$result[$item] = $val[1];
break;
case inc:
$result[$item] = $this->parseKey($val[1]) . + . floatval($val[2]);
break;
case dec:
$result[$item] = $this->parseKey($val[1]) . - . floatval($val[2]);
break;
}
} elseif (is_scalar($val)) {
// 過濾非標量數據
if (0 === strpos($val, :) && $this->query->isBind(substr($val, 1))) {
$result[$item] = $val;
} else {
$key = str_replace(., _, $key);
$this->query->bind(data__ . $key, $val, isset($bind[$key]) ? $bind[$key] : PDO::PARAM_STR);
$result[$item] = :data__ . $key;
}
}
}
return $result;
}

0x04 結束

如果看不懂的,可以先去了解一下thinkphp這個框架,其他框架大同小異。如果裡面一些PHP代碼看不懂的話,可以去複習下PHP。

0x05 參考

kancloud.cn/manual/thin

mp.weixin.qq.com/s?

chybeta.github.io/2018/


推薦閱讀:
相關文章