Thursday, 16 May 2013

Using AST to programmatically create an Asmx WebServices WebMethod invocation wrapper (for HacmeBank)

Following the Creating a REPL editor that is linked to a Code editor and a Using AST technology (from ICSharpCode.NRefactory) to script the creation of a C# file  posts, here is how use AST technology to create a wrapper for HacmeBank web services:


First we execute the webservices directly using:

image

which will create this AST generated script file  (note: 'the script below was created from the script above', and that makes no sense to you, please read the Using AST technology (from ICSharpCode.NRefactory) to script the creation of a C# file post) :

image

which when executed results in:

image

Next step is to load the WS_UserManagement.cs file, get its AST, find the Login Method and add that method to the AClass Ast

image

The generated code will look like this:

image

One of the best parts of AST manipulation is that we can easily use on AST to create another one.

In this case we are going to use the WebService’s Login method to create the ‘wrapper/proxy login method’

image

The script shown above will create this script:

image

which is exactly what I’m trying to do: a C# based proxy for a web service :)

To quickly test it we can add a method that invoke that wrapper method:

image

which will create this code:

image

which when executed will show the login Id on the Log Viewer:

image

Here is an interesting twist, which also shows the power of this technique to script unit tests.

Since the Login method (in HacmeBank) is vulnerable to SQL injection, we can code a payload on via the AST generation:

image

which will result in the code and execution result of:

image

Note the SQL injection error in the Log :)


We can also use a payload that returns an SQL error with a value (like jv’ and 1 = @@version -- )

image

where we will get this script and execution result (see Log Viewer)

image

and this traffic in fiddler:

image

As you can see this is a real powerful technique where I was able to use AST manipulation to programmatically create a Proxy Method for a particular WebService’s WebMethod.

Finally, just to show the interactivity of this type of development (using the GUI explained in Creating a REPL editor that is linked to a Code editor ), this is what my GUI looked like after running the 'AST generated script with the SQL Injection' (note that right-hand-side code editor is populated, compiled and executed in real-time)

image


Scripts used in this Post:

1) invoking the Login WebService directly:
   1: var compilationUnit = new CompilationUnit();

   2: compilationUnit.add_Using("O2.DotNetWrappers.ExtensionMethods");

   3: compilationUnit.add_Using("System");

   4:  

   5: var aClass  = compilationUnit.add_Type("AClass");

   6: var aMethod = aClass.add_Method("Main")

   7:                     .setReturnType("void") 

   8:                     .public_Static();  

   9:                 

  10: var wsUserManegementType = "WS_UserManagement".ast_TypeReference();

  11:  

  12: var body = aMethod.add_Body(); 

  13:     body.add_Variable("webService", wsUserManegementType.ast_ObjectCreate(),wsUserManegementType);

  14:     var invocation = "webService".ast_Invocation("Login","jv","jv789");

  15:     

  16:     body.add_Variable("result", invocation, "String"); 

  17:     body.add_Invocation("result","info");

  18:     body.add_Invocation("Console","Write","The Login Invocation result is: ");

  19:     body.add_Invocation("Console","WriteLine","result".identifier());

  20:  

  21:     

  22:  

  23: var csharpCode = compilationUnit.csharpCode()

  24:                                 .insertAt(0, @"//O2File:E:\O2\O2.Temp\5_10_2013\wsdl_tmpC5E1\WS_UserManagement.cs".line());

  25:  

  26:  

  27:  

  28: var tempFile = csharpCode.saveWithExtension(".cs");

  29: codeEditor.open(tempFile)

  30:           .compileCSSharpFile()

  31:           .executeFirstMethod();

  32:  

  33:           return "ok";

  34: //using ICSharpCode.NRefactory.Ast

  35: //using O2.API.AST.ExtensionMethods.CSharp

  36: //O2File:_Extra_methods_To_Add_to_Main_CodeBase.cs

