CyberArsenal

Welcome to the forum. We focus on computer and network security as well as reverse engineering - you should sign up to see content and better yet participate. There is no payment, credits system, reply-to-reveal, or any of that here. We want quality over quantity. This is an experiment and the idea is to build a good natured and mature/professional community. Please be kind and share! Thanks.

  • ⚠️ Even if sourced from us, never blindly trust cracked software. Always utilize isolated environments (like Docker or VMs) without internet access and deny local network access. Thoroughly review scripts before execution to protect not only yourself but also your friends, family, and colleagues. Stay secure! ⚠️

Specter Insight C2 Analysys + Keygen

ByteVigil

Administrator
Staff member
You can find the keygen Here

- Download the software from original source (must register).
- Once downloaded, extract the archive SpecterInsight.zip
- It will have a lot of folders, but we're only interested into:
- client/
- server/
- Starting from the server, we will analyze:
- AmsiScanner.Common.dll which holds encryption / decryption functions
- SpecterInsight.Server.dll which holds the logic for parsing the license
- Now we can check the logic. This is the actual flow:
- You can find ImportLicense that is the actual logic to parse the license file.
C#:
public LicenseValidationInfoEx ImportLicense(string path)
{
    byte[] array = Utility.Decrypt(File.ReadAllBytes(path), "71eee87b4a514a7196cf10c42eae4af7");
    JsonSerializer serializer = new JsonSerializer();
    serializer.Formatting = Formatting.Indented;
    LicenseValidationInfoEx licenseValidationInfoEx;
    using (MemoryStream ms = new MemoryStream(array))
    {
        using (StreamReader sr = new StreamReader(ms))
        {
            using (JsonTextReader jtr = new JsonTextReader(sr))
            {
                LicenseValidationInfoEx info = serializer.Deserialize<LicenseValidationInfoEx>(jtr);
                if (info == null)
                {
                    throw new InvalidDataException("Failed to import license details.");
                }
                if (!this.IsKeyValid(info.Key))
                {
                    throw new Exception("This license is not valid. Please visit www.practicalsecurityanalytics.com to purchase a license.");
                }
                if (!info.Validate(info.CustomerEmail))
                {
                    throw new Exception("This license is not valid. Please visit www.practicalsecurityanalytics.com to update your license.");
                }
                licenseValidationInfoEx = info;
            }
        }
    }
    return licenseValidationInfoEx;
}
- As you can see, it decrypts with AES the license with the hardcoded key 71eee87b4a514a7196cf10c42eae4af7 then loads the content as JSON.
- It then uses a static Salt and a Marker
- SALT: new byte[] { 251, 51, 164, 251, 59, 131, 182, 228 };
- MARKER: new byte[] { 89, 37, 32, 212, 143, 199, 216, 38, 176, 236, 164, 32, 184, 202, 182 };
- Decryption code (inside AmsiScanner.Common.dll):
C#:
public static byte[] Decrypt(byte[] ciphertextbytes, string password = "5e16e53245c147a8acd1b3e38de0135d")
{
    Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, Utility.SALT);
    byte[] array6;
    using (AesCryptoServiceProvider aesCryptoServiceProvider = new AesCryptoServiceProvider())
    {
        aesCryptoServiceProvider.KeySize = 256;
        aesCryptoServiceProvider.BlockSize = 128;
        aesCryptoServiceProvider.Key = rfc2898DeriveBytes.GetBytes(aesCryptoServiceProvider.KeySize / 8);
        byte[] array = new byte[16];
        Array.Copy(ciphertextbytes, array, array.Length);
        aesCryptoServiceProvider.IV = array;
        ICryptoTransform cryptoTransform = aesCryptoServiceProvider.CreateDecryptor(aesCryptoServiceProvider.Key, aesCryptoServiceProvider.IV);
        using (MemoryStream memoryStream = new MemoryStream())
        {
            using (MemoryStream memoryStream2 = new MemoryStream(ciphertextbytes))
            {
                byte[] array2 = new byte[4096];
                memoryStream2.Read(array2, 0, 16);
                using (CryptoStream cryptoStream = new CryptoStream(memoryStream2, cryptoTransform, CryptoStreamMode.Read))
                {
                    int num;
                    while ((num = cryptoStream.Read(array2, 0, array2.Length)) > 0)
                    {
                        memoryStream.Write(array2, 0, num);
                    }
                }
                byte[] array3 = memoryStream.ToArray();
                byte[] array4 = new byte[Utility.MARKER.Length];
                Array.Copy(array3, array4, array4.Length);
                if (!array4.SequenceEqual(Utility.MARKER))
                {
                    throw new Exception("File is not using a supported encryption format.");
                }
                byte[] array5 = new byte[array3.Length - array4.Length];
                Array.Copy(array3, array4.Length, array5, 0, array5.Length);
                array6 = array5;
            }
        }
    }
    return array6;
}
- We can then get the License model from the ImportLicense function, as you can read it's actually LicenseValidationInfoEx
- Now we have all we need to craft the actual license.
- For simplicity, here is a demo code for that model:
C#:
LicenseValidationInfoEx licenseValidationInfoEx = new LicenseValidationInfoEx()
{
    ActivationsLeft = "999999",
    CustomerEmail = EmailInput.Text,
    CustomerName = NameInput.Text,
    Expires = DateTime.Now.AddYears(100),
    License = "valid",
    ItemId = "1094",
    ItemName = "CyberArsenal",
    LicenseLimit = "999999",
    PaymentId = 1234,
    PriceId = "1234567890",
    Success = true,
    SiteCount = "999999",
    Key = <licenseKeyEncrypted>
};
- <licenseKeyEncrypted> needs to be the Base64 URL Encoded value of the license key, which is split in two values:
- byte[] _data;
- byte[] _signature
- It then creates a new array of those two values togheter
- It gets parsed this way:
C#:
public static LicenseKey Parse(string serialized)
{
    if (serialized.Length > 256)
    {
        throw new FormatException("Invalid key length.");
    }
    byte[] array = WebEncoders.Base64UrlDecode(serialized);
    byte[] data = new byte[16];
    byte[] signature = new byte[array.Length - 16];
    Array.Copy(array, 0, data, 0, 16);
    Array.Copy(array, 16, signature, 0, signature.Length);
    return new LicenseKey(data, signature);
}
- The signature will just be a usual RSA / EDCSA Verification, so nothing really hard to replicate:
C#:
public bool Validate(X509Certificate2 pkey)
{
    bool flag;
    using (ECDsa ecdsa = pkey.GetECDsaPublicKey())
    {
        flag = ecdsa.VerifyData(this._data, this._signature, HashAlgorithmName.SHA256, DSASignatureFormat.Rfc3279DerSequence);
    }
    return flag;
}
- Pretty easy to re-create, check the keygen's code.
- Now we have averything to craft our license, let's sum up:
- Create a self signed certificate + private key as ECDSA
- Replace the Validator resource in both client and server with our own
- Run the keygen to generate a valid license
- Save the license to Specter Insight setting's folder (<base_path>/settings/license.json)
- Run the software and enjoy!

