NetGear AC2400 漏洞复现

Catalpa 网络安全爱好者

身份验证绕过以及命令注入

Authentication Bypass

基本信息

官方发布信息:https://kb.netgear.com/000062641/Security-Advisory-for-Password-Recovery-Vulnerabilities-on-Some-Routers

披露信息:https://www.zerodayinitiative.com/advisories/ZDI-20-1451/

漏洞评分:8.8(High)

漏洞描述:NetGear 部分路由器存在登录验证绕过漏洞,攻击者可以利用此漏洞绕过正常的登录逻辑直接访问后台接口,可以结合其他漏洞实现任意代码执行。

漏洞分析

根据披露信息,去网件官网下载到存在漏洞的固件:https://www.netgear.com/support/

ZDI 披露信息指出漏洞影响多个型号的设备,我们以 AC2400 为例分析。

下载 1.2.0.74 和 1.2.0.76 两个版本固件,分析公开漏洞一个比较实用的方法就是进行版本比较,常用工具包括 Ghidra、Bindiff、diaphora 等。(PS:IDA 7.5 支持 MIPS 反编译啦,可以使用 Bindiff 6)

首先对固件解包,固件没有经过特殊处理,直接 binwalk 一下即可。解开得到一个 Linux 文件系统,按照披露信息找到 /usr/sbin/mini_httpd 二进制程序,加载到 IDA。

Shift+F12 搜索字符串,漏洞位于处理用户请求的位置,所以直接搜索 Content-Length 或者其他请求头中会出现的字符串,通过交叉引用可以定位到函数 0x40A540 (1.2.0.74),其中存在以下代码片段

1
2
3
fprintf(v4, "[%s::%s():%d] ", "mini_httpd.c", "handle_request", 1634);
fputs("read\n", v4);
fclose(v4);

可以猜测这个函数叫做 handle_request,主要用于处理 HTTP 请求。

