-
Notifications
You must be signed in to change notification settings - Fork 54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add RustdeskPlugin Support #992
base: main
Are you sure you want to change the base?
Conversation
Rustdesk doesn't support Mac as a server and the original android path was not supported as a relative path.
IDK, what happened with the checks, but this is a complete disaster and i barely know what exactly went wrong. Although linting should make some sort of indication. |
|
||
|
||
RemoteAccessLogRecord = create_extended_descriptor([UserRecordDescriptorExtension])( | ||
"remoteaccess/restdesk/log", GENERIC_LOG_RECORD_FIELDS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo here on the record descriptor, should be remoteaccess/rustdesk/log
@Peter-The-Great Should also use pep8 for formatting as the linter is expecting blank lines and some lines are too long. Have reformatted and attached the two code files here if you like |
Alright i have just added the PEP 8 code Style to the code and fixed the typo. |
@@ -0,0 +1,115 @@ | |||
import logging |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import logging | |
from __future__ import annotations | |
|
||
log = logging.getLogger(__name__) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
log = logging.getLogger(__name__) |
SERVER_GLOBS = [ | ||
# Windows >= Windows 7 | ||
"sysvol/Windows/ServiceProfiles/LocalService/AppData/Roaming/RustDesk/log/server/*.log", | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
USER_GLOBS = [ | ||
# Windows | ||
"AppData/Roaming/Rustdesk/log/*.log", | ||
|
||
# Linux | ||
".local/share/logs/RustDesk/server/*.log", | ||
|
||
# Android | ||
"storage/emulated/0/RustDesk/logs/*.log", | ||
|
||
# Mac | ||
"Library/Logs/RustDesk/*.log", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
USER_GLOBS = [ | |
# Windows | |
"AppData/Roaming/Rustdesk/log/*.log", | |
# Linux | |
".local/share/logs/RustDesk/server/*.log", | |
# Android | |
"storage/emulated/0/RustDesk/logs/*.log", | |
# Mac | |
"Library/Logs/RustDesk/*.log", | |
USER_GLOBS = [ | |
# Windows | |
"AppData/Roaming/Rustdesk/log/*.log", | |
# Linux | |
".local/share/logs/RustDesk/server/*.log", | |
# Android | |
"storage/emulated/0/RustDesk/logs/*.log", | |
# Mac | |
"Library/Logs/RustDesk/*.log", |
|
||
assert records[0].ts == datetime(2025, 1, 1, 13, 4, 8, 350802, tzinfo=timezone.utc) | ||
assert records[0].message == "DEBUG src\\server\\connection.rs:983 #1362 Connection opened from REDACTED IP:6074." | ||
assert records[0].source == "sysvol/Windows/ServiceProfiles/LocalService/AppData/Roaming/RustDesk/log/server/TestRustdesk.log" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assert records[0].source == "sysvol/Windows/ServiceProfiles/LocalService/AppData/Roaming/RustDesk/log/server/TestRustdesk.log" | |
assert ( | |
records[0].source | |
== "sysvol/Windows/ServiceProfiles/LocalService/AppData/Roaming/RustDesk/log/server/TestRustdesk.log" | |
) |
user = None | ||
for log_glob in self.SERVER_GLOBS: | ||
for log_file in self.target.fs.path().glob(log_glob): | ||
self.log_files.add((log_file, user)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
user = None | |
for log_glob in self.SERVER_GLOBS: | |
for log_file in self.target.fs.path().glob(log_glob): | |
self.log_files.add((log_file, user)) | |
for log_glob in self.SERVER_GLOBS: | |
for log_file in self.target.fs.path().glob(log_glob): | |
self.log_files.add((log_file, None)) |
def __init__(self, target): | ||
super().__init__(target) | ||
|
||
self.log_files: set[tuple[TargetPath, UserDetails]] = set() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self.log_files: set[tuple[TargetPath, UserDetails]] = set() | |
self.log_files: set[tuple[TargetPath, UserDetails | None]] = set() |
|
||
def test_rustdesk_plugin_log(target_win_users: Target, fs_win: VirtualFilesystem) -> None: | ||
fs_win.map_file( | ||
"sysvol/Windows/ServiceProfiles/LocalService/AppData/Roaming/RustDesk/log/server/TestRustdesk.log", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"sysvol/Windows/ServiceProfiles/LocalService/AppData/Roaming/RustDesk/log/server/TestRustdesk.log", | |
"Windows/ServiceProfiles/LocalService/AppData/Roaming/RustDesk/log/server/TestRustdesk.log", |
|
||
ts, level, source, message = match.groups() | ||
|
||
timestamp = datetime.fromisoformat(ts) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like the ts
parsed from the log file is not a valid ISO format timestamp because of the space between the timestamp and +01:00
. This causes the tests to fail currently.
line = line.strip() | ||
|
||
try: | ||
# Still needs to be checked for Rustdesk implementation | ||
match = re.match(r"\[(.*?)\] (\w+) \[(.*?)\] (.*)", line) | ||
if not match: | ||
raise ValueError("Line does not match expected format") | ||
|
||
ts, level, source, message = match.groups() | ||
|
||
timestamp = datetime.fromisoformat(ts) | ||
message = re.sub(r"\s\s+", " ", f"{level} {source} {message}") | ||
|
||
yield self.RemoteAccessLogRecord( | ||
ts=timestamp, | ||
message=message, | ||
source=log_file, | ||
_target=self.target, | ||
_user=user, | ||
) | ||
|
||
except ValueError as e: | ||
self.target.log.warning("Could not parse log line in file %s: '%s'", log_file, line) | ||
self.target.log.debug("", exc_info=e) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
line = line.strip() | |
try: | |
# Still needs to be checked for Rustdesk implementation | |
match = re.match(r"\[(.*?)\] (\w+) \[(.*?)\] (.*)", line) | |
if not match: | |
raise ValueError("Line does not match expected format") | |
ts, level, source, message = match.groups() | |
timestamp = datetime.fromisoformat(ts) | |
message = re.sub(r"\s\s+", " ", f"{level} {source} {message}") | |
yield self.RemoteAccessLogRecord( | |
ts=timestamp, | |
message=message, | |
source=log_file, | |
_target=self.target, | |
_user=user, | |
) | |
except ValueError as e: | |
self.target.log.warning("Could not parse log line in file %s: '%s'", log_file, line) | |
self.target.log.debug("", exc_info=e) | |
if line := line.strip(): | |
try: | |
# Still needs to be checked for Rustdesk implementation | |
match = re.match(r"\[(.*?)\] (\w+) \[(.*?)\] (.*)", line) | |
if not match: | |
raise ValueError("Line does not match expected format") | |
ts, level, source, message = match.groups() | |
timestamp = datetime.fromisoformat(ts) | |
message = re.sub(r"\s\s+", " ", f"{level} {source} {message}") | |
yield self.RemoteAccessLogRecord( | |
ts=timestamp, | |
message=message, | |
source=log_file, | |
_target=self.target, | |
_user=user, | |
) | |
except ValueError as e: | |
self.target.log.warning("Could not parse log line in file %s: '%s'", log_file, line) | |
self.target.log.debug("", exc_info=e) |
|
||
@export(record=RemoteAccessLogRecord) | ||
def logs(self) -> Iterator[RemoteAccessLogRecord]: | ||
"""Parse Rustdesk log files. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"""Parse Rustdesk log files. | |
"""Parse RustDesk log files. |
def logs(self) -> Iterator[RemoteAccessLogRecord]: | ||
"""Parse Rustdesk log files. | ||
|
||
Rustdesk is remote access software that allows users to connect to a remote computer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rustdesk is remote access software that allows users to connect to a remote computer. | |
RustDesk is a remote desktop application can be used by adversaries to get (persistent) access to a machine. |
The project is open source and can be found at: https://github.com/rustdesk/rustdesk/ | ||
|
||
The log files are stored in different locations, based on the Target OS and client type. | ||
Unlike Anydesk, Rustdesk does have a carry a time zone designator (TZD). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unlike Anydesk, Rustdesk does have a carry a time zone designator (TZD). | |
Unlike AnyDesk, RustDesk does carry a time zone designator (TZD). |
This PR adds support to inspect
Rustdesk
logs on supported targets (#983). I have tested the Plugin on a both a Linux and Windows machine and they do appear to work. However, if there is any issue with the plugin, just let me know right away and I will try to look in to it.