Itunes Backup
#11
(01-17-2017, 09:33 PM)epixoip Wrote: I'm not that familiar with Apple products or iTunes but assuming the algorithm is one that Hashcat supports, we should be able to modify plist2hashcat.pl to support both iOS and iTunes. Can you provide me with an example of a manifest.plist that contains the required keys?


Password is 123456


Attached Files
.zip   Manifest.zip (Size: 5.01 KB / Downloads: 57)
#12
My file is differently structured
With plistutil you can convert the file to Readable format


Attached Files
.zip   Manifest.plist.zip (Size: 9.08 KB / Downloads: 37)
#13
Just dropping in to register my interest in this as well. If any specific versions of iOS backup need to be created, I could probably help with that too. Thanks.
#14
In the manifest.plist file there are attributes in the keybag to derive the password.  All the attributes (wpky, salt, iter etc) are pretty easy to parse.  There is the header, followed by 00 00 00.  The next offset is the length of the attribute which always seems to run neatly up to the next attribute.

My iTunes pw is 4589.
The iterations are 10000
The wkey (the last wkey in the keybag) is: 1D C1 F4 BA 48 44 D6 79 00 01 F1 45 05 91 32 18 73 C6 1D F3 66 61 12 CE 59 48 BF 93 BB C5 1E C9 00 9B ED 68 1D 0F 67 92
The salt is: 1F 90 BE 09 15 9A 77 21 54 D9 95 F3 93 14 41 83 67 C3 E3 3F

I know that each of those hex bites are required and if any are compromised Elcomsoft can't get the password.  I believe this pw to be PBKDF2-HMAC-SHA1.

This should be all the data required to get the pw, if anyone can figure out how to input this to hashcat we may be done here.  I tried a few variations like converting it to base64 but no luck.  It looks too long.

H5C+CRWadyFU2ZXzkxRBg2fD4z8=:HcH0ukhE1nkAAfFFBZEyGHPGHfNmYRLOWUi/k7vFHskAm+1oHQ9nkg==


Attached Files
.png   Capture.PNG (Size: 10.82 KB / Downloads: 65)
.png   Capture2.PNG (Size: 6.84 KB / Downloads: 50)
#15
My File looks like this


