Code Monkey home page Code Monkey logo

deobshell's Introduction

DeobShell

GitHub license Language: Python Cross-platform v1.0


DeobShell is PoC to deobfuscate Powershell using Abstract Syntax Tree (AST) manipulation in Python. The AST is extracted using a Powershell script by calling System.Management.Automation.Language.Parser and writing relevant nodes to an XML file.

AST manipulation and optimization is based on a set of rules (ex: concat constant string, apply format operator ...).

From the deobfuscated AST, a ps1 script is rebuilt using Python. See the diagram below.

ℹ️ Only a subset of Powershell is supported for now but PR are welcomed :)

⚠️ data/ folder contains real malware samples!

How

diagram

Examples of rules

  • remove empty nodes
  • remove unused variables
  • remove use of uninitialised variables
  • simplify expression
  • join, plus, format, replace operator
  • split, reverse, invoke-expression
  • type convertion to type, string, char, array
  • replace constant variable with their value
  • fix special words case
  • ...

Example: BinaryExpressionAst node for format operator

Input
<BinaryExpressionAst Operator="Format" StaticType="System.Object">
  <StringConstantExpressionAst StringConstantType="DoubleQuoted" StaticType="string">{0}{1}</StringConstantExpressionAst>
  <ArrayLiteralAst StaticType="System.Object[]">
    <Elements>
      <StringConstantExpressionAst StringConstantType="SingleQuoted" StaticType="string">c</StringConstantExpressionAst>
      <StringConstantExpressionAst StringConstantType="SingleQuoted" StaticType="string">AcA</StringConstantExpressionAst>
    </Elements>
  </ArrayLiteralAst>
</BinaryExpressionAst>
Output
<StringConstantExpressionAst StringConstantType="SingleQuoted" StaticType="string">cAcA</StringConstantExpressionAst>

Example

CTF challenge

Input
$mRSp73  =  [ChaR[] ]" ))43]raHc[]gNIRtS[,)38]raHc[+98]raHc[+611]raHc[((eCAlper.)421]raHc[]gNIRtS[,'5IP'(eCAlper.)'$',)09]raHc[+99]raHc[+701]raHc[((eCAlper.)93]raHc[]gNIRtS[,'vzW'(eCAlper.)'


2halB.tcejboZck tuptuO-etirW

7halB.tcejboZck +'+' 6halB.tcejboZck + halB.tc'+'ejboZck '+'= 2galFFT'+'C:'+'vneZck

SYt!eciNSYt = 1galFFTC:vneZck

SYt...aedi dab yre'+'v'+' ,yre'+'v a yllacipyt svzWtaht ,ton fI .ti gninnur erofeb siht detacsufbo-ed uoy epoh ISYt eulaV- 2halB emaN- '+'ytreporPetoN epy'+'TrebmeM- rebmeM-ddA 5IP tcejboZck

SYt'+'.uoy tresed dna dnuora nur annog reveNSYt eulaV- 9hal'+'B emaN- ytreporPetoN epyTrebmeM- rebmeM-ddA 5'+'IP tcejboZck

SYt.nwod uo'+'y tel annog '+'re'+'veN .'+'pu uoy evig annog reveNSYt eulaV- 8halB emaN- ytreporPetoN epyTrebm'+'eM- rebmeM-d'+'dA 5IP tcejboZck

SYt}f1j9kdSYt eulaV- 7halB emaN- y'+'treporPetoN ep'+'yTrebmeM- rebmeM-ddA 5IP tcejboZck

SYtg4lf_3ht_t0nSYt eulaV- 4halB emaN- yt'+'reporPetoN epyTrebmeM- rebmeM-ddA 5IP tcejboZck

SYt1#f!J{SYt eulaV- 6halB emaN- ytreporPetoN epyTrebmeM- rebmeM-'+'ddA 5IP tcejboZck

