Dynamische Bibliothek vor Benutzer verstecken

ikkebins

Stammuser
Hallo Leute,

ich suche schon seit geraumer Zeit eine Möglichkeit, die dynamische Bibliothek eines Programmes zu versteken.

Derzeit starte ich die Anwendung so:

PHP:
LD_PRELOAD=meineLib.so ./dasProgramm
Mein jetziger "Schutz" ist, das meineLib.so wiederrum eine andere dynamische Bibliothek öffnet. Aber das bringt ja nichts, wenn alle Pfade direkt in /proc/self/maps stehen.

Die Benutzer haben alle SSH-Zugang, weswegen sie volle Einsicht in ihr Start-Script haben (um die LD_PRELOAD-Bibliothek zu finden).

Wüsste irgendwer eine Möglichkeit, wie man den .so-Diebstahl verhindern könnte? Da steckt monatelange Kleinarbeit drin, die ich ungern "verlieren" möchte.

Ich hoffe, man kann verstehen, was ich suche. Wenn nicht, einfach nachfragen. :)

Viele Grüße,
gruena
 

bitmuncher

Senior-Nerd
Mit einem Kernel-Modul oder einer modifizierten File-Access-Liste im Kernel liesse sich das sicherlich verstecken. Sollte man aber bleiben lassen, wenn man die Software verkaufen will, da so ein Murks niemand kauft. Abgesehen davon würde ich recht misstrauisch werden, wenn ich auf einem System arbeiten müsste, das Trojaner-Methoden nutzt um irgendeine Arbeit zu schützen. Im Kernel steckt sogar jahrelange Kleinarbeit und man kann ihn trotzdem in den Sources einsehen und modifizieren.

Davon abgesehen... was geklaut werden kann, wird auch geklaut werden. Du solltest also nicht versuchen zu verhindern, dass jemand die Datei findet (Security by Obscurity hat noch nie funktioniert), sondern versuchen dass niemand die Funktionalitäten auseinandernehmen oder sonstwie nutzen kann. Und da hast du dich mit Linux für das falsche System entschieden.
 

CDW

Moderator
Mitarbeiter
Auf welcher Ebene schützen?

Bestimmte Algorithmen/Problemlösungen:
1. den Compiler anweisen, stark zu optimieren
2. jegliche Debuginfos strippen
3. notfalls den schützenswerten Code noch obfuskieren.
Da wird dem "Dieb" nur die Möglichkeit bleiben, die Bibliothek komplett oder zumindest den großen teil der Binary als "BLOB" zu kopieren (was dann auch keinen großen Spass beim Deployment machen dürfte ;) )

Ansonsten würde mir noch einfallen:
Den eigentlichen Kern in einen Dämon/Dienst stecken und die Nutzerrechte so setzen, dass diese darauf keine Zugriff haben.
Die Kommunikation läuft dann z.B über "meineLin.so", die aber "nix kann" und nur einen Wrapper darstellt/die Anfragen an den Dämon weiterleitet.
 

ikkebins

Stammuser
Danke für eure Antworten! Leider konnte ich noch keine Lösung erkennen.

Die Probleme sind:
- man kann bei einem OpenVZ-Linux keine Kernel-Module laden
- ein Dämon ist nicht machtbar, da versteckteLib.so direkten Zugriff auf den Speicher der Anwendung braucht (zum Callbacks setzen, die dann wieder zurück in die versteckteLib.so gehen)

Ich möchte die Software nicht verkaufen, sondern nur vermieten. Das heißt, dass ich etwas mehr Kontrolle über den Zugriff habe.

Bis jetzt läuft es wohl auf die Obfuscation hinaus, wobei ich das nicht so gerne will (Zeichenketten würden eh die Funktionen verraten und ohne Zeichenketten kann man schlecht Meldungen ausgeben).

Kann man vielleicht die /proc/self/maps-Datei ausschalten? Die Datei verrät ja die versteckteLib.so am schnellsten.
 

ikkebins

Stammuser
Könnte man nicht eine ACL-Regel setzen, die besagt, dass nur ./dasProgramm Lese-Zugriff auf die meineLib.so hat?

Ein einfaches "Nein" besagt, dass GNU/Linux nicht dynamisch genug ist.
 

GrafZahl

Member of Honour
was wäre mit einem konstrukt álá

user ruft mit account u1 client_wrapper auf
client_wrapper meldet an daemon (account d) dass ein programmstart gewünscht ist
daemon startet mittels sudo das eigentliche client programm als account u1a und gibt ggf pipes an den client wrapper zurück, der darüber mit dem client prog reden kann

account u1 hat keinen zugriff auf die .so ... u1a hat ... u1a darf sich aber nicht anmelden, sondern nur von d via sudo genutzt werden ...
 

ikkebins

Stammuser
Danke für das Querdenken, das hat mich jetzt schon weiter gebracht. :)

Als ich darüber nachgedachte habe, wie ich das umsetzten könnte, viel mir nämlich noch ein einfacherer Weg ein:

- ./dasProgramm bekommt SUID
- es kann jetzt die meineLib.so laden
- die meineLib.so setzt in ihrem Konstruktor lib_load() die originale User-ID
- die meineLib.so ist also geladen und läuft nicht mehr als root

Das einzige Problem ist jetzt, dass ./dasProgramm closed-source ist. Ich muss also ./dasProgramm erweitern mit meiner main-Funktion, die dann auch die Arbeit von LD_PRELOAD übernimmt. LD_PRELOAD funktioniert ja nicht mit SUID.

Zum Ändern habe ich schon elfsh gefunden, womit man kompilierte Programme erweitern können soll. Das hatte ich dann gleich probiert:
Code:
elfsh32
load dasProgramm
load meineLib.o
redir main fake_main
Das Ergebnis: Segmentation Fault


Kennt vielleicht jemand ein anderes Programm, mit dem man Code an einem Programm anfügen kann (also ein .text-Segment hinzufügen)?

Vielleicht hat ja auch noch jemand eine andere Idee. Das hatte ich z.B. davor noch probiert:

PHP:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

// gcc wrapper.c -o wrapper.elf -m32
// chown root:root wrapper.elf; chmod +s wrapper.elf

int main()
{
    printf("START SECRET WRAPPER %d\n", geteuid());
    getchar();
    
    char * const envs[] = {"LD_PRELOAD=/home/ikkebins/meineLib.so", NULL};
    execve("/home/ikkebins/dasProgramm", NULL, envs);
    return 0;
}
Der lädt einfach nicht die .so, wenn SUID gesetzt ist. Ohne SUID wird sie geladen, aber dann braucht der normale User ja wieder Leserechte.

Ich hoffe noch auf eine recht einfache Lösung, ohne irgendwelche Dämone ins Spiel zu bringen. :D
 
Zuletzt bearbeitet:

ikkebins

Stammuser
Ich habe jetzt eine Möglichkeit gefunden, wie man eine Bibliothek bei einem SUID-Programm vorladen kann. Dazu schreibt man einfach den kompletten Pfad der Bibliothek in /etc/ld.so.preload (standardmäßig muss die Datei erst angelegt werden bei Debian).

Das Problem ist nur, dass die Bibliothek zu JEDEM Prozess geladen wird. Mir macht das allerdings nicht viel aus, da ich ein Multiarch-Setup führe. Die 64bit-Programme bekommen also eine "leere" Bibliothek untergeschoben (gegen Fehlermeldungen) und die 32bit-Programme die "echte" Bibliothek.

/etc/ld.so.preload
Code:
/$LIB/libwrapper.so
$LIB evaluiert nach lib32 (bei 32bit) oder lib (bei 64bit).
 
Oben