Injeção de código malicioso no Facebook
Neste blog, apresentarei a vocês um estudo que realizei junto com Dikla Barda. Neste estudo, fomos capazes de fazer upload de um arquivo malicioso para o CDN do Facebook manipulando o navegador e criando um Fuzzer simples que nos ajudou a contornar o Analisador de Imagens do Facebook, que excluía o código malicioso da imagem..
Neste estudo, apresentamos um método interessante pelo qual um arquivo malicioso pode ser inserido em uma imagem e armazenado no CDN do Facebook e, assim, basicamente contornar todos os mecanismos de assinatura, uma vez que o Facebook é considerado um domínio confiável, não havera nenhum bloqueio de links provenientes dele-Facebook.
Para tirar proveito da falha de segurança, tivemos que localizar e contornar uma série de fatores:
- Falha de segurança do lado do servidor
- Realizar manipulação e pesquisa sobre o próprio navegador
- Contorne o intérprete de imagem que comprime as imagens novamente e reduz a imagem
Vídeo de demonstração:
Part 1
Quando você carrega uma imagem para o Facebook, a imagem é carregada para o CDN para desempenho e tempos de resposta mais rápidos, uma vez que você carrega uma imagem com uma resolução acima de 962x541, a imagem é carregada para o CDN sem parâmetros que identificam a imagem com qualquer conta. assim que é:
`` https://scontent-lhr3-1.xx.fbcdn.net/t31.0-8/14102894_1137188709676282_2198558191558447569_o.jpg`
Se a resolução for menor do que isso obteremos um link com parâmetros que não podem ser modificados:
Nosso primeiro passo foi fazer upload de diferentes fotos no Facebook em diferentes resoluções e examiná-las. Assim que encontramos a resolução apropriada, que é acima da resolução de 962x541, passamos para a próxima etapa, a de inserção de código na imagem. Apenas para fins de demonstração:
WshShell=new ActiveXObject("WScript.Shell");
WshShell.Run('c:/windows/system32/calc.exe',1,false);
O resultado fica assim:
Carregamos o arquivo no Facebook e baixamos de volta depois que passou pelo processo de conversão de imagem do Facebook pelo leitor de fotos (Image Parser).
Esperávamos que pelo menos parte do código inserido permanecesse, mas o resultado foi um tanto problemático: Todo o código que inserimos na imagem foi substituído pelo intérprete de imagem que compactou a imagem para economizar espaço.
Como contornar algo assim?
Primeiro tentamos pegar o arquivo compactado que passa pelo interpetre e inserir o código nele, porque um arquivo que já foi compactado usando o lado do servidor do Facebook não será compactado novamente na mesma extensão e mais caracteres permanecerão no arquivo.
Depois de modificar o arquivo compactado, pudemos ver pelo menos uma pequena parte do código que inserimos.
Como progredir a partir daqui?
Depois de muito pensar, ocorreu-nos escrever um fuzzer que usa uma API gráfica que executa as seguintes etapas:
-
- Define um local no arquivo e insere nosso código nele.
-
- Carrega imagem para-Facebook.
-
- Baixa a imagem de volta depois de compactada.
-
- Verifica se nosso código está na imagem.
-
- Se o código não for encontrado movemos um byte para a direita ou para a esquerda de acordo com o melhor resultado.
-
- Paramos após 50 tentativas para diagnosticar os resultados e atualizar o-fuzzer.
Abaixo está a principal função do código escrito:
`` def payload_check(): # Send Picture to Facebook r = requests.post("https://graph.facebook.com/v2.7/me/photos?access_FBToken={}&caption={}&url={}".format(FBToken,message,URLToImage)) # Get the Picture Back r = requests.get('https://graph.facebook.com/v2.7/me/posts?access_FBToken={}&debug=all&fields=message,object_id,type&format=json&limit=1&method=get&pretty=0&suppress_http_code=1&with="{}"'.format(FBToken,message)) image_code = json.loads(r.text)["data"][0]["object_id"] r = requests.get('https://graph.facebook.com/v2.7/{}/picture?access_FBToken={}&debug=all&format=json&method=get&pretty=0&redirect=false&suppress_http_code=1'.format(image_code,FBToken)) # This URL will not contain the Payload, We need the full size one :) # print json.loads(r.text)["data"]["url"] # This url may contain the Payload! good_url = str(json.loads(r.text)["data"]["url"]).replace("s720x720/","") download_file(good_url) # Check if we see some part of the payload to enhance the positions with open("image.jpg","r") as f: if half_payload in f.read(): print "[+] Found! Values:" print "Counter1: {}, Counter2: {}, Cursor: {}, half_payload: {}, Index: {}".format(counter1, counter2, cursor, half_payload, index) return True else: return False`
Observe que a API Graph retorna uma imagem no formato s720x720, a imagem é menor, o que significa que estão faltando caracteres! Para acessar a imagem original, devemos excluir o s720x720 do URL e, em seguida, acessar a imagem.
Após a primeira execução, conseguimos encontrar um local que nos permite fazer upload de quase todo o código em sua totalidade, enquanto na segunda execução nosso Fuzzer foi capaz de encontrar um local exato que nos permite fazer upload de todo o código! No qual ficou assim:
Os caracteres ‘A’ O que você vê é, na verdade, o padding que o fuzzer executou.
Então, conseguimos fazer o upload do código para uma imagem .jpg próxima ao servidor, mas isso é apenas o começo, agora temos que fazer o arquivo finalizar com a extensão .hta para que o arquivo seja executado, caso contrário, o que faríamos com ele?
Se examinarmos a resposta do servidor, parece que seu content-type (tipo de conteúdo) é image/jpeg Então, se baixarmos o arquivo, obteremos um arquivo de imagem, então precisamos encontrar uma maneira de converter o content-type para outra coisa, como application/octet-stram
Depois de várias tentativas, descobrimos que é possível adicionar um ponto à extensão da url para obter o content-type desejado:
Uma vez que tenhamos conseguido controlar o tipo de conteúdo, temos que fazer a imagem ser baixada pela URL, para fazer isso vamos adicionar o parâmetro dl=1 O que indica fazer download, o que será assim:
Voltamos para burp suite para analizar o pacote, você pode ver que o o parâmetro dl=1 Adiciona o título à URL
`` Content-Disposition: attachment`
O que indica o download do arquivo
Como o Facebook não anexou o nome do arquivo ao content-dispostion, o navegador terá que decidir qual será o nome do arquivo que pretende baixar do site..
Part 2
Para entender em que base o navegador conclui qual será o nome do arquivo, vamos olhar o código-fonte do projeto chromium:
`` https://cs.chromium.org/chromium/src/content/renderer/loader/web_url_loader_impl.cc`
Começaremos com a função PopulateURLResponse, que sua função é abordar as informações provenientes do servidor.
Esta função gerencia todas as informações recebidas e responde aos títulos de acordo, ela também determina o nome do arquivo se tivermos content-disposition nos títulos da resposta do servidor.
Se houver realmente um content-disposition, esta função chama a função GetSuggestedFileName :
Na função headers->EnumerateHeader Verifiqqa se existe um nome de arquivo no content-disposition e se não existe o valor que é a segunda variável da função GetSuggestedFilename estará realmente vazio.
Se olharmos para esta função, parece que ela apenas envolve o GetSuggestedFilenameImpl:
Esta função verifica se content_disposition está vazio e, se estiver, entra na função GetFileNameFromURL
Esta função verifica se a chamada é realmente uma chamada normal e não data:// ou about:// Em seguida, chama a-ExtractFileName
Que só envolve DoExtractFileName
A função DoExtractFileName é assim:
Ele tenta localizar o nome do arquivo do final da URL até a última barra, mas se tivermos um ponto e vírgula ";" Portanto, o nome do arquivo é determinado da última barra até a vírgula dessa forma:
`` /filename.extension;`
Part 3
Com base nessas informações, podemos basicamente controlar o nome do arquivo que queremos selecionar pelo navegador. por exemplo:
O URL ficará assim:
`` https://scontent-lhr3-1.xx.fbcdn.net/t31.0-8/14102894_1137188709676282_2198558191558447569_o.jpg/facebook_password.exe;.?dl=1`
É claro que um arquivo exe não será executado porque o cabeçalho do arquivo não corresponde ao cabeçalho PE, mas o que podemos fazer é alterar o arquivo para uma extensão .hta que executará o código javascript que inserimos no arquivo anteriormente na primeira parte.
que será assim:
Só nos resta copiar e enviar o link, e quem clicar no link executará nosso código armazenado nos servidores do CDN. Facebook.
Baixar o arquivo e clicar nele irá ativar a calculadora, pois foi isso que fizemos em nosso código:
Part 4
Ao esconder o link no messenger, tentamos verificar se é possível ocultar o link no messenger de alguma forma e chegamos ao seguinte truque:
Fazemos upload da imagem que contém o código JavaScript que mostrei antes, mas desta vez fazemos upload para-Messenger:
Modificaremos o tipo de conteúdo e extensão de arquivo, para o tipo de conteúdo escolhido image/svg+xml E para o nome do arquivo é selecionado novamente .hta então:
Vamos enviar o arquivo, e parece que nem precisamos de um link, podemos enviar uma foto regular em-Messenger:
Clicando na imagem vai baixar o arquivo e renomeá-lo para .hta pois é o sufixo que escolhemos para o arquivo e desta vez ele aparece em-content-disposition:
Clicar no arquivo ativará o código e, assim, executará calculadora: