2016-01-22 17 views
5

Piszę oprogramowanie, które często musi uruchamiać polecenie z uprawnieniami roota.Zyskaj uprawnienia administracyjne dzięki aplikacji Swift dla komputerów Mac

W tej chwili robię to, prosząc użytkownika o jego hasło raz, zapisując je, a następnie przekazując to hasło do NSAppleScript jako argument wraz z with administrator privileges.

To oczywiście jest bardzo niebezpieczne dla użytkownika, ponieważ ktoś może uzyskać dostęp do jego hasła.

Szukałem lepszej części tygodnia i nie mogę znaleźć rozwiązania.

SMJobBless wydaje się pozwalać na zainstalowanie aplikacji z wyższymi uprawnieniami.

Podążyłem za przykładem aplikacji i otrzymuję błąd z ich skryptu SMJobBlessUtil.

Tutaj jest błąd:

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)") 

Oczywiście, coś jest nie tak. Oto poszczególne listy właściwości

Usługi 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> 

Aplikacje Informacje 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>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> 

szukałem at this stackoverflow post i wiele innych lubią to. Jak je rozumiem, mam poprawnie ustawione pliki. Co ja robię źle?

Odpowiedz

6

Kluczowym elementem tego podejścia jest opisany na podstawie „Listy Property” pod sekcją „Jak to działa” w ReadMe.txt:

[…] when you sign the helper tool with a Developer ID, Xcode automatically sets the helper tool's designated requirement like this, and that's what you should use for SMPrivilegedExecutables. Moreover, this is what the "setreq" command shown above does: extracts the designated requirement from the built tool and put it into the app's Info.plist source code.

Ponieważ nie podpisujemy produkty (przynajmniej nie z certyfikatem opisanym w przykładach), proces ten zawsze kończy się niepowodzeniem.

Jeśli nie uczestniczysz w Programie dla programistów, możesz podpisać się pod numerem create a self-signed certificate. Jednak w mniejszym lub większym stopniu ogranicza to cel wymagania podpisania. Jeśli nie planujesz rejestrując się w programie Developer, powinieneś być w stanie skrócić ten proces następująco:

  1. w twojej aplikacji Info.plist, skracać wymogu określonego SMPrivilegedExecutables po prostu dopasować identyfikator Pomocników:

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

    • w waszych Pomocników Info.plist, skracać wymogu określonego SMAuthorizedClients po prostu dopasować zakres aplikacji Identyfikator:

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

    • Zignoruj ​​ins "Building and Running the Sample" truights of ReadMe.txt i intead po prostu buduj i uruchamiaj projekt jak zwykle.

Nie mogę powiedzieć, że polecam to oczywiście; te wymagania dotyczące podpisywania istnieją z dobrego powodu. Jest jednak co najmniej lepsza niż ostatnia alternatywa, która używałaby tego NSAppleScript, aby dać programowi wykonawczemu bit root setuid za pośrednictwem chmod i chown.


Uzupełnienie do opracowania na niektórych pojęć grają:

Running uprzywilejowany kod pochodzi z dużą ilością potencjalnych luk bezpieczeństwa; bezpieczne uwierzytelnianie użytkownika to tylko pierwszy krok. Delegowanie wszystkich uprzywilejowanych operacji do osobnego procesu jest kolejnym mocnym krokiem, ale najważniejszym problemem, jaki pozostaje, jest zapewnienie, że aplikacja, do której użytkownik faktycznie przyznał przywileje, jest jedyną jednostką zdolną do korzystania z uprzywilejowanego dostępu.

Przykład Apple demonstruje użycie podpisywania kodu w celu rozwiązania tego problemu. Na wszelki wypadek: podpisywanie kodu polega na kryptograficznym oznaczaniu produktów końcowych w taki sposób, aby system OS X mógł zweryfikować, czy twoje programy nie zostały zastąpione przez skompromitowane wersje. Te dodatkowe odniesienia do "liści certyfikatu" są w tym przykładzie z oryginalnego przykładu: SMAuthorizedClients i SMPrivilegedExecutables; opisują certyfikat, z którym twoja aplikacja i pomocnik musiały zostać podpisane, aby móc ze sobą współdziałać.

Aby pomóc malować obraz trochę, tu jest szorstki wybiegiem, jak ta gra się:

  1. Upoważnienie dotacje użytkowników do launchd zainstalować demona pomocnika oznaczony com.domain.AppName.SampleService.
  2. launchd znajduje wpis com.domain.AppName.SampleService pod numerem SMPrivilegedExecutables w pliku Info.plist aplikacji; opisuje to certyfikat, z którym powinien być podpisany plik binarny pomocnika. (Jeśli nie pasują, teoretycznie atakujący zastąpił narzędzie pomocnicze własną wersją, aby uruchomić go jako root).
  3. Po zainstalowaniu ważnego narzędzia pomocniczego Twoja aplikacja wysyła żądanie uruchomienia, aby odrodzić pomocnika pod twoją kontrolą. W tym momencie launchd konsultuje się z sekcją SMAuthorizedClients w pliku Info.plist narzędzia pomocniczego, aby upewnić się, że aplikacja rzeczywiście ma prawo do uruchomienia narzędzia. I, oczywiście, weryfikuje podpis Twojej aplikacji, aby upewnić się, że nie została naruszona.

Powrót do swojego scenariusza, sposób, w jaki obecnie działają produkty, polega na wyeliminowaniu kroków związanych z podpisywaniem. Jedyne, co poleciłeś uruchomieniu, aby sprawdzić, to czy plik Info.plist Twojej aplikacji zawiera jego identyfikator "com.domain.AppName".Ponieważ nic nie stoi na przeszkodzie, aby osoba atakująca zmieniła swoją stronę Info.plist, aby to powiedzieć, masz nadzieję, że nie będą mogli użyć narzędzia pomocniczego, by wyrządzić jakąkolwiek krzywdę, gdy tylko będą mieć nad nim kontrolę.

dodatkowe uzupełnienie przedstawiając alternatywy:

+0

Nie miałem zamiaru utrzymywać nagrody. Problem z twoim wpisem na Reddicie polega na tym, że mówi ciąg. Naprawdę przypadkowo natknąłem się na permutację. Ale odpowiedź jest wystarczająco dobra. Zalecam, aby edytować swoje pytanie, aby uwzględnić krok po kroku niezbędne zmiany w stosunku do pierwotnego pytania. Utknąłem na tym przez kilka dni i nadal nie rozumiem, jak niezupełna linia tożsamości jest wystarczająca, podczas gdy jabłko ma znacznie dłuższy ciąg – Cripto

+0

Cóż, teraz nie czuję się głupcem. Ponownie, nagroda nie była konieczna, ale jest bardzo doceniana ... Zaktualizowałem swoją odpowiedź, aby spróbować wyjaśnić ogólne uzasadnienie, jak również szczegóły, o które prosiłeś; nie wahaj się, jeśli to nie obejmuje. –

0

Poruszasz się we właściwym kierunku. Obecnie uprzywilejowane narzędzie pomocnicze jest najlepszą praktyką do wykonywania zadań w trybie uprzywilejowanym. W tym celu możesz użyć Swift, ale po prostu zamień wywołanie funkcji C na wersję Swift. (Apple wprowadziła alternatyw w 10.11 SDK), na przykład zamiast

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

można użyć:

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

Ale nigdy nie widziałem przykłady uprzywilejowanym narzędziem pomocniczym w Internecie ... Więc trzeba zobaczyć w kod celu C. Na szczęście kod Obj C niewiele.

Powiązane problemy