コード例 #1
0
    async def send_result(self, result: Optional[Dict]):
        if result:
            try:
                success = access_dot_path(result, 'data.tcp.status')
            except:
                success = 'unknown-error'
            try:
                content_length = int(
                    access_dot_path(result,
                                    'data.tcp.result.response.content_length'))
            except:
                content_length = 0

            if self.stats:
                if success == 'success':
                    self.stats.count_good += 1
                else:
                    self.stats.count_error += 1

            line = None
            line_out = None
            try:
                if self.success_only:
                    if success == 'success':
                        line = result
                else:
                    line = result
            except Exception:
                pass

            if line:
                if self.body_not_empty:
                    if content_length > 0:
                        line_out = ujson_dumps(line)
                else:
                    line_out = ujson_dumps(line)

            if line_out:
                await self.output_queue.put(line_out)
コード例 #2
0
def test_access_dot_path(some_dict, path, expected):
    assert access_dot_path(some_dict, path) == expected
コード例 #3
0
    async def do(self, target: Target):
        """
        сопрограмма, осуществляет подключение к Target, отправку и прием данных, формирует результата в виде dict
        """
        def return_ip_from_deep(sess, response) -> str:
            try:
                ip_port = response.connection.transport.get_extra_info(
                    'peername')
                if is_ip(ip_port[0]):
                    return ip_port[0]
            except BaseException:
                pass
            try:
                _tmp_conn_key = sess.connector._conns.items()
                for k, v in _tmp_conn_key:
                    _h = v[0][0]
                    ip_port = _h.transport.get_extra_info('peername')
                    if is_ip(ip_port[0]):
                        return ip_port[0]
            except BaseException:
                pass
            return ''

        def update_line(json_record, target):
            json_record['ip'] = target.ip
            # json_record['ip_v4_int'] = int(ip_address(target.ip))
            # json_record['datetime'] = datetime.datetime.utcnow()
            # json_record['port'] = int(target.port)
            return json_record

        async with self.semaphore:
            result = None
            timeout = ClientTimeout(total=target.total_timeout)

            # region tmp disable
            trace_config = TraceConfig()
            trace_config.on_request_start.append(on_request_start)
            trace_config.on_request_end.append(on_request_end)
            # endregion
            resolver = AsyncResolver(nameservers=['8.8.8.8', '8.8.4.4'])
            # resolver = None
            # https://github.com/aio-libs/aiohttp/issues/2228  - closed
            if target.ssl_check:

                conn = TCPConnector(
                    ssl=False,
                    family=2,  # need set current family (only IPv4)
                    limit_per_host=0,
                    resolver=resolver)
                session = ClientSession(timeout=timeout,
                                        connector=conn,
                                        response_class=WrappedResponseClass,
                                        trace_configs=[trace_config])
                simple_zero_sleep = 0.250
            else:
                simple_zero_sleep = 0.001
                session = ClientSession(
                    connector=TCPConnector(
                        limit_per_host=0,
                        family=2,  # need set current family (only IPv4)
                        resolver=resolver),
                    timeout=timeout,
                    trace_configs=[trace_config])
            selected_proxy_connection = None
            try:
                selected_proxy_connection = next(
                    self.app_config.proxy_connections)
            except:
                pass
            try:
                async with session.request(
                        target.method,
                        target.url,
                        timeout=timeout,
                        headers=target.headers,
                        cookies=target.cookies,
                        allow_redirects=target.allow_redirects,
                        data=target.payload,
                        proxy=selected_proxy_connection,
                        trace_request_ctx=self.trace_request_ctx) as response:
                    _default_record = create_template_struct(target)
                    if target.ssl_check:
                        cert = convert_bytes_to_cert(response.peer_cert)
                        if not self.app_config.without_certraw:
                            _default_record['data']['http']['result'][
                                'response']['request']['tls_log'][
                                    'handshake_log']['server_certificates'][
                                        'certificate']['raw'] = b64encode(
                                            response.peer_cert).decode('utf-8')
                        if cert:
                            _default_record['data']['http']['result'][
                                'response']['request']['tls_log'][
                                    'handshake_log']['server_certificates'][
                                        'certificate']['parsed'] = cert
                    _default_record['data']['http']['status'] = "success"
                    _default_record['data']['http']['result']['response'][
                        'status_code'] = response.status
                    # region
                    _header = {}
                    for key in response.headers:
                        _header[key.lower().replace(
                            '-', '_')] = response.headers.getall(key)
                    _default_record['data']['http']['result']['response'][
                        'headers'] = _header
                    # endregion
                    if target.method in [
                            'GET', 'POST', 'PUT', 'DELETE', 'UPDATE'
                    ]:
                        buffer = b""
                        try:
                            read_c = asyncio.wait_for(
                                read_http_content(response, n=target.max_size),
                                timeout=target.total_timeout)
                            buffer = await read_c
                        except Exception as e:
                            pass
                        else:
                            if filter_bytes(buffer, target):
                                _default_record['data']['http']['result'][
                                    'response']['content_length'] = len(buffer)
                                _default_record['data']['http']['result'][
                                    'response']['body'] = ''
                                try:
                                    _default_record['data']['http']['result'][
                                        'response']['body'] = buffer.decode()
                                except Exception as e:
                                    pass
                                if not self.app_config.without_base64:
                                    try:
                                        _base64_data = b64encode(
                                            buffer).decode('utf-8')
                                        _default_record['data']['http'][
                                            'result']['response'][
                                                'body_raw'] = _base64_data
                                    except Exception as e:
                                        pass
                                if not self.app_config.without_hashs:
                                    try:
                                        hashs = {
                                            'sha256': sha256,
                                            'sha1': sha1,
                                            'md5': md5
                                        }
                                        for namehash, func in hashs.items():
                                            hm = func()
                                            hm.update(buffer)
                                            _default_record['data']['http'][
                                                'result']['response'][
                                                    f'body_{namehash}'] = hm.hexdigest(
                                                    )
                                    except Exception as e:
                                        pass
                                result = update_line(_default_record, target)
                            else:
                                # TODO: добавить статус success-not-contain для обозначения того,
                                #  что сервис найден, но не попал под фильтр?
                                result = create_error_template(
                                    target,
                                    error_str='',
                                    status_string='success-not-contain')
                    if result:
                        if not result['ip']:
                            result['ip'] = return_ip_from_deep(
                                session, response)
            except Exception as exp:
                error_str = ''
                try:
                    error_str = exp.strerror
                except:
                    pass
                result = create_error_template(target, error_str,
                                               type(exp).__name__)
                await asyncio.sleep(simple_zero_sleep)
                try:
                    await session.close()
                except:
                    pass
                try:
                    await conn.close()
                except:
                    pass
            if result:
                if 'duration' in self.trace_request_ctx:
                    request_duration = self.trace_request_ctx['duration']
                    result['data']['http']['duration'] = request_duration
                success = access_dot_path(result, "data.http.status")
                if self.stats:
                    if success == "success":
                        self.stats.count_good += 1
                    else:
                        self.stats.count_error += 1
                if not (self.app_config.status_code == CONST_ANY_STATUS):
                    response_status = access_dot_path(
                        result, 'data.http.result.response.status_code')
                    if response_status:
                        if self.app_config.status_code != response_status:
                            error_str = f'status code: {response_status} is not equal to filter: {self.app_config.status_code}'
                            result = create_error_template(
                                target,
                                error_str=error_str,
                                status_string='success-not-need-status')
                            self.stats.count_good -= 1
                            self.stats.count_error += 1
                line = None
                try:
                    if self.success_only:
                        if success == "success":
                            line = ujson_dumps(result)
                    else:
                        line = ujson_dumps(result)
                except Exception:
                    pass
                if line:
                    await self.output_queue.put(line)

            await asyncio.sleep(simple_zero_sleep)
            try:
                await session.close()
            except:
                pass
            try:
                await conn.close()
            except:
                pass