SYtgalF,ehT,toN,oslASYt eulaV- 5halB emaN- ytreporPetoN epyTrebmeM- rebmeM-ddA 5IP tcejboZck

SY'+'t}fdjfkslfdSYt eulaV- 3halB emaN- ytrepor'+'PetoN e'+'pyTrebmeM- rebmeM-ddA 5IP tcejboZ'+'ck

SYtgalfSYt eulaV- halB em'+'aN- ytreporPetoN e'+'pyTrebmeM- rebmeM-ddA 5IP tcej'+'boZck

tc'+'ejbO'+'SP tcejbO-weN = tc'+'ejboZck'( ()''nioJ-'x'+]3,1[)eCNERefErpESoBreV$]GniRTS[( (. " ;[aRRAy]::REVerse($MrSp73);. ( 'IeX') ( -JoiN$MrSp73)
Output
$object = New-Object PSObject;
$object | Add-Member  NoteProperty  Blah  "flag";
$object | Add-Member  NoteProperty  Blah3  "dflskfjdf}";
$object | Add-Member  NoteProperty  Blah5  "Also,Not,The,Flag";
$object | Add-Member  NoteProperty  Blah6  "{J!f`#1";
$object | Add-Member  NoteProperty  Blah4  "n0t_th3_fl4g";
$object | Add-Member  NoteProperty  Blah7  "dk9j1f}";
$object | Add-Member  NoteProperty  Blah8  "Never gonna give you up. Never gonna let you down.";
$object | Add-Member  NoteProperty  Blah9  "Never gonna run around and desert you.";
$object | Add-Member  NoteProperty  Blah2  "I hope you de-obfuscated this before running it. If not, that''s typically a very, very bad idea...";
$env:CTFFlag1 = "Nice!";
$env:CTFFlag2 = $object.Blah + $object.Blah6 + $object.Blah7;
Write-Output $object.Blah2;

References

deobshell's People

Contributors

heck-gd avatar thewhiteninja avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

deobshell's Issues

NoneType object has no attribute 'replace' in opt_binary_expression_replace

Hi again,

Encountered another issue with a specific sample.