NOTE: The tutorial / writeup is not made too simple, so people can get more motivated in getting their own hands dirty and learn even more.
 
SpecterInsight C2 v5.0.0 Crack Analysis

You can find the keygen Here: Link


Download the software from original source (If you've acc) In case you don't have one download the files from here :- Link, Backup

Once downloaded, extract the archive SpecterInsight.zip
It will have a lot of folders, but we're only interested into:
  • client/
  • server/
Starting from the server, we will analyze:
  • -AmsiScanner.Common.dll which holds encryption / decryption functions
  • -SpecterInsight.Server.dll which holds the logic for parsing the license
Now we can check the logic. This is the actual flow:

You can find ImportLicense that is the actual logic to parse the license file.

C#:
public LicenseValidationInfoEx ImportLicense(string path)
{
byte[] array = Utility.Decrypt(File.ReadAllBytes(path), "5e16e53245c147a8acd1b3e38de0135d");
JsonSerializer serializer = new JsonSerializer();
serializer.Formatting = Formatting.Indented;
LicenseValidationInfoEx licenseValidationInfoEx;
using (MemoryStream ms = new MemoryStream(array))
{
using (StreamReader sr = new StreamReader(ms))
{
using (JsonTextReader jtr = new JsonTextReader(sr))
{
LicenseValidationInfoEx info = serializer.Deserialize<LicenseValidationInfoEx>(jtr);
if (info == null)
{
throw new InvalidDataException("Failed to import license details.");
}
if (!this.IsKeyValid(info.Key))
{
throw new Exception("This license is not valid. Please visit [url]www.practicalsecurityanalytics.com[/url] to purchase a license.");
}
if (!info.Validate(info.CustomerEmail))
{
throw new Exception("This license is not valid. Please visit [url]www.practicalsecurityanalytics.com[/url] to update your license.");
}
licenseValidationInfoEx = info;
}
}
}
return licenseValidationInfoEx;
}

As you can see, it decrypts with AES the license with the hardcoded key 5e16e53245c147a8acd1b3e38de0135d then loads the content as JSON. (The old key was 71eee87b4a514a7196cf10c42eae4af7)

It then uses a static Salt and a Marker

  • SALT: new byte[] { 251, 51, 164, 251, 59, 131, 182, 228 };
  • MARKER: new byte[] { 89, 37, 32, 212, 143, 199, 216, 38, 176, 236, 164, 32, 184, 202, 182 };
Decryption code (inside AmsiScanner.Common.dll) - unchanged from v4.1.0:

C#:
public static byte[] Decrypt(byte[] ciphertextbytes, string password = "5e16e53245c147a8acd1b3e38de0135d")
{
Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, Utility.SALT);
byte[] array6;
using (AesCryptoServiceProvider aesCryptoServiceProvider = new AesCryptoServiceProvider())
{
aesCryptoServiceProvider.KeySize = 256;
aesCryptoServiceProvider.BlockSize = 128;
aesCryptoServiceProvider.Key = rfc2898DeriveBytes.GetBytes(aesCryptoServiceProvider.KeySize / 8);
byte[] array = new byte[16];
Array.Copy(ciphertextbytes, array, array.Length);
aesCryptoServiceProvider.IV = array;
ICryptoTransform cryptoTransform = aesCryptoServiceProvider.CreateDecryptor(aesCryptoServiceProvider.Key, aesCryptoServiceProvider.IV);
using (MemoryStream memoryStream = new MemoryStream())
{
using (MemoryStream memoryStream2 = new MemoryStream(ciphertextbytes))
{
byte[] array2 = new byte[4096];
memoryStream2.Read(array2, 0, 16);
using (CryptoStream cryptoStream = new CryptoStream(memoryStream2, cryptoTransform, CryptoStreamMode.Read))
{
int num;
while ((num = cryptoStream.Read(array2, 0, array2.Length)) > 0)
{
memoryStream.Write(array2, 0, num);
}
}
byte[] array3 = memoryStream.ToArray();
byte[] array4 = new byte[Utility.MARKER.Length];
Array.Copy(array3, array4, array4.Length);
if (!array4.SequenceEqual(Utility.MARKER))
{
throw new Exception("File is not using a supported encryption format.");
}
byte[] array5 = new byte[array3.Length - array4.Length];
Array.Copy(array3, array4.Length, array5, 0, array5.Length);
array6 = array5;
}
}
}
return array6;
}

