Package rekall :: Package plugins :: Package windows :: Module dumpcerts
[frames] | no frames]

Source Code for Module rekall.plugins.windows.dumpcerts

  1  # Volatility 
  2  # Copyright (C) 2007-2013 Volatility Foundation 
  3  # Copyright 2013 Google Inc. All Rights Reserved. 
  4  # 
  5  # Authors: 
  6  # Michael Hale Ligh <michael.ligh@mnin.org> 
  7  # Michael Cohen <scudette@google.com> 
  8  # 
  9  # Contributors/References: 
 10  #   ## Based on sslkeyfinder: http://www.trapkit.de/research/sslkeyfinder/ 
 11   
 12  # This program is free software; you can redistribute it and/or modify 
 13  # it under the terms of the GNU General Public License as published by 
 14  # the Free Software Foundation; either version 2 of the License, or (at 
 15  # your option) any later version. 
 16  # 
 17  # This program is distributed in the hope that it will be useful, but 
 18  # WITHOUT ANY WARRANTY; without even the implied warranty of 
 19  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 20  # General Public License for more details. 
 21  # 
 22  # You should have received a copy of the GNU General Public License 
 23  # along with this program; if not, write to the Free Software 
 24  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 25   
 26  try: 
 27      from M2Crypto import X509, RSA 
 28  except ImportError: 
 29      X509 = RSA = None 
 30   
 31  from rekall import plugin 
 32  from rekall import scan 
 33  from rekall import testlib 
 34   
 35  from rekall.plugins import core 
 36  from rekall.plugins import yarascanner 
 37  from rekall.plugins.windows import common 
 38  from rekall.plugins.overlays import basic 
 39  from rekall_lib import utils 
 40   
 41   