摘录两个版本的代码如下

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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
// 1.2.0.74
int handle_request()
{
// 省略变量定义部分

memcpy(maybe_allow_uris, off_427030, sizeof(maybe_allow_uris));
signal(14, sub_407B68);
alarm(0x3Cu);
dword_42972C = 0;
dword_429730 = 0;
path = 0;
dword_429734 = 0;
dword_42974C = -1;
dword_429738 = 0;
dword_42973C = "";
dword_429744 = 0;
dword_429748 = -1;
host = 0;
v0 = 4390912;
::haystack = "";
dword_429768 = "";
dword_42976C = "";
dword_429750 = 0;
authorization = 0;
v1 = 4390912;
dword_429758 = -1;
v2 = 4390912;
dword_429760 = -1;
dword_429740 = 0;
dword_429754 = 0;
dword_42975C = 0;
login_or_not = 1;
if ( !do_ssl )
{
v170 = 1;
setsockopt(fd, 6, 3, &v170, 4u);
}
if ( do_ssl )
{
dword_429770 = SSL_new(dword_428718, v0, v1, v2);
SSL_set_fd(dword_429770, fd);
if ( !SSL_accept(dword_429770) )
goto LABEL_97;
}
dword_429774 = 0;
dword_429778 = 0;
do
{
while ( 1 )
{
v3 = sub_406E2C(v178, 9999, v1, v2);
if ( !access("/tmp/dbg_x", 0) )
{
v4 = fopen64("/dev/console", "a+");
if ( v4 )
{
fprintf(v4, "[%s::%s():%d] ", "mini_httpd.c", "handle_request", 1634);
fputs("read\n", v4);
fclose(v4);
}
}
if ( v3 >= 0 )
break;
v5 = *_errno_location();
if ( v5 != 4 && v5 != 11 )
{
LABEL_14:
v6 = access("/tmp/dbg_x", 0);
v7 = 4259840;
if ( !v6 )
{
v8 = fopen64("/dev/console", "a+");
if ( v8 )
{
fprintf(v8, "[%s::%s():%d] ", "mini_httpd.c", "handle_request", 1639);
v9 = "break on nothing read\n";
LABEL_25:
fputs(v9, v8);
fclose(v8);
goto LABEL_26;
}
}
goto LABEL_26;
}
}
if ( !v3 )
goto LABEL_14;
alarm(0x3Cu);
if ( !access("/tmp/dbg_x", 0) )
{
v10 = fopen64("/dev/console", "a+");
if ( v10 )
{
fprintf(v10, "[%s::%s():%d] ", "mini_httpd.c", "handle_request", 1643);
fprintf(v10, "read: %s\n", v178);
fclose(v10);
}
}
sub_405A40(&dword_42977C, &dword_429774, &dword_429780, v178, v3);
v11 = dword_42977C;
}
while ( !strstr(dword_42977C, "\r\n\r\n") && !strstr(v11, "\n\n") );
v12 = access("/tmp/dbg_x", 0);
v7 = 4259840;
if ( !v12 )
{
v8 = fopen64("/dev/console", "a+");
if ( v8 )
{
fprintf(v8, "[%s::%s():%d] ", "mini_httpd.c", "handle_request", 1649);
v9 = "break on find 2 crlf\n";
goto LABEL_25;
}
}
LABEL_26:
v13 = sub_405720(v7);
v14 = v13;
if ( !v13 )
goto LABEL_45;
v15 = strpbrk(v13, " \t\n\r");
path = v15;
if ( !v15 )
goto LABEL_45;
*v15 = 0;
path = (v15 + 1);
if ( strstr(v15 + 1, "ptimeout.cgi") )
{
if ( !multi_login_flag )
{
v17 = getppid();
kill(v17, 2);
}
v18 = path;
path = v18 + strspn(path, " \t\n\r");
v19 = strpbrk(path, " \t\n\r");
dword_429740 = v19;
if ( v19 )
{
*v19 = 0;
dword_429740 = (v19 + 1);
v20 = 401;
v21 = "Unauthorized";
v22 = ("\r\n\r\n" + 4);
v23 = "Authorization required.";
goto LABEL_382;
}
LABEL_45:
v20 = 400;
v21 = "Bad Request";
v22 = ("\r\n\r\n" + 4);
LABEL_266:
v23 = "Can't parse request.";
goto LABEL_382;
}
while ( 1 )
{
v37 = sub_405720(v16);
if ( !v37 || !*v37 )
break;
if ( !strncasecmp(v37, "Authorization:", 0xEu) )
{
authorization = &v37[strspn(v37 + 14, " \t") + 14];
}
else if ( !strncasecmp(v37, "Content-Length:", 0xFu) )
{
v24 = v37 + 15;
v25 = strspn(v24, " \t");
dword_429758 = atol(&v24[v25]);
}
else if ( !strncasecmp(v37, "Content-Type:", 0xDu) )
{
dword_429754 = &v37[strspn(v37 + 13, " \t") + 13];
}
else if ( !strncasecmp(v37, "Cookie:", 7u) )
{
dword_42975C = &v37[strspn(v37 + 7, " \t") + 7];
dword_429784 = 1;
}
else if ( !strncasecmp(v37, "Host:", 5u) )
{
v26 = &v37[strspn(v37 + 5, " \t") + 5];
host = v26;
if ( strchr(v26, 47) || *v26 == 46 )
goto LABEL_45;
}
else if ( !strncasecmp(v37, "If-Modified-Since:", 0x12u) )
{
v27 = v37 + 18;
v28 = strspn(v27, " \t");
dword_429760 = tdate_parse(&v27[v28]);
}
else if ( !strncasecmp(v37, "Referer:", 8u) )
{
::haystack = &v37[strspn(v37 + 8, " \t") + 8];
}
else if ( !strncasecmp(v37, "Referrer:", 9u) )
{
::haystack = &v37[strspn(v37 + 9, " \t") + 9];
}
else if ( !strncasecmp(v37, "User-Agent:", 0xBu) )
{
dword_429768 = &v37[strspn(v37 + 11, " \t") + 11];
}
else
{
v29 = strncasecmp(v37, "Accept-Language:", 0x10u);
v30 = v37;
if ( v29 )
{
v31 = v37 + 11;
if ( !strncasecmp(v30, "SOAPAction:", 0xBu) )
{
v32 = strspn(v31, " \t");
v33 = strcasestr(&v31[v32], "urn:NETGEAR-ROUTER:service:");
v16 = (v33 + 27);
if ( v33 )
{
for ( i = 0; ; ++i )
{
v35 = *v16;
if ( v35 == 58 )
break;
*(i + 4364168) = v35;
++v16;
}
v36 = strchr(v16, 35);
if ( v36 && v36[1] )
snprintf(&byte_429808, 0x80u, "%s", v36 + 1);
byte_429788[i] = 0;
currentsetting_flag = 1;
}
}
}
else
{
dword_42976C = &v37[strspn(v37 + 16, " \t") + 16];
}
}
}
if ( host )
{
v38 = nvram_get("config_state");
if ( !v38 )
v38 = ("\r\n\r\n" + 4);
if ( *v38 == 98 )
goto LABEL_407;
v39 = nvram_get("config_state");
if ( !v39 )
v39 = ("\r\n\r\n" + 4);
if ( *v39 == 99 )
{
LABEL_407:
if ( is_captive_detecting(host, dword_429768) )
{
dword_42988C = 1;
dword_429740 = strpbrk(path, " \t\n\r");
v20 = 200;
v21 = "OK";
v22 = ("\r\n\r\n" + 4);
v23 = "Success";
goto LABEL_382;
}
}
}
if ( !host && currentsetting_flag == 1 )
host = "www.routerlogin.com";
is_usb_session = usb_session_check();
v40 = 1;
LODWORD(v182) = &host;
HIDWORD(v182) = host;
v41 = nvram_get("lan_ipaddr");
if ( strcmp(HIDWORD(v182), v41) )
v40 = strstr(*v182, "routerlogin") != 0;
LODWORD(v182) = 4259840;
if ( *nvram_get("http_server_wan_enable") == 49 && *nvram_get("fw_remote") == 48 )
{
v42 = nvram_get("wifi_ap_mode");
if ( !v42 )
v42 = ("\r\n\r\n" + 4);
if ( *v42 == 49 )
{
if ( v40 || (LODWORD(v182) = host, v43 = getIPAddress("group1"), !strcmp(v182, v43)) )
v40 = 1;
}
else if ( !(v40 | is_usb_session) )
{
nvram_get("config_state");
v40 = 0;
}
}
if ( *nvram_get("http_server_wan_enable") == 48 && *nvram_get("fw_remote") == 49 && *nvram_get("config_state") == 115 )
{
v44 = is_usb_session;
if ( is_usb_session && !v40 )
{
system("/bin/echo drop request usb > /dev/console");
LABEL_97:
v45 = 1;
goto LABEL_98;
}
}
else
{
v44 = is_usb_session;
}
if ( v44 )
multi_login_flag = 0;
if ( !check_valid_request() )
{
v20 = 403;
v21 = "Forbidden";
v22 = ("\r\n\r\n" + 4);
v23 = "URL is illegal.";
goto LABEL_382;
}
if ( strstr(path, "setupwizard.cgi") )
currentsetting_flag = 1;
if ( currentsetting_flag == 1 && !check_lan_guest() )
{
system("/bin/echo genie from wan, drop request now > /dev/console");
v45 = 0;
LABEL_98:
exit(v45);
}
if ( currentsetting_flag == 1 ) // 是安装向导就进入 if
{
system("/bin/echo it is for setupwizard! >> /tmp/sw.log");
LODWORD(v182) = 0x430000;
strcpy(temp_uri, "/setupwizard.cgi HTTP/1.1\r\n");
path = v182 - 0x6770;
if ( dword_429784 == 1 )
{
dword_429A90 = 0;
dword_429A94 = 0;
dword_429A98 = 0;
dword_429A9C = 0;
byte_429AA0 = 0;
v46 = strchr(dword_42975C, '=');
if ( v46 )
strlcpy(&dword_429A90, v46 + 1, 17);
}
}
else
{
if ( !access("/tmp/dnshj.out", 0) && (!strstr(host, "routerlogin") || !strncmp(path, "/ ", 2u)) )
{
v47 = dword_428518;
if ( !dword_428518 )
v47 = "indexdnshj.htm";
sprintf(temp_uri, "/ca/setup.cgi?next_file=%s HTTP/1.1\r\n", v47);
path = temp_uri;
}
if ( access("/tmp/blank_state.out", 0) )
{
if ( !access("/tmp/tm_already_warning", 0) )
unlink("/tmp/tm_already_warning");
}
else
{
v48 = select_request_type(1); // 除了安装向导和 setup 的请求走这里
if ( !strcasecmp(v14, v48) ) // 判断是不是 GET 请求?
{
v49 = path;
if ( strstr(path, ".htm") || !strncmp(v49, "/ HTTP", 6u) )// 如果 PATH 里面有 .htm 或者直接访问的根目录,就进入 if
{
LODWORD(v182) = host;
v50 = nvram_get("lan_ipaddr");
v51 = strcmp(v182, v50);
haystack = 1;
if ( v51 )
haystack = (strstr(host, "routerlogin") != 0);// 不能存在 routerlogin
nvram_get("tm_action_internet");
v52 = path;
stream = strstr(path, "traffic_status.htm");
if ( !haystack || (v53 = strstr(v52, "_h.htm") != 0, access("/tmp/tm_already_warning", 0)) && !v53 )
{
strcpy(temp_uri, "/ HTTP/1.1\r\n");
if ( !stream ) // URI 也没有 traffic_status.htm
{
v54 = fopen64("/tmp/blank_state.out", "r");// 是否存在这个文件?
stream = v54;
if ( v54 )
{
if ( fgets(v177, 99, v54) && (v55 = strstr(v177, "htm")) != 0 )
{
v55[3] = 0;
sprintf(temp_uri, "/setup.cgi?next_file=%s HTTP/1.1\r\n", v177);
if ( access("/tmp/tm_block_internet", 0) )
{
system("/usr/sbin/rc dnshj stop");
}
else
{
LODWORD(v182) = 4259840;
if ( access("/tmp/tm_already_warning", 0) )
{
v56 = fopen64(v182 + 14864, "w+");
if ( v56 )
fclose(v56);
}
}
path = temp_uri;
login_or_not = 0;
}
else if ( !strstr(v177, "lan_wan_conflict") && !haystack )
{
sprintf(temp_uri, "/setup.cgi?next_file=%s HTTP/1.1\r\n", "alert.htm");
path = temp_uri;
}
fclose(stream);
multi_login_flag = 0;
}
}
}
}
}
}
}
if ( !access("/tmp/lan_ip_auto_changed", 0) ) // 前提是存在这个文件
{
v57 = dword_429768;
if ( strstr(dword_429768, "Genie") || strstr(v57, "LANWizard") )
goto LABEL_162;
v58 = select_request_type(1);
if ( !strcasecmp(v14, v58) ) // 如果是 GET 请求就进入 if
{
v59 = path;
if ( !strstr(path, "error-tab-rec.htm")
&& (strstr(v59, ".htm") || !strncmp(v59, "/ HTTP", 6u) || strstr(v59, ".aspx")) )
{
if ( access("/tmp/conflict_warning", 0) )
{
strlcpy(temp_uri, "/setup.cgi?next_file=BRS_wanlan_conflict.html HTTP/1.1\r\n", 512);
path = temp_uri;
system("/bin/cp /proc/uptime /tmp/conflict_warning");
}
}
}
login_or_not = 0;
}
if ( !access("/tmp/conflict_warning", 0) && strstr(path, "settings.jpg") )
{
system("/bin/touch /tmp/stop_conflict_warning");
unlink("/tmp/conflict_warning");
}
if ( !access("/tmp/conflict_warning", 0) )
{
v182 = get_uptime("/tmp/conflict_warning");
v60 = get_uptime("/proc/uptime");
if ( HIDWORD(v60) - HIDWORD(v182) != v60 < v182 || (v60 - v182) >= 3 )
{
unlink("/tmp/conflict_warning");
unlink("/tmp/lan_ip_auto_changed");
unlink("/tmp/stop_conflict_warning");
system("/usr/sbin/rc dnshj stop");
}
}
LABEL_162:
if ( access("/tmp/brs_hijack.out", 0) )
goto LABEL_205;
v61 = getIPAddress("group1");
v62 = host;
if ( !strcmp(host, "www.msftncsi.com") && strstr(path, "ncsi.txt")
|| !strcmp(v62, "www.msftconnecttest.com") && strstr(path, "connecttest.txt") )
{
dword_429740 = "HTTP/1.0";
v20 = 404;
v21 = "Not Found";
v22 = ("\r\n\r\n" + 4);
LABEL_372:
v23 = "File not found.";
goto LABEL_382;
}
v63 = socket(2, 3, 255);
if ( v63 == -1 )
return (perror)("socket creating failed");
v65 = nvram_get("wan_ifname");
strlcpy(v172, v65, 16);
if ( ioctl(v63, 0x8915u, v172) )
{
v74 = nvram_get("wifi_ap_mode");
if ( !v74 )
v74 = ("\r\n\r\n" + 4);
v75 = 0;
if ( *v74 )
{
v75 = 1;
if ( strcmp(host, v61) )
{
v76 = nvram_get("wifi_ap_mode");
if ( !v76 )
v76 = "\r\n\r\n" + 4;
v75 = 0;
if ( atoi(v76) )
{
v77 = host;
v78 = nvram_get("wifi_ap_name");
if ( !v78 )
v78 = "";
v75 = strcasestr(v77, v78) != 0;
}
}
}
v79 = host;
v80 = nvram_get("lan_ipaddr");
v81 = v79;
v72 = 1;
if ( strcmp(v81, v80) && !strstr(host, "routerlogin") )
v72 = v75;
}
else
{
v66 = inet_ntoa(in);
v67 = strdup(v66);
v68 = host;
v70 = v67;
v69 = nvram_get("lan_ipaddr");
v71 = v68;
v72 = 1;
if ( strcmp(v71, v69) )
{
v73 = host;
if ( !strstr(host, "routerlogin") )
v72 = strstr(v73, v70) != 0;
}
}
v82 = select_request_type(1);
if ( strcasecmp(v14, v82) )
goto LABEL_203;
v83 = path;
if ( strstr(path, "BRS_")
|| strstr(v83, "debug.htm")
|| strstr(v83, "currentsetting")
|| strstr(v83, "POT.htm")
|| !access("/tmp/wizard_vlan", 0)
|| !access("/tmp/conflict_warning", 0) )
{
goto LABEL_203;
}
if ( v72 && !(need_fakepath)(path) )
goto LABEL_205;
if ( access("/tmp/brs_gui_hijack", 0) )
{
if ( v72 )
v84 = "BRS_index.htm";
else
v84 = "BRS_hijack_index.htm";
sprintf(temp_uri, "/setup.cgi?next_file=%s HTTP/1.1", v84);
path = temp_uri;
LABEL_203:
if ( !v72 )
goto LABEL_204;
goto LABEL_205;
}
if ( !v72 )
{
sprintf(temp_uri, "/setup.cgi?next_file=%s HTTP/1.1", "BRS_hijack_success.htm");
path = temp_uri;
LABEL_204:
login_or_not = 0;
}
LABEL_205:
v85 = nvram_get("config_state");
if ( !v85 )
v85 = ("\r\n\r\n" + 4);
if ( *v85 == 'b' )
goto LABEL_211;
v86 = nvram_get("need_not_login");
if ( !v86 )
v86 = ("\r\n\r\n" + 4);
if ( *v86 == 49 )
{
LABEL_211:
nvram_set("need_not_login", "0");
nvram_set("start_in_blankstate", "1");
}
if ( (path_exist)(path, off_427E50, v14)
|| (v87 = path, strstr(path, "htpwd_recovery.cgi")) && (v88 = select_request_type(3), !strcasecmp(v14, v88))
|| strstr(v87, "PNPX_GetShareFolderList") )
{
multi_login_flag = 0;
login_or_not = 0;
if ( strstr(path, "currentsetting.htm") )
currentsetting_flag = 1;
}
v89 = off_427E50;
v90 = 0;
while ( *v89 )
{
if ( strstr(path, *v89) )
v90 = 1;
++v89;
}
v91 = nvram_get("openvpn_hijack");
if ( !v91 )
v91 = ("\r\n\r\n" + 4);
if ( *v91 == 49 && !do_ssl )
{
v92 = select_request_type(1);
if ( !strcasecmp(v14, v92) && !v90 )
{
v93 = path;
if ( !strstr(path, ".gif")
&& !strstr(v93, ".css")
&& !strstr(v93, ".js")
&& !strstr(v93, ".xml")
&& !strstr(v93, ".png")
&& !strstr(v93, ".jpg")
&& !currentsetting_flag )
{
v94 = dword_429740;
if ( !dword_429740 )
v94 = "HTTP/1.1";
dword_429740 = v94;
snprintf(
v172,
0x64u,
"Location: http://www.routerlogin.net/setup.cgi?next_file=%s",
"openvpn_confirm_update.htm");
LABEL_255:
v20 = 302;
v21 = "Found";
v22 = v172;
v23 = "";
goto LABEL_382;
}
}
}
v95 = nvram_get("tc_from_old");
if ( !v95 )
v95 = ("\r\n\r\n" + 4);
if ( *v95 == 49 && !do_ssl )
{
v96 = select_request_type(1);
if ( !strcasecmp(v14, v96) && !v90 )
{
v97 = path;
if ( !strstr(path, ".gif")
&& !strstr(v97, ".css")
&& !strstr(v97, ".js")
&& !strstr(v97, ".xml")
&& !strstr(v97, ".png")
&& !strstr(v97, ".jpg")
&& !currentsetting_flag )
{
v98 = dword_429740;
if ( !dword_429740 )
v98 = "HTTP/1.1";
dword_429740 = v98;
snprintf(v172, 0x64u, "Location: %s", "tc_exist_unit_hijack.htm");
goto LABEL_255;
}
}
}
v99 = path;
if ( !strstr(path, ".cgi") && strstr(v99, ".htm") && !strstr(v99, "shares") )
{
v100 = strlen(v99);
if ( v100 >= 0x1E2 )
{
v20 = 404;
v21 = "Not Found";
v22 = "";
v23 = "No such file.";
goto LABEL_382;
}
strlcpy(temp_uri, v99, v100 - 8);
v101 = strrchr(temp_uri, 47);
strlcpy(byte_429AA4, temp_uri, v101 - temp_uri);
v102 = path;
if ( *path == '/' )
path = v102 + strlen(byte_429AA4) + 1;
snprintf(temp_uri, 0x200u, "%s/setup.cgi?next_file=%s", byte_429AA4, path);
path = temp_uri;
}
v103 = path;
path = v103 + strspn(path, " \t\n\r");
v104 = strpbrk(path, " \t\n\r");
dword_429740 = v104;
if ( !v104 )
{
v20 = 400;
v21 = "Bad Request";
v22 = "";
goto LABEL_266;
}
*v104 = 0;
dword_429740 = (v104 + 1);
v105 = strchr(path, '?');
dword_42973C = v105;
if ( v105 )
{
*v105 = 0;
v106 = v105 + 1;
}
else
{
v106 = "";
}
dword_42973C = v106;
v107 = select_request_type(1);
v108 = strcasecmp(v14, v107) == 0;
v109 = 1;
if ( !v108 )
{
v110 = select_request_type(2);
v108 = strcasecmp(v14, v110) == 0;
v109 = 2;
if ( !v108 )
{
v111 = select_request_type(3);
v108 = strcasecmp(v14, v111) != 0;
v109 = 3;
if ( v108 )
{
v20 = 501;
v21 = "Not Implemented";
v22 = "";
v23 = "That method is not implemented.";
goto LABEL_382;
}
}
}
v112 = path;
dword_429730 = v109;
if ( strstr(path, "%00") || (sub_4062BC(v112, v112), v113 = path, *path != 47) )
{
v20 = 400;
v21 = "Bad Request";
v22 = "";
v23 = "Bad filename.";
goto LABEL_382;
}
v114 = path + 1;
dword_429734 = (path + 1);
while ( 1 )
{
v117 = strstr(v113 + 1, "//");
v118 = v117;
if ( !v117 )
break;
for ( j = v117 + 2; *j == 47; ++j )
;
HIDWORD(v182) = j;
v116 = strlen(j);
memmove(v118 + 1, HIDWORD(v182), v116 + 1);
}
while ( !strncmp(v113 + 1, "./", 2u) )
{
v119 = strlen(v113 + 3);
memmove((v113 + 1), v113 + 3, v119 + 1);
}
while ( 1 )
{
v121 = strstr(v113 + 1, "/./");
v122 = v121;
if ( !v121 )
break;
HIDWORD(v182) = v121 + 2;
v120 = strlen(v121 + 2);
memmove(v122, HIDWORD(v182), v120 + 1);
}
while ( 1 )
{
if ( !strncmp(v113 + 1, "../", 3u) )
{
v123 = strlen(v113 + 4);
v124 = (v113 + 1);
v125 = v113 + 4;
goto LABEL_299;
}
v126 = strstr(v113 + 1, "/../");
v127 = v126 - 1;
if ( !v126 )
break;
for ( k = v127 < v114; !k && *v127 != 47; k = v127 < v114 )
--v127;
LODWORD(v182) = v127;
HIDWORD(v182) = v126 + 4;
v123 = strlen(v126 + 4);
v125 = HIDWORD(v182);
v124 = (v182 + 1);
LABEL_299:
memmove(v124, v125, v123 + 1);
}
LABEL_304:
v130 = strlen(v113 + 1);
if ( v130 >= 4 )
{
v129 = (v114 + v130 - 3 - 1);
if ( !strcmp((v114 + v130 - 3), "/..") )
{
while ( v129 >= v114 )
{
if ( *v129 == 47 )
{
*v129 = 0;
goto LABEL_304;
}
--v129;
}
}
}
if ( !v113[1] )
dword_429734 = "./";
v131 = dword_429734;
v132 = *dword_429734;
if ( v132 == '/' || v132 == '.' && dword_429734[1] == '.' && (!dword_429734[2] || dword_429734[2] == '/') )
{
v20 = 400;
v21 = "Bad Request";
v22 = "";
v23 = "Illegal filename.";
goto LABEL_382;
}
if ( dword_4284D4 )
{
v133 = host;
if ( !host )
{
v169 = 128;
if ( getsockname(fd, v177, &v169) >= 0 )
v133 = ntoa(v177);
else
v133 = "UNKNOWN_HOST";
}
dword_429750 = v133;
v134 = v133;
for ( l = dword_429750; ; ++l )
{
v136 = *l;
v108 = v136 != 0;
v137 = 2 * v136;
if ( !v108 )
break;
if ( (*(_ctype_b + v137) & 1) != 0 )
*l = *(_ctype_tolower + v137);
}
snprintf(byte_429CA4, 0x2710u, "%s/%s", v134, v131);
dword_429734 = byte_429CA4;
}
signal(14, sub_407E44);
alarm(0x12Cu);
v170 = stat64(dword_429734, &sb);
if ( v170 < 0 )
{
v138 = dword_429734;
for ( dword_429738 = &v138[strlen(dword_429734)]; ; *dword_429738 = 47 )
{
v139 = dword_429734;
v140 = dword_429738;
do
{
if ( dword_429734 >= --v140 )
{
dword_429738 = 0;
v141 = -1;
goto LABEL_334;
}
}
while ( *v140 != 47 );
dword_429738 = v140;
*v140 = 0;
v141 = stat64(v139, &sb);
if ( v141 >= 0 )
break;
}
++dword_429738;
LABEL_334:
v170 = v141;
}
if ( v170 < 0 )
goto LABEL_371;
if ( (!::haystack || !*::haystack) && dword_429734 )
{
v172[0] = 0;
v172[1] = 0;
v172[2] = 0;
v172[3] = 0;
v172[4] = 0;
in.s_addr = 0;
v142 = nvram_get("product_name");
if ( !v142 )
v142 = "";
sprintf(v172, "NETGEAR_%s.cfg", v142);
if ( !strcmp(dword_429734, v172) )
{
v20 = 403;
v21 = "Forbidden";
v22 = "";
v23 = "HTML is illegal.";
goto LABEL_382;
}
}
v143 = dword_429734;
v144 = &v143[strlen(dword_429734)];
if ( (dword_432B40 & 0xF000) == 0x4000 )
{
if ( *(v144 - 1) == 47 || dword_429738 )
{
v146 = maybe_allow_uris;
while ( v146 != v172 )
{
LODWORD(v182) = dword_429734;
if ( !strcmp(dword_429734, "./") )
snprintf(v178, 0x2710u, "%s", *v146);
else
snprintf(v178, 0x2710u, "%s%s", v182, *v146);
if ( is_usb_session )
{
++v146;
}
else
{
++v146;
if ( stat64(v178, &sb) >= 0 )
{
dword_429734 = v178;
goto LABEL_361;
}
}
}
v147 = access("/tmp/http_disable_lan", 0);
v149 = 0x410000;
if ( !v147 )
{
v150 = nvram_get("lan_ipaddr");
v152 = inet_network(v150);
v151 = nvram_get("lan_netmask");
v154 = inet_network(v151);
v153 = inet_network(remote_ip);
v148 = 0x410000;
if ( ((v153 ^ v152) & v154) == 0 )
{
v20 = 503;
v21 = "The Share is not available";
LABEL_369:
v22 = "";
v23 = "";
goto LABEL_382;
}
}
if ( !sc_usb_mounted(v149, v148) )
{
v20 = 503;
v21 = "No Shares Available";
goto LABEL_369;
}
if ( dword_429738 )
{
LABEL_371:
v20 = 404;
v21 = "Not Found";
v22 = "";
goto LABEL_372;
}
if ( is_usb_session )
usb_auth_check(dword_429734);
else
maybe_login(dword_429734);
sub_407980();
if ( !is_usb_session || is_readable(dword_429734, "") )
{
stream = scandir64(dword_429734, &v166, 0, &alphasort64);
if ( stream >= 0 )
{
v169 = 0;
snprintf(
v177,
0x2710u,
"<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n"
"\n"
"<html>\n"
"\n"
" <head>\n"
" <meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\">\n"
" <title>Index of %s</title>\n"
" </head>\n"
"\n"
" <body bgcolor=\"#99cc99\" text=\"#000000\" link=\"#2020ff\" vlink=\"#4040cc\">\n"
" <h4>Index of %s</h4>\n"
" <pre>\n",
dword_429734,
dword_429734);
v156 = 0;
sub_405B4C(&v168, &v169, &v167, v177);
while ( v156 != stream )
{
haystack = dword_429734;
v157 = (*(v166 + 4 * v156) + 19);
v181 = *(v166 + 4 * v156);
snprintf(byte_42EBA4, 0x7D0u, "%s/%s", dword_429734, v157);
if ( !is_usb_session || is_readable(haystack, v157) )
{
v159 = lstat64(byte_42EBA4, v174);
v158 = ("\r\n\r\n" + 4);
if ( v159 >= 0 )
{
v160 = strcmp(v157, ".");
v158 = ("\r\n\r\n" + 4);
if ( v160 )
{
if ( !is_usb_session
|| (v175 & 0xF000) != 40960
|| !*(v181 + 19)
|| (v161 = strstr(haystack, "shares/USB_Storage"), v158 = ("\r\n\r\n" + 4), !v161)
&& (!strstr(haystack, "shares/")
|| (v162 = strstr(haystack, "_Drive"), v158 = ("\r\n\r\n" + 4), !v162)) )
{
if ( !strcmp(v157, "..") )
{
v163 = strcmp(dword_429734, "shares/");
v158 = ("\r\n\r\n" + 4);
if ( v163 )
{
sub_406E78(v157);
snprintf(byte_42EBA4, 0x7D0u, "<A HREF=\"%s\">[To Parent Directory]</A>\n", byte_42F374);
v158 = byte_42EBA4;
}
}
else
{
v164 = localtime(&dword_432B70);
strftime(v172, 0x3Cu, "%A, %B %d, %Y %l:%M %p", v164);
sub_406E78(v157);
snprintf(
byte_42EBA4,
0x7D0u,
"%-40s %14lld <A HREF=\"%s\">%s</A>\n",
v172,
v176,
byte_42F374,
v157);
v158 = byte_42EBA4;
}
}
}
}
}
else
{
memset(byte_42EBA4, 0, sizeof(byte_42EBA4));
v158 = byte_42EBA4;
}
sub_405B4C(&v168, &v169, &v167, v158);
v156 = (v156 + 1);
}
snprintf(
v177,
0x2710u,
" </pre>\n\n <hr>\n\n <address><a href=\"%s\">%s</a></address>\n \n </body>\n\n</html>\n",
"http://www.acme.com/software/mini_httpd/",
"mini_httpd/1.24 10May2016");
sub_405B4C(&v168, &v169, &v167, v177);
sub_4070A4(200, "Ok", "", "", "text/html; charset=%s", optlen_4);
if ( dword_429730 != 2 )
{
*(v168 + v167) = 0;
sub_405BB0(v168);
}
sub_406B58();
return (SSL_free)(dword_429770);
}
v155 = ntoa(&client_addr);
syslog(6, "%.80s Directory \"%.80s\" is protected", v155, path);
v20 = 403;
v21 = "Forbidden";
v22 = "";
}
else
{
v20 = 403;
v21 = "Forbidden";
v22 = "";
}
v23 = "Directory is protected.";
}
else
{
if ( *dword_42973C )
snprintf(v177, 0x2710u, "Location: %s/?%s", path, dword_42973C);
else
snprintf(v177, 0x2710u, "Location: %s/", path);
v20 = 302;
v21 = "Found";
v22 = v177;
v23 = "Directories must end with a slash.";
}
LABEL_382:
send_error(v20, v21, v22, v23);
}
for ( m = v144 - 1; *m == 47; --m )
*m = 0;
LABEL_361:
execute_cgi();
return (SSL_free)(dword_429770);
}
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
// 1.2.0.76
int handle_request()
{
// 省略变量定义部分

memcpy(v224, off_42A080, sizeof(v224));
signal(14, sub_408800);
alarm(0x3Cu);
dword_42C878 = 0;
dword_42C89C = -1;
dword_42C87C = 0;
path = 0;
host = 0;
dword_42C880 = 0;
dword_42C8B4 = "";
dword_42C884 = 0;
dword_42C8B8 = "";
dword_42C8BC = "";
dword_42C888 = "";
dword_42C890 = 0;
dword_42C898 = -1;
dword_42C8A0 = 0;
authorization = 0;
dword_42C8A8 = -1;
dword_42C8B0 = -1;
dword_42C88C = 0;
dword_42C8A4 = 0;
dword_42C8AC = 0;
dword_42A248 = 1;
if ( !do_ssl )
{
v223 = 1;
setsockopt(dword_42C86C, 6, 3, &v223, 4u);
}
if ( do_ssl )
{
dword_42C8C0 = SSL_new(dword_42B864);
SSL_set_fd(dword_42C8C0, dword_42C86C);
v0 = SSL_accept(dword_42C8C0);
v1 = 1;
if ( !v0 )
LABEL_106:
exit(v1);
}
dword_42C8C4 = 0;
dword_42C8C8 = 0;
do
{
while ( 1 )
{
v2 = sub_407960(v230, 9999);
if ( !access("/tmp/dbg_x", 0) )
{
v3 = fopen64("/dev/console", "a+");
if ( v3 )
{
fprintf(v3, "[%s::%s():%d] ", "mini_httpd.c", "handle_request", 1648);
fputs("read\n", v3);
fclose(v3);
}
}
if ( v2 >= 0 )
break;
v4 = *_errno_location();
if ( v4 != 4 && v4 != 11 )
{
LABEL_14:
if ( !access("/tmp/dbg_x", 0) )
{
v6 = fopen64("/dev/console", "a+");
if ( v6 )
{
fprintf(v6, "[%s::%s():%d] ", "mini_httpd.c", "handle_request", 1653);
v7 = "break on nothing read\n";
LABEL_25:
fputs(v7, v6);
fclose(v6);
goto LABEL_26;
}
}
goto LABEL_26;
}
}
if ( !v2 )
goto LABEL_14;
alarm(0x3Cu);
if ( !access("/tmp/dbg_x", 0) )
{
v8 = fopen64("/dev/console", "a+");
if ( v8 )
{
fprintf(v8, "[%s::%s():%d] ", "mini_httpd.c", "handle_request", 1657);
fprintf(v8, "read: %s\n", v230);
fclose(v8);
}
}
sub_406164(&dword_42C8CC, &dword_42C8C4, &dword_42C8D0, v230, v2);
v9 = dword_42C8CC;
}
while ( !strstr(dword_42C8CC, "\r\n\r\n") && !strstr(v9, "\n\n") );
if ( !access("/tmp/dbg_x", 0) )
{
v6 = fopen64("/dev/console", "a+");
if ( v6 )
{
fprintf(v6, "[%s::%s():%d] ", "mini_httpd.c", "handle_request", 1663);
v7 = "break on find 2 crlf\n";
goto LABEL_25;
}
}
LABEL_26:
v10 = sub_405E10(v5);
v11 = v10;
if ( !v10 || (v12 = strpbrk(v10, " \t\n\r"), (path = v12) == 0) )
{
LABEL_45:
v17 = 400;
v19 = "";
v18 = "Bad Request";
LABEL_438:
v20 = "Can't parse request.";
goto LABEL_556;
}
*v12 = 0;
path = (v12 + 1);
if ( strstr(v12 + 1, "ptimeout.cgi") )
{
if ( !dword_42C870 )
{
v14 = getppid();
kill(v14, 2);
}
v15 = path;
path = v15 + strspn(path, " \t\n\r");
v16 = strpbrk(path, " \t\n\r");
dword_42C88C = v16;
if ( v16 )
{
*v16 = 0;
dword_42C88C = (v16 + 1);
v17 = 401;
v18 = "Unauthorized";
v19 = "";
v20 = "Authorization required.";
goto LABEL_556;
}
goto LABEL_45;
}
while ( 1 )
{
v35 = sub_405E10(v13);
if ( !v35 || !*v35 )
break;
if ( !strncasecmp(v35, "Authorization:", 0xEu) )
{
authorization = &v35[strspn(v35 + 14, " \t") + 14];
}
else if ( !strncasecmp(v35, "Content-Length:", 0xFu) )
{
v21 = v35 + 15;
v22 = strspn(v21, " \t");
dword_42C8A8 = atol(&v21[v22]);
}
else if ( !strncasecmp(v35, "Content-Type:", 0xDu) )
{
dword_42C8A4 = &v35[strspn(v35 + 13, " \t") + 13];
}
else if ( !strncasecmp(v35, "Cookie:", 7u) )
{
dword_42C8AC = &v35[strspn(v35 + 7, " \t") + 7];
dword_42C8D4 = 1;
}
else if ( !strncasecmp(v35, "Host:", 5u) )
{
v23 = &v35[strspn(v35 + 5, " \t") + 5];
host = v23;
if ( strchr(v23, 47) || *v23 == 46 )
goto LABEL_45;
}
else if ( !strncasecmp(v35, "If-Modified-Since:", 0x12u) )
{
v24 = v35 + 18;
v25 = strspn(v24, " \t");
dword_42C8B0 = tdate_parse(&v24[v25]);
}
else
{
if ( !strncasecmp(v35, "Referer:", 8u) )
{
v26 = v35 + 8;
goto LABEL_52;
}
if ( !strncasecmp(v35, "Referrer:", 9u) )
{
v26 = v35 + 9;
LABEL_52:
dword_42C8B4 = &v26[strspn(v26, " \t")];
}
else if ( !strncasecmp(v35, "User-Agent:", 0xBu) )
{
dword_42C8B8 = &v35[strspn(v35 + 11, " \t") + 11];
}
else
{
v27 = strncasecmp(v35, "Accept-Language:", 0x10u);
v28 = v35;
if ( v27 )
{
v29 = v35 + 11;
if ( !strncasecmp(v28, "SOAPAction:", 0xBu) )
{
v30 = strspn(v29, " \t");
v31 = strcasestr(&v29[v30], "urn:NETGEAR-ROUTER:service:");
v13 = (v31 + 27);
if ( v31 )
{
for ( i = 0; ; ++i )
{
v33 = *v13;
if ( v33 == 58 )
break;
byte_42C8D8[i] = v33;
++v13;
}
v34 = strchr(v13, 35);
if ( v34 && v34[1] )
snprintf(&byte_42C958, 0x80u, "%s", v34 + 1);
byte_42C8D8[i] = 0;
dword_42C9D8 = 1;
}
}
}
else
{
dword_42C8BC = &v35[strspn(v35 + 16, " \t") + 16];
}
}
}
}
v36 = nvram_get("fw_local_force_https");
if ( !v36 )
v36 = "";
if ( *v36 == '1' && !do_ssl && !path_exist_in_exception_list(path, off_42AEA0, v11) )// 添加了 HTTPS 支持
{
LOBYTE(v230[0].sa_family) = 0;
memset(&v230[0].sa_family + 1, 0, 0x7Fu);
strlcpy(v230, path, 128);
v37 = v230 + strspn(v230, " \t\n\r");
*strpbrk(v37, " \t\n\r") = 0;
v38 = dword_42C88C;
if ( !dword_42C88C )
v38 = "HTTP/1.1";
dword_42C88C = v38;
snprintf(&v225, 0x9Cu, "Location: https://%s%s", host, v37);
v17 = 302;
v19 = &v225;
v20 = "";
v18 = "Found";
goto LABEL_556;
}
if ( host )
{
v39 = nvram_get("config_state");
if ( !v39 )
v39 = "";
if ( *v39 == 98 )
goto LABEL_581;
v40 = nvram_get("config_state");
if ( !v40 )
v40 = "";
if ( *v40 == 99 )
{
LABEL_581:
if ( is_captive_detecting(host, dword_42C8B8) )
{
dword_42C9DC = 1;
dword_42C88C = strpbrk(path, " \t\n\r");
v17 = 200;
v19 = "";
v18 = "OK";
v20 = "Success";
goto LABEL_556;
}
}
}
if ( !host && dword_42C9D8 == 1 )
host = "www.routerlogin.com";
is_usb_session = usb_session_check();
v41 = host;
v42 = nvram_get("lan_ipaddr");
v43 = v41;
v44 = 1;
if ( strcmp(v43, v42) )
v44 = strstr(host, "routerlogin") != 0;
if ( *nvram_get("http_server_wan_enable") == 49 && *nvram_get("fw_remote") == 48 )
{
v45 = nvram_get("wifi_ap_mode");
if ( !v45 )
v45 = "";
if ( *v45 == 49 )
{
if ( v44 || (v235 = host, v46 = getIPAddress("group1"), !strcmp(v235, v46)) )
v44 = 1;
}
else if ( !(v44 | is_usb_session) )
{
v44 = 0;
nvram_get("config_state");
}
}
if ( *nvram_get("http_server_wan_enable") == 48
&& *nvram_get("fw_remote") == 49
&& *nvram_get("config_state") == 115
&& is_usb_session
&& !v44 )
{
system("/bin/echo drop request usb > /dev/console");
v1 = 1;
goto LABEL_106;
}
if ( is_usb_session )
{
dword_42C870 = 0;
if ( port == 443 )
{
v47 = nvram_get("http_server_wan_enable");
if ( !v47 )
v47 = "";
if ( atoi(v47) == 1 )
{
v48 = nvram_get(&unk_416A20);
if ( !v48 )
v48 = "";
if ( atoi(v48) == 443 )
strlcpy(remote_ip, current_remote_ip, 48);
}
}
}
v49 = check_valid_request();
v17 = 403;
if ( !v49 )
{
v18 = "Forbidden";
v19 = "";
v20 = "URL is illegal.";
goto LABEL_556;
}
if ( strstr(path, "setupwizard.cgi") )
dword_42C9D8 = 1;
if ( dword_42C9D8 == 1 && !check_lan_guest() )
{
system("/bin/echo genie from wan, drop request now > /dev/console");
v1 = 0;
goto LABEL_106;
}
if ( dword_42C9D8 == 1 )
{
system("/bin/echo it is for setupwizard! >> /tmp/sw.log");
strcpy(byte_42C9E0, "/setupwizard.cgi HTTP/1.1\r\n");
path = byte_42C9E0;
if ( dword_42C8D4 == 1 )
{
dword_42CBE0 = 0;
dword_42CBE4 = 0;
dword_42CBE8 = 0;
dword_42CBEC = 0;
byte_42CBF0 = 0;
v50 = strchr(dword_42C8AC, 61);
if ( v50 )
strlcpy(&dword_42CBE0, v50 + 1, 17);
}
}
else
{
if ( !access("/tmp/dnshj.out", 0) && (!strstr(host, "routerlogin") || !strncmp(path, "/ ", 2u)) )
{
v51 = dword_42B664;
if ( !dword_42B664 )
v51 = "indexdnshj.htm";
snprintf(byte_42C9E0, 0x200u, "/ca/setup.cgi?next_file=%s HTTP/1.1\r\n", v51);
path = byte_42C9E0;
}
if ( access("/tmp/blank_state.out", 0) )
{
if ( !access("/tmp/tm_already_warning", 0) )
unlink("/tmp/tm_already_warning");
}
else
{
v52 = sub_405EE4(1);
if ( !strcasecmp(v11, v52) )
{
v53 = path;
if ( strstr(path, ".htm") || !strncmp(v53, "/ HTTP", 6u) )
{
v235 = host;
v54 = nvram_get("lan_ipaddr");
v55 = strcmp(v235, v54);
haystack = 1;
if ( v55 )
haystack = (strstr(host, "routerlogin") != 0);
nvram_get("tm_action_internet");
v56 = path;
v232 = strstr(path, "traffic_status.htm");
if ( !haystack || (v57 = strstr(v56, "_h.htm") != 0, access("/tmp/tm_already_warning", 0)) && !v57 )
{
strcpy(byte_42C9E0, "/ HTTP/1.1\r\n");
if ( !v232 )
{
v58 = fopen64("/tmp/blank_state.out", "r");
v59 = v58;
if ( v58 )
{
if ( fgets(v230, 99, v58) && (v60 = strstr(v230, "htm")) != 0 )
{
v60[3] = 0;
snprintf(byte_42C9E0, 0x200u, "/setup.cgi?next_file=%s HTTP/1.1\r\n", v230);
if ( access("/tmp/tm_block_internet", 0) )
{
system("/usr/sbin/rc dnshj stop");
}
else
{
v235 = &loc_410000;
if ( access("/tmp/tm_already_warning", 0) )
{
v61 = fopen64(v235 + 27444, "w+");
if ( v61 )
fclose(v61);
}
}
path = byte_42C9E0;
dword_42A248 = 0;
}
else if ( !strstr(v230, "lan_wan_conflict") && !haystack )
{
snprintf(byte_42C9E0, 0x200u, "/setup.cgi?next_file=%s HTTP/1.1\r\n", "alert.htm");
path = byte_42C9E0;
}
fclose(v59);
dword_42C870 = 0;
}
}
}
}
}
}
}
if ( access("/tmp/lan_ip_auto_changed", 0) )
{
LABEL_169:
if ( !access("/tmp/conflict_warning", 0) && strstr(path, "settings.jpg") )
{
system("/bin/touch /tmp/stop_conflict_warning");
unlink("/tmp/conflict_warning");
}
if ( !access("/tmp/conflict_warning", 0) )
{
v65 = get_uptime("/tmp/conflict_warning");
src = v65;
v66 = get_uptime("/proc/uptime");
if ( HIDWORD(v66) - HIDWORD(v65) != v66 < src || (v66 - src) >= 3 )
{
unlink("/tmp/conflict_warning");
unlink("/tmp/lan_ip_auto_changed");
unlink("/tmp/stop_conflict_warning");
system("/usr/sbin/rc dnshj stop");
}
}
}
else
{
v62 = dword_42C8B8;
if ( !strstr(dword_42C8B8, "Genie") && !strstr(v62, "LANWizard") )
{
v63 = sub_405EE4(1);
if ( !strcasecmp(v11, v63) )
{
v64 = path;
if ( !strstr(path, "error-tab-rec.htm")
&& (strstr(v64, ".htm") || !strncmp(v64, "/ HTTP", 6u) || strstr(v64, ".aspx")) )
{
if ( access("/tmp/conflict_warning", 0) )
{
strlcpy(byte_42C9E0, "/setup.cgi?next_file=BRS_wanlan_conflict.html HTTP/1.1\r\n", 512);
path = byte_42C9E0;
system("/bin/cp /proc/uptime /tmp/conflict_warning");
}
}
}
dword_42A248 = 0;
goto LABEL_169;
}
}
if ( access("/tmp/brs_hijack.out", 0) )
goto LABEL_235;
v67 = getIPAddress("group1");
v68 = host;
if ( !strcmp(host, "www.msftncsi.com") && strstr(path, "ncsi.txt")
|| !strcmp(v68, "www.msftconnecttest.com") && strstr(path, "connecttest.txt") )
{
v17 = 404;
dword_42C88C = "HTTP/1.0";
v18 = &unk_415C74;
v19 = "";
LABEL_546:
v20 = "File not found.";
goto LABEL_556;
}
v69 = socket(2, 3, 255);
if ( v69 == -1 )
return (perror)("socket creating failed");
v71 = nvram_get("wan_ifname");
strlcpy(v229, v71, 16);
if ( ioctl(v69, 0x8915u, v229) )
{
v80 = nvram_get("wifi_ap_mode");
if ( !v80 )
v80 = "";
v81 = 0;
if ( *v80 )
{
v81 = 1;
if ( strcmp(host, v67) )
{
v82 = nvram_get("wifi_ap_mode");
if ( !v82 )
v82 = "";
v81 = 0;
if ( atoi(v82) )
{
v83 = host;
v84 = nvram_get("wifi_ap_name");
if ( !v84 )
v84 = "";
v81 = strcasestr(v83, v84) != 0;
}
}
}
v85 = host;
v86 = nvram_get("lan_ipaddr");
v87 = v85;
v78 = 1;
if ( strcmp(v87, v86) && !strstr(host, "routerlogin") )
v78 = v81;
}
else
{
v72 = inet_ntoa(v229[5]);
v73 = strdup(v72);
v74 = host;
v76 = v73;
v75 = nvram_get("lan_ipaddr");
v77 = v74;
v78 = 1;
if ( strcmp(v77, v75) )
{
v79 = host;
if ( !strstr(host, "routerlogin") )
v78 = strstr(v79, v76) != 0;
}
}
v88 = sub_405EE4(1);
if ( strcasecmp(v11, v88)
|| (v89 = path, strstr(path, "BRS_"))
|| strstr(v89, "debug.htm")
|| strstr(v89, "currentsetting")
|| strstr(v89, "POT.htm")
|| strstr(v89, "sso")
|| strstr(v89, "POT")
|| !access("/tmp/wizard_vlan", 0)
|| !access("/tmp/conflict_warning", 0) )
{
LABEL_233:
if ( !v78 )
goto LABEL_234;
goto LABEL_235;
}
if ( v78 && !need_fakepath(path) )
goto LABEL_235;
if ( access("/tmp/brs_gui_hijack", 0) )
{
if ( v78 )
v95 = "App.html";
else
v95 = "BRS_hijack_index.htm";
snprintf(byte_42C9E0, 0x200u, "/setup.cgi?next_file=%s HTTP/1.1", v95);
path = byte_42C9E0;
goto LABEL_233;
}
if ( !v78 )
{
v90 = nvram_get("mandate_sso");
if ( !v90 )
v90 = "";
if ( *v90 != 49 )
goto LABEL_227;
v91 = nvram_get("config_state");
if ( !v91 )
v91 = "";
if ( *v91 != 99 )
goto LABEL_227;
v92 = nvram_get("sso_first_time");
if ( !v92 )
v92 = "";
if ( *v92 != 48 )
goto LABEL_227;
v93 = nvram_get("RAE_ssoGuiRegStatus");
if ( !v93 )
v93 = "";
if ( strcmp(v93, "InternetNA") )
v94 = "BRS_sso_hijack.html";
else
LABEL_227:
v94 = "BRS_hijack_success.htm";
sprintf(byte_42C9E0, "/setup.cgi?next_file=%s HTTP/1.1", v94);
path = byte_42C9E0;
LABEL_234:
dword_42A248 = 0;
}
LABEL_235:
v96 = nvram_get("config_state");
if ( !v96 )
v96 = "";
if ( *v96 == 98 )
goto LABEL_241;
v97 = nvram_get("need_not_login");
if ( !v97 )
v97 = "";
if ( *v97 == 49 )
{
LABEL_241:
nvram_set("need_not_login", "0");
nvram_set("start_in_blankstate", "1");
}
if ( path_exist(path, off_42AEC4, v11) )
goto LABEL_250;
v98 = path;
if ( strstr(path, "htpwd_recovery.cgi") )
{
v99 = sub_405EE4(3);
if ( !strcasecmp(v11, v99) )
goto LABEL_250;
}
if ( strstr(v98, "PNPX_GetShareFolderList") )
goto LABEL_250;
v100 = nvram_get("config_state");
if ( !v100 )
v100 = "";
if ( *v100 == 99 && strstr(path, "sso") )
{
LABEL_250:
dword_42C870 = 0;
dword_42A248 = 0;
if ( strstr(path, "currentsetting.htm") )
dword_42C9D8 = 1;
}
v101 = off_42AEC4;
v102 = 0;
while ( *v101 )
{
if ( strstr(path, *v101) )
v102 = 1;
++v101;
}
v103 = path;
if ( strstr(path, "sso.html") && !strstr(v103, "?token=") && !strstr(v103, "?error_code=2200") )
{
v104 = nvram_get("sso_from_internet");
if ( !v104 )
v104 = "";
if ( *v104 == 49 )
{
v229[0] = 0;
LOBYTE(v229[1]) = 0;
v105 = nvram_get("sso_fail_times");
if ( !v105 )
v105 = "";
v106 = atoi(v105) + 1;
nvram_set("RAE_ssoGuiRegStatus", "Failed");
if ( v106 < 3 )
{
sprintf(v229, "%d", v106);
v107 = v229;
}
else
{
nvram_set("sso_skip", "1");
v107 = "0";
}
nvram_set("sso_fail_times", v107);
nvram_set("sso_from_internet", "0");
nvram_commit();
v108 = dword_42C88C;
if ( !dword_42C88C )
v108 = "HTTP/1.1";
dword_42C88C = v108;
if ( v106 < 3 )
{
optlen = getpid();
if ( v106 == 1 )
snprintf(v230, 0x64u, "Location: setup.cgi?next_file=%s&timestamp=%d", "BRS_sso_fail.html", optlen);
else
snprintf(v230, 0x64u, "Location: setup.cgi?next_file=%s&timestamp=%d", "BRS_sso_fail_msg.html", optlen);
}
else
{
optlena = getpid();
snprintf(v230, 0x64u, "Location: setup.cgi?next_file=%s&timestamp=%d", "BRS_sso_status.html", optlena);
}
LABEL_335:
v17 = 302;
v19 = v230;
v18 = "Found";
v20 = "";
goto LABEL_556;
}
}
v109 = path;
if ( strstr(path, "?error_code=2200") )
{
v110 = sub_405EE4(1);
if ( !strcasecmp(v11, v110)
&& !v102
&& !strstr(v109, ".gif")
&& !strstr(v109, ".css")
&& !strstr(v109, ".js")
&& !strstr(v109, ".xml")
&& !strstr(v109, ".png")
&& !strstr(v109, ".jpg")
&& !dword_42C9D8 )
{
nvram_set("RAE_ssoGuiRegStatus", "Already register by other SSO");
v111 = nvram_get("sso_first_time");
if ( !v111 )
v111 = "";
v112 = "sso_first_time";
if ( *v111 == 48 )
{
v113 = "1";
goto LABEL_322;
}
goto LABEL_323;
}
}
if ( strstr(v109, "?signature=") )
{
v114 = sub_405EE4(1);
if ( !strcasecmp(v11, v114)
&& !v102
&& !strstr(v109, ".gif")
&& !strstr(v109, ".css")
&& !strstr(v109, ".js")
&& !strstr(v109, ".xml")
&& !strstr(v109, ".png")
&& !strstr(v109, ".jpg")
&& !dword_42C9D8 )
{
v225 = 0;
memset(v226, 0, sizeof(v226));
memset(v229, 0, 0x40u);
sc_get_sn(&v225, 43);
v226[12] = 0;
v115 = strstr(path, "?signature=");
sscanf(v115 + 11, "%s", v229); // maybe vuln
if ( isProductRegistered(&v225, v229) == 1 )
{
nvram_set("sso_first_time", "1");
v116 = "Yes";
}
else
{
nvram_set("sso_first_time", "0");
v116 = "No";
}
nvram_set("RAE_devRegisterStatus", v116);
nvram_commit();
system("/usr/bin/killall -SIGUSR1 sso_deamon");
v117 = dword_42C88C;
if ( !dword_42C88C )
v117 = "HTTP/1.1";
dword_42C88C = v117;
snprintf(v230, 0x64u, "Location: setup.cgi?next_file=%s", "index.htm");
v17 = 302;
v19 = v230;
v18 = "Found";
goto LABEL_427;
}
}
if ( strstr(v109, "?token=") )
{
v118 = sub_405EE4(1);
if ( !strcasecmp(v11, v118)
&& !v102
&& !strstr(v109, ".gif")
&& !strstr(v109, ".css")
&& !strstr(v109, ".js")
&& !strstr(v109, ".xml")
&& !strstr(v109, ".png")
&& !strstr(v109, ".jpg")
&& !dword_42C9D8 )
{
v225 = 0;
memset(v226, 0, sizeof(v226));
memset(v228, 0, 0x200u);
v229[0] = 0;
v229[1] = 0;
v229[2] = 0;
v229[3] = 0;
LOBYTE(v229[4]) = 0;
memset(v227, 0, sizeof(v227));
sc_get_sn(&v225, 43);
v226[12] = 0;
v119 = nvram_get("sso_cur_sessionId");
if ( !v119 )
v119 = "";
snprintf(v229, 0x11u, "%s", v119);
v120 = strstr(path, "?token=");
sscanf(v120 + 7, "%s", v228);
v121 = nvram_get("sso_first_time");
if ( !v121 )
v121 = "";
if ( *v121 == 48 )
nvram_set("sso_first_time", "1");
v112 = "RAE_ssoGuiRegStatus";
v113 = "Success";
LABEL_322:
nvram_set(v112, v113);
LABEL_323:
nvram_set("sso_from_internet", "0");
nvram_commit();
v122 = dword_42C88C;
if ( !dword_42C88C )
v122 = "HTTP/1.1";
dword_42C88C = v122;
v123 = nvram_get("config_state");
if ( !v123 )
v123 = "";
if ( *v123 == 98 )
{
snprintf(v230, 0x64u, "Location: setup.cgi?next_file=%s", "BRS_sso_success.html");
}
else
{
v124 = nvram_get("config_state");
if ( !v124 )
v124 = "";
if ( *v124 == 99 )
v125 = "BRS_netgear_success.html";
else
v125 = "index.htm";
snprintf(v230, 0x64u, "Location: setup.cgi?next_file=%s", v125);
}
goto LABEL_335;
}
}
v126 = nvram_get("config_state");
if ( !v126 )
v126 = "";
if ( *v126 != 98 )
{
v127 = nvram_get("sso_skip");
if ( !v127 )
v127 = "";
if ( *v127 == 48 )
{
v128 = nvram_get("sso_first_time");
if ( !v128 )
v128 = "";
if ( *v128 == 48 )
{
v129 = nvram_get("internet_ok");
if ( !v129 )
v129 = "";
if ( *v129 == 49 )
{
v130 = nvram_get("mandate_sso");
if ( !v130 )
v130 = "";
if ( *v130 == 49 && !do_ssl )
{
v131 = sub_405EE4(1);
if ( !strcasecmp(v11, v131) && !v102 )
{
v132 = path;
if ( !strstr(path, ".gif")
&& !strstr(v132, ".css")
&& !strstr(v132, ".js")
&& !strstr(v132, ".xml")
&& !strstr(v132, ".png")
&& !strstr(v132, ".jpg")
&& !strstr(v132, ".ico")
&& !strstr(v132, "sso_wait.html")
&& !strstr(v132, "BRS_sso_hijack.html")
&& !strstr(v132, "sso_fail")
&& !dword_42C9D8
&& !strstr(v132, "PWD_secure.htm") )
{
v133 = dword_42C88C;
if ( !dword_42C88C )
v133 = "HTTP/1.1";
dword_42C88C = v133;
snprintf(v229, 0x64u, "Location:setup.cgi?next_file=%s", "sso_wait.html");
LABEL_426:
v17 = 302;
v19 = v229;
v18 = "Found";
LABEL_427:
v20 = "";
goto LABEL_556;
}
}
}
}
}
}
}
v134 = nvram_get("openvpn_hijack");
if ( !v134 )
v134 = "";
if ( *v134 == 49 && !do_ssl )
{
v135 = sub_405EE4(1);
if ( !strcasecmp(v11, v135) && !v102 )
{
v136 = path;
if ( !strstr(path, ".gif")
&& !strstr(v136, ".css")
&& !strstr(v136, ".js")
&& !strstr(v136, ".xml")
&& !strstr(v136, ".png")
&& !strstr(v136, ".jpg")
&& !dword_42C9D8 )
{
v137 = dword_42C88C;
if ( !dword_42C88C )
v137 = "HTTP/1.1";
dword_42C88C = v137;
snprintf(
v229,
0x64u,
"Location: http://www.routerlogin.net/setup.cgi?next_file=%s",
"openvpn_confirm_update.htm");
goto LABEL_426;
}
}
}
v138 = nvram_get("tc_from_old");
if ( !v138 )
v138 = "";
if ( *v138 == 49 && !do_ssl )
{
v139 = sub_405EE4(1);
if ( !strcasecmp(v11, v139) && !v102 )
{
v140 = path;
if ( !strstr(path, ".gif")
&& !strstr(v140, ".css")
&& !strstr(v140, ".js")
&& !strstr(v140, ".xml")
&& !strstr(v140, ".png")
&& !strstr(v140, ".jpg")
&& !dword_42C9D8 )
{
v141 = dword_42C88C;
if ( !dword_42C88C )
v141 = "HTTP/1.1";
dword_42C88C = v141;
snprintf(v229, 0x64u, "Location: %s", "tc_exist_unit_hijack.htm");
goto LABEL_426;
}
}
}
v142 = nvram_get("weak_password_check");
if ( !v142 )
v142 = "";
if ( *v142 == 49 && access("/tmp/no_security_page", 0) )
{
v143 = nvram_get("user_ignore_weak_pw");
if ( !v143 )
v143 = "";
if ( *v143 != 49 )
{
v144 = nvram_get("config_state");
if ( !v144 )
v144 = "";
if ( *v144 != 98 )
{
v145 = path;
if ( !strstr(path, "PWD_secure.htm") && !do_ssl )
{
v146 = sub_405EE4(1);
if ( !strcasecmp(v11, v146)
&& !v102
&& !strstr(v145, ".gif")
&& !strstr(v145, ".css")
&& !strstr(v145, ".js")
&& !strstr(v145, ".xml")
&& !strstr(v145, ".png")
&& !strstr(v145, ".jpg")
&& !strstr(v145, "top.htm")
&& !dword_42C9D8 )
{
v147 = dword_42C88C;
if ( !dword_42C88C )
v147 = "HTTP/1.1";
dword_42C88C = v147;
snprintf(v229, 0x64u, "Location: %s", "PWD_secure.htm");
goto LABEL_426;
}
}
}
}
}
v148 = path;
if ( !strstr(path, ".cgi") && strstr(v148, ".htm") && !strstr(v148, "shares") )
{
v149 = strlen(v148);
if ( v149 >= 0x1E2 )
{
v17 = 404;
v18 = &unk_415C74;
v19 = "";
v20 = "No such file.";
goto LABEL_556;
}
strlcpy(byte_42C9E0, v148, v149 - 8);
v150 = strrchr(byte_42C9E0, 47);
strlcpy(byte_42CBF4, byte_42C9E0, v150 - byte_42C9E0);
v151 = path;
if ( *path == 47 )
path = v151 + strlen(byte_42CBF4) + 1;
snprintf(byte_42C9E0, 0x200u, "%s/setup.cgi?next_file=%s", byte_42CBF4, path);
path = byte_42C9E0;
}
v152 = path;
path = v152 + strspn(path, " \t\n\r");
v153 = strpbrk(path, " \t\n\r");
dword_42C88C = v153;
v17 = 400;
if ( !v153 )
{
v18 = "Bad Request";
v19 = "";
goto LABEL_438;
}
*v153 = 0;
dword_42C88C = (v153 + 1);
v154 = strchr(path, 63);
dword_42C888 = v154;
if ( v154 )
{
*v154 = 0;
v155 = v154 + 1;
}
else
{
v155 = "";
}
dword_42C888 = v155;
v156 = sub_405EE4(1);
if ( !strcasecmp(v11, v156) )
{
v157 = 1;
}
else
{
v158 = sub_405EE4(2);
if ( !strcasecmp(v11, v158) )
{
v157 = 2;
}
else
{
v159 = sub_405EE4(3);
v160 = strcasecmp(v11, v159) != 0;
v157 = 3;
if ( v160 )
{
v17 = 501;
v18 = "Not Implemented";
v19 = "";
v20 = "That method is not implemented.";
goto LABEL_556;
}
}
}
v161 = path;
dword_42C87C = v157;
if ( strstr(path, "%00") || (sub_406AF0(v161, v161), v162 = path, *path != 47) )
{
v17 = 400;
v18 = "Bad Request";
v19 = "";
v20 = "Bad filename.";
goto LABEL_556;
}
v163 = path + 1;
dword_42C880 = path + 1;
while ( 1 )
{
v166 = strstr(v162 + 1, "//");
v167 = v166;
if ( !v166 )
break;
for ( j = v166 + 2; *j == 47; ++j )
;
src = j;
v165 = strlen(j);
memmove(v167 + 1, src, v165 + 1);
}
while ( !strncmp(v162 + 1, "./", 2u) )
{
v168 = strlen(v162 + 3);
memmove((v162 + 1), v162 + 3, v168 + 1);
}
while ( 1 )
{
v170 = strstr(v162 + 1, "/./");
v171 = v170;
if ( !v170 )
break;
src = v170 + 2;
v169 = strlen(v170 + 2);
memmove(v171, src, v169 + 1);
}
while ( 2 )
{
if ( !strncmp(v162 + 1, "../", 3u) )
{
v172 = strlen(v162 + 4);
v173 = (v162 + 1);
v174 = (v162 + 4);
LABEL_473:
memmove(v173, v174, v172 + 1);
continue;
}
break;
}
v175 = strstr(v162 + 1, "/../");
v176 = v175 - 1;
if ( v175 )
{
for ( k = v176 < v163; !k && *v176 != 47; k = v176 < v163 )
--v176;
v235 = v176;
src = v175 + 4;
v172 = strlen(v175 + 4);
v174 = src;
v173 = (v235 + 1);
goto LABEL_473;
}
LABEL_478:
v179 = strlen(v162 + 1);
if ( v179 >= 4 )
{
v178 = (v163 + v179 - 3 - 1);
if ( !strcmp((v163 + v179 - 3), "/..") )
{
while ( v178 >= v163 )
{
if ( *v178 == 47 )
{
*v178 = 0;
goto LABEL_478;
}
--v178;
}
}
}
if ( !v162[1] )
dword_42C880 = "./";
v180 = dword_42C880;
v181 = *dword_42C880;
if ( v181 == 47 || v181 == 46 && *(dword_42C880 + 1) == 46 && (!*(dword_42C880 + 2) || *(dword_42C880 + 2) == 47) )
{
v17 = 400;
v18 = "Bad Request";
v19 = "";
v20 = "Illegal filename.";
goto LABEL_556;
}
if ( dword_42B620 )
{
v182 = host;
if ( !host )
{
v222 = 128;
if ( getsockname(dword_42C86C, v230, &v222) >= 0 )
v182 = ntoa(v230);
else
v182 = "UNKNOWN_HOST";
}
dword_42C8A0 = v182;
v183 = v182;
for ( l = dword_42C8A0; ; ++l )
{
v185 = *l;
v160 = v185 != 0;
v186 = 2 * v185;
if ( !v160 )
break;
if ( (*(_ctype_b + v186) & 1) != 0 )
*l = *(_ctype_tolower + v186);
}
snprintf(byte_42CDF4, 0x2710u, "%s/%s", v183, v180);
dword_42C880 = byte_42CDF4;
}
signal(14, sub_408BE0);
alarm(0x12Cu);
v223 = stat64(dword_42C880, &sb);
if ( v223 < 0 )
{
v187 = dword_42C880;
for ( dword_42C884 = v187 + strlen(dword_42C880); ; *dword_42C884 = 47 )
{
v188 = dword_42C880;
v189 = dword_42C884;
do
{
if ( dword_42C880 >= --v189 )
{
dword_42C884 = 0;
v190 = -1;
goto LABEL_508;
}
}
while ( *v189 != 47 );
dword_42C884 = v189;
*v189 = 0;
v190 = stat64(v188, &sb);
if ( v190 >= 0 )
break;
}
++dword_42C884;
LABEL_508:
v223 = v190;
}
if ( v223 < 0 )
goto LABEL_545;
if ( (!dword_42C8B4 || !*dword_42C8B4) && dword_42C880 )
{
v229[0] = 0;
v229[1] = 0;
v229[2] = 0;
v229[3] = 0;
v229[4] = 0;
v229[5] = 0;
v191 = nvram_get("product_name");
if ( !v191 )
v191 = "";
snprintf(v229, 0x18u, "NETGEAR_%s.cfg", v191);
v192 = strcmp(dword_42C880, v229);
v17 = 403;
if ( !v192 )
{
v18 = "Forbidden";
v19 = "";
v20 = "HTML is illegal.";
goto LABEL_556;
}
}
v193 = dword_42C880;
v194 = v193 + strlen(dword_42C880);
if ( (dword_433B70 & 0xF000) == 0x4000 )
{
if ( *(v194 - 1) != 47 && !dword_42C884 )
{
if ( *dword_42C888 )
snprintf(v230, 0x2710u, "Location: %s/?%s", path, dword_42C888);
else
snprintf(v230, 0x2710u, "Location: %s/", path);
v17 = 302;
v18 = "Found";
v19 = v230;
v20 = "Directories must end with a slash.";
goto LABEL_556;
}
v196 = v224;
while ( v196 != &v225 )
{
src = dword_42C880;
if ( !strcmp(dword_42C880, "./") )
snprintf(v229, 0x2710u, "%s", *v196);
else
snprintf(v229, 0x2710u, "%s%s", src, *v196);
if ( is_usb_session )
{
v196 += 4;
}
else
{
v196 += 4;
if ( stat64(v229, &sb) >= 0 )
{
dword_42C880 = v229;
goto LABEL_535;
}
}
}
if ( !access("/tmp/http_disable_lan", 0) )
{
v198 = nvram_get("lan_ipaddr");
v199 = inet_network(v198);
v200 = nvram_get("lan_netmask");
v202 = inet_network(v200);
v201 = inet_network(remote_ip);
v17 = 503;
if ( ((v201 ^ v199) & v202) == 0 )
{
v18 = "The Share is not available";
LABEL_543:
v19 = "";
v20 = "";
goto LABEL_556;
}
}
v203 = sc_usb_mounted(v17);
v17 = 503;
if ( !v203 )
{
v18 = "No Shares Available";
goto LABEL_543;
}
if ( !dword_42C884 )
{
if ( is_usb_session )
usb_auth_check(dword_42C880);
else
maybe_login(dword_42C880);
sub_4085DC();
if ( !is_usb_session || (v204 = is_readable(dword_42C880, ""), v17 = 403, v204) )
{
v232 = scandir64(dword_42C880, &v219, 0, &alphasort64);
if ( v232 >= 0 )
{
strlcpy(v228, dword_42C880, 769);
src = dword_42C880;
v222 = 0;
v206 = encode_buf(v228);
snprintf(
v230,
0x2710u,
"<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n"
"\n"
"<html>\n"
"\n"
" <head>\n"
" <meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\">\n"
" <title>Index of %s</title>\n"
" </head>\n"
"\n"
" <body bgcolor=\"#99cc99\" text=\"#000000\" link=\"#2020ff\" vlink=\"#4040cc\">\n"
" <h4>Index of %s</h4>\n"
" <pre>\n",
src,
v206);
sub_40627C(&v221, &v222, &v220, v230);
for ( m = 0; m != v232; ++m )
{
haystack = dword_42C880;
v208 = (*(v219 + 4 * m) + 19);
v233 = *(v219 + 4 * m);
snprintf(byte_431CF4, 0x7D0u, "%s/%s", dword_42C880, v208);
if ( !is_usb_session || is_readable(haystack, v208) )
{
v210 = lstat64(byte_431CF4, v227);
v209 = "";
if ( v210 >= 0 )
{
v211 = strcmp(v208, ".");
v209 = "";
if ( v211 )
{
if ( !is_usb_session
|| (v227[3] & 0xF000) != 40960
|| !*(v233 + 19)
|| (v212 = strstr(haystack, "shares/USB_Storage"), v209 = "", !v212)
&& (!strstr(haystack, "shares/") || (v213 = strstr(haystack, "_Drive"), v209 = "", !v213)) )
{
if ( !strcmp(v208, "..") )
{
v214 = strcmp(dword_42C880, "shares/");
v209 = "";
if ( v214 )
{
sub_4079B0(v208);
snprintf(byte_431CF4, 0x7D0u, "<A HREF=\"%s\">[To Parent Directory]</A>\n", byte_4324C4);
v209 = byte_431CF4;
}
}
else
{
v215 = localtime(&dword_433BA0);
strftime(&v225, 0x3Cu, "%A, %B %d, %Y %l:%M %p", v215);
sub_4079B0(v208);
v235 = &unk_430000;
strlcpy(&unk_4328AC, v208, 1531);
encode_buf(v235 + 10412);
snprintf(
byte_431CF4,
0x7D0u,
"%-40s %14lld <A HREF=\"%s\">%s</A>\n",
&v225,
v227[7],
byte_4324C4,
v235 + 10412);
v209 = byte_431CF4;
}
}
}
}
}
else
{
memset(byte_431CF4, 0, sizeof(byte_431CF4));
v209 = byte_431CF4;
}
sub_40627C(&v221, &v222, &v220, v209);
}
snprintf(
v230,
0x2710u,
" </pre>\n\n <hr>\n\n <address><a href=\"%s\">%s</a></address>\n \n </body>\n\n</html>\n",
"http://www.acme.com/software/mini_httpd/",
"mini_httpd/1.24 10May2016");
sub_40627C(&v221, &v222, &v220, v230);
sub_407BEC(200, "Ok", "", "", "text/html; charset=%s", optlen_4);
if ( dword_42C87C != 2 )
{
*(v221 + v220) = 0;
sub_4062F0(v221);
}
v197 = sub_407648;
goto LABEL_578;
}
v205 = ntoa(&client_addr);
syslog(6, "%.80s Directory \"%.80s\" is protected", v205, path);
v17 = 403;
v18 = "Forbidden";
v19 = "";
}
else
{
v19 = "";
v18 = "Forbidden";
}
v20 = "Directory is protected.";
LABEL_556:
send_error(v17, v18, v19, v20);
}
LABEL_545:
v17 = 404;
v18 = &unk_415C74;
v19 = "";
goto LABEL_546;
}
for ( n = (v194 - 1); *n == 47; --n )
*n = 0;
LABEL_535:
v197 = &sub_40A154;
LABEL_578:
v197();
return (SSL_free)(dword_42C8C0);
}

