노현종

DB 호환성 수정, 주석 추가, 타입 분류

...@@ -65,10 +65,6 @@ namespace VulnCrawler ...@@ -65,10 +65,6 @@ namespace VulnCrawler
65 65
66 /* 메인 동작 함수 */ 66 /* 메인 동작 함수 */
67 public static void Run() { 67 public static void Run() {
68 -
69 -
70 -
71 -
72 // Repository 폴더들이 있는 주소를 지정하면 하위 폴더 목록을 가져옴(Repository 목록) 68 // Repository 폴더들이 있는 주소를 지정하면 하위 폴더 목록을 가져옴(Repository 목록)
73 Regex.CacheSize = 50; 69 Regex.CacheSize = 50;
74 70
...@@ -88,35 +84,6 @@ namespace VulnCrawler ...@@ -88,35 +84,6 @@ namespace VulnCrawler
88 { 84 {
89 continue; 85 continue;
90 } 86 }
91 - //var crawler = new VulnC();
92 - //crawler.Init(directory);
93 -
94 - //Tree commitTree1 = crawler.Repository.Lookup<Commit>("e589db7a6a9c8f1557007f2cc765ee28ad7a1edd").Tree;
95 - ////Tree parentTree1 = crawler.Repository.Lookup<Commit>("344ba37bdc299660e1b1693b6999e5fe116893e1").Tree;
96 -
97 - //Commit commit = crawler.Repository.Lookup<Commit>("e589db7a6a9c8f1557007f2cc765ee28ad7a1edd");
98 -
99 - //foreach (var parent in commit.Parents)
100 - //{
101 - // Console.WriteLine($"Parent ID:{parent.Sha}");
102 - // Tree commitTree = commit.Tree;
103 - // Tree parentTree = parent.Tree;
104 - // var patch = crawler.Repository.Diff.Compare<Patch>(commitTree, parentTree.);
105 - // foreach (var item in patch.Where(p => p.OldPath.EndsWith(".c")))
106 - // {
107 -
108 - // Console.WriteLine(item.Status);
109 - // Console.WriteLine(item.Path);
110 - // Console.WriteLine(item.Patch);
111 - // }
112 - // Console.ReadLine();
113 -
114 - //}
115 -
116 -
117 - ////Console.WriteLine(patch.Content);
118 - //Console.ReadLine();
119 -
120 // 템플릿 패턴화 T : VulnAbstractCrawler 87 // 템플릿 패턴화 T : VulnAbstractCrawler
121 VulnWorker.Run<VulnC>(directory); 88 VulnWorker.Run<VulnC>(directory);
122 } 89 }
......
...@@ -67,6 +67,7 @@ namespace VulnCrawler ...@@ -67,6 +67,7 @@ namespace VulnCrawler
67 public string FileName { get; set; } = "NULL"; /* FileName */ 67 public string FileName { get; set; } = "NULL"; /* FileName */
68 public string FuncName { get; set; } = "NULL"; /* funcName */ 68 public string FuncName { get; set; } = "NULL"; /* funcName */
69 public string Url { get; set; } = "NULL"; /* Url */ 69 public string Url { get; set; } = "NULL"; /* Url */
70 + public string Product { get; set; }
70 71
71 } 72 }
72 //connect 73 //connect
...@@ -242,7 +243,7 @@ namespace VulnCrawler ...@@ -242,7 +243,7 @@ namespace VulnCrawler
242 { 243 {
243 Connection = Conn, 244 Connection = Conn,
244 //db에 추가 245 //db에 추가
245 - CommandText = "INSERT INTO vulnDetail(type, year, level, userName, cveName, publish_date,update_date, cveDetail,fileName, funcName, url) VALUES(@type, @year, @level, @userName, @cveName, @publish_date,@update_date, @cveDetail,@fileName, @funcName,@url)" 246 + CommandText = "INSERT INTO vulnDetail(type, year, level, userName, cveName, publish_date,update_date, cveDetail,fileName, funcName, url, product) VALUES(@type, @year, @level, @userName, @cveName, @publish_date,@update_date, @cveDetail,@fileName, @funcName,@url,@product)"
246 }; 247 };
247 cmd.Parameters.AddWithValue("@type", $"{vuln.Type}"); 248 cmd.Parameters.AddWithValue("@type", $"{vuln.Type}");
248 cmd.Parameters.AddWithValue("@year", $"{vuln.Year}"); 249 cmd.Parameters.AddWithValue("@year", $"{vuln.Year}");
...@@ -255,16 +256,16 @@ namespace VulnCrawler ...@@ -255,16 +256,16 @@ namespace VulnCrawler
255 cmd.Parameters.AddWithValue("@fileName", $"{vuln.FileName}"); 256 cmd.Parameters.AddWithValue("@fileName", $"{vuln.FileName}");
256 cmd.Parameters.AddWithValue("@funcName", $"{vuln.FuncName}"); 257 cmd.Parameters.AddWithValue("@funcName", $"{vuln.FuncName}");
257 cmd.Parameters.AddWithValue("@url", $"{vuln.Url}"); 258 cmd.Parameters.AddWithValue("@url", $"{vuln.Url}");
258 - 259 + cmd.Parameters.AddWithValue("@product", $"{vuln.Product}");
259 cmd.ExecuteNonQuery(); 260 cmd.ExecuteNonQuery();
260 //콘솔출력용 261 //콘솔출력용
261 sql = "INSERT INTO vulnDetail(type, year, level, userName, cveName, publish_date,update_date, cveDetail,fileName, funcName, url) " + 262 sql = "INSERT INTO vulnDetail(type, year, level, userName, cveName, publish_date,update_date, cveDetail,fileName, funcName, url) " +
262 $"VALUES({vuln.Type}, {vuln.Year}, {vuln.Level}, {vuln.UserName}, {vuln.CveName},{vuln.Publish_date}, {vuln.Update_date}, {vuln.CveDetail}, {vuln.FileName}, {vuln.FuncName}, {vuln.Url})"; 263 $"VALUES({vuln.Type}, {vuln.Year}, {vuln.Level}, {vuln.UserName}, {vuln.CveName},{vuln.Publish_date}, {vuln.Update_date}, {vuln.CveDetail}, {vuln.FileName}, {vuln.FuncName}, {vuln.Url})";
263 - Console.WriteLine(sql); 264 + // Console.WriteLine(sql);
264 } 265 }
265 catch (Exception e) 266 catch (Exception e)
266 { 267 {
267 - Console.WriteLine(e.ToString()); 268 + // Console.WriteLine(e.ToString());
268 string es = e.ToString(); 269 string es = e.ToString();
269 if (es.Contains("Connection must be valid and open")) 270 if (es.Contains("Connection must be valid and open"))
270 { 271 {
......
...@@ -111,10 +111,13 @@ namespace VulnUserCodeAnalyzer ...@@ -111,10 +111,13 @@ namespace VulnUserCodeAnalyzer
111 { 111 {
112 static void Main(string[] args) 112 static void Main(string[] args)
113 { 113 {
114 + /* 연도별 CVE JSON 파일 로드 */
114 CVE_JSON.AutoLoad(); 115 CVE_JSON.AutoLoad();
115 116
117 + /* 크롤러 타입 */
116 var crawler = new VulnC(); 118 var crawler = new VulnC();
117 119
120 + /* 매칭을 위한 자료구조 Bloom Filter */
118 int capacity = 50000000; 121 int capacity = 50000000;
119 var filter = new Filter<string>(capacity); 122 var filter = new Filter<string>(capacity);
120 123
...@@ -146,10 +149,15 @@ namespace VulnUserCodeAnalyzer ...@@ -146,10 +149,15 @@ namespace VulnUserCodeAnalyzer
146 Console.WriteLine("연결 실패"); 149 Console.WriteLine("연결 실패");
147 return; 150 return;
148 } 151 }
152 +
153 + /* hashDict = 사용된 사용자 함수 정보 */
149 var hashDict = new Dictionary<int, HashSet<VulnAbstractCrawler.UserBlock>>(); 154 var hashDict = new Dictionary<int, HashSet<VulnAbstractCrawler.UserBlock>>();
155 + /* 경과 시간 체크 */
150 Stopwatch stopwatch = new Stopwatch(); 156 Stopwatch stopwatch = new Stopwatch();
151 stopwatch.Start(); 157 stopwatch.Start();
152 DirectoryInfo dirInfo = new DirectoryInfo(@"C:\code"); 158 DirectoryInfo dirInfo = new DirectoryInfo(@"C:\code");
159 +
160 + /* 모든 .c 파일 탐색 */
153 var codeFiles = dirInfo.EnumerateFiles("*.c", SearchOption.AllDirectories); 161 var codeFiles = dirInfo.EnumerateFiles("*.c", SearchOption.AllDirectories);
154 int totalFileCount = codeFiles.Count(); 162 int totalFileCount = codeFiles.Count();
155 int count = 0; 163 int count = 0;
...@@ -158,17 +166,21 @@ namespace VulnUserCodeAnalyzer ...@@ -158,17 +166,21 @@ namespace VulnUserCodeAnalyzer
158 Console.WriteLine(codeFile.FullName); 166 Console.WriteLine(codeFile.FullName);
159 using (var reader = codeFile.OpenText()) 167 using (var reader = codeFile.OpenText())
160 { 168 {
169 + /* 사용자 코드를 함수별로 나눔 */
161 var dict = crawler.CrawlUserCode(reader); 170 var dict = crawler.CrawlUserCode(reader);
162 foreach (var item in dict) 171 foreach (var item in dict)
163 { 172 {
173 + /* hashDict의 키와 item.key는 함수 블록의 코드 길이 */
164 if (!hashDict.ContainsKey(item.Key)) 174 if (!hashDict.ContainsKey(item.Key))
165 { 175 {
166 hashDict[item.Key] = new HashSet<VulnAbstractCrawler.UserBlock>(); 176 hashDict[item.Key] = new HashSet<VulnAbstractCrawler.UserBlock>();
167 } 177 }
178 + /* item.Value는 각 코드 길이 마다의 블록 정보
179 + * Bloom Filter에 코드 블록 해쉬값 기록
180 + */
168 foreach (var hash in item.Value) 181 foreach (var hash in item.Value)
169 { 182 {
170 hash.Path = codeFile.FullName; 183 hash.Path = codeFile.FullName;
171 -
172 hashDict[item.Key].Add(hash); 184 hashDict[item.Key].Add(hash);
173 filter.Add(hash.Hash); 185 filter.Add(hash.Hash);
174 } 186 }
...@@ -178,12 +190,11 @@ namespace VulnUserCodeAnalyzer ...@@ -178,12 +190,11 @@ namespace VulnUserCodeAnalyzer
178 Console.WriteLine($"{count} / {totalFileCount} :: {per.ToString("#0.0")}%, 개체 수 : {hashDict.Count}"); 190 Console.WriteLine($"{count} / {totalFileCount} :: {per.ToString("#0.0")}%, 개체 수 : {hashDict.Count}");
179 } 191 }
180 } 192 }
181 - //Console.ReadLine();
182 -
183 var findBlocks = new Queue<VulnAbstractCrawler.UserBlock>(); 193 var findBlocks = new Queue<VulnAbstractCrawler.UserBlock>();
184 var vulnDict = new Dictionary<string, IEnumerable<VulnRDS._Vuln>>(); 194 var vulnDict = new Dictionary<string, IEnumerable<VulnRDS._Vuln>>();
185 foreach (var set in hashDict) 195 foreach (var set in hashDict)
186 { 196 {
197 + /* 사용자 코드의 길이 마다 DB로 부터 같은 길이의 CVE 레코드 목록 가져옴 */
187 var cveList = VulnRDS.SelectVulnbyLen(set.Key).Select(v => v.Cve).Distinct(); 198 var cveList = VulnRDS.SelectVulnbyLen(set.Key).Select(v => v.Cve).Distinct();
188 foreach (var cve in cveList) 199 foreach (var cve in cveList)
189 { 200 {
...@@ -191,6 +202,10 @@ namespace VulnUserCodeAnalyzer ...@@ -191,6 +202,10 @@ namespace VulnUserCodeAnalyzer
191 { 202 {
192 vulnDict[cve] = new HashSet<VulnRDS._Vuln>(); 203 vulnDict[cve] = new HashSet<VulnRDS._Vuln>();
193 var vulnHashSet = vulnDict[cve] as HashSet<VulnRDS._Vuln>; 204 var vulnHashSet = vulnDict[cve] as HashSet<VulnRDS._Vuln>;
205 + /* 같은 길이의 CVE에서 또 같은 종류의 CVE 레코드 목록 가져옴
206 + * 같은 종류의 CVE 레코드들이 사용자 코드에서 모두 포함되어야
207 + * CVE를 가지고 있다고 인정하는 프로그램 정책 때문
208 + */
194 var searchedCveHashList = VulnRDS.SelectVulnbyCve(cve); 209 var searchedCveHashList = VulnRDS.SelectVulnbyCve(cve);
195 Console.WriteLine($"cve:{cve}, {searchedCveHashList.Count()}개 가져옴"); 210 Console.WriteLine($"cve:{cve}, {searchedCveHashList.Count()}개 가져옴");
196 foreach (var s in searchedCveHashList) 211 foreach (var s in searchedCveHashList)
...@@ -203,30 +218,37 @@ namespace VulnUserCodeAnalyzer ...@@ -203,30 +218,37 @@ namespace VulnUserCodeAnalyzer
203 } 218 }
204 var findCveDict = new Dictionary<string, List<VulnAbstractCrawler.UserBlock>>(); 219 var findCveDict = new Dictionary<string, List<VulnAbstractCrawler.UserBlock>>();
205 var findCveList = new HashSet<string>(); 220 var findCveList = new HashSet<string>();
221 + /* 본격적인 취약점 매칭 부분 */
206 foreach (var vulnSet in vulnDict) 222 foreach (var vulnSet in vulnDict)
207 { 223 {
208 //Console.WriteLine($"-----cve:{vulnSet.Key}"); 224 //Console.WriteLine($"-----cve:{vulnSet.Key}");
209 bool match = false; 225 bool match = false;
210 foreach (var vuln in vulnSet.Value) 226 foreach (var vuln in vulnSet.Value)
211 { 227 {
228 + /* 사용자 코드 해쉬 저장해논 bloom filter에 취약점 레코드 해쉬값들이 포함되는지 확인
229 + * 포함이 된다는 건 해당 취약점 레코드가 사용자 코드에도 있다는 뜻(취약점)
230 + * 같은 종류의 CVE 레코드가 전부 필터에 포함된다면 취약점으로 판단한다.
231 + */
212 if (filter.Contains(vuln.BlockHash)) 232 if (filter.Contains(vuln.BlockHash))
213 { 233 {
214 - // Console.WriteLine($"필터 확인 : {vuln.BlockHash}");
215 if (hashDict.ContainsKey(vuln.LenFunc)) 234 if (hashDict.ContainsKey(vuln.LenFunc))
216 { 235 {
236 + /* Bloom Filter는 아쉽게도 포함 여부만 알 수 있기에
237 + * 포함되었음을 알았다면 검색해서 정보를 구한다. */
217 var userBlock = hashDict[vuln.LenFunc].FirstOrDefault(b => b.Hash == vuln.BlockHash); 238 var userBlock = hashDict[vuln.LenFunc].FirstOrDefault(b => b.Hash == vuln.BlockHash);
218 if (userBlock == null) 239 if (userBlock == null)
219 { 240 {
220 - //Console.WriteLine("userBlock이 비어있습니다.");
221 continue; 241 continue;
222 } 242 }
243 + /* 해당 유저 블록을 임시 저장한다.
244 + * 밑에서 블록 정보를 DB로 전송하기 위해서다.
245 + */
223 if (!findCveDict.ContainsKey(vuln.Cve)) 246 if (!findCveDict.ContainsKey(vuln.Cve))
224 { 247 {
225 findCveDict[vuln.Cve] = new List<VulnAbstractCrawler.UserBlock>(); 248 findCveDict[vuln.Cve] = new List<VulnAbstractCrawler.UserBlock>();
226 } 249 }
227 userBlock.Url = vuln.Url; 250 userBlock.Url = vuln.Url;
228 findCveDict[vuln.Cve].Add(userBlock); 251 findCveDict[vuln.Cve].Add(userBlock);
229 - //Console.WriteLine($"CVE:{vuln.Cve}, {userBlock.FuncName}, 블록 확인 : DB : {vuln.BlockHash}, User : {userBlock.Hash}");
230 match = true; 252 match = true;
231 } 253 }
232 } 254 }
...@@ -236,10 +258,11 @@ namespace VulnUserCodeAnalyzer ...@@ -236,10 +258,11 @@ namespace VulnUserCodeAnalyzer
236 break; 258 break;
237 } 259 }
238 } 260 }
261 + /* 취약점 레코드가 전부 있어야 CVE 찾음 인정 */
239 if (match) 262 if (match)
240 { 263 {
241 Console.WriteLine($"CVE 찾음 {vulnSet.Key}"); 264 Console.WriteLine($"CVE 찾음 {vulnSet.Key}");
242 - 265 + /* 찾았으면 cve값을 기록함 밑에서 찾은 cve 정보 전송하기 위해 */
243 findCveList.Add(vulnSet.Key); 266 findCveList.Add(vulnSet.Key);
244 } 267 }
245 else 268 else
...@@ -248,22 +271,18 @@ namespace VulnUserCodeAnalyzer ...@@ -248,22 +271,18 @@ namespace VulnUserCodeAnalyzer
248 } 271 }
249 } 272 }
250 stopwatch.Stop(); 273 stopwatch.Stop();
274 + /* 매칭 끝 후처리 (출력, DB 전송 등) */
251 var hours = stopwatch.Elapsed.Hours; 275 var hours = stopwatch.Elapsed.Hours;
252 var minutes = stopwatch.Elapsed.Minutes; 276 var minutes = stopwatch.Elapsed.Minutes;
253 var seconds = stopwatch.Elapsed.Seconds; 277 var seconds = stopwatch.Elapsed.Seconds;
254 Console.WriteLine($"경과 시간 {hours.ToString("00")}:{minutes.ToString("00")}:{seconds.ToString("00")}"); 278 Console.WriteLine($"경과 시간 {hours.ToString("00")}:{minutes.ToString("00")}:{seconds.ToString("00")}");
255 - // CVE JSON 검색
256 Console.WriteLine($"찾은 CVE 개수 : {findCveList.Count}"); 279 Console.WriteLine($"찾은 CVE 개수 : {findCveList.Count}");
257 -
258 var yearMatch = new Regex(@"CVE-(\d{4})-(\d+)"); 280 var yearMatch = new Regex(@"CVE-(\d{4})-(\d+)");
259 foreach (var cve in findCveList) 281 foreach (var cve in findCveList)
260 { 282 {
261 Console.WriteLine(cve); 283 Console.WriteLine(cve);
262 -
263 var c = yearMatch.Match(cve); 284 var c = yearMatch.Match(cve);
264 -
265 int year = int.Parse(c.Groups[1].Value); 285 int year = int.Parse(c.Groups[1].Value);
266 -
267 if (!CVE_JSON.CveDict.ContainsKey(year)) 286 if (!CVE_JSON.CveDict.ContainsKey(year))
268 { 287 {
269 continue; 288 continue;
...@@ -273,19 +292,59 @@ namespace VulnUserCodeAnalyzer ...@@ -273,19 +292,59 @@ namespace VulnUserCodeAnalyzer
273 continue; 292 continue;
274 } 293 }
275 var data = CVE_JSON.CveDict[year][cve]; 294 var data = CVE_JSON.CveDict[year][cve];
295 +
296 + /* 취약점 타입 분류 */
297 + string type = "NORMAL";
298 + if (data.Detail.IndexOf("overflow", StringComparison.CurrentCultureIgnoreCase) > 0)
299 + {
300 + type = "OVERFLOW";
301 + }
302 + else if (data.Detail.IndexOf("xss", StringComparison.CurrentCultureIgnoreCase) > 0)
303 + {
304 + type = "XSS";
305 + }
306 + else if (data.Detail.IndexOf("injection", StringComparison.CurrentCultureIgnoreCase) > 0)
307 + {
308 + type = "SQLINJECTION";
309 + }
310 + else if (data.Detail.IndexOf("dos", StringComparison.CurrentCultureIgnoreCase) > 0)
311 + {
312 + type = "DOS";
313 + }
314 + else if (data.Detail.IndexOf("Memory", StringComparison.CurrentCultureIgnoreCase) > 0)
315 + {
316 + type = "MEMORY";
317 + }
318 + else if (data.Detail.IndexOf("CSRF", StringComparison.CurrentCultureIgnoreCase) > 0)
319 + {
320 + type = "CSRF";
321 + }
322 + else if (data.Detail.IndexOf("inclusion", StringComparison.CurrentCultureIgnoreCase) > 0)
323 + {
324 + type = "FILEINCLUSION";
325 + }
326 + else if (data.Detail.IndexOf("EXCUTE", StringComparison.CurrentCultureIgnoreCase) > 0)
327 + {
328 + type = "EXCUTE";
329 + }
330 + var urlBytes = Convert.FromBase64String(findCveDict[cve].FirstOrDefault().Url);
331 + string url = Encoding.Unicode.GetString(urlBytes);
332 +
333 + /* DB 전송 */
276 VulnRDS.InsertVulnDetail(new VulnRDS.Vuln_detail 334 VulnRDS.InsertVulnDetail(new VulnRDS.Vuln_detail
277 { 335 {
278 CveName = data.Code, 336 CveName = data.Code,
279 - Type = data.Type, 337 + Type = type,
280 Level = data.Level.ToString(), 338 Level = data.Level.ToString(),
281 Year = data.Year.ToString(), 339 Year = data.Year.ToString(),
282 CveDetail = data.Detail, 340 CveDetail = data.Detail,
283 - Publish_date = data.Publish_Date.ToString(), 341 + Publish_date = data.Publish_Date.ToString("yyyy-MM-dd"),
284 - Update_date = data.Update_Date.ToString(), 342 + Update_date = data.Update_Date.ToString("yyyy-MM-dd"),
285 UserName = "samsung", 343 UserName = "samsung",
286 - Url = findCveDict[cve].FirstOrDefault().Url, 344 + Url = url,
287 - FileName = findCveDict[cve].FirstOrDefault().Path, 345 + FileName = findCveDict[cve].FirstOrDefault().Path.Replace(@"C:\code", ""),
288 FuncName = findCveDict[cve].FirstOrDefault().FuncName, 346 FuncName = findCveDict[cve].FirstOrDefault().FuncName,
347 + Product = data.Type,
289 }); 348 });
290 Console.WriteLine("추가 완료"); 349 Console.WriteLine("추가 완료");
291 } 350 }
......