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