比较两份代码,主要逻辑变化不大,但是新版中添加了 SSO 相关逻辑,即单点登录,猜测官方通过引入单点登录的手段对漏洞进行修复。

通过分析代码,可以定位到处理 login 请求的函数是 0x407FC0 (1.2.0.74),关键片段如下

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
char *__fastcall maybe_login(int a1)
{
_BOOL4 v2; // $v0
void (__fastcall *v3)(const char *); // $t9
const char *v4; // $a0
char *result; // $v0
FILE *v6; // $s0
const char *v7; // $v0
int v8; // $a0
int v9; // $s1
FILE *v10; // $s1
FILE *v11; // $s1
FILE *v12; // $s1
int v13; // $v0
char *v14; // $v0
const char *v15; // $v0
const char *v16; // $s6
const char *v17; // $v0
const char *v18; // $v0
const char *v19; // $v0
FILE *v20; // $s1
FILE *v21; // $s1
int v22; // $v0
const char *v23; // $a0
char *v24; // $a1
const char *v25; // $a0
char *v26; // $s4
int v27; // $v0
const char *v28; // $v0
FILE *v29; // $s4
const char *v30; // $a3
char *v31; // $v0
char *v32; // $v0
const char *v33; // $fp
int v34; // $v0
int v35; // $v0
int v36; // $v0
int v37; // $a0
FILE *v38; // $s1
int v39; // $v0
int v40; // $v0
const char *v41; // $a0
char *v42; // $a1
const char *v43; // $a0
char *v44; // $s4
int v45; // $v0
struct sysinfo v46; // [sp+20h] [-238h] BYREF
char v47[504]; // [sp+60h] [-1F8h] BYREF

if ( currentsetting_flag != 1 )
{
// logic when currentsetting_flag != 1
}
v2 = check_lan_guest();
v3 = &system;
if ( !v2 )
{
v4 = "/bin/echo genie from wan, drop request > /dev/console";
goto LABEL_7;
}
system("/bin/echo genie from lan, ok > /dev/console");
result = strchr(current_remote_ip, 58);
if ( result )
{
system("/bin/echo genie ipv6, drop request > /dev/console");
v6 = fopen64("/dev/console", "a+");
if ( !v6 )
goto LABEL_8;
fprintf(v6, "[%s::%s():%d] ", "mini_httpd.c", "auth_check", 3487);
fprintf(v6, "current_remote_ip:%s\n", current_remote_ip);
v4 = v6;
v3 = &fclose;
LABEL_7:
v3(v4);
LABEL_8:
exit(0);
}
return result;
}

