长亭百川云 - 文章详情

什么是域前置

域前置介绍

域名前置技术,亦称为域名伪装,是一种用于规避审查的网络技术,其核心功能在于隐藏真实的服务端点。该技术在应用层面上运作,允许用户通过HTTPS协议连接至被屏蔽的服务,同时在表面上看似与另一个完全不同的网站进行通信。

域前置工作原理

域名前置技术的运作原理主要依赖于内容分发网络(CDN)。通过配置A记录或AAAA记录,将网站域名指向服务器的公网IP地址,从而实现用户能够通过易于记忆的域名直接访问服务器上部署的网站,而无需依赖于难以记忆且缺乏直观标识的IP地址。CDN不仅能够加速域名的访问,而且在域名访问请求过程中,并不直接解析至IP地址,这为申请CDN加速服务的虚拟私人服务器(V-PS)提供了隐藏真实IP地址的效果。

CDN工作原理

内容分发网络(CDN)的工作机制如下:当用户尝试访问某个域名时,首先会向本地DNS服务器(LDNS)发起请求。如果LDNS服务器中存在缓存,则直接返回相应的IP地址给用户;若无缓存,则LDNS会向授权DNS服务器发起请求。授权DNS服务器解析域名后返回一个别名域名,随后请求被转发至公有云DNS调度系统,该系统负责分配最佳的节点IP地址。LDNS服务器会缓存此IP地址,用户随后根据该IP地址请求所需资源。通过这种方式,节点IP地址实际上隐藏了真实的IP地址。    

什么是云函数?

函数即服务(FaaS: Function as a Service)

函数即服务提供的是计算能力。原有的计算能力,无论是容器也好,虚拟机也好都承载在一定的操作系统之上,函数即服务把计算能力进行了进一步抽象。

后端及服务(BaaS: Backend as a Service)

后端即服务,比如对象存储,数据库应用,缓存服务,我们也可以称之为Serverless,因为这些服务也能够在云上提供开通即服务,开通即使用的能力。在使用这些产品时同样不需要关注它的服务器是什么样的,它的服务器部署在哪里,而是服务开通就可以使用了,后面的运维工作都交给了云,所以不用感知它的最底层服务器。

函数即服务(FaaS: Function as a Service)是指一种计算能力的提供方式。传统的计算能力,无论是通过容器还是虚拟机实现,均建立在特定的操作系统之上。而函数即服务则进一步抽象了这种计算能力。

后端即服务(BaaS: Backend as a Service)涉及的是一系列后端功能,例如对象存储、数据库应用和缓存服务等。这类服务亦可被称为无服务器(Serverless),因为它们能够在云平台上实现即开即用的服务模式。在使用这些服务时,用户无需关心服务器的具体配置、部署位置等底层细节,仅需开通服务即可开始使用。相应的运维工作由云服务提供商负责,因此用户无需直接感知到最底层的服务器架构。    

针对云函数、域前置如何反制?

常规手法

批量部署钓鱼马程序

通过客户端观察可见,部署后的IP地址会周期性地自动更迭(此为云函数的固有特性)。若一次性部署大量IP地址,将导致攻击方难以辨识真实来源(即便将所有IP部署于同一虚拟机亦无妨,因为云函数的特性使得每次心跳包均被视为新的请求,从而分配新的IP地址)。

消耗云函数配额

云函数隐藏的命令与控制(C2)中心与内容分发网络(CDN)相似,均存在一个共同的弱点:访问时需计费。因此,可以编写脚本消耗攻击方的云函数配额,从而使得攻击方的所有恶意程序无法上线。

相关工具可于以下网址获取:工具 https://github.com/a1phaboy/MenoyGone

虚假上线策略

通过重新发送心跳包以模拟上线,但攻击方无法执行任何命令(消磨攻击者精力时间)。

截图举报

