Get administrative privileges with a fast Mac app

I am writing pice software that should often run a command with root privileges.

I am currently doing this by asking for the user password once, saving it, and then providing that NSAppleScript password as an argument along with with administrator privileges .

This is clearly unsafe for the user, as someone can access their password.

I searched for the best part of the week and cannot find a solution.

SMJobBless seems to allow you to install the application with a higher privilege.

I followed the sample application and I get an error message from their SMJobBlessUtil script.

Here is the error:

 SMJobBlessUtil.py: tool designated requirement (identifier "com.domain.AppName.SampleService" and anchor apple generic and certificate leaf[subject.CN] = "Mac Developer: firstName lastName (XXXXXXXXXX)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */) doesn't match entry in 'SMPrivilegedExecutables' (anchor apple generic and identifier "com.domain.AppName.SampleService" and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.CN] = "Mac Developer: firstName lastName (XXXXXXXXXX)") 

Obviously, something is wrong. Here are the corresponding plates

Service Info plist

 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleIdentifier</key> <string>com.domain.AppName.SampleService</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundleName</key> <string>SampleService</string> <key>CFBundleVersion</key> <string>6</string> <key>SMAuthorizedClients</key> <array> <string>anchor apple generic and identifier "com.domain.AppName" and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = xxxxxxxxxx)</string> </array> </dict> </plist> 

Application Details Table

 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> <string>en</string> <key>CFBundleDisplayName</key> <dict/> <key>CFBundleExecutable</key> <string>$(EXECUTABLE_NAME)</string> <key>CFBundleGetInfoString</key> <dict/> <key>CFBundleIdentifier</key> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundleName</key> <string>Away</string> <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleShortVersionString</key> <string>1.0.99</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleVersion</key> <string>9</string> <key>LSApplicationCategoryType</key> <string>public.app-category.utilities</string> <key>LSMinimumSystemVersion</key> <string>$(MACOSX_DEPLOYMENT_TARGET)</string> <key>LSUIElement</key> <true/> <key>NSHumanReadableCopyright</key> <string>Copyright © 2016 firstName lastName. All rights reserved.</string> <key>NSMainStoryboardFile</key> <string>Main</string> <key>NSPrincipalClass</key> <string>NSApplication</string> <key>SMPrivilegedExecutables</key> <dict> <key>com.domain.AppName.SampleService</key> <string>anchor apple generic and identifier "com.domain.AppName.SampleService" and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.CN] = "Mac Developer: firstName lastName (XXXXXXXXXX)"</string> </dict> </dict> </plist> 

I was looking at https://stackoverflow.com/a/4129169/ and many others liked it. As far as I understand, I have the correct settings. What am I doing wrong?

+5
source share
2 answers

A key part of this approach is described in the REAL ESTATE SERVICES section of the How It Works section of ReadMe.txt:

[...] when you sign up a helper tool with a developer identifier, Xcode automatically sets the required helper like this and what you should use for SMPrivilegedExecutables. Moreover, this is what the setreq command shown above does: it extracts the specified requirement from the built-in tool and places it in the source code of the Info.plist application.

Since you do not sign products (at least not with the certificate described in your examples), this process always fails.

If you are not in the Developer Program, you can create a self-signed certificate for signing. However, this more or less strikes the purpose of the signature requirement. If you do not plan to participate in the Developer Program, you can shorten the process as follows:

  • In your Info.plist application, reduce the requirement in SMPrivilegedExecutables to match the helper ID:

    <string>identifier "com.domain.AppName.SampleService"</string>

    • In your Info.plist helper, reduce the requirement in SMAuthorizedClients to just match the application id:

    <string>identifier "com.domain.AppName"</string>

    • Ignore the instructions for "Creating and Running a Sample" in the ReadMe.txt file and just simply create and run the project as usual.

I cannot say that I recommend this, of course; these signing requirements exist for a good reason. This is at least better than the final alternative, however, which this NSAppleScript will use to give the helper the executable root setuid bit via chmod and chown .


Adding to the development of some of the concepts presented here:

Running privileged code with many potential security holes; Secure user authentication is only the first step. Delegating all privileged operations to a separate process is another serious step, but the main problem is how to ensure that your application - the one that the user actually granted privileges to - is the only entity that can use privileged access.

Example Apple demonstrates the use of code signing to solve this problem. Just in case, if you are not familiar: signing a code involves cryptographically marking your end products in such a way that OS X can verify that your programs have not been replaced by vulnerable versions. These additional "certificate sheet" links are provided in the original example SMAuthorizedClients and SMPrivilegedExecutables specifically for this; they describe the certificate to which your application and helper must be signed in order to interact with each other.

To color the picture a bit, here is a rough summary of how this happens:

  • Your user grants permission to run to install the daemon helper with the label com.domain.AppName.SampleService .
  • launchd posts the com.domain.AppName.SampleService entry in SMPrivilegedExecutables in your Info.plist application; this describes the certificate with which the auxiliary binary must be signed. (If they do not match, then in theory the attacker replaced your assistant with his version to run it as root.)
  • If there is a working assistant, the application makes a launch request to call the assistant under your control. At this point, launchd will hide the SMAuthorizedClients section of your Info.plist helper tool to make sure that the application really has the right to run the tool. And, of course, it checks your application signature to make sure it is not tampered with.

Returning to your scenario, the way your products currently work is the elimination of the signing steps. The only thing you have specified startd for verification is whether your Info.plist application indicates its identifier as "com.domain.AppName". Since there is nothing to prevent an attacker from modifying their Info.plist to say so, you assume that they will not be able to use your auxiliary tool to do any harm once they control it.

Additional Supplement Describing Alternatives:

+6
source

You are moving in the right direction. Currently, a privileged helper tool is the best practice for completing a task in privileged mode. You can also use Swift for this, but just replace the version of the C functions with Swift. (Apple introduced alternatives in SDK 10.11) For example, instead of

 Boolean SMJobBless( CFStringRef domain, CFStringRef executableLabel, AuthorizationRef auth, CFErrorRef *outError); 

you can use:

 SMJobBless(_: CFString!, _: CFString, _: AuthorizationRef, _: UnsafeMutablePointer<Unmanaged<CFError>?>) -> UInt8 

But I have never seen examples of a privileged helper tool on the Internet ... Therefore, you need to see the Objective-C code. Fortunately, there is not much Obj C code.

0
source

Source: https://habr.com/ru/post/1241189/