我们观察到 login 函数开头对一个名为 currentsetting_flag 的标志位进行判断,如果不等于 1,就执行正常的 login 逻辑,否则会跳过 login 逻辑。最后对访客的 IP 地址进行判断,如果访客来自于公网,会丢弃相关请求。

那如果某处代码能控制这个变量为 1,就能绕过 login 直接访问后台内容。

通过交叉引用,在 handle_login 函数中找到了为这个变量赋值的位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if ( path_exist(path, off_427E50, v14)
|| (v87 = path, strstr(path, "htpwd_recovery.cgi")) && (v88 = select_request_type(3), !strcasecmp(v14, v88))
|| strstr(v87, "PNPX_GetShareFolderList") )
{
multi_login_flag = 0;
login_or_not = 0;
if ( strstr(path, "currentsetting.htm") )
currentsetting_flag = 1;
}
v89 = off_427E50;
v90 = 0;
while ( *v89 )
{
if ( strstr(path, *v89) )
v90 = 1;
++v89;
}

第 8 行会将 currentsetting_flag 设为 1,从这里向前分析限制条件,要求我们发送的请求

1
2
3
1. 访问的 URL 位于 off_427E50 指向的列表中
2. 如果目标资源不在列表中,则需要 URL 中包含 htpwd_recovery.cgi 并且请求类型是 POST
3. 如果上面两个条件都不满足,则需要 URL 中包含 PNPX_GetShareFolderList

