...
tid = request->get_form_field( 'tid' ).
CALL TRANSACTION tid USING bdcdata MODE 'N'
MESSAGES INTO messtab.
...
APPHOME
de configuração do aplicativo e, em seguida, carrega uma biblioteca nativa com base em um caminho relativo a partir do diretório especificado.
...
string lib = ConfigurationManager.AppSettings["APPHOME"];
Environment.ExitCode = AppDomain.CurrentDomain.ExecuteAssembly(lib);
...
APPHOME
de configuração desse aplicativo de forma que ela aponte para um caminho diferente contendo uma versão mal-intencionada de LIBNAME
. Como o programa não valida o valor lido do ambiente, se um invasor puder controlar o valor da propriedade do sistema APPHOME
, ele poderá enganar o aplicativo, fazendo com que este execute o código mal-intencionado, e assumir o controle do sistema.
...
RegQueryValueEx(hkey, "APPHOME",
0, 0, (BYTE*)home, &size);
char* lib=(char*)malloc(strlen(home)+strlen(INITLIB));
if (lib) {
strcpy(lib,home);
strcat(lib,INITCMD);
LoadLibrary(lib);
}
...
INITLIB
. Como o programa não valida o valor lido do ambiente, se um invasor conseguir controlar o valor de APPHOME
, ele poderá enganar o arquivo para que ele execute código mal-intencionado.liberty.dll
, que se destina a ser encontrada em um diretório padrão do sistema.
LoadLibrary("liberty.dll");
liberty.dll
. Se um invasor colocar uma biblioteca mal-intencionada chamada liberty.dll
na ordem de pesquisa em uma posição superior à do arquivo pretendido e tiver uma maneira de executar o programa no respectivo ambiente, e não no ambiente de um servidor Web, o aplicativo carregará essa biblioteca mal-intencionada em vez da biblioteca confiável. Como esse tipo de aplicativo é executado com privilégios elevados, o conteúdo do arquivo liberty.dll
do invasor é agora executado com privilégios elevados, possivelmente dando a ele controle total sobre o sistema.LoadLibrary()
quando um caminho absoluto não é especificado. Se o diretório atual for pesquisado antes dos diretórios do sistema, como era o caso até as versões mais recentes do Windows, esse tipo de ataque se tornará comum caso o invasor consiga executar o programa localmente. A ordem de pesquisa depende da versão do sistema operacional e é controlada em sistemas operacionais mais recentes pelo valor desta chave do registro:
HKLM\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode
LoadLibrary()
se comporta da seguinte maneira:SafeDllSearchMode
for 1, a ordem de pesquisa será a seguinte:PATH
.SafeDllSearchMode
for 0, a ordem de pesquisa será a seguinte:PATH
.
...
ACCEPT PROGNAME.
EXEC CICS
LINK PROGRAM(PROGNAME)
COMMAREA(COMA)
LENGTH(LENA)
DATALENGTH(LENI)
SYSID('CONX')
END-EXEC.
...
APPHOME
para determinar o diretório no qual ele está instalado e, em seguida, carrega uma biblioteca nativa com base em um caminho relativo a partir do diretório especificado.
...
String home = System.getProperty("APPHOME");
String lib = home + LIBNAME;
java.lang.Runtime.getRuntime().load(lib);
...
APPHOME
de forma que ela aponte para um caminho diferente contendo uma versão mal-intencionada de LIBNAME
. Como o programa não valida o valor lido do ambiente, se um invasor puder controlar o valor da propriedade do sistema APPHOME
, ele poderá enganar o aplicativo, fazendo com que este execute o código mal-intencionado, e assumir o controle do sistema.System.loadLibrary()
para carregar o código de uma biblioteca nativa denominada library.dll
, que é normalmente encontrada em um diretório de sistema padrão.
...
System.loadLibrary("library.dll");
...
System.loadLibrary()
aceita um nome de biblioteca, mas não um caminho, para a biblioteca a ser carregada. A partir da documentação da API Java 1.4.2, essa função se comporta da seguinte maneira [1]:library.dll
em uma posição na ordem de pesquisa superior à do arquivo que o aplicativo pretende carregar, este carregará a cópia mal-intencionada em vez do arquivo pretendido. Por causa da natureza do aplicativo, ele é executado com privilégios elevados, o que significa que o conteúdo do arquivo library.dll
do invasor será agora executado com privilégios elevados, possivelmente concedendo a ele controle total sobre o sistema.Express
para carregar dinamicamente um arquivo de biblioteca. Em seguida, Node.js
continua a pesquisar o respectivo caminho de carga de biblioteca normal em busca de um arquivo ou uma pasta que contenha essa biblioteca[1].
var express = require('express');
var app = express();
app.get('/', function(req, res, next) {
res.render('tutorial/' + req.params.page);
});
Express
, a página transmitida para Response.render()
carregará uma biblioteca da extensão quando for anteriormente desconhecida. Isso geralmente não apresenta prolemas para entradas, como "foo.pug", pois significará o carregamento da biblioteca pug
, um notório mecanismo de modelo. No entanto, se um invasor puder controlar a página e, portanto, a extensão, ele poderá optar por carregar qualquer biblioteca nos caminhos de carregamento de módulo Node.js
. Como o programa não valida as informações recebidas do parâmetro de URL, o invasor pode enganar o aplicativo, fazendo com que ele execute código mal-intencionado, e assumir o controle do sistema.APPHOME
para determinar o diretório no qual ele está instalado e, em seguida, carrega uma biblioteca nativa com base em um caminho relativo a partir do diretório especificado.
...
$home = getenv("APPHOME");
$lib = $home + $LIBNAME;
dl($lib);
...
APPHOME
de forma que ela aponte para um caminho diferente contendo uma versão mal-intencionada de LIBNAME
. Como o programa não valida o valor lido do ambiente, se um invasor puder controlar o valor da propriedade do sistema APPHOME
, ele poderá enganar o aplicativo, fazendo com que este execute o código mal-intencionado, e assumir o controle do sistema.dl()
para carregar o código de uma biblioteca chamada sockets.dll
, que pode ser carregada de vários locais, dependendo da sua instalação e da sua configuração.
...
dl("sockets");
...
dl()
aceita um nome de biblioteca, mas não um caminho, para a biblioteca a ser carregada.sockets.dll
em uma posição na ordem de pesquisa superior à do arquivo que o aplicativo pretende carregar, este carregará a cópia mal-intencionada em vez do arquivo pretendido. Por causa da natureza do aplicativo, ele é executado com privilégios elevados, o que significa que o conteúdo do arquivo sockets.dll
do invasor será agora executado com privilégios elevados, possivelmente concedendo a ele controle total sobre o sistema.Kernel.system()
para executar um executável chamado program.exe
, que normalmente é encontrado em um diretório de sistema padrão.
...
system("program.exe")
...
Kernel.system()
executa algo por meio de um shell. Se um invasor puder manipular as variáveis de ambiente RUBYSHELL
ou COMSPEC
, ele poderá apontar para um executável malicioso que será chamado com o comando dado a Kernel.system()
. Por causa da natureza do aplicativo, ele é executado com os privilégios necessários para realizar operações do sistema, o que significa que, agora, o program.exe
do invasor será executado com esses privilégios, possivelmente concedendo a ele controle total sobre o sistema.Kernel.system()
. Se um invasor puder modificar a variável $PATH
a fim de que aponte para um binário malicioso chamado program.exe
e executar o aplicativo no ambiente dele, o binário malicioso será carregado ao invés do binário pretendido. Por causa da natureza do aplicativo, ele é executado com os privilégios necessários para realizar operações do sistema, o que significa que, agora, o program.exe
do invasor será executado com esses privilégios, possivelmente concedendo a ele controle total sobre o sistema.InvokerServlet
pode permitir que invasores invoquem qualquer classe no servidor.InvokerServlet
preterida pode ser usada para invocar qualquer classe disponível para a máquina virtual do servidor. Ao adivinhar o nome totalmente qualificado de uma classe, um invasor pode carregar não só classes de Servlet, como também classes POJO ou qualquer outra classe disponível para a JVM.
@GetMapping("/prompt_injection")
String generation(String userInput1, ...) {
return this.clientBuilder.build().prompt()
.system(userInput1)
.user(...)
.call()
.content();
}
client = new Anthropic();
# Simulated attacker's input attempting to inject a malicious system prompt
attacker_input = ...
response = client.messages.create(
model = "claude-3-5-sonnet-20240620",
max_tokens=2048,
system = attacker_input,
messages = [
{"role": "user", "content": "Analyze this dataset for anomalies: ..."}
]
);
...
client = OpenAI()
# Simulated attacker's input attempting to inject a malicious system prompt
attacker_input = ...
completion = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": attacker_input},
{"role": "user", "content": "Compose a poem that explains the concept of recursion in programming."}
]
)
@GetMapping("/prompt_injection_persistent")
String generation(String userInput1, ...) {
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users WHERE ...");
String userName = "";
if (rs != null) {
rs.next();
userName = rs.getString("userName");
}
return this.clientBuilder.build().prompt()
.system("Assist the user " + userName)
.user(userInput1)
.call()
.content();
}
client = new Anthropic();
# Simulated attacker's input attempting to inject a malicious system prompt
attacker_query = ...;
attacker_name = db.qyery('SELECT name FROM user_profiles WHERE ...');
response = client.messages.create(
model = "claude-3-5-sonnet-20240620",
max_tokens=2048,
system = "Provide assistance to the user " + attacker_name,
messages = [
{"role": "user", "content": attacker_query}
]
);
...
client = OpenAI()
# Simulated attacker's input attempting to inject a malicious system prompt
attacker_name = cursor.fetchone()['name']
attacker_query = ...
completion = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "Provide assistance to the user " + attacker_name},
{"role": "user", "content": attacker_query}
]
)
Object.prototype
, se um invasor puder sobrescrever o protótipo de um objeto, ele normalmente poderá sobrescrever a definição de Object.prototype
, afetando todos os objetos dentro do aplicativo.undefined
em vez de sempre serem explicitamente definidas, então se o protótipo foi poluído, o aplicativo poderá ler inadvertidamente o protótipo em vez do objeto pretendido.lodash
para poluir o protótipo do objeto:
import * as lodash from 'lodash'
...
let clonedObject = lodash.merge({}, JSON.parse(untrustedInput));
...
{"__proto__": { "isAdmin": true}}
, então Object.prototype
terá definido isAdmin = true
.
...
let config = {}
if (isAuthorizedAsAdmin()){
config.isAdmin = true;
}
...
if (config.isAdmin) {
// do something as the admin
}
...
isAdmin
só deve ser definido como verdadeiro se isAuthorizedAdmin()
retorna verdadeiro, porque o aplicativo não consegue definir config.isAdmin = false
na outra condição, ele se baseia no fato de que config.isAdmin === undefined === false
.config
agora foi definido isAdmin === true
, que permite que a autorização do administrador seja ignorada.select()
SimpleDB que procura faturas correspondentes a uma categoria de produto especificada pelo usuário. O usuário também pode especificar a coluna pela qual os resultados são classificados. Suponha que o aplicativo já tenha sido devidamente autenticado e defina o valor de customerID
antes desse segmento de código.
...
String customerID = getAuthenticatedCustomerID(customerName, customerCredentials);
...
AmazonSimpleDBClient sdbc = new AmazonSimpleDBClient(appAWSCredentials);
String query = "select * from invoices where productCategory = '"
+ productCategory + "' and customerID = '"
+ customerID + "' order by '"
+ sortColumn + "' asc";
SelectResult sdbResult = sdbc.select(new SelectRequest(query));
...
select * from invoices
where productCategory = 'Fax Machines'
and customerID = '12345678'
order by 'price' asc
productCategory
e price
não contiverem caracteres de aspas simples. Porém, se um invasor fornecer a string "Fax Machines' or productCategory = \"
" para productCategory
e a string "\" order by 'price
" para sortColumn
, a consulta se tornará a seguinte:
select * from invoices
where productCategory = 'Fax Machines' or productCategory = "'
and customerID = '12345678'
order by '" order by 'price' asc
select * from invoices
where productCategory = 'Fax Machines'
or productCategory = "' and customerID = '12345678' order by '"
order by 'price' asc
customerID
e permite que ele veja registros de faturas correspondentes a 'Fax Machines'
para todos os clientes.customerID
antes desse segmento de código.
...
productCategory = this.getIntent().getExtras().getString("productCategory");
sortColumn = this.getIntent().getExtras().getString("sortColumn");
customerID = getAuthenticatedCustomerID(customerName, customerCredentials);
c = invoicesDB.query(Uri.parse(invoices), columns, "productCategory = '" + productCategory + "' and customerID = '" + customerID + "'", null, null, null, "'" + sortColumn + "'asc", null);
...
select * from invoices
where productCategory = 'Fax Machines'
and customerID = '12345678'
order by 'price' asc
productCategory
. Portanto, ela se comportará corretamente somente se productCategory
e sortColumn
não contiverem caracteres de aspas simples. Se um invasor fornecer a string "Fax Machines' or productCategory = \"
" para productCategory
e a string "\" order by 'price
" para sortColumn
, a consulta se tornará:
select * from invoices
where productCategory = 'Fax Machines' or productCategory = "'
and customerID = '12345678'
order by '" order by 'price' asc
select * from invoices
where productCategory = 'Fax Machines'
or productCategory = "' and customerID = '12345678' order by '"
order by 'price' asc
customerID
e permite que ele veja registros de faturas correspondentes a 'Fax Machines'
para todos os clientes.
...
var authenticated = true;
...
database_connect.query('SELECT * FROM users WHERE name == ? AND password = ? LIMIT 1', userNameFromUser, passwordFromUser, function(err, results){
if (!err && results.length > 0){
authenticated = true;
}else{
authenticated = false;
}
});
if (authenticated){
//do something privileged stuff
authenticatedActions();
}else{
sendUnathenticatedMessage();
}
true
, caso contrário, false
. Infelizmente, uma vez que o retorno de chamada é bloqueado por E/S, ele será executado de forma assíncrona e poderá ser executado após a verificação para if (authenticated)
, e, como o padrão era verdadeiro, ele vai para a if-statement quer o o usuário esteja realmente autenticado ou não.
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory() + "/download/" + "app.apk")), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
...
public class Box{
public int area;
public static final int width = 10;
public static final Box box = new Box();
public static final int height = (int) (Math.random() * 100);
public Box(){
area = width * height;
}
...
}
...
Example 1
, o desenvolvedor esperaria que box.area
fosse um número inteiro aleatório que, por acaso, é um múltiplo de 10, já que width
é igual a 10. Porém, na realidade, isso sempre terá um valor inserido em código fixo de 0. Campos estáticos finais declarados com uma constante em tempo de compilação são inicializados primeiros e depois cada um é executado em ordem. Isso significa que, como height
não é uma constante em tempo de compilação, ela é declarada após a declaração de box
e, portanto, o construtor é chamado antes da inicialização do campo height
.
...
class Foo{
public static final int f = Bar.b - 1;
...
}
...
class Bar{
public static final int b = Foo.f + 1;
...
}
This example is perhaps easier to identify, but would be dependent on which class is loaded first by the JVM. In this exampleFoo.f
could be either -1 or 0, andBar.b
could be either 0 or 1.
setuid root
. O programa executa certas operações de arquivo em nome de usuários sem privilégios e usa verificações de acesso para garantir que ele não use seus privilégios de root para executar operações que não deveriam estar disponíveis ao usuário atual. O programa usa a chamada de sistema access()
para verificar se a pessoa que está executando o programa tem permissão para acessar o arquivo especificado antes de abri-lo e executar as operações necessárias.
if (!access(file,W_OK)) {
f = fopen(file,"w+");
operate(f);
...
}
else {
fprintf(stderr,"Unable to open file %s.\n",file);
}
access()
se comporta conforme o esperado, retornando 0
quando o usuário que está executando o programa tem as permissões necessárias para gravar no arquivo e -1 em outros casos. No entanto, como access()
e fopen()
operam ambos em nomes de arquivo em vez de em identificadores de arquivo, não há nenhuma garantia de que a variável file
ao ser transmitida para fopen()
ainda faça referência ao mesmo arquivo no disco de quando ela foi transmitida para access()
. Se um invasor substituir file
após a chamada para access()
por um link simbólico para um arquivo diferente, o programa usará seus privilégios de root para operar nesse arquivo, mesmo que este seja um arquivo que o invasor seria incapaz de modificar em outras circunstâncias. Ao enganar o programa a ponto de fazer com que ele realizasse uma operação que de outra forma seria inadmissível, o invasor obteve privilégios elevados.root
. Se o aplicativo for capaz de realizar qualquer operação que o invasor de outra forma não teria permissão para realizar, então ele será um possível alvo.
fd = creat(FILE, 0644); /* Create file */
if (fd == -1)
return;
if (chown(FILE, UID, -1) < 0) { /* Change file owner */
...
}
chown()
seja igual ao arquivo criado pela chamada para creat()
, mas isso não é necessariamente o caso. Como chown()
opera em um nome de arquivo e não em um identificador de arquivo, um invasor pode ser capaz de substituir o arquivo por um link para um arquivo que ele não possui. Dessa maneira, a chamada para chown()
daria ao invasor a posse sobre o arquivo vinculado.CBL_CHECK_FILE_EXIST
para verificar se o arquivo existe antes de criar um e executa as operações necessárias.
CALL "CBL_CHECK_FILE_EXIST" USING
filename
file-details
RETURNING status-code
END-CALL
IF status-code NOT = 0
MOVE 3 to access-mode
MOVE 0 to deny-mode
MOVE 0 to device
CALL "CBL_CREATE_FILE" USING
filename
access-mode
deny-mode
device
file-handle
RETURNING status-code
END-CALL
END-IF
CBL_CHECK_FILE_EXIST
comporta-se como esperado e retorna um valor não zero, indicando que o arquivo não existe. Entretanto, como tanto CBL_CHECK_FILE_EXIST
quanto CBL_CREATE_FILE
operam de acordo com nomes de arquivo, em vez de identificadores de arquivo, não há garantia de que a variável filename
, ao ser passada para CBL_CREATE_FILE
, ainda faça referência ao mesmo arquivo a que se referia ao ser passada para CBL_CHECK_FILE_EXIST
. Se um invasor criar filename
após a chamada para CBL_CHECK_FILE_EXIST
, a chamada para CBL_CREATE_FILE
falhará, levando o programa a acreditar que o arquivo está vazio, quando, na realidade, ele contém dados controlados pelo invasor.root
que executa certas operações de arquivo em nome de usuários sem privilégios e usa verificações de acesso para garantir que ele não use seus privilégios de root para executar operações que não deveriam estar disponíveis ao usuário atual. Ao enganar o programa e fazer com que ele execute uma operação que, de outro modo, não seria permitida, o invasor pode aumentar seus privilégios.parse()
e format()
em java.text.Format
contêm uma falha de design que pode fazer com que um usuário veja os dados de outro usuário.parse()
e format()
em java.text.Format
contêm uma condição de corrida que pode fazer com que um usuário veja os dados de outro usuário.
public class Common {
private static SimpleDateFormat dateFormat;
...
public String format(Date date) {
return dateFormat.format(date);
}
...
final OtherClass dateFormatAccess=new OtherClass();
...
public void function_running_in_thread1(){
System.out.println("Time in thread 1 should be 12/31/69 4:00 PM, found: "+ dateFormatAccess.format(new Date(0)));
}
public void function_running_in_thread2(){
System.out.println("Time in thread 2 should be around 12/29/09 6:26 AM, found: "+ dateFormatAccess.format(new Date(System.currentTimeMillis())));
}
}
format()
.open_basedir
contém uma falha de design que a deixa vulnerável a condições de corrida de acesso a arquivos que, por sua vez, podem permitir que um invasor se esquive de verificações de controle de acesso no sistema de arquivos.open_basedir
tenta impedir que programas PHP operem em arquivos fora das árvores de diretórios especificadas em php.ini. Embora a opção open_basedir
seja uma vantagem geral para a segurança, a implementação é afetada por uma condição de corrida que pode permitir que os invasores se esquivem de suas restrições em algumas circunstâncias [2]. Existe uma condição de corrida TOCTOU (tempo de verificação/tempo de uso) entre o momento em que o PHP realiza a verificação de permissão de acesso e o momento em que o arquivo é aberto. Tal como acontece com condições de corrida no sistema de arquivos em outras linguagens, essa vulnerabilidade pode permitir que os invasores substituam um link simbólico para um arquivo, aprovado na verificação de controle de acesso, por outro para o qual o teste seria reprovado de outra forma, obtendo assim acesso ao arquivo protegido.RoamingFolder
ou RoamingSettings
da classe Windows.Storage.ApplicationData
.RoamingFolder
e RoamingSettings
obtêm um contêiner no repositório de dados do aplicativo em roaming, que pode então ser usado para compartilhar dados entre mais dois dispositivos. Ao gravar e ler objetos armazenados no repositório de dados do aplicativo móvel, o desenvolvedor aumenta o risco de comprometimento. Isso inclui a confidencialidade, a integridade e a disponibilidade dos dados, aplicativos e sistemas que compartilham esses objetos por meio do repositório de dados em roaming.free()
duas vezes no mesmo valor pode resultar em um estouro de buffer. Quando um programa chama free()
duas vezes com o mesmo argumento, as estruturas de dados de gerenciamento de memória desse programa se tornam corrompidas. Essa corrupção pode fazer com que o programa trave ou, em algumas circunstâncias, com que duas chamadas posteriores para malloc()
retornem o mesmo apontador. Se malloc()
retornar o mesmo valor duas vezes, e, mais tarde, o programa der ao invasor controle sobre os dados que são gravados nessa memória duplamente alocada, o programa se tornará vulnerável a um ataque de estouro de buffer.
void sh(int dummy) {
...
free(global2);
free(global1);
...
}
int main(int argc,char* argv[]) {
...
signal(SIGHUP,sh);
signal(SIGTERM,sh);
...
}
public class GuestBook extends HttpServlet {
String name;
protected void doPost (HttpServletRequest req, HttpServletResponse res) {
name = req.getParameter("name");
...
out.println(name + ", thanks for visiting!");
}
}
Dick
" a name
Jane
" a name
Jane, thanks for visiting!
"Jane, thanks for visiting!
"
public class ConnectionManager {
private static Connection conn = initDbConn();
...
}
dangerouslySetInnerHTML
O atributo é definido como HTML do código desnecessariamente.dangerouslySetInnerHTML
no React substitui o uso de innerHTML no DOM do navegador, mas a API foi renomeada para transmitir os possíveis perigos de usá-lo. Em geral, definir o HTML com base no código é arriscado porque é fácil expor inadvertidamente seus usuários a um ataque de script entre sites (XSS).dangerouslySetInnerHTML
:
function MyComponent(data) {
return (
<div
dangerouslySetInnerHTML={{__html: data.innerHTML}}
/>
);
}