From bfc4e13c10cd72864b9060ca6ba53463037409a6 Mon Sep 17 00:00:00 2001 From: nomuus <927151+nomuus@users.noreply.github.com> Date: Wed, 6 Jul 2022 17:24:37 -0500 Subject: [PATCH 1/2] refactor to support linux --- NSGenCS.py | 115 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 31 deletions(-) diff --git a/NSGenCS.py b/NSGenCS.py index 213cd5e..c02234c 100644 --- a/NSGenCS.py +++ b/NSGenCS.py @@ -4,6 +4,8 @@ import subprocess import argparse import random +import re +import shutil import string import sys import os @@ -20,12 +22,12 @@ def generateEncodedShell(encoder, key, file, sdir): shellcode = open(file, "r") shelcode_data = shellcode.read() # Open the original C# Code for the encoder - full_template_path = "{0}/{1}/template".format(base_dir, sdir) + full_template_path = f"{base_dir}{os.sep}{sdir}{os.sep}template" original = open(full_template_path, "r") data = original.read() # Grab the encryption code to place in template - encryption_template = "{0}/{1}/encrypt.txt".format(base_dir, encoder) + encryption_template = f"{base_dir}{os.sep}{encoder}{os.sep}encrypt.txt" encryptfile = open(encryption_template,"r") encryptcode = encryptfile.read() @@ -38,7 +40,7 @@ def generateEncodedShell(encoder, key, file, sdir): data = data.replace("KEYHERE", key) # Open a new file and write the replaced text here - temp_tempate_path = "{0}/{1}/Program.cs".format(base_dir, sdir) + temp_tempate_path = f"{base_dir}{os.sep}{sdir}{os.sep}Program.cs" template = open(temp_tempate_path, "w+") template.write(data) @@ -50,23 +52,41 @@ def generateEncodedShell(encoder, key, file, sdir): else: print("[-] Shellcode path is not exists, please check it!") -def generatePayload(encoder, template_directory, key, sdir): +def generatePayload(encoder, template_directory, key, sdir, target_framework): + # Backup the original project file (Payload.csproj.orig) and replace the active Payload.csproj TargetFramework value + csproj = f"{base_dir}{os.sep}{template_directory}{os.sep}Payload.csproj" + if not os.path.exists(csproj + ".orig"): + with open(csproj + ".orig", "w") as orig: + with open(csproj, "r") as active: + data = active.read() + orig.write(data) + else: + with open(csproj + ".orig", "r") as orig: + data = orig.read() + data = re.sub("[^<]+", f"{target_framework}", data) + with open(csproj, "w") as active: + active.write(data) + # Build the encrypted version of the shellcode and save it to output.shellcode - build_command = "cd {0}/{1}/ && dotnet run > output.shellcode".format(base_dir, sdir) - os.system(build_command) + build_command = ["dotnet", "run"] + os.chdir(f"{base_dir}{os.sep}{sdir}") + + proc = subprocess.run(build_command, capture_output=True) + with open("output.shellcode", "w") as fp: + fp.write(proc.stdout.decode()) # Open the shellcode - shellcode_path = "{0}/{1}/output.shellcode".format(base_dir, sdir) + shellcode_path = f"{base_dir}{os.sep}{sdir}{os.sep}output.shellcode" shellcode = open(shellcode_path,"r") shelcode_data = shellcode.read() # Open the original C# code for the payload - original_code_path = "{0}/{1}/template".format(base_dir, template_directory) + original_code_path = f"{base_dir}{os.sep}{template_directory}{os.sep}template" original = open(original_code_path, "r") data = original.read() # Grab the decryption code to place in template - decryption_code_path = "{0}/{1}/decrypt.txt".format(base_dir, encoder) + decryption_code_path = f"{base_dir}{os.sep}{encoder}{os.sep}decrypt.txt" decrypt_file = open(decryption_code_path,"r") decrypt_code = decrypt_file.read() @@ -78,38 +98,53 @@ def generatePayload(encoder, template_directory, key, sdir): if key != "false": data = data.replace("KEYHERE", key) original.close() - tmp_tempate_path = "{0}/{1}/Program.cs".format(base_dir, template_directory) + tmp_tempate_path = f"{base_dir}{os.sep}{template_directory}{os.sep}Program.cs" template = open(tmp_tempate_path, "w+") template.write(data) shellcode.close() decrypt_file.close() -def cleanUp(encoder,template_directory,outfile,sdir): +def cleanUp(encoder,template_directory,outfile,sdir,target_framework): #TO DO improve cleaning up of files - compile_command = "cd {0}/{1} && dotnet publish -c Release -r win10-x64".format(base_dir, template_directory) - os.system(compile_command) + compile_command = ["dotnet", "publish", "-c", "Release", "-r", "win10-x64"] + os.chdir(f"{base_dir}{os.sep}{template_directory}") + _ = subprocess.run(compile_command) - copy_command = r"copy {}\{}\bin\Release\net45\win10-x64\payload.exe {}\{} /Y".format(base_dir, template_directory, base_dir, outfile) - os.system(copy_command) + #copy_command + src = f"{base_dir}{os.sep}{template_directory}{os.sep}bin{os.sep}Release{os.sep}{target_framework}{os.sep}win10-x64{os.sep}payload.exe" + dst = f"{base_dir}{os.sep}{outfile}" + if os.path.exists(src): + shutil.copyfile(src, dst) time.sleep(0.5) if not args.noclean: - delete_template_command = r"del {}\{}\Program.cs && del {}\{}\Program.cs && rd /s/q {}\{}\bin".format(base_dir,template_directory,base_dir,sdir,base_dir,template_directory) - os.system(delete_template_command) - - delete_shellcode_command = "del {}\{}\output.shellcode".format(base_dir, sdir) - os.system(delete_shellcode_command) - - delete_bin_directory = r"rd /s/q {}\{}\bin".format(base_dir, sdir) - os.system(delete_bin_directory) - - delete_obj_directory_command = r"rd /s/q {}\{}\obj".format(base_dir,sdir) - os.system(delete_obj_directory_command) - - delete_template_directory_command = r"rd /s/q {}\{}\obj".format(base_dir, template_directory) - os.system(delete_template_directory_command) + # delete template + os.remove(f"{base_dir}{os.sep}{template_directory}{os.sep}Program.cs") + os.remove(f"{base_dir}{os.sep}{sdir}{os.sep}Program.cs") + # delete shellcode + os.remove(f"{base_dir}{os.sep}{sdir}{os.sep}output.shellcode") + + try: + shutil.rmtree(f"{base_dir}{os.sep}{template_directory}{os.sep}bin") + except FileNotFoundError: + pass + try: + # delete bin directory + shutil.rmtree(f"{base_dir}{os.sep}{sdir}{os.sep}bin") + except FileNotFoundError: + pass + try: + # delete obj directory + shutil.rmtree(f"{base_dir}{os.sep}{sdir}{os.sep}obj") + except FileNotFoundError: + pass + try: + # delete template directory + shutil.rmtree(f"{base_dir}{os.sep}{template_directory}{os.sep}obj") + except FileNotFoundError: + pass else: print("Files not cleaned as -noclean flag present") @@ -172,6 +207,24 @@ def cleanUp(encoder,template_directory,outfile,sdir): required=False, ) +# https://docs.microsoft.com/en-us/dotnet/standard/frameworks +target_frameworks = ["netcoreapp1.0", "netcoreapp1.1", "netcoreapp2.0", "netcoreapp2.1", + "netcoreapp2.2", "netcoreapp3.0", "netcoreapp3.1", "net5.0", "net6.0", + "netstandard1.0", "netstandard1.1", "netstandard1.2", "netstandard1.3", + "netstandard1.4", "netstandard1.5", "netstandard1.6", "netstandard2.0", + "netstandard2.1", "net11", "net20", "net35", "net40", "net403", "net45", + "net451", "net452", "net46", "net461", "net462", "net47", "net471", + "net472", "net48"] +requiredNamed.add_argument( + "-targetframework", + dest="target_framework", + help="Override the target framework moniker in Payload.csproj project file", + required=False, + metavar="TFM", + choices=target_frameworks, + default="net45" +) + args = parser.parse_args() #TO DO - check encrypt/decrypt file in method folder for presence of KEYHERE. If present and args.key = false then break and alert. @@ -196,8 +249,8 @@ def cleanUp(encoder,template_directory,outfile,sdir): print("> Creating encoded shellcode from CS file") generateEncodedShell(args.method,args.key,args.file, args.shelldir) print("> Generating payload") -generatePayload(args.method,args.templatedir,args.key, args.shelldir) +generatePayload(args.method,args.templatedir,args.key, args.shelldir, args.target_framework) print("> Cleanup") -cleanUp(args.method, args.templatedir, args.out, args.shelldir) +cleanUp(args.method, args.templatedir, args.out, args.shelldir, args.target_framework) print("\nIf you didn't see a bunch of red lines before this message, you should see " + args.out + " now :)") exit() From abf14f581730f73c189b5e2cdb670f85f3a09d56 Mon Sep 17 00:00:00 2001 From: nomuus <927151+nomuus@users.noreply.github.com> Date: Wed, 6 Jul 2022 18:25:38 -0500 Subject: [PATCH 2/2] documentation on linux support --- Linux.md | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 Linux.md diff --git a/Linux.md b/Linux.md new file mode 100644 index 0000000..9a4d0de --- /dev/null +++ b/Linux.md @@ -0,0 +1,92 @@ +# .NET for Linux + +.NET is supported on Linux through official Microsoft packages or manual installation. Installation instructions for supported operating systems and package management systems are available through the Microsoft .NET Core site. + +General steps are as follows: + +1) [Microsoft: Install .NET on Linux](https://docs.microsoft.com/en-us/dotnet/core/install/linux). For example, instructions are listed for [Debian](https://docs.microsoft.com/en-us/dotnet/core/install/linux) as well as other Linux operating systems. + +2) Install the SDK, making sure to complete any pre-installation steps such as removing previous versions, adding package management repositories and signing keys, dependencies, etc. + +3) Make note of any instructions to install other .NET versions other than the latest versiopn. For example, Microsoft states for [Debian](https://docs.microsoft.com/en-us/dotnet/core/install/linux): + + > The packages added to package manager feeds are named in a hackable format, for example: {product}-{type}-{version}. + > + > ... + > + > - version + > + > The version of the SDK or runtime to install. This article will always give the instructions for the latest supported version. Valid options are any released version, such as: + > + > - 5.0 + > - 3.1 + > - 3.0 + > - 2.1 + > + > ... + > + > Install the .NET Core 3.1 SDK: `dotnet-sdk-3.1` + +4) Check installed .NET versions after installation is completed, for example: + + ```$``` ```dotnet --list-sdks``` + + ```3.1.420 [/usr/share/dotnet/sdk]``` + + +# Linux Support +The source has been minimally refactored to support Linux paths and file system operations. The tool will also create a backup of the original project file, for example, `Payload.csproj.orig` to avoid inadvertedly globbering it. + +The tool now supports the replacing the target framework moniker (TFM) within the templates SDK-style project files and is specifically hardcoded to look for `Payload.csproj`. This is implemented as an optional argument `-targetframework TFM`. By default, it will use `net45` to support the versions in the original template project files (backward compatibility). + +**The `net45` version will fail on Linux since it is not a supported .NET version on Linux.** + +For Linux, simply use the `-targetframework` command line argument to align with the installed version. This will modify the specified template's `TargetVersion` tag. For example, `-targetframework netcoreapp3.1` will read `Payload.csproj.orig`, replace the string, then create a new version of `Payload.csproj` with the .NET Core 3.1 SDK string `netcoreapp3.1`. + +## Example + +After installing .NET on Linux then executing `python3 nsgencs.py` with the proper arguments, an error will likely be thrown resembling the following: + +```$``` ```python3 NSGenCS.py -file msgbox.cs -method xor -template Thread_Hijack -key 22``` +``` +... + +> Creating encoded shellcode from CS file +> Generating payload +> Cleanup +Microsoft (R) Build Engine version 16.7.2+b60ddb6f4 for .NET +Copyright (C) Microsoft Corporation. All rights reserved. + + Determining projects to restore... + Restored /home/user/NSGenCS/Thread_Hijack/Payload.csproj (in 92 ms). +/usr/share/dotnet/sdk/3.1.420/Microsoft.Common.CurrentVersion.targets(1177,5): error MSB3644: The reference assemblies for .NETFramework,Version=v4.5 were not found. To resolve this, install the Developer Pack (SDK/Targeting Pack) for this framework version or retarget your application. You can download .NET Framework Developer Packs at https://aka.ms/msbuild/developerpacks [/home/user/NSGenCS/Thread_Hijack/Payload.csproj] +``` + +In the above example, the .NET Core 3.1 SDK has been installed but `dotnet` is failing due to target version defined in the project file. + +To resolve, use the `-targetframework`. + +```$``` ```python3 NSGenCS.py -file msgbox.cs -method xor -template Thread_Hijack -key 22 -targetframework netcoreapp3.1``` + +``` +... + +> Creating encoded shellcode from CS file +> Generating payload +> Cleanup +Microsoft (R) Build Engine version 16.7.2+b60ddb6f4 for .NET +Copyright (C) Microsoft Corporation. All rights reserved. + + Determining projects to restore... + Restored /home/user/NSGenCS/Thread_Hijack/Payload.csproj (in 141 ms). + Payload -> /home/user/NSGenCS/Thread_Hijack/bin/Release/netcoreapp3.1/win10-x64/Payload.dll + Payload -> /home/user/NSGenCS/Thread_Hijack/bin/Release/netcoreapp3.1/win10-x64/publish/ + +If you didn't see a bunch of red lines before this message, you should see payload.exe now :) +``` + +## Additional Information + +More information on the TFMs can be found on Microsoft's site, [Target frameworks in SDK-style projects](https://docs.microsoft.com/en-us/dotnet/standard/frameworks). + +More information on the the project file syntax can be found on Microsoft's site, [Target Framework Monikers define build time APIs](https://docs.microsoft.com/en-us/dotnet/core/versions/selection#target-framework-monikers-define-build-time-apis) \ No newline at end of file