如果满足上面所述的条件,就会进入到 if 中,分别设置两个全局变量:multi_login_flag、login_or_not,并且如果 URL 中还包含 currentsetting.htm,就把 currentsetting_flag 设置成 1。

此外,maybe_login 函数只在 handle_request 函数中调用了一次,handle_request 函数中还调用了另一个比较关键的函数 execute_cgi。

httpd 只充当处理请求的角色,在确定了访问哪些接口之后,它会调用相应的 cgi 程序,execute_cgi 函数就负责解析和调用这些 cgi 程序。

在这个函数中还存在一些登录逻辑,相关代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
strlcpy(v101, dword_429734, 10000);
v0 = strrchr(v101, 47);
if ( v0 )
*v0 = 0;
else
strlcpy(v101, ".", 10000);
if ( is_usb_session )
{
usb_auth_check(v101);
}
else if ( login_or_not )
{
maybe_login(v101);
}

判断了 login_or_not 变量,如果不等于 0 就执行 login,同上,当构造满足特定要求的请求时,login_or_not 会被设置成 0,也能绕过这个逻辑。

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
if ( !login_or_not
|| currentsetting_flag
|| *v2 != 48
|| *v3 == 98
|| !authorization
|| !*authorization
|| !strncmp(path, "/cgi-bin/genie.cgi", 0x12u) )
{
if ( access("/tmp/dbg_sessionid", 0) )
goto LABEL_43;
v9 = fopen64("/dev/console", "a+");
if ( !v9 )
goto LABEL_43;
fprintf(v9, "[%s::%s():%d] ", "mini_httpd.c", "do_file", 2539);
fprintf(
v9,
"no need verify for no auth or soap or genie.cgi, %d, %d, %s, %s, %s\n",
login_or_not,
currentsetting_flag,
v2,
v3,
authorization);
v10 = v9;
goto LABEL_42;
}

