輸入驗證和表示法問題是由中繼字元、替代編碼和數值表示法引起的。信任輸入會導致安全問題。問題包括:「Buffer Overflows」、「Cross-Site Scripting」攻擊、「SQL Injection」及其他許多問題。
send
函數及其變體允許程式設計師修改針對函數的 Ruby 存取規範。特別是,程式設計師可藉此存取通常不允許的私人和受保護的欄位、函數和行為。paramName
URL 參數的任何轉換或驗證。
...
<bookmark>
<method>#{paramHandler.handleParams}</method>
<url-parameter>
<name>paramName</name>
<value>#{requestScope.paramName}</value>
</url-parameter>
</bookmark>
...
userClassPath
來決定搜尋要載入的類別所在的目錄。
...
productCategory = this.getIntent().getExtras().getString("userClassPath");
DexClassLoader dexClassLoader = new DexClassLoader(productCategory, optimizedDexOutputPath.getAbsolutePath(), null, getClassLoader());
...
userClassPath
的結果來指向所控制的其他路徑,從而讓攻擊者利用應用程式的提升權限,載入程式庫並潛在地執行任意程式碼。因為程式不會驗證從環境讀取的值,所以如果攻擊者可以控制 userClassPath
的值,則攻擊者便可使用與原始應用程式相同的權限,愚弄應用程式,讓應用程式指向他們所控制的目錄,從而載入他們所定義的類別。userOutput
來決定應寫入最佳化 DEX 檔案的目錄。
...
productCategory = this.getIntent().getExtras().getString("userOutput");
DexClassLoader dexClassLoader = new DexClassLoader(sanitizedPath, productCategory, null, getClassLoader());
...
userOutput
值變更為他們所控制的目錄,如外部儲存裝置。一旦完成竄改,便只需將輸出的 ODEX 檔案替換為惡意 ODEX 檔案,就可以使用與原始應用程式相同的權限執行該動作。ModelState.IsValid
檢查模型是否通過驗證。class.classLoader
的特別 bean 屬性,這些屬性允許攻擊者取代系統屬性,並可能執行任意程式碼。
String prop = request.getParameter('prop');
String value = request.getParameter('value');
HashMap properties = new HashMap();
properties.put(prop, value);
BeanUtils.populate(user, properties);
strncpy()
的範圍函數,使用不正確時也會引起弱點。大多數 Buffer overflow 弱點的根本原因,都是緩衝區的處理,加上對資料的大小或組成假設錯誤。gets()
函數,將一個任意長度的資料讀取到堆疊緩衝區。因為沒有什麼方法可以限制這個函數讀取的資料量,所以使用者輸入的字元數必須少於 BUFSIZE
,以確保程式碼的安全性。範例 1.b:此範例顯示只要使用
...
char buf[BUFSIZE];
gets(buf);
...
>>
運算子將輸入讀取到 char[]
字串中,即可輕易模仿 C++ 中 gets()
函數不安全的運作方式。範例 2:雖然這個範例中的程式碼也是依賴於使用者的輸入來控制它的運作方式,但是它會藉由使用邊界記憶體複製函數
...
char buf[BUFSIZE];
cin >> (buf);
...
memcpy()
增加一個間接的層面。此函數接受目的緩衝區、來源緩衝區,以及要複製的位元組數量。輸入緩衝區由 read()
的範圍呼叫所填滿,但使用者指定 memcpy()
要複製的位元組數量。
...
char buf[64], in[MAX_SIZE];
printf("Enter buffer contents:\n");
read(0, in, MAX_SIZE-1);
printf("Bytes to copy:\n");
scanf("%d", &bytes);
memcpy(buf, in, bytes);
...
lccopy()
的函數將一個字串做為引數讀取,然後將這個字串中所有的大寫字母轉化成小寫字母回傳一個堆疊分配的字串副本。這個函數不會對其輸入執行範圍檢查,因為程式預期 str
始終小於 BUFSIZE
。如果攻擊者避開對呼叫 lccopy()
的程式碼的測試,或者,如果程式碼有什麼變化,使得關於 str
長度的假設失真,那麼 lccopy()
就會在 strcpy()
超出邊界的呼叫過程中溢位 buf
。範例 4:下列程式碼示範了第三種情況,其中程式碼太過複雜以致無法輕易預測其行為。這段程式碼來自於主流的 libPNG 圖像解碼器,此解碼器廣泛用於多種應用程式。
char *lccopy(const char *str) {
char buf[BUFSIZE];
char *p;
strcpy(buf, str);
for (p = buf; *p; p++) {
if (isupper(*p)) {
*p = tolower(*p);
}
}
return strdup(buf);
}
png_crc_read()
複製的資料量。不過,在測試長度之前,程式碼會立即對 png_ptr->mode
執行檢查。檢查失敗時,系統會發出警告,而處理會繼續執行下去。由於 length
會在一個 else if
區塊中進行測試,所以當第一個檢查失敗時,就不會測試 length
;且在呼叫 png_crc_read()
期間對其的盲目使用易引發堆疊 Buffer overflow。範例 5:此範例同樣證明了第三種情況,程式的複雜性將 Buffer overflow 的問題暴露出來。在此案例中,弱點歸咎於函數某個不明確的介面,而不是程式碼的結構 (就如同前面一個範例中所描述的)。
if (!(png_ptr->mode & PNG_HAVE_PLTE)) {
/* Should be an error, but we can cope with it */
png_warning(png_ptr, "Missing PLTE before tRNS");
}
else if (length > (png_uint_32)png_ptr->num_palette) {
png_warning(png_ptr, "Incorrect tRNS chunk length");
png_crc_finish(png_ptr, length);
return;
}
...
png_crc_read(png_ptr, readbuf, (png_size_t)length);
getUserInfo()
函數採用一個定義為多位元組字元串的使用者名和一個指標來組成使用者資訊的結構,並將使用者資訊填入這個結構。因為 Windows 對使用者名稱的 authentication 是使用統一的字元編碼標準,所以 username
是第一個從多位元組字元串轉換成統一字元編碼標準的字串的參數。函數接著會不正確地以位元組而非字元傳送 unicodeUser
的大小。呼叫 MultiByteToWideChar()
可能會因此而將最多 (UNLEN+1)*sizeof(WCHAR)
個寬字元,或(UNLEN+1)*sizeof(WCHAR)*sizeof(WCHAR)
個位元組寫入 unicodeUser
陣列,而僅為該陣列分配了 (UNLEN+1)*sizeof(WCHAR)
個位元組。如果 username
字串包含了多於 UNLEN
的字元,那麼呼叫 MultiByteToWideChar()
將會溢出 unicodeUser
緩衝區。
void getUserInfo(char *username, struct _USER_INFO_2 info){
WCHAR unicodeUser[UNLEN+1];
MultiByteToWideChar(CP_ACP, 0, username, -1,
unicodeUser, sizeof(unicodeUser));
NetUserGetInfo(NULL, unicodeUser, 2, (LPBYTE *)&info);
}
strncpy()
的範圍函數,使用不正確時也會引起弱點。大多數 Buffer overflow 弱點的根本原因,都是緩衝區的處理,加上對資料的大小或組成假設錯誤。c
,因為 double
類型需要為 c
所分配的空間還要大的空間。
void formatString(double d) {
char c;
scanf("%d", &c)
}
strncpy()
的範圍函數,使用不正確時也會引起弱點。大多數 Buffer overflow 弱點的根本原因,都是緩衝區的處理,加上對資料的大小或組成假設錯誤。buf
,因為視 f
的大小而定,Format String 規範 "%d %.1f ... "
會超出分配記憶體容量。
void formatString(int x, float f) {
char buf[40];
sprintf(buf, "%d %.1f ... ", x, f);
}
strncpy()
的範圍函數,使用不正確時也會引起弱點。大多數 Buffer overflow 弱點的根本原因,都是緩衝區的處理,加上對資料的大小或組成假設錯誤。recv
傳回 sizeof(buf)
位元組讀取允許上限時發生。在此案例中,後續解除參照 buf[nbytes]
將會在配置記憶體邊界以外寫入 null
位元組。
void receive(int socket) {
char buf[MAX];
int nbytes = recv(socket, buf, sizeof(buf), 0);
buf[nbytes] = '\0';
...
}
strncpy()
的範圍函數,使用不正確時也會引起弱點。大多數 Buffer overflow 弱點的根本原因,都是緩衝區的處理,加上對資料的大小或組成假設錯誤。getInputLength()
讀取的不信賴值要小於目的緩衝區 output
的大小,來嘗試避免 off-by-one Buffer overflow 的發生。但由於 len
和 MAX
的比較為有符號比較法,所以若 len
為負數值,當其轉換為 memcpy()
的無符號引數時,就會變成非常大的正數值。
void TypeConvert() {
char input[MAX];
char output[MAX];
fillBuffer(input);
int len = getInputLength();
if (len <= MAX) {
memcpy(output, input, len);
}
...
}
function MyController(function($stateParams, $interpolate){
var ctx = { foo : 'bar' };
var interpolated = $interpolate($stateParams.expression);
this.rendered = interpolated(ctx);
...
}
$stateParams.expression
將會採用可能由使用者控制的資料,並將此評估為與指定內容搭配使用的範本。進而讓惡意使用者能夠在瀏覽器內執行任何所需程式碼,以擷取與執行內容相關的資訊、尋找有關如何建立應用程式的其他資訊或將此轉變為全面的 XSS 攻擊。template
標籤的 <cfinclude>
屬性。 ../../users/wileyh/malicious
」的惡意檔案名稱的可能性,這會導致應用程式包含並執行位於攻擊者主目錄的檔案內容。
<cfinclude template =
"C:\\custom\\templates\\#Form.username#.cfm">
<cfinclude>
標籤所包含的檔案,他們就可能使應用程式在目前頁面上幾乎包含伺服器檔案系統中所有檔案的內容。這至少會對兩個方面產生重大的影響。如果攻擊者可以在伺服器檔案系統中的某個位置 (譬如使用者的主目錄或通用的上傳目錄) 進行寫入,則他們就可能使應用程式在頁面中包含惡意檔案,並由伺服器執行該檔案。即使沒有伺服器檔案系統的寫入權,攻擊者通常也可能透過指定伺服器上的檔案路徑,存取敏感或私人資訊。APPHOME
來決定目錄的安裝位置,並且根據指定目錄的相對路徑來執行初始化 Script。
...
CALL FUNCTION 'REGISTRY_GET'
EXPORTING
KEY = 'APPHOME'
IMPORTING
VALUE = home.
CONCATENATE home INITCMD INTO cmd.
CALL 'SYSTEM' ID 'COMMAND' FIELD cmd ID 'TAB' FIELD TABL[].
...
Example 1
中的程式碼允許攻擊者藉由修改登錄金鑰 APPHOME
,來指向包含惡意版本的 INITCMD
的其他路徑,運用提升的應用程式權限來執行任意指令。因為程式不會驗證從登錄中讀取的值,所以如果攻擊者可以控制登錄金鑰 APPHOME
的值,那麼他們就可以欺騙應用程式去執行惡意程式碼並取得對系統的控制。rman
公用程式周圍的批次檔包裝函式來開始 Oracle 資料庫備份,並接著執行 cleanup.bat
Script 來刪除一些暫存檔案。Script rmanDB.bat
會接受單一指令行參數,其中指定了要執行的備份類型。因為存取資料庫是受限制的,所以應用程式需具有較高權限的使用者來執行備份。
...
btype = request->get_form_field( 'backuptype' )
CONCATENATE `/K 'c:\\util\\rmanDB.bat ` btype `&&c:\\util\\cleanup.bat'` INTO cmd.
CALL FUNCTION 'SXPG_COMMAND_EXECUTE_LONG'
EXPORTING
commandname = cmd_exe
long_params = cmd_string
EXCEPTIONS
no_permission = 1
command_not_found = 2
parameters_too_long = 3
security_risk = 4
OTHERS = 5.
...
backuptype
參數進行任何驗證。通常 SXPG_COMMAND_EXECUTE_LONG
函數模組不會執行多重指令,但在此例中,程式首先執行 cmd.exe
shell,以在單一呼叫 CALL 'SYSTEM'
時執行多重指令。一旦叫用 Shell,Shell 就會允許執行多個由兩個 & 分隔的指令。如果攻擊者傳遞一個 "&& del c:\\dbms\\*.*"
形式的字串,那麼應用程式將會執行這個指令以及由此程式指定的其他指令。因為此應用程式本質的關係,所以應用程式必須要有權限才可與資料庫互動,這表示攻擊者插入的所有指令也都會使用這些權限進行運作。/var/yp
目錄下執行 make
指令。
...
MOVE 'make' to cmd.
CALL 'SYSTEM' ID 'COMMAND' FIELD cmd ID 'TAB' FIELD TABL[].
...
CALL 'SYSTEM'
呼叫前清除它的環境變數。如果攻擊者能夠修改 $PATH
變數,指向名為 make
的惡意二進位碼,並使得程式在它們的環境中執行,那麼程式會載入此惡意的二進位碼,代替原來的程式碼。由於應用程式的特性,它需要特定的權限才能執行系統作業,這表示攻擊者的 make
將會在這些權限下執行,攻擊者可能會完全控制系統。
...
var fs:FileStream = new FileStream();
fs.open(new File(String(configStream.readObject())+".txt"), FileMode.READ);
home = String(fs.readObject(home));
var cmd:String = home + INITCMD;
fscommand("exec", cmd);
...
Example 1
中的程式碼允許攻擊者藉由修改組態設定檔案 configStream
的內容來指向包含惡意版本的 INITCMD
的其他路徑,藉此運用提升的應用程式權限來執行任意指令。因為程式不會驗證從檔案中讀取的值,所以如果攻擊者可以控制該值,他們就可以欺騙應用程式去執行惡意程式碼並控制系統。rman
公用程式周圍的批次檔包裝函式來開始 Oracle 資料庫備份,並接著執行 cleanup.bat
Script 來刪除一些暫存檔案。Script rmanDB.bat
會接受單一指令行參數,其中指定了要執行的備份類型。因為存取資料庫是受限制的,所以應用程式需具有較高權限的使用者來執行備份。
...
var params:Object = LoaderInfo(this.root.loaderInfo).parameters;
var btype:String = String(params["backuptype"]);
var cmd:String = "cmd.exe /K \"c:\\util\\rmanDB.bat " + btype + "&&c:\\util\\cleanup.bat\"";
fscommand("exec", cmd);
...
backuptype
參數進行任何驗證。通常 fscommand()
函數不會執行多重指令,但在此例中,程式首先執行 cmd.exe
shell,以在單一呼叫 fscommnd()
時執行多重指令。一旦叫用 Shell,Shell 就會允許執行多個由兩個 & 分隔的指令。如果攻擊者傳遞一個 "&& del c:\\dbms\\*.*"
形式的字串,那麼應用程式將會執行這個指令以及由此程式指定的其他指令。因為此應用程式本質的關係,所以應用程式必須要有權限才可與資料庫互動,這表示攻擊者插入的所有指令也都會使用這些權限進行運作。/var/yp
目錄下執行 make
指令。
...
fscommand("exec", "make");
...
fscommand()
呼叫前清除它的環境變數。如果攻擊者能夠修改 $PATH
變數,指向名為 make
的惡意二進位碼,並使得程式在它們的環境中執行,那麼程式會載入此惡意的二進位碼,代替原來的程式碼。由於應用程式的特性,它需要特定的權限才能執行系統作業,這表示攻擊者的 make
將會在這些權限下執行,攻擊者可能會完全控制系統。APPHOME
來決定其安裝目錄,並且根據指定目錄的相對路徑來執行初始化 Script。
...
string val = Environment.GetEnvironmentVariable("APPHOME");
string cmd = val + INITCMD;
ProcessStartInfo startInfo = new ProcessStartInfo(cmd);
Process.Start(startInfo);
...
Example 1
中的程式碼允許攻擊者藉由修改系統屬性 APPHOME
,來指向包含惡意版本的 INITCMD
的其他路徑,運用提升的應用程式權限來執行任意指令。因為程式不會驗證從環境中讀取的值,所以如果攻擊者可以控制系統屬性 APPHOME
的值,那麼他們就可以欺騙應用程式去執行惡意程式碼並取得對系統的控制。rman
公用程式周圍的批次檔包裝函式來開始 Oracle 資料庫備份,並接著執行 cleanup.bat
Script 來刪除一些暫存檔案。Script rmanDB.bat
會接受單一指令行參數,其中指定了要執行的備份類型。因為存取資料庫是受限制的,所以應用程式需具有較高權限的使用者來執行備份。
...
string btype = BackupTypeField.Text;
string cmd = "cmd.exe /K \"c:\\util\\rmanDB.bat"
+ btype + "&&c:\\util\\cleanup.bat\""));
Process.Start(cmd);
...
BackupTypeField
進行任何驗證。通常 Process.Start()
函數不會執行多重指令,但在此例中,程式首先執行 cmd.exe
shell,以在單一呼叫 Process.Start()
時執行多重指令。一旦叫用 Shell,Shell 就會允許執行多個由兩個 & 分隔的指令。如果攻擊者傳遞一個 "&& del c:\\dbms\\*.*"
形式的字串,那麼應用程式將會執行這個指令以及由此程式指定的其他指令。因為此應用程式本質的關係,所以應用程式必須要有權限才可與資料庫互動,這表示攻擊者插入的所有指令也都會使用這些權限進行運作。update.exe
指令,如下所示:
...
Process.Start("update.exe");
...
Process.start()
呼叫前清除它的環境變數。如果攻擊者能夠修改 $PATH
變數,指向名為 update.exe
的惡意二進位碼,並使得程式在它們的環境中執行,那麼程式會載入此惡意的二進位碼,代替原來的程式碼。由於應用程式的特性,它需要特定的權限才能執行系統作業,這表示攻擊者的 update.exe
將會在這些權限下執行,攻擊者可能會完全控制系統。setuid root
安裝的,因為這個程式的意圖是作為一個學習工具來使用,以便讓那些仍在培訓中的系統管理員查看各權限的系統檔,而不給他們篡改權限,或者損壞系統的能力。
int main(char* argc, char** argv) {
char cmd[CMD_MAX] = "/usr/bin/cat ";
strcat(cmd, argv[1]);
system(cmd);
}
root
的權限來執行,所以 system()
的呼叫也以 root
的權限來執行。如果使用者指定了一個標準的檔案名稱,那麼呼叫就能如預期般執行。但是,如果攻擊者傳遞 ";rm -rf /"
形式的字串,則對 system()
的呼叫會由於缺少引數而無法執行 cat
,然後以遞迴方式刪除根分割的內容。$APPHOME
來決定應用程式的安裝目錄,並在該目錄中執行初始化指令碼。
...
char* home=getenv("APPHOME");
char* cmd=(char*)malloc(strlen(home)+strlen(INITCMD));
if (cmd) {
strcpy(cmd,home);
strcat(cmd,INITCMD);
execl(cmd, NULL);
}
...
Example 1
所述,這個範例中的程式碼提升了應用程式的權限,允許攻擊者隨意執行任何指令。在此範例中,攻擊者可能修改環境變數 $APPHOME
來指定包含 INITCMD
惡意版本的不同路徑。由於程式不會驗證從環境讀取的值,透過控制該環境變數,攻擊者可能欺騙應用程式執行惡意程式碼。/var/yp
目錄中執行 make
。注意,程式更新密碼記錄後,就已按照 setuid root
進行安裝了。make
:
system("cd /var/yp && make &> /dev/null");
system()
的引數。但是,由於程式沒有指定 make
的絕對路徑,而且沒有在叫用指令之前清除任何環境變數,因此攻擊者可能修改他們的 $PATH
變數,以指向名為 make
的惡意二進位碼,並從 shell 提示執行 CGI 指令碼。而且因為程式是按照 setuid root
安裝的,所以攻擊者的 make
版本現在會以 root
權限執行。_spawn()
系列中的一個函數來叫用 CreateProcess()
時,如果執行檔或路徑中包含空格,請務必小心。
...
LPTSTR cmdLine = _tcsdup(TEXT("C:\\Program Files\\MyApplication -L -S"));
CreateProcess(NULL, cmdLine, ...);
...
CreateProcess()
剖析空格的方式,作業系統嘗試執行的第一個執行檔會是 Program.exe
,而不是 MyApplication.exe
。所以,如果攻擊者能夠在系統上安裝名為 Program.exe
的惡意應用程式,任何會使用 Program Files
目錄不正確呼叫 CreateProcess()
的程式將會執行此應用程式,而不會執行原本所要執行的應用程式。system()
、exec()
和 CreateProcess()
這類的函數,可利用程式呼叫這些函數的環境,因此攻擊者會有機會去影響這些呼叫的運作情況。$PATH
或程式執行環境的其他層面,使用程式來執行惡意二進位檔案。/var/yp
目錄中執行 make
。注意,程式更新密碼記錄後,就已按照 setuid root
進行安裝了。make
:
MOVE "cd /var/yp && make &> /dev/null" to command-line
CALL "CBL_EXEC_RUN_UNIT" USING command-line
length of command-line
run-unit-id
stack-size
flags
CBL_EXEC_RUN_UNIT
的引數。但是,由於程式沒有為 make
指定絕對路徑,並且在叫用該指令之前未清除其環境變數,因此攻擊者可將 $PATH
變數修改為指向名為 make
的惡意二進位檔案,並透過 Shell 提示執行 CGI 指令碼。另外,由於程式已按照 setuid root
進行安裝,因此攻擊者的 make
版本現在能利用 root
權限來執行。pdfprint
指令列印的檔案。
DISPLAY "TEMP" UPON ENVIRONMENT-NAME
ACCEPT ws-temp-dir FROM ENVIRONMENT-VARIABLE
STRING "pdfprint " DELIMITED SIZE
ws-temp-dir DELIMITED SPACE
"/" DELIMITED SIZE
ws-pdf-filename DELIMITED SPACE
x"00" DELIMITED SIZE
INTO cmd-buffer
CALL "SYSTEM" USING cmd-buffer
pdfprint
指定絕對路徑,因此攻擊者可將 $PATH
變數修改為指向惡意二進位檔案。此外,儘管 DELIMITED SPACE
片語會防止 ws-temp-dir
和 ws-pdf-filename
中嵌入空格,但其中的任何一個都可以嵌入 shell 中繼字元 (例如 &&
)。cmd
要求參數指定任意指令。
...
<cfset var="#url.cmd#">
<cfexecute name = "C:\windows\System32\cmd.exe"
arguments = "/c #var#"
timeout = "1"
variable="mycmd">
</cfexecute>
...
APPHOME
來決定目錄的安裝位置,並且根據指定目錄的相對路徑來執行初始化 Script。
...
final cmd = String.fromEnvironment('APPHOME');
await Process.run(cmd);
...
Example 1
中的程式碼允許攻擊者藉由修改系統屬性 APPHOME
,來指向包含惡意版本的 INITCMD
的其他路徑,運用提升的應用程式權限來執行任意指令。因為程式不會驗證從環境中讀取的值,所以如果攻擊者可以控制系統屬性 APPHOME
的值,那麼他們就可以欺騙應用程式去執行惡意程式碼並取得對系統的控制。
cmdName := request.FormValue("Command")
c := exec.Command(cmdName)
c.Run()
APPHOME
來決定目錄的安裝位置,並且根據指定目錄的相對路徑來執行初始化 Script。
...
String home = System.getProperty("APPHOME");
String cmd = home + INITCMD;
java.lang.Runtime.getRuntime().exec(cmd);
...
Example 1
中的程式碼允許攻擊者藉由修改系統屬性 APPHOME
,來指向包含惡意版本的 INITCMD
的其他路徑,運用提升的應用程式權限來執行任意指令。因為程式不會驗證從環境中讀取的值,所以如果攻擊者可以控制系統屬性 APPHOME
的值,那麼他們就可以欺騙應用程式去執行惡意程式碼並取得對系統的控制。rman
公用程式周圍的批次檔包裝函式來開始 Oracle 資料庫備份,並接著執行 cleanup.bat
Script 來刪除一些暫存檔案。Script rmanDB.bat
會接受單一指令行參數,其中指定了要執行的備份類型。因為存取資料庫是受限制的,所以應用程式需具有較高權限的使用者來執行備份。
...
String btype = request.getParameter("backuptype");
String cmd = new String("cmd.exe /K
\"c:\\util\\rmanDB.bat "+btype+"&&c:\\util\\cleanup.bat\"")
System.Runtime.getRuntime().exec(cmd);
...
backuptype
參數進行任何驗證。通常 Runtime.exec()
函數不會執行多重指令,但在此例中,程式首先執行 cmd.exe
shell,以在單一呼叫 Runtime.exec()
時執行多重指令。一旦叫用 Shell,Shell 就會允許執行多個由兩個 & 分隔的指令。如果攻擊者傳遞一個 "&& del c:\\dbms\\*.*"
形式的字串,那麼應用程式將會執行這個指令以及由此程式指定的其他指令。因為此應用程式本質的關係,所以應用程式必須要有權限才可與資料庫互動,這表示攻擊者插入的所有指令也都會使用這些權限進行運作。/var/yp
目錄下執行 make
指令。
...
System.Runtime.getRuntime().exec("make");
...
Runtime.exec()
呼叫前清除它的環境變數。如果攻擊者能夠修改 $PATH
變數,指向名為 make
的惡意二進位碼,並使得程式在它們的環境中執行,那麼程式會載入此惡意的二進位碼,代替原來的程式碼。由於應用程式的特性,它需要特定的權限才能執行系統作業,這表示攻擊者的 make
將會在這些權限下執行,攻擊者可能會完全控制系統。
...
String[] cmds = this.getIntent().getStringArrayExtra("commands");
Process p = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(p.getOutputStream());
for (String cmd : cmds) {
os.writeBytes(cmd+"\n");
}
os.writeBytes("exit\n");
os.flush();
...
APPHOME
來決定其安裝目錄,並且根據指定目錄的相對路徑來執行初始化 Script。
var cp = require('child_process');
...
var home = process.env('APPHOME');
var cmd = home + INITCMD;
child = cp.exec(cmd, function(error, stdout, stderr){
...
});
...
Example 1
中的程式碼允許攻擊者藉由修改系統屬性 APPHOME
,來指向包含惡意版本的 INITCMD
的其他路徑,運用提升的應用程式權限來執行任意指令。因為程式不會驗證從環境中讀取的值,所以如果攻擊者可以控制系統屬性 APPHOME
的值,那麼他們就可以欺騙應用程式去執行惡意程式碼並取得對系統的控制。rman
公用程式周圍的批次檔包裝函式來開始 Oracle 資料庫備份。Script rmanDB.bat
會接受單一指令行參數,其中指定了要執行的備份類型。因為存取資料庫是受限制的,所以應用程式需具有較高權限的使用者來執行備份。
var cp = require('child_process');
var http = require('http');
var url = require('url');
function listener(request, response){
var btype = url.parse(request.url, true)['query']['backuptype'];
if (btype !== undefined){
cmd = "c:\\util\\rmanDB.bat" + btype;
cp.exec(cmd, function(error, stdout, stderr){
...
});
}
...
}
...
http.createServer(listener).listen(8080);
backuptype
參數進行任何驗證,只有驗證此參數是否存在。一旦叫用此 Shell,就可能允許執行多個指令,並且因為應用程式本質的關係,應用程式將會使用與資料庫互動的必要權限來執行,這表示攻擊者插入的所有指令也會使用這些權限來執行。/var/yp
目錄下執行 make
指令。
...
require('child_process').exec("make", function(error, stdout, stderr){
...
});
...
make
的絕對路徑,因此沒能在執行 child_process.exec()
呼叫前清除它的環境變數。如果攻擊者能夠修改 $PATH
變數,指向名為 make
的惡意二進位碼,並使得程式在它們的環境中執行,那麼程式會載入此惡意的二進位碼,代替原來的程式碼。由於應用程式的特性,它需要特定的權限才能執行系統作業,這表示攻擊者的 make
將會在這些權限下執行,攻擊者可能會完全控制系統。APPHOME
來決定目錄的安裝位置,並且根據指定目錄的相對路徑來執行初始化 Script。
...
$home = $_ENV['APPHOME'];
$cmd = $home . $INITCMD;
system(cmd);
...
Example 1
中的程式碼允許攻擊者藉由修改系統屬性 APPHOME
,來指向包含惡意版本的 INITCMD
的其他路徑,運用提升的應用程式權限來執行任意指令。因為程式不會驗證從環境中讀取的值,所以如果攻擊者可以控制系統屬性 APPHOME
的值,那麼他們就可以欺騙應用程式去執行惡意程式碼並取得對系統的控制。rman
公用程式周圍的批次檔包裝函式來開始 Oracle 資料庫備份,並接著執行 cleanup.bat
Script 來刪除一些暫存檔案。Script rmanDB.bat
會接受單一指令行參數,其中指定了要執行的備份類型。因為存取資料庫是受限制的,所以應用程式需具有較高權限的使用者來執行備份。
...
$btype = $_GET['backuptype'];
$cmd = "cmd.exe /K \"c:\\util\\rmanDB.bat " . $btype . "&&c:\\util\\cleanup.bat\"";
system(cmd);
...
backuptype
參數進行任何驗證。通常 Runtime.exec()
函數不會執行多重指令,但在此例中,程式首先執行 cmd.exe
shell,以在單一呼叫 Runtime.exec()
時執行多重指令。一旦叫用 Shell,Shell 就會允許執行多個由兩個 & 分隔的指令。如果攻擊者傳遞一個 "&& del c:\\dbms\\*.*"
形式的字串,那麼應用程式將會執行這個指令以及由此程式指定的其他指令。因為此應用程式本質的關係,所以應用程式必須要有權限才可與資料庫互動,這表示攻擊者插入的所有指令也都會使用這些權限進行運作。/var/yp
目錄下執行 make
指令。
...
$result = shell_exec("make");
...
Runtime.exec()
呼叫前清除它的環境變數。如果攻擊者能夠修改 $PATH
變數,指向名為 make
的惡意二進位碼,並使得程式在它們的環境中執行,那麼程式會載入此惡意的二進位碼,代替原來的程式碼。由於應用程式的特性,它需要特定的權限才能執行系統作業,這表示攻擊者的 make
將會在這些權限下執行,攻擊者可能會完全控制系統。
...
CREATE PROCEDURE dbo.listFiles (@path NVARCHAR(200))
AS
DECLARE @cmd NVARCHAR(500)
SET @cmd = 'dir ' + @path
exec xp_cmdshell @cmd
GO
...
APPHOME
來決定目錄的安裝位置,並且根據指定目錄的相對路徑來執行初始化 Script。
...
home = os.getenv('APPHOME')
cmd = home.join(INITCMD)
os.system(cmd);
...
Example 1
中的程式碼允許攻擊者藉由修改系統屬性 APPHOME
,來指向包含惡意版本的 INITCMD
的其他路徑,運用提升的應用程式權限來執行任意指令。因為程式不會驗證從環境中讀取的值,所以如果攻擊者可以控制系統屬性 APPHOME
的值,那麼他們就可以欺騙應用程式去執行惡意程式碼並取得對系統的控制。rman
公用程式周圍的批次檔包裝函式來開始 Oracle 資料庫備份,並接著執行 cleanup.bat
Script 來刪除一些暫存檔案。Script rmanDB.bat
會接受單一指令行參數,其中指定了要執行的備份類型。因為存取資料庫是受限制的,所以應用程式需具有較高權限的使用者來執行備份。
...
btype = req.field('backuptype')
cmd = "cmd.exe /K \"c:\\util\\rmanDB.bat " + btype + "&&c:\\util\\cleanup.bat\""
os.system(cmd);
...
backuptype
參數進行任何驗證。通常 Runtime.exec()
函數不會執行多重指令,但在此例中,程式首先執行 cmd.exe
shell,以在單一呼叫 Runtime.exec()
時執行多重指令。一旦叫用 Shell,Shell 就會允許執行多個由兩個 & 分隔的指令。如果攻擊者傳遞一個 "&& del c:\\dbms\\*.*"
形式的字串,那麼應用程式將會執行這個指令以及由此程式指定的其他指令。因為此應用程式本質的關係,所以應用程式必須要有權限才可與資料庫互動,這表示攻擊者插入的所有指令也都會使用這些權限進行運作。/var/yp
目錄下執行 make
指令。
...
result = os.system("make");
...
os.system()
呼叫前清除它的環境變數。如果攻擊者能夠修改 $PATH
變數,指向名為 make
的惡意二進位碼,並使得程式在它們的環境中執行,那麼程式會載入此惡意的二進位碼,代替原來的程式碼。由於應用程式的特性,它需要特定的權限才能執行系統作業,這表示攻擊者的 make
將會在這些權限下執行,攻擊者可能會完全控制系統。APPHOME
來決定目錄的安裝位置,並且根據指定目錄的相對路徑來執行初始化 Script。
...
home = ENV['APPHOME']
cmd = home + INITCMD
Process.spawn(cmd)
...
Example 1
中的程式碼允許攻擊者藉由修改系統屬性 APPHOME
,來指向包含惡意版本的 INITCMD
的其他路徑,運用提升的應用程式權限來執行任意指令。因為程式不會驗證從環境中讀取的值,所以如果攻擊者可以控制系統屬性 APPHOME
的值,那麼他們就可以欺騙應用程式去執行惡意程式碼並取得對系統的控制。rman
公用程式周圍的批次檔包裝函式來開始 Oracle 資料庫備份,並接著執行 cleanup.bat
Script 來刪除一些暫存檔案。Script rmanDB.bat
會接受單一指令行參數,其中指定了要執行的備份類型。因為存取資料庫是受限制的,所以應用程式需具有較高權限的使用者來執行備份。
...
btype = req['backuptype']
cmd = "C:\\util\\rmanDB.bat #{btype} &&C:\\util\\cleanup.bat"
spawn(cmd)
...
backuptype
參數進行任何驗證。一旦透過 Kernel.spawn
叫用 Shell,Shell 就會允許執行多個由兩個 & 分隔的指令。如果攻擊者傳遞一個 "&& del c:\\dbms\\*.*"
形式的字串,那麼應用程式將會執行這個指令以及由此程式指定的其他指令。因為此應用程式本質的關係,所以應用程式必須要有權限才可與資料庫互動,這表示攻擊者插入的所有指令也都會使用這些權限進行運作。/var/yp
目錄下執行 make
指令。
...
system("make")
...
Kernel.system()
呼叫前清除它的環境變數。如果攻擊者能夠修改 $PATH
變數,指向名為 make
的惡意二進位碼,並使得程式在它們的環境中執行,那麼程式會載入此惡意的二進位碼,代替原來的程式碼。由於應用程式的特性,它需要特定的權限才能執行系統作業,這表示攻擊者的 make
將會在這些權限下執行,攻擊者可能會完全控制系統。
def changePassword(username: String, password: String) = Action { request =>
...
s'echo "${password}" | passwd ${username} --stdin'.!
...
}
APPHOME
來決定其安裝目錄,並且根據指定目錄的相對路徑來執行初始化 Script。
...
Dim cmd
Dim home
home = Environ$("AppHome")
cmd = home & initCmd
Shell cmd, vbNormalFocus
...
Example 1
中的程式碼允許攻擊者藉由修改系統屬性 APPHOME
,來指向包含惡意版本的 INITCMD
的其他路徑,運用提升的應用程式權限來執行任意指令。因為程式不會驗證從環境中讀取的值,所以如果攻擊者可以控制系統屬性 APPHOME
的值,那麼他們就可以欺騙應用程式去執行惡意程式碼並取得對系統的控制。rman
公用程式周圍的批次檔包裝函式來開始 Oracle 資料庫備份,並接著執行 cleanup.bat
Script 來刪除一些暫存檔案。Script rmanDB.bat
會接受單一指令行參數,其中指定了要執行的備份類型。因為存取資料庫是受限制的,所以應用程式需具有較高權限的使用者來執行備份。
...
btype = Request.Form("backuptype")
cmd = "cmd.exe /K " & Chr(34) & "c:\util\rmanDB.bat " & btype & "&&c:\util\cleanup.bat" & Chr(34) & ";
Shell cmd, vbNormalFocus
...
backuptype
參數進行任何驗證。一旦叫用 Shell,Shell 就會允許執行多個由兩個 & 分隔的指令。如果攻擊者傳遞一個 "&& del c:\\dbms\\*.*"
形式的字串,那麼應用程式將會執行這個指令以及由此程式指定的其他指令。因為此應用程式本質的關係,所以應用程式必須要有權限才可與資料庫互動,這表示攻擊者插入的所有指令也都會使用這些權限進行運作。/var/yp
目錄下執行 make
指令。
...
$result = shell_exec("make");
...
Runtime.exec()
呼叫前清除它的環境變數。如果攻擊者能夠修改 $PATH
變數,指向名為 make
的惡意二進位碼,並使得程式在它們的環境中執行,那麼程式會載入此惡意的二進位碼,代替原來的程式碼。由於應用程式的特性,它需要特定的權限才能執行系統作業,這表示攻擊者的 make
將會在這些權限下執行,攻擊者可能會完全控制系統。
...
steps:
- run: echo "${{ github.event.pull_request.title }}"
...
github.event.pull_request.title
值表示的任何程式碼。如果 github.event.pull_request.title
包含惡意可執行程式碼,則該動作將會執行惡意程式碼,從而導致 Command Injection。
...
string password = Request.Form["db_pass"]; //gets POST parameter 'db_pass'
SqlConnection DBconn = new SqlConnection("Data Source = myDataSource; Initial Catalog = db; User ID = myUsername; Password = " + password + ";");
...
db_pass
參數,例如
...
password := request.FormValue("db_pass")
db, err := sql.Open("mysql", "user:" + password + "@/dbname")
...
db_pass
參數,例如:
username = req.field('username')
password = req.field('password')
...
client = MongoClient('mongodb://%s:%s@aMongoDBInstance.com/?ssl=true' % (username, password))
...
password
參數:
hostname = req.params['host'] #gets POST parameter 'host'
...
conn = PG::Connection.new("connect_timeout=20 dbname=app_development user=#{user} password=#{password} host=#{hostname}")
...
host
參數,例如content://my.authority/messages
content://my.authority/messages/123
content://my.authority/messages/deleted
deleted
的 msgId 程式碼來呼叫 content://my.authority/messages/deleted
:
// "msgId" is submitted by users
Uri dataUri = Uri.parse(WeatherContentProvider.CONTENT_URI + "/" + msgId);
Cursor wCursor1 = getContentResolver().query(dataUri, null, null, null, null);
...
var params:Object = LoaderInfo(this.root.loaderInfo).parameters;
var url:String = String(params["url"]);
var ldr:Loader = new Loader();
var urlReq:URLRequest = new URLRequest(url);
ldr.load(urlReq);
...
eid
,並將其向使用者顯示。
<% String eid = request.getParameter("eid"); %>
...
Employee ID: <%= eid %>
eid
只包含標準英數字元,則這個範例中的程式碼會正確地執行。如果 eid
中有包含中繼字元或來源程式碼中的值,那麼網路瀏覽器就會像顯示 HTTP 回應那樣執行程式碼。
<%...
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from emp where id="+eid);
if (rs != null) {
rs.next();
String name = rs.getString("name");
}
%>
Employee Name: <%= name %>
Example 1
所述,name
的值正常運作時,此程式碼也會正常運作,但如果該值不正常運作,則會完全無法避免程式碼遭受攻擊。此外,這個程式碼之所以看似不那麼危險,是因為 name
的值是從資料庫中讀取的,而顯然這些內容是由應用程式管理的。但是,如果 name
的值是從使用者提供的資料中產生,那麼資料庫可能會成為提供惡意內容的管道。如果未對資料庫中儲存的所有資料進行適當的輸入驗證,那麼攻擊者可能在使用者的網路瀏覽器中執行惡意指令。這類型的攻擊稱為 Persistent XSS (或 Stored XSS),其性質特別狡詐,因為間接的資料儲存方式而難以辨別該威脅,且該攻擊影響多個使用者的可能性可能提高。XSS 盜取會從存取提供造訪者訪客留名簿 (guestbook) 的網站開始。攻擊者會在他們的訪客留名簿項目中加入 JavaScript,所有後來前往訪客留名簿頁面的造訪者都可能會執行這些惡意程式碼。
...
WebView webview = (WebView) findViewById(R.id.webview);
webview.getSettings().setJavaScriptEnabled(true);
String url = this.getIntent().getExtras().getString("url");
webview.loadUrl(url);
...
url
的值以 javascript:
開頭,隨後的 JavaScript 程式碼將在網頁範圍中的 WebView 內執行。Example 1
所述,會直接從 HTTP 要求中讀取資料,並在 HTTP 回應中回傳資料。當攻擊者誘使使用者提供危險內容給易受攻擊的 Web 應用程式,接著這些危險內容就會回傳給使用者並由在網路瀏覽器中執行,這時就會出現 Reflected XSS 攻擊行為。傳遞惡意內容最常用的機制就是,將惡意內容當作參數隱藏在公開發表的 URL 中,或者以電子郵件方式直接傳送給受害者。以這種方法建立的 URL 會構成許多網路釣魚 (phishing) 架構的核心,攻擊者可以藉此誘使受害者去造訪一個指向到易受攻擊網站的 URL。網站將攻擊者的內容回傳給使用者之後,就會執行這些內容,並接著從使用者的電腦將可能包含階段作業資訊的 Cookie 之類的私人資訊傳給攻擊者,或者執行其他惡意活動。Example 2
所述,應用程式會將危險資料儲存到資料庫或其他可信任的資料儲存區中。這些危險資料隨後會被回讀到應用程式,並包含在動態內容中。Persistent XSS 攻擊會在以下情況出現:攻擊者把危險內容插入到之後會讀取的資料儲存區中,並包含在動態內容中。從攻擊者的角度來看,插入惡意內容的最佳位置莫過於一個會對很多使用者或特別感興趣的使用者顯示的區域。感興趣的使用者通常會在應用程式中擁有較高的權限,或者會與敏感資料進行互動,且這些資料對攻擊者而言很有利用價值。如果其中一個使用者執行了惡意內容,攻擊者可能會代替使用者去執行需要權限許可的作業,或者取得存取使用者專屬敏感資料的權限。Example 3
所述,應用程式以外的來源會在資料庫或是其他資料儲存區中儲存危險資料,且之後這些危險資料會被當作信賴的資料回讀到應用程式,並會包含在動態內容中。message
擷取回應,並顯示給使用者。
const openai = new OpenAI({
apiKey: ...,
});
const chatCompletion = await openai.chat.completions.create(...);
message = res.choices[0].message.content
console.log(chatCompletion.choices[0].message.content)
message
擷取回應,並顯示給使用者。
client = openai.OpenAI()
res = client.chat.completions.create(...)
message = res.choices[0].message.content
self.writeln(f"<p>{message}<\p>")
text/html
MIME 類型。因此,只有回應使用此 MIME 類型或任何其他也會強制瀏覽器以 HTML 呈現回應或可能會執行指令碼 (例如 SVG 影像 (image/svg+xml
)、XML 文件 (application/xml
等)) 的類型時,XSS 才會運作。 application/octet-stream
) 的回應時,不會呈現 HTML 或執行指令碼。但 Internet Explorer 等部分瀏覽器會執行名為 Content Sniffing
的作業。Content Sniffing 會忽略提供的 MIME 類型,並嘗試依據回應的內容推論正確的 MIME 類型。text/html
的 MIME 類型只是可能導致 XSS 弱點的一種 MIME 類型。可以執行諸如 SVG 影像 (image/svg+xml
)、XML 文件 (application/xml
) 等指令碼的其他文件,也可能導致 XSS 弱點,無論瀏覽器是否執行 Content Sniffing。 <html><body><script>alert(1)</script></body></html>
之類的回應可以呈現為 HTML,即使其 content-type
標頭已設為 application/octet-stream
, multipart-mixed
等。application/octet-stream
回應中反映使用者資料。
@RestController
public class SomeResource {
@RequestMapping(value = "/test", produces = {MediaType.APPLICATION_OCTET_STREAM_VALUE})
public String response5(@RequestParam(value="name") String name){
return name;
}
}
name
參數設為 <html><body><script>alert(1)</script></body></html>
,則伺服器會產生以下回應:
HTTP/1.1 200 OK
Content-Length: 51
Content-Type: application/octet-stream
Connection: Closed
<html><body><script>alert(1)</script></body></html>
text/html
MIME 類型。因此,只有回應使用此 MIME 類型或任何其他也會強制瀏覽器以 HTML 呈現回應或可能會執行指令碼 (例如 SVG 影像 (image/svg+xml
)、XML 文件 (application/xml
等)) 的類型時,XSS 才會運作。 application/json
) 提供回應給大多數現代瀏覽器時,這些瀏覽器並不會呈現 HTML,也不會執行指令碼。但 Internet Explorer 等部分瀏覽器會執行名為 Content Sniffing
的作業。Content Sniffing 會忽略提供的 MIME 類型,並嘗試依據回應的內容推論正確的 MIME 類型。但要特別注意的是,text/html
的 MIME 類型只是可能導致 XSS 弱點的一種 MIME 類型。image/svg+xml
)、XML 文件 (application/xml
) 等指令碼的其他文件,也可能導致 XSS 弱點,無論瀏覽器是否執行 Content Sniffing。 <html><body><script>alert(1)</script></body></html>
之類的回應可以呈現為 HTML,即使其 content-type
標頭已設為 application/json
。application/json
回應中反映使用者資料。
def mylambda_handler(event, context):
name = event['name']
response = {
"statusCode": 200,
"body": "{'name': name}",
"headers": {
'Content-Type': 'application/json',
}
}
return response
name
參數設為 <html><body><script>alert(1)</script></body></html>
,則伺服器會產生以下回應:
HTTP/1.1 200 OK
Content-Length: 88
Content-Type: application/json
Connection: Closed
{'name': '<html><body><script>alert(1)</script></body></html>'}
eid
,並將 ID 顯示給使用者。
String queryString = Window.Location.getQueryString();
int pos = queryString.indexOf("eid=")+4;
HTML output = new HTML();
output.setHTML(queryString.substring(pos, queryString.length()));
eid
只包含標準英數字元,則這個範例中的程式碼會正確地執行。如果 eid
中有包含中繼字元或來源程式碼中的值,那麼網路瀏覽器就會像顯示 HTTP 回應那樣執行程式碼。eid
並顯示給使用者。範例 2:請考慮使用 HTML 表單:
<SCRIPT>
var pos=document.URL.indexOf("eid=")+4;
document.write(document.URL.substring(pos,document.URL.length));
</SCRIPT>
<div id="myDiv">
Employee ID: <input type="text" id="eid"><br>
...
<button>Show results</button>
</div>
<div id="resultsDiv">
...
</div>
$(document).ready(function(){
$("#myDiv").on("click", "button", function(){
var eid = $("#eid").val();
$("resultsDiv").append(eid);
...
});
});
eid
) 只包含標準英數字元,這些程式碼便會正確地運作。如果 eid
中有包含中繼字元或來源程式碼中的值,那麼網路瀏覽器就會像顯示 HTTP 回應那樣執行程式碼。
let element = JSON.parse(getUntrustedInput());
ReactDOM.render(<App>
{element}
</App>);
Example 3
中,如果攻擊者可以控制從 getUntrustedInput()
擷取的整個 JSON 物件,則可能會讓 React 將 element
解譯為元件,因此可以傳遞具有 dangerouslySetInnerHTML
及其自己的控制值的物件 (典型的 Cross-Site Scripting 攻擊)。