atomicshop 2.16.29__py3-none-any.whl → 2.16.30__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of atomicshop might be problematic. Click here for more details.
- atomicshop/__init__.py +1 -1
- atomicshop/http_parse.py +78 -57
- atomicshop/mitm/connection_thread_worker.py +23 -23
- atomicshop/mitm/engines/__parent/recorder___parent.py +6 -2
- atomicshop/mitm/message.py +30 -4
- atomicshop/mitm/mitm_main.py +8 -6
- atomicshop/wrappers/socketw/dns_server.py +1 -1
- atomicshop/wrappers/socketw/sender.py +23 -4
- atomicshop/wrappers/socketw/sni.py +27 -16
- atomicshop/wrappers/socketw/socket_wrapper.py +8 -11
- {atomicshop-2.16.29.dist-info → atomicshop-2.16.30.dist-info}/METADATA +1 -1
- {atomicshop-2.16.29.dist-info → atomicshop-2.16.30.dist-info}/RECORD +15 -15
- {atomicshop-2.16.29.dist-info → atomicshop-2.16.30.dist-info}/LICENSE.txt +0 -0
- {atomicshop-2.16.29.dist-info → atomicshop-2.16.30.dist-info}/WHEEL +0 -0
- {atomicshop-2.16.29.dist-info → atomicshop-2.16.30.dist-info}/top_level.txt +0 -0
atomicshop/__init__.py
CHANGED
atomicshop/http_parse.py
CHANGED
|
@@ -2,6 +2,7 @@ from http.server import BaseHTTPRequestHandler
|
|
|
2
2
|
from http.client import HTTPResponse
|
|
3
3
|
import http
|
|
4
4
|
from io import BytesIO
|
|
5
|
+
import socket
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
class HTTPRequestParse(BaseHTTPRequestHandler):
|
|
@@ -50,38 +51,25 @@ class HTTPRequestParse(BaseHTTPRequestHandler):
|
|
|
50
51
|
|
|
51
52
|
# noinspection PyMissingConstructor
|
|
52
53
|
def __init__(self, request_text):
|
|
53
|
-
self.
|
|
54
|
-
self.raw_requestline = self.rfile.readline()
|
|
55
|
-
self.error_code = self.error_message = None
|
|
56
|
-
self.parse_request()
|
|
54
|
+
self.request_text = request_text
|
|
57
55
|
|
|
58
|
-
#
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
56
|
+
# noinspection PyTypeChecker
|
|
57
|
+
self.rfile = None
|
|
58
|
+
self.raw_requestline = None
|
|
59
|
+
self.error_code = None
|
|
60
|
+
self.error_message = None
|
|
62
61
|
|
|
63
62
|
self.content_length = None
|
|
64
63
|
self.body = None
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if hasattr(self, 'headers'):
|
|
68
|
-
# The "body" of request is in the 'Content-Length' key. If it exists in "headers" - get the body
|
|
69
|
-
if 'Content-Length' in self.headers.keys():
|
|
70
|
-
# "self.headers.get('Content-Length')" returns number in string format, "int" converts it to integer
|
|
71
|
-
self.content_length = int(self.headers.get('Content-Length'))
|
|
72
|
-
self.body = self.rfile.read(self.content_length)
|
|
73
|
-
|
|
74
|
-
# Examples:
|
|
75
|
-
# Getting path: self.path
|
|
76
|
-
# Getting Request Version: self.request_version
|
|
77
|
-
# Getting specific header: self.headers['host']
|
|
64
|
+
# noinspection PyTypeChecker
|
|
65
|
+
self.path = None
|
|
78
66
|
|
|
79
67
|
# noinspection PyMethodOverriding
|
|
80
68
|
def send_error(self, code, message):
|
|
81
69
|
self.error_code = code
|
|
82
70
|
self.error_message = message
|
|
83
71
|
|
|
84
|
-
def
|
|
72
|
+
def parse(self):
|
|
85
73
|
"""
|
|
86
74
|
Function to check if parsed object is HTTP request or not.
|
|
87
75
|
'reason' will be populated with parsing status and errors.
|
|
@@ -116,7 +104,26 @@ class HTTPRequestParse(BaseHTTPRequestHandler):
|
|
|
116
104
|
client_message.request_raw_decoded = request_decoded
|
|
117
105
|
"""
|
|
118
106
|
|
|
119
|
-
error:
|
|
107
|
+
error: str = str()
|
|
108
|
+
info: str = str()
|
|
109
|
+
|
|
110
|
+
self.rfile = BytesIO(self.request_text)
|
|
111
|
+
self.raw_requestline = self.rfile.readline()
|
|
112
|
+
self.error_code = self.error_message = None
|
|
113
|
+
self.parse_request()
|
|
114
|
+
|
|
115
|
+
# Before checking for body, we need to make sure that ".headers" property exists, if not, return empty values.
|
|
116
|
+
if hasattr(self, 'headers'):
|
|
117
|
+
# The "body" of request is in the 'Content-Length' key. If it exists in "headers" - get the body
|
|
118
|
+
if 'Content-Length' in self.headers.keys():
|
|
119
|
+
# "self.headers.get('Content-Length')" returns number in string format, "int" converts it to integer
|
|
120
|
+
self.content_length = int(self.headers.get('Content-Length'))
|
|
121
|
+
self.body = self.rfile.read(self.content_length)
|
|
122
|
+
|
|
123
|
+
# Examples:
|
|
124
|
+
# Getting path: self.path
|
|
125
|
+
# Getting Request Version: self.request_version
|
|
126
|
+
# Getting specific header: self.headers['host']
|
|
120
127
|
|
|
121
128
|
# If there's any error in HTTP parsing
|
|
122
129
|
if self.error_message:
|
|
@@ -125,67 +132,82 @@ class HTTPRequestParse(BaseHTTPRequestHandler):
|
|
|
125
132
|
# If it's 'Bad request' this is not HTTP request, so we can
|
|
126
133
|
# continue the execution and parse the code as NON-HTTP Request.
|
|
127
134
|
# Currently, seen 'Bad request syntax' and 'Bad request version'.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
error: False
|
|
135
|
+
error = f"HTTP Request Parsing: Not HTTP request: {self.error_message}"
|
|
136
|
+
is_http = False
|
|
131
137
|
else:
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
error = True
|
|
138
|
+
error = f"HTTP Request Parsing: HTTP Request with Script Undocumented ERROR: {self.error_message}"
|
|
139
|
+
is_http = False
|
|
135
140
|
# If there's no error at all in HTTP Parsing, then it's fine HTTP Request
|
|
136
141
|
else:
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
error = False
|
|
142
|
+
is_http = True
|
|
143
|
+
info = "HTTP Request Parsing: Valid HTTP request"
|
|
140
144
|
|
|
141
|
-
return
|
|
145
|
+
return self, is_http, info, error
|
|
142
146
|
|
|
143
147
|
|
|
144
148
|
class FakeSocket:
|
|
145
149
|
"""
|
|
146
|
-
FakeSocket
|
|
150
|
+
FakeSocket mimics a socket object for parsing HTTP responses.
|
|
147
151
|
"""
|
|
148
152
|
def __init__(self, response_bytes):
|
|
149
153
|
self._file = BytesIO(response_bytes)
|
|
150
154
|
|
|
151
|
-
def makefile(self,
|
|
155
|
+
def makefile(self, mode='rb', buffering=-1) -> BytesIO:
|
|
156
|
+
"""
|
|
157
|
+
Mimics the socket's makefile method, returning the BytesIO object.
|
|
158
|
+
"""
|
|
152
159
|
return self._file
|
|
153
160
|
|
|
161
|
+
def fileno(self) -> int:
|
|
162
|
+
"""
|
|
163
|
+
Provide a dummy file descriptor, as some code might call this.
|
|
164
|
+
"""
|
|
165
|
+
raise OSError("File descriptor not available in FakeSocket")
|
|
166
|
+
|
|
154
167
|
|
|
155
168
|
class HTTPResponseParse:
|
|
156
169
|
def __init__(self, response_raw_bytes: bytes):
|
|
157
|
-
self.error = None
|
|
158
170
|
self.response_raw_bytes: bytes = response_raw_bytes
|
|
171
|
+
|
|
172
|
+
self.error = None
|
|
173
|
+
self.source = None
|
|
174
|
+
self.response_raw_decoded = None
|
|
175
|
+
self.is_http: bool = False
|
|
176
|
+
|
|
177
|
+
def parse(self):
|
|
159
178
|
# Assigning FakeSocket with response_raw_bytes.
|
|
160
179
|
self.source = FakeSocket(self.response_raw_bytes)
|
|
161
180
|
|
|
162
181
|
# Initializing HTTPResponse class with the FakeSocket with response_raw_bytes as input.
|
|
182
|
+
# noinspection PyTypeChecker
|
|
163
183
|
self.response_raw_decoded = HTTPResponse(self.source)
|
|
164
184
|
|
|
165
185
|
# Try to parse HTTP Response.
|
|
166
186
|
try:
|
|
167
187
|
self.response_raw_decoded.begin()
|
|
188
|
+
self.is_http = True
|
|
168
189
|
# If there were problems with the status line.
|
|
169
190
|
except http.client.BadStatusLine:
|
|
170
191
|
self.error = "HTTP Response Parsing: Not a valid HTTP Response: Bad Status Line."
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
if 'Content-Length' in self.response_raw_decoded.headers.keys():
|
|
192
|
+
self.is_http = False
|
|
193
|
+
|
|
194
|
+
header_exists: bool = False
|
|
195
|
+
if (self.response_raw_decoded is not None and hasattr(self.response_raw_decoded, 'headers') and
|
|
196
|
+
self.response_raw_decoded.headers is not None):
|
|
197
|
+
header_exists = True
|
|
198
|
+
|
|
199
|
+
if header_exists and self.response_raw_decoded.headers.defects:
|
|
200
|
+
self.error = f"HTTP Response Parsing: Not a valid HTTP Response: Some defects in headers: " \
|
|
201
|
+
f"{self.response_raw_decoded.headers.defects}"
|
|
202
|
+
self.is_http = False
|
|
203
|
+
|
|
204
|
+
if self.is_http:
|
|
205
|
+
# Before checking for body, we need to make sure that ".headers" property exists,
|
|
206
|
+
# if not, return empty values.
|
|
207
|
+
self.response_raw_decoded.content_length = None
|
|
208
|
+
self.response_raw_decoded.body = None
|
|
209
|
+
if header_exists and 'Content-Length' in self.response_raw_decoded.headers.keys():
|
|
210
|
+
# The "body" of response is in the 'Content-Length' key. If it exists in "headers" - get the body.
|
|
189
211
|
# "self.response_raw_decoded.headers.get('Content-Length')" returns number in string format,
|
|
190
212
|
# "int" converts it to integer.
|
|
191
213
|
self.response_raw_decoded.content_length = int(self.response_raw_decoded.headers.get('Content-Length'))
|
|
@@ -193,6 +215,5 @@ class HTTPResponseParse:
|
|
|
193
215
|
# of the response that we received.
|
|
194
216
|
# self.response_raw_bytes[-23:]
|
|
195
217
|
self.response_raw_decoded.body = self.response_raw_bytes[-self.response_raw_decoded.content_length:]
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
self.response_raw_decoded.body = None
|
|
218
|
+
|
|
219
|
+
return self.response_raw_decoded, self.is_http, self.error
|
|
@@ -82,29 +82,22 @@ def thread_worker_main(
|
|
|
82
82
|
def parse_http():
|
|
83
83
|
nonlocal error_message
|
|
84
84
|
# Parsing the raw bytes as HTTP.
|
|
85
|
-
request_decoded =
|
|
86
|
-
|
|
87
|
-
request_is_http, http_parsing_reason, http_parsing_error = request_decoded.check_if_http()
|
|
85
|
+
request_decoded, is_http_request, request_parsing_info, request_parsing_error = (
|
|
86
|
+
HTTPRequestParse(client_message.request_raw_bytes).parse())
|
|
88
87
|
|
|
89
|
-
|
|
90
|
-
if not http_parsing_error:
|
|
91
|
-
print_api(http_parsing_reason, logger=network_logger, logger_method='info')
|
|
92
|
-
# If there was error - the request is really HTTP, but there's a problem with its structure.
|
|
93
|
-
else:
|
|
94
|
-
client_message.error = http_parsing_reason
|
|
95
|
-
error_message = (
|
|
96
|
-
f'HTTP Parse Request Error: '
|
|
97
|
-
f'The request is HTTP protocol, but there was a problem with its structure: '
|
|
98
|
-
f'{http_parsing_error}')
|
|
99
|
-
print_api(error_message, logger=network_logger, logger_method='error', color='yellow')
|
|
100
|
-
statistics_error_list.append(error_message)
|
|
101
|
-
|
|
102
|
-
# If the request is HTTP protocol.
|
|
103
|
-
if request_is_http:
|
|
88
|
+
if is_http_request:
|
|
104
89
|
client_message.protocol = 'HTTP'
|
|
90
|
+
client_message.request_raw_decoded = request_decoded
|
|
91
|
+
print_api(request_parsing_info, logger=network_logger, logger_method='info')
|
|
105
92
|
network_logger.info(f"Method: {request_decoded.command}")
|
|
106
93
|
network_logger.info(f"Path: {request_decoded.path}")
|
|
107
|
-
|
|
94
|
+
# If there was error - the request is really HTTP, but there's a problem with its structure.
|
|
95
|
+
else:
|
|
96
|
+
# client_message.error = request_parsing_error
|
|
97
|
+
print_api(request_parsing_error, logger=network_logger, logger_method='error', color='yellow')
|
|
98
|
+
# It doesn't matter if we have HTTP Parsing error, since the request may not be really HTTP, so it is OK
|
|
99
|
+
# not to log it into statistics.
|
|
100
|
+
# statistics_error_list.append(error_message)
|
|
108
101
|
|
|
109
102
|
def finish_thread():
|
|
110
103
|
# At this stage there could be several times that the same socket was used to the service server - we need to
|
|
@@ -184,6 +177,8 @@ def thread_worker_main(
|
|
|
184
177
|
client_message.destination_port = destination_port
|
|
185
178
|
client_message.process_name = process_commandline
|
|
186
179
|
client_message.server_name = server_name
|
|
180
|
+
# Getting current time of message received from client.
|
|
181
|
+
client_message.request_time_received = datetime.now()
|
|
187
182
|
|
|
188
183
|
network_logger.info(f"Initializing Receiver on cycle: {str(cycle_count+1)}")
|
|
189
184
|
# Getting message from the client over the socket using specific class.
|
|
@@ -196,10 +191,10 @@ def thread_worker_main(
|
|
|
196
191
|
if client_received_raw_data:
|
|
197
192
|
# Putting the received message to the aggregating message class.
|
|
198
193
|
client_message.request_raw_bytes = client_received_raw_data
|
|
199
|
-
# Getting current time of message received from client.
|
|
200
|
-
client_message.request_time_received = datetime.now()
|
|
201
194
|
|
|
202
195
|
parse_http()
|
|
196
|
+
if client_message.protocol != 'HTTP':
|
|
197
|
+
pass
|
|
203
198
|
|
|
204
199
|
# Custom parser, should parse HTTP body or the whole message if not HTTP.
|
|
205
200
|
parser_instance = parser(client_message)
|
|
@@ -268,8 +263,13 @@ def thread_worker_main(
|
|
|
268
263
|
client_message.response_list_of_raw_decoded = list()
|
|
269
264
|
# Make HTTP Response parsing only if there was response at all.
|
|
270
265
|
if response_raw_bytes:
|
|
271
|
-
response_raw_decoded =
|
|
272
|
-
|
|
266
|
+
response_raw_decoded, is_http_response, response_parsing_error = (
|
|
267
|
+
HTTPResponseParse(response_raw_bytes).parse())
|
|
268
|
+
|
|
269
|
+
if is_http_response:
|
|
270
|
+
client_message.response_list_of_raw_decoded.append(response_raw_decoded)
|
|
271
|
+
else:
|
|
272
|
+
client_message.response_list_of_raw_decoded.append(None)
|
|
273
273
|
|
|
274
274
|
# So if the socket was closed and there was an error we can break the loop
|
|
275
275
|
if not service_ssl_socket:
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from datetime import datetime
|
|
3
|
+
import json
|
|
3
4
|
|
|
4
5
|
from ...shared_functions import build_module_names, create_custom_logger, get_json
|
|
5
6
|
from ... import message, recs_files
|
|
@@ -87,10 +88,13 @@ class RecorderParent:
|
|
|
87
88
|
# Convert the requests and responses to hex.
|
|
88
89
|
self.convert_messages()
|
|
89
90
|
# Get the message in dict / JSON format
|
|
90
|
-
record_message = get_json(self.class_client_message)
|
|
91
|
+
# record_message = get_json(self.class_client_message)
|
|
92
|
+
record_message_dict: dict = dict(self.class_client_message)
|
|
93
|
+
recorded_message_json_string = json.dumps(record_message_dict)
|
|
91
94
|
|
|
92
95
|
# Since we already dumped the object to dictionary string, we'll just save the object to regular file.
|
|
93
|
-
file_io.write_file(
|
|
96
|
+
file_io.write_file(
|
|
97
|
+
recorded_message_json_string, self.record_file_path, enable_long_file_path=True, **{'logger': self.logger})
|
|
94
98
|
|
|
95
99
|
self.logger.info(f"Recorded to file: {self.record_file_path}")
|
|
96
100
|
|
atomicshop/mitm/message.py
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Union
|
|
3
|
+
|
|
4
|
+
from .. import http_parse
|
|
5
|
+
from ..basics import dicts
|
|
6
|
+
|
|
7
|
+
|
|
1
8
|
class ClientMessage:
|
|
2
9
|
""" A class that will store all the message details from the client """
|
|
3
10
|
def __init__(self):
|
|
4
11
|
self.request_raw_bytes: bytearray = bytearray()
|
|
5
|
-
|
|
6
|
-
self.
|
|
12
|
+
# noinspection PyTypeChecker
|
|
13
|
+
self.request_time_received: datetime = None
|
|
14
|
+
self.request_raw_decoded: Union[http_parse.HTTPRequestParse, any] = None
|
|
7
15
|
self.request_body_parsed = None
|
|
8
16
|
self.request_raw_hex: hex = None
|
|
9
|
-
# self.response_raw_bytes: bytearray = bytearray()
|
|
10
17
|
self.response_list_of_raw_bytes: list = list()
|
|
11
18
|
self.response_list_of_raw_decoded: list = list()
|
|
12
|
-
# self.response_raw_hex: hex = None
|
|
13
19
|
self.response_list_of_raw_hex: list = list()
|
|
14
20
|
self.server_name: str = str()
|
|
15
21
|
self.server_ip: str = str()
|
|
@@ -22,3 +28,23 @@ class ClientMessage:
|
|
|
22
28
|
self.error: str = str()
|
|
23
29
|
self.protocol: str = str()
|
|
24
30
|
self.recorded_file_path: str = str()
|
|
31
|
+
|
|
32
|
+
def __iter__(self):
|
|
33
|
+
# __dict__ returns a dictionary containing the instance's attributes
|
|
34
|
+
for key, value in self.__dict__.items():
|
|
35
|
+
if key == 'request_raw_bytes':
|
|
36
|
+
value = str(value)
|
|
37
|
+
elif key == 'request_time_received':
|
|
38
|
+
value = value.strftime('%Y-%m-%d-%H:%M:%S.%f')
|
|
39
|
+
elif key == 'request_raw_decoded':
|
|
40
|
+
if isinstance(value, http_parse.HTTPRequestParse):
|
|
41
|
+
value = dicts.convert_complex_object_to_dict(value)
|
|
42
|
+
else:
|
|
43
|
+
value = str(value)
|
|
44
|
+
elif key == 'request_body_parsed':
|
|
45
|
+
value = dicts.convert_complex_object_to_dict(value)
|
|
46
|
+
elif key == 'response_list_of_raw_bytes':
|
|
47
|
+
value = [str(bytes_response) for bytes_response in value]
|
|
48
|
+
elif key == 'response_list_of_raw_decoded':
|
|
49
|
+
value = [dicts.convert_complex_object_to_dict(complex_response) for complex_response in value]
|
|
50
|
+
yield key, value
|
atomicshop/mitm/mitm_main.py
CHANGED
|
@@ -38,9 +38,11 @@ def exit_cleanup():
|
|
|
38
38
|
dns.set_connection_dns_gateway_dynamic(use_default_connection=True)
|
|
39
39
|
print_api.print_api("Returned default DNS gateway...", color='blue')
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
RECS_PROCESS_INSTANCE
|
|
43
|
-
|
|
41
|
+
# The process will not be executed if there was an exception in the beginning.
|
|
42
|
+
if RECS_PROCESS_INSTANCE is not None:
|
|
43
|
+
print_api.print_api(RECS_PROCESS_INSTANCE.is_alive())
|
|
44
|
+
RECS_PROCESS_INSTANCE.terminate()
|
|
45
|
+
RECS_PROCESS_INSTANCE.join()
|
|
44
46
|
|
|
45
47
|
|
|
46
48
|
def mitm_server(config_file_path: str):
|
|
@@ -392,8 +394,8 @@ def mitm_server_main(config_file_path: str):
|
|
|
392
394
|
exit_cleanup()
|
|
393
395
|
return 0
|
|
394
396
|
except Exception as e:
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
397
|
+
# The error logger will not be initiated if there will be a problem with configuration file or checks.
|
|
398
|
+
if MITM_ERROR_LOGGER is not None:
|
|
399
|
+
MITM_ERROR_LOGGER.write(e)
|
|
398
400
|
exit_cleanup()
|
|
399
401
|
return 1
|
|
@@ -589,7 +589,7 @@ class DnsServer:
|
|
|
589
589
|
google_dns_ipv4_socket.recvfrom(self.buffer_size_receive)
|
|
590
590
|
except TimeoutError as function_exception_object:
|
|
591
591
|
print_api(function_exception_object, logger=self.logger, logger_method='error',
|
|
592
|
-
traceback_string=True)
|
|
592
|
+
traceback_string=True, oneline=True)
|
|
593
593
|
google_dns_ipv4_socket.close()
|
|
594
594
|
counter += 1
|
|
595
595
|
# Pass the exception.
|
|
@@ -6,6 +6,8 @@ from ...print_api import print_api
|
|
|
6
6
|
from ..loggingw import loggingw
|
|
7
7
|
from ...basics import tracebacks
|
|
8
8
|
|
|
9
|
+
from . import base, ssl_base
|
|
10
|
+
|
|
9
11
|
|
|
10
12
|
class Sender:
|
|
11
13
|
def __init__(
|
|
@@ -67,21 +69,38 @@ class Sender:
|
|
|
67
69
|
# At this point the sending loop finished successfully
|
|
68
70
|
self.logger.info(f"Sent the message to destination.")
|
|
69
71
|
except ConnectionResetError as e:
|
|
72
|
+
destination_address, destination_port = base.get_destination_address_from_socket(self.ssl_socket)
|
|
73
|
+
if self.ssl_socket.server_hostname:
|
|
74
|
+
destination_address = self.ssl_socket.server_hostname
|
|
75
|
+
destination: str = f'{destination_address}:{destination_port}'
|
|
76
|
+
|
|
70
77
|
error_class_type = str(type(e)).replace("<class '", '').replace("'>", '')
|
|
71
78
|
exception_error = tracebacks.get_as_string(one_line=True)
|
|
72
|
-
error_message = (f"Socket Send: Error, Couldn't reach the server - Connection was reset | "
|
|
79
|
+
error_message = (f"Socket Send: {destination}: Error, Couldn't reach the server - Connection was reset | "
|
|
73
80
|
f"{error_class_type}: {exception_error}")
|
|
74
81
|
except (ssl.SSLEOFError, ssl.SSLZeroReturnError, ssl.SSLWantWriteError, TimeoutError) as e:
|
|
82
|
+
destination_address, destination_port = base.get_destination_address_from_socket(self.ssl_socket)
|
|
83
|
+
if self.ssl_socket.server_hostname:
|
|
84
|
+
destination_address = self.ssl_socket.server_hostname
|
|
85
|
+
destination: str = f'{destination_address}:{destination_port}'
|
|
86
|
+
|
|
75
87
|
error_class_type = str(type(e)).replace("<class '", '').replace("'>", '')
|
|
76
88
|
exception_error = tracebacks.get_as_string(one_line=True)
|
|
77
|
-
error_message = f"Socket Send: {error_class_type}: {exception_error}"
|
|
89
|
+
error_message = f"Socket Send: {destination}: {error_class_type}: {exception_error}"
|
|
78
90
|
except Exception as e:
|
|
91
|
+
destination_address, destination_port = base.get_destination_address_from_socket(self.ssl_socket)
|
|
92
|
+
if self.ssl_socket.server_hostname:
|
|
93
|
+
destination_address = self.ssl_socket.server_hostname
|
|
94
|
+
destination: str = f'{destination_address}:{destination_port}'
|
|
95
|
+
|
|
79
96
|
error_class_type = str(type(e)).replace("<class '", '').replace("'>", '')
|
|
80
97
|
exception_error = tracebacks.get_as_string(one_line=True)
|
|
81
98
|
if 'ssl' in error_class_type.lower():
|
|
82
|
-
error_message = f"Socket Send:
|
|
99
|
+
error_message = (f"Socket Send: {destination}: "
|
|
100
|
+
f"SSL UNDOCUMENTED Exception: {error_class_type}{exception_error}")
|
|
83
101
|
else:
|
|
84
|
-
error_message = f"Socket Send:
|
|
102
|
+
error_message = (f"Socket Send: {destination}: "
|
|
103
|
+
f"Error, UNDOCUMENTED Exception: {error_class_type}{exception_error}")
|
|
85
104
|
|
|
86
105
|
if error_message:
|
|
87
106
|
print_api(error_message, logger=self.logger, logger_method='error')
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import ssl
|
|
2
2
|
from dataclasses import dataclass
|
|
3
3
|
|
|
4
|
-
from
|
|
4
|
+
from ..loggingw import loggingw
|
|
5
5
|
from ...domains import get_domain_without_first_subdomain_if_no_subdomain_return_as_is
|
|
6
6
|
from ...print_api import print_api
|
|
7
7
|
|
|
8
|
+
from . import certificator, creator
|
|
9
|
+
|
|
8
10
|
|
|
9
11
|
@dataclass
|
|
10
12
|
class SNIReceivedParameters:
|
|
@@ -43,7 +45,8 @@ class SNISetup:
|
|
|
43
45
|
forwarding_dns_service_ipv4_list___only_for_localhost: list,
|
|
44
46
|
tls: bool,
|
|
45
47
|
domain_from_dns_server: str = None,
|
|
46
|
-
skip_extension_id_list: list = None
|
|
48
|
+
skip_extension_id_list: list = None,
|
|
49
|
+
exceptions_logger: loggingw.ExceptionCsvLogger = None
|
|
47
50
|
):
|
|
48
51
|
self.ca_certificate_name = ca_certificate_name
|
|
49
52
|
self.ca_certificate_filepath = ca_certificate_filepath
|
|
@@ -68,6 +71,7 @@ class SNISetup:
|
|
|
68
71
|
self.domain_from_dns_server: str = domain_from_dns_server
|
|
69
72
|
self.skip_extension_id_list = skip_extension_id_list
|
|
70
73
|
self.tls = tls
|
|
74
|
+
self.exceptions_logger = exceptions_logger
|
|
71
75
|
|
|
72
76
|
self.certificator_instance = None
|
|
73
77
|
|
|
@@ -154,7 +158,8 @@ class SNISetup:
|
|
|
154
158
|
sni_create_server_certificate_for_each_domain=self.sni_create_server_certificate_for_each_domain,
|
|
155
159
|
certificator_instance=self.certificator_instance,
|
|
156
160
|
domain_from_dns_server=self.domain_from_dns_server,
|
|
157
|
-
default_certificate_domain_list=self.default_certificate_domain_list
|
|
161
|
+
default_certificate_domain_list=self.default_certificate_domain_list,
|
|
162
|
+
exceptions_logger=self.exceptions_logger
|
|
158
163
|
)
|
|
159
164
|
ssl_context.set_servername_callback(
|
|
160
165
|
sni_handler_instance.setup_sni_callback(print_kwargs=print_kwargs))
|
|
@@ -172,7 +177,8 @@ class SNIHandler:
|
|
|
172
177
|
sni_create_server_certificate_for_each_domain: bool,
|
|
173
178
|
certificator_instance: certificator.Certificator,
|
|
174
179
|
domain_from_dns_server: str,
|
|
175
|
-
default_certificate_domain_list: list
|
|
180
|
+
default_certificate_domain_list: list,
|
|
181
|
+
exceptions_logger: loggingw.ExceptionCsvLogger
|
|
176
182
|
):
|
|
177
183
|
self.sni_use_default_callback_function_extended = sni_use_default_callback_function_extended
|
|
178
184
|
self.sni_add_new_domains_to_default_server_certificate = sni_add_new_domains_to_default_server_certificate
|
|
@@ -180,6 +186,7 @@ class SNIHandler:
|
|
|
180
186
|
self.certificator_instance = certificator_instance
|
|
181
187
|
self.domain_from_dns_server: str = domain_from_dns_server
|
|
182
188
|
self.default_certificate_domain_list = default_certificate_domain_list
|
|
189
|
+
self.exceptions_logger = exceptions_logger
|
|
183
190
|
|
|
184
191
|
# noinspection PyTypeChecker
|
|
185
192
|
self.sni_received_parameters: SNIReceivedParameters = None
|
|
@@ -202,18 +209,22 @@ class SNIHandler:
|
|
|
202
209
|
sni_ssl_socket: ssl.SSLSocket,
|
|
203
210
|
sni_destination_name: str,
|
|
204
211
|
sni_ssl_context: ssl.SSLContext):
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
212
|
+
|
|
213
|
+
try:
|
|
214
|
+
# Set 'server_hostname' for the socket.
|
|
215
|
+
sni_ssl_socket.server_hostname = sni_destination_name
|
|
216
|
+
|
|
217
|
+
# If 'sni_execute_extended' was set to True.
|
|
218
|
+
if self.sni_use_default_callback_function_extended:
|
|
219
|
+
self.sni_received_parameters = SNIReceivedParameters(
|
|
220
|
+
ssl_socket=sni_ssl_socket,
|
|
221
|
+
destination_name=sni_destination_name,
|
|
222
|
+
ssl_context=sni_ssl_context
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
self.sni_handle_extended(print_kwargs=print_kwargs)
|
|
226
|
+
except Exception as e:
|
|
227
|
+
self.exceptions_logger.write(e)
|
|
217
228
|
|
|
218
229
|
return sni_handle
|
|
219
230
|
|
|
@@ -426,7 +426,6 @@ class SocketWrapper:
|
|
|
426
426
|
listening_socket_list = self.listening_sockets
|
|
427
427
|
|
|
428
428
|
while True:
|
|
429
|
-
# noinspection PyBroadException
|
|
430
429
|
try:
|
|
431
430
|
# Using "select.select" which is currently the only API function that works on all
|
|
432
431
|
# operating system types: Windows / Linux / BSD.
|
|
@@ -503,7 +502,8 @@ class SocketWrapper:
|
|
|
503
502
|
domain_from_dns_server=domain_from_dns_server,
|
|
504
503
|
forwarding_dns_service_ipv4_list___only_for_localhost=(
|
|
505
504
|
self.forwarding_dns_service_ipv4_list___only_for_localhost),
|
|
506
|
-
tls=is_tls
|
|
505
|
+
tls=is_tls,
|
|
506
|
+
exceptions_logger=self.exceptions_logger
|
|
507
507
|
)
|
|
508
508
|
|
|
509
509
|
ssl_client_socket, accept_error_message = \
|
|
@@ -538,7 +538,7 @@ class SocketWrapper:
|
|
|
538
538
|
if not pass_function_reference_to_thread:
|
|
539
539
|
before_socket_thread_worker(
|
|
540
540
|
callable_function=reference_function_name, thread_args=thread_args,
|
|
541
|
-
|
|
541
|
+
exceptions_logger=self.exceptions_logger)
|
|
542
542
|
# If 'pass_function_reference_to_thread' was set to 'True', execute the callable function reference
|
|
543
543
|
# in a new thread.
|
|
544
544
|
else:
|
|
@@ -552,11 +552,8 @@ class SocketWrapper:
|
|
|
552
552
|
error_message=accept_error_message,
|
|
553
553
|
host=domain_from_dns_server,
|
|
554
554
|
process_name=process_name)
|
|
555
|
-
except Exception:
|
|
556
|
-
|
|
557
|
-
logger_method="error", traceback_string=True, logger=self.logger)
|
|
558
|
-
pass
|
|
559
|
-
continue
|
|
555
|
+
except Exception as e:
|
|
556
|
+
self.exceptions_logger.write(e)
|
|
560
557
|
|
|
561
558
|
def _send_accepted_socket_to_thread(self, thread_function_name, reference_args=()):
|
|
562
559
|
# Creating thread for each socket
|
|
@@ -575,17 +572,17 @@ class SocketWrapper:
|
|
|
575
572
|
def before_socket_thread_worker(
|
|
576
573
|
callable_function: callable,
|
|
577
574
|
thread_args: tuple,
|
|
578
|
-
|
|
575
|
+
exceptions_logger: loggingw.ExceptionCsvLogger = None
|
|
579
576
|
):
|
|
580
577
|
"""
|
|
581
578
|
Function that will be executed before the thread is started.
|
|
582
579
|
:param callable_function: callable, function that will be executed in the thread.
|
|
583
580
|
:param thread_args: tuple, arguments that will be passed to the function.
|
|
584
|
-
:param
|
|
581
|
+
:param exceptions_logger: loggingw.ExceptionCsvLogger, logger object that will be used to log exceptions.
|
|
585
582
|
:return:
|
|
586
583
|
"""
|
|
587
584
|
|
|
588
585
|
try:
|
|
589
586
|
callable_function(*thread_args)
|
|
590
587
|
except Exception as e:
|
|
591
|
-
|
|
588
|
+
exceptions_logger.write(e)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
atomicshop/__init__.py,sha256=
|
|
1
|
+
atomicshop/__init__.py,sha256=ZRwxdpiCNZUwHXRtBUzWN6sTrKE1qIh258JoD4OfSDc,124
|
|
2
2
|
atomicshop/_basics_temp.py,sha256=6cu2dd6r2dLrd1BRNcVDKTHlsHs_26Gpw8QS6v32lQ0,3699
|
|
3
3
|
atomicshop/_create_pdf_demo.py,sha256=Yi-PGZuMg0RKvQmLqVeLIZYadqEZwUm-4A9JxBl_vYA,3713
|
|
4
4
|
atomicshop/_patch_import.py,sha256=ENp55sKVJ0e6-4lBvZnpz9PQCt3Otbur7F6aXDlyje4,6334
|
|
@@ -19,7 +19,7 @@ atomicshop/functions.py,sha256=pK8hoCE9z61PtWCxQJsda7YAphrLH1wxU5x-1QJP-sY,499
|
|
|
19
19
|
atomicshop/get_process_list.py,sha256=8cxb7gKe9sl4R6H2yMi8J6oe-RkonTvCdKjRFqi-Fs4,6075
|
|
20
20
|
atomicshop/get_process_name_cmd_dll.py,sha256=CtaSp3mgxxJKCCVW8BLx6BJNx4giCklU_T7USiCEwfc,5162
|
|
21
21
|
atomicshop/hashing.py,sha256=Le8qGFyt3_wX-zGTeQShz7L2HL_b6nVv9PnawjglyHo,3474
|
|
22
|
-
atomicshop/http_parse.py,sha256=
|
|
22
|
+
atomicshop/http_parse.py,sha256=bIrJODFmumfI6uSwWkTtjtJWS-o40kn_eg7J9Mmwr20,10002
|
|
23
23
|
atomicshop/inspect_wrapper.py,sha256=sGRVQhrJovNygHTydqJj0hxES-aB2Eg9KbIk3G31apw,11429
|
|
24
24
|
atomicshop/ip_addresses.py,sha256=Hvi4TumEFoTEpKWaq5WNF-YzcRzt24IxmNgv-Mgax1s,1190
|
|
25
25
|
atomicshop/keyboard_press.py,sha256=1W5kRtOB75fulVx-uF2yarBhW0_IzdI1k73AnvXstk0,452
|
|
@@ -124,11 +124,11 @@ atomicshop/file_io/xmls.py,sha256=zh3SuK-dNaFq2NDNhx6ivcf4GYCfGM8M10PcEwDSpxk,21
|
|
|
124
124
|
atomicshop/mitm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
125
125
|
atomicshop/mitm/config_static.py,sha256=ROAtbibSWSsF3BraUbhu-QO3MPIFqYY5KUKgsQbiSkk,7813
|
|
126
126
|
atomicshop/mitm/config_toml_editor.py,sha256=2p1CMcktWRR_NW-SmyDwylu63ad5e0-w1QPMa8ZLDBw,1635
|
|
127
|
-
atomicshop/mitm/connection_thread_worker.py,sha256=
|
|
127
|
+
atomicshop/mitm/connection_thread_worker.py,sha256=fybUBcZckgF7TC_P1z2yIYGH6ATX7jQEfsQSBuddt2s,16531
|
|
128
128
|
atomicshop/mitm/import_config.py,sha256=_nu8mgA-M4s6dZ8_QWx3x0aVb75upvsCuX_PIUg4X2w,8345
|
|
129
129
|
atomicshop/mitm/initialize_engines.py,sha256=VyJE8QnzlgD3QbX5inz5o6rC3zQ3is9CeTL7-B10g1w,8292
|
|
130
|
-
atomicshop/mitm/message.py,sha256=
|
|
131
|
-
atomicshop/mitm/mitm_main.py,sha256=
|
|
130
|
+
atomicshop/mitm/message.py,sha256=URR5JKSuAT8XmGIkyprEjlPW2GW4ef_gfUz_GgcFseE,2184
|
|
131
|
+
atomicshop/mitm/mitm_main.py,sha256=wEW0UAqxnn9kI4oO5zyNtG04Glmi3hR-C-0W6SpxVWY,22446
|
|
132
132
|
atomicshop/mitm/recs_files.py,sha256=VjgtJF7vy365mBjctwB2bpDYoLMkEeogzF8kbb01dAk,2977
|
|
133
133
|
atomicshop/mitm/shared_functions.py,sha256=jjCDZVQCwQ8hf9QNMe3T8W3ISkfZo4Mm2HtXOJLZYgI,1999
|
|
134
134
|
atomicshop/mitm/statistic_analyzer.py,sha256=mBmwEe68WAjnIskGndQTRldnsAsDHuaOW0O7UXlM3Pc,26702
|
|
@@ -137,7 +137,7 @@ atomicshop/mitm/engines/create_module_template.py,sha256=tRjVSm1sD6FzML71Qbuwvit
|
|
|
137
137
|
atomicshop/mitm/engines/create_module_template_example.py,sha256=X5xhvbV6-g9jU_bQVhf_crZmaH50LRWz3bS-faQ18ds,489
|
|
138
138
|
atomicshop/mitm/engines/__parent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
139
139
|
atomicshop/mitm/engines/__parent/parser___parent.py,sha256=RK2wviepP0oeq7zuLpgkvqvTJtc0r0a7hDGWdV0dGc4,657
|
|
140
|
-
atomicshop/mitm/engines/__parent/recorder___parent.py,sha256=
|
|
140
|
+
atomicshop/mitm/engines/__parent/recorder___parent.py,sha256=xPc_5BGDubPfgNa4z8qBtm8MacDlas_yQNkfNsji46k,4677
|
|
141
141
|
atomicshop/mitm/engines/__parent/responder___parent.py,sha256=7WQeR3UmMnN74bDwn-0nz2OfhXJ3-ClXpNGUFZ7wJUE,12004
|
|
142
142
|
atomicshop/mitm/engines/__reference_general/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
143
143
|
atomicshop/mitm/engines/__reference_general/parser___reference_general.py,sha256=57MEPZMAjTO6xBDZ-yt6lgGJyqRrP0Do5Gk_cgCiPns,2998
|
|
@@ -296,21 +296,21 @@ atomicshop/wrappers/socketw/accepter.py,sha256=hZZKVYlF3LOHQJsSIEKXZUf6QXXWm-Atq
|
|
|
296
296
|
atomicshop/wrappers/socketw/base.py,sha256=evoOIxg5Xff3THJnrVX00D5HobaOpDp6_e_gso7TJmA,2191
|
|
297
297
|
atomicshop/wrappers/socketw/certificator.py,sha256=3CpQKtcW68FSbH6LVSEZTqWBS6Yg_-3K0x4nFkId4UY,12236
|
|
298
298
|
atomicshop/wrappers/socketw/creator.py,sha256=3_OraDkw2DAWZfoSdY3svCGMOIxpjLEEY7NxWd7M5P4,9873
|
|
299
|
-
atomicshop/wrappers/socketw/dns_server.py,sha256=
|
|
299
|
+
atomicshop/wrappers/socketw/dns_server.py,sha256=F-t2ZOrMAS0hZ5AaoTsIEbe7jj0tUathp8gs4CTNDqM,48967
|
|
300
300
|
atomicshop/wrappers/socketw/exception_wrapper.py,sha256=B-X5SHLSUIWToihH2MKnOB1F4A81_X0DpLLfnYKYbEc,7067
|
|
301
301
|
atomicshop/wrappers/socketw/get_process.py,sha256=zKEqh98cB9UDLFhtxVpperfXsCjyIMNANHilDD06p0U,6094
|
|
302
302
|
atomicshop/wrappers/socketw/receiver.py,sha256=XVvWOoeCo3vA0O5p19ryi-hcDIyx382WNG7WzMNVeYk,9322
|
|
303
|
-
atomicshop/wrappers/socketw/sender.py,sha256=
|
|
304
|
-
atomicshop/wrappers/socketw/sni.py,sha256=
|
|
303
|
+
atomicshop/wrappers/socketw/sender.py,sha256=DIkseEsgrcT3wU-orZ4falPTQPG9tsGt4ASQCnXTG5s,5620
|
|
304
|
+
atomicshop/wrappers/socketw/sni.py,sha256=J1kPnQ77XwKN1pO5aOI1c_VfhuivCm95OOaQxMpPuZ0,17627
|
|
305
305
|
atomicshop/wrappers/socketw/socket_client.py,sha256=XC-YaqA1wu0rvWQ9Q99DWLxcycKPkPc72pSnflzalfo,20320
|
|
306
306
|
atomicshop/wrappers/socketw/socket_server_tester.py,sha256=Qobmh4XV8ZxLUaw-eW4ESKAbeSLecCKn2OWFzMhadk0,6420
|
|
307
|
-
atomicshop/wrappers/socketw/socket_wrapper.py,sha256=
|
|
307
|
+
atomicshop/wrappers/socketw/socket_wrapper.py,sha256=jOIux6eedupRtiEKQeaPSBt7xJbJixpBbK1zNcQUDqU,35451
|
|
308
308
|
atomicshop/wrappers/socketw/ssl_base.py,sha256=kmiif84kMhBr5yjQW17p935sfjR5JKG0LxIwBA4iVvU,2275
|
|
309
309
|
atomicshop/wrappers/socketw/statistics_csv.py,sha256=w1AH-zf4mBuT4euf28UKij9ihM-b1BRU9Qfby0QDdqI,2957
|
|
310
310
|
atomicshop/wrappers/winregw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
311
311
|
atomicshop/wrappers/winregw/winreg_network.py,sha256=bQ8Jql8bVGBJ0dt3VQ56lga_1LBOMLI3Km_otvvbU6c,7138
|
|
312
|
-
atomicshop-2.16.
|
|
313
|
-
atomicshop-2.16.
|
|
314
|
-
atomicshop-2.16.
|
|
315
|
-
atomicshop-2.16.
|
|
316
|
-
atomicshop-2.16.
|
|
312
|
+
atomicshop-2.16.30.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
|
|
313
|
+
atomicshop-2.16.30.dist-info/METADATA,sha256=TE56Q_3IHpOLBlD1Tp4N45ZpofIIs0cJmWDd9y4o6mQ,10473
|
|
314
|
+
atomicshop-2.16.30.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
315
|
+
atomicshop-2.16.30.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
|
|
316
|
+
atomicshop-2.16.30.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|