上面这段代码判断多个变量的状态,和前一个判断 login_or_not 相同,有趣的是当满足条件进入 if,会打印

1
no need verify for no auth or soap or genie.cgi

某些接口确实不需要权限验证就能访问,但是在实现这项功能时使用了 strstr 而不是精确匹配,导致出现绕过的问题。

用某公网设备测试,AC2400 存在一个可以开启 debug 模式的接口,链接

1
/setup.cgi?todo=debug

默认情况下访问这个接口会得到 401

构造一个满足条件的 URL

1
/setup.cgi?todo=debug&x=currentsetting.htm

再次访问

可以看到成功访问了该接口,但可能是防火墙的原因,没法儿连接到 telnet。

还有一些可用的链接

1
2
3
4
5
6
7
8
9
10
11
12
13
# https://gist.github.com/Donearm/978555
# 请用本地设备测试

DEBUGURL = 'http://192.168.0.1/setup.cgi?todo=debug'
REBOOTURL = 'http://192.168.0.1/setup.cgi?next_file=diag.htm&todo=reboot'
#DISCONNECTURL = 'http://192.168.0.1/setup.cgi?todo=disconnect&this_file=st_poe.htm&next_file=st_poe.htm'
DISCONNECTURL = 'http://192.168.0.1/setup.cgi?todo=disconnect'
#CONNECTURL = 'http://192.168.0.1/setup.cgi?todo=connect&this_file=st_poe.htm&next_file=st_poe.htm'
CONNECTURL = 'http://192.168.0.1/setup.cgi?todo=connect'
STATTBLURL = 'http://192.168.0.1/setup.cgi?next_file=stattbl.htm'
LOGOUTURL = 'http://192.168.0.1/setup.cgi?todo=logout'
INTERVALURL = 'http://192.168.0.1/setup.cgi?next_file=interval.htm'
STATUSURL = 'http://192.168.0.1/setup.cgi?next_file=s_status.htm'

