Los problemas de validación y representación de entradas están causados por metacaracteres, codificaciones alternativas y representaciones numéricas. Los problemas de seguridad surgen de entradas en las que se confía. Estos problemas incluyen: «desbordamientos de búfer», ataques de «scripts de sitios», "SQL injection" y muchas otras acciones.
validate()
que no puede llamar super.validate()
.validate()
de formulario para contrastar el contenido de las propiedades del formulario con las restricciones especificadas en el formulario de validación asociado. Esto significa que las clases siguientes tienen un método validate()
que forma parte del marco de validación:
ValidatorForm
ValidatorActionForm
DynaValidatorForm
DynaValidatorActionForm
validate()
, debe llamar super.validate()
en su implementación de validate()
. De no ser así, el marco de validación no podrá contrastar el contenido del formulario con un formulario de validación. Es decir, el marco de validación se deshabilitará para el formulario en cuestión.
ValidatorForm
ValidatorActionForm
DynaValidatorActionForm
DynaValidaorForm
validate()
en estas clases.
ActionForm
DynaActionForm
ActionForm
para más de un propósito. En situaciones como esta, es posible que haya campos que no se utilicen en algunas asignaciones de acción. Es fundamental que los campos sin utilizar también se validen. Preferiblemente, los campos sin usar se deben limitar de manera que solo puedan estar vacíos o sin definir. Si los campos sin usar no se validan, la lógica de negocios compartida en una acción podría permitir a los atacantes anular las comprobaciones de validación que se llevan a cabo para otros usos del formulario.form-bean
para asignar formularios HTML a acciones. Si el elemento <action-mappings>
del archivo de configuración de Struts no contiene una entrada que se corresponda con un formulario de acción pertinente definido a través de una etiqueta <form-bean>
, es posible que la lógica de la aplicación no esté actualizada.bean2
.
<form-beans>
<form-bean name="bean1" type="coreservlets.UserFormBean1" />
<form-bean name="bean2" type="coreservlets.UserFormBean2" />
</form-beans>
<action-mappings>
<action path="/actions/register1" type="coreservlets.RegisterAction1" name="bean1" scope="request" />
</action-mappings>
validate()
del formulario.
<action path="/download"
type="com.website.d2.action.DownloadAction"
name="downloadForm"
scope="request"
input=".download"
validate="false">
</action>
ActionForm
. Una indicación de que la lógica de validación no se mantiene correctamente son las inconsistencias entre el formulario de acción y el formulario de validación.
public class DateRangeForm extends ValidatorForm {
String startDate, endDate;
public void setStartDate(String startDate) {
this.startDate = startDate;
}
public void setEndDate(String endDate) {
this.endDate = endDate;
}
}
startDate
y endDate
.
<form name="DateRangeForm">
<field property="startDate" depends="date">
<arg0 key="start.date"/>
</field>
<field property="endDate" depends="date">
<arg0 key="end.date"/>
</field>
<field property="scale" depends="integer">
<arg0 key="range.scale"/>
</field>
</form>
scale
. La presencia del tercer campo sugiere que DateRangeForm
se modificó sin tener en cuenta la validación.
app.get('/', function(req, res){
let param = req.params['template']
let val = req.params['templateVal']
let template = Handlebars.compile('{{user}}: {{' + param + '}}');
let templateInput = {}
templateInput['user'] = 'John'
templateInput[param] = val
let result = template(templateInput)
//...
});
Example 1
utiliza Handlebars
como motor de plantilla y los datos controlados por el usuario se concatenan en la plantilla compilada, lo que permite a los atacantes ejecutar JavaScript arbitrario.Echo
. La clase declara un método nativo que utiliza C para devolver comandos introducidos en la consola al usuario.
class Echo {
public native void runEcho();
static {
System.loadLibrary("echo");
}
public static void main(String[] args) {
new Echo().runEcho();
}
}
Echo
:
#include <jni.h>
#include "Echo.h" //the java class fromExample 1
compiled with javah
#include <stdio.h>
JNIEXPORT void JNICALL
Java_Echo_runEcho(JNIEnv *env, jobject obj)
{
char buf[64];
gets(buf);
printf(buf);
}
gets()
, que no realiza ninguna comprobación de límites en su entrada. Example 1
podría detectarse fácilmente a través de una auditoría de código fuente de la implementación del método nativo. Es posible que esto no resulte factible o práctico en función de la disponibilidad del código fuente de C y el modo en que se ha creado el proyecto, aunque en la mayoría de los casos será suficiente. Sin embargo, la capacidad para compartir objetos entre los métodos de Java y nativos eleva el riesgo potencial a casos mucho más insidiosos en los que una administración inadecuada de los datos en Java puede provocar vulnerabilidades inesperadas en el código nativo u operaciones poco seguras en las estructuras de datos dañados del código nativo en Java.Redirect
. La clase declara un método JavaScript nativo, que usa JavaScript para cambiar la ubicación del documento.
import com.google.gwt.user.client.ui.UIObject;
class MyDiv {
...
public static void changeName(final UIObject object, final String name) {
changeName(object.getElement(), url);
}
public static native void changeName(final Element e, final String name) /*-{
$wnd.jQuery(e).html(name);
}-*/;
...
}
Echo
. La clase declara un método nativo que utiliza C para devolver comandos introducidos en la consola al usuario.
class Echo
{
[DllImport("mylib.dll")]
internal static extern void RunEcho();
static void main(String[] args)
{
RunEcho();
}
}
Echo
:
#include <stdio.h>
void __stdcall RunEcho()
{
char* buf = (char*) malloc(64 * sizeof(char));
gets(buf);
printf(buf);
}
gets()
, que no lleva a cabo ninguna comprobación de límites en su entrada. Asimismo, buf
se asigna, pero no se libera, por lo que produce una fuga de memoria.Example 1
podría detectarse fácilmente a través de una auditoría de código fuente de la implementación del método nativo. Es posible que esta operación no sea factible o posible en función de la disponibilidad del código fuente y la forma en que se ha creado el proyecto, aunque, en la mayoría de los casos, este método es suficiente. Sin embargo, la capacidad para compartir objetos entre los entornos administrado y nativo amplía el riesgo potencial de que se produzcan casos más insidiosos cuando una administración inadecuada de los datos en el código administrado puede provocar vulnerabilidades inesperadas u operaciones que no son seguras en el código nativo, lo que daña las estructuras de datos del código administrado.
var params:Object = LoaderInfo(this.root.loaderInfo).parameters;
var ctl:String = String(params["ctl"]);
var ao:Worker;
if (ctl == "Add) {
ao = new AddCommand();
} else if (ctl == "Modify") {
ao = new ModifyCommand();
} else {
throw new UnknownActionError();
}
ao.doAction(params);
var params:Object = LoaderInfo(this.root.loaderInfo).parameters;
var ctl:String = String(params["ctl"]);
var ao:Worker;
var cmdClass:Class = getDefinitionByName(ctl + "Command") as Class;
ao = new cmdClass();
ao.doAction(params);
if/else
se han eliminado por completo y ahora es posible agregar nuevos tipos de comando sin modificar el distribuidor de comandos.Worker
. Si el distribuidor de comandos sigue siendo responsable del control de acceso, entonces cada vez que los programadores creen una nueva clase que implemente la interfaz Worker
, no deben olvidar modificar el código de control de acceso del distribuidor. Si no pueden modificar el código de control de acceso, algunas clases Worker
no tendrán ningún control de acceso.Worker
sea responsable de realizar la comprobación de control de acceso. A continuación se muestra un ejemplo del código refactorizado:
var params:Object = LoaderInfo(this.root.loaderInfo).parameters;
var ctl:String = String(params["ctl"]);
var ao:Worker;
var cmdClass:Class = getDefinitionByName(ctl + "Command") as Class;
ao = new cmdClass();
ao.checkAccessControl(params);
ao.doAction(params);
Continuation
podría permitir a los atacantes crear rutas de flujo de control inesperadas a través de la aplicación, lo que podría eludir los controles de seguridad.continuationMethod
, que determina el nombre del método al que se llamará al recibir una respuesta.
public Object startRequest() {
Continuation con = new Continuation(40);
Map<String,String> params = ApexPages.currentPage().getParameters();
if (params.containsKey('contMethod')) {
con.continuationMethod = params.get('contMethod');
} else {
con.continuationMethod = 'processResponse';
}
HttpRequest req = new HttpRequest();
req.setMethod('GET');
req.setEndpoint(LONG_RUNNING_SERVICE_URL);
this.requestLabel = con.addHttpRequest(req);
return con;
}
continuationMethod
se establezca mediante parámetros de solicitud de tiempo de ejecución, lo que permite a los atacantes llamar a cualquier función que coincida con el nombre.
...
Dim ctl As String
Dim ao As New Worker()
ctl = Request.Form("ctl")
If (String.Compare(ctl,"Add") = 0) Then
ao.DoAddCommand(Request)
Else If (String.Compare(ctl,"Modify") = 0) Then
ao.DoModifyCommand(Request)
Else
App.EventLog("No Action Found", 4)
End If
...
...
Dim ctl As String
Dim ao As New Worker()
ctl = Request.Form("ctl")
CallByName(ao, ctl, vbMethod, Request)
...
if/else
se han eliminado por completo y ahora es posible agregar nuevos tipos de comando sin modificar el distribuidor de comandos.Worker
. Si el distribuidor de comandos se encarga del control de acceso, cada vez que los programadores creen un número método en la clase Worker
, deben acordarse de modificar la lógica de control de acceso del distribuidor. Si esta lógica de control de acceso se queda obsoleta, algunos métodos Worker
no tendrán ningún control de acceso.Worker
sea responsable de realizar la comprobación de control de acceso. A continuación se muestra un ejemplo del código refactorizado:
...
Dim ctl As String
Dim ao As New Worker()
ctl = Request.Form("ctl")
If (ao.checkAccessControl(ctl,Request) = True) Then
CallByName(ao, "Do" & ctl & "Command", vbMethod, Request)
End If
...
clazz
.
char* ctl = getenv("ctl");
...
jmethodID mid = GetMethodID(clazz, ctl, sig);
status = CallIntMethod(env, clazz, mid, JAVA_ARGS);
...
Ejemplo 2: Similar al ejemplo anterior, la aplicación utiliza el paquete
...
func beforeExampleCallback(scope *Scope){
input := os.Args[1]
if input{
scope.CallMethod(input)
}
}
...
reflect
para recuperar el nombre de una función a la que se va a llamar desde un argumento de la línea de comandos.
...
input := os.Args[1]
var worker WokerType
reflect.ValueOf(&worker).MethodByName(input).Call([]reflect.Value{})
...
String ctl = request.getParameter("ctl");
Worker ao = null;
if (ctl.equals("Add")) {
ao = new AddCommand();
} else if (ctl.equals("Modify")) {
ao = new ModifyCommand();
} else {
throw new UnknownActionError();
}
ao.doAction(request);
String ctl = request.getParameter("ctl");
Class cmdClass = Class.forName(ctl + "Command");
Worker ao = (Worker) cmdClass.newInstance();
ao.doAction(request);
if/else
se han eliminado por completo y ahora es posible agregar nuevos tipos de comando sin modificar el distribuidor de comandos.Worker
. Si el distribuidor de comandos sigue siendo responsable del control de acceso, entonces cada vez que los programadores creen una nueva clase que implemente la interfaz Worker
, no deben olvidar modificar el código de control de acceso del distribuidor. Si no pueden modificar el código de control de acceso, algunas clases Worker
no tendrán ningún control de acceso.Worker
sea responsable de realizar la comprobación de control de acceso. A continuación se muestra un ejemplo del código refactorizado:
String ctl = request.getParameter("ctl");
Class cmdClass = Class.forName(ctl + "Command");
Worker ao = (Worker) cmdClass.newInstance();
ao.checkAccessControl(request);
ao.doAction(request);
Worker
; se puede llamar al constructor predeterminado de cualquier objeto del sistema. Si el objeto no implementa la interfaz de Worker
, se generará una ClassCastException
antes de la asignación a ao
. Sin embargo, si el constructor realiza operaciones que trabajan a favor del usuario malintencionado, el daño ya estará hecho. Aunque este escenario es relativamente benigno en aplicaciones sencillas, en las aplicaciones de mayor tamaño en las que la complejidad crece exponencialmente, es razonable creer que un usuario malintencionado podría encontrar un constructor para aprovecharlo como parte de un ataque.performSelector
, lo que podría permitirles crear rutas de flujo de control inesperadas a través de la aplicación, omitiendo potencialmente las comprobaciones de seguridad.UIApplicationDelegate
.
...
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
NSString *query = [url query];
NSString *pathExt = [url pathExtension];
[self performSelector:NSSelectorFromString(pathExt) withObject:query];
...
$ctl = $_GET["ctl"];
$ao = null;
if (ctl->equals("Add")) {
$ao = new AddCommand();
} else if ($ctl.equals("Modify")) {
$ao = new ModifyCommand();
} else {
throw new UnknownActionError();
}
$ao->doAction(request);
$ctl = $_GET["ctl"];
$args = $_GET["args"];
$cmdClass = new ReflectionClass(ctl . "Command");
$ao = $cmdClass->newInstance($args);
$ao->doAction(request);
if/else
se han eliminado por completo y ahora es posible agregar nuevos tipos de comando sin modificar el distribuidor de comandos.Worker
. Si el distribuidor de comandos sigue siendo responsable del control de acceso, entonces cada vez que los programadores creen una nueva clase que implemente la interfaz Worker
, no deben olvidar modificar el código de control de acceso del distribuidor. Si no pueden modificar el código de control de acceso, algunas clases Worker
no tendrán ningún control de acceso.Worker
sea responsable de realizar la comprobación de control de acceso. A continuación se muestra un ejemplo del código refactorizado:
$ctl = $_GET["ctl"];
$args = $_GET["args"];
$cmdClass = new ReflectionClass(ctl . "Command");
$ao = $cmdClass->newInstance($args);
$ao->checkAccessControl(request);
ao->doAction(request);
Worker
; se puede llamar al constructor predeterminado de cualquier objeto del sistema. Si el objeto no implementa la interfaz de Worker
, se generará una ClassCastException
antes de la asignación a $ao
. Sin embargo, si el constructor realiza operaciones que trabajan a favor del usuario malintencionado, el daño ya estará hecho. Aunque este escenario es relativamente benigno en aplicaciones sencillas, en las aplicaciones de mayor tamaño en las que la complejidad crece exponencialmente, es razonable creer que un usuario malintencionado podría encontrar un constructor para aprovecharlo como parte de un ataque.
ctl = req['ctl']
if ctl=='add'
addCommand(req)
elsif ctl=='modify'
modifyCommand(req)
else
raise UnknownCommandError.new
end
ctl = req['ctl']
ctl << "Command"
send(ctl)
if/else
se han eliminado por completo y ahora es posible agregar nuevos tipos de comando sin modificar el distribuidor de comandos.define_method()
o llamarlos mediante el reemplazo de missing_method()
. Auditar y realizar un seguimiento de estos métodos y de cómo se utiliza el código de control de acceso con ellos resulta muy difícil, y si consideramos que también depende de qué código de biblioteca se cargue, realizar esta tarea correctamente puede convertirse en una misión imposible.
def exec(ctl: String) = Action { request =>
val cmdClass = Platform.getClassForName(ctl + "Command")
Worker ao = (Worker) cmdClass.newInstance()
ao.doAction(request)
...
}
if/else
se han eliminado por completo y ahora es posible agregar nuevos tipos de comando sin modificar el distribuidor de comandos.Worker
. Si el distribuidor de comandos sigue siendo responsable del control de acceso, entonces cada vez que los programadores creen una nueva clase que implemente la interfaz Worker
, no deben olvidar modificar el código de control de acceso del distribuidor. Si no pueden modificar el código de control de acceso, algunas clases Worker
no tendrán ningún control de acceso.Worker
sea responsable de realizar la comprobación de control de acceso. A continuación se muestra un ejemplo del código refactorizado:
def exec(ctl: String) = Action { request =>
val cmdClass = Platform.getClassForName(ctl + "Command")
Worker ao = (Worker) cmdClass.newInstance()
ao.checkAccessControl(request);
ao.doAction(request)
...
}
Worker
; se puede llamar al constructor predeterminado de cualquier objeto del sistema. Si el objeto no implementa la interfaz de Worker
, se generará una ClassCastException
antes de la asignación a ao
. Sin embargo, si el constructor realiza operaciones que trabajan a favor del usuario malintencionado, el daño ya estará hecho. Aunque este escenario es relativamente benigno en aplicaciones sencillas, en las aplicaciones de mayor tamaño en las que la complejidad crece exponencialmente, es razonable creer que un usuario malintencionado podría encontrar un constructor para aprovecharlo como parte de un ataque.performSelector
, lo que podría permitirles crear rutas de flujo de control inesperadas a través de la aplicación, omitiendo potencialmente las comprobaciones de seguridad.UIApplicationDelegate
.
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
...
let query = url.query
let pathExt = url.pathExtension
let selector = NSSelectorFromString(pathExt!)
performSelector(selector, withObject:query)
...
}
...
Dim ctl As String
Dim ao As new Worker
ctl = Request.Form("ctl")
If String.Compare(ctl,"Add") = 0 Then
ao.DoAddCommand Request
Else If String.Compare(ctl,"Modify") = 0 Then
ao.DoModifyCommand Request
Else
App.EventLog "No Action Found", 4
End If
...
...
Dim ctl As String
Dim ao As Worker
ctl = Request.Form("ctl")
CallByName ao, ctl, vbMethod, Request
...
if/else
se han eliminado por completo y ahora es posible agregar nuevos tipos de comando sin modificar el distribuidor de comandos.Worker
. Si el distribuidor de comandos sigue siendo responsable del control de acceso, siempre que los programadores creen un nuevo método dentro de la clase Worker
, deberán acordarse de modificar el código de control de acceso del distribuidor. Si no pueden modificar el código de control de acceso, algunos métodos de Worker
no tendrán ningún control de acceso.Worker
sea responsable de realizar la comprobación de control de acceso. A continuación se muestra un ejemplo del código refactorizado:
...
Dim ctl As String
Dim ao As Worker
ctl = Request.Form("ctl")
If ao.checkAccessControl(ctl,Request) = True Then
CallByName ao, "Do" & ctl & "Command", vbMethod, Request
End If
...
HttpRequest
proporciona acceso programático a las variables procedentes de las colecciones QueryString
, Form
, Cookies
o ServerVariables
en la forma de un acceso de matriz (p. ej. Request["myParam"]
). Cuando existe más de una variable con el mismo nombre, .NET Framework devuelve el valor de la variable que aparece primero cuando se buscan las colecciones en el siguiente orden: QueryString
, Form
, Cookies
y ServerVariables
. Como QueryString
está primero en el orden de búsqueda, los parámetros QueryString
pueden sustituir los valores de variables de servidor, cookies y formularios. Del mismo modo, los valores de formularios pueden reemplazar las variables de las colecciones Cookies
y ServerVariables
, y las variables de la colección Cookies
pueden reemplazar las de ServerVariables
.
...
String toAddress = Request["email"]; //Expects cookie value
Double balance = GetBalance(userID);
SendAccountBalance(toAddress, balance);
...
Example 1
se ejecuta al visitar http://www.example.com/GetBalance.aspx
. Si un atacante puede hacer que un usuario autenticado haga clic en un enlace que solicite http://www.example.com/GetBalance.aspx?email=evil%40evil.com
, se enviará un mensaje de correo electrónico con el balance de cuentas del usuario a evil@evil.com
.HttpRequest
proporciona acceso programático a las variables procedentes de las colecciones QueryString
, Form
, Cookies
o ServerVariables
en la forma de un acceso de matriz (p. ej. Request["myParam"]
). Cuando existe más de una variable con el mismo nombre, .NET Framework devuelve el valor de la variable que aparece primero cuando se buscan las colecciones en el siguiente orden: QueryString
, Form
, Cookies
y ServerVariables
. Como QueryString
está primero en el orden de búsqueda, los parámetros QueryString
pueden sustituir los valores de variables de servidor, cookies y formularios. Del mismo modo, los valores de formularios pueden reemplazar las variables de las colecciones Cookies
y ServerVariables
, y las variables de la colección Cookies
pueden reemplazar las de ServerVariables
.www.example.com
antes de proporcionar contenido.
...
if (Request["HTTP_REFERER"].StartsWith("http://www.example.com"))
ServeContent();
else
Response.Redirect("http://www.example.com/");
...
Example 1
se ejecuta al visitar http://www.example.com/ProtectedImages.aspx
. Si un atacante realiza una solicitud directa a la URL, no se establecerá el encabezado de referencia correspondiente y la solicitud no se cumplirá. No obstante, si el atacante envía un parámetro HTTP_REFERER
artificial con el valor requerido, como http://www.example.com/ProtectedImages.aspx?HTTP_REFERER=http%3a%2f%2fwww.example.com
, la búsqueda devolverá el valor de QueryString
en lugar de ServerVariables
y se realizará la comprobación.
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
...
DATA(ixml) = cl_ixml=>create( ).
DATA(stream_factory) = ixml->create_stream_factory( ).
istream = stream_factory->create_istream_string(
`<?xml version="1.0" encoding="UTF-8"?> ` &&
`<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> ` &&
`<stockCheck>&xxe;</stockCheck>` ).
istream->set_dtd_restriction( level = 0 ).
DATA(document) = ixml->create_document( ).
parser = ixml->create_parser(
stream_factory = stream_factory
istream = istream
document = document ).
parser->set_validating( mode = `0` ).
DATA(rc) = parser->parse( ).
...
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/winnt/win.ini" >]><foo>&xxe;</foo>
- (void) parseSomeXML: (NSString *) rawXml {
BOOL success;
NSData *rawXmlConvToData = [rawXml dataUsingEncoding:NSUTF8StringEncoding];
NSXMLParser *myParser = [[NSXMLParser alloc] initWithData:rawXmlConvToData];
[myParser setShouldResolveExternalEntities:YES];
[myParser setDelegate:self];
}
rawXml
de tal forma que el código XML sea similar al siguiente:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/boot.ini" >]><foo>&xxe;</foo>
boot.ini
.
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///dev/random" >]><foo>&xxe;</foo>
String xml = "...";
...
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
DefaultHandler handler = new DefaultHandler() {
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
System.out.println(new String(ch, start, length));
}
};
saxParser.parse(new InputSource(new StringReader(xml)), handler);
} catch (Exception e) {
e.printStackTrace();
}
...
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///dev/random" >]><foo>&xxe;</foo>
- (void) parseSomeXML: (NSString *) rawXml {
BOOL success;
NSData *rawXmlConvToData = [rawXml dataUsingEncoding:NSUTF8StringEncoding];
NSXMLParser *myParser = [[NSXMLParser alloc] initWithData:rawXmlConvToData];
[myParser setShouldResolveExternalEntities:YES];
[myParser setDelegate:self];
}
rawXml
de tal forma que el código XML sea similar al siguiente:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/boot.ini" >]><foo>&xxe;</foo>
boot.ini
.
...
<?php
$goodXML = $_GET["key"];
$doc = simplexml_load_string($goodXml);
echo $doc->testing;
?>
...
Example 2
:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/boot.ini" >]><foo>&xxe;</foo>
boot.ini
del sistema. El atacante podría utilizar los elementos XML que se devuelven al cliente para extraer datos u obtener información sobre la existencia de recursos de red.
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///dev/random" >]><foo>&xxe;</foo>
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]><foo>&xxe;</foo>
/etc/passwd
y lo incluirá en el documento.
def readFile() = Action { request =>
val xml = request.cookies.get("doc")
val doc = XMLLoader.loadString(xml)
...
}
func parseXML(xml: String) {
parser = NSXMLParser(data: rawXml.dataUsingEncoding(NSUTF8StringEncoding)!)
parser.delegate = self
parser.shouldResolveExternalEntities = true
parser.parse()
}
rawXml
de tal forma que el código XML sea similar al siguiente:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/boot.ini" >]><foo>&xxe;</foo>
boot.ini
.shoes
en el siguiente documento XML:
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
por shoes</item><price>1.00</price><item>shoes
. El XML nuevo tendría este aspecto:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
anula el valor de la primera etiqueta <price>
. Esto permite que el atacante compre un par de zapatos de 100 $ a 1 $.shoes
en el siguiente documento XML.
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
por shoes</item><price>1.00</price><item>shoes
. El nuevo documento XML sería:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
anula el valor de la primera etiqueta <price>
. Esto permite que el atacante compre un par de zapatos de 100 $ a 1 $.shoes
en el siguiente documento XML.
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
por shoes</item><price>1.00</price><item>shoes
. El nuevo documento XML sería:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
anula el valor de la primera etiqueta <price>
. Esto permite que el atacante compre un par de zapatos de 100 $ a 1 $.shoes
en el siguiente documento XML:
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
por shoes</item><price>1.00</price><item>shoes
. El XML nuevo tendría este aspecto:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
anula el valor de la primera etiqueta <price>
. Esto permite que el atacante compre un par de zapatos de $ 100 a $ 1.shoes
en el siguiente documento XML.
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
por shoes</item><price>1.00</price><item>shoes
. El nuevo documento XML sería:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
anula el valor de la primera etiqueta <price>
. Esto permite que el atacante compre un par de zapatos de 100 $ a 1 $.shoes
en el siguiente documento XML:
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
por shoes</item><price>1.00</price><item>shoes
. El nuevo documento XML sería:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
shoes
en el siguiente documento XML.
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
por shoes</item><price>1.00</price><item>shoes
. El nuevo documento XML sería:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
anula el valor de la primera etiqueta <price>
. Esto permite que el atacante compre un par de zapatos de 100 $ a 1 $.shoes
en el siguiente documento XML.
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
por shoes</item><price>1.00</price><item>shoes
. El nuevo documento XML sería:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
anula el valor de la primera etiqueta <price>
. Esto permite que el atacante compre un par de zapatos de 100 $ a 1 $.
...
<?php
$goodXML = $_GET["key"];
$doc = simplexml_load_string($goodXml);
echo $doc->testing;
?>
...
Example 2
:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/boot.ini" >]><foo>&xxe;</foo>
boot.ini
del sistema. El atacante podría utilizar los elementos XML que se devuelven al cliente para extraer datos u obtener información sobre la existencia de recursos de red.shoes
en el siguiente documento XML.
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
por shoes</item><price>1.00</price><item>shoes
. El nuevo documento XML sería:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
anula el valor de la primera etiqueta <price>
. Esto permite que el atacante compre un par de zapatos de 100 $ a 1 $.shoes
en el siguiente documento XML.
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
por shoes</item><price>1.00</price><item>shoes
. El nuevo documento XML sería:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
anula el valor de la primera etiqueta <price>
. Esto permite que el atacante compre un par de zapatos de 100 $ a 1 $.shoes
en el siguiente documento XML.
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
por shoes</item><price>1.00</price><item>shoes
. El nuevo documento XML sería:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
anula el valor de la primera etiqueta <price>
. Esto permite que el atacante compre un par de zapatos de 100 $ a 1 $.shoes
en el siguiente documento XML.
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
por shoes</item><price>1.00</price><item>shoes
. El nuevo documento XML sería:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
anula el valor de la primera etiqueta <price>
. Esto permite que el atacante compre un par de zapatos de 100 $ a 1 $.a:t
desde el siguiente documento Open XML.
<a:t>YoY results: up 10%</a:t>