首页
社区
课程
招聘
[原创]tenda某摄像头分析二
发表于: 2022-8-8 11:49 13042

[原创]tenda某摄像头分析二

2022-8-8 11:49
13042

noodles服务分析

填点坑,这次只分析了noodles服务

 

之前分析后,确定了通过监听的端口来进行深入。
不过呢之前没有系统学习过网络编程,花了一周时间把tinyhttpd的源代码阅读理解了一下,并且仿照用python写了一个简易的httpd,可以看我另一篇文章。

 

通过相关分析之后,发现了几个漏洞。

 

noodles文件加了一个upx的壳,所以直接放ida或者ghidra看不出东西。

 

直接upx -d noodles即可。

 

这边因为无法进入uart shell,但是可以看到其打印输出,为了方便选择qemu模拟调试。

 

image-20220808092817121

 

所以使用qemu-arm-static

 

image-20220808092935022

 

nmap 扫描端口

 

启动前

 

image-20220808093119102

 

启动后

 

image-20220808093029820

 

可以看到noodles监听了1300和843端口。

 

通过字符串查找main函数。

 

这里我修改了函数名称

 

image-20220808093532231

 

main中两个strcmp函数对参数做了处理,所以noodles是有两个参数,--version和-d

 

image-20220808093832783

 

image-20220808093857375

 

-d这个参数通过分析是对操作进行打印了,所以后续为了看起来更清晰,这里加上-d

 

image-20220808094441331

 

image-20220808094427534

 

下面是流程分析。

fun_00013d3c()

通过一系列不重要的文件读写操作后,来到了fun_00013d3c()

 

image-20220808095245756

 

image-20220808100049378

 

多线程创建,主要分析FUN_00013b78,下面的一些函数内容和测试内容在代码下面贴图。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
undefined4 FUN_00013b78(void)
 
{
  int __fd;
  int __fd_00;
  int iVar1;
  char *pcVar2;
  socklen_t local_424;
  sockaddr sStack1056;
  char acStack1040 [1024];
 
  prctl(0xf,"policy_thread");
  __fd = FUN_00014eb8(0x34b); //0x34b = 843 即监听了的843端口,所以该函数进行了socket创建绑定等操作,
  if ((__fd < 1) && (__fd = FUN_00014eb8(0x228b), __fd < 1)) {
    return 0;
  }
  local_424 = 0x10;
LAB_00013bac:
  do {
    while (__fd_00 = accept(__fd,&sStack1056,&local_424), __fd_00 < 1) { //等待连接
      puts("accect err!");
    }
    iVar1 = FUN_0001d63c(__fd_00,1); //设置opt
    if ((iVar1 == 0) && (iVar1 = FUN_0001d59c(__fd_00,1), iVar1 == 0)) {
      if (DAT_000361f0 != 0) {
        printf("policy client<%d> linked, start receive...\n",__fd_00);
      }
      iVar1 = FUN_00014dd4(__fd_00,acStack1040,0x400,0xffffffff);//获取client的传值,并返回给ivar1
      if (iVar1 < 0) { //判断如果小于0,即断开链接,可以传入-1测试,
        puts("flv_recv failed");
        close(__fd_00);
        goto LAB_00013bac;
      }
      if (DAT_000361f0 == 0) { //这里的判断是根据启动是是否有-d参数,所以猜测这个-d参数应该是debug
        pcVar2 = strstr(acStack1040,"policy-file-request");
        if (pcVar2 != (char *)0x0) {
LAB_00013c30:
          iVar1 = send(__fd_00,
                       "<?xml version=\"1.0\"?><cross-domain-policy><allow-access-from domain=\"*\"  to-ports=\"*\"/></cross-domain-policy>"
                       ,0x6e,0);
          if (iVar1 == 0x6e) {
            if (DAT_000361f0 != 0) {
              puts("send_policy_string Done!");
              goto LAB_00013c80;
            }
          }
          else {
            puts("send_policy_string err!");
          }
        }
      }
      else {
        printf("policy<%d>  reqest <%s>\n",__fd_00,acStack1040);
        pcVar2 = strstr(acStack1040,"policy-file-request");
        if (pcVar2 != (char *)0x0) goto LAB_00013c30;
LAB_00013c80:
        if (DAT_000361f0 != 0) {
          printf("close <%d>\n",__fd_00);
        }
      }
    }
    close(__fd_00);
  } while( true );
 
}

FUN_00013b78

FUN_00014eb8

image-20220808102520619

FUN_00014dd4

image-20220808103611138

测试

image-20220808105020169

 

image-20220808110045122

 

上面是对845的流程分析,并未发现可利用或者其他功能。

 

主要功能点在于1300,发现的两个漏洞也在这里。

