#!/usr/bin/env python """ EFIPW (C) 2010 by Paul Makowski (my.hndl@gmail.com) http://code.google.com/p/efipw/ http://paulmakowski.wordpress.com/ License: GPLv3 Warranty: Unless otherwise stated, this software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THERE IS NO WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. About: EFIPW is a tool to modify and/or decode firmware passwords stored on EFI-based Apple computers in nvram. It may be useful for both lab administrators and pen testers. It was inspired by the OPFW tool. Requires root permissions. If you find this software useful, I would appreciate it if you let me know, but you're certainly not required to. Usage: ./efipy.py -h Modes: none: Firmware password is ignored, all boot actions allowed (single user, boot off external, etc). This is the default. command: Firmware password enforced if user requests to boot off another device by holding down 'alt' during boot. Single user, target disk mode, etc disabled. This is the default when passwords are set. full: All actions are disallowed, unless correct password is entered (including normal boot to blessed drive). Changelog: 0.1: initial release 0.1a: re-release (i put the wrong binary in the .zip file) 0.2: complete rewrite in Python (for simplicity, maintainability & 10.6 support) 0.2a: if new password is set and mode is not, default mode to "command" """ from optparse import OptionParser import os import binascii parser = OptionParser(version="%prog 0.2a") if os.geteuid(): parser.error("Must be run as root. (e.g. sudo ./efipw.py [options])") parser.add_option("-q", "--quiet", action="store_true", dest="quiet", default=False, help="suppress confirmation messages") parser.add_option("-d", "--decode", action="store_true", dest="decode", default=False, help="decode current EFI password") parser.add_option("-p", "--password", dest="newPassword", metavar="PASSWORD", type="string", help="set new EFI password") parser.add_option("-m", "--mode", dest="newMode", metavar="MODE", type="string", help="set new EFI mode [none, command, full]") (options, args) = parser.parse_args() # lolCrypt: Apple's lolzy encryption function def lolCrypt(input): output = "" for i in range(0, len(input)): output += (chr(ord(input[i]) ^ 170)) # 170 in decimal is 10101010 in binary; this is the key...don't tell anyone ;) return output def splitLen(seq, length): return [seq[i:i+length] for i in range(0, len(seq), length)] # REVEAL CURRENT PASSWORD if options.decode: # get the current (encoded) password p = os.popen('nvram -p | grep security-password',"r") curPassword = p.readline().strip() print lolCrypt(binascii.unhexlify(curPassword[curPassword.find('%'):].replace('%', ''))) # SET NEW PASSWORD if options.newPassword: # set mode to command if not specified if not options.newMode: options.newMode = "command" if len(options.newPassword) > 48: print "Password cannot be longer than 48 characters; new password not set." # set new password else: # prep the password newPassword = splitLen(binascii.hexlify(lolCrypt(options.newPassword)), 2) for i in range(len(newPassword)): newPassword[i] = '%' + newPassword[i] newPassword = ''.join(newPassword) # set the password p = os.popen('nvram security-password=' + newPassword,"r") if not options.quiet: print 'EFI password set.' # SET NEW MODE if options.newMode: # validate mode if options.newMode not in ["none", "command", "full"]: print "Invalid mode '" + options.newMode + "' specified; mode not set." else: p = os.popen('nvram security-mode=' + options.newMode,"r") if not options.quiet: print 'EFI mode set.'