■ 河南 郭建偉
編者按: 在很多Web應用中,外部可以利用傳參的方式,來指定服務器中的文件名,例如在外界傳入參數時指定一個模版文件名,通過讀取模版文件的內容,將其內容在網頁中展示等。這不可避免的會導致出現一些安全隱患,例如黑客可以非法訪問Web服務器中的文件,來讀取服務器中的敏感文件并展示在網頁中等。黑客甚至還可以執行OS命令注入,在服務器上非法執行各種命令等。
當在Web應用中允許外界以參數的形式來指定服務器上的文件名時,如果沒有對文件名進行充分的校驗,就可能出現文件被非法瀏覽,甚至被惡意修改和刪除等,這其實就是大家常說的目錄遍歷漏洞。
實際上,在網上有很多Web服務器都存在該漏洞,其危害是不可忽視的。該漏洞會泄露服務器中的重要信息,黑客利用該漏洞可以對網頁進行篡改,發布各種惡意信息,利用非法鏈接將用戶誘至預設的惡意網站,對服務器配置文件進行破壞,導致服務器運行異常。
黑客還可能修改重要的腳本文件,在服務器上執行各種惡意操作。可以說,凡是能夠由外界指定文件名的頁面,都可能存在該漏洞,其會對所有頁面產生影響。
對該漏洞進行的防范的要點在于對外界指定的文件名進行嚴格的限制,例如禁止由外界指定文件名,如果必須指定的話,文件名中不能包含目錄名,即只允許外界讀取指定目錄的內容,禁止隨意切換目錄,限制文件名中僅包含字母和數字,這樣外界用戶就無法切換目錄,因為目錄名必須包含斜杠等特殊字符。
對該漏洞進行防御,最根本的策略是避免由外界指定文件名,例如將文件名固定,將文件名保存在會話變量中,不直接指定文件名而使用編號等方法間接指定等。例如,在某網站中存在“”,“
”,“”等語句,來讀取外部指定的模版文件,按照正常情況,當提交了合法的文件名后,就可以從指定的目錄中讀取該文件,將其內容顯示在頁面中。但當攻擊者指定文件名,就會將密碼文件顯示出來,這對系統安全構成了威脅。將上述網頁代碼修改為“”,“if ($ tmp_no ==1)”,“{$tmpl = "1.html"}”,“else”,“{die(' 只支持文件編號!')}”等,根據編號來讀取指定的文件,這樣就避免了上述漏洞。如果必須由外界指定文件名,那么文件名中不能包括目錄名(例如“../”等),就可以盡量降低目錄遍歷漏洞產生的風險。表示目錄 的 字 符 包 括“/”,“”?等,根據系統的不同存在差異。例如將上述程序修改為”等,利用指定函數來讀取傳入文件名,對其分析后得到末尾的文件名。
這樣,即使黑客傳入了非法文件名,其中包含的雜亂信息會被自動過濾,Web程序只得到末尾的文件名,當進行讀取時,只能得到錯誤信息。對傳入文件名的內容進行限制,只允許包含字母和數字,也可以防御該漏洞。
在有些網站中,因為誤操作等原因,在公開目錄中有時可能存儲著對外保密的文件。這樣外界用戶只要知道了文件地址,就可以輕松的瀏覽其內容。為防止出現上述情況,可以采取盡量不要在公開目錄放置敏感文件,對文件設置合適的訪問權限,或者直接禁用目錄列表功能等方法來解決該問題。
如果目錄列表功能沒有被禁用,當使用URL指定目錄名稱時,網頁上會顯示目錄中的所有文件。例如在Web服務器上執行“vim/etc/httpd/conf/httpd.conf”命令,可看到公開目錄信息。在對應的“”等語句中顯示對應公開目錄的屬性信息,其中“xxx”表示目錄名稱,在“Options”欄中應該只包含“Includes ExecCGI FollowSymLinks”內容,而禁止包含“Indexs”字樣,這樣該公開目錄的列表功能就被禁用了。
此外,對公開目錄中的敏感文件名要進行必要處理,例如禁止包含日期、用戶名或連續數值等易于被猜到的內容,避免使用諸如“user.dat”、“data.txt”常用文件名等。關閉錯誤信息顯示功能也可在一定程序上避免暴露敏感文件。例如,在PHP配置文件中輸入“display_errors = off”行,關閉錯誤信息顯示功能。
當然,最根本的方法還是在設計程序時將重要文件存放到安全目錄,在租用服務器時確認可以使用非公開目錄等。
在使用PHP等語言開發Web程序時,在很多情況下需要使用一些系統級的命令來實現某些功能。即通過Shell執行操作系統命令,或者在開發中用到的某個方法時,在其內部會利用Shell來執行OS命令等。
在執行這類操作時,就可能出現操作系統命令被任意執行的問題。例如在網頁中需要發送郵件時,會使用Linux中 的“sendmail”命令來實現。
例如,在某網頁中存在“$mail = $_Post['mail']”、“system("/usr/sbin/sendmail -i 對OS注入漏洞進行分析,可以發現在相關程序內部調用OS命令,多數是通過Shell來啟動命令的。 Shell是用來操作OS的命令行界面,例如Windows中的“cmd.exe”,Linux中的“sh”、“bash”、“csh”等。通過Shell來啟動命令,能夠使得管道命令或者重定向等功能的使用變得更加快捷。但是,Shell提供的遍歷功能有時卻成為了OS注入的根源。 并且Shell提供了一次啟動多個命令的語法,因此,黑客就可能在參數中添加非法內容,在原來命令的基礎上讓其他的命令被隨意執行,這樣OS命令注入就產生了。 在Shell中提供了在一個命令行啟動多個程序的方法,其中OS命令注入就是惡意利用了該特性。在Windows中的“cmd.exe”程序可以利用“&”字符來連續執行多個命令。此外,還可以 使 用“|”、“&&”、“||”等字符來執行連續執行多個命令等。 在Shell中擁有特殊意義的上述字符被稱為元字符,將其作為普通字符使用時需要進行轉義。如果在指定的OS命令參數中的字符串中混入了Shell元字符,就會讓攻擊者非法添加的命令得以順利執行。 而若要產生OS注入漏洞,則必須滿足一些條件,例如包括使用了內部調用的Shell的函數(例如“system”、“open”等),將外界傳入的參數傳遞給內部調用的Shell的函數,參數中的Shell的元字符沒有被轉義等。 為了防御OS注入漏洞,可以使用各種方法靈活應對。例如選擇不調用OS命令的實現方法,即在程序中不通過Shell來調用系統命令。不要將外界輸入的字符串傳遞給命令行參數,使用安全的函數對傳遞來的參數進行轉義等。例如對于上述存在問題的代碼來說,可以不使用系統提供的“senmail”命令來實現,使用PHP提供的“mb_send_mail”函數,也可以實現郵件發送功能。 例如將其修改為“”等語句,來執行郵件發送功能。這樣,就徹底消除了OS注入漏洞的威脅,還消除了調用OS命令的系統開銷,從多個方面提高了應用的性能。 如果必須通過Shell調用OS命令,或者并不了解所使用的函數內部是否使用了Shell的話,那么不將參數傳遞給命令行,是防御OS命令注入的有效對策。例如對于“sendmail”命令來說,可以使用“-t”參數,讓收件人地址不在命令行中指定,而是從郵件的消息頭中讀取。這樣就沒有必要將外界輸入的參數字符串指派給命令行,即消除了OS命令注入漏洞。 例如將上述代碼修改為“ 注意,為了防止郵件頭注入漏洞,這里對用戶輸入的郵箱地址進行了校驗,禁止其包含非法內容。但是,在調用“sendmal”命令時,沒有任何外界傳入的參數,OS命令注入漏洞自然無法成立。 當然,對外界傳入的OS命令的參數進行轉義處理,也可以有效消除OS命令注入漏洞。例如將上述代碼修改為“$mail= $_Post['mail']”、“system("/usr/sbin/sendmail -i OS注入漏洞產生的根源
防御OS注入的對策