main

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
undefined4 main(int param_1,undefined4 *param_2)
 
{
  int iVar1;
  int __fd;
  int iVar2;
  int iVar3;
  int iVar4;
  socklen_t local_448;
  sockaddr sStack1092;
  undefined local_434 [20];
  undefined auStack1056 [1028];
 
  FUN_00016b3c(*param_2);
  if (param_1 < 2) {
    FUN_00016900("noodles");
    fprintf(stderr,"@@@@@@@@@@ NOODLES v%s START @@@@@@@@@@@@@@@@@\n",PTR_DAT_00036184);
  }
  else {
    iVar1 = strcmp((char *)param_2[1],"--version");
    if (iVar1 == 0) {
      puts(PTR_DAT_00036184);
      return 0;
    }
    FUN_00016900("noodles");
    fprintf(stderr,"@@@@@@@@@@ NOODLES v%s START @@@@@@@@@@@@@@@@@\n",PTR_DAT_00036184);
    iVar1 = strcmp((char *)param_2[1],"-d");
    if (iVar1 == 0) {
      DAT_000361f0 = 1;
    }
  }
  FUN_00016820(0);
  sigemptyset((sigset_t *)(local_434 + 0xc));
  local_434._0_4_ = &DAT_0001284c;
  local_434._4_4_ = 4;
  sigaction(0xb,(sigaction *)local_434,(sigaction *)0x0);
  sigaction(10,(sigaction *)local_434,(sigaction *)0x0);
  sigaction(8,(sigaction *)local_434,(sigaction *)0x0);
  sigaction(4,(sigaction *)local_434,(sigaction *)0x0);
  sigaction(7,(sigaction *)local_434,(sigaction *)0x0);
  sigaction(6,(sigaction *)local_434,(sigaction *)0x0);
  sigaction(0x1f,(sigaction *)local_434,(sigaction *)0x0);
  sigaction(0xd,(sigaction *)local_434,(sigaction *)0x0);
  FUN_00013d3c();
  iVar1 = FUN_00014eb8(0x514);//从这里开始为1300端口,这里的操作与上面socket操作一致。
  while (iVar1 < 1) {
    sleep(2);
    printf("Failed create listen on port %d, restart ...\n",0x514);
    iVar1 = FUN_00014eb8(0x514);
  }
  FUN_00013af0(0x514);
  FUN_00013b50();
  if (DAT_000361f0 != 0) {
    printf("noodles server listen on port <%d>\n",0x514);
  }
  local_448 = 0x10;
  do {
    while (__fd = accept(iVar1,&sStack1092,&local_448), __fd < 1) { //监听到client
      puts("accept err!");
    }
    iVar2 = FUN_0001d63c(__fd,1); //设置opt
    if ((iVar2 == 0) && (iVar2 = FUN_0001d59c(__fd,1), iVar2 == 0)) {
      memset(auStack1056,0,0x400);
      do {
        iVar3 = FUN_00014dd4(__fd,auStack1056 + iVar2,0x400 - iVar2,0xffffffff); //获取从client传进来的内容
        if (iVar3 < 0) { //断开
          printf("client <%d> recv failed\n",__fd);
          break;
        }
        if (DAT_000361f0 != 0) {
          printf("receive_cmd from client<%d>: <%s> len = %d\n",__fd,auStack1056,iVar3);
        }
        iVar4 = canshuchuli(auStack1056,"UPGRADE",0);  //注意这个函数,是处理参数,获取<upgrade></upgrade>中的内容,如果匹配则执行相关内容
        if (iVar4 != 0) {
          if (DAT_000361f0 != 0) {
            printf("cmd<%d>: %s\n",1,auStack1056);
          }
          FUN_00013b64();
          FUN_000146f4(__fd,auStack1056); //使用这个来进行具体功能分析
          FUN_00013b50();
          goto LAB_00011bc8;
        }
        iVar4 = canshuchuli(auStack1056,"BURNMAC",0);
        if (iVar4 != 0) {
          if (DAT_000361f0 != 0) {
            printf("cmd<%d>: %s\n",2,auStack1056);
          }
          FUN_00013d80(__fd,auStack1056);
          goto LAB_00011bc8;
        }
        iVar4 = canshuchuli(auStack1056,"ELFEXEC",0);
        if (iVar4 != 0) {
          if (DAT_000361f0 != 0) {
            printf("cmd<%d>: %s\n",3,auStack1056);
          }
          FUN_000127e8(__fd,auStack1056);
          goto LAB_00011bc8;
        }
        iVar4 = canshuchuli(auStack1056,"SYSTEM",0);
        if (iVar4 != 0) {
          if (DAT_000361f0 != 0) {
            printf("cmd<%d>: %s\n",4,auStack1056);
          }
          FUN_000140b4(__fd,auStack1056);
          goto LAB_00011bc8;
        }
        iVar4 = canshuchuli(auStack1056,"SYSTEMEX",0);
        if (iVar4 != 0) {
          if (DAT_000361f0 != 0) {
            printf("cmd<%d>: %s\n",5,auStack1056);
          }
          FUN_00014308(__fd,auStack1056);
          goto LAB_00011bc8;
        }
        iVar4 = canshuchuli(auStack1056,"DOWNLOAD",0);
        if (iVar4 != 0) {
          if (DAT_000361f0 != 0) {
            printf("cmd<%d>: %s\n",6,auStack1056);
          }
          FUN_000145bc(__fd,auStack1056);
          goto LAB_00011bc8;
        }
        iVar4 = canshuchuli(auStack1056,"UPLOAD",0);
        if (iVar4 != 0) {
          if (DAT_000361f0 != 0) {
            printf("cmd<%d>: %s\n",7,auStack1056);
          }
          FUN_0001462c(__fd,auStack1056);
          goto LAB_00011bc8;
        }
        iVar4 = canshuchuli(auStack1056,"FLASHDUMP",0);
        if (iVar4 != 0) {
          if (DAT_000361f0 != 0) {
            printf("cmd<%d>: %s\n",8,auStack1056);
          }
          FUN_00014690(__fd,auStack1056);
          goto LAB_00011bc8;
        }
        iVar4 = canshuchuli(auStack1056,"BURNSN",0);
        if (iVar4 != 0) {
          if (DAT_000361f0 != 0) {
            printf("cmd<%d>: %s\n",9,auStack1056);
          }
          FUN_00013e28(__fd,auStack1056);
          goto LAB_00011bc8;
        }
        iVar4 = canshuchuli(auStack1056,"READSN",0);
        if (iVar4 != 0) {
          if (DAT_000361f0 != 0) {
            printf("cmd<%d>: %s\n",10,auStack1056);
          }
          FUN_00013ecc(__fd,auStack1056);
          goto LAB_00011bc8;
        }
        iVar4 = canshuchuli(auStack1056,"WRITEENV",0);
        if (iVar4 != 0) {
          if (DAT_000361f0 != 0) {
            printf("cmd<%d>: %s\n",0xb,auStack1056);
          }
          FUN_00013f4c(__fd,auStack1056);
          goto LAB_00011bc8;
        }
        iVar4 = canshuchuli(auStack1056,"READENV",0);
        if (iVar4 != 0) {
          if (DAT_000361f0 != 0) {
            printf("cmd<%d>: %s\n",0xc,auStack1056);
          }
          FUN_00014008(__fd,auStack1056);
          goto LAB_00011bc8;
        }
        iVar2 = iVar2 + iVar3;
      } while (iVar2 < 0x400);
      if (DAT_000361f0 != 0) {
        printf("cmd<%d>: %s\n",0,auStack1056);
      }
      puts("Not supported cmd!");
    }
LAB_00011bc8:
    close(__fd);
  } while( true );
}
canshuchuli()

