Problemas de validação e representação da entrada são causados por metacaracteres, codificações alternativas e representações numéricas. Confiar na entrada resulta em problemas de segurança. Os problemas incluem: “Buffer Overflows”, ataques de “Cross-Site Scripting”, “SQL Injection”, entre outros.
...
DirectorySearcher src =
new DirectorySearcher("(manager=" + managerName.Text + ")");
src.SearchRoot = de;
src.SearchScope = SearchScope.Subtree;
foreach(SearchResult res in src.FindAll()) {
...
}
(manager=Smith, John)
managerName
não contiver metacaracteres LDAP. Se um invasor inserir a string Hacker, Wiley)(|(objectclass=*)
para managerName
, a consulta se tornará a seguinte:
(manager=Hacker, Wiley)(|(objectclass=*))
|(objectclass=*)
faz com que o filtro seja correspondido com todas as entradas do diretório e permite que o invasor recupere informações sobre o grupo inteiro de usuários. A amplitude desse ataque pode ser limitada dependendo das permissões com as quais a consulta LDAP é realizada. Porém, se o invasor puder controlar a estrutura de comandos da consulta, esse ataque poderá afetar pelo menos todos os registros que podem ser acessados pelo usuário com base no qual a consulta LDAP é executada.
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
não contiver metacaracteres LDAP. Se um invasor inserir a string Hacker, Wiley)(|(objectclass=*)
para manager
, a consulta se tornará a seguinte:
(manager=Hacker, Wiley)(|(objectclass=*))
|(objectclass=*)
faz com que o filtro seja correspondido com todas as entradas do diretório e permite que o invasor recupere informações sobre o grupo inteiro de usuários. A amplitude desse ataque pode ser limitada dependendo das permissões com as quais a consulta LDAP é realizada. Porém, se o invasor puder controlar a estrutura de comandos da consulta, esse ataque poderá afetar pelo menos todos os registros que podem ser acessados pelo usuário com base no qual a consulta LDAP é executada.
...
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
não contiver metacaracteres LDAP. Se um invasor inserir a string Hacker, Wiley)(|(objectclass=*)
para managerName
, a consulta se tornará a seguinte:
(manager=Hacker, Wiley)(|(objectclass=*))
|(objectclass=*)
faz com que o filtro seja correspondido com todas as entradas do diretório e permite que o invasor recupere informações sobre o grupo inteiro de usuários. A amplitude desse ataque pode ser limitada dependendo das permissões com as quais a consulta LDAP é realizada. Porém, se o invasor puder controlar a estrutura de comandos da consulta, esse ataque poderá afetar pelo menos todos os registros que podem ser acessados pelo usuário com base no qual a consulta LDAP é executada.
...
$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
não contiver metacaracteres LDAP.Se um invasor inserir a string Hacker, Wiley)(|(objectclass=*)
para managerName
, a consulta se tornará a seguinte:
(manager=Hacker, Wiley)(|(objectclass=*))
|(objectclass=*)
faz com que o filtro seja correspondido com todas as entradas do diretório e permite que o invasor recupere informações sobre o grupo inteiro de usuários.A amplitude desse ataque pode ser limitada dependendo das permissões com as quais a consulta LDAP é realizada. Porém, se o invasor puder controlar a estrutura de comandos da consulta, esse ataque poderá afetar pelo menos todos os registros que podem ser acessados pelo usuário com base no qual a consulta LDAP é executada.ou
de um campo oculto enviado por meio de uma solicitação HTTP e o utiliza para criar um novo DirectoryEntry
.
...
de = new DirectoryEntry("LDAP://ad.example.com:389/ou="
+ hiddenOU.Text + ",dc=example,dc=com");
...
ou
inesperado. O problema é que o desenvolvedor não conseguiu tirar proveito dos mecanismos de controle de acesso apropriados necessários para permitir que consultas subsequentes acessem somente os registros de funcionários que o usuário atual tem permissão para ler.dn
de um soquete e a utiliza para realizar uma consulta 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
inesperada. O problema é que o desenvolvedor não conseguiu tirar proveito dos mecanismos de controle de acesso apropriados necessários para permitir que consultas subsequentes acessem somente os registros de funcionários que o usuário atual tem permissão para ler.
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
do usuário e a utiliza para realizar uma consulta LDAP.
$dn = $_POST['dn'];
if (ldap_bind($ds)) {
...
try {
$rs = ldap_search($ds, $dn, "ou=People,dc=example,dc=com", $attr);
...
dn
base provém de uma entrada do usuário e a consulta é realizada com uma associação anônima, um invasor pode alterar os resultados dessa consulta especificando uma string dn inesperada. O problema é que o desenvolvedor não conseguiu tirar proveito dos mecanismos de controle de acesso apropriados necessários para permitir que consultas subsequentes acessem somente os registros de funcionários que o usuário atual tem permissão para ler.webview
, mas não implementa nenhum controle para impedir ataques de discagem automática ao visitar sites mal-intencionados.webview
para carregar um site que pode conter links não confiáveis, mas ele não especifica um delegado capaz de validar as solicitações iniciadas nesta webview
:
...
NSURL *webUrl = [[NSURL alloc] initWithString:@"https://some.site.com/"];
NSURLRequest *webRequest = [[NSURLRequest alloc] initWithURL:webUrl];
[_webView loadRequest:webRequest];
...
webview
, mas não implementa nenhum controle para impedir ataques de discagem automática ao visitar sites mal-intencionados.webview
para carregar um site que pode conter links não confiáveis, mas ele não especifica um delegado capaz de validar as solicitações iniciadas nesta webview
:
...
let webUrl : NSURL = NSURL(string: "https://some.site.com/")!
let webRequest : NSURLRequest = NSURLRequest(URL: webUrl)
webView.loadRequest(webRequest)
...
webview
, mas não implementa nenhum controle para verificar e validar os links nos quais o usuário poderá clicar.webview
para carregar um site que pode conter links não confiáveis, mas ele não especifica um delegado capaz de validar as solicitações iniciadas nesta webview
:
...
NSURL *webUrl = [[NSURL alloc] initWithString:@"https://some.site.com/"];
NSURLRequest *webRequest = [[NSURLRequest alloc] initWithURL:webUrl];
[webView loadRequest: webRequest];
webview
, mas não implementa nenhum controle para verificar e validar os links nos quais o usuário poderá clicar.webview
para carregar um site que pode conter links não confiáveis, mas ele não especifica um delegado capaz de validar as solicitações iniciadas nesta 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.
...
FOO
" para val
, a seguinte entrada será registrada:
XY E 123 VAL: FOO
FOO XY E 124 VAL: BAR
", a seguinte entrada será registrada:
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);
}
twenty-one
" para val
, a seguinte entrada será registrada:
Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
", a seguinte entrada será registrada:
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);
}
...
twenty-one
" para val
, a seguinte entrada será registrada:
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
", a seguinte entrada será registrada:
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);
...
twenty-one
" para val
, a seguinte entrada será registrada:
Illegal value=twenty-one
twenty-one\n\nINFO: User logged out=evil
", a seguinte entrada será registrada:
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.
...
FOO
" para VAL
, a seguinte entrada será registrada:
VAL: FOO
FOO VAL: BAR
", a seguinte entrada será registrada:
VAL: FOO VAL: BAR
<cflog file="app_log" application="No" Thread="No"
text="Failed to parse val="#Form.val#">
twenty-one
" para val
, a seguinte entrada será registrada:
"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
", a seguinte entrada será registrada:
"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
" para logout
e ele puder criar um usuário com o nome "admin
", a seguinte entrada será armazenada em log:
Attempt to log out: name: admin logout: twenty-one
admin+logout:+1+++++++++++++++++++++++
", a seguinte entrada será armazenada em log:
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);
}
...
twenty-one
" para val
, a seguinte entrada será registrada:
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
", a seguinte entrada será registrada:
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
Example 1
à plataforma 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);
...
twenty-one
" para val
, a seguinte entrada será registrada:
INFO: Failed to parse val = twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
", a seguinte entrada será registrada:
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);
...
twenty-one
" para val
, a seguinte entrada será registrada:
INFO: Illegal value=twenty-one
twenty-one\n\nINFO: User logged out=evil
", a seguinte entrada será registrada:
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
" para logout
e ele puder criar um usuário com o nome "admin
", a seguinte entrada será armazenada em log:
PHP Notice: Attempt to log out: name: admin logout: twenty-one
admin+logout:+1+++++++++++++++++++++++
", a seguinte entrada será armazenada em log:
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
" para logout
e ele puder criar um usuário com o nome "admin
", a seguinte entrada será armazenada em log:
Attempt to log out: name: admin logout: twenty-one
admin+logout:+1+++++++++++++++++++++++
", a seguinte entrada será armazenada em log:
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
...
twenty-one
" para val
, a seguinte entrada será registrada:
INFO: Failed to parse val
INFO: twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
", a seguinte entrada será registrada:
INFO: Failed to parse val
INFO: twenty-one
INFO: User logged out=badguy
...
let num = Int(param)
if num == nil {
NSLog("Illegal value = %@", param)
}
...
twenty-one
" para val
, a seguinte entrada será registrada:
INFO: Illegal value = twenty-one
twenty-one\n\nINFO: User logged out=evil
", a seguinte entrada será registrada:
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
...
twenty-one
" para val
, a seguinte entrada será registrada:
Failed to parse val=twenty-one
twenty-one%0a%0a+User+logged+out%3dbadguy
", a seguinte entrada será registrada:
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);
}
}
twenty-one
" para val
, a seguinte entrada será registrada:
Failed to parse val: twenty-one
twenty-one%0a%0aUser+logged+out%3dbadguy
", a seguinte entrada será registrada:
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);
}
...
twenty-one
" para val
, a seguinte entrada será registrada:
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
", a seguinte entrada será registrada:
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
Example 1
à plataforma 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)
}
...
twenty-one
" para val
, a seguinte entrada será registrada:
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
", a seguinte entrada será registrada:
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);
}
...
twenty-one
" para val
, a seguinte entrada será registrada:
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
", a seguinte entrada será registrada:
INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy
Example 1
à plataforma 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);
...
twenty-one
" para val
, a seguinte entrada será registrada:
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
", a seguinte entrada será registrada:
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)
...
twenty-one
" para val
, a seguinte entrada será registrada:
INFO: Failed to parse val=twenty-one
twenty-one%0a%0aINFO:+User+logged+out%3dbadguy
", a seguinte entrada será registrada:
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
...
twenty-one
" para val
, a seguinte entrada será registrada:
DEBUG: Failed to parse val
DEBUG: twenty-one
twenty-one%0a%DEBUG:+User+logged+out%3dbadguy
", a seguinte entrada será registrada:
DEBUG: Failed to parse val
DEBUG: twenty-one
DEBUG: User logged out=badguy
CREATE
que é enviado ao servidor IMAP. Um invasor pode usar esse parâmetro para modificar o comando enviado ao servidor e injetar novos comandos usando caracteres 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
e PASS
que é enviado ao servidor POP3. Um invasor pode usar esse parâmetro para modificar o comando enviado ao servidor e injetar novos comandos usando caracteres CRLF.
...
String username = request.getParameter("username");
String password = request.getParameter("password");
...
POP3SClient pop3 = new POP3SClient(proto, false);
pop3.login(username, password)
...
VRFY
que é enviado para o servidor SMTP. Um invasor pode usar esse parâmetro para modificar o comando enviado ao servidor e injetar novos comandos usando caracteres CRLF.
...
c, err := smtp.Dial(x)
if err != nil {
log.Fatal(err)
}
user := request.FormValue("USER")
c.Verify(user)
...
VRFY
que é enviado ao servidor SMTP. Um invasor pode usar esse parâmetro para modificar o comando enviado ao servidor e injetar novos comandos usando caracteres 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
que é enviado ao servidor SMTP. Um invasor pode usar esse parâmetro para modificar o comando enviado ao servidor e injetar novos comandos usando caracteres 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
é o comprimento da resposta.ignore 0 0 1\r\n1\r\nset injected 0 3600 10\r\n0123456789\r\nset req-
e, em seguida, a operação torna-se a seguinte:
set req-ignore 0 0 1
1
set injected 0 3600 10
0123456789
set req-1233 0 0 n
<serialized_response_instance>
injected=0123456789
, e os invasores poderão envenenar o cache.
...
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-
e, em seguida, a operação torna-se a seguinte:
set req-ignore 0 0 1
1
set injected 0 3600 10
0123456789
set req-1233 0 0 n
<serialized_response_instance>
injected=0123456789
. Dependendo da carga, os invasores serão capazes de envenenar o cache ou executar código arbitrário injetando uma carga serializada por Pickle que executará um código arbitrário mediante a desserialização.
def form = Form(
mapping(
"name" -> text,
"age" -> number
)(UserData.apply)(UserData.unapply)
)
FormAction
que não consegue validar os dados em relação às exigências esperadas:Exemplo 2: O código a seguir define o estado de uma ação do Spring WebFlow que não consegue validar os dados em relação às exigências esperadas:
<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
não contiver um caractere de aspas simples. Se um invasor com o nome de usuário wiley
inserir a cadeia de caracteres "123' || '4' != '5
" para emailId
, a consulta se tornará a seguinte:
user == 'wiley' && emailId == '123' || '4' != '5'
|| '4' != '5'
faz com que a cláusula where sempre seja avaliada como true
e, portanto, a consulta retorna todas as entradas armazenadas na coleção emails
, independentemente do proprietário do e-mail.
...
// "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
contiver apenas um dos valores esperados. Se um invasor fornecer um valor type como :value = :value OR :value
, a consulta se transforma no seguinte::value = :value OR :value = :value AND Password = :password
:value = :value
faz com que a cláusula "where" sempre seja avaliada como "true" e, portanto, a consulta retorna todas as entradas armazenadas na coleção users
, independentemente do proprietário do email.
...
// "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
contiver apenas um dos valores esperados. Se um invasor fornecer um valor type como :value = :value OR :value
, a consulta se transforma no seguinte::value = :value OR :value = :value AND Password = :password
:value = :value
faz com que a cláusula "where" sempre seja avaliada como "true" e, portanto, a consulta retorna todas as entradas armazenadas na coleção users
, independentemente do proprietário do email.
...
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
não contiver um caractere de aspas simples. Se um invasor com o nome de usuário wiley
inserir a cadeia de caracteres "123' || '4' != '5
" para emailId
, a consulta se tornará a seguinte:
this.owner == 'wiley' && this.emailId == '123' || '4' != '5'
|| '4' != '5'
faz com que a cláusula where sempre seja avaliada como true
e, portanto, a consulta retorna todas as entradas armazenadas na coleção emails
, independentemente do proprietário do e-mail.
...
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
não contiver um caractere de aspas duplas. Se um invasor com o nome de usuário wiley
inserir a string "123" || "4" != "5
" para emailId
, a consulta se tornará a seguinte:
this.owner == "wiley" && this.emailId == "123" || "4" != "5"
|| "4" != "5"
faz com que a cláusula "where" sempre seja avaliada como "true" e, portanto, a consulta retorna todas as entradas armazenadas na coleção emails
, independentemente do proprietário do email.
...
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
não contiver um caractere de aspas duplas. Se um invasor com o nome de usuário wiley
inserir a string "123" || "4" != "5
" para emailId
, a consulta se tornará a seguinte:
this.owner == "wiley" && this.emailId == "123" || "4" != "5"
|| "4" != "5"
faz com que a cláusula "where
" sempre seja avaliada como "true" e, portanto, a consulta retorna todas as entradas armazenadas na coleção emails
, independentemente do proprietário do email.
...
NSString *emailId = [self getEmailIdFromUser];
NSString *query = [NSString stringWithFormat:@"id == '%@'", emailId];
RLMResults<Email *> *emails = [Email objectsInRealm:realm where:query];
...
id == '<emailId value>'
emailId
não contiver um caractere de aspas simples. Se um invasor inserir a string 123' or '4' != '5
para emailId
, a consulta se tornará a seguinte:
id == '123' or '4' != '5'
or '4' != '5'
faz com que a cláusula where
sempre seja avaliada como "true" e, com isso, a consulta retorna todas as entradas armazenadas na coleção emails
, independentemente do proprietário do email.
...
let emailId = getFromUser("emailId")
let email = realm.objects(Email.self).filter("id == '" + emailId + "'")
...
id == '<emailId value>'
emailId
não contiver um caractere de aspas simples. Se um invasor inserir a string 123' or '4' != '5
para emailId
, a consulta se tornará a seguinte:
id == '123' or '4' != '5'
or '4' != '5'
faz com que a cláusula filter
sempre seja avaliada como "true" e, com isso, a consulta retorna todas as entradas armazenadas na coleção emails
, independentemente do proprietário do email.unserialize()
. Os invasores poderiam passar cadeias de caracteres serializadas criadas especialmente para uma chamada unserialize()
vulnerável, resultando em uma injeção de objeto(s) PHP arbitrário(s) no escopo do aplicativo. A gravidade da vulnerabilidade depende das classes disponíveis no escopo de aplicativo. As classes que estão implementando método de mágica PHP, como __wakeup
ou __destruct
, serão interessantes para os invasores, já que eles serão capazes de executar o código nesses métodos.__destruct()
e executando um comando do sistema definido como uma propriedade de classe. Há também uma chamada insegura para unserialize()
com dados fornecidos pelo usuário.
...
class SomeAvailableClass {
public $command=null;
public function __destruct() {
system($this->command);
}
}
...
$user = unserialize($_GET['user']);
...
Example 1
, o aplicativo pode estar esperando um objeto User
serializado, mas um invasor pode na verdade fornecer uma versão serializada de SomeAvailableClass
com um valor predefinido para sua propriedade command
:
GET REQUEST: http://server/page.php?user=O:18:"SomeAvailableClass":1:{s:7:"command";s:8:"uname -a";}
$user
e ele executará o comando fornecido pelo invasor.unserialize()
vulnerável está sendo chamado usando uma técnica conhecida como "Programação orientada à propriedade", que foi introduzida por Stefan Esser durante a conferência BlackHat de 2010. Essa técnica permite que um invasor reutilize o código existente para criar a sua própria carga de trabalho.YAML.load()
. Os invasores podem transmitir cadeias especialmente projetadas para uma chamada vulnerável YAML.load()
, resultando na injeção de objetos arbitrários Ruby no programa, desde que a classe seja carregada no aplicativo no momento da desserialização. Isso pode permitir uma vasta gama de oportunidades de ataque, como ignorar a lógica de validação para encontrar vulnerabilidades de cross-site scripting, permitis a SQL Injection por meio do que parecem ser valores codificados ou mesmo uma execução de código completo.YAML.load()
com dados fornecidos pelo usuário.
...
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
, o aplicativo pode estar esperando um objeto User
serializado, o qual também tem uma função chamada print_details
, mas um invasor pode de fato fornecer uma versão serializada de um objeto Transaction
com um valor predefinido para o respectivo atributo @id
. Uma solicitação como essa pode, portanto, permitir que se ignore a verificação de validação que tenta se certificar de que @id
seja um valor numérico
GET REQUEST: http://server/page?user=!ruby%2Fobject%3ATransaction%0Aid%3A4%20or%205%3D5%0A
user
é atribuído !ruby/object:Transaction\nid:4 or 5=5\n
.Transaction
, definindo como @id
para "4 or 5=5"
. Quando o desenvolvedor acreditar que está chamando User#print_details()
, na verdade estará chamando Transaction#print_details()
e a interpolação de cadeia do Ruby significará que a consulta SQL será alterada para executar a consulta: SELECT * FROM transactions WHERE id=4 or 5=5
. Devido à cláusula extra adicionada, a consulta é avaliada como true
e retornará tudo dentro da tabela transactions
em vez da única linha pretendida pelo desenvolvedor.YAML.load()
vulnerável está sendo chamado usando uma técnica conhecida como "Programação orientada à propriedade", que foi introduzida por Stefan Esser durante a conferência BlackHat de 2010. Essa técnica permite que um invasor reutilize o código existente para criar a sua própria carga de trabalho.