Skip to content

Commit

Permalink
Merge pull request #91 from odedshimon/improve-kerberos-parsing
Browse files Browse the repository at this point in the history
Improve kerberos parsing
  • Loading branch information
odedshimon authored May 1, 2021
2 parents 572c8ff + 22964e6 commit 4333c6e
Show file tree
Hide file tree
Showing 17 changed files with 258 additions and 71 deletions.
2 changes: 2 additions & 0 deletions BruteShark/BruteForce/Hashes/KerberosAsRepHash.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ namespace BruteForce
{
public class KerberosAsRepHash : Hash
{
// TODO: use enum
public int Etype { get; set; }
public string Realm { get; set; }
public string Username { get; set; }
public string ServiceName { get; set; }
Expand Down
2 changes: 2 additions & 0 deletions BruteShark/BruteForce/Hashes/KerberosTgsRepHash.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ namespace BruteForce
{
public class KerberosTgsRepHash : Hash
{
// TODO: use enum
public int Etype { get; set; }
public string Realm { get; set; }
public string Username { get; set; }
public string ServiceName { get; set; }
Expand Down
68 changes: 49 additions & 19 deletions BruteShark/BruteForce/Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

namespace BruteForce
{
[Serializable]
public class NotSupportedHashcatHash : Exception
{
public NotSupportedHashcatHash(string message) : base(message) { }
}

public static class Utilities
{
public static string ConvertToHashcatFormat(Hash hash)
Expand Down Expand Up @@ -34,37 +40,61 @@ public static string ConvertToHashcatFormat(Hash hash)
}
else
{
throw new Exception("Hash type not supported");
throw new NotSupportedHashcatHash("Hash type not supported");
}

return res;
}

public static string ConvertToHashcatFormat(KerberosTgsRepHash kerberosHash)
{
// Acording to Hashcat examples page this is the format:
// $krb5tgs$23$*user$realm$test/spn*$63386d22d359fe42230300d56852c9eb$891ad31d09ab89c6b3b8c5e5de6....
// return string.Format("$krb5tgs$23${0}${1}${2}${3}${4}",
// kerberosHash.Username,
// kerberosHash.Realm,
// kerberosHash.ServiceName,
// kerberosHash.HashedData.Substring(0, 32),
// kerberosHash.HashedData.Substring(32));
if (kerberosHash.Etype == 23)
{
// On Kerberos RC4 (Etype 23) the checksum part is the first 16 bytes of the cipher and the
// hash is the data from the 16 byte.
return string.Format("$krb5tgs${0}$*{1}${2}${3}*${4}${5}",
kerberosHash.Etype,
kerberosHash.Username,
kerberosHash.Realm,
kerberosHash.ServiceName,
kerberosHash.HashedData.Substring(0, 32),
kerberosHash.HashedData.Substring(32));
}
else if (kerberosHash.Etype == 18 || kerberosHash.Etype == 17)
{
// On Kerberos AES 128\256 (Etype 17\18) the checksum part is the last 12 bytes of the
// cipher and the hash the cipher without the 12 bytes.
var checksumStartPosition = kerberosHash.HashedData.Length - 24;

// But at other places i saw this format, this is worked great with Hashcat 6.0.
return string.Format("$krb5tgs$23${0}${1}",
kerberosHash.HashedData.Substring(0, 32),
kerberosHash.HashedData.Substring(32));
return String.Format("$krb5tgs${0}${1}${2}$*{3}*${4}${5}",
kerberosHash.Etype,
kerberosHash.Username,
kerberosHash.Realm,
kerberosHash.ServiceName,
kerberosHash.HashedData.Substring(checksumStartPosition),
kerberosHash.HashedData.Substring(0, checksumStartPosition));
}
else
{
throw new NotSupportedHashcatHash($"Kerberos TGS-REP Etype {kerberosHash.Etype} is not supported by Hashcat");
}
}

public static string ConvertToHashcatFormat(KerberosAsRepHash kerberosHash)
{
// [email protected]:3e156ada591263b8aab0965f5aebd837$007497cb5....
return string.Format("$krb5asrep$23${0}@{1}:{2}${3}",
kerberosHash.Username,
kerberosHash.Realm,
kerberosHash.HashedData.Substring(0, 32),
kerberosHash.HashedData.Substring(32));
if (kerberosHash.Etype == 23)
{
// [email protected]:3e156ada591263b8aab0965f5aebd837$007497cb5....
return string.Format("$krb5asrep$23${0}@{1}:{2}${3}",
kerberosHash.Username,
kerberosHash.Realm,
kerberosHash.HashedData.Substring(0, 32),
kerberosHash.HashedData.Substring(32));
}
else
{
throw new NotSupportedHashcatHash($"Kerberos AS-REP Etype {kerberosHash.Etype} is not supported by Hashcat");
}
}

public static string ConvertToHashcatFormat(KerberosHash kerberosHash)
Expand Down
2 changes: 1 addition & 1 deletion BruteShark/BruteSharkCli/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"profiles": {
"BruteSharkCli": {
"commandName": "Project",
"commandLineArgs": " -d C:\\\\Users\\King\\\\Desktop\\SIP-RTP_examples -m Voip -o C:\\Users\\King\\Desktop\\Test"
"commandLineArgs": "-d C:\\\\Users\\King\\\\github\\BS_SEP\\BruteShark\\Pcap_Examples -m Credentials,NetworkMap,FileExtracting,DNS -o C:\\\\Users\\King\\Desktop\\Test"
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,13 @@ private void CreateHashcatFileButton_Click(object sender, EventArgs e)

MessageBox.Show($"Hashes exported: {outputFilePath}");
}
catch (Exception Ex)
catch (BruteForce.NotSupportedHashcatHash ex)
{
MessageBox.Show("Failed to export hashes");
MessageBox.Show($"Hashcat does not support this hash type: {ex.Message}");
}
catch (Exception ex)
{
MessageBox.Show($"Failed to export hashes: {ex.Message}");
}
}

Expand Down
6 changes: 5 additions & 1 deletion BruteShark/BruteSharkDesktopInstaller/Product.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<Product
Id="CE452A31-5E74-41BE-A768-EBEE7B325862"
Name="BruteSharkDesktop"
Language="1033" Version="1.2.8.0"
Language="1033" Version="1.2.9.0"
Manufacturer="Oded Shimon"
UpgradeCode="9bec2dfd-0f30-466a-9077-cf86db101cac">

Expand Down Expand Up @@ -155,6 +155,10 @@
<File Id="CommonUi.dll" Source="$(var.BruteSharkDesktop.TargetDir)" Name="CommonUi.dll" />
</Component>

<Component Id="System.Text.Encodings.Web.dll">
<File Id="System.Text.Encodings.Web.dll" Source="$(var.BruteSharkDesktop.TargetDir)" Name="System.Text.Encodings.Web.dll" />
</Component>

</ComponentGroup>
</Fragment>
</Wix>
2 changes: 2 additions & 0 deletions BruteShark/CommonUi/Casting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ private static BruteForce.Hash CastAnalyzerHashToBruteForceHash(PcapAnalyzer.Ker
{
return new BruteForce.KerberosTgsRepHash()
{
Etype = kerberosTgsRepHash.Etype,
ServiceName = kerberosTgsRepHash.ServiceName,
Realm = kerberosTgsRepHash.Realm,
HashedData = kerberosTgsRepHash.Hash,
Expand Down Expand Up @@ -155,6 +156,7 @@ private static BruteForce.Hash CastAnalyzerHashToBruteForceHash(PcapAnalyzer.Ker
{
return new BruteForce.KerberosAsRepHash()
{
Etype = kerberosAsRepHash.Etype,
ServiceName = kerberosAsRepHash.ServiceName,
Realm = kerberosAsRepHash.Realm,
HashedData = kerberosAsRepHash.Hash,
Expand Down
1 change: 1 addition & 0 deletions BruteShark/CommonUi/Exporting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public static string ExportFiles(string dirPath, HashSet<PcapAnalyzer.NetworkFil

return extractedFilesDir;
}

public static string ExportVoipCalls(string dirPath, HashSet<VoipCall> voipCalls )
{
var VoipCallsDir = Path.Combine(dirPath, "VoipCalls");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,35 @@ public enum MessageType : byte
krb_tgs_rep = 13
}

public static object GetKerberosPacket(byte[] kerberosBuffer)
public static object GetKerberosPacket(byte[] kerberosBuffer, string protocol)
{
object result = null;

// Consider the TCP Record Mark when parsing Kerberos over TCP packets.
if (protocol == "TCP")
{
var recordMarkLengthBuffer = kerberosBuffer.SubArray(0, 4);

// The return value of ToInt32 method depends on system architecture.
// Therfore we explicitly enforce BigEndian.
if (BitConverter.IsLittleEndian)
Array.Reverse(recordMarkLengthBuffer);

var recordMarkLength = BitConverter.ToInt32(recordMarkLengthBuffer, 0);

if (recordMarkLength + 4 <= kerberosBuffer.Length)
kerberosBuffer = kerberosBuffer.SubArray(4, recordMarkLength);
else
throw new Exception("Kerberos record mark length is out of range");
}

byte[] asn_buffer = AsnIO.FindBER(kerberosBuffer);

if (asn_buffer != null)
{
AsnElt asn_object = AsnElt.Decode(asn_buffer);

// Get the application number
// Get the application number.
switch (asn_object.TagValue)
{
case (int)MessageType.krb_tgs_rep:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,51 +16,51 @@ public NetworkLayerObject Parse(TcpPacket tcpPacket) =>

private NetworkLayerObject GetKerberosTicketsHash(string source, string destination, string protocol, byte[] data)
{
var kerberosPacket = KerberosPacketParser.GetKerberosPacket(data);
var kerberosPacket = KerberosPacketParser.GetKerberosPacket(data, protocol);

if (kerberosPacket is null)
{
return null;
}

// TODO: refactor this boilerplate code
// TODO: use enum for hashes types
if (kerberosPacket is KerberosTgsRepPacket)
{
var kerberosTgsRepPacket = kerberosPacket as KerberosTgsRepPacket;

if (kerberosTgsRepPacket.Ticket.EncrytedPart.Etype == 23)
if (kerberosTgsRepPacket.Ticket.EncrytedPart.Etype == 23 || kerberosTgsRepPacket.Ticket.EncrytedPart.Etype == 18 || kerberosTgsRepPacket.Ticket.EncrytedPart.Etype == 17)
{
return new KerberosTgsRepHash()
{
Source = source,
Destination = destination,
Realm = kerberosTgsRepPacket.Ticket.Realm,
Etype = 23,
Etype = kerberosTgsRepPacket.Ticket.EncrytedPart.Etype,
Username = kerberosTgsRepPacket.Cname.Name,
ServiceName = kerberosTgsRepPacket.Ticket.Sname.Name,
Hash = NtlmsspHashParser.ByteArrayToHexString(kerberosTgsRepPacket.Ticket.EncrytedPart.Cipher),
Protocol = protocol,
HashType = "Kerberos V5 TGS-REP etype 23"
HashType = $"Kerberos V5 TGS-REP etype {kerberosTgsRepPacket.Ticket.EncrytedPart.Etype}"
};
}
}
else if (kerberosPacket is KerberosAsRepPacket)
{
var kerberosAsRepPacket = kerberosPacket as KerberosAsRepPacket;

if (kerberosAsRepPacket.Ticket.EncrytedPart.Etype == 23)
if (kerberosAsRepPacket.Ticket.EncrytedPart.Etype == 23 || kerberosAsRepPacket.Ticket.EncrytedPart.Etype == 18)
{
return new KerberosAsRepHash()
{
Source = source,
Destination = destination,
Realm = kerberosAsRepPacket.Ticket.Realm,
Etype = 23,
Etype = kerberosAsRepPacket.Ticket.EncrytedPart.Etype,
Username = kerberosAsRepPacket.Cname.Name,
ServiceName = kerberosAsRepPacket.Ticket.Sname.Name,
Hash = NtlmsspHashParser.ByteArrayToHexString(kerberosAsRepPacket.Ticket.EncrytedPart.Cipher),
Protocol = protocol,
HashType = "Kerberos V5 AS-REP etype 23"
HashType = $"Kerberos V5 AS-REP etype {kerberosAsRepPacket.Ticket.EncrytedPart.Etype}"
};
}
}
Expand Down
8 changes: 4 additions & 4 deletions BruteShark/PcapAnalyzer/PcapAnalyzer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
<UserSecretsId>323354f7-3e9f-4606-9a77-73084fa01769</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Asn1DotNet" Version="1.0.3"/>
<PackageReference Include="DNS" Version="6.1.0"/>
<PackageReference Include="System.Text.Json" Version="5.0.0"/>
<PackageReference Include="SIPSorcery" Version="5.0.3"/>
<PackageReference Include="Asn1DotNet" Version="1.0.4" />
<PackageReference Include="DNS" Version="6.1.0" />
<PackageReference Include="System.Text.Json" Version="5.0.2" />
<PackageReference Include="SIPSorcery" Version="5.2.0" />
</ItemGroup>
</Project>
Loading

0 comments on commit 4333c6e

Please sign in to comment.