輸入驗證和表示法問題是由中繼字元、替代編碼和數值表示法引起的。信任輸入會導致安全問題。問題包括:「Buffer Overflows」、「Cross-Site Scripting」攻擊、「SQL Injection」及其他許多問題。
nresp = packet_get_int();
if (nresp > 0) {
response = xmalloc(nresp*sizeof(char*));
for (i = 0; i < nresp; i++)
response[i] = packet_get_string(NULL);
}
nresp
的值為 1073741824
,且 sizeof(char*)
的典型值為 4
,則 nresp*sizeof(char*)
運算的結果將發生溢位,xmalloc()
的引數將是 0
。多數 malloc()
實作會允許配置 0 個位元組的緩衝區,導致隨後的迭代循環發生堆積緩衝區 response
溢位。
char* processNext(char* strm) {
char buf[512];
short len = *(short*) strm;
strm += sizeof(len);
if (len <= 512) {
memcpy(buf, strm, len);
process(buf);
return strm + len;
} else {
return -1;
}
}
512
,則不會處理輸入。問題在於,len
是有符號的整數,因此針對結構長度上限的檢查會使用有符號的整數來執行,但是 len
將轉換為無符號的整數以呼叫 memcpy()
。若 len
是負數,似乎結構大小適當 (將使用 if
分支語句),但是 memcpy()
所複製的記憶體量會很大,攻擊者可以針對 strm
中的資料產生堆疊溢位。
77 accept-in PIC 9(10).
77 num PIC X(4) COMP-5. *> native 32-bit unsigned integer
77 mem-size PIC X(4) COMP-5.
...
ACCEPT accept-in
MOVE accept-in TO num
MULTIPLY 4 BY num GIVING mem-size
CALL "CBL_ALLOC_MEM" USING
mem-pointer
BY VALUE mem-size
BY VALUE 0
RETURNING status-code
END-CALL
num
的值為 1073741824
,則 MULTIPLY 4 BY num
運算的結果將發生溢位,malloc()
的 mem-size
引數將是 0
。多數 malloc()
實作會允許配置 0 個位元組的緩衝區,導致後續陳述式中的堆積緩衝區 mem-pointer
出現溢位。uint256
類型儲存,則表示它以 0 到 2^256-1 範圍內 256 位元無符號數儲存。如果算術運算導致數字大於上限,則會發生溢位,並從起始值 (0) 開始新增餘數。如果算術運算導致數字低於下限,則會發生欠位,並從最大值 (2^256-1) 中減去餘數。uint256
對應,可能會導致整數溢位/欠位並影響對應中的非計畫索引。
contract overflow {
mapping(uint256 => uint256) map;
function init(uint256 k, uint256 v) public {
map[k] -= v;
}
}
String arg = request.getParameter("arg");
...
Intent intent = new Intent();
...
intent.setClassName(arg);
ctx.startActivity(intent);
...
Intent
來啟動活動、啟動服務或傳遞廣播時,都可能讓攻擊者可以任意啟動內部應用程式元件、控制內部元件的行為或透過臨時權限授予間接存取內容提供者的受保護資料。Intent
的額外組合中巢狀化的任意 Intent
。startActivity
、startService
或 sendBroadcast
來使用任意 Intent
啟動元件。Intent
,並使用該 Intent
來啟動活動。
...
Intent nextIntent = (Intent) getIntent().getParcelableExtra("next-intent");
startActivity(nextIntent);
...
username
和 password
將非特殊權限使用者的使用者帳戶驗證資訊 (這類使用者具有「default」角色,而具特殊權限之使用者具有「admin」角色) 序列化為位於 C:\user_info.json
的 JSON 檔案:
...
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
using (JsonWriter writer = new JsonTextWriter(sw))
{
writer.Formatting = Formatting.Indented;
writer.WriteStartObject();
writer.WritePropertyName("role");
writer.WriteRawValue("\"default\"");
writer.WritePropertyName("username");
writer.WriteRawValue("\"" + username + "\"");
writer.WritePropertyName("password");
writer.WriteRawValue("\"" + password + "\"");
writer.WriteEndObject();
}
File.WriteAllText(@"C:\user_info.json", sb.ToString());
JsonWriter.WriteRawValue()
來執行的,所以將不會驗證 username
和 password
中的不可信賴資料以逸出與 JSON 相關的特殊字元。如此便允許使用者任意插入 JSON 金鑰,進而可能變更已序列化之 JSON 的結構。在此範例中,如果密碼為 Evil123!
的非特殊權限使用者 mallory
在依設定 username
變數值的提示進行輸入時,將 ","role":"admin
附加至其使用者名稱,則產生並儲存到 C:\user_info.json
的 JSON 將會如下所示:
{
"role":"default",
"username":"mallory",
"role":"admin",
"password":"Evil123!"
}
JsonConvert.DeserializeObject()
還原序列化為 Dictionary
物件,如下所示:
String jsonString = File.ReadAllText(@"C:\user_info.json");
Dictionary<string, string> userInfo = JsonConvert.DeserializeObject<Dictionary<string, strin>>(jsonString);
Dictionary
物件中 username
、password
和 role
金鑰產生的值將分別是 mallory
、Evil123!
和 admin
。如果未進一步驗證還原序列化的 JSON 值是否有效,應用程式將會錯誤指派「admin」權限給使用者 mallory
。username
和 password
將非特殊權限使用者的使用者帳戶驗證資訊 (這類使用者具有「default」角色,而擁有特殊權限的使用者具有「admin」角色) 序列化為位於 ~/user_info.json
的 JSON 檔案:
...
func someHandler(w http.ResponseWriter, r *http.Request){
r.parseForm()
username := r.FormValue("username")
password := r.FormValue("password")
...
jsonString := `{
"username":"` + username + `",
"role":"default"
"password":"` + password + `",
}`
...
f, err := os.Create("~/user_info.json")
defer f.Close()
jsonEncoder := json.NewEncoder(f)
jsonEncoder.Encode(jsonString)
}
username
和 password
中的不可信賴資料以逸出與 JSON 相關的特殊字元。如此便允許使用者任意插入 JSON 金鑰,進而可能變更已序列化之 JSON 的結構。在此範例中,如果密碼為 Evil123!
的非特殊權限使用者 mallory
在輸入自己的使用者名稱時附加了 ","role":"admin
,則產生並儲存至 ~/user_info.json
的 JSON 將會如下所示:
{
"username":"mallory",
"role":"default",
"password":"Evil123!",
"role":"admin"
}
mallory
。username
和 password
將非特殊權限使用者的使用者帳戶驗證資訊 (這類使用者具有「default」角色,而具特殊權限之使用者具有「admin」角色) 序列化為位於 ~/user_info.json
的 JSON 檔案:
...
JsonFactory jfactory = new JsonFactory();
JsonGenerator jGenerator = jfactory.createJsonGenerator(new File("~/user_info.json"), JsonEncoding.UTF8);
jGenerator.writeStartObject();
jGenerator.writeFieldName("username");
jGenerator.writeRawValue("\"" + username + "\"");
jGenerator.writeFieldName("password");
jGenerator.writeRawValue("\"" + password + "\"");
jGenerator.writeFieldName("role");
jGenerator.writeRawValue("\"default\"");
jGenerator.writeEndObject();
jGenerator.close();
JsonGenerator.writeRawValue()
來執行的,所以將不會驗證 username
和 password
中的不可信賴資料以逸出與 JSON 相關的特殊字元。如此便允許使用者任意插入 JSON 金鑰,進而可能變更已序列化之 JSON 的結構。在此範例中,如果密碼為 Evil123!
的非特殊權限使用者 mallory
在依設定 username
變數值的提示進行輸入時,將 ","role":"admin
附加至其使用者名稱,則產生並儲存到 ~/user_info.json
的 JSON 將會如下所示:
{
"username":"mallory",
"role":"admin",
"password":"Evil123!",
"role":"default"
}
JsonParser
還原序列化為 HashMap
物件,如下所示:
JsonParser jParser = jfactory.createJsonParser(new File("~/user_info.json"));
while (jParser.nextToken() != JsonToken.END_OBJECT) {
String fieldname = jParser.getCurrentName();
if ("username".equals(fieldname)) {
jParser.nextToken();
userInfo.put(fieldname, jParser.getText());
}
if ("password".equals(fieldname)) {
jParser.nextToken();
userInfo.put(fieldname, jParser.getText());
}
if ("role".equals(fieldname)) {
jParser.nextToken();
userInfo.put(fieldname, jParser.getText());
}
if (userInfo.size() == 3)
break;
}
jParser.close();
HashMap
物件中 username
、password
和 role
金鑰產生的值將分別是 mallory
、Evil123!
和 admin
。如果未進一步驗證還原序列化的 JSON 值是否有效,應用程式將會錯誤指派「admin」權限給使用者 mallory
。
var str = document.URL;
var url_check = str.indexOf('name=');
var name = null;
if (url_check > -1) {
name = decodeURIComponent(str.substring((url_check+5), str.length));
}
$(document).ready(function(){
if (name !== null){
var obj = jQuery.parseJSON('{"role": "user", "name" : "' + name + '"}');
...
}
...
});
name
中不可信賴的資料,以逸出與 JSON 相關的特殊字元。如此便允許使用者任意注入 JSON 金鑰,進而可能變更已序列化之 JSON 的結構。在此範例中,如果非特殊權限使用者 mallory
將 ","role":"admin
附加至 URL 中的名稱參數,JSON 會變成:
{
"role":"user",
"username":"mallory",
"role":"admin"
}
jQuery.parseJSON()
進行剖析並設定為純物件,這表示 obj.role
現在會傳回 "admin",而不是 "user"_usernameField
和 _passwordField
,將非特殊權限使用者的使用者帳戶驗證資訊 (這類使用者具有「default」角色,而具特殊權限之使用者具有「admin」角色) 序列化為 JSON:
...
NSString * const jsonString = [NSString stringWithFormat: @"{\"username\":\"%@\",\"password\":\"%@\",\"role\":\"default\"}" _usernameField.text, _passwordField.text];
NSString.stringWithFormat:
來執行的,所以將不會驗證 _usernameField
和 _passwordField
中的不可信賴資料以逸出與 JSON 相關的特殊字元。如此便允許使用者任意插入 JSON 金鑰,進而可能變更已序列化之 JSON 的結構。在此範例中,如果密碼為 Evil123!
的非特殊權限使用者 mallory
在輸入 _usernameField
欄位時,會將 ","role":"admin
附加至其使用者名稱,則產生的 JSON 將會如下所示:
{
"username":"mallory",
"role":"admin",
"password":"Evil123!",
"role":"default"
}
NSJSONSerialization.JSONObjectWithData:
還原序列化為 NSDictionary
物件,如下所示:
NSError *error;
NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:&error];
NSDictionary
物件中產生的 username
、password
和 role
值將分別是 mallory
、Evil123!
和 admin
。如果未進一步驗證還原序列化的 JSON 值是否有效,應用程式將會錯誤指派「admin」權限給使用者 mallory
。
import json
import requests
from urllib.parse import urlparse
from urllib.parse import parse_qs
url = 'https://www.example.com/some_path?name=some_value'
parsed_url = urlparse(url)
untrusted_values = parse_qs(parsed_url.query)['name'][0]
with open('data.json', 'r') as json_File:
data = json.load(json_File)
data['name']= untrusted_values
with open('data.json', 'w') as json_File:
json.dump(data, json_File)
...
name
中不受信任的資料,以逸出與 JSON 相關的特殊字元。如此便允許使用者任意注入 JSON 金鑰,進而可能變更已序列化的 JSON 結構。在此範例中,如果非特殊權限使用者 mallory
將 ","role":"admin
附加至 URL 中的名稱參數,JSON 會變成:
{
"role":"user",
"username":"mallory",
"role":"admin"
}
usernameField
和 passwordField
,將非特殊權限使用者的使用者帳戶驗證資訊 (這類使用者具有「default」角色,而具特殊權限之使用者具有「admin」角色) 序列化為 JSON:
...
let jsonString : String = "{\"username\":\"\(usernameField.text)\",\"password\":\"\(passwordField.text)\",\"role\":\"default\"}"
usernameField
和 passwordField
中不受信任的資料以逸出與 JSON 相關的特殊字元。如此便允許使用者任意注入 JSON 金鑰,進而可能變更已序列化之 JSON 的結構。在此範例中,如果密碼為 Evil123!
的非特殊權限使用者 mallory
在輸入 usernameField
欄位時,會將 ","role":"admin
附加至其使用者名稱,則產生的 JSON 將會如下所示:
{
"username":"mallory",
"role":"admin",
"password":"Evil123!",
"role":"default"
}
NSJSONSerialization.JSONObjectWithData:
還原序列化為 NSDictionary
物件,如下所示:
var error: NSError?
var jsonData : NSDictionary = NSJSONSerialization.JSONObjectWithData(jsonString.dataUsingEncoding(NSUTF8StringEncoding), options: NSJSONReadingOptions.MutableContainers, error: &error) as NSDictionary
NSDictionary
物件中產生的 username
、password
和 role
值將分別是 mallory
、Evil123!
和 admin
。如果未進一步驗證還原序列化的 JSON 值是否有效,應用程式將會錯誤指派「admin」權限給使用者 mallory
。
def searchUserDetails(key:String) = Action.async { implicit request =>
val user_json = getUserDataFor(user)
val value = (user_json \ key).get.as[String]
...
}
key
可由使用者控制,惡意使用者便可利用這一點來存取使用者的密碼及 JSON 文件內可能包含的任何其他私密資料。search
方法的 javax.naming.directory.SearchControls
實例上將 returningObjectFlag
設為 true
或使用代表其設定此旗標的程式庫函式,執行物件傳回搜尋。
<beans ... >
<authentication-manager>
<ldap-authentication-provider
user-search-filter="(uid={0})"
user-search-base="ou=users,dc=example,dc=org"
group-search-filter="(uniqueMember={0})"
group-search-base="ou=groups,dc=example,dc=org"
group-role-attribute="cn"
role-prefix="ROLE_">
</ldap-authentication-provider>
</authentication-manager>
</beans>
...
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 查詢的使用者能夠存取的所有記錄。