Attached Files
.png   Screenshot at 23-12-32.png (Size: 43.02 KB / Downloads: 55)
#16
Well, it is pretty easy to see from the link posted by keen (http://stackoverflow.com/questions/14983...one-backup) that after the $key = pbkdf2_hmac_sha1 ($pass, $salt, $iter) call the WPKY key needs to be "unwrapped" (see AESUnwrap ($key, $wpky) in the code snippet from the stackoverflow post) to verify if the first 8 bytes are 0xa6a6a6a6a6a6a6a6.
If this is successfull the $pass (and therefore the $key + $wpky combination) are correct.

Therefore this algorithm is not just -m 12000 = PBKDF2-HMAC-SHA1 and is also not yet supported by hashcat.



Update:

Here you have a POC (proof of concept) to show that this is exactly how you possibly can attack this:

Code:
#!/usr/bin/env perl

# Author: philsmd
# License: public domain
# Date: January 2017

use strict;
use warnings;

use Crypt::PBKDF2;
use Crypt::Mode::ECB;

#
# Constants
#

my $CHECK_SIG = 12008468691120727718; # 0xa6a6a6a6a6a6a6a6
my $MAX_PLIST_SEARCH_DISTANCE = 256;

#
# Helper functions
#

sub to_64bit_num
{
  my $str = shift;

  my $res = 0;

  for (my $i = 0; $i < 8; $i++)
  {
    $res += ord (substr ($str, $i, 1)) << (8 * (7 - $i));
  }

  return $res ;
}

sub from_64bit_num
{
  my $num = shift;

  my $res = "";

  for (my $i = 0; $i < 8; $i++)
  {
    $res = chr ($num & 0xff) . $res;
    $num >>= 8;
  }

  return $res ;
}

sub aes_unwrap
{
  my $key  = shift;
  my $WPKY = shift;

  # init

  my @C;

  for (my $i = 0; $i < length ($WPKY) / 8; $i++)
  {
    $C[$i] = unpack ("Q>", substr ($WPKY, $i * 8, 8)); # $C[$i] = to_64bit_num (substr ($WPKY, $i * 8, 8));
  }

  my $n = scalar (@C) - 1;
  my @R = (0) x ($n + 1);
  my $A = $C[0];

  for (my $i = 1; $i < $n + 1; $i++)
  {
    $R[$i] = $C[$i];
  }

  # AES mode ECB

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

  # main unwrap loop

  for (my $j = 5; $j >= 0; $j--)
  {
    for (my $i = $n; $i > 0; $i--)
    {
      my $todec;

      $todec  = pack ("Q>", $A ^ ($n * $j + $i)); # $todec = from_64bit_num ($A ^ ($n * $j + $i));
      $todec .= pack ("Q>", $R[$i]);

      my $B = $m->decrypt ($todec, $key);

      $A     = unpack ("Q>", substr ($B, 0, 8));
      $R[$i] = unpack ("Q>", substr ($B, 8, 8));
    }
  }

  return $A;
}

sub parse_manifest_file
{
  my $fp = shift;

  my $wpky = undef;
  my $salt = undef;
  my $iter = undef;

  my $manifest_buffer = do
  {
    local $/ = undef;
    <$fp>;
  };

  my $manifest_buffer_len = length ($manifest_buffer);

  return (undef, undef, undef) if (length ($manifest_buffer) < 4 + 4 + 4 + 4 + 4 + 4);

  my @salt_matches = ($manifest_buffer =~ /SALT..../g);

  # okay, I admit this is some strange parsing, but it seems to work all the times (for me)
  # for instance, it assumes that the order is always like this: 1. salt, 2. iter, 3. wpky

  my $idx_glob = 0;

  for (my $i = 0; $i < scalar (@salt_matches); $i++)
  {
    my $idx_salt = index ($manifest_buffer, "SALT", $idx_glob + 0);

    last if ($idx_salt == -1);

    my $idx_iter = index ($manifest_buffer, "ITER", $idx_salt + 1);

    last if ($idx_iter == -1);

    my $idx_wpky = index ($manifest_buffer, "WPKY", $idx_iter + 1);

    last if ($idx_wpky == -1);

    # special case:

    last if ($manifest_buffer_len - $idx_wpky < 8); # too close to the EOF

    if ($idx_wpky - $idx_salt < $MAX_PLIST_SEARCH_DISTANCE) # some sane distance between the items
    {
      my $salt_len = substr ($manifest_buffer, $idx_salt + 4, 4);
      my $iter_len = substr ($manifest_buffer, $idx_iter + 4, 4);
      my $wpky_len = substr ($manifest_buffer, $idx_wpky + 4, 4);

      $idx_salt += 8;
      $idx_iter += 8;
      $idx_wpky += 8;

      $salt = substr ($manifest_buffer, $idx_salt, unpack ("L>", $salt_len));
      $iter = substr ($manifest_buffer, $idx_iter, unpack ("L>", $iter_len));
      $wpky = substr ($manifest_buffer, $idx_wpky, unpack ("L>", $wpky_len));

      # iter is a special case, needs to be converted to a number
      $iter = unpack ("L>", $iter);

      last;
    }

    $idx_glob = $idx_wpky + 1;
  }

  return ($wpky, $salt, $iter);
}

#
# MAIN
#

# init:

if (scalar (@ARGV) != 1)
{
  print "Usage: $0 <Manifest.plist file>\n";

  exit (1);
}

my $manifest_file = $ARGV[0];

my $FH_MANIFEST;

if (! open ($FH_MANIFEST, "<$manifest_file"))
{
  print "ERROR: Could not open '$manifest_file'\n";

  exit (1);
}

binmode ($FH_MANIFEST);

my ($WPKY, $SALT, $ITER) = parse_manifest_file ($FH_MANIFEST);

close ($FH_MANIFEST);

if (! defined ($WPKY))
{
  print "ERROR: WPKY could not be found in '$manifest_file'\n";

  exit (1);
}

if (! defined ($SALT))
{
  print "ERROR: SALT could not be found in '$manifest_file'\n";

  exit (1);
}

if (! defined ($ITER))
{
  print "ERROR: ITER could not be found in '$manifest_file'\n";

  exit (1);
}

# crypto init

my $pbkdf2 = Crypt::PBKDF2->new
(
  hasher     => Crypt::PBKDF2->hasher_from_algorithm ('HMACSHA1'),
  iterations => $ITER,
  output_len => 32
);

#
# Actual START
#

while (my $pass = <STDIN>)
{
  chomp ($pass);

  my $key = $pbkdf2->PBKDF2 ($SALT, $pass);

  if (aes_unwrap ($key, $WPKY) == $CHECK_SIG)
  {
    print "Password found: $pass\n";

    exit (0);
  }
}

exit (1);

Note: I put this code together pretty quickly so please don't blame me for it. Feel free to use it (pubic domain license).

This is an example on how you use it (dictionary/password candidates come from stdin, Manifest file as first command line argument):


Code:
./hashcat --stdout -a 3 ?d?d?d?d?d?d | ./crack_plist_file.pl Manifest.plist

Password found: 123456
#17
Nice work and thanks for straightening this out.
#18
It works. Thank you . I still have something from the password for 3 characters he already calculates 4 hours. Does my command work?


Code:
./hashcat --stdout -a 3 48df8dx4?a?a?a | ./plisttohash.pl Manifest.plist
#19
Yeah, looks good Tuxel (if you are sure about the hard-coded "48df8dx4" beginning).

In theory you should be able to speed it up significantly e.g. with the "parallels" tool:

Code:
./hashcat --stdout -a 3 48df8dx4?a?a?a | parallel --pipe ./plisttohash.pl Manifest.plist

Well, and if you want that devs implement this into hashcat (with GPU support), then you shouldn't hesitate to open a github feature request. But there is still some information missing to be double-checked (see https://hashcat.net/faq#i_want_to_reques...plish_this). For instance, we should know exactly the max/min salt, wpky lengths, min/max iterations etc.
#20
I would be very glad if there would be a GPU Hashcat integration. It's a great project.
Thank you all
Uwe