コード例 #4
0
    async def do(self, target: Target):
        """
        сопрограмма, осуществляет подключение к Target, отправку и прием данных, формирует результата в виде dict
        """
        async with self.semaphore:
            result = None
            certificate_dict = None
            cert_bytes_base64 = None

            if target.ssl_check:  # если при запуске в настройках указано --use-ssl - то контекст ssl
                ssl_context = ssl_create_unverified_context()
                future_connection = asyncio.open_connection(
                    target.ip,
                    target.port,
                    ssl=ssl_context,
                    ssl_handshake_timeout=target.ssl_timeout)
            else:
                future_connection = asyncio.open_connection(
                    target.ip, target.port)
            try:
                reader, writer = await asyncio.wait_for(
                    future_connection, timeout=target.conn_timeout)
                if target.ssl_check:
                    try:
                        # noinspection PyProtectedMember
                        _sub_ssl = writer._transport.get_extra_info(
                            'ssl_object')
                        cert_bytes = _sub_ssl.getpeercert(binary_form=True)
                        cert_bytes_base64 = b64encode(cert_bytes).decode(
                            'utf-8')
                        certificate_dict = convert_bytes_to_cert(cert_bytes)
                    except BaseException:
                        pass
            except Exception as e:
                await asyncio.sleep(0.005)
                try:
                    future_connection.close()
                    del future_connection
                except Exception as e:
                    pass
                result = create_error_template(target, str(e))
            else:
                try:
                    status_data = False
                    if target.payload:  # если указан payload - то он и отправляется в первую очередь
                        writer.write(target.payload)
                        await writer.drain()
                    if target.mode == 'single':
                        status_data, data_or_error_result = await single_read(
                            reader, target)
                    elif target.mode == 'multi':
                        status_data, data_or_error_result = await asyncio.wait_for(
                            multi_read(reader, target),
                            timeout=target.read_timeout)
                    if status_data:
                        check_filter = filter_bytes(data_or_error_result,
                                                    target)
                        if check_filter:
                            result = make_document_from_response(
                                data_or_error_result, target)
                            if target.ssl_check:
                                if cert_bytes_base64:
                                    result['data']['tcp']['result']['response'][
                                        'request']['tls_log']['handshake_log'][
                                            'server_certificates'][
                                                'certificate'][
                                                    'raw'] = cert_bytes_base64
                                if certificate_dict:
                                    result['data']['tcp']['result']['response'][
                                        'request']['tls_log']['handshake_log'][
                                            'server_certificates'][
                                                'certificate'][
                                                    'parsed'] = certificate_dict

                        else:
                            # TODO: добавить статус success-not-contain для обозначения того,
                            #  что сервис найден, но не попал под фильтр
                            pass
                        await asyncio.sleep(0.005)
                    else:
                        result = data_or_error_result  # get errors
                    try:
                        writer.close()
                    except BaseException:
                        pass
                except Exception as e:
                    result = create_error_template(target, str(e))
                    try:
                        future_connection.close()
                    except Exception:
                        pass
                    await asyncio.sleep(0.005)
                    try:
                        writer.close()
                    except Exception:
                        pass
            if result:
                success = access_dot_path(result, "data.tcp.status")
                if self.stats:
                    if success == "success":
                        self.stats.count_good += 1
                    else:
                        self.stats.count_error += 1
                line = None
                try:
                    if self.success_only:
                        if success == "success":
                            line = ujson_dumps(result)
                    else:
                        line = ujson_dumps(result)
                except Exception:
                    pass
                if line:
                    await self.output_queue.put(line)