注:对于不同型号的设备,能够绕过验证的功能不完全一致,某些可以用于 GET 请求,另一些可能只对 POST 请求有效。某些可能只对 htm 页面有效,其它只对 cgi 有效。

新版的修复手段静态来看似乎是添加了单点登录,由于没有设备暂时无法验证新版固件的登录逻辑。

此外,NetGear 存在某些历史漏洞,也是登录验证绕过,触发方法是在 URL 中添加空字节或者添加 1.jpg 等字符串,参考链接:

1
2
https://github.com/zer0yu/CVE_Request/tree/master/netgear
https://www.zerodayinitiative.com/advisories/ZDI-19-866/

Command Injection

基本信息

官方发布信息:https://kb.netgear.com/000062641/Security-Advisory-for-Password-Recovery-Vulnerabilities-on-Some-Routers

披露信息:https://www.zerodayinitiative.com/advisories/ZDI-20-1423/

漏洞评分:6.8(Medium)

漏洞描述:NetGear 部分路由器存在命令注入漏洞,拥有后台权限的攻击者可以利用此漏洞实现任意命令执行。

漏洞分析

还是以 AC2400 为例,披露信息中提到命令注入发生的位置是 funjsq_access_token 参数,在解包目录中搜索包含这个字符串的文件

1
grep -r "funjsq_access_token"

