permissions := strconv.Atoi(os.Getenv("filePermissions"));
fMode := os.FileMode(permissions)
os.chmod(filePath, fMode);
...
String permissionMask = System.getProperty("defaultFileMask");
Path filePath = userFile.toPath();
...
Set<PosixFilePermission> perms = PosixFilePermissions.fromString(permissionMask);
Files.setPosixFilePermissions(filePath, perms);
...
$rName = $_GET['publicReport'];
chmod("/home/". authenticateUser . "/public_html/" . rName,"0755");
...
publicReport
, como "../../localuser/public_html/.htpasswd
", o aplicativo tornará o arquivo especificado como legível para o invasor.
...
$mask = $CONFIG_TXT['perms'];
chmod($filename,$mask);
...
permissions = os.getenv("filePermissions");
os.chmod(filePath, permissions);
...
...
rName = req['publicReport']
File.chmod("/home/#{authenticatedUser}/public_html/#{rName}", "0755")
...
publicReport
, como "../../localuser/public_html/.htpasswd
", o aplicativo tornará o arquivo especificado como legível para o invasor.
...
mask = config_params['perms']
File.chmod(filename, mask)
...
sprintf()
, FormatMessageW()
ou syslog()
.snprintf()
.
int main(int argc, char **argv){
char buf[128];
...
snprintf(buf,128,argv[1]);
}
%x
, do que a função utiliza como argumentos a serem formatados. (Neste exemplo, a função não usa argumentos a serem formatados.) Ao usar a diretiva de formatação %n
, o invasor pode gravar na pilha, fazendo com que snprintf()
grave no argumento especificado o número de bytes cuja saída foi processada até o momento (em vez de ler um valor do argumento, que é o comportamento pretendido). Uma versão sofisticada desse ataque usará quatro gravações escalonadas para controlar completamente o valor de um apontador na pilha.
printf("%d %d %1$d %1$d\n", 5, 9);
5 9 5 5
Example 1
.syslog()
por vezes utilizada da seguinte maneira:
...
syslog(LOG_ERR, cmdBuf);
...
syslog()
é uma string de formato, qualquer diretiva de formatação incluída em cmdBuf
é interpretada conforme descrito no Example 1
.syslog()
:
...
syslog(LOG_ERR, "%s", cmdBuf);
...
sprintf()
, FormatMessageW()
, syslog()
, NSLog
, ou NSString.stringWithFormat
como um argumento do formato StringNSString.stringWithFormat:
.
int main(int argc, char **argv){
char buf[128];
...
[NSString stringWithFormat:argv[1], argv[2] ];
}
%x
, do que a função utiliza como argumentos a serem formatados. (Neste exemplo, a função não usa argumentos a serem formatados.)
printf("%d %d %1$d %1$d\n", 5, 9);
5 9 5 5
Example 1
.syslog()
por vezes utilizada da seguinte maneira:
...
syslog(LOG_ERR, cmdBuf);
...
syslog()
é uma string de formato, qualquer diretiva de formatação incluída em cmdBuf
é interpretada conforme descrito no Example 1
.syslog()
:Exemplo 4: As classes principais da Apple proporcionam rotas interessantes para explorar as vulnerabilidades do formato String.
...
syslog(LOG_ERR, "%s", cmdBuf);
...
String.stringByAppendingFormat()
por vezes utilizada da seguinte maneira:
...
NSString test = @"Sample Text.";
test = [test stringByAppendingFormat:[MyClass
formatInput:inputControl.text]];
...
stringByAppendingFormat()
:
...
NSString test = @"Sample Text.";
test = [test stringByAppendingFormat:@"%@", [MyClass
formatInput:inputControl.text]];
...
strncpy()
, podem causar vulnerabilidades quando usadas incorretamente. A combinação entre manipulação de memória e suposições equivocadas sobre o tamanho ou a composição de um determinado dado é a causa raiz da maioria dos estouros de buffer.
void wrongNumberArgs(char *s, float f, int d) {
char buf[1024];
sprintf(buf, "Wrong number of %.512s");
}
strncpy()
, podem causar vulnerabilidades quando usadas incorretamente. A combinação entre manipulação de memória e suposições equivocadas sobre o tamanho ou a composição de um determinado dado é a causa raiz da maioria dos estouros de buffer.f
de um flutuante usando um especificador de formato %d
.
void ArgTypeMismatch(float f, int d, char *s, wchar *ws) {
char buf[1024];
sprintf(buf, "Wrong type of %d", f);
...
}
...
String lang = Request.Form["lang"];
WebClient client = new WebClient();
client.BaseAddress = url;
NameValueCollection myQueryStringCollection = new NameValueCollection();
myQueryStringCollection.Add("q", lang);
client.QueryString = myQueryStringCollection;
Stream data = client.OpenRead(url);
...
lang
como en&poll_id=1
e, em seguida, conseguisse alterar poll_id
à vontade.
...
String lang = request.getParameter("lang");
GetMethod get = new GetMethod("http://www.example.com");
get.setQueryString("lang=" + lang + "&poll_id=" + poll_id);
get.execute();
...
lang
como en&poll_id=1
e, em seguida, fosse capaz de alterar poll_id
à vontade.
<%
...
$id = $_GET["id"];
header("Location: http://www.host.com/election.php?poll_id=" . $id);
...
%>
name=alice
, mas adicionou name=alice&
e, se isso estiver em uso em um servidor que obtém a primeira ocorrência, ele poderá representar alice
para obter mais informações sobre a conta dela.
String arg = request.getParameter("arg");
...
Intent intent = new Intent();
...
intent.setClassName(arg);
ctx.startActivity(intent);
...
Intent
interna implícita foi detectada. Intenções internas implícitas podem expor o sistema a ataques do tipo man-in-the-middle em componentes internos.Intent
interna usa uma ação personalizada conforme definido por um componente interno. Intenções implícitas podem facilitar a chamada de intenções de qualquer componente externo sem o conhecimento do componente específico. A combinação das duas permite que um aplicativo acesse intenções especificadas para um uso interno específico fora do contexto do aplicativo desejado.Intent
interna de um aplicativo externo pode permitir uma ampla variedade de explorações man-in-the-middle que variam em gravidade desde vazamento de informações e negação de serviço até execução remota de código, dependendo da capacidade de ação interna especificada pela Intent
.Intent
interna implícita.
...
val imp_internal_intent_action = Intent("INTERNAL_ACTION_HERE")
startActivity(imp_internal_intent_action)
...
PendingIntent
implícita foi detectada. Intenções pendentes implícitas podem resultar em vulnerabilidades de segurança, como negação de serviço, vazamento de informações privadas e do sistema e escalonamento de privilégios.Intent
posteriormente. As intenções implícitas facilitam a chamada de intenções de qualquer componente externo, usando um nome geral e um filtro para determinar a execução.Intent
implícita é criada como uma PendingIntent
, isso pode permitir que Intent
seja enviada para um componente não intencional que é executado fora do contexto temporal pretendido, deixando o sistema vulnerável a explorar vetores como negação de serviço, vazamento de informações privadas e do sistema e escalonamento de privilégios.PendingIntent
implícita.
...
val imp_intent = Intent()
val flag_mut = PendingIntent.FLAG_MUTABLE
val pi_flagmutable_impintintent = PendingIntent.getService(
this,
0,
imp_intent,
flag_mut
)
...
PendingIntent
foi detectada com seu valor de sinalizador definido como FLAG_MUTABLE
. Intenções pendentes criadas com o valor do sinalizador de FLAG_MUTABLE
são suscetíveis a ter campos não especificados Intent
definido a jusante, que pode modificar a capacidade da Intent
e deixar o sistema aberto a vulnerabilidades.Intent
subjacente de uma PendingIntent
após sua criação pode deixar um sistema aberto a ataques. Isso depende principalmente da capacidade geral da Intent
subjacente. Na maioria dos casos, é uma prática recomendada evitar possíveis problemas definindo o sinalizador PendingIntent
como FLAG_IMMUTABLE
.PendingIntent
criada com um valor de sinalizador de FLAG_MUTABLE
.
...
val intent_flag_mut = Intent(Intent.ACTION_GTALK_SERVICE_DISCONNECTED, Uri.EMPTY, this, DownloadService::class.java)
val flag_mut = PendingIntent.FLAG_MUTABLE
val pi_flagmutable = PendingIntent.getService(
this,
0,
intent_flag_mut,
flag_mut
)
...
Intent
aninhado de uma entrada externa para iniciar uma atividade, iniciar um serviço ou realizar uma transmissão pode permitir que um invasor inicie arbitrariamente componentes de aplicativos internos, controle o comportamento de um componente interno ou acesse indiretamente dados protegidos de um provedor de conteúdo por meio de concessões de permissão temporárias.Intent
arbitrário aninhado no pacote de extras de um Intent
fornecido externamente.Intent
arbitrário para iniciar um componente chamando startActivity
, startService
ou sendBroadcast
.Intent
aninhado de uma fonte externa e usa esse Intent
para iniciar uma atividade.
...
Intent nextIntent = (Intent) getIntent().getParcelableExtra("next-intent");
startActivity(nextIntent);
...
returningObjectFlag
como true
na instãncia javax.naming.directory.SearchControls
passada para o método search
ou usando uma função de biblioteca que define este sinalizador em seu nome.
<beans ... >
<authentication-manager>
<ldap-authentication-provider
user-search-filter="(uid={0})"
user-search-base="ou=users,dc=example,dc=org"
group-search-filter="(uniqueMember={0})"
group-search-base="ou=groups,dc=example,dc=org"
group-role-attribute="cn"
role-prefix="ROLE_">
</ldap-authentication-provider>
</authentication-manager>
</beans>
...
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
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)
...
null
.Item
é null
antes de chamar a função membro Equals()
, causando possivelmente um cancelamento de referência null
string itemName = request.Item(ITEM_NAME);
if (itemName.Equals(IMPORTANT_ITEM)) {
...
}
...
null
."null
.malloc()
.
buf = (char*) malloc(req_size);
strncpy(buf, xfer, req_size);
malloc()
falhou por que req_size
era grande demais ou por que muitas solicitações estavam sendo tratadas ao mesmo tempo? Ou ela foi causada por um vazamento de memória que se acumulou com o passar do tempo? Sem realizar o tratamento do erro, não há como saber.null
.getParameter()
é null
antes de chamar a função membro compareTo()
, causando possivelmente um cancelamento de referência null
.Exemplo 2:. O código a seguir mostra uma propriedade do sistema que é definida como
String itemName = request.getParameter(ITEM_NAME);
if (itemName.compareTo(IMPORTANT_ITEM)) {
...
}
...
null
e, mais tarde, tem sua referência desfeita por um programador, que erroneamente assume que ela sempre será definida.
System.clearProperty("os.name");
...
String os = System.getProperty("os.name");
if (os.equalsIgnoreCase("Windows 95") )
System.out.println("Not supported");
null
."NullException
.cmd
" definida. Se um invasor puder controlar o ambiente do programa de forma que "cmd
" não seja definido, o programa lançará uma exceção de ponteiro nulo quando tentar chamar o método Trim()
.
string cmd = null;
...
cmd = Environment.GetEnvironmentVariable("cmd");
cmd = cmd.Trim();
null
antes que seja verificado se ele é realmente null
. Erros de desreferência após a verificação ocorrem quando um programa faz uma verificação explícita em busca de valores null
, mas prossegue para desreferenciar o ponteiro quando se sabe que ele é null
. Erros desse tipo são frequentemente o resultado de um erro de digitação ou de uma desatenção do programador. Um erro de desreferência após o armazenamento ocorre quando um programa define explicitamente um ponteiro como null
e o desreferencia mais tarde. Esse erro é frequentemente o resultado de um programador inicializar uma variável como null
quando ela é declarada.ptr
não seja NULL
. Essa suposição se torna explícita quando o programador desreferencia o ponteiro. Mais tarde, essa suposição é contrariada quando o programador verifica ptr
contra NULL
. Se a variável ptr
puder ser NULL
quando for verificada na instrução if
, ela também poderá ser NULL
quando desreferenciada, podendo causar uma falha de segmentação.Exemplo 2: No código a seguir, o programador confirma que a variável
ptr->field = val;
...
if (ptr != NULL) {
...
}
ptr
é NULL
e depois a desreferencia erroneamente. Se a variável ptr
for NULL
quando for verificada na instrução if
, ocorrerá uma desreferência null
, causando assim uma falha de segmentação.Exemplo 3: No código a seguir, o programador se esquece de que a cadeia de caracteres
if (ptr == null) {
ptr->field = val;
...
}
'\0'
é, na verdade, 0 ou NULL
, desreferenciando assim um ponteiro nulo e provocando uma falha de segmentação.Exemplo 4: No código a seguir, o programador define explicitamente a variável
if (ptr == '\0') {
*ptr = val;
...
}
ptr
como NULL
. Mais tarde, o programador desreferencia ptr
antes de verificar o objeto em busca de um valor null
.
*ptr = NULL;
...
ptr->field = val;
...
}
NullPointerException
.cmd
" definida. Se um invasor puder controlar o ambiente do programa de forma que "cmd
" não seja definido, o programa lançará uma exceção de ponteiro nulo quando tentar chamar o método trim()
.
String val = null;
...
cmd = System.getProperty("cmd");
if (cmd)
val = util.translateCommand(cmd);
...
cmd = val.trim();
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.clone()
deve chamar super.clone()
para obter o novo objeto.clone()
devem obter o novo objeto chamando super.clone()
. Se uma classe não seguir essa convenção, o método clone()
de uma subclasse retornará um objeto do tipo errado.super.clone()
. Devido à forma como Kibitzer
implementa clone()
, o método clone de FancyKibitzer
retornará um objeto do tipo Kibitzer
em vez 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();
...
}
}