{
	"id": "8578c917-e2f2-4af5-953b-4293c3f6c338",
	"created_at": "2026-04-06T00:20:00.974809Z",
	"updated_at": "2026-04-10T13:11:48.466259Z",
	"deleted_at": null,
	"sha1_hash": "0f0e69c44de1efcd93891f15686a37532b493c73",
	"title": "Detecting PoshC2 - Indicators of Compromise",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 98656,
	"plain_text": "Detecting PoshC2 - Indicators of Compromise\r\nBy Rob Bone\r\nPublished: 2020-06-17 · Archived: 2026-04-05 17:26:56 UTC\r\nAs a counterpart to the release of PoshC2 version 6.0 we are providing a list of some of its Indicators of\r\nCompromise (IoCs), particularly as used out-of-the-box, as well as some other effective methods for detecting it in\r\nyour environment.\r\nWe also introduce the new PoshC2 Detections GitHub repository\r\nat https://github.com/nettitude/PoshC2_IOCs that will be continually updated as development continues, in order\r\nto assist blue teams with detecting PoshC2, particularly when used by less sophisticated attackers that do not alter\r\nor configure it to change the default IoCs. We encourage the community to contribute to and help update and\r\nimprove this repository.\r\nIt is worth noting that PoshC2 is open source, so while these are IoCs for PoshC2 if used it its default state,\r\nultimately it can be altered either through configuration or by changing the source code itself. The default\r\nconfiguration is subject to change, however where possible the location of that value is pointed out to the reader in\r\norder to allow these values to be monitored and updated, in addition to providing the GitHub repository.\r\nCommunications\r\nOne way to detect PoshC2 is to focus on the communications. Compromised hosts have to communicate with the\r\nC2 server somehow in order to pick up tasks and return task output. This is unavoidable and PoshC2 can currently\r\nonly do this through the use of HTTP(S) requests.\r\nThat isn’t to say this this makes it easy to detect; a huge amount of HTTP traffic is present in most environments\r\nand the flexibility of the protocol allows for traffic to be hidden and routed through legitimate websites using\r\ntechniques such as Domain Fronting and reverse proxies.\r\nAn example of HTTP comms when domain fronting.\r\nAn example of HTTP comms when domain fronting.\r\nSomething very helpful for catching C2 communications is SSL Inspection. By being able to inspect SSL traffic\r\nleaving the perimeter, the contents of that traffic can be checked and statistics acquired for detecting C2\r\ncommunications. Without this, network defenders are largely blind, particularly against domain fronted\r\ncommunications which travel via legitimate third-party websites.\r\nIf SSL Inspection is implemented then the HTTP traffic can be viewed, and while PoshC2 encrypts the contents of\r\nthe HTTP bodies, the HTTP URLs and headers can still be viewed.\r\nURLs\r\nhttps://labs.nettitude.com/blog/detecting-poshc2-indicators-of-compromise/\r\nPage 1 of 9\n\nPoshC2 has two different ways of generating URLs to use for communications. Operators can either use a static\r\nlist of URLs or provide a wordlist from which random URLs will be generated, and these files are stored\r\nat  resources/urls.txt  and  resources/wordlist.txt  respectively, with the static URL list being the default\r\noption. These URLs are then loaded into the database when the project is first created, and a random URL is\r\nchosen by each implant each time it beacons. The default URL list is below:\r\n/adsense/troubleshooter/1631343/\r\n/adServingData/PROD/TMClient/6/8736/\r\n/advanced_search?hl=en-GB\u0026fg=\r\n/async/newtab?ei=\r\n/babel-polyfill/6.3.14/polyfill.min.js=\r\n/bh/sync/aol?rurl=/ups/55972/sync?origin=\r\n/bootstrap/3.1.1/bootstrap.min.js?p=\r\n/branch-locator/search.asp?WT.ac\u0026api=\r\n/business/home.asp\u0026ved=\r\n/business/retail-business/insurance.asp?WT.mc_id=\r\n/cdba?ptv=48\u0026profileId=125\u0026av=1\u0026cb=\r\n/cisben/marketq?bartype=AREA\u0026showheader=FALSE\u0026showvaluemarkers=\r\n/classroom/sharewidget/widget_stable.html?usegapi=\r\n/client_204?\u0026atyp=i\u0026biw=1920\u0026bih=921\u0026ei=\r\n/load/pages/index.php?t=\r\n/putil/2018/0/11/po.html?ved=\r\n/qqzddddd/2018/load.php?lang=en\u0026modules=\r\n/status/995598521343541248/query=\r\n/TOS?loc=GB\u0026hl=en\u0026privacy=\r\n/trader-update/history\u0026pd=\r\n/types/translation/v1/articles/\r\n/uasclient/0.1.34/modules/\r\n/usersync/tradedesk/\r\n/utag/lbg/main/prod/utag.15.js?utv=\r\n/vfe01s/1/vsopts.js?\r\n/vssf/wppo/site/bgroup/visitor/\r\n/wpaas/load.php?debug=false\u0026lang=en\u0026modules=\r\n/web/20110920084728/\r\n/webhp?hl=en\u0026sa=X\u0026ved=\r\n/work/embedded/search?oid=\r\n/GoPro5/black/2018/\r\n/Philips/v902/\r\nWhile these URLs were originally copied from legitimate requests, if you see several of them being repeated to a\r\nsite, particularly if they do not seem relevant to that site and if the response does not make sense, then it could be\r\nPoshC2 beacon traffic.\r\nHTTP Responses\r\nhttps://labs.nettitude.com/blog/detecting-poshc2-indicators-of-compromise/\r\nPage 2 of 9\n\n---\ntitle: 404 Not Found\n---\nPoshC2 also has static HTML responses that it responds with. The default is six HTTP 200 responses and one 404\nresponse. These are stored in files at resources/responses/ and also loaded into the database when the server is\nfirst created. The server responds with a random 200 response to POST requests that do not error or require a\nspecific response, and with the single 404 response to all unexpected URLs or when the C2 server errors. Other\nresponses return context relevant data, such as tasks, implant code and so on.\n\n# Not Found\n\nThe requested URL was not found on this server.\n\n---\nApache (Debian) Server This static HTML file then at resources/responses/404_response.html is an IoC and if returned from a\nwebserver that you are investigating is suggestive of PoshC2. Similarly, the 200_response* files in the same\ndirectory are IoCs if returned by POST requests.\nNote however, that it is recommended that operators change these files before creating a PoshC2 project, as is the\nuse of a C2 proxy, so as with the other indicators the absence of this particular response is not unexpected for a\nPoshC2 installation.\nSSL Certificate\nPoshC2 by default creates a self-signed certificate for its HTTP server, the values for which are stored\nin poshc2/server/Config.py file. These values are not in the ‘normal’ configuration file config.yml and are\nless documented and are therefore harder to change.\nCert_C = \"US\"\nCert_ST = \"Minnesota\"\nCert_L = \"Minnetonka\"\nCert_O = \"Pajfds\"\nCert_OU = \"Jethpro\"\nCert_CN = \"P18055077\"\nCert_SerialNumber = 1000\nCert_NotBefore = 0\nCert_NotAfter = (10 * 365 * 24 * 60 * 60)\nAn experienced operator will not expose their C2 server to the internet, but will instead use a proxy server with a\nvalid certificate and filter firewall traffic to the C2 server that is not from that proxy, however if these steps are not\ntaken and a certificate with the below values is presented then it is another strong indicator that PoshC2 is in use,\nlikely by less sophisticated adversaries.\nhttps://labs.nettitude.com/blog/detecting-poshc2-indicators-of-compromise/\nPage 3 of 9\n\nThe issuer data can be viewed using Chrome and the default values suggest this is a PoshC2 server.\r\nThe issuer data can be viewed using Chrome and the default values suggest this is a PoshC2 server.\r\nJA3 Signatures\r\nAnother method for signaturing C2 traffic without SSL Inspection is to fingerprint the Client Hello packet that\r\ninitialises the TCP connection. The specific bytes that make up the packet are dependent upon the type of\r\nconnection being formed and the underlying packages and methods used to do so.\r\nAs these packets are sent before encryption has been established they are cleartext and can be intercepted and\r\nread. It turns out that the packet contents are quite unique and can be fingerprinted. Salesforce have an excellent\r\nblog post on JA3 fingerprinting, but essentially the details are extracted from the packets that make up this TCP\r\nhandshake and hashed to create a quick and easy signature, that can be used to identify not only that PoshC2 is in\r\nuse, but also the specific implant type.\r\nThe current Windows 10 PoshC2 signatures are below:\r\nPowerShell: c12f54a3f91dc7bafd92cb59fe009a35\r\nSharp: fc54e0d16d9764783542f0146a98b300\r\nJA3 fingerprinting has been incorporated into security products such as Splunk and Darktrace to provide quick\r\nand easy identification of C2 traffic, and can be utilised with these fingerprints. These fingerprints are available\r\nand will be maintained in the PoshC2 Detections GitHub repository.\r\nTelemetry\r\nAnother mechanism for detecting C2 traffic, with or without SSL Inspection, is through the use of telemetry.\r\nPoshC2’s default values for beacon time and jitter in the  config.yml  file are 5 seconds and a 20% jitter, as can\r\nbe seen below, which is both a fast beacon rate and a small jitter, making it relatively easy to detect using this\r\nmethod.\r\nDefaultSleep: \"5s\"\r\nJitter: 0.20\r\nWith these values the implants are going to beacon every 4-6 seconds by default, with an average of 5 seconds.\r\nhttps://labs.nettitude.com/blog/detecting-poshc2-indicators-of-compromise/\r\nPage 4 of 9\n\nAfter capturing some traffic, filtering by the C2 server host and only checking TLS Client Hello packets, we can\r\nsee that the TLS connection is created roughly every five seconds, confirming what we expect.\r\nWe can see the difference between each session initialisation is between 4 and 6 seconds.\r\nWe can see the difference between each session initialisation is between 4 and 6 seconds.\r\nBy exploring this small sample of data, we can determine that the average time between the requests is 5.05\r\nseconds, with a standard deviation of 0.81 or 16%, close to the 5 second beacon with the 20% jitter we expect\r\nfrom PoshC2’s defaults.\r\nSecurity products that can provide telemetry data, e.g. Splunk can be used to detect C2 traffic in this way by\r\nchecking for repetitive beacons at a relatively fixed frequency, whether it’s at the above defaults for PoshC2 or at\r\nany frequency, given that it is configurable.\r\nPowerShell Implant\r\nPoshC2 has three implant types; PowerShell, C#, and Python, with the latter being a lightweight implant type\r\nmostly intended for compromising *nix hosts.\r\nThe PowerShell Implant runs by loading  System.Management.Automation.dll , the engine\r\nbehind  PowerShell.exe , into the desired process and executing PowerShell commands directly using this DLL.\r\nThe PowerShell implant supports full PowerShell execution from any process (here netsh.exe) by loading\r\nSystem.Management.Automation.dll.\r\nThe PowerShell implant supports full PowerShell execution from any process (here netsh.exe) by loading\r\nSystem.Management.Automation.dll.\r\nWhile this does not utilise  PowerShell.exe,  bypassing many restrictions and controls, it is still subject to\r\nPowerShell specific constraints such as Constrained Language mode and ScriptBlock logging. The latter, in\r\nparticular, can be used to detect PoshC2 and any other malicious PowerShell commands, whether\r\nvia  PowerShell.exe  or otherwise.\r\nNote, however, that ScriptBlock logging was only enabled in PowerShell v5.0 and above, so if PowerShell v2.0 is\r\navailable on the target then a downgrade attack can be performed and PowerShell 2.0 used, bypassing Constrained\r\nLanguage mode, ScriptBlock logging, AMSI and other controls added in v5.0.\r\nPS Logging\r\nEnabling ScriptBlock logging and Transcript Logging for PowerShell allows logging of processes running\r\nPowerShell commands.\r\nThere are multiple IoCs here, not least that the Host Application is not  PowerShell.exe , as should be expected,\r\nbut instead  netsh.exe .\r\nPowerShell transcripts provide valuable information. Alerting on Host Applications that are not PowerShell.exe\r\nis a good way to find PowerShell implants from any C2 framework.\r\nhttps://labs.nettitude.com/blog/detecting-poshc2-indicators-of-compromise/\r\nPage 5 of 9\n\nPowerShell transcripts provide valuable information. Alerting on Host Applications that are not PowerShell.exe is\r\na good way to find PowerShell implants from any C2 framework.\r\nSimilarly in the Event Viewer for ScriptBlock logging:\r\nPowerShell ScriptBlock logging can reveal a wealth of information, here including the beacon URLs for\r\nPoshC2 and again netsh.exe as a host process.\r\nPowerShell ScriptBlock logging can reveal a wealth of information, here including the beacon URLs for PoshC2\r\nand again netsh.exe as a host process.\r\nThis also includes the ‘command line’ of the ScriptBlock being executed, which includes the beacon URLs from\r\nwhich a random element is being chosen, therefore listing all the C2 URLs that are in use by this implant.\r\nAside from the wealth of information ScriptBlock logging provides for any threat hunter, an event command line\r\nspecific to PoshC2 that can be used to identify the PowerShell implant is below:\r\nThe $ServerClean variable is specific to PoshC2 and a clear IoC.\r\nThe $ServerClean variable is specific to PoshC2 and a clear IoC.\r\nCommandLine= $ServerClean = Get-Random $ServerURLS\r\nThis ScriptBlock is part of the beaconing process and will be repeated frequently in the Event Viewer making it\r\neasy to identify.\r\nSystem.Management.Automation.dll\r\nAs mentioned earlier, the PowerShell implant does not function by invoking  PowerShell.exe , but instead by\r\nloading  System.Management.Automation.dll  into the implant process.\r\nThis means that this is an IoC, and if we find a process that should not have this DLL loaded, particularly if it is an\r\nunmanaged code binary (so not .NET) then it is highly likely that this is a process that has been injected into by a\r\nPowerShell implant, PoshC2 or otherwise.\r\nSystem.Management.Automation.dll, the engine behind PowerShell, is a .NET library.\r\nSystem.Management.Automation.dll, the engine behind PowerShell, is a .NET library.\r\nnetsh.exe is a C++ binary and should not be loading .NET libraries.\r\nnetsh.exe is a C++ binary and should not be loading .NET libraries.\r\nWe can see this DLL loaded into an implant process using Process Hacker:\r\nSystem.Management.Automation.dll loaded into netsh.exe.\r\nSystem.Management.Automation.dll loaded into netsh.exe.\r\nSimilarly we can view the .NET Assemblies in the process:\r\nhttps://labs.nettitude.com/blog/detecting-poshc2-indicators-of-compromise/\r\nPage 6 of 9\n\nWe can view the .NET Assemblies in the netsh.exe process and see PowerShell is loaded.\r\nWe can view the .NET Assemblies in the netsh.exe process and see PowerShell is loaded.\r\nThis tab shouldn’t even be present for a genuine  netsh.exe  process as it is unmanaged code!\r\nThe module is not loaded in a genuine netsh process and the .NET tabs are not available.\r\nThe module is not loaded in a genuine netsh process and the .NET tabs are not available.\r\nAn operator can be smarter about their migration by injecting into .NET processes, however it is still unlikely that\r\na legitimate process (that isn’t  PowerShell.exe ) would load  System.Management.Automation.dll , so this is a\r\ngreat IoC to look out for in your environment.\r\nThis can be implemented at scale by searching for loaded modules in an EDR product, for example in\r\nCarbonBlack with a query of:\r\nmodload:System.Management.Automation* AND -process_name:powershell.exe AND –\r\nprocess_name:powershell_ise.exe\r\nThis searches for process\r\nwith  System.Management.Automation.dll  or  System.Management.Automation.ni.dll  (the Native Image\r\nversion) loaded into a process when that process is not  PowerShell.exe  or  PowerShell_ISE.exe . Other\r\nlegitimate exclusions may need to be added for your particular environment.\r\nHere we can see various processes that have loaded System.Management.Automation.dll into memory that are\r\nlikely implants.\r\nHere we can see various processes that have loaded System.Management.Automation.dll into memory that are\r\nlikely implants.\r\nC# Implant\r\nThe C# or Sharp implant is PoshC2’s ‘next gen’ implant, written (unsurprisingly) in C#. The key difference from a\r\ndetection perspective is that this implant does not require loading  System.Management.Automation.dll  in order\r\nto function. Most of the functionality of the C# implant is custom-written and while\r\nit can load  System.Management.Automation.dll  in order to execute PowerShell, this is an operator decision and\r\nis by no means necessary.\r\nA similar process to the above can be applied, but is a little harder to implement. .NET processes load\r\nthe  mscoree.dll  library which is the core library behind the .NET CLR (Command Language Runtime), so\r\nagain any unmanaged code processes that are loading this library could have been migrated into. The issue here is\r\nfinding these processes, as it’s not as simple as searching for just ‘module loaded and process name is not\r\npowershell.exe’.\r\nA blacklist can be created of common target processes that are unmanaged, always available and should not be\r\nloading the .NET runtime, and these can be monitored, as well as noting this during manual triage.\r\nhttps://labs.nettitude.com/blog/detecting-poshc2-indicators-of-compromise/\r\nPage 7 of 9\n\nImplant loads mscoree.dll if it is not already present in the process – another IoC if the process is supposed to\r\nbe unmanaged.\r\nA C# implant loads mscoree.dll if it is not already present in the process – another IoC if the process is supposed\r\nto be unmanaged.\r\nNote that the PowerShell implant will also load this library as it is also a .NET process, however the presence\r\nof  System.Management.Automation.dll  marks it as an implant that can run PowerShell.\r\nThe C# implant has the ability to load compiled binaries into memory over C2 and run them, which is extremely\r\npowerful. There are indicators of this however, as a new virtual runspace is created for each module and their\r\nnamespace is listed in the AppDomain to which they are loaded.\r\nViewing the .NET Assemblies in Process Explorer or Process Hacker for example then reveals what modules have\r\nbeen run.\r\nIn the C# implant loaded modules have their namespace visible in the AppDomain, making it clear what has\r\nbeen loaded into the implant.\r\nIn the C# implant loaded modules have their namespace visible in the AppDomain, making it clear what has been\r\nloaded into the implant.\r\nAbove we can see the Core and dropper_cs modules that make up the core functionality of the C# implant, as well\r\nas some native modules from Microsoft that are required to run. These modules will always be present in the\r\nPoshC2 C# implant and are a clear IoC. We also see Seatbelt and SharpUp, two common C# offensive modules\r\nfrom SpectreOps, and we can surmise that they have been on the target.\r\nIn General\r\nMigration\r\nWe have used  netsh.exe  as the example implant process in this post and that is for a good reason. The default\r\nmigration process for PoshC2 in the C# and PowerShell implants is  C:\\Windows\\System32\\netsh.exe , so when\r\nthe  migrate  or  inject-shellcode  commands are used and a specific process ID or name is not set, then a\r\nnew  netsh.exe  process is spawned and migrated into.\r\nThis itself is a common IoC for PoshC2, as  netsh.exe  is not typically frequently run in environments, and\r\ncertainly not on most end user’s hosts. Therefore, if there is a sudden uptick in the number of these processes\r\nbeing run in the environment or if several are running on a host then it could be worth investigating.\r\nPersistence\r\nPoshC2 has three quick persistence commands available to the PowerShell implant. Each of these installs\r\na  PowerShell.exe  one liner payload to the registry in the key\r\nat  HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\themes  with a\r\nname Wallpaper777, Wallpaper555 or Wallpaper666, depending on the command being run.\r\nhttps://labs.nettitude.com/blog/detecting-poshc2-indicators-of-compromise/\r\nPage 8 of 9\n\nThis payload is then triggered by either:\r\nA registry key at  HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\run  with the name  IEUpdate\r\nA Scheduled Task, also with the name  IEUpdate\r\nA shortcut file placed at  %APPDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\IEUpdate.lnk\r\nAll of these can be alerted upon and used to determine that the adversary using PoshC2, in addition to alerting on\r\nthe invocation of  PowerShell.exe  with encoded parameters, and so on.\r\nBinary payloads\r\nSome of the more common payloads that are dropped on targets are the PoshC2 executables and DLLs that can be\r\nrun using  rundll32.exe .\r\nFor the DLLs, there are different versions for PowerShell and Sharp implants across versions 2 and 4 of\r\nPowerShell and x86 and x64 bit architectures, however all the DLLs have a single entry-point common to\r\nall:  VoidFunc .\r\nAll the DLL payloads have the same single entry point of VoidFunc.\r\nAll the DLL payloads have the same single entry point of VoidFunc.\r\nThis entry-point is hard-coded in PoshC2 and cannot be changed without hacking the compiled binary itself.\r\nFor the common executable and DLL payloads we’ve also added Yara rules for detecting them. These are based on\r\nsignaturable parts of the binaries that will not change across different installs of PoshC2, for example with\r\ndifferent comms options. These are also available in the new PoshC2 Detections GitHub repository.\r\nIn Summary\r\nWe’ve looked at a few different detections for catching PoshC2 when used out-of-the-box. Using these in your\r\nenvironment will help protect against the less sophisticated users of PoshC2 in addition to further understanding\r\nhow the tool works.\r\nAny new detections or amendments can be added to the https://github.com/nettitude/PoshC2_IOCs repository and\r\nwe encourage the community to add their own detections or rules and configurations for other security tools to\r\nhelp build a centralised data store for everyone.\r\nSource: https://labs.nettitude.com/blog/detecting-poshc2-indicators-of-compromise/\r\nhttps://labs.nettitude.com/blog/detecting-poshc2-indicators-of-compromise/\r\nPage 9 of 9",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://labs.nettitude.com/blog/detecting-poshc2-indicators-of-compromise/"
	],
	"report_names": [
		"detecting-poshc2-indicators-of-compromise"
	],
	"threat_actors": [],
	"ts_created_at": 1775434800,
	"ts_updated_at": 1775826708,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/0f0e69c44de1efcd93891f15686a37532b493c73.pdf",
		"text": "https://archive.orkl.eu/0f0e69c44de1efcd93891f15686a37532b493c73.txt",
		"img": "https://archive.orkl.eu/0f0e69c44de1efcd93891f15686a37532b493c73.jpg"
	}
}