可以找到名为 setup.cgi 的二进制程序,IDA 载入,找到字符串并交叉引用发现相关函数如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int __fastcall sub_407C80(int a1)
{
const char *v1; // $s0
const char *v2; // $a1
char v4; // [sp+18h] [-400h] BYREF
char v5[1023]; // [sp+19h] [-3FFh] BYREF

v1 = find_val(a1, "funjsq_access_token");
v4 = 0;
memset(v5, 0, sizeof(v5));
if ( v1 && strlen(v1) >= 6 )
{
COMMAND("/tmp/funjsq/bin/funjsq.sh login %s", v1);
v2 = "{ \"success\": \"1\" }";
}
else
{
v2 = "{ \"success\": \"0\" }";
}
strcpy(&v4, v2);
mime_header("text/html");
fputs(&v4, stdout);
return 0;
}

setup.cgi 主要负责实现后台的一些功能,某功能会用到参数 funjsq_access_token,在上面这个函数中解析出来之后直接带入函数 COMMAND (参数长度必须大于等于 6)。

经过查找,COMMAND 函数是 /lib/libscmisc.so 链接库导出的,相关代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int COMMAND(const char *a1, ...)
{
int v2; // $s0
int result; // $v0
char v4; // [sp+1Ch] [-404h] BYREF
char v5[1023]; // [sp+1Dh] [-403h] BYREF
va_list va; // [sp+42Ch] [+Ch] BYREF

va_start(va, a1);
v4 = 0;
memset(v5, 0, sizeof(v5));
vsnprintf(&v4, 0x400u, a1, va);
v2 = open("/etc/cmd_agent", 1);
result = 1;
if ( v2 >= 0 )
{
write(v2, &v4, 0x400u);
close(v2);
usleep(1u);
result = 0;
}
return result;
}

把传入的参数写入 cmd_agent,它也是一个二进制程序,位于 /usr/sbin 目录下。IDA 简单分析发现它会执行写入其中的命令,那么显然这里存在命令注入的问题。

新版本代码

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
int __fastcall sub_411840(int a1)
{
const char *v2; // $s0
FILE *v3; // $s0
const char *v4; // $v0
const char *v5; // $a1
char v7; // [sp+20h] [-404h] BYREF
char v8[1023]; // [sp+21h] [-403h] BYREF

v2 = find_val(a1, "funjsq_access_token");
v7 = 0;
memset(v8, 0, sizeof(v8));
if ( sub_4117D0(a1) )
{
v3 = fopen("/dev/console", "a+");
if ( v3 )
{
fprintf(v3, "[%s::%s():%d] ", "action.c", "funjsq_login", 11165);
fputs("wrong method\n", v3);
fclose(v3);
}
}
else if ( region_isPR(4980736) )
{
v4 = nvram_get("wiz_language");
if ( !v4 )
v4 = nptr;
if ( !strcmp(v4, "Chinese") && test_command_inject(v2) )
{
if ( !v2 )
goto LABEL_13;
if ( strstr(v2, "telneted") )
return 0;
if ( strlen(v2) >= 6 )
{
COMMAND("/tmp/funjsq/bin/funjsq.sh login %s", v2);
v5 = "{ \"success\": \"1\" }";
}
else
{
LABEL_13:
v5 = "{ \"success\": \"0\" }";
}
strcpy(&v7, v5);
mime_header("text/html");
fputs(&v7, stdout);
return 0;
}
}
return 0;
}

funjsq_access_token 参数主要是帆游加速器这个功能使用的,从新版代码来看,似乎是中国特供的功能,新版本中加入了对语言的判定,如果是中文才进行下一步操作。

另外引入了函数 test_command_inject 对参数过滤,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int __fastcall test_command_inject(const char *a1)
{
int v2; // $s2
FILE *v3; // $s0

if ( strstr(a1, "/bin") || strstr(a1, "/sbin") || (v2 = 1, strchr(a1, '`')) )
{
v3 = fopen("/dev/console", "a+");
v2 = 0;
if ( v3 )
{
fprintf(v3, "[%s::%s():%d] ", "other.c", "test_command_inject", 2495);
fprintf(v3, "Possible COMMAND injection detected:\"%s\"!\n", a1);
fclose(v3);
}
}
return v2;
}

要求参数中不能存在 /bin、/sbin、字符 ‘`’、字符串 telneted (从解压出来的固件中并没有发现 telneted 这个程序,似乎是开发人员多打了一个 e ?)。

静态来看这个漏洞并没有完全修复,虽然不能使用字符 ‘`’,但是依然可以用其他手段绕过。

可以结合以上两个漏洞实现无需身份验证的任意命令执行,手头暂时没有合适的设备调试,感兴趣的同学可以自己尝试构造一下利用脚本。

Buffer Overflow

基本信息

披露信息:暂无

漏洞分析

首先声明,我不确定这个漏洞能否触发,目前暂时没办法测试。

问题出现在新版本固件中(1.2.0.76),用 IDA 进行分析,定位到函数 handle_request,从第 979 行开始代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if ( strstr(v109, "?signature=") )
{
v114 = sub_405EE4(1);
if ( !strcasecmp(v11, v114)
&& !v102
&& !strstr(v109, ".gif")
&& !strstr(v109, ".css")
&& !strstr(v109, ".js")
&& !strstr(v109, ".xml")
&& !strstr(v109, ".png")
&& !strstr(v109, ".jpg")
&& !dword_42C9D8 )
{
v225 = 0;
memset(v226, 0, sizeof(v226));
memset(v229, 0, 0x40u);
sc_get_sn(&v225, 43);
v226[12] = 0;
v115 = strstr(path, "?signature=");
sscanf(v115 + 11, "%s", v229); // maybe vuln

如果传入的请求满足以下条件

1
2
3
1. URL 中包含 ?signature=
2. 请求类型是 GET
3. URL 中不包含 currentsetting.htm 以及上面写出的一些字符串

程序会先用 strstr 定位 ?signature= 的位置,然后跳过这个字符串,接着用 sscanf 函数将后续内容拷贝到变量 v229。

在拷贝的过程中没有判断源字符串长度,可能会导致溢出。不过 IDA 自动识别目的缓冲区大小为 2500 字节,能否传入这么长的 URL 暂时无法确定。

  • Title: NetGear AC2400 漏洞复现
  • Author: Catalpa
  • Created at : 2021-01-13 00:00:00
  • Updated at : 2024-10-17 08:22:26
  • Link: https://wzt.ac.cn/2021/01/13/AC2400_vuln/
  • License: This work is licensed under CC BY-NC-SA 4.0.