Telegram and hashcat.
#9
okay, I just spend a couple of free minutes to come up with this perl script (POC):
telegram_desktop.pl
Code:
#!/usr/bin/env perl

# Author: philsmd
# Date: February 2020
# License: public domain, credits go to philsmd and hashcat

use strict;
use warnings;

use Crypt::PBKDF2;
use Digest::SHA1 qw (sha1);
use Crypt::Mode::ECB;

#
# Constants:
#

my $AES256_IGE_BLOCK_SIZE = 16;

#
# Helper functions:
#

sub exclusive_or
{
  my $in1 = shift;
  my $in2 = shift;

  # MIN () function (should always be 16 for us):
  # my $len = (length ($in1) <= length ($in2)) ? length ($in2) : length ($in1);

  # padding if input not multiple of block size:
  # $in1 .= "\x00" x ($AES256_IGE_BLOCK_SIZE - $len);
  # $in2 .= "\x00" x ($AES256_IGE_BLOCK_SIZE - $len);

  my $out = "";

  for (my $i = 0; $i < $AES256_IGE_BLOCK_SIZE; $i++) # $i < $len
  {
    $out .= chr (ord (substr ($in1, $i, 1)) ^ ord (substr ($in2, $i, 1)));
  }

  return $out;
}

sub aes256_decrypt_ige
{
  my $key = shift;
  my $iv  = shift;
  my $in  = shift;

  my $x_prev = substr ($iv,                      0, $AES256_IGE_BLOCK_SIZE);
  my $y_prev = substr ($iv, $AES256_IGE_BLOCK_SIZE, $AES256_IGE_BLOCK_SIZE);

  my $m = Crypt::Mode::ECB->new ('AES', 0);

  my $out = "";

  for (my $i = 0; $i < length ($in); $i += $AES256_IGE_BLOCK_SIZE)
  {
    my $x = substr ($in, $i, $AES256_IGE_BLOCK_SIZE);

    my $y_xor = exclusive_or ($x, $y_prev);

    my $y_final = $m->decrypt ($y_xor, $key);
    # $y_final .= "\x00" x ($AES256_IGE_BLOCK_SIZE - length ($y_final));

    my $y = exclusive_or ($y_final, $x_prev);

    $x_prev = $x;
    $y_prev = $y;

    $out .= $y;
  }

  return $out;
}

#
# Example:
#

# examples from JTR: https://github.com/magnumripper/JohnTheRipper/blob/b7cea20625354e8a009a3a66e9061792babefef2/src/telegram_common_plug.c#L14-L15

# Example 1:

# $telegram$1*4000*e693c27ff92fe83a5a247cce198a8d6a0f3a89ffedc6bcddbc39586bb1bcb50b*d6fb7ebda06a23a9c42fc57c39e2c3128da4ee1ff394f17c2fc4290229e13d1c9e45c42ef1aee64903e5904c28cffd49498358fee96eb01888f2251715b7a5e71fa130918f46da5a2117e742ad7727700e924411138bb8d4359662da0ebd4f4357d96d1aa62955e44d4acf2e2ac6e0ce057f48fe24209090fd35eeac8a905aca649cafb2aade1ef7a96a7ab44a22bd7961e79a9291b7fea8749dd415f2fcd73d0293cdb533554f396625f669315c2400ebf6f1f30e08063e88b59b2d5832a197b165cdc6b0dc9d5bfa6d5e278a79fa101e10a98c6662cc3d623aa64daada76f340a657c2cbaddfa46e35c60ecb49e8f1f57bc170b8064b70aa2b22bb326915a8121922e06e7839e62075ee045b8c82751defcba0e8fb75c32f8bbbdb8b673258:openwall123

my $iterations = 4000;

my $word = "openwall123";

my $salt = pack ("H*", "e693c27ff92fe83a5a247cce198a8d6a0f3a89ffedc6bcddbc39586bb1bcb50b");
my $data = pack ("H*", "d6fb7ebda06a23a9c42fc57c39e2c3128da4ee1ff394f17c2fc4290229e13d1c9e45c42ef1aee64903e5904c28cffd49498358fee96eb01888f2251715b7a5e71fa130918f46da5a2117e742ad7727700e924411138bb8d4359662da0ebd4f4357d96d1aa62955e44d4acf2e2ac6e0ce057f48fe24209090fd35eeac8a905aca649cafb2aade1ef7a96a7ab44a22bd7961e79a9291b7fea8749dd415f2fcd73d0293cdb533554f396625f669315c2400ebf6f1f30e08063e88b59b2d5832a197b165cdc6b0dc9d5bfa6d5e278a79fa101e10a98c6662cc3d623aa64daada76f340a657c2cbaddfa46e35c60ecb49e8f1f57bc170b8064b70aa2b22bb326915a8121922e06e7839e62075ee045b8c82751defcba0e8fb75c32f8bbbdb8b673258");


# Example 2:

