HTTP
. Esto expone los datos a acceso no autorizado, manipulaciones y posible robo.protocol
de un HTTP Listener Connector (listener-connection
) a HTTP
. Como resultado, las conexiones con HTTP Listener no son seguras.
<http:listener-config name="http_listener_config">
<http:listener-connection host="example.com" port="8080" protocol="HTTP">
...
</http:listener-connection>
</http:listener-config>
tls:context
define un conjunto de configuraciones de conexión TLS. Entre las configuraciones, el elemento tls:trust-store
especifica un archivo que contiene certificados de autoridades de certificación de confianza que un cliente usa para verificar un certificado presentado por un servidor. De forma predeterminada, el motor de tiempo de ejecución de Mule verifica el certificado del servidor para cada conexión TLS.insecure
del elemento tls:trust-store
es true
, los certificados de servidor se aceptan sin verificación.insecure
en true
. Como resultado, el motor de tiempo de ejecución de Mule no verifica el certificado del servidor de ninguna conexión con el contexto TLS denominado demoTlsContext
. Esta conexión es vulnerable a un ataque "man-in-the-middle".
...
<tls:context name="demoTlsContext">
...
<tls:trust-store ... insecure="true" ... />
...
<tls:context/>
...
...
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
no contiene un carácter de comilla simple. Si un atacante con el nombre de usuario wiley
introduce la cadena "123' || '4' != '5
" para emailId
, la consulta se convertirá en lo siguiente:
user == 'wiley' && emailId == '123' || '4' != '5'
|| '4' != '5'
hace que la cláusula where siempre se evalúe como true
, por lo que la consulta devuelve todas las entradas almacenadas en la colección emails
, independientemente del propietario del correo electrónico.
...
// "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
contiene alguno de los valores esperados. Si un usuario malintencionado introduce un valor de tipo como :value = :value OR :value
, entonces la consulta será como se muestra a continuación::value = :value OR :value = :value AND Password = :password
:value = :value
hace que la cláusula where siempre se evalúe como true, por lo que la consulta devuelve todas las entradas almacenadas en la colección users
, sin importar el propietario del correo electrónico.
...
// "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
contiene alguno de los valores esperados. Si un usuario malintencionado introduce un valor de tipo como :value = :value OR :value
, entonces la consulta será como se muestra a continuación::value = :value OR :value = :value AND Password = :password
:value = :value
hace que la cláusula where siempre se evalúe como true, por lo que la consulta devuelve todas las entradas almacenadas en la colección users
, sin importar el propietario del correo electrónico.
...
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
no contiene un carácter de comilla simple. Si un atacante con el nombre de usuario wiley
introduce la cadena "123' || '4' != '5
" para emailId
, la consulta se convertirá en lo siguiente:
this.owner == 'wiley' && this.emailId == '123' || '4' != '5'
|| '4' != '5'
hace que la cláusula where siempre se evalúe como true
, por lo que la consulta devuelve todas las entradas almacenadas en la colección emails
, independientemente del propietario del correo electrónico.
...
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
no contiene un carácter de comilla doble. Si un atacante con el nombre de usuario wiley
introduce la cadena "123" || "4" != "5
" para emailId
, la consulta se convertirá en lo siguiente:
this.owner == "wiley" && this.emailId == "123" || "4" != "5"
|| "4" != "5"
hace que la cláusula where siempre se evalúe como true, por lo que la consulta devuelve todas las entradas almacenadas en la colección emails
, sin importar el propietario del correo electrónico.
...
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
no contiene un carácter de comilla doble. Si un atacante con el nombre de usuario wiley
introduce la cadena "123" || "4" != "5
" para emailId
, la consulta se convertirá en lo siguiente:
this.owner == "wiley" && this.emailId == "123" || "4" != "5"
|| "4" != "5"
, la cláusula where
siempre se evalúa como true, por lo que la consulta devuelve todas las entradas almacenadas en la colección emails
, sin importar el propietario del correo electrónico.
...
NSString *emailId = [self getEmailIdFromUser];
NSString *query = [NSString stringWithFormat:@"id == '%@'", emailId];
RLMResults<Email *> *emails = [Email objectsInRealm:realm where:query];
...
id == '<emailId value>'
emailId
no contiene un carácter de comilla simple. Si un usuario malintencionado introduce la cadena 123' or '4' != '5
para emailId
, entonces la consulta será de la siguiente forma:
id == '123' or '4' != '5'
or '4' != '5'
, la cláusula where
siempre se evalúa como true, lo que podría hacer que la consulta devuelva todas las entradas almacenadas en la colección emails
, sin importar el propietario del correo electrónico.
...
let emailId = getFromUser("emailId")
let email = realm.objects(Email.self).filter("id == '" + emailId + "'")
...
id == '<emailId value>'
emailId
no contiene un carácter de comilla simple. Si un usuario malintencionado introduce la cadena 123' or '4' != '5
para emailId
, entonces la consulta será de la siguiente forma:
id == '123' or '4' != '5'
or '4' != '5'
, la cláusula filter
siempre se evalúa como true, lo que podría hacer que la consulta devuelva todas las entradas almacenadas en la colección emails
, sin importar el propietario del correo electrónico.NullException
.cmd
". Si un usuario malintencionado puede controlar el entorno del programa para que no se defina "cmd
", el programa genera una excepción de puntero nulo al intentar llamar al método Trim()
.
string cmd = null;
...
cmd = Environment.GetEnvironmentVariable("cmd");
cmd = cmd.Trim();
null
antes de comprobar si es null
o no. Los errores de desreferencia tras la comprobación se producen cuando un programa realiza una comprobación explícita de null
y procede a desreferenciar el puntero cuando se sabe que es null
. Los errores de este tipo son normalmente el resultado de errores de escritura o descuidos del programador. Los errores de desreferencia tras el almacenamiento se producen cuando un programa establece de forma explícita un puntero en null
y luego lo desreferencia. Con frecuencia, el error es el resultado de que un programador inicialice una variable en null
cuando se declara.ptr
no es NULL
. Esta suposición se hace explícita cuando el programador desreferencia el puntero. Esta suposición luego queda contradicha cuando el programador contrasta ptr
y NULL
. Si ptr
puede ser NULL
al comprobarla en la instrucción if
, entonces también puede ser NULL
cuando se desreferencia y podría ocasionar un error de segmentación.Ejemplo 2: En el código siguiente, el programador confirma que la variable
ptr->field = val;
...
if (ptr != NULL) {
...
}
ptr
es NULL
y por eso lo desreferencia erróneamente. Si ptr
es NULL
cuando se comprueba en la instrucción if
, entonces se produce una desreferencia de null
que provocará un error de segmentación.Ejemplo 3: En el código siguiente, el programador olvida que la cadena
if (ptr == null) {
ptr->field = val;
...
}
'\0'
es en realidad 0 o NULL
; por lo tanto, puede desreferenciar un puntero nulo y provocar un fallo de segmentación.Ejemplo 4: En el código siguiente, el programador establece explícitamente la variable
if (ptr == '\0') {
*ptr = val;
...
}
ptr
en NULL
. A continuación, el programador desreferencia ptr
antes de comprobar si en el objeto hay un valor null
.
*ptr = NULL;
...
ptr->field = val;
...
}
NullPointerException
.cmd
". Si un usuario malintencionado puede controlar el entorno del programa para que no se defina "cmd
", el programa genera una excepción de puntero nulo al intentar llamar al método trim()
.
String val = null;
...
cmd = System.getProperty("cmd");
if (cmd)
val = util.translateCommand(cmd);
...
cmd = val.trim();
unserialize()
. Los usuarios malintencionados podrían transferir cadenas serializadas especialmente diseñadas a una llamada unserialize()
vulnerable, dando como resultado la inyección de objetos PHP en el ámbito de la aplicación. La gravedad de esta vulnerabilidad depende de las clases disponibles en el ámbito de la aplicación. Las clases que implementan un método mágico PHP como __wakeup
o __destruct
serán interesantes para los atacantes dado que podrán ejecutar el código dentro de esos métodos.__destruct()
y ejecuta un comando del sistema definido como una propiedad de clases. También hay una llamada no segura a unserialize()
con datos proporcionados por el usuario.
...
class SomeAvailableClass {
public $command=null;
public function __destruct() {
system($this->command);
}
}
...
$user = unserialize($_GET['user']);
...
Example 1
, la aplicación puede estar esperando un objeto de User
serializado, pero un atacante podría proporcionar una versión serializada de SomeAvailableClass
con un valor predefinido para su propiedad command
:
GET REQUEST: http://server/page.php?user=O:18:"SomeAvailableClass":1:{s:7:"command";s:8:"uname -a";}
$user
y, a continuación, ejecutará el comando proporcionado por el atacante.unserialize()
vulnerable mediante una técnica conocida como "Programación orientada a las propiedades", que introdujo Stefan Esser durante la conferencia BlackHat de 2010. Esta técnica permite a un atacante volver a utilizar el código existente para diseñar su propia carga.YAML.load()
. Los usuarios malintencionados podrían transferir cadenas serializadas especialmente diseñadas a una llamada YAML.load()
vulnerable, dando como resultado la inyección de objetos de Ruby arbitrarios en el programa, siempre y cuando la clase se cargue en la aplicación en el momento de deserialización. Esto puede facilitar un montón de oportunidades de ataques diversos, como omitir la lógica de validación para buscar vulnerabilidades de Cross-Site Scripting, permitir la SQL Injection a través de lo que parecen ser valores codificados o incluso la ejecución de código completa.YAML.load()
con datos proporcionados por el usuario.
...
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
, la aplicación puede estar esperando a un objeto de User
serializado, que también tiene una función llamada print_details
, pero un atacante en realidad podría proporcionar una versión serializada de un objeto Transaction
con un valor predefinido para su atributo @id
. Por lo tanto, una solicitud como la siguiente puede permitir la omisión de la comprobación de validación que intenta asegurarse de que @id
es un valor numérico.
GET REQUEST: http://server/page?user=!ruby%2Fobject%3ATransaction%0Aid%3A4%20or%205%3D5%0A
user
tiene asignado !ruby/object:Transaction\nid:4 or 5=5\n
.Transaction
y @id
se establecerá en "4 or 5=5"
. Cuando el desarrollador cree que se llamará a User#print_details()
, ahora se llamará a Transaction#print_details()
y la interpolación de cadena de Ruby significará que la consulta SQL se cambiará para ejecutar la consulta: SELECT * FROM transactions WHERE id=4 or 5=5
. Dado que se agregó la cláusula adicional, la consulta se evalúa en true
y devolverá todo dentro de la tabla transactions
en lugar de la única fila prevista por el desarrollador.YAML.load()
vulnerable mediante una técnica conocida como "Programación orientada a las propiedades", que introdujo Stefan Esser durante la conferencia BlackHat de 2010. Esta técnica permite a un atacante volver a utilizar el código existente para diseñar su propia carga.clone()
debe llamar super.clone()
para obtener el nuevo objeto.clone()
deben obtener el nuevo objeto llamando super.clone()
. Si una clase no puede seguir esta convención, un método clone()
de subclase devolverá un objeto del tipo incorrecto.super.clone()
. Dada la forma en que Kibitzer
implementa clone()
, el método de clonación de FancyKibitzer
devolverá un objeto de tipo Kibitzer
en lugar de FancyKibitzer
.
public class Kibitzer implements Cloneable {
public Object clone() throws CloneNotSupportedException {
Object returnMe = new Kibitzer();
...
}
}
public class FancyKibitzer extends Kibitzer
implements Cloneable {
public Object clone() throws CloneNotSupportedException {
Object returnMe = super.clone();
...
}
}
Equals()
y GetHashCode()
.a.Equals(b) == true
, entonces a.GetHashCode() == b.GetHashCode()
. Equals()
pero no GetHashCode()
.
public class Halfway() {
public override boolean Equals(object obj) {
...
}
}
equals()
y hashCode()
.a.equals(b) == true
, entonces a.hashCode() == b.hashCode()
. equals()
pero no hashCode()
.
public class halfway() {
public boolean equals(Object obj) {
...
}
}
saveState()
y restoreState()
.saveState(javax.faces.context.FacesContext)
como restoreState(javax.faces.context.FacesContext, java.lang.Object)
, o no implementar ninguna de ellos. Como estos dos métodos tienen una relación estrecha, no se pueden tener los métodos saveState(javax.faces.context.FacesContext)
y restoreState(javax.faces.context.FacesContext, java.lang.Object)
residiendo en diferentes niveles de la jerarquía de herencia.saveState()
y no restoreState()
, de forma que siempre está equivocada, independientemente de lo que pueda hacer cualquier clase
public class KibitzState implements StateHolder {
public Object saveState(FacesContext fc) {
...
}
}
SqlClientPermission
, que controla el modo en el que los usuarios pueden conectarse a una base de datos. En este ejemplo, el programa transfiere false
como segundo parámetro al constructor, que controla si los usuarios tienen permiso para establecer conexión con contraseñas en blanco. Al transferir el valor false a este parámetro, se indica que no deben permitirse contraseñas en blanco.
...
SCP = new SqlClientPermission(pstate, false);
...
PermissionState
transferido como primer parámetro reemplaza cualquier valor transferido al segundo parámetro, el constructor permite el uso de contraseñas en blanco para las conexiones de base de datos, lo que contradice el segundo argumento. Para rechazar las contraseñas en blanco, el programa debe transferir PermissionState.None
al primer parámetro del constructor. Debido a la ambigüedad en su funcionalidad, la versión de dos parámetros del constructor SqlClientPermission
se ha dejado de utilizar en favor de la versión de un único parámetro, que transmite el mismo grado de información sin el riesgo de interpretaciones erróneas.getpw()
para comprobar que una contraseña de texto sin formato coincide con una contraseña cifrada del usuario. Si la contraseña es válida, la función establece result
en 1; de lo contrario, se establece en 0.
...
getpw(uid, pwdline);
for (i=0; i<3; i++){
cryptpw=strtok(pwdline, ":");
pwdline=0;
}
result = strcmp(crypt(plainpw,cryptpw), cryptpw) == 0;
...
getpw(
) puede provocar problemas desde el punto de vista de la seguridad, ya que puede desbordar el búfer que pasa a su segundo parámetro. Debido a esta vulnerabilidad, getpw()
se ha sustituido por getpwuid()
, que realiza la misma búsqueda que getpw()
, pero que devuelve un puntero a una estructura asignada estadísticamente para mitigar el riesgo.
...
String name = new String(nameBytes, highByte);
...
nameBytes
. Debido a la evolución de los juegos de caracteres utilizados para codificar cadenas, este constructor quedó obsoleto y reemplazado por un constructor que acepta como uno de sus parámetros el nombre del charset
que se utiliza para codificar los bytes para la conversión.Digest::HMAC
, cuyo uso está explícitamente contraindicado en la documentación debido a su implicación accidental dentro de una versión.
require 'digest/hmac'
hmac = Digest::HMAC.new("foo", Digest::RMD160)
...
hmac.update(buf)
...
Digest::HMAC
dejó de utilizarse de forma inmediata al estar implicada en una inclusión accidental dentro de una versión. Debido a la posibilidad de que no funcione según lo previsto a causa del código experimental o no probado adecuadamente, su uso está fuertemente contraindicado, especialmente si consideramos la relación que tienen los códigos HMAC con la funcionalidad criptográfica.IsBadXXXPtr()
. Estas funciones:IsBadWritePtr()
en un intento de impedir malas escrituras de memoria.
if (IsBadWritePtr(ptr, length))
{
[handle error]
}
checkCallingOrSelfPermission()
o checkCallingOrSelfUriPermission()
determina si el programa que realiza la llamada cuenta con el permiso necesario para acceder a determinado servicio o URI. Sin embargo, estas funciones deben utilizarse con cuidado, ya que pueden conceder acceso a aplicaciones malintencionadas, que carecen de los permisos correspondientes, adoptando los permisos de las aplicaciones.