Now, v5.0.0 introduces a new method called CheckLicenseStatus that the UI calls to get the license object. This method was not present in v4.1.0.

Update: If you're using the keygen in the right way (i.e., you've updated the AES key and replaced the Validator resource correctly), you might not need to patch CheckLicenseStatus. However, if you see the "This server is unlicensed" banner, this patch fixes it.

C#:
public Task<LicenseValidationInfoEx> CheckLicenseStatus()
{
var info = new LicenseValidationInfoEx
{
ActivationsLeft = "999999",
CustomerEmail = "Pwn3rzs@Cyberarsenal",
CustomerName = "Pwn3rzs",
Expires = DateTime.Now.AddYears(100),
License = "valid",
ItemId = "1094",
ItemName = "CyberArsenal",
LicenseLimit = "999999",
PaymentId = 1234,
PriceId = "1234567890",
Success = true,
SiteCount = "999999",
Key = "Pwn3rzs"
};
return Task.FromResult(info);
}

We also need to patch IsKeyValid to always return true (bypass certificate check):

C#:
public bool IsKeyValid(string key)
{
return true;
}

And patch IsLicenseAppliedAndValid:

C#:
public bool IsLicenseAppliedAndValid()
{
return true;
}

We can then get the License model from the ImportLicense function, as you can read it's actually LicenseValidationInfoEx

