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
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()