Skip to content

pebmasquerade plugin #1825

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

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from

Conversation

SolitudePy
Copy link
Contributor

Hello, trying my way around os internals & memory :P

(venv) ubuntu@ubuntuPC:~/Dev/volatility3$ vol -f ~/dumps/peb_masq_dump.raw -r json windows.pebmasquerade | jq 'map(select(.Notes != "OK"))'
Volatility 3 Framework 2.26.2
[               
  {
    "EPROCESS_ImageFileName": "powershell_ise",
    "EPROCESS_SeAudit_ImageFileName": "\\Device\\HarddiskVolume3\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell_ise.exe",
    "Notes": "['Potential PEB.ImageFilePath Spoofing: EPROCESS=powershell_ise;PEB=explorer.exe', 'Potential PEB.CommandLine Spoofing: EPROCESS=powershell_ise;PEB=explorer.exe', 'Potential PEB.ImageFilePath Spoofing (via _EPROCESS.SeAuditProcessCreationInfo): EPROCESS=windows/system32/windowspowershell/v1.0/powershell_ise.exe;PEB=windows/explorer.exe']",
    "PEB_CommandLine_Path": "C:\\Windows\\explorer.exe",
    "PEB_ImageFilePath": "C:\\Windows\\explorer.exe",
    "PID": 11096,
    "ProcessName": "powershell_ise",
    "__children": []
  },
  {
    "EPROCESS_ImageFileName": "peb_masquerade",
    "EPROCESS_SeAudit_ImageFileName": "\\Device\\HarddiskVolume3\\Users\\Robot\\Dev\\peb_masquerade.exe",
    "Notes": "['Potential PEB.ImageFilePath Spoofing: EPROCESS=peb_masquerade;PEB=notepad.exe', 'Potential PEB.CommandLine Spoofing: EPROCESS=peb_masquerade;PEB=notepad.exe', 'Potential PEB.ImageFilePath Spoofing (via _EPROCESS.SeAuditProcessCreationInfo): EPROCESS=users/robot/dev/peb_masquerade.exe;PEB=windows/system32/notepad.exe']",
    "PEB_CommandLine_Path": "C:\\windows\\system32\\notepad.exe",
    "PEB_ImageFilePath": "C:\\windows\\system32\\notepad.exe",
    "PID": 12372,
    "ProcessName": "peb_masquerade",
    "__children": []
  }
]

@SolitudePy
Copy link
Contributor Author

added _UNICODE_STRING length checks.
ProcessParameters.CommandLine introduced 2 "false positives" on my test:

(venv) ubuntu@ubuntuPC:~/Dev/volatility3$ vol -f ~/dumps/peb_masq_dump.raw -r json windows.pebmasquerade | jq 'map(select(.Notes != "OK"))'
Volatility 3 Framework 2.26.2
/home/ubuntu/Dev/volatility3/volatility3/framework/deprecation.py:105: FutureWarning: This plugin (PluginRequirement) has been renamed and will be removed in the first release after 2026-06-01. PluginRequirement is to be deprecated. Use VersionRequirement instead.
  warnings.warn(
[rogress:  100.00               PDB scanning finished                        
  {
    "EPROCESS_ImageFileName": "WmiPrvSE.exe",
    "EPROCESS_SeAudit_ImageFileName": "\\Device\\HarddiskVolume3\\Windows\\System32\\wbem\\WmiPrvSE.exe",
    "Notes": "['PEB.CommandLine Length Mismatch: Commandline=C:\\Windows\\system32\\wbem\\wmiprvse.exe, Length=48, MaximumLength=48, Actual=37']",
    "PEB_CommandLine_Path": "C:\\Windows\\system32\\wbem\\wmiprvse.exe",
    "PEB_ImageFilePath": "C:\\Windows\\system32\\wbem\\wmiprvse.exe",
    "PID": 2640,
    "ProcessName": "WmiPrvSE.exe",
    "__children": []
  },
  {
    "EPROCESS_ImageFileName": "audiodg.exe",
    "EPROCESS_SeAudit_ImageFileName": "\\Device\\HarddiskVolume3\\Windows\\System32\\audiodg.exe",
    "Notes": "['PEB.CommandLine Length Mismatch: Commandline=C:\\Windows\\system32\\AUDIODG.EXE 0x540, Length=43, MaximumLength=43, Actual=37']",
    "PEB_CommandLine_Path": "C:\\Windows\\system32\\AUDIODG.EXE",
    "PEB_ImageFilePath": "C:\\Windows\\system32\\AUDIODG.EXE",
    "PID": 11384,
    "ProcessName": "audiodg.exe",
    "__children": []
  }
]

Copy link
Member

@ikelos ikelos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A number of little issues around this one, it feels like a lot of string manipulation that don't necessarily feel robust. I'll give it another look once you've addressed the comments though...

]

@staticmethod
def _get_cmdline_image(cmdline: str) -> Union[str, PureWindowsPath]:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why wouldn't we just return a string in all instances? By returning a path we're making people potentially test whether it's a path object or not? When would we return a string?

return ""

# Regex to extract first .exe ending string (handles quotes, paths, no quotes)
match = re.search(r'(?i)(["\']?)([^"\']*?\.exe)\1(?=\s|$)', cmdline)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels brittle and impenetrable. This will also prevent executables like pat o'malley.exe which I believe would be a legitimate path. Let's not code all this complexity into a regex, but clarify exactly the process we're going through to find the first parameter (which would return the same results whether it ended in .exe or not, so splitting it into two cases seems pointless?).

return ""

@staticmethod
def _are_paths_equal(device_path: str, drive_path: str) -> Tuple[bool, str, str]:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the return values, this feels like it's doing too much? Either people will use the two additional results (and carrying out their own equality test is trivial) or they only care about the equality and unpacking a tuple to get to it is a bit pointless. Consider rethinking what this is trying to achieve...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function is not that trivial because it checks if a windows device path (i.e \Device\HardDIsk03\path) equals to its drive path (i.e C:\path), and both of the new paths are returned as well because they are then used for the note, maybe I should change the function name & description? also you are saying it is better if I simply returned the results and have the caller check if its equal? thats possible too but then _are_paths_equal need to be changed as well to something like _normalize_paths

eprocess_seaudit_imagefilename,
peb_imagefilepath,
peb_cmdline_path_render,
"[" + ", ".join(notes) + "]" if notes else "OK",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't allow programs consuming the results to parse the data easily. Rather than designing the output for human consumption, each boolean should be returned as a field and the UI allowed to display the results as it sees fit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ikelos you mean, every type of note should be a different column? then its a bit hard to supply the values because its not boolean... what I meant to achieve is to create a list as str that can easily be parsed by python and such. but I guess its not the best approach

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, if they're strings that need to be strings, then I guess use them, but the point is putting them in a list rather than each having its own column will make it much harder for other automated systems to make use of the output. Ideally any that could be represented as a boolean should be to make the columns as thin as possible (for humans to read).

Copy link
Contributor Author

@SolitudePy SolitudePy Jun 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont see how it can be each in its own column, but the 'OK' Note with json renderer and a tool like jq like I previewed my test, makes it quite easy to go through results, I dont think it can be converted to human readable grid as long as there are notes... I can remove the notes and then people need to check themselves if names, length etc are not equal but thats also a pain

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants