Como criar um ataque de injeção SQL com Shift-JIS e CP932?

Estou escrevendo alguns testes de unidade para garantir que meu código não seja vulnerável à injeção de SQL em vários tipos de caracteres.

De acordo com esta resposta , você pode criar uma vulnerabilidade injetando \xbf\x27 usando um dos seguintes graficos: big5 , cp932 , gb2312 , gbk e sjis

Isso ocorre porque se seu escaper não estiver configurado corretamente, ele verá o 0x27 e tentará escaping dele, de modo que ele se torne \xbf\x5c\x27 . No entanto, \xbf\x5c é realmente um caractere nestes caracteres, portanto, a citação ( 0x27 ) é deixada sem 0x27 .

Conforme descobri através dos testes, no entanto, isso não é inteiramente verdade. Funciona para big5 , gb2312 e gbk mas nem 0xbf27 ou 0xbf5c são caracteres válidos em sjis e cp932 .

Ambos

 mb_strpos("abc\xbf\x27def","'",0,'sjis') 

e

 mb_strpos("abc\xbf\x27def","'",0,'cp932') 

Retorno 4 . ou seja, o PHP não vê \xbf\x27 como um único caractere. Isso retorna false para big5 , gb2312 e gbk .

Além disso, isto:

 mb_strlen("\xbf\x5c",'sjis') 

Retorna 2 (retorna 1 para gbk ).

Então, a questão é: existe outra seqüência de caracteres que torna o sjis e o cp932 vulneráveis ​​à injeção de SQL, ou eles realmente não são vulneráveis? ou está de mentir PHP, estou completamente enganada, e o MySQL irá interpretar isso de forma totalmente diferente?

   

O demônio está nos detalhes … vamos começar com como a resposta em questão descreve a lista de conjuntos de caracteres vulneráveis:

Para que este ataque funcione, precisamos da codificação que o servidor está esperando na conexão tanto para codificar ' como em ASCII ou seja, 0x27 e ter algum caractere cujo byte final é um ASCII \ ie 0x5c . Como se verifica, existem 5 tais codificações suportadas no MySQL 5.6 por padrão: big5 , cp932 , gb2312 , gbk e sjis . Vamos selecionar gbk aqui .

Isso nos dá algum contexto – 0xbf5c é usado como um exemplo para o gbk , não como o caráter universal a ser usado para todos os conjuntos de 5 caracteres.
Acontece que a mesma seqüência de bytes também é um caractere válido em big5 e gb2312 .

Neste ponto, sua pergunta torna-se tão fácil quanto esta:

Qual sequência de bytes é um caractere válido em cp932 e sjis e termina em 0x5c ?

Para ser justo, a maioria das pesquisas do Google que tentei para esses conjuntos de personagens não oferecem resultados úteis. Mas eu encontrei esse arquivo CP932.TXT , no qual, se você procurar por '5c ' (com o espaço), você irá saltar para esta linha:

0x815C 0x2015 # BARRA AUTÊNTICA

E temos um vencedor! 🙂

Alguns documentos Oracle confirmam que 0x815c é o mesmo caractere para cp932 e sjis e o PHP também o reconhece:

 php > var_dump(mb_strlen("\x81\x5c", "cp932"), mb_strlen("\x81\x5c", "sjis")); int(1) int(1) 

Aqui está um script PoC para o ataque:

 < ?php $username = 'username'; $password = 'password'; $mysqli = new mysqli('localhost', $username, $password); foreach (array('cp932', 'sjis') as $charset) { $mysqli->query("SET NAMES {$charset}"); $mysqli->query("CREATE DATABASE {$charset}_db CHARACTER SET {$charset}"); $mysqli->query("USE {$charset}_db"); $mysqli->query("CREATE TABLE foo (bar VARCHAR(16) NOT NULL)"); $mysqli->query("INSERT INTO foo (bar) VALUES ('baz'), ('qux')"); $input = "\x81\x27 OR 1=1 #"; $input = $mysqli->real_escape_string($input); $query = "SELECT * FROM foo WHERE bar = '{$input}' LIMIT 1"; $result = $mysqli->query($query); if ($result->num_rows > 1) { echo "{$charset} exploit successful!\n"; } $mysqli->query("DROP DATABASE {$charset}_db"); }