노현종

merge

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