这个函数的作用是,将从client传进来的内容进行处理,获取<param_2></param_2> 中的内容并返回
image-20220808114815083
这里的话就是判断获取<CHECKSTATUS></CHECKSTATUS>等参数的值

 

image-20220808112837400

 

所以整个1300端口的交流是以<upgrade></upgrade><CHECKSTATUS></CHECKSTATUS><METHOD></METHOD>这样子的参数进行传递。

 

漏洞挖掘也要从这些标签入手。

 

<upgrade></upgrade><CHECKSTATUS></CHECKSTATUS><METHOD></METHOD>

 

可自行复现了解下。
这里就不贴漏洞位置了,各位自行发现应该没啥问题
自己写完感觉好乱,如果有问题可以直接找我,尽量给解答。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2022-8-8 11:50 被p1yang编辑 ,原因:
收藏
免费 1
支持
分享
最新回复 (2)
雪    币: 21580
活跃值: (6401)
能力值: (RANK:445 )
在线值:
发帖
回帖
粉丝
2

上一篇看起来就很有条理,这一篇确实有点乱,建议整理下。

此外,代码图贴得有点多,建议图片展示关键点即可。

最后于 2022-8-9 10:39 被胡一米编辑 ,原因:
2022-8-9 10:37
0
雪    币: 286
活跃值: (1789)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
3
胡一米 上一篇看起来就很有条理,这一篇确实有点乱,建议整理下。此外,代码图贴得有点多,建议图片展示关键点即可。
之后看下把两篇合并下,好好整理下
2022-8-9 13:51
0
游客
登录 | 注册 方可回帖
返回
//