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.
-
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.
-
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.
-
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 :
- Ceci n'est pas sécurisé, car vous exposez toujours les arguments de votre programme avant de les modifier
- 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é.