输入验证与表示问题是由元字符、交替编码和数字表示引起的。安全问题源于信任输入。这些问题包括:“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
,此类属性将允许攻击者覆盖系统属性并可能会执行任意代码。
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:这一例子表明模仿 C++ 中
...
char buf[BUFSIZE];
gets(buf);
...
gets()
函数的不安全行为是如此的简单,只要通过使用 >>
运算符将输入读取到 char[]
字符串中。例 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 中的用户名使用 Unicode,所以 username
参数首先要从多字节字符串转换成 Unicode 字符串。然后,这个函数便会错误地将 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
的大小,格式字符串说明符 "%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
将采用可能受用户控制的数据,并将其作为用于指定上下文的模板进行计算。这又可能会允许恶意用户在浏览器中运行他们想要的代码、检索关于代码运行的上下文的信息、查找有关如何创建应用程序的额外信息,或将此代码转换为 full blown XSS 攻击。<cfinclude>
标签的 template
属性。 ../../users/wileyh/malicious
",从而导致该应用程序执行攻击者主目录下文件的恶意内容。
<cfinclude template =
"C:\\custom\\templates\\#Form.username#.cfm">
<cfinclude>
标签所包含的文件,即表示他们能使应用程序在当前页上包含服务器文件系统中几乎所有文件的内容。这至少会对两个方面产生重大影响。如果攻击者可以在服务器的文件系统上某个位置(如用户的主目录或一个通用的上传目录)进行写入,即表示他们能使应用程序在页面中包含一个恶意文件,并将由服务器执行该文件。即使不具备服务器文件系统的写权限,攻击者通常也能通过指定服务器上某个文件的路径,访问敏感或私人信息。APPHOME
来决定其安装目录,然后根据指定目录的相对路径执行初始化脚本。
...
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
脚本来删除一些临时文件。脚本 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 之后,它即会允许执行用两个与号分隔的多条命令。如果攻击者传递了一个形式为 "&& 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
脚本来删除一些临时文件。脚本 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 之后,它即会允许执行用两个与号分隔的多条命令。如果攻击者传递了一个形式为 "&& del c:\\dbms\\*.*"
的字符串,那么应用程序将随程序指定的其他命令一起执行此命令。由于该应用程序的特性,运行该应用程序需要具备与数据库进行交互所需的权限,这就意味着攻击者注入的任何命令都将通过这些权限得以运行。/var/yp
目录中运行 make
命令。
...
fscommand("exec", "make");
...
fscommand()
调用前清除它的环境变量。如果攻击者能够修改 $PATH
变量,把它指向名为 make
恶意二进制代码,程序就会在其指定的环境下执行,然后加载该恶意二进制代码,而非原本期望的代码。由于应用程序自身的特性,运行该应用程序需要具备执行系统操作所需的权限,这意味着攻击者会利用这些权限执行自己的 make
,从而可能导致攻击者完全控制系统。APPHOME
来决定其安装目录,然后根据指定目录的相对路径执行一个初始化脚本。
...
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
脚本来删除一些临时文件。脚本 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 之后,它即会允许执行用两个与号分隔的多条命令。如果攻击者传递了一个形式为 "&& 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
权限运行的,所以也会以 root
权限来调用 system()
。如果用户指定了标准的文件名,那么调用就可按照您期望的方式进行。然而,如果攻击者传递了一个 ";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
来确定其安装目录,然后根据指定目录的相对路径执行初始化脚本。
...
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
来决定其安装目录,然后根据指定目录的相对路径执行一个初始化脚本。
...
String home = System.getProperty("APPHOME");
String cmd = home + INITCMD;
java.lang.Runtime.getRuntime().exec(cmd);
...
Example 1
中的代码可以使攻击者通过修改系统属性 APPHOME
以指向包含恶意版本 INITCMD
的其他路径来提高自己在应用程序中的权限,继而随心所欲地执行命令。由于程序不会验证从环境中读取的值,因此如果攻击者能够控制系统属性 APPHOME
的值,他们就能欺骗应用程序去运行恶意代码,从而取得系统控制权。rman
实用程序的批处理文件封装器来启动 Oracle 数据库备份,然后运行一个 cleanup.bat
脚本来删除一些临时文件。脚本 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 之后,它即会允许执行用两个与号分隔的多条命令。如果攻击者传递了一个形式为 "&& 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
来决定其安装目录,然后根据指定目录的相对路径来执行初始化脚本。
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 数据库备份。脚本 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
来决定其安装目录,然后根据指定目录的相对路径执行一个初始化脚本。
...
$home = $_ENV['APPHOME'];
$cmd = $home . $INITCMD;
system(cmd);
...
Example 1
中的代码可以使攻击者通过修改系统属性 APPHOME
以指向包含恶意版本 INITCMD
的其他路径来提高自己在应用程序中的权限,继而随心所欲地执行命令。由于程序不会验证从环境中读取的值,因此如果攻击者能够控制系统属性 APPHOME
的值,他们就能欺骗应用程序去运行恶意代码,从而取得系统控制权。rman
实用程序的批处理文件封装器来启动 Oracle 数据库备份,然后运行一个 cleanup.bat
脚本来删除一些临时文件。脚本 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 之后,它即会允许执行用两个与号分隔的多条命令。如果攻击者传递了一个形式为 "&& 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
来决定其安装目录,然后根据指定目录的相对路径执行一个初始化脚本。
...
home = os.getenv('APPHOME')
cmd = home.join(INITCMD)
os.system(cmd);
...
Example 1
中的代码可以使攻击者通过修改系统属性 APPHOME
以指向包含恶意版本 INITCMD
的其他路径来提高自己在应用程序中的权限,继而随心所欲地执行命令。由于程序不会验证从环境中读取的值,因此如果攻击者能够控制系统属性 APPHOME
的值,他们就能欺骗应用程序去运行恶意代码,从而取得系统控制权。rman
实用程序的批处理文件封装器来启动 Oracle 数据库备份,然后运行一个 cleanup.bat
脚本来删除一些临时文件。脚本 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 之后,它即会允许执行用两个与号分隔的多条命令。如果攻击者传递了一个形式为 "&& del c:\\dbms\\*.*"
的字符串,那么应用程序将随程序指定的其他命令一起执行此命令。由于该应用程序的特性,运行该应用程序需要具备与数据库进行交互所需的权限,这就意味着攻击者注入的任何命令都将通过这些权限得以运行。/var/yp
目录中运行 make
命令。
...
result = os.system("make");
...
os.system()
调用前清除它的环境变量。如果攻击者能够修改 $PATH
变量,把它指向名为 make
恶意二进制代码,程序就会在其指定的环境下执行,然后加载该恶意二进制代码,而非原本期望的代码。由于应用程序自身的特性,运行该应用程序需要具备执行系统操作所需的权限,这意味着攻击者会利用这些权限执行自己的 make
,从而可能导致攻击者完全控制系统。APPHOME
来决定其安装目录,然后根据指定目录的相对路径执行一个初始化脚本。
...
home = ENV['APPHOME']
cmd = home + INITCMD
Process.spawn(cmd)
...
Example 1
中的代码可以使攻击者通过修改系统属性 APPHOME
以指向包含恶意版本 INITCMD
的其他路径来提高自己在应用程序中的权限,继而随心所欲地执行命令。由于程序不会验证从环境中读取的值,因此如果攻击者能够控制系统属性 APPHOME
的值,他们就能欺骗应用程序去运行恶意代码,从而取得系统控制权。rman
实用程序的批处理文件封装器来启动 Oracle 数据库备份,然后运行一个 cleanup.bat
脚本来删除一些临时文件。脚本 rmanDB.bat
接受单个命令行参数,该参数指定了要执行的备份类型。由于访问数据库受限,所以应用程序执行备份需要具有较高权限的用户。
...
btype = req['backuptype']
cmd = "C:\\util\\rmanDB.bat #{btype} &&C:\\util\\cleanup.bat"
spawn(cmd)
...
backuptype
参数进行任何验证。在通过 Kernel.spawn
调用该 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
来决定其安装目录,然后根据指定目录的相对路径执行一个初始化脚本。
...
Dim cmd
Dim home
home = Environ$("AppHome")
cmd = home & initCmd
Shell cmd, vbNormalFocus
...
Example 1
中的代码可以使攻击者通过修改系统属性 APPHOME
以指向包含恶意版本 INITCMD
的其他路径来提高自己在应用程序中的权限,继而随心所欲地执行命令。由于程序不会验证从环境中读取的值,因此如果攻击者能够控制系统属性 APPHOME
的值,他们就能欺骗应用程序去运行恶意代码,从而取得系统控制权。rman
实用程序的批处理文件封装器来启动 Oracle 数据库备份,然后运行一个 cleanup.bat
脚本来删除一些临时文件。脚本 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 之后,它即会允许执行用两个与号分隔的多条命令。如果攻击者传递了一个形式为 "&& 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
中的某个值包含元字符或源代码,则 Web 浏览器就会在显示 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
的值来自用户提供的数据,数据库就会成为恶意内容传播的通道。如果不对数据库中存储的所有数据进行恰当的输入验证,那么攻击者就可以在用户的 Web 浏览器中执行恶意命令。这种类型的漏洞利用称为 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 中的 Web 页面上下文内部执行。Example 1
中所示,系统从 HTTP 请求中直接读取数据,并在 HTTP 响应中返回数据。当攻击者诱使用户为易受攻击的 Web 应用程序提供危险内容,而这些危险内容随后会反馈给用户并在 Web 浏览器中执行时,就会发生 Reflected XSS 漏洞利用。发送恶意内容最常用的方法是,将恶意内容作为一个参数包含在公开发布或通过电子邮件直接发送给受害者的 URL 中。以这种手段构造的 URL 已成为多种网络钓鱼阴谋的核心,攻击者会借此诱骗受害者访问指向易受攻击站点的 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
等 MIME 类型时执行脚本。但是,Internet Explorer 等某些浏览器可执行称为 Content Sniffing
的内容。Content Sniffing 涉及到忽略提供的 MIME 类型并尝试根据响应的内容推断正确的 MIME 类型。text/html
是可能导致 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
等 MIME 类型时执行脚本。但是,Internet Explorer 等某些浏览器可执行称为 Content Sniffing
的内容。Content Sniffing 涉及到忽略提供的 MIME 类型并尝试根据响应的内容推断正确的 MIME 类型。text/html
是可能导致 XSS 漏洞的唯一 MIME 类型。可执行 SVG 图像 (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
,并将其显示给用户。
String queryString = Window.Location.getQueryString();
int pos = queryString.indexOf("eid=")+4;
HTML output = new HTML();
output.setHTML(queryString.substring(pos, queryString.length()));
eid
只包含标准的字母或数字文本,这个例子中的代码就能正确运行。如果 eid
中的某个值包含元字符或源代码,则 Web 浏览器就会在显示 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
的雇员 ID 仅包含标准字母数字文本,则这些代码示例可正确运行。如果 eid
中的某个值包含元字符或源代码,则 Web 浏览器就会在显示 HTTP 响应时执行该代码。
let element = JSON.parse(getUntrustedInput());
ReactDOM.render(<App>
{element}
</App>);
Example 3
中,如果攻击者可以控制从 getUntrustedInput()
检索到的整个 JSON 对象,他们可能就能够使 React 将 element
呈现为一个组件,从而可以使用他们自己控制的值传递具有 dangerouslySetInnerHTML
的对象,这是一种典型的 Cross-Site Scripting 攻击。