在收集证据时,应重点记录具有云函数特征的信息,如主机名、X-Api-FuncName、X-Api-AppId等(其中X-Api-AppId尤为重要)。这些信息表明对方正在利用云函数对我公司进行恶意攻击。据此,我们应请求相关机构对攻击方进行临时封禁处理。

样本情报聚合、流量特征识别方案

1.收集阶段

1.1 提取样本信息

首先,基于公司收到的恶意钓鱼邮件或者恶意程序进行初始分析,得到相关特征。

提取内容:

云函数信息:提取样本中使用的云函数名称、提供商、配置等信息。

C2通信地址:提取样本中嵌入的C2服务器地址,包括域名和IP地址。

域名:提取样本中使用的所有域名。

IP地址:提取样本中使用的所有IP地址。

URL:提取样本中访问的所有URL。

工具:

YARA规则:使用YARA规则进行样本特征匹配和提取。

静态分析工具:如IDA Pro、Ghidra,用于逆向工程和静态分析。

动态分析工具:如Cuckoo Sandbox,用于行为分析和提取动态信息。

1.2收集恶意样本

来源:

威胁情报平台:订阅和使用威胁情报平台(如微步在线情报社区、VirusTotal、AlienVault OTX)。

开源情报(OSINT):利用开源情报工具(如Shodan、Censys)和社区(如GitHub、Reddit)。

合作伙伴共享:与其他企业或组织建立威胁情报共享机制。    

蜜罐系统:部署蜜罐系统(如Cowrie、Dionaea)来捕获恶意样本。

工具:

VirusTotal:用于提交和分析恶意文件。

Cuckoo Sandbox:用于自动化恶意软件分析。

微步沙箱:用于高级恶意软件行为分析。

2. 分析阶段

2.1 初步分析

静态分析:

特征字符串:提取样本中的可疑字符串,如URL、IP地址、域名等。(这里主要提取流量特征)

API调用:分析样本中调用的API函数,识别潜在的恶意行为。

嵌入域名/IP:提取样本中硬编码的域名和IP地址。

动态分析:

行为监控:在沙箱环境中运行样本,记录其行为,如文件操作、注册表修改、网络通信等。

网络流量:捕获和分析样本的网络流量,识别其通信模式和目标。

2.2 深度分析

云函数映射:

微步情报社区:提交样本到微步沙箱,提取与样本相关的云函数映射IP。(微步对域前置、CDN识别得特别准确)

统计IP:统计样本中所有提取到的IP地址,识别潜在的云服务提供商。    

相似度对比:

相似度算法:使用VT内部的相似度对比功能,分析样本与已知恶意样本的相似性。

特征对比:对比样本的特征,如文件哈希、字符串、API调用等。

C2特征对比:

URL模式:分析样本中使用的URL模式,识别C2服务器。

通信协议:分析样本使用的通信协议和加密方式,识别C2通信特征。

行为特征:记录样本的行为特征,如定时任务、数据泄露等。

3. 检测阶段

3.1 CDN和域前置检测

识别域前置:

DNS解析:使用DNS解析工具(如nslookup、dig)解析样本中使用的域名,识别域前置技术。

前置域名记录:记录前置域名和实际通信域名,分析其关联性。

CDN检测:

CDN节点识别:分析样本中使用的CDN服务,记录相关的CDN节点IP和域名。    

流量分析:使用流量分析工具(如Wireshark、Zeek)监控样本的网络通信,识别CDN流量特征。

3.2 威胁狩猎

微步沙箱/情报社区API:

基于微步强大的样本库以及情报能力,收敛相关的恶意样本进行特征关联。

IOC匹配:

IOC提取:提取样本中的IOC(Indicator of Compromise),如域名、IP地址、URL、文件哈希等。

日志匹配:将提取的IOC与现有日志进行匹配,识别潜在威胁。

网络流量分析:

流量捕获:使用网络流量捕获工具(如Wireshark、Zeek)捕获网络流量。

异常检测:分析捕获的网络流量,识别异常流量和恶意通信。