Now we have all we need to craft the actual license.

For simplicity, here is a demo code for that model:

C#:
LicenseValidationInfoEx licenseValidationInfoEx = new LicenseValidationInfoEx()
{
ActivationsLeft = "999999",
CustomerEmail = EmailInput.Text,
CustomerName = NameInput.Text,
Expires = DateTime.Now.AddYears(100),
License = "valid",
ItemId = "1094",
ItemName = "CyberArsenal",
LicenseLimit = "999999",
PaymentId = 1234,
PriceId = "1234567890",
Success = true,
SiteCount = "999999",
Key = <licenseKeyEncrypted>
};

<licenseKeyEncrypted> needs to be the Base64 URL Encoded value of the license key, which is split in two values:

  • byte[] _data;
  • byte[] _signature
It then creates a new array of those two values together

It gets parsed this way:

C#:
public static LicenseKey Parse(string serialized)
{
if (serialized.Length > 256)
{
throw new FormatException("Invalid key length.");
}
byte[] array = WebEncoders.Base64UrlDecode(serialized);
byte[] data = new byte[16];
byte[] signature = new byte[array.Length - 16];
Array.Copy(array, 0, data, 0, 16);
Array.Copy(array, 16, signature, 0, signature.Length);
return new LicenseKey(data, signature);
}

The signature will just be a usual RSA / EDCSA Verification, so nothing really hard to replicate:

C#:
public bool Validate(X509Certificate2 pkey)
{
bool flag;
using (ECDsa ecdsa = pkey.GetECDsaPublicKey())
{
flag = ecdsa.VerifyData(this._data, this._signature, HashAlgorithmName.SHA256, DSASignatureFormat.Rfc3279DerSequence);
}
return flag;
}

Pretty easy to re-create, check the keygen's code.

Now we have everything to craft our license, let's sum up:

  • Create a self signed certificate + private key as ECDSA
Important: The P12 file MUST be without password.

Code:
openssl ecparam -name prime256v1 -genkey -noout -out cert.key
openssl req -new -key cert.key -out ecdsa_request.csr -subj "/C=RU/ST=Russia/L=Moscow/O=Pwn3rzs/OU=CyberArsenal/CN=Pwn3rzs"
openssl x509 -req -in ecdsa_request.csr -signkey cert.key -out cert.pem -days 3650
openssl pkcs12 -export -out cert.p12 -inkey cert.key -in cert.pem -name "SpecterInsight Keygen Cert" -password pass:

  • Replace the Validator resource in both client and server with our own
In v5.0.0, the Validator resource still exists in both SpecterInsight.UI.dll and SpecterInsight.Server.dll. Replace it with your cert.p12.

The Validator resource exists in both DLLs. Right-click -> Replace -> select your cert.p12.

  • Update the AES key in the keygen source code from 71eee87b4a514a7196cf10c42eae4af7 to 5e16e53245c147a8acd1b3e38de0135d
This is important. If you don't update the AES key, the keygen will generate a license that the server cannot decrypt.

  • Patch IsKeyValid, IsLicenseAppliedAndValid in SpecterInsight.Server.dll (and CheckLicenseStatus if needed)
  • Run the keygen to generate a valid license
Name and email can be anything. Select your cert.p12, leave password empty, generate license.json.

  • Save the license to Specter Insight setting's folder (<base_path>/settings/license.json)
  • Edit hosts file to block online validation:
Code:
127.0.0.1 www.practicalsecurityanalytics.com
127.0.0.1 www.practicalsecurityanalytics.com.
127.0.0.1 practicalsecurityanalytics.com
127.0.0.1 practicalsecurityanalytics.com.
::1 www.practicalsecurityanalytics.com
::1 www.practicalsecurityanalytics.com.
::1 practicalsecurityanalytics.com
::1 practicalsecurityanalytics.com.

  • Run the software and enjoy!
NOTE: The tutorial / writeup is not made too simple, so people can get more motivated in getting their own hands dirty and learn even more. Also Due to some lack of time & laziness I haven't tested it whole just some hours and it seems everything is working! Enjoy :P
 
Back
Top