输入验证与表示问题是由元字符、交替编码和数字表示引起的。安全问题源于信任输入。这些问题包括:“Buffer Overflows”、“Cross-Site Scripting”攻击、“SQL Injection”等其他问题。
Value Stack
上下文中计算 EL 表达式。允许根据 Value Stack
计算未经验证的表达式,这将使攻击者有权修改系统变量或执行任意代码。
OgnlContext ctx = new OgnlContext();
String expression = request.getParameter("input");
Object expr = Ognl.parseExpression(expression);
Object value = Ognl.getValue(expr, ctx, root);
System.out.println("Value: " + value);
(#rt = @java.lang.Runtime@getRuntime(),#rt.exec("calc.exe"))
%{expr}
)。控制第一次计算结果的攻击者可能会控制要在第二次 OGNL 计算中计算的表达式,并注入任意 OGNL 表达式。redirectAction
结果可计算其参数两次。在这种情况下,攻击者可以通过提供 redirect
请求参数,控制 actionName
参数中强制 OGNL 表达式的结果。
...
<action name="index" class="com.acme.MyAction">
<result type="redirectAction">
<param name="actionName">${#parameters['redirect']}</param>
<param name="namespace">/foo</param>
</result>
</action>
...
%{#parameters['redirect']}
表达式,该表达式返回的用户控制字符串将作为 OGNL 表达式进行计算,从而允许攻击者计算任意 OGNL 表达式。execute()
以外的方法。如果启用“动态方法调用”,可在操作 URL 中使用 !
(bang) 字符或 method:
前缀,以在操作中调用任何公共方法。在 Struts 2 版本 2.3.20
中,先前基于反映调用替代方法的机制将替换为使用 OGNL,这样攻击者将可以提供恶意 OGNL 表达式而不是替代方法名称。debug
请求参数触发:console
将弹出 OGNL 评估控制台,允许开发人员对服务器上的任意 OGNL 表达式进行评估。command
将允许开发人员提交任意 OGNL 表达式,以使用请求参数 expression
进行评估。xml
可将参数、上下文、会话和值堆栈转储为一个 XML 文档。browser
可将参数、上下文、会话和值堆栈转储在一个可浏览的 HTML 文档中。dest
请求参数中解析的 URL。
...
DATA: str_dest TYPE c.
str_dest = request->get_form_field( 'dest' ).
response->redirect( str_dest ).
...
Example 1
中的代码就会将浏览器重定向到“http://www.wilyhacker.com”。dest
请求参数中读取的 URL。
...
var params:Object = LoaderInfo(this.root.loaderInfo).parameters;
var strDest:String = String(params["dest"]);
host.updateLocation(strDest);
...
Example 1
中的代码就会将浏览器重定向到“http://www.wilyhacker.com”。PageReference
对象,其中包含来自 dest
请求参数的 URL。
public PageReference pageAction() {
...
PageReference ref = ApexPages.currentPage();
Map<String,String> params = ref.getParameters();
return new PageReference(params.get('dest'));
}
Example 1
中的代码就会将浏览器重定向到“http://www.wilyhacker.com”。dest
请求参数中解析的 URL。
String redirect = Request["dest"];
Response.Redirect(redirect);
Example 1
中的代码就会将浏览器重定向到“http://www.wilyhacker.com”。dest
请求参数解析的 URL。
...
final server = await HttpServer.bind(host, port);
await for (HttpRequest request in server) {
final response = request.response;
final headers = request.headers;
final strDest = headers.value('strDest');
response.headers.contentType = ContentType.text;
response.redirect(Uri.parse(strDest!));
await response.close();
}
...
Example 1
中的代码就会将浏览器重定向到“http://www.wilyhacker.com”。dest
请求参数解析的 URL。
...
strDest := r.Form.Get("dest")
http.Redirect(w, r, strDest, http.StatusSeeOther)
...
Example 1
中的代码就会将浏览器重定向到 "http://www.wilyhacker.com"。dest
请求参数解析的 URL。
<end-state id="redirectView" view="externalRedirect:#{requestParameters.dest}" />
Example 1
中的代码就会将浏览器重定向到“http://www.wilyhacker.com”。dest
请求参数中读取的 URL。
...
strDest = form.dest.value;
window.open(strDest,"myresults");
...
Example 1
中的代码就会将浏览器重定向到“http://www.wilyhacker.com”。dest
请求参数中解析的 URL。
<%
...
$strDest = $_GET["dest"];
header("Location: " . $strDest);
...
%>
Example 1
中的代码就会将浏览器重定向到“http://www.wilyhacker.com”。dest
请求参数解析的 URL。
...
-- Assume QUERY_STRING looks like dest=http://www.wilyhacker.com
dest := SUBSTR(OWA_UTIL.get_cgi_env('QUERY_STRING'), 6);
OWA_UTIL.redirect_url('dest');
...
Example 1
中的代码就会将浏览器重定向到“http://www.wilyhacker.com”。dest
请求参数中解析的 URL。
...
strDest = request.field("dest")
redirect(strDest)
...
Example 1
中的代码就会将浏览器重定向到“http://www.wilyhacker.com”。dest
请求参数中解析的 URL:
...
str_dest = req.params['dest']
...
res = Rack::Response.new
...
res.redirect("http://#{dest}")
...
Example 1
中的代码就会将浏览器重定向到“http://www.wilyhacker.com”。dest
请求参数中解析的 URL。
def myAction = Action { implicit request =>
...
request.getQueryString("dest") match {
case Some(location) => Redirect(location)
case None => Ok("No url found!")
}
...
}
Example 1
中的代码就会将浏览器重定向到“http://www.wilyhacker.com”。requestToLoad
来指向原始 URL 的“dest”参数(如果存在该参数,如果不存在则指向使用 http://
方案的原始 URL),并最终在 WKWebView 内加载此请求:
...
let requestToLoad : String
...
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
...
if let urlComponents = NSURLComponents(URL: url, resolvingAgainstBaseURL: false) {
if let queryItems = urlComponents.queryItems as? [NSURLQueryItem]{
for queryItem in queryItems {
if queryItem.name == "dest" {
if let value = queryItem.value {
request = NSURLRequest(URL:NSURL(string:value))
requestToLoad = request
break
}
}
}
}
if requestToLoad == nil {
urlComponents.scheme = "http"
requestToLoad = NSURLRequest(URL:urlComponents.URL)
}
}
...
}
...
...
let webView : WKWebView
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
webView.loadRequest(appDelegate.requestToLoad)
...
Example 1
中的代码会尝试在 WKWebView 中请求并加载“http://www.wilyhacker.com”。dest
请求参数中解析的 URL。
...
strDest = Request.Form('dest')
HyperLink.NavigateTo strDest
...
Example 1
中的代码就会将浏览器重定向到“http://www.wilyhacker.com”。strncpy()
),使用方式不正确也会引发漏洞。对内存的处理加之有关数据段大小和结构方面所存在种种错误假设,是导致大多数 buffer overflow 漏洞产生的根源。memcpy()
调用会从分配的 cArray
边界之外读取内存,其中包含 char
类型的 MAX
元素,而 iArray
包含 int
类型的 MAX
元素。例 2:以下短程序在使用分析用的字元常数
void MemFuncs() {
char array1[MAX];
int array2[MAX];
memcpy(array2, array1, sizeof(array2));
}
memchr()
时,将一个不可信赖的命令行参数作为搜索缓冲区使用。
int main(int argc, char** argv) {
char* ret = memchr(argv[0], 'x', MAX_PATH);
printf("%s\n", ret);
}
argv[0]
数据直至一个常数字节来输出 argv[0]
的一个子字符串。然而,因为(常数)字节数可能大于为 argv[0]
分配的数据,搜索可能在分配给 argv[0]
的数据之外进行。当在 argv[0]
中无法找到 x
时会发生这种情况。strncpy()
),使用方式不正确也会引发漏洞。对内存的处理加之有关数据段大小和结构方面所存在种种错误假设,是导致大多数 buffer overflow 漏洞产生的根源。char
五元数组,最后一个引用会引入 off-by-one 错误。
char Read() {
char buf[5];
return 0
+ buf[0]
+ buf[1]
+ buf[2]
+ buf[3]
+ buf[4]
+ buf[5];
}
strncpy()
),使用方式不正确也会引发漏洞。对内存的处理加之有关数据段大小和结构方面所存在种种错误假设,是导致大多数 buffer overflow 漏洞产生的根源。getInputLength()
中读取的不可信的值,验证其是否小于目标缓冲区 output
的大小,来避免从边界之外进行读取的 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);
}
...
}
...
*Get the report that is to be deleted
r_name = request->get_form_field( 'report_name' ).
CONCATENATE `C:\\users\\reports\\` r_name INTO dsn.
DELETE DATASET dsn.
...
..\\..\\usr\\sap\\DVEBMGS00\\exe\\disp+work.exe
”的文件夹名,应用程序会删除重要文件,导致 SAP 系统立即崩溃。
...
PARAMETERS: p_date TYPE string.
*Get the invoice file for the date provided
CALL FUNCTION 'FILE_GET_NAME'
EXPORTING
logical_filename = 'INVOICE'
parameter_1 = p_date
IMPORTING
file_name = v_file
EXCEPTIONS
file_not_found = 1
OTHERS = 2.
IF sy-subrc <> 0.
* Implement suitable error handling here
ENDIF.
OPEN DATASET v_file FOR INPUT IN TEXT MODE.
DO.
READ DATASET v_file INTO v_record.
IF SY-SUBRC NE 0.
EXIT.
ELSE.
WRITE: / v_record.
ENDIF.
ENDDO.
...
..\\..\\usr\\sap\\sys\\profile\\default.pfl
”的字符串,而不提供有效日期,应用程序将显示所有默认 SAP 应用程序服务器配置文件参数设置,这可能会导致更精确的攻击。../../tomcat/conf/server.xml
”一样的文件名,从而导致应用程序删除它自己的配置文件。示例 2:下面的代码使用来自于配置文件的输入来决定打开哪个文件,并写入“Debug”控制台或日志文件。如果程序以足够的权限运行,且恶意用户能够篡改配置文件,那么他们可以通过程序读取系统中以扩展名
var params:Object = LoaderInfo(this.root.loaderInfo).parameters;
var rName:String = String(params["reportName"]);
var rFile:File = new File("/usr/local/apfr/reports/" + rName);
...
rFile.deleteFile();
.txt
结尾的任何文件。
var fs:FileStream = new FileStream();
fs.open(new File(String(configStream.readObject())+".txt"), FileMode.READ);
fs.readBytes(arr);
trace(arr);
public class MyController {
...
public PageRerference loadRes() {
PageReference ref = ApexPages.currentPage();
Map<String,String> params = ref.getParameters();
if (params.containsKey('resName')) {
if (params.containsKey('resPath')) {
return PageReference.forResource(params.get('resName'), params.get('resPath'));
}
}
return null;
}
}
..\\..\\Windows\\System32\\krnl386.exe
”这样的文件名,这会导致应用程序删除重要的 Windows 系统文件。示例 2:以下代码使用来自于配置文件的输入来决定打开哪个文件,并返回给用户。如果程序以足够的权限运行,并且恶意用户能够篡改配置文件,那么他们就可以使用该程序来读取系统中以“.txt”扩展名结尾的任何文件。
String rName = Request.Item("reportName");
...
File.delete("C:\\users\\reports\\" + rName);
sr = new StreamReader(resmngr.GetString("sub")+".txt");
while ((line = sr.ReadLine()) != null) {
Console.WriteLine(line);
}
../../apache/conf/httpd.conf
”一样的文件名,从而导致应用程序删除特定的配置文件。示例 2:以下代码使用来自于命令行的输入来决定该打开哪个文件,并返回到用户。如果程序以足够的权限运行,并且恶意用户能够创建指向文件的软链接,那么他们可以使用程序来读取系统中任何文件的开始部分。
char* rName = getenv("reportName");
...
unlink(rName);
ifstream ifs(argv[0]);
string s;
ifs >> s;
cout << s;
...
EXEC CICS
WEB READ
FORMFIELD(FILE)
VALUE(FILENAME)
...
END-EXEC.
EXEC CICS
READ
FILE(FILENAME)
INTO(RECORD)
RIDFLD(ACCTNO)
UPDATE
...
END-EXEC.
...
..\\..\\Windows\\System32\\krnl386.exe
”这样的文件名,这会导致应用程序删除重要的 Windows 系统文件。
<cffile action = "delete"
file = "C:\\users\\reports\\#Form.reportName#">
final server = await HttpServer.bind('localhost', 18081);
server.listen((request) async {
final headers = request.headers;
final path = headers.value('path');
File(path!).delete();
}
Example 1
中,在对文件执行删除功能之前未验证 headers.value('path')
。../../tomcat/conf/server.xml
”一样的文件名,从而导致应用程序删除它自己的配置文件。示例 2:下面的代码使用来自于配置文件的输入来决定打开哪个文件,并返回给用户。如果程序以足够的权限运行,且恶意用户能够篡改配置文件,那么他们可以通过程序读取系统中以扩展名
rName := "/usr/local/apfr/reports/" + req.FormValue("fName")
rFile, err := os.OpenFile(rName, os.O_RDWR|os.O_CREATE, 0755)
defer os.Remove(rName);
defer rFile.Close()
...
.txt
结尾的任何文件。
...
config := ReadConfigFile()
filename := config.fName + ".txt";
data, err := ioutil.ReadFile(filename)
...
fmt.Println(string(data))
../../tomcat/conf/server.xml
”一样的文件名,从而导致应用程序删除它自己的配置文件。示例 2:以下代码使用来自于配置文件的输入来决定打开哪个文件,并返回给用户。如果程序以足够的权限运行,且恶意用户能够篡改配置文件,那么他们可以通过程序读取系统中以扩展名
String rName = request.getParameter("reportName");
File rFile = new File("/usr/local/apfr/reports/" + rName);
...
rFile.delete();
.txt
结尾的任何文件。
fis = new FileInputStream(cfg.getProperty("sub")+".txt");
amt = fis.read(arr);
out.println(arr);
Example 1
以适应 Android 平台。
...
String rName = this.getIntent().getExtras().getString("reportName");
File rFile = getBaseContext().getFileStreamPath(rName);
...
rFile.delete();
...
../../tomcat/conf/server.xml
”一样的文件名,从而导致应用程序删除它自己的配置文件。示例 2:以下代码使用来自于本地存储的输入来决定该打开哪个文件,并返回到用户。如果恶意用户能够更改本地存储的内容,就可以使用该程序来读取系统中扩展名为
...
var reportNameParam = "reportName=";
var reportIndex = document.indexOf(reportNameParam);
if (reportIndex < 0) return;
var rName = document.URL.substring(reportIndex+reportNameParam.length);
window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
fs.root.getFile('/usr/local/apfr/reports/' + rName, {create: false}, function(fileEntry) {
fileEntry.remove(function() {
console.log('File removed.');
}, errorHandler);
}, errorHandler);
}, errorHandler);
.txt
的任何文件。
...
var filename = localStorage.sub + '.txt';
function oninit(fs) {
fs.root.getFile(filename, {}, function(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
var txtArea = document.createElement('textarea');
txtArea.value = this.result;
document.body.appendChild(txtArea);
};
reader.readAsText(file);
}, errorHandler);
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 1024*1024, oninit, errorHandler);
...
../../tomcat/conf/server.xml
”一样的文件名,从而导致应用程序删除它自己的配置文件。示例 2:下面的代码使用来自于配置文件的输入来决定打开哪个文件,并返回给用户。如果程序以足够的权限运行,且恶意用户能够篡改配置文件,那么他们可以通过程序读取系统中以扩展名
val rName: String = request.getParameter("reportName")
val rFile = File("/usr/local/apfr/reports/$rName")
...
rFile.delete()
.txt
结尾的任何文件。
fis = FileInputStream(cfg.getProperty("sub").toString() + ".txt")
amt = fis.read(arr)
out.println(arr)
Example 1
以适应 Android 平台。
...
val rName: String = getIntent().getExtras().getString("reportName")
val rFile: File = getBaseContext().getFileStreamPath(rName)
...
rFile.delete()
...
- (NSData*) testFileManager {
NSString *rootfolder = @"/Documents/";
NSString *filePath = [rootfolder stringByAppendingString:[fileName text]];
NSFileManager *fm = [NSFileManager defaultManager];
return [fm contentsAtPath:filePath];
}
../../tomcat/conf/server.xml
”一样的文件名,从而导致应用程序删除它自己的配置文件。示例 2:以下代码使用来自于配置文件的输入来决定打开哪个文件,并返回给用户。如果程序以足够的权限运行,且恶意用户能够篡改配置文件,那么他们可以通过程序读取系统中以扩展名
$rName = $_GET['reportName'];
$rFile = fopen("/usr/local/apfr/reports/" . rName,"a+");
...
unlink($rFile);
.txt
结尾的任何文件。
...
$filename = $CONFIG_TXT['sub'] . ".txt";
$handle = fopen($filename,"r");
$amt = fread($handle, filesize($filename));
echo $amt;
...
../../tomcat/conf/server.xml
”一样的文件名,从而导致应用程序删除它自己的配置文件。示例 2:以下代码使用来自于配置文件的输入来决定打开哪个文件,并返回给用户。如果程序以足够的权限运行,且恶意用户能够篡改配置文件,那么他们可以通过程序读取系统中以扩展名
rName = req.field('reportName')
rFile = os.open("/usr/local/apfr/reports/" + rName)
...
os.unlink(rFile);
.txt
结尾的任何文件。
...
filename = CONFIG_TXT['sub'] + ".txt";
handle = os.open(filename)
print handle
...
../../tomcat/conf/server.xml
”一样的文件名,从而导致应用程序删除它自己的配置文件。示例 2:以下代码使用来自于配置文件的输入来决定打开哪个文件,并返回给用户。如果程序以足够的权限运行,且恶意用户能够篡改配置文件,那么他们可以通过程序读取系统中以扩展名
rName = req['reportName']
File.delete("/usr/local/apfr/reports/#{rName}")
.txt
结尾的任何文件。
...
fis = File.new("#{cfg.getProperty("sub")}.txt")
amt = fis.read
puts amt
../../tomcat/conf/server.xml
”一样的文件名,从而导致应用程序删除它自己的配置文件。示例 2:以下代码使用来自于配置文件的输入来决定打开哪个文件,并返回给用户。如果程序以足够的权限运行,且恶意用户能够篡改配置文件,那么他们可以通过程序读取系统中以扩展名
def readFile(reportName: String) = Action { request =>
val rFile = new File("/usr/local/apfr/reports/" + reportName)
...
rFile.delete()
}
.txt
结尾的任何文件。
val fis = new FileInputStream(cfg.getProperty("sub")+".txt")
val amt = fis.read(arr)
out.println(arr)
func testFileManager() -> NSData {
let filePath : String = "/Documents/\(fileName.text)"
let fm : NSFileManager = NSFileManager.defaultManager()
return fm.contentsAtPath(filePath)
}
..\conf\server.xml
”一样的文件名,从而导致应用程序删除它自己的配置文件。示例 2:以下代码使用来自于配置文件的输入来决定打开哪个文件,并返回给用户。如果程序以足够的权限运行,且恶意用户能够篡改配置文件,那么他们可以通过程序读取系统中以扩展名
Dim rName As String
Dim fso As New FileSystemObject
Dim rFile as File
Set rName = Request.Form("reportName")
Set rFile = fso.GetFile("C:\reports\" & rName)
...
fso.DeleteFile("C:\reports\" & rName)
...
.txt
结尾的任何文件。
Dim fileName As String
Dim tsContent As String
Dim ts As TextStream
Dim fso As New FileSystemObject
fileName = GetPrivateProfileString("MyApp", "sub", _
"", value, Len(value), _
App.Path & "\" & "Config.ini")
...
Set ts = fso.OpenTextFile(fileName,1)
tsContent = ts.ReadAll
Response.Write tsContent
...
Path.Combine
将多个文件路径作为参数。 连接它们可获得一条完整路径,通常后面跟随该文件的 read()
或 write()
调用。 根据第一个参数还是剩余参数是绝对路径,文档介绍了几种不同情况。 如果第二个或剩余参数为绝对路径,则 Path.Combine()
将返回该绝对路径。 以前的参数将忽略。 这里的含义对于具有类似下面示例代码的应用程序而言非常重要。
// Called with user-controlled data
public static bytes[] getFile(String filename)
{
String imageDir = "\\FILESHARE\images\";
filepath = Path.Combine(imageDir, filename);
return File.ReadAllBytes(filepath);
}
C:\\inetpub\wwwroot\web.config
),攻击者可以控制应用程序返回哪个文件。
...
" Add Binary File to
CALL METHOD lr_abap_zip->add
EXPORTING
name = p_ifile
content = lv_bufferx.
" Read Binary File to
CALL METHOD lr_abap_zip->get
EXPORTING
name = p_ifile
IMPORTING
content = lv_bufferx2.
...
Example 1
中,在对此条目中的数据执行读取/写入函数之前未验证 p_ifile
。如果 ZIP 文件最初放置在基于 Unix 的计算机的 "/tmp/
" 目录中,并且 ZIP 条目为 "../etc/hosts
",而应用程序在必要的权限下运行,则它将覆盖系统的 hosts
文件,从而会使该计算机的流量进入攻击者所需的任何位置,例如返回至攻击者的计算机。
public static void UnzipFile(ZipArchive archive, string destDirectory)
{
foreach (var entry in archive.Entries)
{
string file = entry.FullName;
if (!string.IsNullOrEmpty(file))
{
string destFileName = Path.Combine(destDirectory, file);
entry.ExtractToFile(destFileName, true);
}
}
}
Example 1
中,在对此条目中的数据执行读取/写入操作之前不会对 entry.FullName
进行验证。如果此 Zip 文件最初放置在“C:\TEMP
”目录中,并且某个 Zip 条目名称包含“..\
segments”,而应用程序在所需的权限下运行,则它可以随意覆盖系统文件。
func Unzip(src string, dest string) ([]string, error) {
var filenames []string
r, err := zip.OpenReader(src)
if err != nil {
return filenames, err
}
defer r.Close()
for _, f := range r.File {
// Store filename/path for returning and using later on
fpath := filepath.Join(dest, f.Name)
filenames = append(filenames, fpath)
if f.FileInfo().IsDir() {
// Make Folder
os.MkdirAll(fpath, os.ModePerm)
continue
}
// Make File
if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
return filenames, err
}
outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return filenames, err
}
rc, err := f.Open()
if err != nil {
return filenames, err
}
_, err = io.Copy(outFile, rc)
// Close the file without defer to close before next iteration of loop
outFile.Close()
rc.Close()
if err != nil {
return filenames, err
}
}
return filenames, nil
}
Example 1
中,在对此条目中的数据执行读取/写入函数之前未验证 f.Name
。如果 Zip 文件最初放置在基于 Unix 的计算机的“/tmp/
”目录中,并且 Zip 条目为“../etc/hosts
”,而应用程序在所需的权限下运行,则它将覆盖系统 hosts
文件。从而可能会使该计算机的流量进入攻击者所需的任何位置,例如返回至攻击者的计算机。
private static final int BUFSIZE = 512;
private static final int TOOBIG = 0x640000;
...
public final void unzip(String filename) throws IOException {
FileInputStream fis = new FileInputStream(filename);
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis));
ZipEntry zipEntry = null;
int numOfEntries = 0;
long total = 0;
try {
while ((zipEntry = zis.getNextEntry()) != null) {
byte data[] = new byte[BUFSIZE];
int count = 0;
String outFileName = zipEntry.getName();
if (zipEntry.isDirectory()){
new File(outFileName).mkdir(); //create the new directory
continue;
}
FileOutputStream outFile = new FileOutputStream(outFileName);
BufferedOutputStream dest = new BufferedOutputStream(outFile, BUFSIZE);
//read data from Zip, but do not read huge entries
while (total + BUFSIZE <= TOOBIG && (count = zis.read(data, 0, BUFSIZE)) != -1) {
dest.write(data, 0, count);
total += count;
}
...
}
} finally{
zis.close();
}
}
...
Example 1
中,在对此条目中的数据执行读取/写入函数之前未验证 zipEntry.getName()
。如果 Zip 文件最初放置在基于 Unix 的计算机的“/tmp/
”目录中,并且 Zip 条目为“../etc/hosts
”,而应用程序在所需的权限下运行,则它将覆盖系统 hosts
文件。从而可能会使该计算机的流量进入攻击者所需的任何位置,例如返回至攻击者的计算机。
var unzipper = require('unzipper');
var fs = require('fs');
var untrusted_zip = getZipFromRequest();
fs.createReadStream(zipPath).pipe(unzipper.Extract({ path: 'out' }));
ZZArchive* archive = [ZZArchive archiveWithURL:[NSURL fileURLWithPath: zipPath] error:&error];
for (ZZArchiveEntry* entry in archive.entries) {
NSString *fullPath = [NSString stringWithFormat: @"%@/%@", destPath, [entry fileName]];
[[entry newDataWithError:nil] writeToFile:newFullPath atomically:YES];
}
Example 1
中,在对此条目中的数据执行读取/写入函数之前未验证 entry.fileName
。如果 Zip 文件最初放置在 iOS 应用程序的“Documents/hot_patches
”目录中,并且 Zip 条目为“../js/page.js
”,则它将覆盖 page.js
文件,从而可能会使攻击者能够注入可能导致代码执行的恶意代码。
...
$zip = new ZipArchive();
$zip->open("userdefined.zip", ZipArchive::RDONLY);
$zpm = $zip->getNameIndex(0);
$zip->extractTo($zpm);
...
Example 1
中,在对此条目中的数据执行读取/写入函数之前未验证 f.Name
。如果 Zip 文件位于基于 Unix 的计算机的“/tmp/
”目录中,并且 Zip 条目为“../etc/hosts
”,而应用程序在所需的权限下运行,则它将覆盖系统 hosts
文件。这样会使该计算机的流量进入攻击者所需的任何位置,例如返回至攻击者的计算机。
import zipfile
import tarfile
def unzip(archive_name):
zf = zipfile.ZipFile(archive_name)
zf.extractall(".")
zf.close()
def untar(archive_name):
tf = tarfile.TarFile(archive_name)
tf.extractall(".")
tf.close()
示例 2:以下示例从 Zip 文件中提取文件并以不安全的方式将其写入磁盘。
import better.files._
...
val zipPath: File = getUntrustedZip()
val destinationPath = file"out/dest"
zipPath.unzipTo(destination = destinationPath)
import better.files._
...
val zipPath: File = getUntrustedZip()
val destinationPath = file"out/dest"
zipPath.newZipInputStream.mapEntries( (entry : ZipEntry) => {
entry.extractTo(destinationPath, new FileInputStream(entry.getName))
})
Example 2
中,在对此条目中的数据执行读取/写入函数之前未验证 entry.getName
。如果 Zip 文件最初放置在基于 Unix 的计算机的“/tmp/
”目录中,并且 Zip 条目为“../etc/hosts
”,而应用程序在所需的权限下运行,则它将覆盖系统 hosts
文件。从而可能会使该计算机的流量进入攻击者所需的任何位置,例如返回至攻击者的计算机。
let archive = try ZZArchive.init(url: URL(fileURLWithPath: zipPath))
for entry in archive.entries {
let fullPath = URL(fileURLWithPath: destPath + "/" + entry.fileName)
try entry.newData().write(to: fullPath)
}
Example 1
中,在对此条目中的数据执行读取/写入函数之前未验证 entry.fileName
。如果 Zip 文件最初放置在 iOS 应用程序的“Documents/hot_patches
”目录中,并且 Zip 条目为“../js/page.js
”,则它将覆盖 page.js
文件,从而可能会使攻击者能够注入可能导致代码执行的恶意代码。varName
提供恶意值,则对 SetVariable()
的调用可能会覆盖所有任意变量,包括 #first#
。在这种情况下,如果包含 JavaScript 的恶意值覆盖 #first#
,则该程序会很容易受到 cross-site scripting 攻击。
<cfset first = "User">
<cfscript>
SetVariable(url.varName, url.varValue);
</cfscript>
<cfoutput>
#first#
</cfoutput>
str
提供恶意值,则对 parse_str()
的调用可能会覆盖当前作用域中的所有任意变量,包括 first
。在这种情况下,如果包含 JavaScript 的恶意值覆盖 first
,则该程序会很容易受到 cross-site scripting 攻击。
<?php
$first="User";
...
$str = $_SERVER['QUERY_STRING'];
parse_str($str);
echo $first;
?>
str
提供恶意值,则对 mb_parse_str()
的调用可能会覆盖所有任意变量,包括 first
。在这种情况下,如果包含 JavaScript 的恶意值覆盖 first
,则该程序会很容易受到 cross-site scripting 攻击。
<?php
$first="User";
...
$str = $_SERVER['QUERY_STRING'];
mb_parse_str($str);
echo $first;
?>
NSPredicate
,则可能会允许攻击者修改语句的含义。NSPredicate
实例指定应如何从来源(如 CoreData
永久性存储系统、数组和字典)获取或过滤集合。其查询语言提供与 SQL
类似的表达性语言,以定义搜索集合时所应依据的逻辑条件。NSPredicate
作为身份验证因素来访问应用程序所存储的某些数据。由于用户可以提供任意 PIN 值,因此他们可以使用通配符 (*
) 绕过 PIN 保护。
NSString *pin = [self getPinFromUser];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"pin LIKE %@", pin];
NSPredicate
,则可能会允许攻击者修改语句的含义。NSPredicate
实例指定应如何从来源(如 CoreData
永久性存储系统、数组和字典)获取或过滤集合。其查询语言提供与 SQL
类似的表达性语言,以定义搜索集合时所应依据的逻辑条件。NSPredicate
作为身份验证因素来访问应用程序所存储的某些数据。由于用户可以提供任意 PIN 值,因此他们可以使用通配符 (*
) 绕过 PIN 保护。
let pin = getPinFromUser();
let predicate = NSPredicate(format: "pin LIKE '\(pin)'", argumentArray: nil)
...
tid = request->get_form_field( 'tid' ).
CALL TRANSACTION tid USING bdcdata MODE 'N'
MESSAGES INTO messtab.
...
APPHOME
,然后根据指定目录的相对路径加载本地库。
...
string lib = ConfigurationManager.AppSettings["APPHOME"];
Environment.ExitCode = AppDomain.CurrentDomain.ExecuteAssembly(lib);
...
APPHOME
以指向包含恶意版本 LIBNAME
的不同路径,从而使用更高的应用程序权限来执行任意代码。由于程序不会验证从环境中读取的值,因此如果攻击者能够控制系统属性 APPHOME
的值,他们就能欺骗应用程序去运行恶意代码,从而控制系统。
...
RegQueryValueEx(hkey, "APPHOME",
0, 0, (BYTE*)home, &size);
char* lib=(char*)malloc(strlen(home)+strlen(INITLIB));
if (lib) {
strcpy(lib,home);
strcat(lib,INITCMD);
LoadLibrary(lib);
}
...
INITLIB
恶意版本的其他路径,进而允许攻击者加载一个任意库,以提高的应用程序权限去执行库中的任意代码。因为程序不会校验从环境中读取的值,如果攻击者能够控制 APPHOME
的值,就能欺骗应用程序去运行恶意的代码。liberty.dll
的库,该库通常可在一个标准的系统目录中找到。
LoadLibrary("liberty.dll");
liberty.dll
的绝对路径。在搜索顺序上,如果攻击者将一个名为 liberty.dll
的恶意库放在原本想要的库的前面,并且攻击者能够让程序在他们的环境(而不是 web 服务器环境)中运行,那么应用程序就会加载该恶意库,而不是原本想要的可信赖的库。由于这种类型的应用程序会以提高了的权限运行,因此攻击者的 liberty.dll
中的内容也将以提高的权限运行,这可能会使攻击者完全控制系统。LoadLibrary()
所使用的搜索顺序造成的。如果当前目录比系统目录先搜索到,就像现在大多数最新的 Windows 版本,那么如果攻击者可在本地执行程序,这种类型的攻击就会变得十分简单。搜索顺序取决于操作系统的版本,在比较新的操作系统中,这一顺序由注册表主键控制:
HKLM\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode
LoadLibrary()
按以下方式运行:SafeDllSearchMode
为 1,搜索顺序如下所示:PATH
环境变量中列出来的目录。SafeDllSearchMode
为 0,搜索顺序如下所示:PATH
环境变量中列出来的目录。
...
ACCEPT PROGNAME.
EXEC CICS
LINK PROGRAM(PROGNAME)
COMMAREA(COMA)
LENGTH(LENA)
DATALENGTH(LENI)
SYSID('CONX')
END-EXEC.
...
APPHOME
来确定系统的安装目录,然后用基于指定目录的相对路径加载本地库。
...
String home = System.getProperty("APPHOME");
String lib = home + LIBNAME;
java.lang.Runtime.getRuntime().load(lib);
...
APPHOME
,指向一个包含恶意版本 LIBNAME
的不同路径,从而使用较高的应用程序权限去执行任意代码。由于程序不会验证从环境中读取的值,所以如果攻击者能够控制系统属性 APPHOME
的值,他们就能欺骗应用程序去运行恶意代码从而取得系统控制权。 System.loadLibrary()
从名为 library.dll
的本地库加载代码,它通常可以在标准的系统目录中找到。
...
System.loadLibrary("library.dll");
...
System.loadLibrary()
只会接受库的名称,而不接受库的路径。根据 Java 1.4.2 API 文档,这个函数会进行如下操作 [1]:library.dll
放在高于应用程序需要加载的文件的位置,那么应用程序就会加载该恶意代码,而不会选择加载最初需要的文件。由于应用程序的这一特性,它会以较高的权限运行,这就意味着攻击者的 library.dll
内容将以较高的权限运行,从而可能导致攻击者完全控制整个系统。Express
当前未记录的“功能”动态加载库文件。然后,Node.js
将继续在其正则库加载路径中搜索包含此库的文件或目录[1]。
var express = require('express');
var app = express();
app.get('/', function(req, res, next) {
res.render('tutorial/' + req.params.page);
});
Express
中,传递到 Response.render()
的页面将加载先前未知的扩展库。这对于“foo.pug”等输入来说通常没有问题,因为这意味着加载 pug
库,该库是广为人知的模板引擎。但是,如果攻击者可以控制页面并进而控制扩展,那么他们便可以选择加载 Node.js
模块加载路径内的任何库。因为程序不会验证从 URL 参数接收的信息,所以攻击者可能会欺骗应用程序,去执行恶意代码并取得对系统的控制。APPHOME
来确定系统的安装目录,然后用基于指定目录的相对路径加载本地库。
...
$home = getenv("APPHOME");
$lib = $home + $LIBNAME;
dl($lib);
...
APPHOME
,指向一个包含恶意版本 LIBNAME
的不同路径,从而使用较高的应用程序权限去执行任意代码。由于程序不会验证从环境中读取的值,所以如果攻击者能够控制系统属性 APPHOME
的值,他们就能欺骗应用程序去运行恶意代码从而取得系统控制权。dl()
来从名为 sockets.dll
的库加载代码,此库可从多个位置加载,具体取决于您的安装和配置。
...
dl("sockets");
...
dl()
只会接受库的名称,而不接受库的路径。sockets.dll
放在高于应用程序需要加载的文件的位置,那么应用程序就会加载该恶意代码,而不会选择加载最初需要的文件。由于应用程序的这一特性,它会以较高的权限运行,这就意味着攻击者的 sockets.dll
内容将以较高的权限运行,从而可能导致攻击者完全控制整个系统。Kernel.system()
来运行称为 program.exe
的可执行文件,通常在标准系统目录中可找到该可执行文件。
...
system("program.exe")
...
Kernel.system()
通过 shell 执行程序。如果攻击者可以操纵 RUBYSHELL
或 COMSPEC
环境变量,这两个环境变量就能够指向恶意的可执行文件,通过为 Kernel.system()
指定的命令将会调用该可执行文件。由于应用程序自身的特性,它需要特定的权限执行系统操作,这意味着攻击者会利用这些权限执行自己的 program.exe
,从而可能导致攻击者完全控制这个系统。Kernel.system()
调用之前未能清理其环境。如果攻击者能够篡改 $PATH
变量,使其指向一个名为 program.exe
的恶意二进制代码,然后在指定环境中运行应用程序,那么应用程序就会加载该恶意二进制代码,并以此替代原本期望的代码。由于应用程序自身的特性,它需要特定的权限执行系统操作,这意味着攻击者会利用这些权限执行自己的 program.exe
,从而可能导致攻击者完全控制这个系统。InvokerServlet
类可允许攻击者调用服务器上的任意类。InvokerServlet
类可用于调用服务器虚拟机可用的任意类。通过猜测类的完整名称,攻击者不但可以加载 Servlet 类,还可以加载 POJO 类或对 JVM 可用的其他任何类。
@GetMapping("/prompt_injection")
String generation(String userInput1, ...) {
return this.clientBuilder.build().prompt()
.system(userInput1)
.user(...)
.call()
.content();
}
client = new Anthropic();
# Simulated attacker's input attempting to inject a malicious system prompt
attacker_input = ...
response = client.messages.create(
model = "claude-3-5-sonnet-20240620",
max_tokens=2048,
system = attacker_input,
messages = [
{"role": "user", "content": "Analyze this dataset for anomalies: ..."}
]
);
...
client = OpenAI()
# Simulated attacker's input attempting to inject a malicious system prompt
attacker_input = ...
completion = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": attacker_input},
{"role": "user", "content": "Compose a poem that explains the concept of recursion in programming."}
]
)
@GetMapping("/prompt_injection_persistent")
String generation(String userInput1, ...) {
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users WHERE ...");
String userName = "";
if (rs != null) {
rs.next();
userName = rs.getString("userName");
}
return this.clientBuilder.build().prompt()
.system("Assist the user " + userName)
.user(userInput1)
.call()
.content();
}
client = new Anthropic();
# Simulated attacker's input attempting to inject a malicious system prompt
attacker_query = ...;
attacker_name = db.qyery('SELECT name FROM user_profiles WHERE ...');
response = client.messages.create(
model = "claude-3-5-sonnet-20240620",
max_tokens=2048,
system = "Provide assistance to the user " + attacker_name,
messages = [
{"role": "user", "content": attacker_query}
]
);
...
client = OpenAI()
# Simulated attacker's input attempting to inject a malicious system prompt
attacker_name = cursor.fetchone()['name']
attacker_query = ...
completion = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "Provide assistance to the user " + attacker_name},
{"role": "user", "content": attacker_query}
]
)
Object.prototype
的原型,所以如果攻击者可以覆盖对象的原型,他们通常可以覆盖 Object.prototype
的定义,从而影响应用程序内的所有对象。undefined
而不是始终显式设置的事实,那么如果原型已被污染,应用程序可能会无意中从原型而不是预期的对象中进行读取。lodash
版本污染对象的原型:
import * as lodash from 'lodash'
...
let clonedObject = lodash.merge({}, JSON.parse(untrustedInput));
...
{"__proto__": { "isAdmin": true}}
,则 Object.prototype
将定义 isAdmin = true
。
...
let config = {}
if (isAuthorizedAsAdmin()){
config.isAdmin = true;
}
...
if (config.isAdmin) {
// do something as the admin
}
...
isAdmin
仅在 isAuthorizedAdmin()
返回 true 时才应设置为 true,但由于应用程序无法在 else 条件下设置 config.isAdmin = false
,因此它依据的是 config.isAdmin === undefined === false
这一事实。config
的原型现已设置 isAdmin === true
,因此允许绕过管理员授权。