日志分析:

日志收集:收集防火墙、IDS/IPS、Web服务器等设备的日志。

日志分析:使用日志分析工具(如ELK Stack)分析日志,识别与样本相关的恶意活动。

4. 响应阶段

4.1 阻断与隔离

阻断恶意域名/IP:

防火墙规则:在防火墙上添加规则,阻断恶意域名和IP地址。

DNS黑名单:在DNS服务器上添加黑名单,阻止解析恶意域名。    

隔离受感染系统:

网络隔离:将受感染的系统从网络中隔离,防止进一步传播。

物理隔离:如果必要,将受感染的系统物理断网。

4.2 取证与恢复

数字取证:

证据收集:使用数字取证工具(如FTK Imager、EnCase)收集证据。

证据分析:分析收集到的证据,识别攻击路径和攻击者行为。

系统恢复:

备份恢复:根据备份和恢复计划,恢复受感染系统的正常运行。

补丁管理:应用最新的安全补丁,修复系统漏洞。

4.3 通报与改进

威胁通报:

内部通报:将分析结果通报给相关部门和团队。

外部通报:将威胁情报通报给合作伙伴和威胁情报共享社区。

安全改进:

策略更新:根据分析结果,更新安全策略和措施。

技术改进:引入新的安全技术和工具,提升整体安全水平。    

5. 持续监控

5.1 持续监控

实时监控:

MISP系统:使用MISP系统,进行实时监控和告警。(或商业化安全运营平台)

行为分析:使用用户和实体行为分析(UEBA)工具,监控异常行为。

定期扫描:

漏洞扫描:定期进行漏洞扫描,识别和修复系统漏洞。

渗透测试:定期进行渗透测试,评估系统的安全性。

5.2 防御手法策略

规则更新:

检测规则:根据最新威胁情报,更新防火墙、IDS/IPS等设备的检测规则。

YARA规则:更新YARA规则,用于样本特征匹配和提取。

培训与演练:

安全培训:定期进行安全培训,提高员工的安全意识和技能。

应急演练:定期进行应急演练,提高安全团队的响应能力。

实际案例:

对于CDN运营商,一般流量请求的第一跳IP在一段时间内,不会有太大的变化,可以基于微步情报社区API提取IP相关的云函数信息,挖掘云函数关联的恶意样本,对其流量进行匹配,将流量近似的恶意样本进行梳理关联,做到提前预知,同步封禁。    

近似流量匹配

Api

相关脚本

Main:

