Jak je zde vysvětleno, Linux vkládá argumenty programu do datového prostoru programu a udržuje ukazatel na začátek této oblasti. To je to, co používá ps
a tak dále, abyste našli a ukázali argumenty programu.
Jelikož jsou data v prostoru programu, může s nimi manipulovat. Chcete-li to provést bez změny samotného programu, musíte nahrát podložku s main()
funkce, která bude volána před skutečným hlavním programem. Tato podložka může zkopírovat skutečné argumenty do nového prostoru a poté přepsat původní argumenty tak, aby ps
uvidí pouze nulu.
Následující kód C to dělá.
/* 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);
}
Na main()
není možné zasahovat , ale můžete zasáhnout do standardní funkce knihovny C __libc_start_main
, který pokračuje voláním main. Zkompilujte tento soubor shim_main.c
jak je uvedeno v komentáři na začátku, a spusťte jej podle obrázku. Zanechal jsem printf
v kódu, takže zkontrolujete, že se skutečně volá. Například spustit
LD_PRELOAD=/tmp/shim_main.so /bin/sleep 100
pak proveďte ps
a uvidíte prázdný příkaz a zobrazené argumenty.
Stále existuje malá doba, po kterou mohou být args příkazu viditelné. Abyste tomu zabránili, můžete například změnit podložku tak, aby přečetla vaše tajemství ze souboru a přidala jej k argumentům předávaným programu.
-
Přečtěte si dokumentaci rozhraní příkazového řádku příslušné aplikace. Může existovat možnost zadat tajemství ze souboru místo přímého argumentu.
-
Pokud se to nepodaří, odešlete hlášení o chybě aplikace s odůvodněním, že neexistuje žádný bezpečný způsob, jak jí poskytnout tajemství.
-
Řešení v meuh’s můžete vždy pečlivě (!) přizpůsobit svým konkrétním potřebám. Věnujte zvláštní pozornost Stéphanovu komentáři a jeho následným krokům.
Pokud potřebujete předat programu argumenty, aby fungoval, budete mít smůlu bez ohledu na to, co uděláte, pokud nemůžete použít hidepid
na procfs.
Protože jste zmínili, že se jedná o bash skript, měli byste již mít k dispozici zdrojový kód, protože bash není kompilovaný jazyk.
Pokud se tak nestane, můžete být schopen přepsat cmdline procesu pomocí gdb
nebo podobné a hrát si s argc
/argv
jakmile to již začalo, ale:
- Toto není bezpečné, protože před změnou argumentů svého programu stále odhalujete
- Tohle je docela otřesné, i když byste to mohli uvést do provozu, nedoporučoval bych na to spoléhat.
Opravdu bych jen doporučil získat zdrojový kód nebo si promluvit s dodavatelem, aby kód upravil. Poskytování tajných informací na příkazovém řádku v operačním systému POSIX je nekompatibilní se zabezpečeným provozem.