Showing
1 changed file
with
224 additions
and
166 deletions
... | @@ -224,7 +224,25 @@ namespace VulnUserCodeAnalyzer | ... | @@ -224,7 +224,25 @@ namespace VulnUserCodeAnalyzer |
224 | Console.WriteLine($"{userName}, {repository}"); | 224 | Console.WriteLine($"{userName}, {repository}"); |
225 | } | 225 | } |
226 | 226 | ||
227 | - Console.ReadLine(); | 227 | + repoPath = repoDir.FullName; |
228 | + userId = userName; | ||
229 | +<<<<<<<<< Temporary merge branch 1 | ||
230 | + } | ||
231 | + if (!string.IsNullOrWhiteSpace(repoPath) && !string.IsNullOrWhiteSpace(userId)) | ||
232 | + { | ||
233 | + break; | ||
234 | + } | ||
235 | +========= | ||
236 | + } | ||
237 | + if (!string.IsNullOrWhiteSpace(repoPath) && !string.IsNullOrWhiteSpace(userId)) | ||
238 | + { | ||
239 | + break; | ||
240 | + } | ||
241 | +>>>>>>>>> Temporary merge branch 2 | ||
242 | + repoWatch.Restart(); | ||
243 | + } | ||
244 | + //Console.WriteLine("엔터를 누르세요"); | ||
245 | + //Console.ReadLine(); | ||
228 | 246 | ||
229 | /* hashDict = 사용된 사용자 함수 정보 */ | 247 | /* hashDict = 사용된 사용자 함수 정보 */ |
230 | var hashDict = new Dictionary<int, HashSet<VulnAbstractCrawler.UserBlock>>(); | 248 | var hashDict = new Dictionary<int, HashSet<VulnAbstractCrawler.UserBlock>>(); |
... | @@ -233,197 +251,237 @@ namespace VulnUserCodeAnalyzer | ... | @@ -233,197 +251,237 @@ namespace VulnUserCodeAnalyzer |
233 | stopwatch.Start(); | 251 | stopwatch.Start(); |
234 | DirectoryInfo dirInfo = new DirectoryInfo(repoPath); | 252 | DirectoryInfo dirInfo = new DirectoryInfo(repoPath); |
235 | 253 | ||
236 | - /* 모든 .c 파일 탐색 */ | 254 | + /* 모든 .c 파일 탐색 */ |
237 | - var codeFiles = dirInfo.EnumerateFiles("*.c", SearchOption.AllDirectories); | 255 | + var codeFiles = dirInfo.EnumerateFiles("*.c", SearchOption.AllDirectories); |
238 | - int totalFileCount = codeFiles.Count(); | 256 | + int totalFileCount = codeFiles.Count(); |
239 | - int count = 0; | 257 | + int count = 0; |
240 | - foreach (var codeFile in codeFiles) | 258 | + foreach (var codeFile in codeFiles) |
241 | - { | ||
242 | - Console.WriteLine(codeFile.FullName); | ||
243 | - using (var reader = codeFile.OpenText()) | ||
244 | { | 259 | { |
245 | - /* 사용자 코드를 함수별로 나눔 */ | 260 | + Console.WriteLine(codeFile.FullName); |
246 | - var dict = crawler.CrawlUserCode(reader); | 261 | + using (var reader = codeFile.OpenText()) |
247 | - foreach (var item in dict) | ||
248 | { | 262 | { |
249 | - /* hashDict의 키와 item.key는 함수 블록의 코드 길이 */ | 263 | + /* 사용자 코드를 함수별로 나눔 */ |
250 | - if (!hashDict.ContainsKey(item.Key)) | 264 | + var dict = crawler.CrawlUserCode(reader); |
265 | + foreach (var item in dict) | ||
251 | { | 266 | { |
252 | - hashDict[item.Key] = new HashSet<VulnAbstractCrawler.UserBlock>(); | 267 | + /* hashDict의 키와 item.key는 함수 블록의 코드 길이 */ |
253 | - } | 268 | + if (!hashDict.ContainsKey(item.Key)) |
254 | - /* item.Value는 각 코드 길이 마다의 블록 정보 | 269 | + { |
255 | - * Bloom Filter에 코드 블록 해쉬값 기록 | 270 | + hashDict[item.Key] = new HashSet<VulnAbstractCrawler.UserBlock>(); |
256 | - */ | 271 | + } |
257 | - foreach (var hash in item.Value) | 272 | + /* item.Value는 각 코드 길이 마다의 블록 정보 |
258 | - { | 273 | + * Bloom Filter에 코드 블록 해쉬값 기록 |
259 | - hash.Path = codeFile.FullName; | 274 | + */ |
260 | - hashDict[item.Key].Add(hash); | 275 | + foreach (var hash in item.Value) |
261 | - filter.Add(hash.Hash); | 276 | + { |
277 | + hash.Path = codeFile.FullName; | ||
278 | + hashDict[item.Key].Add(hash); | ||
279 | + filter.Add(hash.Hash); | ||
280 | + } | ||
262 | } | 281 | } |
282 | + count++; | ||
283 | + double per = ((double)count / (double)totalFileCount) * 100; | ||
284 | + Console.WriteLine($"{count} / {totalFileCount} :: {per.ToString("#0.0")}%, 개체 수 : {hashDict.Count}"); | ||
263 | } | 285 | } |
264 | - count++; | ||
265 | - double per = ((double)count / (double)totalFileCount) * 100; | ||
266 | - Console.WriteLine($"{count} / {totalFileCount} :: {per.ToString("#0.0")}%, 개체 수 : {hashDict.Count}"); | ||
267 | } | 286 | } |
268 | - } | 287 | + var findBlocks = new Queue<VulnAbstractCrawler.UserBlock>(); |
269 | - var findBlocks = new Queue<VulnAbstractCrawler.UserBlock>(); | 288 | + var vulnDict = new Dictionary<string, IEnumerable<VulnRDS._Vuln>>(); |
270 | - var vulnDict = new Dictionary<string, IEnumerable<VulnRDS._Vuln>>(); | 289 | + foreach (var set in hashDict) |
271 | - foreach (var set in hashDict) | ||
272 | - { | ||
273 | - /* 사용자 코드의 길이 마다 DB로 부터 같은 길이의 CVE 레코드 목록 가져옴 */ | ||
274 | - var cveList = VulnRDS.SelectVulnbyLen(set.Key).Select(v => v.Cve).Distinct(); | ||
275 | - foreach (var cve in cveList) | ||
276 | { | 290 | { |
277 | - if (!vulnDict.ContainsKey(cve)) | 291 | + /* 사용자 코드의 길이 마다 DB로 부터 같은 길이의 CVE 레코드 목록 가져옴 */ |
292 | + var cveList = VulnRDS.SelectVulnbyLen(set.Key).Select(v => v.Cve).Distinct(); | ||
293 | + foreach (var cve in cveList) | ||
278 | { | 294 | { |
279 | - vulnDict[cve] = new HashSet<VulnRDS._Vuln>(); | 295 | + if (!vulnDict.ContainsKey(cve)) |
280 | - var vulnHashSet = vulnDict[cve] as HashSet<VulnRDS._Vuln>; | ||
281 | - /* 같은 길이의 CVE에서 또 같은 종류의 CVE 레코드 목록 가져옴 | ||
282 | - * 같은 종류의 CVE 레코드들이 사용자 코드에서 모두 포함되어야 | ||
283 | - * CVE를 가지고 있다고 인정하는 프로그램 정책 때문 | ||
284 | - */ | ||
285 | - var searchedCveHashList = VulnRDS.SelectVulnbyCve(cve); | ||
286 | - Console.WriteLine($"cve:{cve}, {searchedCveHashList.Count()}개 가져옴"); | ||
287 | - foreach (var s in searchedCveHashList) | ||
288 | { | 296 | { |
289 | - vulnHashSet.Add(s); | 297 | + vulnDict[cve] = new HashSet<VulnRDS._Vuln>(); |
298 | + var vulnHashSet = vulnDict[cve] as HashSet<VulnRDS._Vuln>; | ||
299 | + /* 같은 길이의 CVE에서 또 같은 종류의 CVE 레코드 목록 가져옴 | ||
300 | + * 같은 종류의 CVE 레코드들이 사용자 코드에서 모두 포함되어야 | ||
301 | + * CVE를 가지고 있다고 인정하는 프로그램 정책 때문 | ||
302 | + */ | ||
303 | + var searchedCveHashList = VulnRDS.SelectVulnbyCve(cve); | ||
304 | +<<<<<<<<< Temporary merge branch 1 | ||
305 | + Console.WriteLine($"cve:{cve}, {searchedCveHashList.Count()}개 가져옴"); | ||
306 | +========= | ||
307 | + Console.WriteLine($"CVE:{cve}, Received Count : {searchedCveHashList.Count()}"); | ||
308 | +>>>>>>>>> Temporary merge branch 2 | ||
309 | + foreach (var s in searchedCveHashList) | ||
310 | + { | ||
311 | + vulnHashSet.Add(s); | ||
312 | + } | ||
313 | + | ||
290 | } | 314 | } |
291 | - | ||
292 | } | 315 | } |
293 | } | 316 | } |
294 | - } | 317 | + var findCveDict = new Dictionary<string, List<VulnAbstractCrawler.UserBlock>>(); |
295 | - var findCveDict = new Dictionary<string, List<VulnAbstractCrawler.UserBlock>>(); | 318 | + var findCveList = new HashSet<string>(); |
296 | - var findCveList = new HashSet<string>(); | 319 | + /* 본격적인 취약점 매칭 부분 */ |
297 | - /* 본격적인 취약점 매칭 부분 */ | 320 | + foreach (var vulnSet in vulnDict) |
298 | - foreach (var vulnSet in vulnDict) | ||
299 | - { | ||
300 | - //Console.WriteLine($"-----cve:{vulnSet.Key}"); | ||
301 | - bool match = false; | ||
302 | - foreach (var vuln in vulnSet.Value) | ||
303 | { | 321 | { |
304 | - /* 사용자 코드 해쉬 저장해논 bloom filter에 취약점 레코드 해쉬값들이 포함되는지 확인 | 322 | + Console.WriteLine($"-----cve:{vulnSet.Key}"); |
305 | - * 포함이 된다는 건 해당 취약점 레코드가 사용자 코드에도 있다는 뜻(취약점) | 323 | + bool match = false; |
306 | - * 같은 종류의 CVE 레코드가 전부 필터에 포함된다면 취약점으로 판단한다. | 324 | + foreach (var vuln in vulnSet.Value) |
307 | - */ | ||
308 | - if (filter.Contains(vuln.BlockHash)) | ||
309 | { | 325 | { |
310 | - if (hashDict.ContainsKey(vuln.LenFunc)) | 326 | + /* 사용자 코드 해쉬 저장해논 bloom filter에 취약점 레코드 해쉬값들이 포함되는지 확인 |
327 | + * 포함이 된다는 건 해당 취약점 레코드가 사용자 코드에도 있다는 뜻(취약점) | ||
328 | + * 같은 종류의 CVE 레코드가 전부 필터에 포함된다면 취약점으로 판단한다. | ||
329 | + */ | ||
330 | + if (filter.Contains(vuln.BlockHash)) | ||
311 | { | 331 | { |
312 | - /* Bloom Filter는 아쉽게도 포함 여부만 알 수 있기에 | 332 | + if (hashDict.ContainsKey(vuln.LenFunc)) |
313 | - * 포함되었음을 알았다면 검색해서 정보를 구한다. */ | ||
314 | - var userBlock = hashDict[vuln.LenFunc].FirstOrDefault(b => b.Hash == vuln.BlockHash); | ||
315 | - if (userBlock == null) | ||
316 | - { | ||
317 | - continue; | ||
318 | - } | ||
319 | - /* 해당 유저 블록을 임시 저장한다. | ||
320 | - * 밑에서 블록 정보를 DB로 전송하기 위해서다. | ||
321 | - */ | ||
322 | - if (!findCveDict.ContainsKey(vuln.Cve)) | ||
323 | { | 333 | { |
324 | - findCveDict[vuln.Cve] = new List<VulnAbstractCrawler.UserBlock>(); | 334 | +<<<<<<<<< Temporary merge branch 1 |
335 | + Console.WriteLine("찾음"); | ||
336 | +========= | ||
337 | + //Console.WriteLine("찾음"); | ||
338 | +>>>>>>>>> Temporary merge branch 2 | ||
339 | + /* Bloom Filter는 아쉽게도 포함 여부만 알 수 있기에 | ||
340 | + * 포함되었음을 알았다면 검색해서 정보를 구한다. */ | ||
341 | + var userBlock = hashDict[vuln.LenFunc].FirstOrDefault(b => b.Hash == vuln.BlockHash); | ||
342 | + if (userBlock == null) | ||
343 | + { | ||
344 | + continue; | ||
345 | + } | ||
346 | + /* 해당 유저 블록을 임시 저장한다. | ||
347 | + * 밑에서 블록 정보를 DB로 전송하기 위해서다. | ||
348 | + */ | ||
349 | + if (!findCveDict.ContainsKey(vuln.Cve)) | ||
350 | + { | ||
351 | + findCveDict[vuln.Cve] = new List<VulnAbstractCrawler.UserBlock>(); | ||
352 | + } | ||
353 | + userBlock.Url = vuln.Url; | ||
354 | + findCveDict[vuln.Cve].Add(userBlock); | ||
355 | + match = true; | ||
325 | } | 356 | } |
326 | - userBlock.Url = vuln.Url; | ||
327 | - findCveDict[vuln.Cve].Add(userBlock); | ||
328 | - match = true; | ||
329 | } | 357 | } |
358 | + else | ||
359 | + { | ||
360 | + match = false; | ||
361 | + break; | ||
362 | + } | ||
363 | + } | ||
364 | + /* 취약점 레코드가 전부 있어야 CVE 찾음 인정 */ | ||
365 | + if (match) | ||
366 | + { | ||
367 | +<<<<<<<<< Temporary merge branch 1 | ||
368 | + Console.WriteLine($"CVE 찾음 {vulnSet.Key}"); | ||
369 | +========= | ||
370 | + Console.WriteLine($"Matched CVE : {vulnSet.Key}"); | ||
371 | +>>>>>>>>> Temporary merge branch 2 | ||
372 | + /* 찾았으면 cve값을 기록함 밑에서 찾은 cve 정보 전송하기 위해 */ | ||
373 | + findCveList.Add(vulnSet.Key); | ||
330 | } | 374 | } |
331 | else | 375 | else |
332 | { | 376 | { |
333 | - match = false; | 377 | +<<<<<<<<< Temporary merge branch 1 |
334 | - break; | 378 | + Console.WriteLine("없음"); |
379 | +========= | ||
380 | + Console.WriteLine("Not"); | ||
381 | +>>>>>>>>> Temporary merge branch 2 | ||
335 | } | 382 | } |
336 | } | 383 | } |
337 | - /* 취약점 레코드가 전부 있어야 CVE 찾음 인정 */ | 384 | + stopwatch.Stop(); |
338 | - if (match) | 385 | + /* 매칭 끝 후처리 (출력, DB 전송 등) */ |
339 | - { | 386 | + var hours = stopwatch.Elapsed.Hours; |
340 | - Console.WriteLine($"CVE 찾음 {vulnSet.Key}"); | 387 | + var minutes = stopwatch.Elapsed.Minutes; |
341 | - /* 찾았으면 cve값을 기록함 밑에서 찾은 cve 정보 전송하기 위해 */ | 388 | + var seconds = stopwatch.Elapsed.Seconds; |
342 | - findCveList.Add(vulnSet.Key); | 389 | +<<<<<<<<< Temporary merge branch 1 |
343 | - } | 390 | + Console.WriteLine($"경과 시간 {hours.ToString("00")}:{minutes.ToString("00")}:{seconds.ToString("00")}"); |
344 | - else | 391 | + Console.WriteLine($"찾은 CVE 개수 : {findCveList.Count}"); |
345 | - { | 392 | +========= |
346 | - Console.WriteLine("없음"); | 393 | + Console.WriteLine($"Elapsed Time : {hours.ToString("00")}:{minutes.ToString("00")}:{seconds.ToString("00")}"); |
347 | - } | 394 | + Console.WriteLine($"Matched CVE Count : {findCveList.Count}"); |
348 | - } | 395 | +>>>>>>>>> Temporary merge branch 2 |
349 | - stopwatch.Stop(); | 396 | + //Console.ReadLine(); |
350 | - /* 매칭 끝 후처리 (출력, DB 전송 등) */ | ||
351 | - var hours = stopwatch.Elapsed.Hours; | ||
352 | - var minutes = stopwatch.Elapsed.Minutes; | ||
353 | - var seconds = stopwatch.Elapsed.Seconds; | ||
354 | - Console.WriteLine($"경과 시간 {hours.ToString("00")}:{minutes.ToString("00")}:{seconds.ToString("00")}"); | ||
355 | - Console.WriteLine($"찾은 CVE 개수 : {findCveList.Count}"); | ||
356 | - var yearMatch = new Regex(@"CVE-(\d{4})-(\d+)"); | ||
357 | - foreach (var cve in findCveList) | ||
358 | - { | ||
359 | - Console.WriteLine(cve); | ||
360 | - var c = yearMatch.Match(cve); | ||
361 | - int year = int.Parse(c.Groups[1].Value); | ||
362 | - if (!CVE_JSON.CveDict.ContainsKey(year)) | ||
363 | - { | ||
364 | - continue; | ||
365 | - } | ||
366 | - if (!CVE_JSON.CveDict[year].ContainsKey(cve)) | ||
367 | - { | ||
368 | - continue; | ||
369 | - } | ||
370 | - var data = CVE_JSON.CveDict[year][cve]; | ||
371 | 397 | ||
372 | - /* 취약점 타입 분류 */ | 398 | + var yearMatch = new Regex(@"CVE-(\d{4})-(\d+)"); |
373 | - string type = "NORMAL"; | 399 | + foreach (var cve in findCveList) |
374 | - if (data.Detail.IndexOf("overflow", StringComparison.CurrentCultureIgnoreCase) > 0) | ||
375 | - { | ||
376 | - type = "OVERFLOW"; | ||
377 | - } | ||
378 | - else if (data.Detail.IndexOf("xss", StringComparison.CurrentCultureIgnoreCase) > 0) | ||
379 | - { | ||
380 | - type = "XSS"; | ||
381 | - } | ||
382 | - else if (data.Detail.IndexOf("injection", StringComparison.CurrentCultureIgnoreCase) > 0) | ||
383 | - { | ||
384 | - type = "SQLINJECTION"; | ||
385 | - } | ||
386 | - else if (data.Detail.IndexOf("dos", StringComparison.CurrentCultureIgnoreCase) > 0) | ||
387 | - { | ||
388 | - type = "DOS"; | ||
389 | - } | ||
390 | - else if (data.Detail.IndexOf("Memory", StringComparison.CurrentCultureIgnoreCase) > 0) | ||
391 | - { | ||
392 | - type = "MEMORY"; | ||
393 | - } | ||
394 | - else if (data.Detail.IndexOf("CSRF", StringComparison.CurrentCultureIgnoreCase) > 0) | ||
395 | { | 400 | { |
396 | - type = "CSRF"; | 401 | + Console.WriteLine(cve); |
397 | - } | 402 | + var c = yearMatch.Match(cve); |
398 | - else if (data.Detail.IndexOf("inclusion", StringComparison.CurrentCultureIgnoreCase) > 0) | 403 | + int year = int.Parse(c.Groups[1].Value); |
399 | - { | 404 | + if (!CVE_JSON.CveDict.ContainsKey(year)) |
400 | - type = "FILEINCLUSION"; | 405 | + { |
401 | - } | 406 | + continue; |
402 | - else if (data.Detail.IndexOf("EXCUTE", StringComparison.CurrentCultureIgnoreCase) > 0) | 407 | + } |
403 | - { | 408 | + if (!CVE_JSON.CveDict[year].ContainsKey(cve)) |
404 | - type = "EXCUTE"; | 409 | + { |
405 | - } | 410 | + continue; |
406 | - | 411 | + } |
407 | - var urlBytes = Convert.FromBase64String(findCveDict[cve].FirstOrDefault().Url); | 412 | + var data = CVE_JSON.CveDict[year][cve]; |
408 | - string url = Encoding.Unicode.GetString(urlBytes); | ||
409 | 413 | ||
410 | - /* DB 전송 */ | 414 | + /* 취약점 타입 분류 */ |
411 | - VulnRDS.InsertVulnDetail(new VulnRDS.Vuln_detail | 415 | + string type = "NORMAL"; |
412 | - { | 416 | + if (data.Detail.IndexOf("overflow", StringComparison.CurrentCultureIgnoreCase) > 0) |
413 | - CveName = data.Code, | 417 | + { |
414 | - Type = type, | 418 | + type = "OVERFLOW"; |
415 | - Level = data.Level.ToString(), | 419 | + } |
416 | - Year = data.Year.ToString(), | 420 | + else if (data.Detail.IndexOf("xss", StringComparison.CurrentCultureIgnoreCase) > 0) |
417 | - CveDetail = data.Detail, | 421 | + { |
418 | - Publish_date = data.Publish_Date.ToString("yyyy-MM-dd"), | 422 | + type = "XSS"; |
419 | - Update_date = data.Update_Date.ToString("yyyy-MM-dd"), | 423 | + } |
420 | - UserName = "samsung", | 424 | + else if (data.Detail.IndexOf("injection", StringComparison.CurrentCultureIgnoreCase) > 0) |
421 | - Url = url, | 425 | + { |
422 | - FileName = findCveDict[cve].FirstOrDefault().Path.Replace(@"C:\code", ""), | 426 | + type = "SQLINJECTION"; |
423 | - FuncName = findCveDict[cve].FirstOrDefault().FuncName, | 427 | + } |
424 | - Product = data.Type, | 428 | + else if (data.Detail.IndexOf("dos", StringComparison.CurrentCultureIgnoreCase) > 0) |
425 | - }); | 429 | + { |
426 | - Console.WriteLine("추가 완료"); | 430 | + type = "DOS"; |
431 | + } | ||
432 | + else if (data.Detail.IndexOf("Memory", StringComparison.CurrentCultureIgnoreCase) > 0) | ||
433 | + { | ||
434 | + type = "MEMORY"; | ||
435 | + } | ||
436 | + else if (data.Detail.IndexOf("CSRF", StringComparison.CurrentCultureIgnoreCase) > 0) | ||
437 | + { | ||
438 | + type = "CSRF"; | ||
439 | + } | ||
440 | + else if (data.Detail.IndexOf("inclusion", StringComparison.CurrentCultureIgnoreCase) > 0) | ||
441 | + { | ||
442 | + type = "FILEINCLUSION"; | ||
443 | + } | ||
444 | + else if (data.Detail.IndexOf("EXCUTE", StringComparison.CurrentCultureIgnoreCase) > 0) | ||
445 | + { | ||
446 | + type = "EXCUTE"; | ||
447 | + } | ||
448 | + | ||
449 | + var urlBytes = Convert.FromBase64String(findCveDict[cve].FirstOrDefault().Url); | ||
450 | + string url = Encoding.Unicode.GetString(urlBytes); | ||
451 | +<<<<<<<<< Temporary merge branch 1 | ||
452 | + Console.WriteLine(findCveDict[cve].FirstOrDefault().Path.Replace(repoPath, "")); | ||
453 | + /* DB 전송 */ | ||
454 | + VulnRDS.InsertVulnDetail(new VulnRDS.Vuln_detail | ||
455 | +========= | ||
456 | + //Console.WriteLine(findCveDict[cve].FirstOrDefault().Path.Replace(repoPath, "")); | ||
457 | + | ||
458 | + var vulnDetail = new VulnRDS.Vuln_detail | ||
459 | +>>>>>>>>> Temporary merge branch 2 | ||
460 | + { | ||
461 | + CveName = data.Code, | ||
462 | + Type = type, | ||
463 | + Level = data.Level.ToString(), | ||
464 | + Year = data.Year.ToString(), | ||
465 | + CveDetail = data.Detail, | ||
466 | + Publish_date = data.Publish_Date.ToString("yyyy-MM-dd"), | ||
467 | + Update_date = data.Update_Date.ToString("yyyy-MM-dd"), | ||
468 | + UserName = userId, | ||
469 | + Url = url, | ||
470 | + FileName = findCveDict[cve].FirstOrDefault().Path.Replace(repoPath, ""), | ||
471 | + FuncName = findCveDict[cve].FirstOrDefault().FuncName, | ||
472 | + Product = data.Type, | ||
473 | +<<<<<<<<< Temporary merge branch 1 | ||
474 | + }); | ||
475 | + Console.WriteLine("추가 완료"); | ||
476 | +========= | ||
477 | + }; | ||
478 | + | ||
479 | + /* DB 전송 */ | ||
480 | + VulnRDS.InsertVulnDetail(vulnDetail); | ||
481 | + | ||
482 | + Console.WriteLine($"Added CVE: {vulnDetail.CveName}, Type: {vulnDetail.Type}, CVSS: {vulnDetail.Level}"); | ||
483 | +>>>>>>>>> Temporary merge branch 2 | ||
484 | + } | ||
427 | } | 485 | } |
428 | } | 486 | } |
429 | } | 487 | } | ... | ... |
-
Please register or login to post a comment