Python安全攻防:渗透测试实战指南
上QQ阅读APP看书,第一时间看更新

4.1.3 邮件爬取

在针对目标系统进行渗透的过程中,如果目标服务器安全性很高,通过服务器很难获取目标权限时,通常会采用社工的方式对目标服务进行进一步攻击。邮件钓鱼攻击是常见的攻击方式之一。在进行钓鱼之前,需要针对目标相关人员的邮件信息进行全面采集。下面将带领大家一起编写一个邮件采集工具。

此处邮件采集工具主要通过国内常见的搜索引擎(百度、Bing等)进行搜集。针对搜索界面的相关邮件信息进行爬取、处理等操作之后。利用获得的邮箱账号批量发送钓鱼邮件,诱骗、欺诈目标用户或者管理员进行账号登录或者点击执行,进而获取目标系统的权限。该邮件采集工具所用到的相关库函数如下所示:


import sys
import getopt
import requests
from bs4 import BeautifulSoup
import re

1)在程序的起始部分,当执行过程中没有发生异常时,则执行定义的start()函数。通过sys.argv[]实现外部指令的接收。其中,sys.argv[0]表示代码本身的文件路径,sys.argv[1:]表示从第一个命令行参数到输入的最后一个命令行参数,存储形式为list类型:


if __name__ == '__main__':
    #定义异常
    try:
        start(sys.argv[1:])
    except KeyboardInterrupt:
        print("interrupted by user, killing all threads...")

2)编写命令行参数处理功能。此处主要应用getopt.getopt()函数处理命令行参数,该函数目前有短选项和长选项两种格式。短选项格式为“-”加上单个字母选项;长选项格式为“--”加上一个单词选项。opts为一个两元组列表,每个元素形式为“(选项串,附加参数)”。当没有附加参数时,则为空串。之后通过for语句循环输出opts列表中的数值并赋值给自定义的变量:


#主函数,传入用户输入的参数
def start(argv):
    url = ""
    pages = ""
    if len(sys.argv) < 2:
        print("-h 帮助信息;\n")
        sys.exit()
    #定义异常处理
    try:
        banner()
        opts,args = getopt.getopt(argv,"-u:-p:-h")
    except getopt.GetoptError:
        print('Error an argument!')
        sys.exit()
    for opt,arg in opts:
        if opt == "-u":
            url = arg
        elif opt == "-p":
            pages = arg
        elif opt == "-h":
            print(usage())
    launcher(url,pages)

