GNU/Linux >> Tutoriels Linux >  >> Linux

Masquer les arguments pour programmer sans code source

Comme expliqué ici, Linux place les arguments d'un programme dans l'espace de données du programme et conserve un pointeur vers le début de cette zone. C'est ce qui est utilisé par ps et ainsi de suite pour trouver et afficher les arguments du programme.

Puisque les données sont dans l'espace du programme, il peut les manipuler. Faire cela sans changer le programme lui-même implique de charger un shim avec un main() fonction qui sera appelée avant le vrai main du programme. Ce shim peut copier les arguments réels dans un nouvel espace, puis écraser les arguments d'origine afin que ps ne verra que des valeurs nulles.

Le code C suivant le fait.

/* https://unix.stackexchange.com/a/403918/119298
 * capture calls to a routine and replace with your code
 * gcc -Wall -O2 -fpic -shared -ldl -o shim_main.so shim_main.c
 * LD_PRELOAD=/.../shim_main.so theprogram theargs...
 */
#define _GNU_SOURCE /* needed to get RTLD_NEXT defined in dlfcn.h */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <dlfcn.h>

typedef int (*pfi)(int, char **, char **);
static pfi real_main;

/* copy argv to new location */
char **copyargs(int argc, char** argv){
    char **newargv = malloc((argc+1)*sizeof(*argv));
    char *from,*to;
    int i,len;

    for(i = 0; i<argc; i++){
        from = argv[i];
        len = strlen(from)+1;
        to = malloc(len);
        memcpy(to,from,len);
        memset(from,'\0',len);    /* zap old argv space */
        newargv[i] = to;
        argv[i] = 0;
    }
    newargv[argc] = 0;
    return newargv;
}

static int mymain(int argc, char** argv, char** env) {
    fprintf(stderr, "main argc %d\n", argc);
    return real_main(argc, copyargs(argc,argv), env);
}

int __libc_start_main(pfi main, int argc,
                      char **ubp_av, void (*init) (void),
                      void (*fini)(void),
                      void (*rtld_fini)(void), void (*stack_end)){
    static int (*real___libc_start_main)() = NULL;

    if (!real___libc_start_main) {
        char *error;
        real___libc_start_main = dlsym(RTLD_NEXT, "__libc_start_main");
        if ((error = dlerror()) != NULL) {
            fprintf(stderr, "%s\n", error);
            exit(1);
        }
    }
    real_main = main;
    return real___libc_start_main(mymain, argc, ubp_av, init, fini,
            rtld_fini, stack_end);
}

Il n'est pas possible d'intervenir sur le main() , mais vous pouvez intervenir sur la fonction standard de la bibliothèque C __libc_start_main , qui appelle ensuite main. Compilez ce fichier shim_main.c comme indiqué dans le commentaire au début, et exécutez-le comme indiqué. J'ai laissé un printf dans le code afin de vérifier qu'il est bien appelé. Par exemple, exécutez

LD_PRELOAD=/tmp/shim_main.so /bin/sleep 100

puis faites un ps et vous verrez une commande vide et des arguments affichés.

Il y a encore un peu de temps pendant lequel les arguments de la commande peuvent être visibles. Pour éviter cela, vous pouvez, par exemple, changer le shim pour lire votre secret à partir d'un fichier et l'ajouter aux arguments passés au programme.


  1. Lisez la documentation de l'interface de ligne de commande de l'application en question. Il peut bien y avoir une option pour fournir le secret à partir d'un fichier au lieu d'être directement un argument.

  2. Si cela échoue, déposez un rapport de bogue contre l'application au motif qu'il n'existe aucun moyen sûr de lui fournir un secret.

  3. Vous pouvez toujours soigneusement (!) adapter la solution dans la réponse de meuh à vos besoins spécifiques. Portez une attention particulière au commentaire de Stéphane et à ses suites.


Si vous devez passer des arguments au programme pour le faire fonctionner, vous n'aurez pas de chance quoi que vous fassiez si vous ne pouvez pas utiliser hidepid sur procfs.

Puisque vous avez mentionné qu'il s'agit d'un script bash, vous devriez déjà avoir le code source disponible, car bash n'est pas un langage compilé.

A défaut, vous pouvez pouvoir réécrire la cmdline du processus en utilisant gdb ou similaire et jouer avec argc /argv une fois qu'il a déjà commencé, mais :

  1. Ceci n'est pas sécurisé, car vous exposez toujours les arguments de votre programme avant de les modifier
  2. C'est assez hacky, même si vous pouviez le faire fonctionner, je ne recommanderais pas de vous y fier

Je recommanderais simplement d'obtenir le code source ou de parler au fournisseur pour faire modifier le code. La fourniture de secrets sur la ligne de commande dans un système d'exploitation POSIX est incompatible avec un fonctionnement sécurisé.


Linux
  1. Top 5 des référentiels de code source

  2. C argc et argv Exemples d'analyse d'arguments de ligne de commande

  3. Où puis-je trouver le code source des appels système ?

  4. Comment passer des arguments à un script invoqué par la commande source ?

  5. Numéros de ligne source dans le graphique d'appel de performance ?

Une introduction aux diffs et aux patchs

Comment installer un programme à partir de la source sous Linux

Principes de base de la compilation de logiciels à partir du code source sous Linux

Ohcount - Le compteur et l'analyseur de lignes de code source

Supprimer le code source Ppa ?

Trace de la pile du noyau vers les lignes de code source