著者:楠目幹
こんにちは。香川大学工学部 学部4年生の楠目です。高校時代にPCがマルウェアに感染した経験がきっかけでセキュリティに興味を持ち、マルウェア対策やペネトレーションテストに関する分野の勉強を行っています。
昨年の8月「セキュリティ・キャンプ全国大会2017」に参加しました。そこでは「Linux向けマルウェア対策ソフトを作ろう」と言う講義に参加し、「surface indicator+αなELFマルウェアの分類」というテーマに、チームで取り組みました。このテーマの目標は、機械学習や複雑な解析を用いずにELFマルウェアの亜種を素早く検出することです。今回の記事では、私が講師やチューターの方、チームのメンバーと一緒に取り組んだ内容をご紹介します。
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 |
#! /usr/bin/env python3 # VirusTotalのメタデータから特定のアンチウィルスソフトウェアで特定の検出名を持つものを出力 # Usage: ./z2kit_find_virustotal.py import glob import json import sys import z2kit.elf import z2kit.features AV_SOFTWARE = '指定したアンチウィルスソフトウェア' EXPECTED_DETECTION = '対応する検体名' def set_features(elffile): if not isinstance(elffile, z2kit.elf.ELFFile): raise ValueError('ELFFileクラスを与えなければなりません。') elffile.features = {} elffile.features['md5'] = z2kit.features.MD5Feature().get_feature(elffile) elffile.features['ssdeep'] = z2kit.features.SsdeepFeature().get_feature(elffile) elffile.features['lstrfuzzy'] = z2kit.features.LstrfuzzyFeature().get_feature(elffile) with open('virustotal-ELF-VXShare.json') as f: virustotal_info = json.load(f) for filename in glob.glob('z2/VirusShare_*'): try: elffile = z2kit.elf.ELFFile.read_from_file(filename) set_features(elffile) md5 = elffile.features['md5'] if md5 not in virustotal_info: continue if AV_SOFTWARE not in virustotal_info[md5]['scans']: continue if not virustotal_info[md5]['scans'][AV_SOFTWARE]['detected']: continue if virustotal_info[md5]['scans'][AV_SOFTWARE]['result'] != EXPECTED_DETECTION: continue print(filename) except: raise |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#! /usr/bin/env python3 # ファイルリストを受け取ってlstrfuzzyデータを出力 # Usage: ./z2kit_extract_lstrfuzzy.py FILELIST import sys import z2kit.elf import z2kit.features def set_features(elffile): if not isinstance(elffile, z2kit.elf.ELFFile): raise ValueError('ELFファイルを与えなければなりません。') elffile.features = {} elffile.features['md5'] = z2kit.features.MD5Feature().get_feature(elffile) elffile.features['ssdeep'] = z2kit.features.SsdeepFeature().get_feature(elffile) elffile.features['lstrfuzzy'] = z2kit.features.LstrfuzzyFeature().get_feature(elffile) with open(sys.argv[1], 'r') as f: for ln in f: filename = ln[:-1] try: elffile = z2kit.elf.ELFFile.read_from_file(filename) set_features(elffile) print(filename, elffile.features['lstrfuzzy']) except: pass |
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 |
#! /usr/bin/env python3 # z2kit_extract_lstrfuzzy.pyの結果をもとに検出器を作成する # 検出器を使った結果とz2kit_find_virustotal.pyとの結果を比較する # Usage: ./z2_find_match.py import glob import json import sys import z2kit.elf import z2kit.features import ssdeep AV_SOFTWARE = '指定したアンチウィルスソフトウェア' EXPECTED_DETECTION = '対応する検体名' def set_features(elffile): if not isinstance(elffile, z2kit.elf.ELFFile): raise ValueError('ELFFile クラスを与えなければなりません。') elffile.features = {} elffile.features['md5'] = z2kit.features.MD5Feature().get_feature(elffile) elffile.features['ssdeep'] = z2kit.features.SsdeepFeature().get_feature(elffile) elffile.features['lstrfuzzy'] = z2kit.features.LstrfuzzyFeature().get_feature(elffile) def is_malware_to_focus(elffile): return \ ssdeep.compare(elffile.features['lstrfuzzy'], '選出したハッシュ値') >= 50 or \ ssdeep.compare(elffile.features['lstrfuzzy'], '選出したハッシュ値') >= 50 or \ ssdeep.compare(elffile.features['lstrfuzzy'], '選出したハッシュ値') >= 50 for filename in glob.glob('z2/VirusShare_*'): try: elffile = z2kit.elf.ELFFile.read_from_file(filename) set_features(elffile) if is_malware_to_focus(elffile): print(filename) except: pass |
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 |
#! /usr/bin/env python3 # stringsコマンドの結果を特徴量とする # Usage: ./z2kit_find_strings_by_virustotal.py | ./histogram_to_graph.py /dev/stdin > TEXT import glob import json import sys import z2kit.elf import z2kit.features AV_SOFTWARE = '指定したアンチウィルスソフトウェア' EXPECTED_DETECTION = '対応する検体名' def set_features(elffile): if not isinstance(elffile, z2kit.elf.ELFFile): raise ValueError('ELFFile クラスを与えなければなりません。') elffile.features = {} elffile.features['md5'] = z2kit.features.MD5Feature().get_feature(elffile) #elffile.features['ssdeep'] = z2kit.features.SsdeepFeature().get_feature(elffile) #elffile.features['lstrfuzzy'] = z2kit.features.LstrfuzzyFeature().get_feature(elffile) elffile.features['strings'] = z2kit.features.StringsFeature().get_feature(elffile) with open('virustotal-ELF-VXShare.json') as f: virustotal_info = json.load(f) HISTOGRAM = {} for filename in glob.glob('z2/VirusShare_*'): try: elffile = z2kit.elf.ELFFile.read_from_file(filename) set_features(elffile) md5 = elffile.features['md5'] if md5 not in virustotal_info: continue if AV_SOFTWARE not in virustotal_info[md5]['scans']: continue if not virustotal_info[md5]['scans'][AV_SOFTWARE]['detected']: continue if virustotal_info[md5]['scans'][AV_SOFTWARE]['result'] != EXPECTED_DETECTION: continue strings = elffile.features['strings'] for s in strings.keys(): if s not in HISTOGRAM: HISTOGRAM[s] = 0 HISTOGRAM[s] += strings[s] except: pass json.dump(HISTOGRAM, sys.stdout) #! /usr/bin/env python3 # JSONファイルをもとにヒストグラムを作成 # Usage: ./histogram_to_graph.py JSON_FILE import json import sys WIDTH = 40 FILLER = '#' with open(sys.argv[1], 'r', encoding='utf-8') as f: obj = json.load(f) m = 0 for v in obj.values(): m = max(v, m) FORMAT = '{}{} {:' + str(len(str(m))) + 'd} {}' for i, v in sorted(obj.items(), key=lambda x:-x[1]): g = int((WIDTH - 1) * 1.0 * v / m) g = FILLER * g + ' ' * (WIDTH - 1 - g) print(FORMAT.format(FILLER, g, v, i)) |
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 |
#! /usr/bin/env python3 # stringsコマンドの特徴量をもとにz2kit_find_strings_by_virustotal.pyとの結果を比較 # Usage: ./z2kit_find_strings_match.py import glob import json import sys import z2kit.elf import z2kit.features import ssdeep def set_features(elffile): if not isinstance(elffile, z2kit.elf.ELFFile): raise ValueError('ELFFile クラスを与えなければなりません。') elffile.features = {} #elffile.features['md5'] = z2kit.features.MD5Feature().get_feature(elffile) #elffile.features['ssdeep'] = z2kit.features.SsdeepFeature().get_feature(elffile) elffile.features['lstrfuzzy'] = z2kit.features.LstrfuzzyFeature().get_feature(elffile) elffile.features['strings'] = z2kit.features.StringsFeature().get_feature(elffile) def is_strings_matching(elffile, substring): for k in elffile.features['strings'].keys(): if substring in k: return True return False def is_malware_to_focus(elffile): return is_strings_matching(elffile, '特徴量として選出した文字列') for filename in glob.glob('z2/VirusShare_*'): try: elffile = z2kit.elf.ELFFile.read_from_file(filename) set_features(elffile) if is_malware_to_focus(elffile): print(filename) except: pass |