{"id":160,"date":"2021-05-16T19:50:45","date_gmt":"2021-05-16T17:50:45","guid":{"rendered":"https:\/\/theredwindows.net\/?p=160"},"modified":"2021-07-30T19:18:07","modified_gmt":"2021-07-30T17:18:07","slug":"contournement-des-protections-de-powershell-1-ep-amsi-clm","status":"publish","type":"post","link":"https:\/\/theredwindows.net\/index.php\/2021\/05\/16\/contournement-des-protections-de-powershell-1-ep-amsi-clm\/","title":{"rendered":"Contournement des Protections de PowerShell #1\u00a0: EP, AMSI, CLM"},"content":{"rendered":"\n<p>Microsoft n\u2019\u00e9tait clairement pas aveugle concernant l\u2019usage malveillant qu\u2019il \u00e9tait fait de son nouveau Shell. Ainsi, pour aider les d\u00e9fenseurs, l\u2019\u00e9quipe PowerShell a travaill\u00e9 sur diff\u00e9rentes protections (sur lesquelles vous pouvez bri\u00e8vement vous renseigner en consultant l\u2019article de documentation sur PowerShell, disponible sur le blog). Chacune permettant de limiter l\u2019impact de PowerShell sur un environnement Windows. Dans cet article, nous traiterons des contournements des r\u00e8gles d\u2019ex\u00e9cutions, de l&#8217; &#8220;AntiMalware Scan Interface&#8221; et du mode de langage contraint.<\/p>\n\n\n\n<h2>PowerShell depuis C#<\/h2>\n\n\n\n<p>A plusieurs reprises dans l\u2019article, on aura la n\u00e9cessit\u00e9 de contr\u00f4ler les instructions que PowerShell ex\u00e9cute. Pour r\u00e9soudre ce probl\u00e8me, on va simplement construire un programme C# qui utilise <code>System.Management.Automation.dll<\/code>. On va dans un premier temps indiquer que le programme utilisera les namespaces <code>System.Management.Automation<\/code> pour le c\u0153ur de PowerShell et <code>System.Management.Automation.Runspaces<\/code> qui permet de rendre persistante les entr\u00e9es (si on cr\u00e9e une variable, elle est sauvegard\u00e9e en m\u00e9moire). On d\u00e9finit deux m\u00e9thodes, la premi\u00e8re lance simplement une commande PowerShell unique en utilisant un objet de la classe PowerShell et la m\u00e9thode <code><code data-enlighter-language=\"powershell\" class=\"EnlighterJSRAW\">.Invoke()<\/code><\/code>. La deuxi\u00e8me cr\u00e9e un runspace, puis lui ajoute une pipeline qui permet l\u2019ex\u00e9cution d\u2019une commande PowerShell via la m\u00e9thode d\u00e9j\u00e0 cit\u00e9e.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" width=\"636\" height=\"645\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/CustomPWSH1.png\" alt=\"\" class=\"wp-image-161\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/CustomPWSH1.png 636w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/CustomPWSH1-296x300.png 296w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/CustomPWSH1-400x406.png 400w\" sizes=\"(max-width: 636px) 100vw, 636px\" \/><\/figure><\/div>\n\n\n\n<h2>ExecutionPolicy<\/h2>\n\n\n\n<p>Officiellement l\u2019ExecutionPolicy est d\u00e9fini ainsi\u00a0: &#8220;La strat\u00e9gie d\u2019ex\u00e9cution de PowerShell est une fonctionnalit\u00e9 de s\u00e9curit\u00e9 qui contr\u00f4le les conditions dans lesquelles PowerShell charge les fichiers de configuration et ex\u00e9cute des scripts&#8221;. C\u2019est cette derni\u00e8re qui vous interdit donc, dans un syst\u00e8me natif, d\u2019effectuer des commandes comme <code>PS>.\\script.ps1<\/code> . En r\u00e9alit\u00e9 il ne s\u2019agit pas vraiment d\u2019une protection, un script n\u2019est rien de moins qu\u2019une cha\u00eene de caract\u00e8re interpr\u00e9t\u00e9e pr\u00e9sente dans un fichier. Un contournement de cette restriction serait <code><code data-enlighter-language=\"powershell\" class=\"EnlighterJSRAW\">Invoke-Expression $(Get-Content .\\script.ps1)<\/code><\/code> ou de faire un DownloadCradle. S\u2019il est souhait\u00e9 de pouvoir s\u2019affranchir directement au lancement, PowerShell propose un argument <code>-ExecutionPolicy<\/code> (abr\u00e9g\u00e9 <code>exec<\/code>) qui permet de contr\u00f4ler les r\u00e8gles d\u2019ex\u00e9cutions adopt\u00e9es pour la session qui s\u2019ouvrira. Il n\u2019est absolument pas n\u00e9cessaire d\u2019\u00eatre administrateur pour pouvoir influer sur cet argument, ainsi lorsqu\u2019on lui fournit la valeur &#8220;Bypass&#8221;, PowerShell appliquera cette ExecutionPolicy qui nous autorise le lancement de script. S\u2019il est souhait\u00e9 de contourner cette restriction en &#8220;RunTime&#8221;, alors on peut utiliser ceci\u00a0:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">Set-ExecutionPolicy Bypass -Force -Scope Process\n\n# ou pour faire styl\u00e9\n\n$ctx = $ExecutionContext.GetType().GetField(\"_context\",\"NonPublic,Instance\").GetValue($ExecutionContext)\n$ctx.GetType().GetField(\"_authorizationManager\",\"NonPublic,Instance\").SetValue($ctx, (New-Object System.Management.Automation.AuthorizationManager(\"Microsoft.PowerShell\")))<\/pre>\n\n\n\n<p>Je ne d\u00e9taillerai pas l\u2019origine de ces courtes lignes et pourquoi elles permettent de contourner la restriction souhait\u00e9e car ce n\u2019est pas le plus int\u00e9ressant et comme mentionn\u00e9, l\u2019ExecutionPolicy est une restriction et non une protection. De surcro\u00eet en RedTeam on \u00e9vite le plus possible de d\u00e9poser des fichiers\/binaires sur le disque.<\/p>\n\n\n\n<h2>AMSI<\/h2>\n\n\n\n<p>L\u2019AMSI (pour &#8220;AntiMalware Scan Interface&#8221;) est une solution apport\u00e9e par Microsoft pour pouvoir analyser le contenu de la m\u00e9moire afin de parer au mieux les attaques usant de langage de Scripting tel PowerShell, Jscript, VBA et plus r\u00e9cemment certaines API .NET. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" width=\"727\" height=\"321\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Implementation.jpg\" alt=\"\" class=\"wp-image-187\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Implementation.jpg 727w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Implementation-300x132.jpg 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Implementation-400x177.jpg 400w\" sizes=\"(max-width: 727px) 100vw, 727px\" \/><\/figure><\/div>\n\n\n\n<p>Il s\u2019agit d\u2019une DLL situ\u00e9e en <code>C:\\Windows\\System32\\amsi.dll<\/code> et qui n\u2019a pas \u00e9t\u00e9 con\u00e7ue en C#. Pour PowerShell, son impl\u00e9mentation se situe comme habituellement dans <code>System.Management.Automation.dll<\/code>, et cette derni\u00e8re est une dll .NET. On lance ILSpy et on d\u00e9compile la dll sus-mentionn\u00e9e depuis GAC et on regarde la classe <code>AmsiUtils<\/code>. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" width=\"938\" height=\"597\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/amsi3.png\" alt=\"\" class=\"wp-image-162\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/amsi3.png 938w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/amsi3-300x191.png 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/amsi3-768x489.png 768w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/amsi3-400x255.png 400w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/amsi3-800x509.png 800w\" sizes=\"(max-width: 938px) 100vw, 938px\" \/><\/figure><\/div>\n\n\n\n<p>Cette derni\u00e8re charge plusieurs fonctions de <code>amsi.dll<\/code>. Certaines parties de la classe semblent plus int\u00e9ressantes que d\u2019autres: la d\u00e9finition des variables de la classe et la m\u00e9thode <code>ScanContent<\/code>. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" width=\"505\" height=\"397\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/amsi5.png\" alt=\"\" class=\"wp-image-163\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/amsi5.png 505w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/amsi5-300x236.png 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/amsi5-400x314.png 400w\" sizes=\"(max-width: 505px) 100vw, 505px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" width=\"853\" height=\"421\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/amsi4.png\" alt=\"\" class=\"wp-image-164\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/amsi4.png 853w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/amsi4-300x148.png 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/amsi4-768x379.png 768w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/amsi4-400x197.png 400w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/amsi4-800x395.png 800w\" sizes=\"(max-width: 853px) 100vw, 853px\" \/><\/figure><\/div>\n\n\n\n<p>On charge dans DNSpy notre runspace PowerShell ainsi que PowerShell.exe et ajoutons les points d\u2019arr\u00eat suivants directement dans <code>Sysem.Management.Automation<\/code>:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" width=\"1024\" height=\"188\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyAMSI1-1024x188.png\" alt=\"\" class=\"wp-image-165\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyAMSI1-1024x188.png 1024w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyAMSI1-300x55.png 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyAMSI1-768x141.png 768w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyAMSI1-400x73.png 400w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyAMSI1-800x147.png 800w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyAMSI1.png 1397w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" width=\"1024\" height=\"298\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyAMSI2-1024x298.png\" alt=\"\" class=\"wp-image-166\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyAMSI2-1024x298.png 1024w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyAMSI2-300x87.png 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyAMSI2-768x224.png 768w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyAMSI2-400x117.png 400w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyAMSI2-800x233.png 800w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyAMSI2.png 1383w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n\n<p>Ainsi les points d\u2019arr\u00eat suivants dans notre m\u00e9thode <code>RunspaceExec<\/code>:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" width=\"776\" height=\"623\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyMain.png\" alt=\"\" class=\"wp-image-168\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyMain.png 776w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyMain-300x241.png 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyMain-768x617.png 768w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyMain-400x321.png 400w\" sizes=\"(max-width: 776px) 100vw, 776px\" \/><\/figure><\/div>\n\n\n\n<p>En suivant l\u2019ex\u00e9cution d\u2019une commande, on remarque que notre commande est pass\u00e9e \u00e0 <code>ScanContent<\/code> qui dans un premier temps va v\u00e9rifier si l\u2019AMSI est bien en place avant que l\u2019antivirus analyse notre instruction et retourne si oui ou non elle a le droit d\u2019\u00eatre ex\u00e9cut\u00e9e.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" width=\"1024\" height=\"507\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug6-1024x507.png\" alt=\"\" class=\"wp-image-169\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug6-1024x507.png 1024w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug6-300x148.png 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug6-768x380.png 768w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug6-400x198.png 400w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug6-800x396.png 800w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug6.png 1124w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n\n<p>On peut alors \u00e9tudier le comportement de PowerShell lorsque des commandes plus agressives sont donn\u00e9es.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"1024\" height=\"203\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/GetRekt-1024x203.png\" alt=\"\" class=\"wp-image-170\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/GetRekt-1024x203.png 1024w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/GetRekt-300x60.png 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/GetRekt-768x152.png 768w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/GetRekt-400x79.png 400w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/GetRekt-800x159.png 800w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/GetRekt.png 1219w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"1024\" height=\"157\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Detected-1024x157.png\" alt=\"\" class=\"wp-image-171\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Detected-1024x157.png 1024w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Detected-300x46.png 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Detected-768x117.png 768w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Detected-400x61.png 400w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Detected-800x122.png 800w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Detected.png 1288w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>La technique mise en place n\u2019est finalement pas magique, si la fonction <code>ScanBuffer<\/code> n\u2019est pas appel\u00e9e, l\u2019antivirus est totalement aveugle \u00e0 ce qu\u2019il se passe. On remarque en revanche que certains court-circuits existent. Si l\u2019AMSI n\u2019est pas correctement initialis\u00e9e, la variable de classe <code>amsiInitFailed<\/code> est mise a <code>true<\/code> qui r\u00e9sultera en le retour syst\u00e9matique de <code>AMSI_RESULT NOT_DETECTED<\/code>. Or nous avons le total contr\u00f4le sur la m\u00e9moire de notre processus, mieux encore, les possibilit\u00e9s d\u2019interaction avec .NET nous permettent de modifier le comportement intrins\u00e8que de PowerShell. Construisons un Bypass. Comme vous l\u2019aurez peut-\u00eatre remarqu\u00e9, la classe <code>AmsiUtils<\/code> est une classe priv\u00e9e, c\u2019est-\u00e0-dire qu\u2019elle n\u2019est pas accessible ais\u00e9ment depuis l\u2019ext\u00e9rieur de la dll. En revanche, le type est toujours utilisable ce qui nous permet d\u2019acc\u00e9der \u00e0 la classe <code>AmsiUtils<\/code> en utilisant une r\u00e9f\u00e9rence \u00e0 l\u2019<code>assembly<\/code> ce qui peut \u00eatre fait comme ceci\u00a0:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils')<\/pre>\n\n\n\n<p>En utilisant la m\u00e9thode <code><code data-enlighter-language=\"powershell\" class=\"EnlighterJSRAW\">.GetField()<\/code><\/code>, on peut acc\u00e9der \u00e0 <code>amsiInitFailed<\/code>, ce qui nous permet de manipuler sa valeur:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed', 'NonStatic,Public').SetValue($null, $true)<\/pre>\n\n\n\n<p>Ce bypass nous provient de <a rel=\"noreferrer noopener\" href=\"https:\/\/twitter.com\/matterpreter\" data-type=\"URL\" data-id=\"https:\/\/twitter.com\/matterpreter\" target=\"_blank\">Matt Graebers<\/a>, qui l&#8217;a publi\u00e9 dans un tweet et a donc utilis\u00e9 tout les moyens possibles pour le maintenir concis. Pour l\u2019offusquer par exemple, changer l\u2019acc\u00e9l\u00e9rateur de type ou la classe pour acc\u00e9der \u00e0 <code>System.Management.Automation<\/code> est une excellente id\u00e9e (puisque c\u2019est g\u00e9n\u00e9ralement cela qui est flag)\u00a0:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">[PSObject].Assembly\n(New-Object PSObject).GetType().Assembly \n([System.AppDomain]::CurrentDomain.GetAssemblies() | ? {try{$_.Location.Contains(\u2018Automation\\\u2019)} catch {}})<\/pre>\n\n\n\n<p>En r\u00e9alit\u00e9 il est simplement exig\u00e9 d\u2019obtenir une r\u00e9f\u00e9rence de type <code>RuntimeAssembly<\/code> \u00e0 <code>System.Management.Automation<\/code>. Avec un peu d&#8217;offuscation, on parvient \u00e0 contourner l&#8217;AMSI.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"1024\" height=\"323\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/NotRekt-1024x323.png\" alt=\"\" class=\"wp-image-184\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/NotRekt-1024x323.png 1024w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/NotRekt-300x95.png 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/NotRekt-768x243.png 768w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/NotRekt-400x126.png 400w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/NotRekt-800x253.png 800w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/NotRekt.png 1216w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Cette m\u00e9thode, bien que rapide, a depuis perdu beaucoup de son efficacit\u00e9. Defender \u00e9tant particuli\u00e8rement \u00e0 l\u2019aise pour d\u00e9tecter ce dernier (m\u00eame offusquer par moment). Ainsi on voudrait trouver une autre mani\u00e8re pour proc\u00e9der. Retournons voir le code de la classe <code>AmsiUtils<\/code>. Une variable relativement \u00e9trange est cr\u00e9\u00e9e <code>AmsiContext<\/code>, qui est pass\u00e9 en argument \u00e0 <code>ScanBuffer<\/code>. On lance Ghidra et on regarde \u00e0 quoi correspond cette valeur. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"1024\" height=\"386\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/ScanBuffer-1024x386.png\" alt=\"\" class=\"wp-image-173\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/ScanBuffer-1024x386.png 1024w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/ScanBuffer-300x113.png 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/ScanBuffer-768x289.png 768w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/ScanBuffer-1536x579.png 1536w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/ScanBuffer-400x151.png 400w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/ScanBuffer-800x301.png 800w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/ScanBuffer.png 1627w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Rapidement on trouve que si cette derni\u00e8re est diff\u00e9rente de 0 alors une erreur est lev\u00e9e (la valeur <code>0x80070057<\/code> est retourn\u00e9e, qui est un code <code>HRESULT<\/code> signifiant qu&#8217;un argument est invalide) et l\u2019analyse de notre commande n\u2019est pas effectu\u00e9e. En utilisant le m\u00eame proc\u00e9d\u00e9 de changement de variable que le bypass pr\u00e9c\u00e9dent il vient naturellement:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiContext', 'NonPublic,Static').SetValue($null, [System.IntPtr]::new(1234))<\/pre>\n\n\n\n<p>Vous l\u2019aurez compris, ces bypass ne s\u2019appliquent uniquement qu&#8217;\u00e0 PowerShell ce qui peut donc poser probl\u00e8me pour les autres langages de Scripting ou d\u00e9sormais du chargement d\u2019<code>assembly<\/code> .NET. Puisque depuis la version 4.8, la m\u00e9thode <code><code data-enlighter-language=\"powershell\" class=\"EnlighterJSRAW\">[System.Reflection.Assembly]::Load()<\/code><\/code> (qui permet le chargement en m\u00e9moire d\u2019assembly .NET) est surveill\u00e9e par l\u2019AMSI.<\/p>\n\n\n\n<h2>ConstrainLanguageMode<\/h2>\n\n\n\n<p>Sous PowerShell il existe principalement 4 types de &#8220;langage&#8221; d\u2019ex\u00e9cution. Ces derniers changent notre rapport au Scripting et \u00e0 l\u2019interaction avec .NET:<\/p>\n\n\n\n<ul><li><code>FullLanguage<\/code> permet de faire tout ce que l\u2019on souhaite.<\/li><li><code>NoLanguage<\/code> est tout le contraire, seul les cmdlets autoris\u00e9es sont disponibles.<\/li><li><code>RestrictedLanguage<\/code>, les scriptblock sont interdits, seul les cmdlets sont autoris\u00e9es quelques op\u00e9rateurs et variables par d\u00e9faut restent cependant accessibles.<\/li><li><code>ConstrainLanguageMode<\/code> (abr\u00e9g\u00e9 CLM) aucune interaction avec .NET n\u2019est autoris\u00e9e.Les m\u00e9thodes vue plus haut sont donc interdites, <code><code data-enlighter-language=\"powershell\" class=\"EnlighterJSRAW\">New-Object<\/code><\/code> ne peut \u00eatre appel\u00e9 uniquement qu&#8217;avec les types &#8220;core&#8221;. <code><code data-enlighter-language=\"powershell\" class=\"EnlighterJSRAW\">Add-Type<\/code><\/code> est bloqu\u00e9, tout comme <code>System.Reflection<\/code>. Des modules peuvent \u00eatre import\u00e9s et une confiance aveugle (ex\u00e9cution des fonctions import\u00e9es en <code>FullLanguage<\/code>) leur est donn\u00e9 s\u2019ils proviennent d\u2019une installation PowerShell.<\/li><\/ul>\n\n\n\n<p><code>ConstrainLanguageMode<\/code> est donc la protection id\u00e9ale contre les scripts malveillant et les malwares puisque ces derniers reposent essentiellement sur les possibilit\u00e9s tr\u00e8s puissantes de .NET qui sont d\u00e9sormais inaccessibles. Globalement, il existe 3 mani\u00e8res diff\u00e9rentes de param\u00e9trer CLM, avec AppLocker, DeviceGuard et en utilisant la cl\u00e9 de registre <code>__PSLockdownPolicy<\/code> en lui donnant pour valeur 4. En revanche, la derni\u00e8re m\u00e9thode est absolument \u00e0 prohiber et nous allons voir pourquoi. Comme toujours dans ILSpy on d\u00e9compile <code>System.Management.Automation.dll<\/code> et on inspecte la classe <code>Security<\/code>. Une m\u00e9thode de cette derni\u00e8re semble \u00eatre plus int\u00e9ressante que les autres <code>GetDebugLockdownPolicy()<\/code> qui nous informe des r\u00e8gles de s\u00e9curit\u00e9 pr\u00e9sentes. Un argument \u00e9nigmatique <code>path<\/code> peut \u00e9ventuellement \u00eatre pass\u00e9, et s\u2019il est diff\u00e9rent de nul et qu\u2019il contient le cha\u00eene &#8220;System32&#8221;, il retourne une restriction inexistante (sentez-vous l\u2019arnaque venir&nbsp;?). Sinon, il obtient la valeur de la cl\u00e9 de registre <code>__PSLockdownPolicy<\/code> et la passe \u00e0 la m\u00e9thode <code>GetLockdownPolicyForResult()<\/code>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"994\" height=\"865\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/SourceCode1.png\" alt=\"\" class=\"wp-image-174\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/SourceCode1.png 994w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/SourceCode1-300x261.png 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/SourceCode1-768x668.png 768w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/SourceCode1-400x348.png 400w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/SourceCode1-800x696.png 800w\" sizes=\"(max-width: 994px) 100vw, 994px\" \/><\/figure>\n\n\n\n<p>Comme pr\u00e9c\u00e9demment, on charge notre programme avec DNSpy et posons les m\u00eames points d\u2019arr\u00eat que tout \u00e0 l&#8217;heure. Nous poserons aussi des points d\u2019arr\u00eat dans la classe Security directement dans <code>System.Management.Automation.dll<\/code>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"1024\" height=\"594\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyCLM-1024x594.png\" alt=\"\" class=\"wp-image-175\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyCLM-1024x594.png 1024w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyCLM-300x174.png 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyCLM-768x445.png 768w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyCLM-400x232.png 400w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyCLM-800x464.png 800w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/DNSpyCLM.png 1076w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Le langage de PowerShell est obtenu lors de la cr\u00e9ation du runspace via la m\u00e9thode <code>DoLanguage<\/code>, on inspecte donc cette derni\u00e8re avec ILSpy et on comprend qu\u2019aucun bypass n\u2019est possible \u00e0 ce niveau puisque la m\u00e9thode ne fait qu\u2019ajouter une propri\u00e9t\u00e9 \u00e0 partir d\u2019une variable d\u00e9j\u00e0 existante. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" width=\"1000\" height=\"380\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug1.png\" alt=\"\" class=\"wp-image-176\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug1.png 1000w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug1-300x114.png 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug1-768x292.png 768w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug1-400x152.png 400w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug1-800x304.png 800w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" \/><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" width=\"564\" height=\"310\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug3.png\" alt=\"\" class=\"wp-image-177\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug3.png 564w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug3-300x165.png 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug3-400x220.png 400w\" sizes=\"(max-width: 564px) 100vw, 564px\" \/><\/figure><\/div>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"999\" height=\"511\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug4.png\" alt=\"\" class=\"wp-image-178\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug4.png 999w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug4-300x153.png 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug4-768x393.png 768w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug4-400x205.png 400w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug4-800x409.png 800w\" sizes=\"(max-width: 999px) 100vw, 999px\" \/><\/figure>\n\n\n\n<p>Avec cette m\u00e9thode d\u2019analyse nous ne pourrons aller bien loin. En effet, l\u2019usage d\u2019une pipeline nous bloque totalement dans notre recherche puisque cette derni\u00e8re contourne par d\u00e9finition la protection. Essayons cette fois-ci de charger <code>PowerShell.exe<\/code> dans DNSpy. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" width=\"1018\" height=\"480\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug5.png\" alt=\"\" class=\"wp-image-179\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug5.png 1018w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug5-300x141.png 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug5-768x362.png 768w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug5-400x189.png 400w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug5-800x377.png 800w\" sizes=\"(max-width: 1018px) 100vw, 1018px\" \/><\/figure><\/div>\n\n\n\n<p>Tout de suite, la m\u00e9thode que nous suspections est appel\u00e9e avec, pour la variable <code>path<\/code>, le chemin vers un fichier de module <code>PSReadLine<\/code>.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" width=\"905\" height=\"167\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug8.png\" alt=\"\" class=\"wp-image-180\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug8.png 905w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug8-300x55.png 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug8-768x142.png 768w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug8-400x74.png 400w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Debug8-800x148.png 800w\" sizes=\"(max-width: 905px) 100vw, 905px\" \/><\/figure><\/div>\n\n\n\n<p> Or ce dernier est le r\u00e9sultat de l\u2019importation d\u2019un module, op\u00e9ration permise m\u00eame avec CLM activ\u00e9. Construisons notre m\u00e9thode de contre-mesure. On commence par la cr\u00e9ation d\u2019un dossier de nom <code>System32<\/code> puis \u00e9crivons un petit script PowerShell qui nous informe du <code>LanguageMode<\/code> du contexte dans lequel il est charg\u00e9. Puis on l\u2019\u00e9crit dans un fichier de module PowerShell <code>.psm1<\/code>, enfin nous l\u2019importons (sans oublier le param\u00e8tre <code>-Force<\/code>). <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" width=\"779\" height=\"149\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Trigger1.png\" alt=\"\" class=\"wp-image-181\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Trigger1.png 779w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Trigger1-300x57.png 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Trigger1-768x147.png 768w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Trigger1-400x77.png 400w\" sizes=\"(max-width: 779px) 100vw, 779px\" \/><\/figure><\/div>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"1024\" height=\"123\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Trigger2-1024x123.png\" alt=\"\" class=\"wp-image-182\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Trigger2-1024x123.png 1024w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Trigger2-300x36.png 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Trigger2-768x92.png 768w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Trigger2-400x48.png 400w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Trigger2-800x96.png 800w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Trigger2.png 1287w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Comme pr\u00e9vu, c\u2019est le chemin vers notre script, puis vers notre fichier de module. Nous nous retrouvons avec une excellente surprise affich\u00e9e. Bypassed&nbsp;!<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"891\" height=\"463\" src=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Bypass.png\" alt=\"\" class=\"wp-image-183\" srcset=\"https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Bypass.png 891w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Bypass-300x156.png 300w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Bypass-768x399.png 768w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Bypass-400x208.png 400w, https:\/\/theredwindows.net\/wp-content\/uploads\/2021\/05\/Bypass-800x416.png 800w\" sizes=\"(max-width: 891px) 100vw, 891px\" \/><\/figure>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$Host.Runspace.LanguageMode\nNew-Item 'System32' -ItemType Directory\n'Write-Host ($Host.Runspace.LanguageMode)' | Out-File .\\System32\\bypass.psm1\nImport-Module .\\System32\\bypass.psm1 -Force<\/pre>\n\n\n\n<p>Cette m\u00e9thode ne risque pas de pouvoir \u00eatre souvent utilis\u00e9e. G\u00e9n\u00e9ralement si ce type de protection est pr\u00e9sent, c\u2019est surtout car DeviceGuard ou AppLocker est activ\u00e9 et \u00e0 ce stade les choses se compliquent. La mani\u00e8re donc PowerShell se renseigne sur les protections activent r\u00e9sulte en le chargement de dlls sp\u00e9cifiques sur lesquels nous n\u2019avons aucun pouvoir.<\/p>\n\n\n\n<p>Une autre strat\u00e9gie de contournement r\u00e9side dans la confiance accord\u00e9e aux modules et aux codes sign\u00e9s. Si ces derniers sont vuln\u00e9rables, alors il est possible de faire ex\u00e9cuter du code dans un contexte <code>FullLanguage<\/code>. Ces vuln\u00e9rabilit\u00e9s d\u2019injections de codes sont rares mais possibles, surtout quand il s\u2019agit de fonction non officielle d\u00e9ploy\u00e9e sur un serveur JEA (qui sont assez rares tout de m\u00eame) nous y reviendrons dans un prochain article. Le point d\u2019entr\u00e9e le plus connu concerne \u00e9videmment les fonctions usant de <code><code data-enlighter-language=\"powershell\" class=\"EnlighterJSRAW\">Invoke-Expression<\/code><\/code>, cmdlet permettant l\u2019ex\u00e9cution de code \u00e0 partir de cha\u00eenes de caract\u00e8re. Consid\u00e9rons le code suivant:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">function New-StartupService {\n\n\tparam {\n\t\t[String] $ServiceName\n\t\t[String] $BinaryPath\n\t}\n\n\tInvoke-Expression -Command \" sc.exe create $ServiceName binPath=$BinaryPath start=auto \"\n}<\/pre>\n\n\n\n<p>Il est assez clair ici que les donn\u00e9es que l\u2019utilisateur sp\u00e9cifient ne sont pas v\u00e9rifi\u00e9es. Ainsi, la fonction est vuln\u00e9rable puisque si cette derni\u00e8re est appel\u00e9e de la sorte <code><code data-enlighter-language=\"powershell\" class=\"EnlighterJSRAW\">New-StartupService -ServiceName \"\u00a0\/?; Write-Host 'hello'#\u00a0\"<\/code><\/code> alors notre code PowerShell qui ici simplement affiche &#8220;hello&#8221; sera ex\u00e9cut\u00e9. Souvent, l\u2019appelle \u00e0 de telle fonctionnalit\u00e9 n\u2019est pas directe et on peut trouver par exemple: <code><code data-enlighter-language=\"powershell\" class=\"EnlighterJSRAW\">[PowerShell]::Create().AddScript($commande).Invoke()<\/code><\/code> ou encore <code><code data-enlighter-language=\"powershell\" class=\"EnlighterJSRAW\">$ExecutionContext.InvokeCommand.ExpandString($var)<\/code><\/code>. Certains modules n\u00e9cessitent l\u2019ajout de classes et m\u00e9thodes C# pour fonctionner correctement, voir personnaliser ces derni\u00e8res en fonctions de param\u00e8tres. Par cons\u00e9quent il peut ajouter du code C# \u00e0 la session actuelle sans \u00eatre contraint par le mode de langage. Si nous sommes en capacit\u00e9 d\u2019interf\u00e9rer sur une telle variable, alors nous pourrons faire ex\u00e9cuter du code C# ou PowerShell via <code>System.Reflection<\/code> ou <code>System.Management.Automation<\/code>. Prenons l\u2019exemple d\u2019une vuln\u00e9rabilit\u00e9 patch\u00e9e : le module <a rel=\"noreferrer noopener\" href=\"https:\/\/www.powershellgallery.com\/packages\/Microsoft.PowerShell.OdataUtils\/1.1.6.0\/Content\/Microsoft.PowerShell.OdataAdapter.ps1\" data-type=\"URL\" data-id=\"https:\/\/www.powershellgallery.com\/packages\/Microsoft.PowerShell.OdataUtils\/1.1.6.0\/Content\/Microsoft.PowerShell.OdataAdapter.ps1\" target=\"_blank\">Microsoft.PowerShell.ODataUtils en version 1.1.6.0<\/a> (exemple tir\u00e9 du blog de matterpreter). Le probl\u00e8me provient du d\u00e9but du script. En effet l\u2019attaquant poss\u00e8de un droit d\u2019\u00e9criture sur toutes les variables globales et peut m\u00eame en modifier les propri\u00e9t\u00e9s. Consid\u00e9rons un code repr\u00e9sentatif et un peu plus minimaliste:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$Global:TypeDefinition =  @\" \nusing System ;\nusing System.Diagnostics ;\n\npublic class CurrentProcess \n{\n\tpublic static void GetProcess() \n\t{\n\t\tProcess[] processCollection = Process.GetProcesses() ;\n\t\tforeach (Process p in processCollection)\n\t\t{\n\t\t\tConsole.WriteLine(p.ProcessName) ;\n\t\t}\n\t}\n}\n \"@\n\nAdd-Type -TypeDefinition $Global:TypeDefinition -Language Csharp<\/pre>\n\n\n\n<p>Lors de l\u2019importation du module, le contenu d\u2019une variable globale est utilis\u00e9 pour dynamiser et ajouter une classe .NET. Or nous avons le contr\u00f4le total de la m\u00e9moire et des variables de notre processus. Donc si on souhaite changer le contenu de la variable avant l\u2019importation du module ET que l\u2019on change le type de variable pour de la lecture seule, alors le module ne pourra \u00e9craser le contenu et donc ajoutera notre code, ce qui est effectu\u00e9 ainsi:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$SharpPick = @\" \nusing System;\nusing System.Collections.ObjectModel;\nusing System.Management.Automation;\nusing System.Management.Automation.Runspaces;\n\npublic static class Exploit\n{\n\tpublic static void Exec(string c)\n\t{\n\t\tRunspace rs = RunspaceFactory.CreateRunspace();\n\t\trs.Open();\n\t\tPipeline pline = rs.CreatePipeline();\n\t\tpline.Commands.AddScript(c + \"|Out-String\");\n\t\tCollection&lt;PSObject> res = pline.Invoke();\n\t\trs.Close();\n\t\tforeach (var re in res)\n\t\t{\n\t\t\tConsole.WriteLine(re);\n\t\t}\n\t}\n}\n \"@\nSet-Variable -Name $Global:TypeDefinition -Value $SharpPick -Option ReadOnly<\/pre>\n\n\n\n<p>Le module mentionn\u00e9 \u00e0 \u00e9videmment \u00e9t\u00e9 corrig\u00e9 et le patch est pour le moins minimaliste puisqu\u2019il a suffit de changer le registre de <a rel=\"noreferrer noopener\" href=\"https:\/\/www.powershellgallery.com\/packages\/Microsoft.PowerShell.ODataUtils\/1.1.7.0\/Content\/Microsoft.PowerShell.ODataAdapter.ps1\" data-type=\"URL\" data-id=\"https:\/\/www.powershellgallery.com\/packages\/Microsoft.PowerShell.ODataUtils\/1.1.7.0\/Content\/Microsoft.PowerShell.ODataAdapter.ps1\" target=\"_blank\">la variable de <code>Global<\/code> \u00e0 <code>Script<\/code><\/a>.<\/p>\n\n\n\n<p>D&#8217;autres m\u00e9thodes sont plus simples et plus g\u00e9n\u00e9rales. La premi\u00e8re consiste en la cr\u00e9ation d\u2019un runspace PowerShell et l\u2019utilisation d\u2019une pipeline. Comme nous l\u2019avons vu, cette derni\u00e8re contournera ais\u00e9ment le <code>ConstrainLanguageMode<\/code>. L\u2019ex\u00e9cution de commande complexe ou de module via SharpPick (c\u2019est comme \u00e7a que cela s\u2019appelle) n\u00e9cessite parfois, la cr\u00e9ation d\u2019un petit serveur web qui hostera le payload complet, sauf si votre C2 l\u2019utilise nativement \u00e0 l\u2019instar de Covenant. Plusieurs outils utilisent cette technique pour contourner les restrictions de PowerShell, c\u2019est le cas par exemple de <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/p3nt4\/PowerShdll\" data-type=\"URL\" data-id=\"https:\/\/github.com\/p3nt4\/PowerShdll\" target=\"_blank\">PowerShdll<\/a>\/<a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/Exploit-install\/PSShell\" data-type=\"URL\" data-id=\"https:\/\/github.com\/Exploit-install\/PSShell\" target=\"_blank\">PSShell<\/a> qui permet l\u2019ex\u00e9cution, au travers d\u2019une dll, de code PowerShell (avec rundll32.exe par exemple). <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/cobbr\/SharpSploit\" data-type=\"URL\" data-id=\"https:\/\/github.com\/cobbr\/SharpSploit\" target=\"_blank\">SharpSploi<\/a>t (librairie voulant convertir au plus les codes de PowerSploit en C#) permet \u00e9galement de le faire et bien d\u2019autres encore. L\u2019une des cons\u00e9quences du SharpPick est qu\u2019elle requiert l\u2019utilisation d\u2019un bytecode .NET, on pourrait naturellement exiger de pouvoir \u00eatre capable de le faire depuis un binaire plus standard. C\u2019est en (Visual) C++ que l\u2019on peut trouver de telles impl\u00e9mentations puisque Microsoft a cr\u00e9\u00e9e des interfaces permettant l\u2019interaction entre VC++ et CLR. <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/leechristensen\/UnmanagedPowerShell\" data-type=\"URL\" data-id=\"https:\/\/github.com\/leechristensen\/UnmanagedPowerShell\" target=\"_blank\">UnmanagedPowerShell<\/a> par <a rel=\"noreferrer noopener\" href=\"https:\/\/twitter.com\/tifkin_\" data-type=\"URL\" data-id=\"https:\/\/twitter.com\/tifkin_\" target=\"_blank\">leechristensen<\/a> est l\u2019id\u00e9al pour cette t\u00e2che. Il va charger dans un premier temps CLR dans le processus puis importer un SharpPick personnalis\u00e9 pour ex\u00e9cuter les commandes PowerShell, elle contourne donc bien la protection dont nous souhaitons nous affranchir. Remarquons que la possibilit\u00e9 de charger CLR dans la m\u00e9moire d\u2019un processus qui originellement ne l\u2019a pas, nous permet ainsi d\u2019imaginer une autre technique: cr\u00e9er une DLL et l&#8217;injecter l\u00e0 dans un autre processus. Cette derni\u00e8re se pr\u00e9nomme ReflectivePick, et l\u2019outil qui principalement l\u2019utilise est PSInject. L\u2019utilisation de PSInject est tr\u00e8s pratique quand il faut user de scripts tel <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/EmpireProject\/Empire\/blob\/master\/data\/module_source\/collection\/Get-ClipboardContents.ps1\" data-type=\"URL\" data-id=\"https:\/\/github.com\/EmpireProject\/Empire\/blob\/master\/data\/module_source\/collection\/Get-ClipboardContents.ps1\" target=\"_blank\">Get-ClipBoardContent.ps1<\/a> ou bien <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/PowerShellMafia\/PowerSploit\/blob\/master\/Exfiltration\/Get-Keystrokes.ps1\" data-type=\"URL\" data-id=\"https:\/\/github.com\/PowerShellMafia\/PowerSploit\/blob\/master\/Exfiltration\/Get-Keystrokes.ps1\" target=\"_blank\">Get-Keystroke.ps1<\/a> qui n\u2019ont besoin que de &#8220;vivre&#8221; pour obtenir des r\u00e9sultats. ReflectivePick repose sur la m\u00eame construction que UnmanagedPowerShell, mais logiquement il ne faut pas s\u2019attendre \u00e0 un quelconque retour. L\u2019ensemble de ces techniques est appel\u00e9 PowerPick et \u00e9norm\u00e9ment de C2 permettent de l\u2019utiliser, PowerShellEmpire, Covenant, CobaltStrike, MetaSploit, et PoshC2 comme exemple et pour finir cette liste non-exaustive. Les codes sources de ces outils sont bas\u00e9s sur les originaux que vous pouvez retrouvez sur <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/PowerShellEmpire\/PowerTools\/tree\/master\/PowerPick\" data-type=\"URL\" data-id=\"https:\/\/github.com\/PowerShellEmpire\/PowerTools\/tree\/master\/PowerPick\" target=\"_blank\">github<\/a>.<\/p>\n\n\n\n<p>Les vuln\u00e9rabilit\u00e9s exploitant intrins\u00e8quement la conception de CLM sont consid\u00e9r\u00e9es par Microsoft comme des CVEs \u00e0 part enti\u00e8re.<\/p>\n\n\n\n<h2>Le probl\u00e8me de la version 2<\/h2>\n\n\n\n<p>Le gros probl\u00e8me de l\u2019ensemble de ces s\u00e9curit\u00e9s est ce que ces derni\u00e8res ont \u00e9t\u00e9 rajout\u00e9es au cours du temps et de l\u2019\u00e9volution des m\u00e9thodes utilis\u00e9es par les attaquants. Ainsi, sur les toutes premi\u00e8res versions de <code>System.Management.Automation.dll<\/code>, ces s\u00e9curit\u00e9s ne sont pas pr\u00e9sentes. Donc si cette version de PowerShell est disponible, l\u2019utilisation de cette derni\u00e8re contournera l\u2019ensemble des contre-mesures existantes sauf les politiques d\u2019ex\u00e9cutions. Pour lancer PowerShell dans une version sp\u00e9cifique, l\u2019utilisation du param\u00e8tre <code>-version<\/code> est d\u00e9di\u00e9. Cette attaque est appel\u00e9e &#8220;downgrade&#8221;.  <\/p>\n\n\n\n<h2>Enum\u00e9ration<\/h2>\n\n\n\n<p>Une fois fra\u00eechement d\u00e9barqu\u00e9 sur une cible, il est toujours pr\u00e9f\u00e9rable d\u2019\u00e9num\u00e9rer les d\u00e9fenses en vigueurs, SeatBelt est un outil du GhostPack \u00e9crit par les chercheurs de SpecterOps (particuli\u00e8rement <a rel=\"noreferrer noopener\" href=\"https:\/\/twitter.com\/harmj0y\" data-type=\"URL\" data-id=\"https:\/\/twitter.com\/harmj0y\" target=\"_blank\">harmj0y<\/a>). Plusieurs commandes existent pour lister les protections activent sur PowerShell et l\u2019environnement dans lequel nous \u00e9voluons. Pour r\u00e9colter les antivirus en place, on utilise la commande <code>AntiVirus<\/code> et pour savoir si ce dernier poss\u00e8de un provider AMSI on rajoute la commande <code>AMSIProviders<\/code>. Si la DLL par d\u00e9faut de l\u2019AMSI est retourn\u00e9e mais que l\u2019antivirus est diff\u00e9rent de Defender, alors nous n\u2019aurons pas \u00e0 nous en faire puisque lors de l\u2019installation d\u2019un antivirus tiers, Defender se fait d\u00e9sactier. Pour conna\u00eetre la condition de PowerShell c\u2019est-\u00e0-dire, les versions install\u00e9es, si des syst\u00e8mes de logging sont en place, l\u2019argument \u00e0 passer est tout simplement PowerShell. Si \u00e9ventuellement d\u2019autres protections sont en place qui ont un effet sur le comportement de notre shell pr\u00e9f\u00e9r\u00e9; il est aussi possible de les \u00e9num\u00e9rer en utilisant la commande <code>AppLocker<\/code>. En revanche si CLM est activ\u00e9 par valeur de registre, il faudra utiliser la commande <code>EnvironmentVariables <\/code>et chercher <code>__PSLockdownPolicy<\/code>.<\/p>\n\n\n\n<h2>Impacts Forensics<\/h2>\n\n\n\n<p>Malgr\u00e9 tout, ces m\u00e9thodes de contournements laissent des traces. Pour commencer, l&#8217;utilisation de la version 2 de PowerShell est visible. En effet, lorsque PowerShell est lanc\u00e9, il provoque l&#8217;eventid 400 dans lequel plusieurs informations sont pr\u00e9sentes notamment la version du moteur PowerShell utilis\u00e9. De plus, il existe un syst\u00e8me de log natif \u00e0 PowerShell qui expose certaines informations. Un scriptblock, est consid\u00e9r\u00e9 comme une erreur ou un probl\u00e8me s&#8217;il contient certains mots que l&#8217;on peut obtenir en utilisant la commande <code><code data-enlighter-language=\"powershell\" class=\"EnlighterJSRAW\">[ScriptBlock].GetField('signatures', 'NonPublic, Static').GetValue($null)<\/code><\/code>. Lorsque des Pipelines sont utilis\u00e9es, elle seront logg\u00e9es dans l&#8217;eventid 800. De plus, si des r\u00e8gles ETW sont en place, il est possible de savoir quelles sont les r\u00e9f\u00e9rences dont a besoin un bytecode .NET ce qui permet de savoir s&#8217;il utilise <code>System.Management.Automation<\/code>.<\/p>\n\n\n\n<h2>Conclusion<\/h2>\n\n\n\n<p>Bien que les moyens de protection autour de PowerShell ont grandement \u00e9t\u00e9 am\u00e9lior\u00e9s, il subsiste encore des m\u00e9thodes pour s&#8217;affranchir de ces m\u00e9canismes. En revanche, la lourdeur qu&#8217;implique ces contournements rendent l&#8217;utilisation de PowerShell plus contraignante d&#8217;autant plus lorsque des syst\u00e8mes de logging sont pr\u00e9sents. J&#8217;esp\u00e8re que l&#8217;article vous \u00e0 plu !<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Microsoft n\u2019\u00e9tait clairement pas aveugle concernant l\u2019usage malveillant qu\u2019il \u00e9tait fait de son nouveau Shell. Ainsi, pour aider les d\u00e9fenseurs, l\u2019\u00e9quipe PowerShell a travaill\u00e9 sur diff\u00e9rentes protections (sur lesquelles vous pouvez bri\u00e8vement vous renseigner en consultant l\u2019article de documentation sur PowerShell, disponible sur le blog). Chacune permettant de limiter l\u2019impact de PowerShell sur un environnement [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[4],"tags":[],"_links":{"self":[{"href":"https:\/\/theredwindows.net\/index.php\/wp-json\/wp\/v2\/posts\/160"}],"collection":[{"href":"https:\/\/theredwindows.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/theredwindows.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/theredwindows.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/theredwindows.net\/index.php\/wp-json\/wp\/v2\/comments?post=160"}],"version-history":[{"count":9,"href":"https:\/\/theredwindows.net\/index.php\/wp-json\/wp\/v2\/posts\/160\/revisions"}],"predecessor-version":[{"id":266,"href":"https:\/\/theredwindows.net\/index.php\/wp-json\/wp\/v2\/posts\/160\/revisions\/266"}],"wp:attachment":[{"href":"https:\/\/theredwindows.net\/index.php\/wp-json\/wp\/v2\/media?parent=160"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/theredwindows.net\/index.php\/wp-json\/wp\/v2\/categories?post=160"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/theredwindows.net\/index.php\/wp-json\/wp\/v2\/tags?post=160"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}