[git_134.ps1.txt](https://github.com/thewhiteninja/deobshell/files/10772069/git_134.ps1.txt

See Trace Below:

[02-17-2023 17:32:44] [DEBUG] Replace pipeline with single elements by CommandAst
[02-17-2023 17:32:44] [DEBUG] Remove unassigned variable use 'False'
[02-17-2023 17:32:44] [DEBUG] Remove unassigned variable use 'False'
[02-17-2023 17:32:44] [DEBUG] Remove unassigned variable use 'ServiceName'
Traceback (most recent call last):
  File "deobshell\main.py", line 86, in <module>
    main()
  File "deobshell\main.py", line 75, in main
    deob(OPTIONS['input'])
  File "deobshell\main.py", line 52, in deob
    o.optimize(ast)
  File "deobshell\modules\optimize.py", line 78, in optimize
    while optimize_pass(ast):
  File "deobshell\modules\optimize.py", line 63, in optimize_pass
    if opt(ast):
  File "deobshell\modules\optimizations\binary_expressions.py", line 75, in opt_binary_expression_replace
    formatted = target.replace(argument_values[0], argument_values[1])
AttributeError: 'NoneType' object has no attribute 'replace'

Please let me know if there is any way I can help.

Powershell output does not include "." character in some scenarios

Hello! I'm very thankful you've created deobshell; I was in disbelief that a PowerShell formatter seems to be so difficult to find.

I'm encountering an issue with the "." character as part of a CommandAST node. The original code looks like this:

function Sprjtemalinger($skolepigen) {
    . ($Skkestolens) ($skolepigen);
}

The AST looks like this:

<FunctionDefinitionAst Name="Sprjtemalinger">
  <Parameters>
    <ParameterAst Name="$skolepigen" StaticType="System.Object">
      <Attributes />
      <VariableExpressionAst VariablePath="skolepigen" StaticType="System.Object" />
    </ParameterAst>
  </Parameters>
  <ScriptBlockAst>
    <Attributes />
    <UsingStatements />
    <NamedBlockAst>
      <Statements>
        <PipelineAst>
          <PipelineElements>
            <CommandAst>
              <CommandElements>
                <ParenExpressionAst StaticType="System.Object">
                  <PipelineAst>
                    <PipelineElements>
                      <CommandExpressionAst>
                        <VariableExpressionAst VariablePath="Skkestolens" StaticType="System.Object" />
                        <Redirections />
                      </CommandExpressionAst>
                    </PipelineElements>
                  </PipelineAst>
                </ParenExpressionAst>
                <ParenExpressionAst StaticType="System.Object">
                  <PipelineAst>
                    <PipelineElements>
                      <CommandExpressionAst>
                        <VariableExpressionAst VariablePath="skolepigen" StaticType="System.Object" />
                        <Redirections />
                      </CommandExpressionAst>
                    </PipelineElements>
                  </PipelineAst>
                </ParenExpressionAst>
              </CommandElements>
              <Redirections />
            </CommandAst>
          </PipelineElements>
        </PipelineAst>
      </Statements>
    </NamedBlockAst>
  </ScriptBlockAst>
</FunctionDefinitionAst>

And the reconstructed code looks like this:

function Sprjtemalinger($skolepigen){
   ($Skkestolens) ($skolepigen);
}
;

Note that the "." character has not been added. I don't have much experience with PowerShell but at a glance, I can't even tell if the generated AST has any provision for this character, so I'm not sure how you could infer that it's meant to be there. I've attached the malicious script in question as a .zip file with the password "infected".
deobshell_format_missing_dot_character.zip

Obviously this is not a major issue, I can just re-add the character after deobfuscation, but I wanted to make this issue in case you know of a solution. Thank you again for making this tool!

Add support for piping script body to Invoke-Expression instead of passing as first argument

Hello TheWhiteNinja,
Thanks for the great project!

I'm trying to use this and finding that some common malware samples aren't being handled. Specifically things like this:

(New-Object System.IO.StreamReader 
   @(
     (New-Object System.IO.Compression.DeflateStream 
       @([System.IO.MemoryStream][Convert]::FromBase64String("...base64-string..."), 
         [IO.Compression.CompressionMode]::Decompress
        )
     ),
     [System.Text.Encoding]::ASCII
    )
).ReadToEnd() | Invoke-Expression;

I've been thinking about how to add support for this. After digging a bit, I think there are two problems:

  • there is support for Invoke-Expression but it is currently only expecting script body in the first argument
  • there is no support for applying base64 decoding and decompressions statically

I'm going to try to add these in some way. But if you have any hints or thoughts about how this would best fit into the current code, I would very much appreciate a hint!

For the pipeline input into Invoke-Expression I think the easiest way would be to add support in opt_invoke_expression to match parent nodes of the AST to see if it's a member of a pipeline, and if the preceding element is a string constant. Actually, this could just be a separate optimization to rewrite this to Invoke-Expression("...the-string-constant...") | ... <the rest of pipeline>.
Or maybe it would be best as a pipeline optimization? Any pipeline of the form string-constant | command rewrites to command string-constant?

I haven't yet decided what to do with the base64+deflate -> string constant step.

opt_type_constraint_case getting stuck

the function opt_type_constraint_case(ast) is getting stuck at "Fix typename case from 'string' to 'String'"
It looks like the Element isn't getting replaced properly

opt_constant_string_type can crash

cst_string_node.text can be None, so trying to do
member = cst_string_node.text.lower() will crash in this case

Fix:
just insert
if cst_string_node.text is None: continue
inbetween
for cst_string_node in node.findall("StringConstantExpressionAst"):
and
member = cst_string_node.text.lower()

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.