时间:2022-08-04 21:40来源:财神爷站
有时候会遇到这样的需求,不希望命令行的某些参数被ps出来,比如命令行参数里可能存在一些用户名和密码之类的东西,在Linux下如果你想隐藏这些东西的话,你该如何操作?
如果一个程序的命令行是一个password之类的不便展示的字符串,如何不让ps打印出来呢?
ps是从/proc/$pid/cmdline里拿的命令行,而/proc/$pid/cmdline则是在内核空间解析用户程序的stack区域获取的数据,那么答案很简单,只需要覆盖掉这个区域即可,下面是个示例:
#?include ?#?include ?#?include
intmain(?intargc,?char**argv)?{charorig[?16];
//?获取stack上的命令行strcpy(orig,?argv[?1]);?//?获取命令行之后第一时间覆盖stack上的命令行strcpy(argv[?1],?"skinshoe");?getchar;}
如果应用程序不可修改代码重新编译,有没有什么统一的办法呢?当然有,用LD_PRELOAD很方便:
//?inject.c#?define_GNU_SOURCE?#?include? #?include #?include #?include
int(*_main)?(?int,?char*?*,?char*?*);?staticintpixie_main(?intargc,?char**argv,?char**env)?{chartmp[?16];?strcpy(tmp,?argv[?1]);?strncpy(argv[?1],?"pixie",?strlen(argv[?1]));?argv[?1]?=?tmp;?return_main(argc,?argv,?env);?}
int(*orig_start_main)(?int(*main)(?int,?char**,?char**),?intargc,?char**argv,?void(*init)?(?void),?void(*fini)?(?void),?void(*_fini)?(?void),?void(*stack_end));
int__libc_start_main(?int(*main)(?int,?char**,?char**),?intargc,?char**argv,?void(*init)(?void),?void(*fini)(?void),?void(*_fini)(?void),?void(*stack_end))?{orig_start_main?=?dlsym(RTLD_NEXT,?"__libc_start_main");?_main?=?main;returnorig_start_main(pixie_main,?argc,?argv,?init,?fini,?_fini,?stack_end);?}
编译之:
gcc-O2-fPIC-shared-olibinject.soinject.c-ldl
下面是一个“不能改的现有程序”:
//?demo.c#?include #?include
intmain(?intargc,?char**argv)?{printf(?"%s\n",?argv[?1]);?getchar;}
用LD_PRELOAD执行之:
LD_PRELOAD=./libinject.so?./demo?12345
此时,demo程序打印的依然是12345,然后ps看到的就是pixie了。
把LD_PRELOAD部署到路径里就好了。这是劫库的标准手法。
事事都是双刃剑,能做好事就能做坏事,用上面的把戏其实是可以任意修改任意程序的命令行的:
int(*_main)?(?int,?char*?*,?char*?*);?staticintpixie_main(?intargc,?char**argv,?char**env?)?{argv[?1]?=?"pixie";?return_main(argc,?argv,?env);?}
试试看:
root@zhaoya-VirtualBox:~?#?LD_PRELOAD=./libinject.so?ls?-als:?cannot?access?'pixie':?No?such?file?ordirectory?root@zhaoya-VirtualBox:~?#?LD_PRELOAD=./libinject.so?/bin/echo?hellopixie