# $telegram$1*4000*e693c27ff92fe83a5a247cce198a8d6a0f3a89ffedc6bcddbc39586bb1bcb50b*7c04a5becb2564fe4400c124f5bb5f1896117327d8a21f610bd431171f606fa6e064c088aacc59d8eae4e6dce539abdba5ea552f5855412c26284bc851465d6b31949b276f4890fc212d63d73e2ba132d6098688f2a6408b9d9d69c3db4bcd13dcc3a5f80a7926bb11eb2c99c7f02b5d9fd1ced974d18ed9d667deae4be8df6a4a97ed8fae1da90d5131a7536535a9bfa8094ca7f7465deabef00ab4c715f151d016a879197b328c74dfad5b1f854217c741cf3e0297c63c3fb4d5d672d1e31d797b2c01cb8a254f80a37b6c9a011d864c21c4145091f22839a52b6daf23ed2f350f1deb275f1b0b4146285ada0f0b168ce54234854b19ec6657ad0a92ffb0f3b86547c8b8cc3655a29797c398721e740ed606a71018d16545c78ee240ff3635:öye

# my $iterations = 4000;
#
# my $word = "öye";
#
# my $salt = pack ("H*", "e693c27ff92fe83a5a247cce198a8d6a0f3a89ffedc6bcddbc39586bb1bcb50b");
# my $data = pack ("H*", "7c04a5becb2564fe4400c124f5bb5f1896117327d8a21f610bd431171f606fa6e064c088aacc59d8eae4e6dce539abdba5ea552f5855412c26284bc851465d6b31949b276f4890fc212d63d73e2ba132d6098688f2a6408b9d9d69c3db4bcd13dcc3a5f80a7926bb11eb2c99c7f02b5d9fd1ced974d18ed9d667deae4be8df6a4a97ed8fae1da90d5131a7536535a9bfa8094ca7f7465deabef00ab4c715f151d016a879197b328c74dfad5b1f854217c741cf3e0297c63c3fb4d5d672d1e31d797b2c01cb8a254f80a37b6c9a011d864c21c4145091f22839a52b6daf23ed2f350f1deb275f1b0b4146285ada0f0b168ce54234854b19ec6657ad0a92ffb0f3b86547c8b8cc3655a29797c398721e740ed606a71018d16545c78ee240ff3635");

#
# Start:
#

my $pbkdf = Crypt::PBKDF2->new
(
  hash_class => 'HMACSHA1',
  iterations => $iterations,
  output_len => 136 # 256
);

my $authkey = $pbkdf->PBKDF2 ($salt, $word);

my $data_a = "\x00" x 48;
my $data_b = "\x00" x 48;
my $data_c = "\x00" x 48;
my $data_d = "\x00" x 48;

my $message_key = substr ($data, 0, 16);
my $message     = substr ($data, 16);

substr ($data_a,  0, 16) = $message_key; # memcpy ()
substr ($data_b, 16, 16) = $message_key;
substr ($data_c, 32, 16) = $message_key;
substr ($data_d,  0, 16) = $message_key;

substr ($data_a, 16, 32) = substr ($authkey,   8, 32);
substr ($data_b,  0, 16) = substr ($authkey,  40, 16);
substr ($data_b, 32, 16) = substr ($authkey,  56, 16);
substr ($data_c,  0, 32) = substr ($authkey,  72, 32);
substr ($data_d, 16, 32) = substr ($authkey, 104, 32);

my $sha1_a = sha1 ($data_a);
my $sha1_b = sha1 ($data_b);
my $sha1_c = sha1 ($data_c);
my $sha1_d = sha1 ($data_d);

my $aes_key = substr ($sha1_a, 0,  8) . #  8 + 12 + 12      = 32
              substr ($sha1_b, 8, 12) .
              substr ($sha1_c, 4, 12);

my $aes_iv = substr ($sha1_a,  8, 12) . # 12 +  8 +  4 +  8 = 32
             substr ($sha1_b,  0,  8) .
             substr ($sha1_c, 16,  4) .
             substr ($sha1_d,  0,  8);


# AES256 IGE decrypt:

my $decrypted_data = aes256_decrypt_ige ($aes_key, $aes_iv, $message);


# "checksum" of raw data:

my $hash = sha1 ($decrypted_data);

$hash = substr ($hash, 0, 16);


# compare:

if ($hash eq $message_key)
{
  print "Password found: '$word'\n";
}


