Bruteforce Apr1 hashes. posted May 2014
One of my professor organized a Hacking Week this semester but I didn't have time to do it. Since I'm in holidays I thought I would take a look at it and write a bit about how I solved them.
Here's the Crypto Challenge number 2 (out of 5) from this CTF (Capture The Flag):
user0:$apr1$oTsx8NNn$bAjDZHpM7tCvHermlXKfZ0 user1:$apr1$UxOdpNtW$funTxZxL/8y3m8STvonWj0
user2:$apr1$w7YNTrjQ$0/71H7ze5o9/jCnKLt0mj0 user3:$apr1$AIw2h09/$Ti0TRlU9mDpCGm5zg.ZDP. user4:$apr1$048HynE6$io7TkN7FwrBk6PmMzMuyC. user5:$apr1$T2QG6cUw$eIPlGIXG6KZsn4ht/Kpff0 user6:$apr1$2aLkQ0oD$YRb6aFYMkzPoUCj70lsdX0
You have 7 different users with their respective password hashed and you have to find them. It's just the 2nd out of 5 crypto problems, it's pretty basic, but I never brute forced passwords for real before (I remember using John The Ripper when I was in middle school but that's for script kiddies).
What's Apr1 ? It's a hash function that uses md5. And md5 is pretty weak, lots of rainbow tables on google.
This is how Apr1 looks in PHP according to Wikipedia, also the passwords are supposed to be alpha (a to z) in lowercase.
function apr1($mdp, $salt) {
$max = strlen($mdp);
$context = $mdp.'$apr1$'.$salt;
$binary = pack('H32', md5($mdp.$salt.$mdp));
for($i=$max; $i>0; $i-=16)
$context .= substr($binary, 0, min(16, $i));
for($i=$max; $i>0; $i>>=1)
$context .= ($i & 1) ? chr(0) : $mdp{0};
$binary = pack('H32', md5($context));
for($i=0; $i<1000; $i++) {
$new = ($i & 1) ? $mdp : $binary;
if($i % 3) $new .= $salt;
if($i % 7) $new .= $mdp;
$new .= ($i & 1) ? $binary : $mdp;
$binary = pack('H32', md5($new));
}
$hash = '';
for ($i = 0; $i < 5; $i++) {
$k = $i+6;
$j = $i+12;
if($j == 16) $j = 5;
$hash = $binary{$i}.$binary{$k}.$binary{$j}.$hash;
}
$hash = chr(0).chr(0).$binary{11}.$hash;
$hash = strtr(
strrev(substr(base64_encode($hash), 2)),
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
'./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
);
return '$apr1$'.$salt.'$'.$hash;
}
It seems pretty difficult to reverse. Let's not forget that hashes are one-way functions and that they also lose information. I don't know if they do lose information on a 7-letters-password though, but it seemed quite stupid to go down this road when I could just brute force it.
What language offers a good library to hash with Apr1? Well I didn't know, and I felt like maybe Unix could do it well for me.
Turns out that OpenSSL has a command line for it:
openssl passwd -apr1 -salt SALT PASSWD
A quick bash script later:
#!/bin/bash
test[1]='$apr1$oTsx8NNn$bAjDZHpM7tCvHermlXKfZ0'
salt[1]='oTsx8NNn'
test[2]='$apr1$UxOdpNtW$funTxZxL/8y3m8STvonWj0'
salt[2]='UxOdpNtW'
test[3]='$apr1$w7YNTrjQ$0/71H7ze5o9/jCnKLt0mj0'
salt[3]='w7YNTrjQ'
test[4]='$apr1$AIw2h09/$Ti0TRlU9mDpCGm5zg.ZDP.'
salt[4]='AIw2h09/'
test[5]='$apr1$048HynE6$io7TkN7FwrBk6PmMzMuyC.'
salt[5]='048HynE6'
test[6]='$apr1$T2QG6cUw$eIPlGIXG6KZsn4ht/Kpff0'
salt[6]='T2QG6cUw'
test[7]='$apr1$2aLkQ0oD$YRb6aFYMkzPoUCj70lsdX0'
salt[7]='2aLkQ0oD'
while read line
do
if [ "${#line}" == 7 ]
then
for num in {1..7}
do
noob=$(openssl passwd -apr1 -salt $salt[$num] $line)
if [ "$noob" == "$test[$num]" ];
then
echo $line;
fi
done
fi
done < /usr/share/dict/words
I read the /user/share/dict/words
that contains a simple dictionary of words on Unix, I try only the 7-letters-words.
The test ran in a few minutes and gave me nothing.
Well, I guess with a 7 letters password they must have used gibberish words. Let's try a real bruteforce:
for a in {a..z}
do
for b in {a..z}
do
for c in {a..z}
do
for d in {a..z}
do
for e in {a..z}
do
for f in {a..z}
do
for g in {a..z}
do
truc=$a$b$c$d$e$f$g;
for num in {1..7}
do
noob=$(openssl passwd -apr1 -salt $salt[$num] $truc)
if [ "$noob" == "$test[$num]" ];
then
echo $truc;
fi
done
done
done
done
done
done
done
done
It ran and ran and... nothing.
Well. Let's not spend too much on this. There is John The Ripper that does this well and even oclHashcat that does this with the GPU.
Let's create a john.conf
with the following to limit the password to 7 letters:
[Incremental:Alpha7]
File = $JOHN/alpha.chr
MinLen = 7
MaxLen = 7
CharCount = 26
Let's launch John:
john -i=Alpha7 hackingweek.txt
(don't forget to put the hashed password in hackingweek.txt).
Wait and wait and wait.. and get the passwords =)
Comments
leave a comment...