1package main    
2
3
4          
5
6
7import (
8
9
10       "HunterShell/UtilsRun"
11
12
13       "bufio"
14
15
16       "context"
17
18
19       "encoding/json"
20
21
22       "fmt"
23
24
25       "github.com/adrg/strutil"
26
27
28       "github.com/adrg/strutil/metrics"
29
30
31       "golang.org/x/time/rate"
32
33
34       "io/ioutil"
35
36
37       "log"
38
39
40       "os"
41
42
43       "path/filepath"
44
45
46       "sync"
47
48
49       "time"
50
51
52)
53
54
55          
56
57
58func main() {
59
60
61       if len(os.Args) < 2 {
62
63
64              fmt.Println("Usage: go run main.go")
65
66
67              return
68
69
70       }
71
72
73          
74
75
76       ipFilePath := os.Args[1]
77
78
79          
80
81
82       // 读取IP.txt文件中的IP地址
83
84
85       log.Println("Reading IP addresses from", ipFilePath)
86
87
88       ips, err := readLines(ipFilePath)
89
90
91       if err != nil {
92
93
94              log.Fatalf("Error reading IP.txt file: %v", err)
95
96
97       }
98
99
100          
101
102
103       // 将所有域名按行存储到domain.txt文件中
104
105
106       log.Println("Creating domain.txt file")
107
108
109       domainFile, err := os.Create("domain.txt")
110
111
112       if err != nil {
113
114
115              log.Fatalf("Error creating domain.txt file: %v", err)
116
117
118       }
119
120
121       defer domainFile.Close()
122
123
124          
125
126
127       var wg sync.WaitGroup    
128
129
130       domainChan := make(chan string, len(ips))
131
132
133          
134
135
136       // 速率限制器,每秒最多10个请求
137
138
139       limiter := rate.NewLimiter(rate.Every(50*time.Millisecond), 1)
140
141
142          
143
144
145       // 用于存储已经处理过的IP地址
146
147
148       processedIPs := make(map[string]bool)
149
150
151          
152
153
154       for _, ip := range ips {
155
156
157              if processedIPs[ip] {
158
159
160                     continue
161
162
163              }
164
165
166              processedIPs[ip] = true
167
168
169          
170
171
172              wg.Add(1)
173
174
175              go func(ip string) {
176
177
178                     defer wg.Done()
179
180
181                     if err := limiter.Wait(context.Background()); err != nil {
182
183
184                            log.Printf("Rate limit wait error: %v", err)
185
186
187                            return
188
189
190                     }
191
192
193                     log.Printf("Querying IP %s for domains", ip)
194
195
196                     domains, err := UtilsRun.QueryIPForDomains(ip)
197
198
199                     if err != nil {
200
201
202                            log.Printf("Error querying IP %s: %v", ip, err)
203
204
205                            return
206
207
208                     }
209
210
211                     for _, domain := range domains {
212
213
214                            domainChan <- domain
215
216
217                     }
218
219
220              }(ip)
221
222
223       }
224
225
226          
227
228
229       go func() {
230
231
232              wg.Wait()
233
234
235              close(domainChan)
236
237
238       }()
239
240
241          
242
243
244       for domain := range domainChan {
245
246
247              _, err := domainFile.WriteString(domain + "\n")
248
249
250              if err != nil {
251
252
253                     log.Fatalf("Error writing to domain.txt file: %v", err)    
254
255
256              }
257
258
259       }
260
261
262          
263
264
265       // 读取domain.txt文件中的域名
266
267
268       log.Println("Reading domains from domain.txt")
269
270
271       domains, err := readLines("domain.txt")
272
273
274       if err != nil {
275
276
277              log.Fatalf("Error reading domain.txt file: %v", err)
278
279
280       }
281
282
283          
284
285
286       // 将所有样本数据按行存储到result.txt文件中
287
288
289       log.Println("Creating result.txt file")
290
291
292       resultFile, err := os.Create("result.txt")
293
294
295       if err != nil {
296
297
298              log.Fatalf("Error creating result.txt file: %v", err)
299
300
301       }
302
303
304       defer resultFile.Close()
305
306
307          
308
309
310       sampleChan := make(chan UtilsRun.Sample, len(domains))
311
312
313          
314
315
316       // 用于存储已经处理过的域名
317
318
319       processedDomains := make(map[string]bool)
320
321
322          
323
324
325       for _, domain := range domains {
326
327
328              if processedDomains[domain] {
329
330
331                     continue
332
333
334              }
335
336
337              processedDomains[domain] = true
338
339
340          
341
342
343              wg.Add(1)
344
345
346              go func(domain string) {
347
348
349                     defer wg.Done()
350
351
352                     if err := limiter.Wait(context.Background()); err != nil {
353
354
355                            log.Printf("Rate limit wait error: %v", err)
356
357
358                            return
359
360
361                     }
362
363
364                     //log.Printf("Querying domain %s for samples", domain)
365
366
367                     samples, err := UtilsRun.QueryDomainForSamples(domain)
368
369
370                     if err != nil {
371
372
373                            log.Printf("Error querying domain %s: %v", domain, err)
374
375
376                            return    
377
378
379                     }
380
381
382                     for _, sample := range samples {
383
384
385                            sampleChan <- sample
386
387
388                     }
389
390
391              }(domain)
392
393
394       }
395
396
397          
398
399
400       go func() {
401
402
403              wg.Wait()
404
405
406              close(sampleChan)
407
408
409       }()
410
411
412          
413
414
415       for sample := range sampleChan {
416
417
418              _, err := resultFile.WriteString(fmt.Sprintf("  SHA256: %s\n", sample.SHA256))
419
420
421              if err != nil {
422
423
424                     log.Fatalf("Error writing to result.txt file: %v", err)
425
426
427              }
428
429
430          
431
432
433              // 获取样本详细内容并保存为JSON文件
434
435
436              if err := limiter.Wait(context.Background()); err != nil {
437
438
439                     log.Printf("Rate limit wait error: %v", err)
440
441
442                     continue
443
444
445              }
446
447
448              log.Printf("Querying sample details for %s", sample.SHA256)
449
450
451              err = UtilsRun.QuerySampleDetails(sample.SHA256)
452
453
454              if err != nil {
455
456
457                     log.Printf("Error querying sample details for %s: %v", sample.SHA256, err)
458
459
460              }
461
462
463       }
464
465
466          
467
468
469       fmt.Println("Samples have been written to result.txt")
470
471
472       //样本流量对比
473
474
475          
476
477
478       // 保存为JSON文件到指定目录
479
480
481       dirPath := "reportjson"
482
483
484          
485
486
487       // 检查目录是否存在,如果不存在则创建
488
489
490       log.Println("Checking reportjson directory")    
491
492
493       if _, err := os.Stat(dirPath); os.IsNotExist(err) {
494
495
496              err := os.Mkdir(dirPath, 0755)
497
498
499              if err != nil {
500
501
502                     log.Fatalf("Error creating directory: %v", err)
503
504
505              }
506
507
508       }
509
510
511          
512
513
514       requestMap := make(map[string]string)
515
516
517       groupMap := make(map[string]string)
518
519
520       matchInfoMap := make(map[string]string)
521
522
523          
524
525
526       // 遍历目录中的所有文件
527
528
529       log.Println("Walking reportjson directory")
530
531
532       err = filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
533
534
535              if err != nil {
536
537
538                     fmt.Println("Error accessing path:", path, err)
539
540
541                     return err
542
543
544              }
545
546
547          
548
549
550              if !info.IsDir() && filepath.Ext(path) == ".json" {
551
552
553                     // 读取 JSON 文件
554
555
556                     jsonFile, err := os.Open(path)
557
558
559                     if err != nil {
560
561
562                            fmt.Println("Error opening file:", path, err)
563
564
565                            return err
566
567
568                     }
569
570
571                     defer jsonFile.Close()
572
573
574          
575
576
577                     byteValue, err := ioutil.ReadAll(jsonFile)
578
579
580                     if err != nil {
581
582
583                            fmt.Println("Error reading file:", path, err)
584
585
586                            return err
587
588
589                     }
590
591
592          
593
594
595                     var jsonData struct {
596
597
598                            Data struct {
599
600
601                                   Network struct {
602
603
604                                          HTTPSEx []UtilsRun.HTTPSEx `json:"https_ex"`
605
606
607                                   } `json:"network"`
608
609
610                            } `json:"data"`
611
612
613                     }    
614
615
616          
617
618
619                     err = json.Unmarshal(byteValue, &jsonData)
620
621
622                     if err != nil {
623
624
625                            fmt.Println("Error unmarshalling JSON:", path, err)
626
627
628                            return err
629
630
631                     }
632
633
634          
635
636
637                     // 提取 request 信息
638
639
640                     for _, httpsEx := range jsonData.Data.Network.HTTPSEx {
641
642
643                            requestMap[path] = httpsEx.Request
644
645
646                            break
647
648
649                     }
650
651
652              }
653
654
655          
656
657
658              return nil
659
660
661       })
662
663
664          
665
666
667       if err != nil {
668
669
670              fmt.Println("Error walking the path:", dirPath, err)
671
672
673       }
674
675
676          
677
678
679       // 文本相似性归类
680
681
682       log.Println("Performing text similarity classification")
683
684
685       for file1, request1 := range requestMap {
686
687
688              groupMap[file1] = file1
689
690
691              matchInfoMap[file1] = ""
692
693
694              for file2, request2 := range requestMap {
695
696
697          
698
699
700                     if file1 != file2 {
701
702
703                            similarity := strutil.Similarity(request1, request2, metrics.NewJaccard())
704
705
706                            //fmt.Printf(request1, request2)
707
708
709                            if similarity > 0.8 { // 设置相似性阈值
710
711
712                                   groupMap[file2] = groupMap[file1]
713
714
715                                   matchInfoMap[file2] = fmt.Sprintf("Matched with %s (similarity: %.2f), Key Data: %s", file1, similarity, UtilsRun.GetMatchingKeyData(request1, request2))
716
717
718                            }
719
720
721                     }
722
723
724              }
725
726
727       }    
728
729
730          
731
732
733       // 写入分组信息到 spliet.txt
734
735
736       log.Println("Creating spliet.txt file")
737
738
739       groupFile, err := os.Create("spliet.txt")
740
741
742       if err != nil {
743
744
745              fmt.Println("Error creating file:", err)
746
747
748              return
749
750
751       }
752
753
754       defer groupFile.Close()
755
756
757          
758
759
760       groupSet := make(map[string]bool)
761
762
763       for file, group := range groupMap {
764
765
766              if !groupSet[group] {
767
768
769                     groupSet[group] = true
770
771
772                     groupFile.WriteString(fmt.Sprintf("Group: %s\n", group))
773
774
775              }
776
777
778              groupFile.WriteString(fmt.Sprintf("  %s\n", file))
779
780
781              if matchInfo := matchInfoMap[file]; matchInfo != "" {
782
783
784                     groupFile.WriteString(fmt.Sprintf("    %s\n", matchInfo))
785
786
787              }
788
789
790       }
791
792
793       // 输出文件输出成功及文件路径
794
795
796       outputPath := groupFile.Name()
797
798
799       fmt.Printf("文件输出成功,输出路径: %s\n", outputPath)
800
801
802          
803
804
805}
806
807
808          
809
810
811// 读取文件内容并按行分割
812
813
814func readLines(filename string) ([]string, error) {
815
816
817       file, err := os.Open(filename)
818
819
820       if err != nil {
821
822
823              return nil, err
824
825
826       }
827
828
829       defer file.Close()
830
831
832          
833
834
835       var lines []string
836
837
838       scanner := bufio.NewScanner(file)
839
840
841       for scanner.Scan() {
842
843
844              lines = append(lines, scanner.Text())
845
846
847       }    
848
849
850       return lines, scanner.Err()
851
852
853}

