class AccessLevel{
public static final int ROOT = 0;
//...
public static final int NONE = 9;
}
//...
class User {
private static int access;
public User(){
access = AccessLevel.ROOT;
}
public static int getAccessLevel(){
return access;
}
//...
}
class RegularUser extends User {
private static int access;
public RegularUser(){
access = AccessLevel.NONE;
}
public static int getAccessLevel(){
return access;
}
public static void escalatePrivilege(){
access = AccessLevel.ROOT;
}
//...
}
//...
class SecureArea {
//...
public static void doRestrictedOperation(User user){
if (user instanceof RegularUser){
if (user.getAccessLevel() == AccessLevel.ROOT){
System.out.println("doing a privileged operation");
}else{
throw new RuntimeException();
}
}
}
}
user
实例,而非 User
或 RegularUser
类来调用 getAccessLevel()
方法,这意味着此条件下将始终返回 true
且会执行该限制操作,即使使用了 instanceof
以便进入 if/else
块的此部分也是如此。
private void writeObject(java.io.ObjectOutputStream out) throws IOException;
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;
private void readObjectNoData() throws ObjectStreamException;
serialPersistentFields
,必须将其声明为 private
、static
和 final
。serialPersistentFields
数组中指定类的可序列化的字段来手动定义这些字段。仅当 serialPersistentFields
被声明为 private
、static
和 final
时,此功能才能运行。serialPersistentFields
的声明将不会用来定义 Serializable
字段,因为它不是 private
、static
和 final
。
class List implements Serializable {
public ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("myField", List.class) };
...
}
Object.equals()
,而非 java.util.Arrays.equals().
Object.equals()
会检查数组地址是否相同而非检查数组元素是否相同,因此在大多数情况下这是一个错误调用,通常应将该代码替换为 java.util.Arrays.equals()
。 Object.equals()
函数检查两个数组。
...
int[] arr1 = new int[10];
int[] arr2 = new int[10];
...
if (arr1.equals(arr2)){
//treat arrays as if identical elements
}
...
System.Object.Equals()
:
public boolean Equals(string obj) {
...
}
System.Object.Equals()
采用 object
类型的参数,因此永远不会调用该方法。Object.equals()
:
public boolean equals(Object obj1, Object obj2) {
...
}
Object.equals()
只需要一个参数,因此永远不会调用Example 1
中的方法。getOutputStream
之后调用 getWriter()
也是错误的做法,反之亦然。HttpServletRequest
、重定向 HttpServletResponse
或者刷新 servlet 的输出流缓冲区会导致提交相关的数据流。后续执行的任何缓冲区重置或数据流提交操作,例如额外的刷新或重定向,将会导致出现 IllegalStateException
。ServletOutputStream
或 PrintWriter
(但不能同时使用)将数据写入响应数据流。调用 getOutputStream()
之后调用 getWriter()
或者反向调用,也会导致出现 IllegalStateException
。IllegalStateException
会阻止响应处理程序完成运行,轻易地使其中断响应。这会导致服务器不稳定,也间接表明 servlet 实现不正确。例 2:相反,以下代码在请求转发之后会尝试写入并刷新
public class RedirectServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
...
OutputStream out = res.getOutputStream();
...
// flushes, and thereby commits, the output stream
out.flush();
out.close(); // redirecting the response causes an IllegalStateException
res.sendRedirect("http://www.acme.com");
}
}
PrintWriter
的缓冲区。
public class FlushServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
...
// forwards the request, implicitly committing the stream
getServletConfig().getServletContext().getRequestDispatcher("/jsp/boom.jsp").forward(req, res);
...
// IllegalStateException; cannot redirect after forwarding
res.sendRedirect("http://www.acme.com/jsp/boomboom.jsp");
PrintWriter out = res.getWriter();
// writing to an already-committed stream will not cause an exception,
// but will not apply these changes to the final output, either
out.print("Writing here does nothing");
// IllegalStateException; cannot flush a response's buffer after forwarding the request
out.flush();
out.close();
}
}
Content-Length
头文件设为负值。Content-Length
请求标题表示开发者对0
或Content-Length
。
URL url = new URL("http://www.example.com");
HttpURLConnection huc = (HttpURLConnection)url.openConnection();
huc.setRequestProperty("Content-Length", "-1000");
Content-Length
头文件设为负值。Content-Length
请求标题表示开发者对0
或Content-Length
头文件设置为负值:
xhr.setRequestHeader("Content-Length", "-1000");
java.io.Serializable
的内部类可能会导致问题以及泄露外部类中的信息。
...
class User implements Serializable {
private int accessLevel;
class Registrator implements Serializable {
...
}
}
Example 1
中,对内部类 Registrator
执行序列化后,也会对外部类 User
的 accessLevel
字段执行序列化。synchronized
,以保证当多个线程访问相同实例时的正确行为。应将所有重写方法声明为 synchronized
,否则可能会发生意外行为。Foo
覆盖类 Bar
,但未将方法 synchronizedMethod
声明为 synchronized
:
public class Bar {
public synchronized void synchronizedMethod() {
for (int i=0; i<10; i++) System.out.print(i);
System.out.println();
}
}
public class Foo extends Bar {
public void synchronizedMethod() {
for (int i=0; i<10; i++) System.out.print(i);
System.out.println();
}
}
Foo
实例会被转换为 Bar
类型。如果将相同的实例交给两个独立线程,并重复执行 synchronizedMethod
,则行为将不可预知。obj.Equals(null)
将始终为 false。Equals()
方法将一个对象与 null
作比较。Equals()
方法的约定要求这一比较过程始终返回 false。obj.equals(null)
将总是 false。equals()
方法将一个对象与 null
进行比较。这种比较将始终返回 false,因为该对象并不是 null
。(如果对象为 null
,则程序将抛出 NullPointerException
异常)。readObject()
方法会调用可能被覆盖的函数。readObject()
充当构造函数,因此到此函数终止时,对象初始化才会完成。因此,如果 Serializable
类的 readObject()
函数调用了可覆盖的函数,则在对象尚未完成初始化之前,可能会提供对象状态的覆盖方法访问权限。readObject()
函数调用了可覆盖的方法。
...
private void readObject(final ObjectInputStream ois) throws IOException, ClassNotFoundException {
checkStream(ois);
ois.defaultReadObject();
}
public void checkStream(ObjectInputStream stream){
...
}
checkStream()
和其封装类并非 final
和公共字段,则意味着该函数是可覆盖的,这意味着攻击者可以覆盖 checkStream()
函数,以便在反序列化过程中访问对象。
Marker child = MarkerManager.getMarker("child");
Marker parent = MarkerManager.getMarker("parent");
child.addParents(parent);
parent.addParents(child);
String toInfinity = child.toString();
toString()
时,会触发堆栈溢出异常(堆栈耗尽)。此异常是由于 child 和 parent 之间存在循环链接而导致的。String
对象进行对比非常不可靠,不应该这样做。String
对象进行比较,则必须先将该值更改为 String
对象,通常是通过如 Double.toString()
等函数来实现。在将浮点变量转换为 String
对象后,其可能为 "NaN"、"Infinity" 或 "-Infinity",或者带有几位小数点(其中包含 0),或者可能包含指数字段,具体取决于浮点变量的类型和数值。如果转换为十六进制字符串,则其形式也会有很大差异。String
进行了比较。
...
int initialNum = 1;
...
String resultString = Double.valueOf(initialNum/10000.0).toString();
if (s.equals("0.0001")){
//do something
...
}
...
ToString()
在数组上被调用。ToString()
表示开发者希望将数组内容作为字符串返回。然而,在数组上直接调用 ToString()
将返回一个字符串值,它包含该数组的类型。System.String[]
。
String[] stringArray = { "element 1", "element 2", "element 3", "element 4" };
System.Diagnostics.Debug.WriteLine(stringArray.ToString());
toString()
在数组上被调用。toString()
表示开发者希望将数组内容作为字符串返回。然而,在数组上直接调用 toString()
将返回一个字符串值,它包含内存中该数组的类型和哈希码。[Ljava.lang.String;@1232121
。
String[] strList = new String[5];
...
System.out.println(strList);
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
,从而可能导致攻击者完全控制系统。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);
isSecure
参数设置为 true
。Secure
标记。如果设置了该标记,那么浏览器只会通过 HTTPS 发送 Cookie。通过未加密的通道发送 Cookie 将使其受到 Network Sniffing 攻击,因此该安全标记有助于保护 Cookie 值的机密性。如果 Cookie 包含私人数据或带有会话标识符,那么该标记尤其重要。isSecure
参数设置为 true
。
...
Cookie cookie = new Cookie('emailCookie', emailCookie, path, maxAge, false, 'Strict');
...
isSecure
参数,那么在 HTTPS 请求过程中发送的 Cookie 也会在随后的 HTTP 请求过程中被发送。通过未加密的无线连接探查网络流量对攻击者而言十分简单,因此通过 HTTP 发送 Cookie(特别是具有会话 ID 的 Cookie)可能会危及应用程序安全。Secure
标记设置为 true
。Secure
标记。如果设置了该标记,那么浏览器只会通过 HTTPS 发送 cookie。通过未加密的通道发送 cookie 将使其受到网络截取攻击,因此安全标记有助于保护 cookie 值的保密性。如果 cookie 包含私人数据或带有会话标识符,那么该标记尤其重要。Secure
属性的情况下,为响应添加了一个 Cookie。
...
HttpCookie cookie = new HttpCookie("emailCookie", email);
Response.AppendCookie(cookie);
...
Secure
标记,那么在 HTTPS 请求过程中发送的 cookie 也会在随后的 HTTP 请求过程中被发送。通过未加密的无线连接截取网络信息流对攻击者而言十分简单,因此通过 HTTP 发送 cookie(特别是具有会话 ID 的 cookie)可能会危及应用程序安全。Secure
标记设置为 true
。Secure
标记。如果设置了该标记,那么浏览器只会通过 HTTPS 发送 Cookie。通过未加密的通道发送 Cookie 将使其受到 Network Sniffing 攻击,因此该 secure 标记有助于保护 Cookie 值的机密性。如果 Cookie 包含私人数据或会话标识符,或带有 CSRF 标记,那么该标记尤其重要。Secure
标记的情况下将 cookie 添加到响应中。
cookie := http.Cookie{
Name: "emailCookie",
Value: email,
}
http.SetCookie(response, &cookie)
...
Secure
标记,那么在 HTTPS 请求过程中发送的 Cookie 也会在随后的 HTTP 请求过程中被发送。攻击者随后可截取未加密的网络信息流(通过无线网络时十分容易),从而危及 cookie 安全。Secure
标记设置为 true
。Secure
标记。如果设置了该标记,那么浏览器只会通过 HTTPS 发送 Cookie。通过未加密的通道发送 Cookie 将使其受到 Network Sniffing 攻击,因此该 secure 标记有助于保护 Cookie 值的机密性。如果 Cookie 包含私人数据或带有会话标识符,那么该标记尤其重要。use-secure-cookie
属性允许 remember-me
Cookie 通过未加密的传输发送出去。
<http auto-config="true">
...
<remember-me use-secure-cookie="false"/>
</http>
Secure
标记,那么在 HTTPS 请求过程中发送的 Cookie 也会在随后的 HTTP 请求过程中被发送。通过未加密的无线连接监听网络通信对攻击者而言十分简单,因此通过 HTTP 发送 Cookie(特别是具有会话 ID 的 Cookie)可能会危及应用程序安全。Secure
标记设置为 true
。Secure
标记。如果设置了该标记,那么浏览器只会通过 HTTPS 发送 cookie。通过未加密的通道发送 cookie 将使其受到网络截取攻击,因此安全标记有助于保护 cookie 值的保密性。如果 cookie 包含私人数据或带有会话标识符,那么该标记尤其重要。Secure
属性设置为 true
的情况下,为响应添加了一个 Cookie。
res.cookie('important_cookie', info, {domain: 'secure.example.com', path: '/admin', httpOnly: true, secure: false});
Secure
标记,那么在 HTTPS 请求过程中发送的 cookie 也会在随后的 HTTP 请求过程中被发送。通过未加密的无线连接截取网络信息流对攻击者而言十分简单,因此通过 HTTP 发送 cookie(特别是具有会话 ID 的 cookie)可能会危及应用程序安全。NSHTTPCookieSecure
标记设置为 TRUE
。Secure
标记。如果设置了该标记,那么浏览器只会通过 HTTPS 发送 cookie。通过未加密的通道发送 cookie 将使其受到网络截取攻击,因此安全标记有助于保护 cookie 值的保密性。如果 cookie 包含私人数据或带有会话标识符,那么该标记尤其重要。Secure
标记的情况下,为响应添加了一个 Cookie。
...
NSDictionary *cookieProperties = [NSDictionary dictionary];
...
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
...
Secure
标记,那么在 HTTPS 请求过程中发送的 cookie 也会在随后的 HTTP 请求过程中被发送。通过未加密的无线连接截取网络信息流对攻击者而言十分简单,因此通过 HTTP 发送 cookie(特别是具有会话 ID 的 cookie)可能会危及应用程序安全。Secure
标记设置为 true
。Secure
标记。如果设置了该标记,那么浏览器只会通过 HTTPS 发送 cookie。通过未加密的通道发送 cookie 将使其受到网络截取攻击,因此安全标记有助于保护 cookie 值的保密性。如果 cookie 包含私人数据或带有会话标识符,那么该标记尤其重要。Secure
标记的情况下将 cookie 添加到响应中。
...
setcookie("emailCookie", $email, 0, "/", "www.example.com");
...
Secure
标记,那么在 HTTPS 请求过程中发送的 Cookie 也会在随后的 HTTP 请求过程中被发送。攻击者随后可截取未加密的网络信息流(通过无线网络时十分容易),从而危及 cookie 安全。Secure
标记设置为 True
。Secure
标记。如果设置了该标记,那么浏览器只会通过 HTTPS 发送 cookie。通过未加密的通道发送 cookie 将使其受到网络截取攻击,因此安全标记有助于保护 cookie 值的保密性。如果 cookie 包含私人数据或会话标识符,或带有 CSRF 标记,那么该标记尤其重要。Secure
标记的情况下将 cookie 添加到响应中。
from django.http.response import HttpResponse
...
def view_method(request):
res = HttpResponse()
res.set_cookie("emailCookie", email)
return res
...
Secure
标记,那么在 HTTPS 请求过程中发送的 Cookie 也会在随后的 HTTP 请求过程中被发送。攻击者随后可截取未加密的网络信息流(通过无线网络时十分容易),从而危及 cookie 安全。Secure
标记设置为 true
。Secure
标记。如果设置了该标记,那么浏览器只会通过 HTTPS 发送 Cookie。通过未加密的通道发送 Cookie 将使其受到 Network Sniffing 攻击,因此该 secure 标记有助于保护 Cookie 值的机密性。如果 Cookie 包含私人数据或带有会话标识符,那么该标记尤其重要。Secure
标记的情况下,为响应添加了一个 Cookie。
Ok(Html(command)).withCookies(Cookie("sessionID", sessionID, secure = false))
Secure
标记,那么在 HTTPS 请求过程中发送的 Cookie 也会在随后的 HTTP 请求过程中被发送。通过未加密的无线连接监听网络通信对攻击者而言十分简单,因此通过 HTTP 发送 Cookie(特别是具有会话 ID 的 Cookie)可能会危及应用程序安全。NSHTTPCookieSecure
标记设置为 TRUE
。Secure
标记。如果设置了该标记,那么浏览器只会通过 HTTPS 发送 Cookie。通过未加密的通道发送 Cookie 将使其受到 Network Sniffing 攻击,因此该 secure 标记有助于保护 Cookie 值的机密性。如果 Cookie 包含私人数据或带有会话标识符,那么该标记尤其重要。Secure
标记的情况下,为响应添加了一个 Cookie。
...
let properties = [
NSHTTPCookieDomain: "www.example.com",
NSHTTPCookiePath: "/service",
NSHTTPCookieName: "foo",
NSHTTPCookieValue: "bar"
]
let cookie : NSHTTPCookie? = NSHTTPCookie(properties:properties)
...
Secure
标记,那么在 HTTPS 请求过程中发送的 Cookie 也会在随后的 HTTP 请求过程中被发送。通过未加密的无线连接监听网络通信对攻击者而言十分简单,因此通过 HTTP 发送 Cookie(特别是具有会话 ID 的 Cookie)可能会危及应用程序安全。HttpOnly
标记设置为 true
。HttpOnly
Cookie 属性,以阻止客户端脚本访问 Cookie。Cross-Site Scripting 攻击通常会访问 Cookie,以试图窃取会话标识符或身份验证标记。如果未启用 HttpOnly
标记,攻击者就能更容易地访问用户 Cookie。HttpOnly
属性的情况下创建一个 Cookie。
HttpCookie cookie = new HttpCookie("emailCookie", email);
Response.AppendCookie(cookie);
HttpOnly
标记设置为 true
。HttpOnly
Cookie 属性,可阻止客户端脚本访问 Cookie。Cross-Site Scripting 攻击通常会访问 Cookie,以试图窃取会话标识符或身份验证标记。如果未启用 HttpOnly
,攻击者就能更容易地访问用户 Cookie。HttpOnly
属性的情况下创建一个 Cookie。
cookie := http.Cookie{
Name: "emailCookie",
Value: email,
}
...
HttpOnly
标记设置为 true
。HttpOnly
Cookie 属性,以阻止客户端脚本访问 Cookie。Cross-Site Scripting 攻击通常会访问 Cookie,以试图窃取会话标识符或身份验证标记。如果未启用 HttpOnly
标记,攻击者就能更容易地访问用户 Cookie。HttpOnly
属性的情况下创建一个 Cookie。
javax.servlet.http.Cookie cookie = new javax.servlet.http.Cookie("emailCookie", email);
// Missing a call to: cookie.setHttpOnly(true);
HttpOnly
标记设置为 true
。HttpOnly
Cookie 属性,以阻止客户端脚本访问 Cookie。Cross-Site Scripting 攻击通常会访问 Cookie,以试图窃取会话标识符或身份验证标记。如果未启用 HttpOnly
标记,攻击者就能更容易地访问用户 Cookie。httpOnly
属性的情况下创建一个 Cookie。
res.cookie('important_cookie', info, {domain: 'secure.example.com', path: '/admin'});
HttpOnly
标记设置为 true
。HttpOnly
Cookie 属性,以阻止客户端脚本访问 Cookie。Cross-Site Scripting 攻击通常会访问 Cookie,以试图窃取会话标识符或身份验证标记。如果未启用 HttpOnly
标记,攻击者就能更容易地访问用户 Cookie。HttpOnly
属性的情况下创建一个 Cookie。
setcookie("emailCookie", $email, 0, "/", "www.example.com", TRUE); //Missing 7th parameter to set HttpOnly
HttpOnly
标记设置为 True
。HttpOnly
Cookie 属性,可阻止客户端脚本访问 Cookie。Cross-Site Scripting 攻击通常会访问 Cookie,以试图窃取会话标识符或身份验证令牌。如果未启用 HttpOnly
,攻击者就能更容易地访问用户 Cookie。HttpOnly
属性的情况下创建一个 Cookie。
from django.http.response import HttpResponse
...
def view_method(request):
res = HttpResponse()
res.set_cookie("emailCookie", email)
return res
...
HttpOnly
标记设置为 true
。HttpOnly
Cookie 属性,以阻止客户端脚本访问 Cookie。Cross-Site Scripting 攻击通常会访问 Cookie,以试图窃取会话标识符或身份验证标记。如果未启用 HttpOnly
标记,攻击者就能更容易地访问用户 Cookie。HttpOnly
属性的情况下创建一个 Cookie。
Ok(Html(command)).withCookies(Cookie("sessionID", sessionID, httpOnly = false))
HttpOnly
标记设置为 true
。HttpOnly
Cookie 属性,以阻止客户端脚本访问 Cookie。Cross-Site Scripting 攻击通常会访问 Cookie,以试图窃取会话标识符或身份验证标记。如果未启用 HttpOnly
标记,攻击者就能更容易地访问用户 Cookie。HttpOnly
标记设置为 true
的情况下创建会话 Cookie。
server.servlet.session.cookie.http-only=false
HttpOnly
标记设置为 true
。HttpOnly
Cookie 属性,以阻止客户端脚本访问 Cookie。Cross-Site Scripting 攻击通常会访问 Cookie,以试图窃取会话标识符或身份验证标记。如果未启用 HttpOnly
标记,攻击者就能更容易地访问用户 Cookie。HttpOnly
标记设置为 true
的情况下创建会话 Cookie。
session_set_cookie_params(0, "/", "www.example.com", true, false);
HttpOnly
标记设置为 true
。HttpOnly
Cookie 属性,可阻止客户端脚本访问 Cookie。Cross-Site Scripting 攻击通常会访问 Cookie,以试图窃取会话标识符或身份验证令牌。如果未启用 HttpOnly
,攻击者就能更容易地访问用户 Cookie。HttpOnly
属性的情况下显式设置会话 Cookie。
...
MIDDLEWARE = (
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'csp.middleware.CSPMiddleware',
'django.middleware.security.SecurityMiddleware',
...
)
...
SESSION_COOKIE_HTTPONLY = False
...