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.
validate()
que não consegue chamar super.validate()
.validate()
de um formulário para verificar o conteúdo das propriedades do formulário em relação às restrições especificadas no formulário de validação associado. Isso significa que as seguintes classes têm um método validate()
que faz parte da estrutura de validação:
ValidatorForm
ValidatorActionForm
DynaValidatorForm
DynaValidatorActionForm
validate()
, você deverá chamar super.validate()
na sua implementação validate()
. Em caso negativo, a Estrutura de Validação não poderá verificar o conteúdo do formulário com base em um formulário de validação. Em outras palavras, a estrutura de validação será desabilitada para o formulário especificado.
ValidatorForm
ValidatorActionForm
DynaValidatorActionForm
DynaValidaorForm
validate()
nessas classes.
ActionForm
DynaActionForm
ActionForm
para mais de uma finalidade. Em situações como essa, alguns campos podem não ser utilizados em certos mapeamentos de ações. É fundamental que campos não utilizados também sejam validados. De preferência, esses campos não utilizados devem ser restritos de forma a poderem ser apenas vazios ou não definidos. Se os campos não utilizados não forem validados, a lógica de negócios compartilhada em uma ação pode permitir que os invasores se esquivem das verificações de validação que são realizadas para outros usos do formulário.form-bean
para mapear formulários HTML para ações. Se o elemento <action-mappings>
do arquivo de configuração do Struts não contém uma entrada que corresponda a um formulário de ação relevante definido por meio de uma tag <form-bean>
, a lógica do aplicativo pode não estar atualizada.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()
do formulário.
<action path="/download"
type="com.website.d2.action.DownloadAction"
name="downloadForm"
scope="request"
input=".download"
validate="false">
</action>
ActionForm
. Uma indicação de que a lógica de validação não está sendo mantida adequadamente são as inconsistências entre o formulário de ação e o formulário de validação.
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
e 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
. A presença do terceiro campo sugere que a DateRangeForm
foi modificada sem levar em consideração a validação.
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
usa Handlebars
como o mecanismo de modelo, e os dados controlados pelo usuário são concatenados no modelo compilado, o que permite que invasores executem JavaScript arbitrário.Echo
. A classe declara um método nativo que usa C para ecoar comandos inseridos no console de volta para o usuário.
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" //a classe java doExample 1
compilada com javah
#include <stdio.h>
JNIEXPORT void JNICALL
Java_Echo_runEcho(JNIEnv *env, jobject obj)
{
char buf[64];
gets(buf);
printf(buf);
}
gets()
, que não realiza nenhuma verificação de limites em sua entrada.Example 1
pode ser facilmente detectada por meio de uma auditoria de código-fonte da implementação do método nativo. Isso pode não ser prático ou possível, dependendo da disponibilidade do código-fonte C e de como o projeto está estruturado, mas, em muitos casos, pode ser suficiente. No entanto, a capacidade de compartilhar objetos entre métodos Java e nativos expande o possível risco de casos muito mais traiçoeiros nos quais a manipulação imprópria de dados pode fazer com que vulnerabilidades inesperadas ou operações não seguras no código nativo corrompam estruturas de dados em Java.Redirect
. A classe declara um método JavaScript nativo, que usa JavaScript para alterar o local do 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
. A classe declara um método nativo que usa C para ecoar comandos inseridos no console de volta para o usuário.
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 não realiza nenhuma verificação de limites em sua entrada. Além disso, buf
é alocado, mas não é liberado e, portanto, é um vazamento de memória.Example 1
pode ser facilmente detectada por meio de uma auditoria de código-fonte da implementação do método nativo. Isso pode não ser prático ou possível, dependendo da disponibilidade do código-fonte e de como o projeto está estruturado, mas, em muitos casos, pode ser suficiente. No entanto, a capacidade de compartilhar objetos entre os ambientes gerenciados e nativos aumenta o possível risco de casos muito mais traiçoeiros em que a manipulação imprópria de dados pode provocar vulnerabilidades inesperadas ou operações não seguras no código nativo, corrompendo estruturas de dados no código gerenciado.
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
foram totalmente eliminados e agora é possível adicionar novos tipos de comando sem modificar o expedidor de comandos.Worker
. Se o expedidor de comandos ainda for responsável pelo controle de acesso, sempre que os programadores criarem uma nova classe que implementa a interface Worker
, eles deverão se lembrar de modificar o código de controle de acesso do expedidor. Se o código de controle de acesso não for modificado, algumas classes Worker
não terão controle de acesso.Worker
responsável pela execução da verificação de controle de acesso. Veja a seguir um exemplo do código novamente refatorado:
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
pode permitir que invasores criem caminhos de fluxo de controle inesperados através do aplicativo, potencialmente ignorando as verificações de segurança.continuationMethod
, que determina o nome do método a ser chamado ao receber uma resposta.
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
seja definida por parâmetros de solicitação de tempo de execução, o que permite que invasores chamem qualquer função que corresponda ao nome.
...
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
foram totalmente eliminados e agora é possível adicionar novos tipos de comando sem modificar o expedidor de comandos.Worker
. Se o dispatcher de comandos for responsável pelo controle de acesso, sempre que os programadores criarem um novo método na classe Worker
, eles deverão modificar a lógica de controle de acesso do dispatcher. Se essa lógica de controle de acesso se tornar obsoleta, alguns métodos Worker
não terão controle de acesso.Worker
responsável pela execução da verificação de controle de acesso. Veja a seguir um exemplo do código novamente refatorado:
...
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);
...
Exemplo 2: De forma semelhante no exemplo anterior, o aplicativo usa o pacote
...
func beforeExampleCallback(scope *Scope){
input := os.Args[1]
if input{
scope.CallMethod(input)
}
}
...
reflect
para obter o nome de uma função a ser chamada de um argumento da linha de comando.
...
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
foram totalmente eliminados e agora é possível adicionar novos tipos de comando sem modificar o expedidor de comandos.Worker
. Se o expedidor de comandos ainda for responsável pelo controle de acesso, sempre que os programadores criarem uma nova classe que implementa a interface Worker
, eles deverão se lembrar de modificar o código de controle de acesso do expedidor. Se o código de controle de acesso não for modificado, algumas classes Worker
não terão controle de acesso.Worker
responsável pela execução da verificação de controle de acesso. Veja a seguir um exemplo do código novamente refatorado:
String ctl = request.getParameter("ctl");
Class cmdClass = Class.forName(ctl + "Command");
Worker ao = (Worker) cmdClass.newInstance();
ao.checkAccessControl(request);
ao.doAction(request);
Worker
; o construtor padrão para qualquer objeto no sistema pode ser invocado. Se o objeto não implementar a interface Worker
, um ClassCastException
será lançado antes da atribuição a ao
, mas, se o construtor realizar operações que funcionarem a favor do invasor, os danos já terão sido feitos. Embora esse cenário seja relativamente favorável em aplicativos simples, em aplicativos maiores, nos quais a complexidade cresce exponencialmente, não é absurdo considerar que um invasor possa encontrar um construtor a ser otimizado como parte de um ataque.performSelector
, o que pode permitir que eles criem caminhos inesperados de controle de fluxo por meio do aplicativo, potencialmente ignorando as verificações de segurança.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
foram totalmente eliminados e agora é possível adicionar novos tipos de comando sem modificar o expedidor de comandos.Worker
. Se o expedidor de comandos ainda for responsável pelo controle de acesso, sempre que os programadores criarem uma nova classe que implementa a interface Worker
, eles deverão se lembrar de modificar o código de controle de acesso do expedidor. Se o código de controle de acesso não for modificado, algumas classes Worker
não terão controle de acesso.Worker
responsável pela execução da verificação de controle de acesso. Veja a seguir um exemplo do código novamente refatorado:
$ctl = $_GET["ctl"];
$args = $_GET["args"];
$cmdClass = new ReflectionClass(ctl . "Command");
$ao = $cmdClass->newInstance($args);
$ao->checkAccessControl(request);
ao->doAction(request);
Worker
; o construtor padrão para qualquer objeto no sistema pode ser invocado. Se o objeto não implementar a interface Worker
, um ClassCastException
será lançado antes da atribuição a $ao
, mas, se o construtor realizar operações que funcionarem a favor do invasor, os danos já terão sido feitos. Embora esse cenário seja relativamente favorável em aplicativos simples, em aplicativos maiores, nos quais a complexidade cresce exponencialmente, não é absurdo considerar que um invasor possa encontrar um construtor a ser otimizado como parte de um 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
foram totalmente eliminados e agora é possível adicionar novos tipos de comando sem modificar o expedidor de comandos.define_method()
, ou pode ser chamá-los ao substituir missing_method()
. Fazer a auditoria e o rastreio desses métodos assim como de que maneira o código de controle é utilizado com eles é muito difícil e, ao considerar essa situação, ela também dependerá de quais outros códigos de biblioteca estão carregados; isso fará com que essa tarefa seja quase impossível de realizar corretamente.
def exec(ctl: String) = Action { request =>
val cmdClass = Platform.getClassForName(ctl + "Command")
Worker ao = (Worker) cmdClass.newInstance()
ao.doAction(request)
...
}
if/else
foram totalmente eliminados e agora é possível adicionar novos tipos de comando sem modificar o expedidor de comandos.Worker
. Se o expedidor de comandos ainda for responsável pelo controle de acesso, sempre que os programadores criarem uma nova classe que implementa a interface Worker
, eles deverão se lembrar de modificar o código de controle de acesso do expedidor. Se o código de controle de acesso não for modificado, algumas classes Worker
não terão controle de acesso.Worker
responsável pela execução da verificação de controle de acesso. Veja a seguir um exemplo do código novamente refatorado:
def exec(ctl: String) = Action { request =>
val cmdClass = Platform.getClassForName(ctl + "Command")
Worker ao = (Worker) cmdClass.newInstance()
ao.checkAccessControl(request);
ao.doAction(request)
...
}
Worker
; o construtor padrão para qualquer objeto no sistema pode ser invocado. Se o objeto não implementar a interface Worker
, um ClassCastException
será lançado antes da atribuição a ao
, mas, se o construtor realizar operações que funcionarem a favor do invasor, os danos já terão sido feitos. Embora esse cenário seja relativamente favorável em aplicativos simples, em aplicativos maiores, nos quais a complexidade cresce exponencialmente, não é absurdo considerar que um invasor possa encontrar um construtor a ser otimizado como parte de um ataque.performSelector
, o que pode permitir que eles criem caminhos inesperados de controle de fluxo por meio do aplicativo, potencialmente ignorando as verificações de segurança.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
foram totalmente eliminados e agora é possível adicionar novos tipos de comando sem modificar o expedidor de comandos.Worker
. Se o dispatcher de comandos ainda for responsável pelo controle de acesso, sempre que os programadores criarem um novo método na classe Worker
, eles deverão se lembrar de modificar o código de controle de acesso do dispatcher. Se eles não conseguirem modificar o código de controle de acesso, alguns métodos Worker
não terão nenhum controle de acesso.Worker
responsável pela execução da verificação de controle de acesso. Veja a seguir um exemplo do código novamente refatorado:
...
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
fornece acesso programático a variáveis das coleções QueryString
, Form
, Cookies
ou ServerVariables
sob a forma de um acesso de array (por exemplo, Request["myParam"]
). Quando há mais de uma variável com o mesmo nome, o .NET Framework retorna o valor da variável que aparece primeiro quando as coleções são pesquisadas, na ordem seguinte: QueryString
, Form
, Cookies
e depois ServerVariables
. Como QueryString
vem em primeiro lugar na ordem de pesquisa, é possível que parâmetros QueryString
substituam valores de formulários, cookies e variáveis de servidor. Da mesma forma, valores de formulário podem substituir variáveis nas coleções Cookies
e ServerVariables
, enquanto variáveis da coleção Cookies
podem substituir as de ServerVariables
.
...
String toAddress = Request["email"]; //Expects cookie value
Double balance = GetBalance(userID);
SendAccountBalance(toAddress, balance);
...
Example 1
seja executado durante uma visita a http://www.example.com/GetBalance.aspx
. Se um invasor puder fazer com que um usuário autenticado clique em um link que solicita http://www.example.com/GetBalance.aspx?email=evil%40evil.com
, um e-mail com o saldo da conta desse usuário será enviado para evil@evil.com
.HttpRequest
fornece acesso programático a variáveis das coleções QueryString
, Form
, Cookies
ou ServerVariables
sob a forma de um acesso de array (por exemplo, Request["myParam"]
). Quando há mais de uma variável com o mesmo nome, o .NET Framework retorna o valor da variável que aparece primeiro quando as coleções são pesquisadas, na ordem seguinte: QueryString
, Form
, Cookies
e depois ServerVariables
. Como QueryString
vem em primeiro lugar na ordem de pesquisa, é possível que parâmetros QueryString
substituam valores de formulários, cookies e variáveis de servidor. Da mesma forma, valores de formulário podem substituir variáveis nas coleções Cookies
e ServerVariables
, enquanto variáveis da coleção Cookies
podem substituir as de ServerVariables
.www.example.com
antes de apresentar o conteúdo.
...
if (Request["HTTP_REFERER"].StartsWith("http://www.example.com"))
ServeContent();
else
Response.Redirect("http://www.example.com/");
...
Example 1
seja executado durante uma visita a http://www.example.com/ProtectedImages.aspx
. Se um invasor realizar uma solicitação direta para a URL, o cabeçalho de referência adequado não será definido e a solicitação falhará. No entanto, se o invasor enviar um parâmetro HTTP_REFERER
artificial com o valor necessário, como http://www.example.com/ProtectedImages.aspx?HTTP_REFERER=http%3a%2f%2fwww.example.com
, a pesquisa retornará esse valor de QueryString
em vez de ServerVariables
, e a verificação será bem-sucedida.
<?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 o XML tenha a seguinte aparência:
<?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 o XML tenha a seguinte aparência:
<?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
do sistema. O invasor pode usar elementos XML que são devolvidos ao cliente para roubar dados ou obter informações sobre a existência de recursos de rede.
<?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
e o incluirá no 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 o XML tenha a seguinte aparência:
<?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
no seguinte XML:
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
com por shoes</item><price>1.00</price><item>shoes
. O novo XML teria a seguinte aparência:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
substitui o valor da primeira tag <price>
. Isso permite que o invasor compre um par de sapatos de $100 por apenas $1.shoes
no seguinte XML.
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
com por shoes</item><price>1.00</price><item>shoes
. O novo XML teria a seguinte aparência:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
substitui o valor da primeira tag <price>
. Isso permite que o invasor compre um par de sapatos de $100 por apenas $1.shoes
no seguinte XML.
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
com por shoes</item><price>1.00</price><item>shoes
. O novo XML teria a seguinte aparência:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
substitui o valor da primeira tag <price>
. Isso permite que o invasor compre um par de sapatos de $100 por apenas $1.shoes
no seguinte XML:
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
com por shoes</item><price>1.00</price><item>shoes
. O novo XML teria a seguinte aparência:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
. Isso permite que o invasor compre um par de sapatos de $100 por apenas $1.shoes
no seguinte XML.
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
com por shoes</item><price>1.00</price><item>shoes
. O novo XML teria a seguinte aparência:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
substitui o valor da primeira tag <price>
. Isso permite que o invasor compre um par de sapatos de $100 por apenas $1.shoes
no XML a seguir.
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
com por shoes</item><price>1.00</price><item>shoes
. O novo XML teria a seguinte aparência:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
shoes
no seguinte XML.
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
com por shoes</item><price>1.00</price><item>shoes
. O novo XML teria a seguinte aparência:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
substitui o valor da primeira tag <price>
. Isso permite que o invasor compre um par de sapatos de $100 por apenas $1.shoes
no seguinte XML.
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
com por shoes</item><price>1.00</price><item>shoes
. O novo XML teria a seguinte aparência:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
substitui o valor da primeira marca <price>
. Isso permite que o invasor compre um par de sapatos de $100 por apenas $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
do sistema. O invasor pode usar elementos XML que são devolvidos ao cliente para roubar dados ou obter informações sobre a existência de recursos de rede.shoes
no seguinte XML.
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
com por shoes</item><price>1.00</price><item>shoes
. O novo XML teria a seguinte aparência:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
substitui o valor da primeira tag <price>
. Isso permite que o invasor compre um par de sapatos de $100 por apenas $1.shoes
no seguinte XML.
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
com por shoes</item><price>1.00</price><item>shoes
. O novo XML teria a seguinte aparência:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
substitui o valor da primeira tag <price>
. Isso permite que o invasor compre um par de sapatos de $100 por apenas $1.shoes
no seguinte XML.
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
com por shoes</item><price>1.00</price><item>shoes
. O novo XML teria a seguinte aparência:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
substitui o valor da primeira marca <price>
.Isso permite que o invasor compre um par de sapatos de $100 por apenas $1.shoes
no XML a seguir.
<order>
<price>100.00</price>
<item>shoes</item>
</order>
shoes
com por shoes</item><price>1.00</price><item>shoes
. O novo XML teria a seguinte aparência:
<order>
<price>100.00</price>
<item>shoes</item><price>1.00</price><item>shoes</item>
</order>
<price>
substitui o valor da primeira tag <price>
. Isso permite que o invasor compre um par de sapatos de $100 por apenas $1.a:t
do seguinte documento Open XML.
<a:t>YoY results: up 10%</a:t>