2) creating the ‘login wrapper/proxy’ method
   1: var compilationUnit = new CompilationUnit();

   2: compilationUnit.add_Using("O2.DotNetWrappers.ExtensionMethods");

   3: compilationUnit.add_Using("System");

   4:  

   5: var file = @"E:\O2\O2.Temp\5_10_2013\wsdl_tmpC5E1\WS_UserManagement.cs";

   6: var loginMethod = file.csharpAst().method("Login");;

   7: var className = loginMethod.Parent.prop("Name").str(); 

   8:  

   9: var aClass  = compilationUnit.add_Type(className + "_Wrapper");

  10:  

  11: var aMethod = aClass.add_Method(loginMethod);    

  12:  

  13: var body = new BlockStatement();

  14: body.add_Variable("webService", 

  15:                   className.ast_TypeReference().ast_ObjectCreate(),

  16:                   className.ast_TypeReference());

  17: var parameters = loginMethod.parameters().names().ast_Identifiers().ToArray();

  18: var invocation = "webService".ast_Invocation("Login",parameters);

  19: var result = body.add_Variable("result", invocation, loginMethod.TypeReference);

  20: body.add_Return(result.Name.ast_Identifier());

  21:  

  22: loginMethod.Body = body;

  23: loginMethod.Attributes = null;

  24:  

  25:  

  26:  

  27: var csharpCode = compilationUnit.csharpCode()

  28:                                 .insertAt(0, @"//O2File:{0}".format(file).line());

  29:  

  30: var tempFile = csharpCode.saveWithExtension(".cs");

  31: codeEditor.open(tempFile);

3) creating a test method that with an SQL Injection payload:
   1: var compilationUnit = new CompilationUnit();

   2: compilationUnit.add_Using("O2.DotNetWrappers.ExtensionMethods");

   3: compilationUnit.add_Using("System");

   4:  

   5: var file = @"E:\O2\O2.Temp\5_10_2013\wsdl_tmpC5E1\WS_UserManagement.cs";

   6: var loginMethod = file.csharpAst().method("Login");;

   7: var className = loginMethod.Parent.prop("Name").str(); 

   8:  

   9: var aClass  = compilationUnit.add_Type(className + "_Wrapper");

  10:  

  11: var testBody = aClass.add_Method("testMethod")

  12:                       .setReturnType("void")

  13:                        .add_Body();

  14:                   

  15: var loginPayload = "jv' and 1 = @@version --";                  

  16: var loginInvoke = "Login".ast_Invocation(loginPayload,"jv789"); 

  17: var infoInvoke  = loginInvoke.add_Invocation("info");

  18: testBody.append_AsStatement(infoInvoke); 

  19:       

  20:  

  21: var aMethod = aClass.add_Method(loginMethod);    

  22:  

  23: var body = new BlockStatement();

  24: body.add_Variable("webService", 

  25:                   className.ast_TypeReference().ast_ObjectCreate(),

  26:                   className.ast_TypeReference());

  27: var parameters = loginMethod.parameters().names().ast_Identifiers().ToArray();

  28: var invocation = "webService".ast_Invocation_onType("Login",parameters);

  29: var result = body.add_Variable("result", invocation, loginMethod.TypeReference);

  30: body.add_Return(result.Name.ast_Identifier());

  31:  

  32: loginMethod.Body = body;

  33: loginMethod.Attributes = null;

  34:  

  35:  

  36:  

  37: var csharpCode = compilationUnit.csharpCode()

  38:                                 .insertAt(0, @"//O2File:{0}".format(file).line());

  39:  

  40: var tempFile = csharpCode.saveWithExtension(".cs");

  41: codeEditor.open(tempFile);

  42:  

  43: if (true)

  44:     codeEditor.compileCSSharpFile()          

  45:               .executeFirstMethod();

  46:  

  47:           return "ok";

  48: //using ICSharpCode.NRefactory.Ast

  49: //using O2.API.AST.ExtensionMethods.CSharp

  50: //O2File:_Extra_methods_To_Add_to_Main_CodeBase.cs