42 -class CertScanner(scan.BaseScanner):
43 """A scanner for certificate ASN.1 objects. 44 45 Yara rules for the two ASN.1 encoded objects we are looking for: 46 47 'x509' : 'rule x509 { 48 strings: $a = {30 82 ?? ?? 30 82 ?? ??} condition: $a 49 }', 50 51 'pkcs' : 'rule pkcs { 52 strings: $a = {30 82 ?? ?? 02 01 00} condition: $a 53 }', 54 55 These rules are very simple, and so we don't really use Yara for this - its 56 faster to just scan directly. 57 """ 58 59 checks = [ 60 ('StringCheck', dict(needle="\x30\x82")) 61 ] 62
63 - def scan(self, offset=0, maxlen=None):
64 for hit in super(CertScanner, self).scan(offset=offset, maxlen=maxlen): 65 signature = self.address_space.read(hit + 4, 3) 66 size = self.profile.Object( 67 "unsigned be short", offset=hit+2, vm=self.address_space) 68 description = None 69 70 if signature.startswith("\x30\x82"): 71 data = self.address_space.read(hit, size + 4) 72 if X509: 73 try: 74 cert = X509.load_cert_der_string(data) 75 description = utils.SmartStr(cert.get_subject()) 76 except X509.X509Error: 77 pass 78 79 yield hit, "X509", data, description 80 81 elif signature.startswith("\x02\x01\x00"): 82 data = self.address_space.read(hit, size + 4) 83 if RSA: 84 try: 85 pem = ("-----BEGIN RSA PRIVATE KEY-----\n" + 86 data.encode("base64") + 87 "-----END RSA PRIVATE KEY-----") 88 key = RSA.load_key_string(pem) 89 description = "Verified: %s" % key.check_key() 90 except Exception: 91 pass 92 93 yield hit, "RSA", data, description
94 95
96 -class CertScan(plugin.PhysicalASMixin, plugin.TypedProfileCommand, 97 plugin.Command):
98 """Dump RSA private and public SSL keys from the physical address space.""" 99 __name = "simple_certscan" 100 101 # We can just display the certs instead of dumping them. 102 dump_dir_optional = True 103 default_dump_dir = None 104 105 table_header = [ 106 dict(name="address", style="address"), 107 dict(name="type", width=10), 108 dict(name="length", width=10), 109 dict(name="data", hidden=True), 110 dict(name="description"), 111 ] 112
113 - def collect(self):
114 scanner = CertScanner( 115 address_space=self.physical_address_space, 116 session=self.session, 117 profile=basic.Profile32Bits(session=self.session)) 118 119 for hit, type, data, description in scanner.scan( 120 0, self.physical_address_space.end()): 121 yield dict(address=hit, 122 type=type, 123 length=len(data), 124 data=data, 125 description=description)
126 127
128 -class CertDump(core.DirectoryDumperMixin, CertScan):
129 """Dump certs found by cert scan.""" 130 131 name = "simple_certdump" 132 133 table_header = [ 134 dict(name="address", style="address"), 135 dict(name="type", width=10), 136 dict(name="Filename", width=30), 137 dict(name="description"), 138 ] 139
140 - def collect(self):
141 renderer = self.session.GetRenderer() 142 for row in super(CertDump, self).collect(): 143 if self.dump_dir: 144 row["Filename"] = "%s.%08X.der" % (row["type"], row["address"]) 145 with renderer.open(directory=self.dump_dir, 146 filename=row["Filename"], 147 mode="wb") as fd: 148 fd.write(row["data"]) 149 yield row
150 151
152 -class TestCertDump(testlib.HashChecker):
153 PARAMETERS = dict( 154 commandline="certdump -D %(tempdir)s", 155 )
156 157
158 -class CertYaraScan(yarascanner.YaraScanMixin, common.WinScanner):
159 """Scan certificates in windows memory regions.""" 160 name = "certscan" 161 162 table_header = [ 163 dict(name="Owner", width=20), 164 dict(name="Offset", style="address"), 165 dict(name="type", width=10), 166 dict(name="description", width=80), 167 dict(name="data", hidden=True), 168 dict(name="Context"), 169 ] 170 171 scanner_defaults = dict( 172 scan_physical=True 173 ) 174 175 __args = [ 176 dict(name="yara_file", default=None, hidden=True), 177 dict(name="yara_expression", hidden=True, default=""" 178 rule x509 { 179 strings: $a = {30 82 ?? ?? 30 82 ?? ??} condition: $a 180 } 181 rule pkcs { 182 strings: $a = {30 82 ?? ?? 02 01 00} condition: $a 183 } 184 """), 185 dict(name="hits", default=1000000, type="IntParser", 186 help="Total number of hits to report."), 187 ] 188
189 - def verify_hit(self, hit, address_space):
190 signature = address_space.read(hit + 4, 3) 191 size = self.profile.Object( 192 "unsigned be short", offset=hit+2, vm=address_space) 193 description = None 194 195 if signature.startswith("\x30\x82"): 196 data = address_space.read(hit, size + 4) 197 if X509: 198 try: 199 cert = X509.load_cert_der_string(data) 200 description = utils.SmartStr(cert.get_subject()) 201 except X509.X509Error: 202 pass 203 204 return "X509", data, description 205 206 elif signature.startswith("\x02\x01\x00"): 207 data = address_space.read(hit, size + 4) 208 if RSA: 209 try: 210 pem = ("-----BEGIN RSA PRIVATE KEY-----\n" + 211 data.encode("base64") + 212 "-----END RSA PRIVATE KEY-----") 213 key = RSA.load_key_string(pem) 214 description = "Verified: %s" % key.check_key() 215 except Exception: 216 pass 217 218 return "RSA", data, description 219 220 return None, None, None
221
222 - def collect(self):
223 for row in super(CertYaraScan, self).collect(): 224 type, data, description = self.verify_hit( 225 row["Offset"], row["address_space"]) 226 227 if type is not None: 228 yield dict(Owner=row["Owner"], 229 Offset=row["Offset"], 230 type=type, 231 description=description, 232 Context=row["Context"], 233 data=data)
234 235
236 -class TestCertYaraScan(testlib.SimpleTestCase):
237 PARAMETERS = dict( 238 commandline="certscan --limit %(limit)s", 239 limit=20000000 240 )
241 242
243 -class TestCertVadScan(testlib.HashChecker):
244 PARAMETERS = dict( 245 commandline="cert_vad_scan --proc_regex %(regex)s -D %(tempdir)s ", 246 regex="csrss.exe" 247 )
248