コード例 #5
0
    async def do(self, target: Target):
        async with self.semaphore:
            result = None
            future_connection = asyncio.open_connection(target.ip, target.port)
            try:
                reader, writer = await asyncio.wait_for(
                    future_connection, timeout=target.conn_timeout)
            except Exception as e:
                await asyncio.sleep(0.005)
                try:
                    future_connection.close()
                    del future_connection
                except Exception as e:
                    pass
                result = create_error_template(target, str(e))
            else:
                try:
                    for i in range(15, 43):
                        TLS_ClientHello[i] = (TLS_ClientHello[i]
                                              ^ randint(0, 4294967294)) & 0xFF
                    writer.write(bytes(TLS_ClientHello))
                    await writer.drain()
                    await asyncio.sleep(0.05)
                    desc_text = '1 step: read 65535 bytes'
                    status_data, answer = await single_read(
                        reader,
                        target,
                        custom_max_size=65535,
                        operation_description=desc_text)
                    if status_data:
                        if answer[0] != 0x16:
                            message_error_text = "Not a C2. TLS ContentType state"
                            raise AssertionError(message_error_text)
                        if answer[5] != 0x02:
                            message_error_text = f"Not a C2. Expected ServerHello (02) got ({answer[5]:02X})"
                            raise AssertionError(message_error_text)

                        for i in range(15, 267):
                            TLS_HelloRequest[i] = (
                                TLS_HelloRequest[i]
                                ^ randint(0, 4294967294)) & 0xFF

                        packed_size = pack(">H", FULL_SIZE)
                        for i, j in enumerate(range(276, 278)):
                            TLS_HelloRequest[j] = packed_size[i]

                        for i, j in enumerate(range(278, 278 + len(SECRET))):
                            TLS_HelloRequest[j] = SECRET[i]

                        for i in range(278 + len(SECRET), 278 + FULL_SIZE):
                            TLS_HelloRequest[i] = (
                                TLS_HelloRequest[i]
                                ^ randint(0, 4294967294)) & 0xFF

                        writer.write(bytes(TLS_HelloRequest))
                        await writer.drain()
                        await asyncio.sleep(0.05)
                        desc_text = f'2 step: read 5 bytes, timeout={target.read_timeout}'
                        status_data, answer = await single_read(
                            reader,
                            target,
                            custom_max_size=5,
                            operation_description=desc_text)
                        if status_data:
                            if answer[0] != 0x14:
                                message_error_text = f"Not a C2. Expected ChangeCipherSpec (0x14) got ({answer[0]:02X})"
                                raise AssertionError(message_error_text)
                            length = unpack(">H", bytes(answer[3:]))[0]
                            if length > 0x3ff9:
                                message_error_text = f"Not a C2. ChangeCipherSpec too big"
                                raise AssertionError(message_error_text)
                            await asyncio.sleep(0.05)
                            desc_text = f'3 step: read {length}+5 bytes, timeout={target.read_timeout}'
                            status_data, _answer = await single_read(
                                reader,
                                target,
                                custom_max_size=length + 5,
                                operation_description=desc_text)
                            await asyncio.sleep(0.05)
                            if status_data:
                                answer = _answer[-5:]
                                if answer[0] != 0x16:
                                    message_error_text = f"Not a C2. Expected Handshake (0x16) got ({answer[0]:02X})"
                                    raise AssertionError(message_error_text)

                                length = unpack(">H", bytes(answer[3:]))[0]
                                if length > 0x3ff9:
                                    message_error_text = f"Not a C2. Handshake too big"
                                    raise AssertionError(message_error_text)
                                desc_text = f'4 step: read {length} bytes, timeout={target.read_timeout}'
                                status_data, answer = await single_read(
                                    reader,
                                    target,
                                    custom_max_size=length,
                                    operation_description=desc_text)
                                if status_data:
                                    server_secret = answer[:len(SECRET)]
                                    key_stream = derive_key(server_secret)
                                    need_payload = pack_payload(key_stream,
                                                                  pack("<H", 0x200) + \
                                                                  pack("<H", 0x03) + \
                                                                  b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
                                    writer.write(need_payload)
                                    await writer.drain()
                                    await asyncio.sleep(0.05)
                                    desc_text = f'5 step: read 5 bytes, timeout={target.read_timeout}'
                                    status_data, answer = await single_read(
                                        reader,
                                        target,
                                        custom_max_size=5,
                                        operation_description=desc_text)
                                    length = unpack(">H", bytes(answer[3:]))[0]
                                    desc_text = f'6 step: read {length} bytes, timeout={target.read_timeout}'
                                    status_data, answer = await single_read(
                                        reader,
                                        target,
                                        custom_max_size=length,
                                        operation_description=desc_text)
                                    c2_answer = key_stream.decrypt(answer)
                                    command_id = unpack("<H", c2_answer[:2])[0]
                                    module_id = unpack("<H", c2_answer[2:4])[0]
                                    if command_id not in COMMANDS:
                                        message_error_text = f"Not a C2. Invalid response command id"
                                        raise AssertionError(
                                            message_error_text)
                                    if module_id != 3:
                                        message_error_text = f"Not a C2. Invalid response module id"
                                        raise AssertionError(
                                            message_error_text)
                                    result = make_document_from_response(
                                        b'C2 found', target)
                                    await asyncio.sleep(0.005)
                                else:
                                    result = answer
                            else:
                                result = _answer
                        else:
                            result = answer
                    else:
                        result = answer  # get errors
                    try:
                        writer.close()
                    except BaseException:
                        pass
                except AssertionError as e:
                    result = create_error_template(target, str(e))
                    try:
                        future_connection.close()
                    except Exception:
                        pass
                    await asyncio.sleep(0.005)
                    try:
                        writer.close()
                    except Exception:
                        pass
                except Exception as e:
                    result = create_error_template(target, str(e))
                    try:
                        future_connection.close()
                    except Exception:
                        pass
                    await asyncio.sleep(0.005)
                    try:
                        writer.close()
                    except Exception:
                        pass

            if result:
                try:
                    success = access_dot_path(result, 'data.tcp.status')
                except:
                    success = 'unknown-error'
                try:
                    content_length = int(
                        access_dot_path(
                            result, 'data.tcp.result.response.content_length'))
                except:
                    content_length = 0

                if self.stats:
                    if success == 'success':
                        self.stats.count_good += 1
                    else:
                        self.stats.count_error += 1

                line = None
                line_out = None
                try:
                    if self.success_only:
                        if success == 'success':
                            line = result
                    else:
                        line = result
                except Exception:
                    pass

                if line:
                    if self.body_not_empty:
                        if content_length > 0:
                            line_out = ujson_dumps(line)
                    else:
                        line_out = ujson_dumps(line)

                if line_out:
                    await self.output_queue.put(line_out)