3)输出帮助信息,增加代码工具的可读性和易用性。为了使输出信息更加美观简洁,可以通过转义字符设置输出字体颜色,从而实现需要的效果。开头部分包含三个参数:显示方式、前景色、背景色。这三个参数是可选的,可以只写其中的某一个参数。结尾部分可以省略,但是为了书写规范,建议以“\033[0m”结尾。其具体的输出格式如下所示:


开头:\033[显示方式;前景色;背景色m
结尾部分:\033[0m

示例代码如下:


print('\033[0;30;41m ms08067实验室欢迎你 \033[0m')
print('\033[0;31;42m ms08067实验室欢迎你 \033[0m')
print('\033[0;32;43m ms08067实验室欢迎你 \033[0m')
print('\033[0;33;44m ms08067实验室欢迎你 \033[0m')
print('\033[0;34;45m ms08067实验室欢迎你 \033[0m')
print('\033[0;35;46m ms08067实验室欢迎你 \033[0m')
print('\033[0;36;47m ms08067实验室欢迎你 \033[0m')

示例的输出效果如下所示:

该部分主要代码如下所示,先以图案的形式输出脚本出自MS08067实验室,然后输出有关该脚本使用的帮助信息,即可执行参数指令以及对应的功能简介。代码如下:


#banner信息
def banner():
print('\033[1;34m#########################################################
    ###############################\033[0m\n'
      '\033[1;34m######################################\033[1;32MMS08067实验室
          \033[1;34m#####################################\033[0m\n'
      '\033[1;34m#########################################################
          ###############################\033[0m\n')
#使用规则
def usage():
    print('-h: --help 帮助;')
    print('-u: --url  域名;')
    print('-p: --pages 页数;')
    print('eg: python -u "www.baidu.com" -p 100'+'\n')
    sys.exit()
##未授权函数检测

输出效果如下所示:

当然,此处也可以根据自己的喜好设置输出不同类型的字体颜色或者图案。

4)确定搜索邮件的关键字,并调用bing_search()和baidu_search()两个函数,返回Bing与百度两大搜索引擎的查询结果。由获取到的结果进行列表合并,去重之后,循环输出。代码如下:


#漏洞回调函数
def launcher(url,pages):
    email_num = []
    key_words = ['email','mail','mailbox','邮件','邮箱','postbox']
    for page in range(1,int(pages)+1):
        for key_word in key_words:
            bing_emails = bing_search(url,page,key_word)
            baidu_emails = baidu_search(url,page,key_word)
            sum_emails =  bing_emails + baidu_emails
            for email in sum_emails:
                if email in email_num:
                    pass
                else:
                    print(email)
                    with open('data.txt', 'a+') as f:
                        f.write(email + '\n')
                    email_num.append(email)

5)用Bing搜索引擎进行邮件爬取。Bing引擎具有反爬防护,会通过限定referer、cookie等信息来确定是否是网页爬取操作。可以通过指定referer与requests.session()函数自动获取cookie信息,绕过Bing搜索引擎的防爬防护。代码如下:


def bing_search(url,page,key_word):
    referer = "http://cn.bing.com/search?q=email+site%3abaidu.com&qs=n&sp=-1&
        pq=emailsite%3abaidu.com&first=1&FORM=PERE1"
    conn = requests.session()
    bing_url = "http://cn.bing.com/search?q=" + key_word + "+site%3a" + url + 
        "&qs=n&sp=-1&pq=" + key_word + "site%3a" + url + "&first=" + str(
        (page-1)*10) + "&FORM=PERE1"
    conn.get('http://cn.bing.com', headers=headers(referer))
    r = conn.get(bing_url, stream=True, headers=headers(referer), timeout=8)
    emails = search_email(r.text)
    return emails

6)用百度搜索引擎进行邮件爬取。百度搜索引擎同样设定了反爬防护,相对于Bing搜索引擎来说,百度搜索引擎不仅对referer和cookie进行校验,还同时在页面中通过JavaScript语句进行动态请求链接,从而导致不能动态获取页面中的信息。可以通过对链接的提取,再进行request请求,从而绕过百度搜索引擎的反爬设置,具体代码如下所示:


def baidu_search(url,page,key_word):
    email_list = []
    emails = []
    referer = "https://www.baidu.com/s?wd=email+site%3Abaidu.com&pn=1"
    baidu_url = "https://www.baidu.com/s?wd="+key_word+"+site%3A"+url+"&pn=
        "+str((page-1)*10)
    conn = requests.session()
    conn.get(referer,headers=headers(referer))
    r = conn.get(baidu_url, headers=headers(referer))
    soup = BeautifulSoup(r.text, 'lxml')
    tagh3 = soup.find_all('h3')
    for h3 in tagh3:
        href = h3.find('a').get('href')
        try:
            r = requests.get(href, headers=headers(referer),timeout=8)
            emails = search_email(r.text)
        except Exception as e:
            pass
        for email in emails:
            email_list.append(email)
    return email_list

7)通过正则表达式获取邮箱号码。此处也可换成目标企业邮箱的正则表达式,代码如下:


def search_email(html):
    emails = re.findall(r"[a-z0-9\.\-+_]+@[a-z0-9\.\-+_]+\.[a-z]+",html,re.I)
    return emails

def headers(referer):
    headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/
        20100101 Firefox/60.0',
               'Accept': '*/*',
               'Accept-Language': 'en-US,en;q=0.5',
               'Accept-Encoding': 'gzip,deflate',
               'Referer': referer
               }
    return headers

通过Python 3执行刚刚写完的脚本并通过-u参数指定域名,-p参数表示搜索引擎的页数,其输出效果如下所示:

此处也可以指定其他域名,并将爬取结果打印到页面中。