UtilsRun:   

1package UtilsRun
2
3
4          
5
6
7import (
8
9
10       "encoding/json"
11
12
13       "fmt"
14
15
16       "io/ioutil"
17
18
19       "log"
20
21
22       "net/http"
23
24
25       "os"
26
27
28       "strings"
29
30
31       "time"
32
33
34)
35
36
37          
38
39
40// HTTPRequest 结构体表示一个HTTP请求
41
42
43type HTTPRequest struct {
44
45
46       Method  string            // 请求方法
47
48
49       Path    string            // 请求路径
50
51
52       Version string            // HTTP协议版本
53
54
55       Headers map[string]string // 请求头
56
57
58       Body    string            // 请求体
59
60
61}
62
63
64          
65
66
67const (
68
69
70       maxRetries = 3
71
72
73       retryDelay = 2 * time.Second
74
75
76)
77
78
79          
80
81
82// 查询IP地址获取域名    
83
84
85func QueryIPForDomains(ip string) ([]string, error) {
86
87
88       url := fmt.Sprintf("https://api.threatbook.cn/v3/ip/adv_query?apikey=xxx&resource=%s&exclude=cur_domains", ip)
89
90
91          
92
93
94       var domains []string
95
96
97       var err error
98
99
100       for i := 0; i < maxRetries; i++ {
101
102
103              domains, err = queryIPForDomainsWithRetry(url)
104
105
106              if err == nil {
107
108
109                     return domains, nil
110
111
112              }
113
114
115              time.Sleep(retryDelay)
116
117
118       }
119
120
121       return nil, err
122
123
124}
125
126
127          
128
129
130func queryIPForDomainsWithRetry(url string) ([]string, error) {
131
132
133       client := &http.Client{Timeout: 300 * time.Second}
134
135
136       req, err := http.NewRequest("GET", url, nil)
137
138
139       if err != nil {
140
141
142              return nil, err
143
144
145       }
146
147
148          
149
150
151       res, err := client.Do(req)
152
153
154       if err != nil {
155
156
157              return nil, err
158
159
160       }
161
162
163       defer res.Body.Close()
164
165
166          
167
168
169       body, err := ioutil.ReadAll(res.Body)
170
171
172       if err != nil {
173
174
175              return nil, err
176
177
178       }
179
180
181          
182
183
184       var response Response
185
186
187       err = json.Unmarshal(body, &response)
188
189
190       if err != nil {
191
192
193              return nil, err
194
195
196       }
197
198
199          
200
201
202       var domains []string
203
204
205       for _, d := range response.Data.HistoryDomains {
206
207
208              domains = append(domains, d...)    
209
210
211       }
212
213
214          
215
216
217       return domains, nil
218
219
220}
221
222
223          
224
225
226// 查询域名获取样本数据
227
228
229func QueryDomainForSamples(domain string) ([]Sample, error) {
230
231
232       url := fmt.Sprintf("https://api.threatbook.cn/v3/domain/query?apikey=xxxx&resource=%s", domain)
233
234
235          
236
237
238       var samples []Sample
239
240
241       var err error
242
243
244       for i := 0; i < maxRetries; i++ {
245
246
247              samples, err = queryDomainForSamplesWithRetry(url, domain)
248
249
250              if err == nil {
251
252
253                     return samples, nil
254
255
256              }
257
258
259              time.Sleep(retryDelay)
260
261
262       }
263
264
265       return nil, err
266
267
268}
269
270
271          
272
273
274func queryDomainForSamplesWithRetry(url, domain string) ([]Sample, error) {
275
276
277       client := &http.Client{Timeout: 300 * time.Second}
278
279
280       req, err := http.NewRequest("GET", url, nil)
281
282
283       if err != nil {
284
285
286              return nil, err
287
288
289       }
290
291
292          
293
294
295       res, err := client.Do(req)
296
297
298       if err != nil {
299
300
301              return nil, err
302
303
304       }
305
306
307       defer res.Body.Close()
308
309
310          
311
312
313       body, err := ioutil.ReadAll(res.Body)
314
315
316       if err != nil {
317
318
319              return nil, err
320
321
322       }
323
324
325          
326
327
328       var response Response2    
329
330
331       err = json.Unmarshal(body, &response)
332
333
334       if err != nil {
335
336
337              return nil, err
338
339
340       }
341
342
343          
344
345
346       if data, ok := response.Data[domain]; ok {
347
348
349              return data.Samples, nil
350
351
352       }
353
354
355          
356
357
358       return nil, nil
359
360
361}
362
363
364          
365
366
367// 查询样本详细内容并保存为JSON文件
368
369
370func QuerySampleDetails(sha256 string) error {
371
372
373       url := fmt.Sprintf("https://api.threatbook.cn/v3/file/report?apikey=xxxxx&resource=%s&query_fields=network", sha256)
374
375
376          
377
378
379       var err error
380
381
382       for i := 0; i < maxRetries; i++ {
383
384
385              err = querySampleDetailsWithRetry(url, sha256)
386
387
388              if err == nil {
389
390
391                     return nil
392
393
394              }
395
396
397              time.Sleep(retryDelay)
398
399
400       }
401
402
403       return err
404
405
406}
407
408
409          
410
411
412func querySampleDetailsWithRetry(url, sha256 string) error {
413
414
415       client := &http.Client{Timeout: 300 * time.Second}
416
417
418       req, err := http.NewRequest("GET", url, nil)
419
420
421       if err != nil {
422
423
424              return err
425
426
427       }
428
429
430          
431
432
433       resp, err := client.Do(req)
434
435
436       if err != nil {
437
438
439              return err
440
441
442       }
443
444
445       defer resp.Body.Close()
446
447
448          
449
450
451       respBody, err := ioutil.ReadAll(resp.Body)    
452
453
454       if err != nil {
455
456
457              return err
458
459
460       }
461
462
463          
464
465
466       // 保存为JSON文件到指定目录
467
468
469       directory := "reportjson"
470
471
472          
473
474
475       // 检查目录是否存在,如果不存在则创建
476
477
478       if _, err := os.Stat(directory); os.IsNotExist(err) {
479
480
481              err := os.Mkdir(directory, 0755)
482
483
484              if err != nil {
485
486
487                     log.Fatalf("Error creating directory: %v", err)
488
489
490              }
491
492
493       }
494
495
496          
497
498
499       filename := fmt.Sprintf("%s/%s.json", directory, sha256)
500
501
502          
503
504
505       // 确保目录存在
506
507
508       err = os.MkdirAll(directory, 0755)
509
510
511       if err != nil {
512
513
514              return err
515
516
517       }
518
519
520          
521
522
523       err = ioutil.WriteFile(filename, respBody, 0644)
524
525
526       if err != nil {
527
528
529              return err
530
531
532       }
533
534
535          
536
537
538       return nil
539
540
541}
542
543
544          
545
546
547// 获取匹配的关键数据
548
549
550func GetMatchingKeyData(request1, request2 string) string {
551
552
553       // 这里可以根据实际需求实现具体的匹配关键数据提取逻辑
554
555
556       // 例如,提取请求方法、URL、Host等
557
558
559       method1 := extractMethod(request1)
560
561
562       url1 := extractURL(request1)
563
564
565       host1 := extractHost(request1)    
566
567
568          
569
570
571       return fmt.Sprintf("Method: %s, URL: %s, Host: %s", method1, url1, host1)
572
573
574}
575
576
577          
578
579
580// 提取请求方法
581
582
583func extractMethod(request string) string {
584
585
586       lines := strings.Split(request, "\n")
587
588
589       if len(lines) > 0 {
590
591
592              parts := strings.SplitN(lines[0], " ", 3)
593
594
595              if len(parts) > 0 {
596
597
598                     return parts[0]
599
600
601              }
602
603
604       }
605
606
607       return ""
608
609
610}
611
612
613          
614
615
616// 提取URL
617
618
619func extractURL(request string) string {
620
621
622       lines := strings.Split(request, "\n")
623
624
625       if len(lines) > 0 {
626
627
628              parts := strings.SplitN(lines[0], " ", 3)
629
630
631              if len(parts) > 1 {
632
633
634                     return parts[1]
635
636
637              }
638
639
640       }
641
642
643       return ""
644
645
646}
647
648
649          
650
651
652// 提取Host
653
654
655func extractHost(request string) string {
656
657
658       lines := strings.Split(request, "\n")
659
660
661       for _, line := range lines {
662
663
664              if strings.HasPrefix(line, "Host:") {
665
666
667                     return strings.TrimSpace(strings.TrimPrefix(line, "Host:"))
668
669
670              }
671
672
673       }
674
675
676       return ""
677
678
679}

这不请我咖啡啊我丢

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2