Skip to content
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 cPanel lastlogin parser #317

Merged
merged 16 commits into from
Aug 15, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
72 changes: 72 additions & 0 deletions dissect/target/plugins/apps/webhosting/cpanel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import re
from datetime import datetime
from typing import Iterator

from dissect.target.exceptions import UnsupportedPluginError
from dissect.target.helpers.record import TargetRecordDescriptor
from dissect.target.plugin import Plugin, export

CPanelLastloginRecord = TargetRecordDescriptor(
"application/log/cpanel/lastlogin",
[
("datetime", "ts"),
("string", "user"),
("net.ipaddress", "remote_ip"),
],
)

CPANEL_LASTLOGIN = ".lastlogin"
CPANEL_LOGS_PATH = "/usr/local/cpanel/logs"
CPANEL_PATTERN = re.compile(r"([^\s]+) # ([0-9]{4}-[0-9]{2}-[0-9]{2}) ([0-9]{2}:[0-9]{2}:[0-9]{2}) ([+-][0-9]{4})")
Zawadidone marked this conversation as resolved.
Show resolved Hide resolved


class CPanelPlugin(Plugin):
# TODO: Parse other log files https://support.cartika.com/portal/en/kb/articles/whm-cpanel-log-files-and-locations
__namespace__ = "cpanel"

def check_compatible(self) -> None:
if not self.target.fs.path(CPANEL_LOGS_PATH).exists():
raise UnsupportedPluginError("No cPanel log path found")

@export(record=CPanelLastloginRecord)
def lastlogin(self) -> Iterator[CPanelLastloginRecord]:
"""Return the content of the cPanel lastlogin file.

The lastlogin files tracks successful cPanel interface logons. New logon events are only tracked
if the IP-address of the logon changes.

References:
- https://forums.cpanel.net/threads/cpanel-control-panel-last-login-clarification.579221/
- https://forums.cpanel.net/threads/lastlogin.707557/
"""
for user_details in self.target.user_details.all_with_home():
if (lastlogin := user_details.home_path.joinpath(CPANEL_LASTLOGIN)).exists():
try:
for index, line in enumerate(lastlogin.open("rt")):
line = line.strip()
if not line:
continue

events = CPANEL_PATTERN.findall(line)

if events:
Zawadidone marked this conversation as resolved.
Show resolved Hide resolved
for event in events:
remote_ip, date, time, utc_offset = event

timestamp = datetime.strptime(f"{date} {time} {utc_offset}", "%Y-%m-%d %H:%M:%S %z")

yield CPanelLastloginRecord(
ts=timestamp,
user=user_details.user.name,
remote_ip=remote_ip,
_target=self.target,
)
else:
self.target.log.warning(
"The cPanel lastlogin line number %s is malformed: %s", index + 1, lastlogin
)

except Exception:
self.target.log.warning(
"An error occurred parsing cPanel lastlogin line number %i in file: %s", index + 1, lastlogin
)
5 changes: 5 additions & 0 deletions tests/data/plugins/apps/webhosting/cpanel/lastlogin
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
8.8.8.8 # 2023-06-27 14:22:13 +0100
8.8.8.8 # 2023-06-28 14:13:37 +0200
8.8.8.8 # 2023-06-28 14:13:37 +02008.8.8.8 # 2023-06-28 14:13:37 +0200
8.8.8.8 # 2016-10-04 16:40:39 -0500
8.8.8.8 # 2016-10-27 14:33:05 -0500
23 changes: 23 additions & 0 deletions tests/test_plugins_apps_webhosting_cpanel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from datetime import datetime, timezone

from dissect.target.plugins.apps.webhosting.cpanel import CPanelPlugin

from ._utils import absolute_path


def test_cpanel_plugin(target_unix_users, fs_unix):
Zawadidone marked this conversation as resolved.
Show resolved Hide resolved
data_file = absolute_path("data/plugins/apps/webhosting/cpanel/lastlogin")
fs_unix.map_file("/home/user/.lastlogin", data_file)

fs_unix.makedirs("/usr/local/cpanel/logs")

target_unix_users.add_plugin(CPanelPlugin)

results = list(target_unix_users.cpanel.lastlogin())

record = results[0]

assert len(results) == 6
assert record.ts == datetime(2023, 6, 27, 13, 22, 13, tzinfo=timezone.utc)
assert record.user == "user"
assert record.remote_ip == "8.8.8.8"