the only "problem" is the non-widely use AES IGE mode of operation (basically mostly used in Telegram only):
aes256_ige.pl (translated to perl from https://mgp25.com/AESIGE/#php-implementation)
Code:
#!/usr/bin/env perl

# Author: philsmd
# Date: February 2020
# License: public domain, credits go to philsmd and hashcat

use strict;
use warnings;

use Crypt::Mode::ECB;

#
# Constants:
#

my $AES256_IGE_BLOCK_SIZE = 16;

#
# Helper functions:
#

sub exclusive_or
{
  my $in1 = shift;
  my $in2 = shift;

  # MIN () function (should always be 16 for us):
  # my $len = (length ($in1) <= length ($in2)) ? length ($in2) : length ($in1);

  # padding if input not multiple of block size:
  # $in1 .= "\x00" x ($AES256_IGE_BLOCK_SIZE - $len);
  # $in2 .= "\x00" x ($AES256_IGE_BLOCK_SIZE - $len);

  my $out = "";

  for (my $i = 0; $i < $AES256_IGE_BLOCK_SIZE; $i++) # $i < $len
  {
    $out .= chr (ord (substr ($in1, $i, 1)) ^ ord (substr ($in2, $i, 1)));
  }

  return $out;
}

sub aes256_encrypt_ige
{
  my $key = shift;
  my $iv  = shift;
  my $in  = shift;

  my $x_prev = substr ($iv, $AES256_IGE_BLOCK_SIZE, $AES256_IGE_BLOCK_SIZE);
  my $y_prev = substr ($iv,                      0, $AES256_IGE_BLOCK_SIZE);

  my $m = Crypt::Mode::ECB->new ('AES', 0);

  my $out = "";

  for (my $i = 0; $i < length ($in); $i += $AES256_IGE_BLOCK_SIZE)
  {
    my $x = substr ($in, $i, $AES256_IGE_BLOCK_SIZE);

    my $y_xor = exclusive_or ($x, $y_prev);

    my $y_final = $m->encrypt ($y_xor, $key);
    # $y_final .= "\x00" x ($AES256_IGE_BLOCK_SIZE - length ($y_final));

    my $y = exclusive_or ($y_final, $x_prev);

    $x_prev = $x;
    $y_prev = $y;

    $out .= $y;
  }

  return $out;
}

sub aes256_decrypt_ige
{
  my $key = shift;
  my $iv  = shift;
  my $in  = shift;

  my $x_prev = substr ($iv,                      0, $AES256_IGE_BLOCK_SIZE);
  my $y_prev = substr ($iv, $AES256_IGE_BLOCK_SIZE, $AES256_IGE_BLOCK_SIZE);

  my $m = Crypt::Mode::ECB->new ('AES', 0);

  my $out = "";

  for (my $i = 0; $i < length ($in); $i += $AES256_IGE_BLOCK_SIZE)
  {
    my $x = substr ($in, $i, $AES256_IGE_BLOCK_SIZE);

    my $y_xor = exclusive_or ($x, $y_prev);

    my $y_final = $m->decrypt ($y_xor, $key);
    # $y_final .= "\x00" x ($AES256_IGE_BLOCK_SIZE - length ($y_final));

    my $y = exclusive_or ($y_final, $x_prev);

    $x_prev = $x;
    $y_prev = $y;

    $out .= $y;
  }

  return $out;
}

#
# Examples:
#

# take from https://mgp25.com/AESIGE/#test-vectors:

# Example 1:

my $key         = pack ("H*", "000102030405060708090a0b0c0d0e0f");
my $iv          = pack ("H*", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
my $plain_text  = pack ("H*", "0000000000000000000000000000000000000000000000000000000000000000");
my $cipher_text = pack ("H*", "1a8519a6557be652e9da8e43da4ef4453cf456b4ca488aa383c79c98b34797cb");

# Example 2:

# my $key         = pack ("H*", "5468697320697320616e20696d706c65");
# my $iv          = pack ("H*", "6d656e746174696f6e206f6620494745206d6f646520666f72204f70656e5353");
# my $plain_text  = pack ("H*", "99706487a1cde613bc6de0b6f24b1c7aa448c8b9c3403e3467a8cad89340f53b");
# my $cipher_text = pack ("H*", "4c2e204c6574277320686f70652042656e20676f74206974207269676874210a");

#
# Start
#

# encrypt:

print unpack ("H*", aes256_encrypt_ige ($key, $iv, $plain_text)) . "\n";

# decrypt:

print unpack ("H*", aes256_decrypt_ige ($key, $iv, $cipher_text)) . "\n";

so now I've already managed to perform the most important/difficult part to come up with a POC perl script (that we could copy-paste to our test modules in tools/test_modules/)... the missing parts now would be to see what are some input restrictions (data length, salt, iter min/max values) and write the host and kernel code in hashcat. We would probably need that somebody explains this in a github issue with some further examples and facts ... after that a developer could easily start implementing it (if there is enough interest in this algo !?).
Reply


Messages In This Thread
Telegram and hashcat. - by Hack3rcon - 01-16-2020, 11:36 AM
RE: Telegram and hashcat. - by philsmd - 01-16-2020, 11:44 AM
RE: Telegram and hashcat. - by Hack3rcon - 01-16-2020, 12:41 PM
RE: Telegram and hashcat. - by philsmd - 01-16-2020, 01:10 PM
RE: Telegram and hashcat. - by zamok1980 - 01-20-2020, 05:07 PM
RE: Telegram and hashcat. - by undeath - 01-20-2020, 07:07 PM
RE: Telegram and hashcat. - by zamok1980 - 01-20-2020, 07:30 PM
RE: Telegram and hashcat. - by philsmd - 02-26-2020, 01:19 PM
RE: Telegram and hashcat. - by philsmd - 02-28-2020, 04:45 PM
RE: Telegram and hashcat. - by philsmd - 04-08-2020, 12:13 PM