命令注入:
是指通過提交惡意構造的參數破壞命令語句結構,從而達到執行惡意命令的目的。
在Web應用中,有時候會用到一些命令執行的函數,如php中system、exec、shell_exec等,當對用戶輸入的命令沒有進行限制或者過濾不嚴導致用戶可以執行任意命令時,就會造成命令執行漏洞。
命令注入漏洞主要表現為以下兩種形式:
1、攻擊者能夠算改程序執行的命令:攻擊者直接控制了所執行的命令。
2、攻擊者能夠復改命今的執行環境:攻擊者
間接控制了所執行的命令。
在這種情況下,我們
着重關注第一種情況,即攻擊者控制所執行命令的可能性。這種形的 Command Injection漏洞在以下情況下發生:
1.數據從不可信賴的數據源進入應用程序
2.數據被用作代表應用程序所執行命令的字符串,或字符串的部分
3.通過命令的執行,應用程序會授予攻擊者一種原本不該擁有的特權或能力
例1:下面這段來自系統實用程序的代碼根據系統屬性 APPHOME 來決定其安裝目錄,然后根據指定目錄的相對路徑執行一個初始化腳本。
... String home= System. getProperty( "APPHOME"); String cmd = home + INITCMD; java.lang Runtime. getRuntme( exec(cmd));//執行操作命令 ...
例1中的代碼使得攻擊者可通過修改系統屬性 APPHOME而指向一個包含惡意版本 INITOMD的其他路徑,從而提高自己右應用程序中的權限,繼而隨心所欲地執行命令。
由於程序不會驗證
從環境中讀取的值,所以如果攻擊者能夠控制系統屬性 APPHOME的值,他們就能耗應用程序去運行惡意代碼從而取得系統控制權。
例2:下面的代碼來自一個管理web應用程序,旨在使用戶能夠使用一個圍繞rman實用程序的批處理文件封裝器來啟動 Oracle數據庫備份,然后運行一個 clearup.bat.腳本來刪除一些臨時文件。
腳本 manDB.bat接受單個命令行參數,該參數指定了要執行的備份類型。由於訪間數據庫受限,所以應用程序執行備份 需要具有較高權限的用戶。
... Sting btype = request.getparameter("backuptype"); Sting cmd= new Strng("cmd. exe /K \'c: \util\\ramnDB.bat "+btype+" &&c:\\util\\clearup.bat\"") System. Runtime. getRuntime().exec(cmd); ...
這里的問題是:程序沒有對
讀取自用戶的 backtype參數做任何驗證,通常情況下 Runtime,exec()函數不會執行多條命令,但在這種情況下,程序會首先運行 cmd.exe shell,從而可以通過調用一次Runtime.exec()來執行多條命令。一且調用了該shell,它即會允許執行用兩個與號分的多條命令。
如果攻擊者傳了一個形式為 "&&c:\\dbms\\*.*”的字符串,那么應用程序將隨程序指定的其他命令起執行此命令。由於該應用程序的特性,運行該應用程序需要具備與數庫進行交互所需的權限,這就意味着攻主者注入的任何命令都將道過這些權限得以運行。
例3:下面的代碼來自於一個web應用程字,該應用程序就允許用戶訪問一個可在系統中更新用戶密碼的接口,在特定的網絡環境中更新密碼時,其中的一個步驟就是在/var/yp 目錄中運行 make命令,下面顯示了此步驟的代碼:
... System. Runtime. getRuntime().exec(make); ...
這里的問題在於程序沒有在的構造中指定一個
絕對路徑,並且沒能在執行 Runtime. exeo()調用前清除它的環境變量。如果取擊者能夠修改&path變量,把指向名為make惡意二制代碼,程序就會在其指定的環境下執行,然后加載該惡意二進制代碼,而非原本期理的代碼,由於應用程字自身的特性,運行該應用程序要具備執行系統操作所需的權限,這意味着攻擊者會利用這些權限執行自己的make,從而可能導致攻擊者完全控制系統。
例4:以下代碼可從 Android Intent中讀取要執行的命令
... String[] cmds= this.getIntent().getstringArrayExtra("commands"); Process p= Runtime. getRuntime(exec("su")); DataOutputStream os = new DataOutputStream(p.getOutputStream()); for (String cmd: cmds){ os.wnteBytes(cmd+"\n"); } os.writeBytes("ext\n"); os.flush();
經過root的設備上,惡意應用程序會強迫受取擊應用程序使用超用戶權限執行任意命令。
修復建議:
應當禁止用戶直接控制由程序執行的命令。在用戶的輸入會影響命令執行的情兄下,應將用戶輸入限制為從預定的安全命令集合中進行選擇。如果輸入中出現了惡意的內容傳遞到命令執行函數的值將默認從安全命令集合中選擇,或者程序將拒絕執行任何命令。
在需要將用戶的輸入用作程序命令中的參數時,由於合法的參數集合實在很大,或是難以跟蹤,使得這個方法通常都不切實際。開發者通常的做法是
使用黑名單。在輸入之前,黑名單會有選擇的拒絕或避免潛在的危險字符。但是,任何個定義不安全內容的列表都很可能是不完整的,並且會嚴重地依賴於執行命令的環境。
更的方法是組建一份白名單,允許其中的字符出現在輸入中,並只接受完全由這些經認可的字符組成的輸入。
攻擊者可以通過修改程序運行命令的環境來間接控制這些命令的執行。
我們不應當完全信賴環境,還需采取預防指施,防止攻擊者利用某些控制環境的手段進行攻擊。
無論何時,只要有可能,都應由用程序來控制命令,並使用絕對路徑執行命令。如果編譯時尚不了解路徑(如在跨平台應用程序中),應該在執行過程中利用可信賴的值構建一個絕對路徑。應對照一系列定義有效值的常量,
仔細的檢查從配置文件或者環境中讀取的命令值和路徑。
有時還可以執行其他檢驗,以檢查這些來源是否已被惡意篡改。例如,如果一個配置文件為可寫,程序可能會拒絕運行。如果能夠預先得知有關要執行的人進制代碼的信息,程序就會進行檢測,以檢驗這個二進制代碼的合法性。
如果個二進制代碼始終屬於某個特定的用戶,或者被指定了一組特定的訪問權限,這些屬性就會在執行二進制代碼通過程序進行檢驗。
盡管可能無法完全阻止強大的攻擊者為了控制程序執行的命令而對系統進行的攻擊,但只要程序執行外部命令,就務必使用最小授權原則:不給予超過執行該命令所必需的權限。
代碼參考
如下的代碼案例中,獲取路徑的值是從本地的屬性文件當中獲取,本人覺得已經寫得很好啦,
但按照
修復建議 如上,要求即使是從本地屬性文件獲取的值 也要 “
仔細的檢查從配置文件或者環境中讀取的命令值和路徑”,要求很吹毛求疵啦,
如果可以 也可以增加 對輸入值的過濾與限制。
TestController.java
//拿PDF轉換案例舉例 代碼如下
... //調用 openoffice服務線程 String sofficePath= PropertiesUtil. getValue("sofficePath"); String openofficeport= Propertiesutil. getvalue("openofficeport"); ...
... String command = sofficePath +"-headless -accept=\"socket,host=127.0.0.1, port="+ openofficeport+ ";urp; \"-nofirststarwizard"; ps = Runtime.getRuntime().exec( command); ...
PropertiesUtil.java
//屬性文件 WEB-INF/properties 對象 private static Properties aosConfigProp = new Praperties(); static{ //初始加載properties文件 InputStream in=null; try{ String webinfPatH = HttpUtil.getAbsolutePath("WEB-INF"); String fileName = webInfPath+File.separator +"properties"; File file = new File(fileName); if (!file.exists()){ logger.error(webInfPath. concat(“目錄下無propertie配置文件"); }else { in= new FileInputStream(file); aosConfigProp.load(in); } }catch (Exception e) t logger.error(”獲取MEB-INF/ properties配置文件信息異常",e); }finally{ if(in!=null){ try{ in.close(); }catch (IOException e){ // TODO Auto-generated catch block e.printstackTrace(); } } } } //獲取指定參數 public static String getvalue(String name){ return aosConfigProp.getProperty(name,""); }