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  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   
 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       
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   
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   
 150   
151   
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   
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   
 234   
235   
241   
242   
244      PARAMETERS = dict( 
245          commandline="cert_vad_scan --proc_regex %(regex)s -D %(tempdir)s ", 
246          regex="csrss.exe" 
247          ) 
 248