輸入驗證和表示法問題是由中繼字元、替代編碼和數值表示法引起的。信任輸入會導致安全問題。問題包括:「Buffer Overflows」、「Cross-Site Scripting」攻擊、「SQL Injection」及其他許多問題。
...
DirectorySearcher src =
new DirectorySearcher("(manager=" + managerName.Text + ")");
src.SearchRoot = de;
src.SearchScope = SearchScope.Subtree;
foreach(SearchResult res in src.FindAll()) {
...
}
(manager=Smith, John)
managerName
不包含任何 LDAP 中介字元時才會執行正確。如果攻擊者為 managerName
輸入字串 Hacker, Wiley)(|(objectclass=*)
,那麼查詢將會變更為:
(manager=Hacker, Wiley)(|(objectclass=*))
|(objectclass=*)
條件會使篩選與目錄中的所有項目相符合,而且會讓攻擊者擷取關於整個使用者儲存池的資訊。根據執行 LDAP 查詢所需的權限,此攻擊的廣度會受到限制,但是如果攻擊者可能控制查詢的指令結構,則此類攻擊至少會影響執行 LDAP 查詢的使用者能夠存取的所有記錄。
fgets(manager, sizeof(manager), socket);
snprintf(filter, sizeof(filter, "(manager=%s)", manager);
if ( ( rc = ldap_search_ext_s( ld, FIND_DN, LDAP_SCOPE_BASE,
filter, NULL, 0, NULL, NULL, LDAP_NO_LIMIT,
LDAP_NO_LIMIT, &result ) ) == LDAP_SUCCESS ) {
...
}
(manager=Smith, John)
manager
不包含任何 LDAP 中介字元時才會執行正確。如果攻擊者為 manager
輸入字串 Hacker, Wiley)(|(objectclass=*)
,那麼查詢將會變更為:
(manager=Hacker, Wiley)(|(objectclass=*))
|(objectclass=*)
條件會使篩選與目錄中的所有項目相符合,而且會讓攻擊者擷取關於整個使用者儲存池的資訊。根據執行 LDAP 查詢所需的權限,此攻擊的廣度會受到限制,但是如果攻擊者可能控制查詢的指令結構,則此類攻擊至少會影響執行 LDAP 查詢的使用者能夠存取的所有記錄。
...
DirContext ctx = new InitialDirContext(env);
String managerName = request.getParameter("managerName");
//retrieve all of the employees who report to a manager
String filter = "(manager=" + managerName + ")";
NamingEnumeration employees = ctx.search("ou=People,dc=example,dc=com",
filter);
...
(manager=Smith, John)
managerName
不包含任何 LDAP 中介字元時才會執行正確。如果攻擊者為 managerName
輸入字串 Hacker, Wiley)(|(objectclass=*)
,那麼查詢將會變更為:
(manager=Hacker, Wiley)(|(objectclass=*))
|(objectclass=*)
條件會使篩選與目錄中的所有項目相符合,而且會讓攻擊者擷取關於整個使用者儲存池的資訊。根據執行 LDAP 查詢所需的權限,此攻擊的廣度會受到限制,但是如果攻擊者可能控制查詢的指令結構,則此類攻擊至少會影響執行 LDAP 查詢的使用者能夠存取的所有記錄。
...
$managerName = $_POST["managerName"]];
//retrieve all of the employees who report to a manager
$filter = "(manager=" . $managerName . ")";
$result = ldap_search($ds, "ou=People,dc=example,dc=com", $filter);
...
(manager=Smith, John)
managerName
不包含任何 LDAP 中繼字元時才會執行正確。如果攻擊者為 managerName
輸入字串 Hacker, Wiley)(|(objectclass=*)
,則查詢將會變更為:
(manager=Hacker, Wiley)(|(objectclass=*))
|(objectclass=*)
條件會使篩選與目錄中的所有項目相符合,而且會讓攻擊者擷取整個使用者集區的相關資訊。根據執行 LDAP 查詢所需的權限,此攻擊的廣度會受到限制,但是如果攻擊者可能控制查詢的指令結構,則此類攻擊至少會影響執行 LDAP 查詢的使用者能夠存取的所有記錄。ou
字串,並將其用來建立新的 DirectoryEntry
。
...
de = new DirectoryEntry("LDAP://ad.example.com:389/ou="
+ hiddenOU.Text + ",dc=example,dc=com");
...
ou
值來更改查詢的結果。問題是開發人員沒能充分利用適當的 Access Control 機制來限制之後的查詢,使其只能讀取那些允許目前使用者讀取的員工記錄。dn
字串,並且使用此字串來執行 LDAP 查詢。
...
rc = ldap_simple_bind_s( ld, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
...
}
...
fgets(dn, sizeof(dn), socket);
if ( ( rc = ldap_search_ext_s( ld, dn, LDAP_SCOPE_BASE,
filter, NULL, 0, NULL, NULL, LDAP_NO_LIMIT,
LDAP_NO_LIMIT, &result ) ) != LDAP_SUCCESS ) {
...
dn
字串來更改查詢結果。問題是開發人員沒能充分利用適當的 Access Control 機制來限制之後的查詢,使其只能讀取那些允許目前使用者讀取的員工記錄。
env.put(Context.SECURITY_AUTHENTICATION, "none");
DirContext ctx = new InitialDirContext(env);
String empID = request.getParameter("empID");
try
{
BasicAttribute attr = new BasicAttribute("empID", empID);
NamingEnumeration employee =
ctx.search("ou=People,dc=example,dc=com",attr);
...
dn
字串,並且使用此字串來執行 LDAP 查詢。
$dn = $_POST['dn'];
if (ldap_bind($ds)) {
...
try {
$rs = ldap_search($ds, $dn, "ou=People,dc=example,dc=com", $attr);
...
dn
源自使用者輸入並且查詢是在匿名繫結下執行,所以攻擊者可藉由指定非預期的 dn 字串來更改查詢結果。問題是開發人員沒能充分利用適當的 Access Control 機制來限制之後的查詢,使其只能讀取那些允許目前使用者讀取的員工記錄。webview
中載入一個頁面,但不實作任何控制來阻止造訪惡意網站時出現的自動撥號攻擊。webview
來載入可能包含不可信賴連結的網站,但未指定能夠驗證此 webview
中啟動的要求的委派:
...
NSURL *webUrl = [[NSURL alloc] initWithString:@"https://some.site.com/"];
NSURLRequest *webRequest = [[NSURLRequest alloc] initWithURL:webUrl];
[_webView loadRequest:webRequest];
...
webview
中載入一個頁面,但不實作任何控制來阻止造訪惡意網站時出現的自動撥號攻擊。webview
來載入可能包含不可信賴連結的網站,但未指定能夠驗證此 webview
中啟動的要求的委派:
...
let webUrl : NSURL = NSURL(string: "https://some.site.com/")!
let webRequest : NSURLRequest = NSURLRequest(URL: webUrl)
webView.loadRequest(webRequest)
...
webview
中載入一個頁面,但不會實作任何控制來確認和驗證使用者能夠點選的連結。webview
來載入可能包含不可信賴連結的網站,但未指定能夠驗證此 webview
中啟動的要求的委派:
...
NSURL *webUrl = [[NSURL alloc] initWithString:@"https://some.site.com/"];
NSURLRequest *webRequest = [[NSURLRequest alloc] initWithURL:webUrl];
[webView loadRequest: webRequest];
webview
中載入一個頁面,但不會實作任何控制來確認和驗證使用者能夠點選的連結。webview
來載入可能包含不可信賴連結的網站,但未指定能夠驗證此 webview
中啟動的要求的委派:
...
let webUrl = URL(string: "https://some.site.com/")!
let urlRequest = URLRequest(url: webUrl)
webView.load(webRequest)
...
...
DATA log_msg TYPE bal_s_msg.
val = request->get_form_field( 'val' ).
log_msg-msgid = 'XY'.
log_msg-msgty = 'E'.
log_msg-msgno = '123'.
log_msg-msgv1 = 'VAL: '.
log_msg-msgv2 = val.
CALL FUNCTION 'BAL_LOG_MSG_ADD'
EXPORTING
I_S_MSG = log_msg
EXCEPTIONS
LOG_NOT_FOUND = 1
MSG_INCONSISTENT = 2
LOG_IS_FULL = 3
OTHERS = 4.
...
val
的字串「FOO
」,則會記錄以下項目:
XY E 123 VAL: FOO
FOO XY E 124 VAL: BAR
」,則會記錄以下的項目:
XY E 123 VAL: FOO XY E 124 VAL: BAR
var params:Object = LoaderInfo(this.root.loaderInfo).parameters;
var val:String = String(params["username"]);
var value:Number = parseInt(val);
if (value == Number.NaN) {
trace("Failed to parse val = " + val);
}
val
的字串「twenty-one
」,則會記錄以下項目:
Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」,則會記錄以下的項目:
Failed to parse val=twenty-one
User logged out=badguy
...
string val = (string)Session["val"];
try {
int value = Int32.Parse(val);
}
catch (FormatException fe) {
log.Info("Failed to parse val= " + val);
}
...
val
的字串「twenty-one
」,則會記錄以下項目:
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」,則會記錄以下的項目:
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
long value = strtol(val, &endPtr, 10);
if (*endPtr != '\0')
syslog(LOG_INFO,"Illegal value = %s",val);
...
val
的字串「twenty-one
」,則會記錄以下項目:
Illegal value=twenty-one
twenty-one\n\nINFO: User logged out=evil
」,則會記錄以下的項目:
INFO: Illegal value=twenty-one
INFO: User logged out=evil
...
01 LOGAREA.
05 VALHEADER PIC X(50) VALUE 'VAL: '.
05 VAL PIC X(50).
...
EXEC CICS
WEB READ
FORMFIELD(NAME)
VALUE(VAL)
...
END-EXEC.
EXEC DLI
LOG
FROM(LOGAREA)
LENGTH(50)
END-EXEC.
...
VAL
的字串「FOO
」,則會記錄以下項目:
VAL: FOO
FOO VAL: BAR
」,則會記錄以下的項目:
VAL: FOO VAL: BAR
<cflog file="app_log" application="No" Thread="No"
text="Failed to parse val="#Form.val#">
val
的字串「twenty-one
」,則會記錄以下項目:
"Information",,"02/28/01","14:50:37",,"Failed to parse val=twenty-one"
twenty-one%0a%0a%22Information%22%2C%2C%2202/28/01%22%2C%2214:53:40%22%2C%2C%22User%20logged%20out:%20badguy%22
」,則會記錄以下的項目:
"Information",,"02/28/01","14:50:37",,"Failed to parse val=twenty-one"
"Information",,"02/28/01","14:53:40",,"User logged out: badguy"
func someHandler(w http.ResponseWriter, r *http.Request){
r.parseForm()
name := r.FormValue("name")
logout := r.FormValue("logout")
...
if (logout){
...
} else {
log.Printf("Attempt to log out: name: %s logout: %s", name, logout)
}
}
twenty-one
」給 logout
,且能夠建立名稱為「admin
」的使用者,則會記錄以下項目:
Attempt to log out: name: admin logout: twenty-one
admin+logout:+1+++++++++++++++++++++++
」這個使用者名稱,則會記錄以下項目:
Attempt to log out: name: admin logout: 1 logout: twenty-one
...
String val = request.getParameter("val");
try {
int value = Integer.parseInt(val);
}
catch (NumberFormatException nfe) {
log.info("Failed to parse val = " + val);
}
...
val
的字串「twenty-one
」,則會記錄以下項目:
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」,則會記錄以下的項目:
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
Example 1
以適用於 Android 平台。
...
String val = this.getIntent().getExtras().getString("val");
try {
int value = Integer.parseInt();
}
catch (NumberFormatException nfe) {
Log.e(TAG, "Failed to parse val = " + val);
}
...
var cp = require('child_process');
var http = require('http');
var url = require('url');
function listener(request, response){
var val = url.parse(request.url, true)['query']['val'];
if (isNaN(val)){
console.log("INFO: Failed to parse val = " + val);
}
...
}
...
http.createServer(listener).listen(8080);
...
val
的字串「twenty-one
」,則會記錄以下項目:
INFO: Failed to parse val = twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」,則會記錄以下的項目:
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
long value = strtol(val, &endPtr, 10);
if (*endPtr != '\0')
NSLog("Illegal value = %s",val);
...
val
的字串「twenty-one
」,則會記錄以下項目:
INFO: Illegal value=twenty-one
twenty-one\n\nINFO: User logged out=evil
」,則會記錄以下的項目:
INFO: Illegal value=twenty-one
INFO: User logged out=evil
<?php
$name =$_GET['name'];
...
$logout =$_GET['logout'];
if(is_numeric($logout))
{
...
}
else
{
trigger_error("Attempt to log out: name: $name logout: $val");
}
?>
twenty-one
」給 logout
,且能夠建立名稱為「admin
」的使用者,則會記錄以下項目:
PHP Notice: Attempt to log out: name: admin logout: twenty-one
admin+logout:+1+++++++++++++++++++++++
」這個使用者名稱,則會記錄以下項目:
PHP Notice: Attempt to log out: name: admin logout: 1 logout: twenty-one
name = req.field('name')
...
logout = req.field('logout')
if (logout):
...
else:
logger.error("Attempt to log out: name: %s logout: %s" % (name,logout))
twenty-one
」給 logout
,且能夠建立名稱為「admin
」的使用者,則會記錄以下項目:
Attempt to log out: name: admin logout: twenty-one
admin+logout:+1+++++++++++++++++++++++
」這個使用者名稱,則會記錄以下項目:
Attempt to log out: name: admin logout: 1 logout: twenty-one
...
val = req['val']
unless val.respond_to?(:to_int)
logger.info("Failed to parse val")
logger.info(val)
end
...
val
的字串「twenty-one
」,則會記錄以下項目:
INFO: Failed to parse val
INFO: twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」,則會記錄以下的項目:
INFO: Failed to parse val
INFO: twenty-one
INFO: User logged out=badguy
...
let num = Int(param)
if num == nil {
NSLog("Illegal value = %@", param)
}
...
val
的字串「twenty-one
」,則會記錄以下項目:
INFO: Illegal value = twenty-one
twenty-one\n\nINFO: User logged out=evil
」,則會記錄以下的項目:
INFO: Illegal value=twenty-one
INFO: User logged out=evil
...
Dim Val As Variant
Dim Value As Integer
Set Val = Request.Form("val")
If IsNumeric(Val) Then
Set Value = Val
Else
App.EventLog "Failed to parse val=" & Val, 1
End If
...
val
的字串「twenty-one
」,則會記錄以下項目:
Failed to parse val=twenty-one
twenty-one%0a%0a+User+logged+out%3dbadguy
」,則會記錄以下的項目:
Failed to parse val=twenty-one
User logged out=badguy
@HttpGet
global static void doGet() {
RestRequest req = RestContext.request;
String val = req.params.get('val');
try {
Integer i = Integer.valueOf(val);
...
} catch (TypeException e) {
System.Debug(LoggingLevel.INFO, 'Failed to parse val: '+val);
}
}
val
的字串「twenty-one
」,則會記錄以下項目:
Failed to parse val: twenty-one
twenty-one%0a%0aUser+logged+out%3dbadguy
」,則會記錄以下項目:
Failed to parse val: twenty-one
User logged out=badguy
...
String val = request.Params["val"];
try {
int value = Int.Parse(val);
}
catch (FormatException fe) {
log.Info("Failed to parse val = " + val);
}
...
val
的字串「twenty-one
」,則會記錄以下項目:
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」,則會記錄以下項目:
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
Example 1
以適用於 Android 平台。
...
String val = this.Intent.Extras.GetString("val");
try {
int value = Int.Parse(val);
}
catch (FormatException fe) {
Log.E(TAG, "Failed to parse val = " + val);
}
...
...
var idValue string
idValue = req.URL.Query().Get("id")
num, err := strconv.Atoi(idValue)
if err != nil {
sysLog.Debug("Failed to parse value: " + idValue)
}
...
val
的字串「twenty-one
」,則會記錄以下項目:
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」,則會記錄以下項目:
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
...
String val = request.getParameter("val");
try {
int value = Integer.parseInt(val);
}
catch (NumberFormatException nfe) {
log.info("Failed to parse val = " + val);
}
...
val
的字串「twenty-one
」,則會記錄以下項目:
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」,則會記錄以下的項目:
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
Example 1
以適用於 Android 平台。
...
String val = this.getIntent().getExtras().getString("val");
try {
int value = Integer.parseInt();
}
catch (NumberFormatException nfe) {
Log.e(TAG, "Failed to parse val = " + val);
}
...
var cp = require('child_process');
var http = require('http');
var url = require('url');
function listener(request, response){
var val = url.parse(request.url, true)['query']['val'];
if (isNaN(val)){
console.error("INFO: Failed to parse val = " + val);
}
...
}
...
http.createServer(listener).listen(8080);
...
val
的字串「twenty-one
」,則會記錄以下項目:
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」,則會記錄以下的項目:
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
...
val = request.GET["val"]
try:
int_value = int(val)
except:
logger.debug("Failed to parse val = " + val)
...
val
的字串「twenty-one
」,則會記錄以下項目:
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
」,則會記錄以下的項目:
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
...
val = req['val']
unless val.respond_to?(:to_int)
logger.debug("Failed to parse val")
logger.debug(val)
end
...
val
的字串「twenty-one
」,則會記錄以下項目:
DEBUG: Failed to parse val
DEBUG: twenty-one
twenty-one%0a%DEBUG:+User+logged+out%3dbadguy
」,則會記錄以下的項目:
DEBUG: Failed to parse val
DEBUG: twenty-one
DEBUG: User logged out=badguy
CREATE
指令。攻擊者可能使用此參數修改傳送至伺服器的指令,並使用 CRLF 字元插入新指令。
...
final String foldername = request.getParameter("folder");
IMAPFolder folder = (IMAPFolder) store.getFolder("INBOX");
...
folder.doCommand(new IMAPFolder.ProtocolCommand() {
@Override
public Object doCommand(IMAPProtocol imapProtocol) throws ProtocolException {
try {
imapProtocol.simpleCommand("CREATE " + foldername, null);
} catch (Exception e) {
// Handle Exception
}
return null;
}
});
...
USER
和 PASS
指令。攻擊者可能使用此參數修改傳送至伺服器的指令,並使用 CRLF 字元插入新指令。
...
String username = request.getParameter("username");
String password = request.getParameter("password");
...
POP3SClient pop3 = new POP3SClient(proto, false);
pop3.login(username, password)
...
VRFY
指令。攻擊者可能使用此參數修改傳送至伺服器的指令,並使用 CRLF 字元插入新指令。
...
c, err := smtp.Dial(x)
if err != nil {
log.Fatal(err)
}
user := request.FormValue("USER")
c.Verify(user)
...
VRFY
指令。攻擊者可能使用此參數修改傳送至伺服器的指令,並使用 CRLF 字元插入新指令。
...
String user = request.getParameter("user");
SMTPSSLTransport transport = new SMTPSSLTransport(session,new URLName(Utilities.getProperty("smtp.server")));
transport.connect(Utilities.getProperty("smtp.server"), username, password);
transport.simpleCommand("VRFY " + user);
...
VRFY
指令。攻擊者可能使用此參數修改傳送至伺服器的指令,並使用 CRLF 字元插入新指令。
...
user = request.GET['user']
session = smtplib.SMTP(smtp_server, smtp_tls_port)
session.ehlo()
session.starttls()
session.login(username, password)
session.docmd("VRFY", user)
...
...
TextClient tc = (TextClient)Client.GetInstance("127.0.0.1", 11211, MemcachedFlags.TextProtocol);
tc.Open();
string id = txtID.Text;
var result = get_page_from_somewhere();
var response = Http_Response(result);
tc.Set("req-" + id, response, TimeSpan.FromSeconds(1000));
tc.Close();
tc = null;
...
set req-1233 0 1000 n
<serialized_response_instance>
n
是回應的長度。ignore 0 0 1\r\n1\r\nset injected 0 3600 10\r\n0123456789\r\nset req-
字串,然後作業會變成如下所示:
set req-ignore 0 0 1
1
set injected 0 3600 10
0123456789
set req-1233 0 0 n
<serialized_response_instance>
injected=0123456789
快取中成功新增索引鍵/值組,所以攻擊者將能夠破壞快取。
...
def store(request):
id = request.GET['id']
result = get_page_from_somewhere()
response = HttpResponse(result)
cache_time = 1800
cache.set("req-" % id, response, cache_time)
return response
...
set req-1233 0 0 n
<serialized_response_instance>
ignore 0 0 1\r\n1\r\nset injected 0 3600 10\r\n0123456789\r\nset req-
字串,然後作業會變成如下所示:
set req-ignore 0 0 1
1
set injected 0 3600 10
0123456789
set req-1233 0 0 n
<serialized_response_instance>
injected=0123456789
快取中成功新增索引鍵/值組。視裝載而定,攻擊者將能夠透過插入由 Pickle 序列化的裝載 (在還原序列化之後會執行任意程式碼),破壞快取或執行任意程式碼。
def form = Form(
mapping(
"name" -> text,
"age" -> number
)(UserData.apply)(UserData.unapply)
)
FormAction
,但無法按照預期的要求驗證資料:範例 2:以下程式碼定義了 Spring WebFlow 動作狀態,但無法按照預期的要求驗證資料:
<bean id="customerCriteriaAction" class="org.springframework.webflow.action.FormAction">
<property name="formObjectClass"
value="com.acme.domain.CustomerCriteria" />
<property name="propertyEditorRegistrar">
<bean
class="com.acme.web.PropertyEditors" />
</property>
</bean>
<action-state>
<action bean="transferMoneyAction" method="bind" />
</action-state>
def form = Form(
mapping(
"name" -> text,
"age" -> number
)(UserData.apply)(UserData.unapply)
)
...
String userName = User.Identity.Name;
String emailId = request["emailId"];
var client = account.CreateCloudTableClient();
var table = client.GetTableReference("Employee");
var query = table.CreateQuery<EmployeeEntity>().Where("user == '" + userName + "' AND emailId == '" + emailId "'");
var results = table.ExecuteQuery(query);
...
user == "<userName>" && emailId == "<emailId>"
emailId
沒有包含單引號字元的時候,查詢才會正確執行。如果使用者名稱為 wiley
的攻擊者在 emailId
中輸入字串 123' || '4' != '5
,那麼查詢將變成以下內容:
user == 'wiley' && emailId == '123' || '4' != '5'
|| '4' != '5'
會使 where 子句的評估永遠為 true
,所以不論電子郵件擁有者為何,此查詢均會傳回 emails
集合中儲存的所有項目。
...
// "type" parameter expected to be either: "Email" or "Username"
string type = request["type"];
string value = request["value"];
string password = request["password"];
var ddb = new AmazonDynamoDBClient();
var attrValues = new Dictionary<string,AttributeValue>();
attrValues[":value"] = new AttributeValue(value);
attrValues[":password"] = new AttributeValue(password);
var scanRequest = new ScanRequest();
scanRequest.FilterExpression = type + " = :value AND Password = :password";
scanRequest.TableName = "users";
scanRequest.ExpressionAttributeValues = attrValues;
var scanResponse = await ddb.ScanAsync(scanRequest);
...
Email = :value AND Password = :password
Username = :value AND Password = :password
type
僅包含任何預期值的時候,查詢才會正確執行。如果攻擊者提供 :value = :value OR :value
之類的 type 值,那麼查詢將會變更為::value = :value OR :value = :value AND Password = :password
:value = :value
會使 where 子句的評估永遠為 True,所以不論電子郵件擁有者為何,此查詢均會傳回 users
集合中儲存的所有項目。
...
// "type" parameter expected to be either: "Email" or "Username"
String type = request.getParameter("type")
String value = request.getParameter("value")
String password = request.getParameter("password")
DynamoDbClient ddb = DynamoDbClient.create();
HashMap<String, AttributeValue> attrValues = new HashMap<String,AttributeValue>();
attrValues.put(":value", AttributeValue.builder().s(value).build());
attrValues.put(":password", AttributeValue.builder().s(password).build());
ScanRequest queryReq = ScanRequest.builder()
.filterExpression(type + " = :value AND Password = :password")
.tableName("users")
.expressionAttributeValues(attrValues)
.build();
ScanResponse response = ddb.scan(queryReq);
...
Email = :value AND Password = :password
Username = :value AND Password = :password
type
僅包含任何預期值的時候,查詢才會正確執行。如果攻擊者提供 :value = :value OR :value
之類的 type 值,那麼查詢將會變更為::value = :value OR :value = :value AND Password = :password
:value = :value
會使 where 子句的評估永遠為 True,所以不論電子郵件擁有者為何,此查詢均會傳回 users
集合中儲存的所有項目。
...
function getItemsByOwner(username: string) {
db.items.find({ $where: `this.owner === '${username}'` }).then((orders: any) => {
console.log(orders);
}).catch((err: any) => {
console.error(err);
});
}
...
db.items.find({ $where: `this.owner === 'john'; return true; //` })
...
String userName = User.Identity.Name;
String emailId = request["emailId"];
var coll = mongoClient.GetDatabase("MyDB").GetCollection<BsonDocument>("emails");
var docs = coll.Find(new BsonDocument("$where", "this.name == '" + name + "'")).ToList();
...
this.owner == "<userName>" && this.emailId == "<emailId>"
emailId
沒有包含單引號字元的時候,查詢才會正確執行。如果使用者名稱為 wiley
的攻擊者在 emailId
中輸入字串 123' || '4' != '5
,那麼查詢將變成以下內容:
this.owner == 'wiley' && this.emailId == '123' || '4' != '5'
|| '4' != '5'
會使 where 子句的評估永遠為 true
,所以不論電子郵件擁有者為何,此查詢均會傳回 emails
集合中儲存的所有項目。
...
String userName = ctx.getAuthenticatedUserName();
String emailId = request.getParameter("emailId")
MongoCollection<Document> col = mongoClient.getDatabase("MyDB").getCollection("emails");
BasicDBObject Query = new BasicDBObject();
Query.put("$where", "this.owner == \"" + userName + "\" && this.emailId == \"" + emailId + "\"");
FindIterable<Document> find= col.find(Query);
...
this.owner == "<userName>" && this.emailId == "<emailId>"
emailId
不包含雙引號字元的時候,查詢才會正確執行。 如果使用者名稱為 wiley
的攻擊者在 emailId
中輸入字串 123" || "4" != "5
,那麼查詢將變成以下內容:
this.owner == "wiley" && this.emailId == "123" || "4" != "5"
|| "4" != "5"
會使 where 子句的評估永遠為 True,所以不論電子郵件擁有者為何,此查詢會傳回 emails
集合中儲存的所有項目。
...
userName = req.field('userName')
emailId = req.field('emaiId')
results = db.emails.find({"$where", "this.owner == \"" + userName + "\" && this.emailId == \"" + emailId + "\""});
...
this.owner == "<userName>" && this.emailId == "<emailId>"
emailId
不包含雙引號字元的時候,查詢才會正確執行。 如果使用者名稱為 wiley
的攻擊者在 emailId
中輸入字串 123" || "4" != "5
,那麼查詢將變成以下內容:
this.owner == "wiley" && this.emailId == "123" || "4" != "5"
|| "4" != "5"
會使 where
子句的評估永遠為 True,所以不論電子郵件擁有者為何,此查詢會傳回 emails
集合中儲存的所有項目。
...
NSString *emailId = [self getEmailIdFromUser];
NSString *query = [NSString stringWithFormat:@"id == '%@'", emailId];
RLMResults<Email *> *emails = [Email objectsInRealm:realm where:query];
...
id == '<emailId value>'
emailId
沒有包含單引號字元的時候,查詢才會正確執行。如果攻擊者為 emailId
輸入字串 123' or '4' != '5
,那麼查詢將會變更為:
id == '123' or '4' != '5'
or '4' != '5'
會使 where
子句的評估永遠為 True,所以不論電子郵件擁有者為何,此查詢均會傳回 emails
集合中儲存的所有項目。
...
let emailId = getFromUser("emailId")
let email = realm.objects(Email.self).filter("id == '" + emailId + "'")
...
id == '<emailId value>'
emailId
沒有包含單引號字元的時候,查詢才會正確執行。如果攻擊者為 emailId
輸入字串 123' or '4' != '5
,那麼查詢將會變更為:
id == '123' or '4' != '5'
or '4' != '5'
會使 filter
子句的評估永遠為 True,所以不論電子郵件擁有者為何,此查詢均會傳回 emails
集合中儲存的所有項目。unserialize()
函數時,便會發生物件插入弱點。攻擊者可以將精心製作的序列化字串傳遞至易受攻擊的 unserialize()
呼叫,進而導致將任意 PHP 物件插入到應用程式範圍。此弱點的嚴重性取決於應用程式範圍中可用的類別。實作 PHP magic 方法的類別 (例如 __wakeup
或 __destruct
) 將引起攻擊者的興趣,因為他們將能夠在這些方法中執行程式碼。__destruct()
magic 方法並執行類別屬性所定義之系統指令的 PHP 類別。此外,還有一個使用使用者提供的資料對 unserialize()
不安全的呼叫。
...
class SomeAvailableClass {
public $command=null;
public function __destruct() {
system($this->command);
}
}
...
$user = unserialize($_GET['user']);
...
Example 1
中,應用程式可能應該執行序列化 User
物件,但攻擊者實際上可能提供序列化版本的 SomeAvailableClass
,並預先定義其 command
屬性的值:
GET REQUEST: http://server/page.php?user=O:18:"SomeAvailableClass":1:{s:7:"command";s:8:"uname -a";}
$user
物件沒有其他參照,就會呼叫解構函數方法,然後執行攻擊者所提供的指令。unserialize()
時,攻擊者將可能鏈結所宣告的不同類別,此技術是在 BlackHat 2010 年大會時由 Stefan Esser 所提出。此技術允許攻擊者重複使用現有程式碼來製作自己的裝載。YAML.load()
) 時,便會發生物件插入弱點。攻擊者可能將精心製作的序列化字串傳遞至易受攻擊的 YAML.load()
呼叫,進而導致只要類別在還原序列化時載入應用程式,就會將任意 Ruby 物件插入到程式內。這可能會導致一整堆的各種攻擊機會,例如,避開驗證邏輯以尋找 Cross-site scripting 弱點,透過看起來是硬式編碼值的內容允許 SQL 插入,或是甚至執行整個程式碼。YAML.load()
不安全的呼叫。
...
class Transaction
attr_accessor :id
def initialize(num=nil)
@id = num.is_a?(Numeric) ? num : nil
end
def print_details
unless @id.nil?
print $conn.query("SELECT * FROM transactions WHERE id=#{@id}")
end
end
end
...
user = YAML.load(params[:user]);
user.print_details
...
Example 1
中,應用程式可能會執行經過序列化的 User
物件,這正好使用稱為 print_details
的函數,但攻擊者實際上可以提供序列化版本的 Transaction
物件,並預先定義其 @id
屬性的值。如下所示的要求因此可能允許避開驗證檢查,其嘗試確保 @id
為數值
GET REQUEST: http://server/page?user=!ruby%2Fobject%3ATransaction%0Aid%3A4%20or%205%3D5%0A
!ruby/object:Transaction\nid:4 or 5=5\n
會指派給 user
參數。Transaction
的物件,並將 @id
設定為 "4 or 5=5"
。當開發人員認為他們將呼叫 User#print_details()
時,他們將立即呼叫 Transaction#print_details()
,而 Ruby 的字串內插補點則意味著 SQL 查詢將變更為執行查詢:SELECT * FROM transactions WHERE id=4 or 5=5
。由於新增的額外子句,查詢會估算為 true
並且會傳回 transactions
表格中的所有內容,而不是開發人員預期的單一列。YAML.load()
時,攻擊者將可能鏈結所宣告的不同類別,此技術是在 BlackHat 2010 年大會時由 Stefan Esser 所提出。此技術允許攻擊者重複使用現有程式碼來製作自己的裝載。