Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
ExtractRegistry.java
Go to the documentation of this file.
1/*
2 *
3 * Autopsy Forensic Browser
4 *
5 * Copyright 2012-2021 Basis Technology Corp.
6 *
7 * Copyright 2012 42six Solutions.
8 * Contact: aebadirad <at> 42six <dot> com
9 * Project Contact/Architect: carrier <at> sleuthkit <dot> org
10 *
11 * Licensed under the Apache License, Version 2.0 (the "License");
12 * you may not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
14 *
15 * http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
22 */
23package org.sleuthkit.autopsy.recentactivity;
24
25import java.io.BufferedReader;
26import java.io.File;
27import java.io.FileInputStream;
28import java.io.FileNotFoundException;
29import java.io.FileReader;
30import java.io.FileWriter;
31import java.io.IOException;
32import java.io.InputStreamReader;
33import java.io.StringReader;
34import java.nio.charset.StandardCharsets;
35import java.text.ParseException;
36import java.text.SimpleDateFormat;
37import java.util.logging.Level;
38import javax.xml.parsers.DocumentBuilder;
39import javax.xml.parsers.ParserConfigurationException;
40import org.apache.commons.io.FilenameUtils;
41import org.openide.modules.InstalledFileLocator;
42import org.openide.util.NbBundle;
43import org.sleuthkit.autopsy.coreutils.ExecUtil;
44import org.sleuthkit.autopsy.coreutils.Logger;
45import org.sleuthkit.autopsy.coreutils.PlatformUtil;
46import org.sleuthkit.autopsy.coreutils.XMLUtil;
47import org.sleuthkit.autopsy.datamodel.ContentUtils;
48import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProcessTerminator;
49import org.sleuthkit.autopsy.ingest.IngestJobContext;
50import org.sleuthkit.autopsy.recentactivity.UsbDeviceIdMapper.USBInfo;
51import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
52import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
53import org.w3c.dom.Document;
54import org.w3c.dom.Element;
55import org.w3c.dom.Node;
56import org.w3c.dom.NodeList;
57import org.xml.sax.InputSource;
58import org.xml.sax.SAXException;
59import java.nio.file.Path;
60import java.util.AbstractMap;
61import java.util.ArrayList;
62import java.util.List;
63import java.util.Collection;
64import java.util.Collections;
65import java.util.Date;
66import java.util.HashMap;
67import java.util.Map;
68import java.util.Scanner;
69import java.util.Set;
70import java.util.HashSet;
71import static java.util.Locale.US;
72import java.util.Optional;
73import static java.util.TimeZone.getTimeZone;
74import java.util.stream.Collectors;
75import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
76import org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException;
77import org.sleuthkit.autopsy.recentactivity.ShellBagParser.ShellBag;
78import org.sleuthkit.datamodel.AbstractFile;
79import org.sleuthkit.datamodel.Account;
80import org.sleuthkit.datamodel.Blackboard.BlackboardException;
81import org.sleuthkit.datamodel.BlackboardArtifact;
82import org.sleuthkit.datamodel.BlackboardAttribute;
83import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT;
84import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME;
85import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED;
86import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED;
87import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED;
88import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID;
89import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME;
90import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH;
91import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_HOME_DIR;
92import org.sleuthkit.datamodel.Content;
93import org.sleuthkit.datamodel.DataSource;
94import org.sleuthkit.datamodel.Host;
95import org.sleuthkit.datamodel.HostManager;
96import org.sleuthkit.datamodel.OsAccount;
97import org.sleuthkit.datamodel.OsAccount.OsAccountAttribute;
98import org.sleuthkit.datamodel.OsAccountInstance;
99import org.sleuthkit.datamodel.OsAccountManager;
100import org.sleuthkit.datamodel.OsAccountManager.NotUserSIDException;
101import org.sleuthkit.datamodel.OsAccountManager.OsAccountUpdateResult;
102import org.sleuthkit.datamodel.OsAccountRealm;
103import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
104import org.sleuthkit.datamodel.Report;
105import org.sleuthkit.datamodel.TskCoreException;
106import org.sleuthkit.datamodel.TskDataException;
107
114@NbBundle.Messages({
115 "RegRipperNotFound=Autopsy RegRipper executable not found.",
116 "RegRipperFullNotFound=Full version RegRipper executable not found.",
117 "Progress_Message_Analyze_Registry=Analyzing Registry Files",
118 "Shellbag_Artifact_Display_Name=Shell Bags",
119 "WSL_Artifact_Display_Name=Windows Subsystem For Linux",
120 "WSL_Kernal_Command_Attribute_Display_Name=Kernal Command",
121 "Shellbag_Key_Attribute_Display_Name=Key",
122 "Shellbag_Last_Write_Attribute_Display_Name=Last Write",
123 "Sam_Security_Question_1_Attribute_Display_Name=Security Question 1",
124 "Sam_Security_Answer_1_Attribute_Display_Name=Security Answer 1",
125 "Sam_Security_Question_2_Attribute_Display_Name=Security Question 2",
126 "Sam_Security_Answer_2_Attribute_Display_Name=Security Answer 2",
127 "Sam_Security_Question_3_Attribute_Display_Name=Security Question 3",
128 "Sam_Security_Answer_3_Attribute_Display_Name=Security Answer 3",
129 "Recently_Used_Artifacts_Office_Trustrecords=Stored in TrustRecords because Office security exception was granted",
130 "Recently_Used_Artifacts_ArcHistory=Recently opened by 7Zip",
131 "Recently_Used_Artifacts_Applets=Recently opened according to Applets registry key",
132 "Recently_Used_Artifacts_Mmc=Recently opened according to Windows Management Console MRU",
133 "Recently_Used_Artifacts_Winrar=Recently opened according to WinRAR MRU",
134 "Recently_Used_Artifacts_Officedocs=Recently opened according to Office MRU",
135 "Recently_Used_Artifacts_Adobe=Recently opened according to Adobe MRU",
136 "Recently_Used_Artifacts_Mediaplayer=Recently opened according to Media Player MRU",
137 "Recently_Used_Artifacts_WSL=Windows Subsystem For Linux",
138 "Registry_System_Bam=Recently Executed according to Background Activity Moderator (BAM)"
139})
140class ExtractRegistry extends Extract {
141
142 private static final String USERNAME_KEY = "Username"; //NON-NLS
143 private static final String SID_KEY = "SID"; //NON-NLS
144 private static final String RID_KEY = "RID"; //NON-NLS
145 private static final String ACCOUNT_CREATED_KEY = "Account Created"; //NON-NLS
146 private static final String LAST_LOGIN_KEY = "Last Login Date"; //NON-NLS
147 private static final String LOGIN_COUNT_KEY = "Login Count"; //NON-NLS
148 private static final String FULL_NAME_KEY = "Full Name"; //NON-NLS
149 private static final String USER_COMMENT_KEY = "User Comment"; //NON-NLS
150 private static final String ACCOUNT_TYPE_KEY = "Account Type"; //NON-NLS
151 private static final String NAME_KEY = "Name"; //NON-NLS
152 private static final String PWD_RESET_KEY = "Pwd Rest Date"; //NON-NLS
153 private static final String PWD_FAILE_KEY = "Pwd Fail Date"; //NON-NLS
154 private static final String INTERNET_NAME_KEY = "InternetName"; //NON-NLS
155 private static final String PWD_DOES_NOT_EXPIRE_KEY = "Password does not expire"; //NON-NLS
156 private static final String ACCOUNT_DISABLED_KEY = "Account Disabled"; //NON-NLS
157 private static final String PWD_NOT_REQUIRED_KEY = "Password not required"; //NON-NLS
158 private static final String NORMAL_ACCOUNT_KEY = "Normal user account"; //NON-NLS
159 private static final String HOME_DIRECTORY_REQUIRED_KEY = "Home directory required";
160 private static final String TEMPORARY_DUPLICATE_ACCOUNT = "Temporary duplicate account";
161 private static final String MNS_LOGON_ACCOUNT_KEY = "MNS logon user account";
162 private static final String INTERDOMAIN_TRUST_ACCOUNT_KEY = "Interdomain trust account";
163 private static final String WORKSTATION_TRUST_ACCOUNT = "Workstation trust account";
164 private static final String SERVER_TRUST_ACCOUNT = "Server trust account";
165 private static final String ACCOUNT_AUTO_LOCKED = "Account auto locked";
166 private static final String PASSWORD_HINT = "Password Hint";
167 private static final String SECURITY_QUESTION_1 = "Question 1";
168 private static final String SECURITY_ANSWER_1 = "Answer 1";
169 private static final String SECURITY_QUESTION_2 = "Question 2";
170 private static final String SECURITY_ANSWER_2 = "Answer 2";
171 private static final String SECURITY_QUESTION_3 = "Question 3";
172 private static final String SECURITY_ANSWER_3 = "Answer 3";
173
174 private static final String[] PASSWORD_SETTINGS_FLAGS = {PWD_DOES_NOT_EXPIRE_KEY, PWD_NOT_REQUIRED_KEY};
175 private static final String[] ACCOUNT_SETTINGS_FLAGS = {ACCOUNT_AUTO_LOCKED, HOME_DIRECTORY_REQUIRED_KEY, ACCOUNT_DISABLED_KEY};
176 private static final String[] ACCOUNT_TYPE_FLAGS = {NORMAL_ACCOUNT_KEY, SERVER_TRUST_ACCOUNT, WORKSTATION_TRUST_ACCOUNT, INTERDOMAIN_TRUST_ACCOUNT_KEY, MNS_LOGON_ACCOUNT_KEY, TEMPORARY_DUPLICATE_ACCOUNT};
177
178 final private static UsbDeviceIdMapper USB_MAPPER = new UsbDeviceIdMapper();
179 final private static String RIP_EXE = "rip.exe";
180 final private static String RIP_PL = "rip.pl";
181 final private static String RIP_PL_INCLUDE_FLAG = "-I";
182 final private static int MS_IN_SEC = 1000;
183 final private static String NEVER_DATE = "Never";
184 final private static String SECTION_DIVIDER = "----------------------------------------";
185 final private static Logger logger = Logger.getLogger(ExtractRegistry.class.getName());
186 private final List<String> rrCmd = new ArrayList<>();
187 private final List<String> rrFullCmd = new ArrayList<>();
188 private final Path rrHome; // Path to the Autopsy version of RegRipper
189 private final Path rrFullHome; // Path to the full version of RegRipper
190 private Content dataSource;
191 private final IngestJobContext context;
192 private Map<String, String> userNameMap;
193 private final List<String> samDomainIDsList = new ArrayList<>();
194
195 private String compName = "";
196 private String domainName = "";
197
198 private static final String WSL_ARTIFACT_NAME = "WSL_NAME"; //NON-NLS
199 private static final String SHELLBAG_ARTIFACT_NAME = "RA_SHELL_BAG"; //NON-NLS
200 private static final String SHELLBAG_ATTRIBUTE_LAST_WRITE = "RA_SHELL_BAG_LAST_WRITE"; //NON-NLS
201 private static final String WSL_ATTRIBUTE_KERNAL_COMMAND = "WSL_KERNAL_COMMAND"; //NON-NLS
202 private static final String SHELLBAG_ATTRIBUTE_KEY = "RA_SHELL_BAG_KEY"; //NON-NLS
203 private static final String SAM_SECURITY_QUESTION_1 = "RA_SAM_QUESTION_1"; //NON-NLS;
204 private static final String SAM_SECURITY_ANSWER_1 = "RA_SAM_ANSWER_1"; //NON-NLS;
205 private static final String SAM_SECURITY_QUESTION_2 = "RA_SAM_QUESTION_2"; //NON-NLS;
206 private static final String SAM_SECURITY_ANSWER_2 = "RA_SAM_ANSWER_2"; //NON-NLS;
207 private static final String SAM_SECURITY_QUESTION_3 = "RA_SAM_QUESTION_3"; //NON-NLS;
208 private static final String SAM_SECURITY_ANSWER_3 = "RA_SAM_ANSWER_3"; //NON-NLS;
209
210
211 private static final SimpleDateFormat REG_RIPPER_TIME_FORMAT = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy 'Z'", US);
212
213 private BlackboardArtifact.Type wslArtifactType = null;
214 private BlackboardArtifact.Type shellBagArtifactType = null;
215 private BlackboardAttribute.Type kernalCommandAttributeType = null;
216 private BlackboardAttribute.Type shellBagKeyAttributeType = null;
217 private BlackboardAttribute.Type shellBagLastWriteAttributeType = null;
218
219 private OSInfo osInfo = new OSInfo();
220
221 static {
222 REG_RIPPER_TIME_FORMAT.setTimeZone(getTimeZone("GMT"));
223 }
224
225 ExtractRegistry(IngestJobContext context) throws IngestModuleException {
226 super(NbBundle.getMessage(ExtractRegistry.class, "ExtractRegistry.moduleName.text"), context);
227 this.context = context;
228
229 final File rrRoot = InstalledFileLocator.getDefault().locate("rr", ExtractRegistry.class.getPackage().getName(), false); //NON-NLS
230 if (rrRoot == null) {
231 throw new IngestModuleException(Bundle.RegRipperNotFound());
232 }
233
234 final File rrFullRoot = InstalledFileLocator.getDefault().locate("rr-full", ExtractRegistry.class.getPackage().getName(), false); //NON-NLS
235 if (rrFullRoot == null) {
236 throw new IngestModuleException(Bundle.RegRipperFullNotFound());
237 }
238
239 String executableToRun = RIP_EXE;
240 if (!PlatformUtil.isWindowsOS()) {
241 executableToRun = RIP_PL;
242 }
243 rrHome = rrRoot.toPath();
244 String rrPath = rrHome.resolve(executableToRun).toString();
245 rrFullHome = rrFullRoot.toPath();
246
247 if (!(new File(rrPath).exists())) {
248 throw new IngestModuleException(Bundle.RegRipperNotFound());
249 }
250 String rrFullPath = rrFullHome.resolve(executableToRun).toString();
251 if (!(new File(rrFullPath).exists())) {
252 throw new IngestModuleException(Bundle.RegRipperFullNotFound());
253 }
255 rrCmd.add(rrPath);
256 rrFullCmd.add(rrFullPath);
257 } else {
258 String perl;
259 File usrBin = new File("/usr/bin/perl");
260 File usrLocalBin = new File("/usr/local/bin/perl");
261 if (usrBin.canExecute() && usrBin.exists() && !usrBin.isDirectory()) {
262 perl = "/usr/bin/perl";
263 } else if (usrLocalBin.canExecute() && usrLocalBin.exists() && !usrLocalBin.isDirectory()) {
264 perl = "/usr/local/bin/perl";
265 } else {
266 throw new IngestModuleException("perl not found in your system");
267 }
268 rrCmd.add(perl);
269 rrCmd.add(RIP_PL_INCLUDE_FLAG);
270 rrCmd.add(rrHome.toString());
271 rrCmd.add(rrPath);
272 rrFullCmd.add(perl);
273 rrFullCmd.add(RIP_PL_INCLUDE_FLAG);
274 rrFullCmd.add(rrFullHome.toString());
275 rrFullCmd.add(rrFullPath);
276 }
277 }
278
282 private List<AbstractFile> findRegistryFiles() {
283 List<AbstractFile> allRegistryFiles = new ArrayList<>();
284 org.sleuthkit.autopsy.casemodule.services.FileManager fileManager = currentCase.getServices().getFileManager();
285
286 // find the sam hives', process this first so we can map the user id's and sids for later use
287 try {
288 allRegistryFiles.addAll(fileManager.findFiles(dataSource, "sam", "/system32/config")); //NON-NLS
289 } catch (TskCoreException ex) {
290 String msg = NbBundle.getMessage(this.getClass(),
291 "ExtractRegistry.findRegFiles.errMsg.errReadingFile", "sam");
292 logger.log(Level.WARNING, msg, ex);
293 this.addErrorMessage(this.getDisplayName() + ": " + msg);
294 }
295
296 // find the user-specific ntuser-dat files
297 try {
298 allRegistryFiles.addAll(fileManager.findFiles(dataSource, "ntuser.dat")); //NON-NLS
299 } catch (TskCoreException ex) {
300 logger.log(Level.WARNING, "Error fetching 'ntuser.dat' file."); //NON-NLS
301 }
302
303 // find the user-specific ntuser-dat files
304 try {
305 allRegistryFiles.addAll(fileManager.findFiles(dataSource, "usrclass.dat")); //NON-NLS
306 } catch (TskCoreException ex) {
307 logger.log(Level.WARNING, String.format("Error finding 'usrclass.dat' files."), ex); //NON-NLS
308 }
309
310 // find the system hives'
311 String[] regFileNames = new String[]{"system", "software", "security"}; //NON-NLS
312 for (String regFileName : regFileNames) {
313 try {
314 allRegistryFiles.addAll(fileManager.findFiles(dataSource, regFileName, "/system32/config")); //NON-NLS
315 } catch (TskCoreException ex) {
316 String msg = NbBundle.getMessage(this.getClass(),
317 "ExtractRegistry.findRegFiles.errMsg.errReadingFile", regFileName);
318 logger.log(Level.WARNING, msg, ex);
319 this.addErrorMessage(this.getDisplayName() + ": " + msg);
320 }
321 }
322 return allRegistryFiles;
323 }
324
331 private void analyzeRegistryFiles(long ingestJobId) {
332 List<AbstractFile> allRegistryFiles = findRegistryFiles();
333
334 // open the log file
335 FileWriter logFile = null;
336 try {
337 logFile = new FileWriter(RAImageIngestModule.getRAOutputPath(currentCase, "reg", ingestJobId) + File.separator + "regripper-info.txt"); //NON-NLS
338 } catch (IOException ex) {
339 logger.log(Level.SEVERE, null, ex);
340 }
341
342 for (AbstractFile regFile : allRegistryFiles) {
343 if (context.dataSourceIngestIsCancelled()) {
344 return;
345 }
346
347 String regFileName = regFile.getName();
348 long regFileId = regFile.getId();
349 String regFileNameLocal = RAImageIngestModule.getRATempPath(currentCase, "reg", ingestJobId) + File.separator + regFileName;
350 String outputPathBase = RAImageIngestModule.getRAOutputPath(currentCase, "reg", ingestJobId) + File.separator + regFileName + "-regripper-" + Long.toString(regFileId); //NON-NLS
351 File regFileNameLocalFile = new File(regFileNameLocal);
352 try {
353 ContentUtils.writeToFile(regFile, regFileNameLocalFile, context::dataSourceIngestIsCancelled);
354 } catch (ReadContentInputStreamException ex) {
355 logger.log(Level.WARNING, String.format("Error reading registry file '%s' (id=%d).",
356 regFile.getName(), regFileId), ex); //NON-NLS
357 this.addErrorMessage(
358 NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.errMsg.errWritingTemp",
359 this.getDisplayName(), regFileName));
360 continue;
361 } catch (IOException ex) {
362 logger.log(Level.SEVERE, String.format("Error writing temp registry file '%s' for registry file '%s' (id=%d).",
363 regFileNameLocal, regFile.getName(), regFileId), ex); //NON-NLS
364 this.addErrorMessage(
365 NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.errMsg.errWritingTemp",
366 this.getDisplayName(), regFileName));
367 continue;
368 }
369
370 if (context.dataSourceIngestIsCancelled()) {
371 break;
372 }
373
374 try {
375 if (logFile != null) {
376 logFile.write(Long.toString(regFileId) + "\t" + regFile.getUniquePath() + "\n");
377 }
378 } catch (TskCoreException | IOException ex) {
379 logger.log(Level.SEVERE, null, ex);
380 }
381
382 logger.log(Level.INFO, "{0}- Now getting registry information from {1}", new Object[]{getDisplayName(), regFileNameLocal}); //NON-NLS
383 RegOutputFiles regOutputFiles = ripRegistryFile(regFileNameLocal, outputPathBase);
384 if (context.dataSourceIngestIsCancelled()) {
385 break;
386 }
387
388 // parse the autopsy-specific output
389 if (regOutputFiles.autopsyPlugins.isEmpty() == false && parseAutopsyPluginOutput(regOutputFiles.autopsyPlugins, regFile) == false) {
390 this.addErrorMessage(
391 NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.failedParsingResults",
392 this.getDisplayName(), regFileName));
393 }
394
395 if (context.dataSourceIngestIsCancelled()) {
396 return;
397 }
398
399 // create a report for the full output
400 if (!regOutputFiles.fullPlugins.isEmpty()) {
401 //parse the full regripper output from SAM hive files
402 if (regFileNameLocal.toLowerCase().contains("sam") && parseSamPluginOutput(regOutputFiles.fullPlugins, regFile, ingestJobId) == false) {
403 this.addErrorMessage(
404 NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.failedParsingResults",
405 this.getDisplayName(), regFileName));
406 } else if (regFileNameLocal.toLowerCase().contains("ntuser") || regFileNameLocal.toLowerCase().contains("usrclass")) {
407 try {
408 List<ShellBag> shellbags = ShellBagParser.parseShellbagOutput(regOutputFiles.fullPlugins);
409 createShellBagArtifacts(regFile, shellbags);
410 createRecentlyUsedArtifacts(regOutputFiles.fullPlugins, regFile);
411 } catch (IOException | TskCoreException ex) {
412 logger.log(Level.WARNING, String.format("Unable to get shell bags from file %s", regOutputFiles.fullPlugins), ex);
413 }
414 } else if (regFileNameLocal.toLowerCase().contains("system") && parseSystemPluginOutput(regOutputFiles.fullPlugins, regFile) == false) {
415 this.addErrorMessage(
416 NbBundle.getMessage(this.getClass(), "ExtractRegistry.analyzeRegFiles.failedParsingResults",
417 this.getDisplayName(), regFileName));
418 }
419
420 if (context.dataSourceIngestIsCancelled()) {
421 return;
422 }
423
424 try {
425 Report report = currentCase.addReport(regOutputFiles.fullPlugins,
426 NbBundle.getMessage(this.getClass(), "ExtractRegistry.parentModuleName.noSpace"),
427 "RegRipper " + regFile.getUniquePath(), regFile); //NON-NLS
428 } catch (TskCoreException e) {
429 this.addErrorMessage("Error adding regripper output as Autopsy report: " + e.getLocalizedMessage()); //NON-NLS
430 }
431 }
432 // delete the hive
433 regFileNameLocalFile.delete();
434 }
435
436 // RA can be run on non-window images. We are going to assume that
437 // the data source was from windows if there was registry files.
438 // Therefore we will only create the OSInfo object if there are
439 // registry files.
440 if(allRegistryFiles.size() > 0) {
441 osInfo.createOSInfo();
442 }
443
444 try {
445 if (logFile != null) {
446 logFile.close();
447 }
448 } catch (IOException ex) {
449 logger.log(Level.SEVERE, null, ex);
450 }
451 }
452
460 private RegOutputFiles ripRegistryFile(String regFilePath, String outFilePathBase) {
461 String autopsyType = ""; // Type argument for rr for autopsy-specific modules
462 String fullType; // Type argument for rr for full set of modules
463
464 RegOutputFiles regOutputFiles = new RegOutputFiles();
465
466 if (regFilePath.toLowerCase().contains("system")) { //NON-NLS
467 autopsyType = "autopsysystem"; //NON-NLS
468 fullType = "system"; //NON-NLS
469 } else if (regFilePath.toLowerCase().contains("software")) { //NON-NLS
470 autopsyType = "autopsysoftware"; //NON-NLS
471 fullType = "software"; //NON-NLS
472 } else if (regFilePath.toLowerCase().contains("ntuser")) { //NON-NLS
473 autopsyType = "autopsyntuser"; //NON-NLS
474 fullType = "ntuser"; //NON-NLS
475 } else if (regFilePath.toLowerCase().contains("sam")) { //NON-NLS
476 //fullType sam output files are parsed for user information
477 fullType = "sam"; //NON-NLS
478 } else if (regFilePath.toLowerCase().contains("security")) { //NON-NLS
479 fullType = "security"; //NON-NLS
480 } else if (regFilePath.toLowerCase().contains("usrclass")) { //NON-NLS
481 fullType = "usrclass"; //NON-NLS
482 } else {
483 return regOutputFiles;
484 }
485
486 // run the autopsy-specific set of modules
487 if (!autopsyType.isEmpty()) {
488 regOutputFiles.autopsyPlugins = outFilePathBase + "-autopsy.txt"; //NON-NLS
489 String errFilePath = outFilePathBase + "-autopsy.err.txt"; //NON-NLS
490 logger.log(Level.INFO, "Writing RegRipper results to: {0}", regOutputFiles.autopsyPlugins); //NON-NLS
491 executeRegRipper(rrCmd, rrHome, regFilePath, autopsyType, regOutputFiles.autopsyPlugins, errFilePath);
492 }
493 if (context.dataSourceIngestIsCancelled()) {
494 return regOutputFiles;
495 }
496
497 // run the full set of rr modules
498 if (!fullType.isEmpty()) {
499 regOutputFiles.fullPlugins = outFilePathBase + "-full.txt"; //NON-NLS
500 String errFilePath = outFilePathBase + "-full.err.txt"; //NON-NLS
501 logger.log(Level.INFO, "Writing Full RegRipper results to: {0}", regOutputFiles.fullPlugins); //NON-NLS
502 executeRegRipper(rrFullCmd, rrFullHome, regFilePath, fullType, regOutputFiles.fullPlugins, errFilePath);
503 try {
504 scanErrorLogs(errFilePath);
505 } catch (IOException ex) {
506 logger.log(Level.SEVERE, String.format("Unable to run RegRipper on %s", regFilePath), ex); //NON-NLS
507 this.addErrorMessage(NbBundle.getMessage(this.getClass(), "ExtractRegistry.execRegRip.errMsg.failedAnalyzeRegFile", this.getDisplayName(), regFilePath));
508 }
509 }
510 return regOutputFiles;
511 }
512
513 private void scanErrorLogs(String errFilePath) throws IOException {
514 File regfile = new File(errFilePath);
515 try (BufferedReader reader = new BufferedReader(new FileReader(regfile))) {
516 String line = reader.readLine();
517 while (line != null) {
518 line = line.trim();
519 if (line.toLowerCase().contains("error") || line.toLowerCase().contains("@inc")) {
520 logger.log(Level.WARNING, "Regripper file {0} contains errors from run", errFilePath); //NON-NLS
521
522 }
523 line = reader.readLine();
524 }
525 }
526 }
527
528 private void executeRegRipper(List<String> regRipperPath, Path regRipperHomeDir, String hiveFilePath, String hiveFileType, String outputFile, String errFile) {
529 try {
530 List<String> commandLine = new ArrayList<>();
531 for (String cmd : regRipperPath) {
532 commandLine.add(cmd);
533 }
534 commandLine.add("-r"); //NON-NLS
535 commandLine.add(hiveFilePath);
536 commandLine.add("-f"); //NON-NLS
537 commandLine.add(hiveFileType);
538
539 ProcessBuilder processBuilder = new ProcessBuilder(commandLine);
540 processBuilder.directory(regRipperHomeDir.toFile()); // RegRipper 2.8 has to be run from its own directory
541 processBuilder.redirectOutput(new File(outputFile));
542 processBuilder.redirectError(new File(errFile));
543 ExecUtil.execute(processBuilder, new DataSourceIngestModuleProcessTerminator(context, true));
544 } catch (IOException ex) {
545 logger.log(Level.SEVERE, String.format("Error running RegRipper on %s", hiveFilePath), ex); //NON-NLS
546 this.addErrorMessage(NbBundle.getMessage(this.getClass(), "ExtractRegistry.execRegRip.errMsg.failedAnalyzeRegFile", this.getDisplayName(), hiveFilePath));
547 }
548 }
549
550 // @@@ VERIFY that we are doing the right thing when we parse multiple NTUSER.DAT
559 private boolean parseAutopsyPluginOutput(String regFilePath, AbstractFile regFile) {
560 FileInputStream fstream = null;
561 List<BlackboardArtifact> newArtifacts = new ArrayList<>();
562 String parentModuleName = RecentActivityExtracterModuleFactory.getModuleName();
563 try {
564 // Read the file in and create a Document and elements
565 File regfile = new File(regFilePath);
566 fstream = new FileInputStream(regfile);
567 String regString = new Scanner(fstream, "UTF-8").useDelimiter("\\Z").next(); //NON-NLS
568 String startdoc = "<?xml version=\"1.0\"?><document>"; //NON-NLS
569 String result = regString.replaceAll("----------------------------------------", "");
570 result = result.replaceAll("\\n", ""); //NON-NLS
571 result = result.replaceAll("\\r", ""); //NON-NLS
572 result = result.replaceAll("'", "&apos;"); //NON-NLS
573 result = result.replaceAll("&", "&amp;"); //NON-NLS
574 result = result.replace('\0', ' '); // NON-NLS
575 String enddoc = "</document>"; //NON-NLS
576 String stringdoc = startdoc + result + enddoc;
577 DocumentBuilder builder = XMLUtil.getDocumentBuilder();
578 Document doc = builder.parse(new InputSource(new StringReader(stringdoc)));
579
580 // cycle through the elements in the doc
581 Element oroot = doc.getDocumentElement();
582 NodeList children = oroot.getChildNodes();
583 int len = children.getLength();
584 for (int i = 0; i < len; i++) {
585
586 if (context.dataSourceIngestIsCancelled()) {
587 return false;
588 }
589
590 Element tempnode = (Element) children.item(i);
591
592 String dataType = tempnode.getNodeName();
593 NodeList timenodes = tempnode.getElementsByTagName("mtime"); //NON-NLS
594 Long mtime = null;
595 if (timenodes.getLength() > 0) {
596 Element timenode = (Element) timenodes.item(0);
597 String etime = timenode.getTextContent().trim();
598 //sometimes etime will be an empty string and therefore can not be parsed into a date
599 if (etime != null && !etime.isEmpty()) {
600 try {
601 mtime = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy", US).parse(etime).getTime();
602 String Tempdate = mtime.toString();
603 mtime = Long.valueOf(Tempdate) / MS_IN_SEC;
604 } catch (ParseException ex) {
605 logger.log(Level.WARNING, "Failed to parse epoch time when parsing the registry.", ex); //NON-NLS
606 }
607 }
608 }
609
610 NodeList artroots = tempnode.getElementsByTagName("artifacts"); //NON-NLS
611 if (artroots.getLength() == 0) {
612 // If there isn't an artifact node, skip this entry
613 continue;
614 }
615
616 Element artroot = (Element) artroots.item(0);
617 NodeList myartlist = artroot.getChildNodes();
618
619 // If all artifact nodes should really go under one Blackboard artifact, need to process it differently
620 switch (dataType) {
621 case "WinVersion": //NON-NLS
622 String version = "";
623 String systemRoot = "";
624 String productId = "";
625 String regOwner = "";
626 String regOrg = "";
627 Long installtime = null;
628 for (int j = 0; j < myartlist.getLength(); j++) {
629 Node artchild = myartlist.item(j);
630 // If it has attributes, then it is an Element (based off API)
631 if (artchild.hasAttributes()) {
632 Element artnode = (Element) artchild;
633
634 String value = artnode.getTextContent();
635 if (value != null) {
636 value = value.trim();
637 }
638 String name = artnode.getAttribute("name"); //NON-NLS
639 if (name == null) {
640 continue;
641 }
642 switch (name) {
643 case "ProductName": // NON-NLS
644 version = value;
645 break;
646 case "CSDVersion": // NON-NLS
647 // This is dependant on the fact that ProductName shows up first in the module output
648 version = version + " " + value;
649 break;
650 case "SystemRoot": //NON-NLS
651 systemRoot = value;
652 break;
653 case "ProductId": //NON-NLS
654 productId = value;
655 break;
656 case "RegisteredOwner": //NON-NLS
657 regOwner = value;
658 break;
659 case "RegisteredOrganization": //NON-NLS
660 regOrg = value;
661 break;
662 case "InstallDate": //NON-NLS
663 if (value != null && !value.isEmpty()) {
664 try {
665 installtime = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyyZ", US).parse(value + "+0000").getTime();
666 String Tempdate = installtime.toString();
667 installtime = Long.valueOf(Tempdate) / MS_IN_SEC;
668 } catch (ParseException e) {
669 logger.log(Level.WARNING, "RegRipper::Conversion on DateTime -> ", e); //NON-NLS
670 }
671 }
672 break;
673 default:
674 break;
675 }
676 }
677 }
678
679 osInfo.setOsName(version);
680 osInfo.setInstalltime(installtime);
681 osInfo.setSystemRoot(systemRoot);
682 osInfo.setProductId(productId);
683 osInfo.setRegOwner(regOwner);
684 osInfo.setRegOrg(regOrg);
685 break;
686 case "Profiler": // NON-NLS
687 String os = "";
688 String procArch = "";
689 String tempDir = "";
690 for (int j = 0; j < myartlist.getLength(); j++) {
691 Node artchild = myartlist.item(j);
692 // If it has attributes, then it is an Element (based off API)
693 if (artchild.hasAttributes()) {
694 Element artnode = (Element) artchild;
695
696 String value = artnode.getTextContent().trim();
697 String name = artnode.getAttribute("name"); //NON-NLS
698 switch (name) {
699 case "OS": // NON-NLS
700 os = value;
701 break;
702 case "PROCESSOR_ARCHITECTURE": // NON-NLS
703 procArch = value;
704 break;
705 case "PROCESSOR_IDENTIFIER": //NON-NLS
706 break;
707 case "TEMP": //NON-NLS
708 tempDir = value;
709 break;
710 default:
711 break;
712 }
713 }
714 }
715
716 osInfo.setOsName(os);
717 osInfo.setProcessorArchitecture(procArch);
718 osInfo.setTempDir(tempDir);
719 break;
720 case "CompName": // NON-NLS
721 for (int j = 0; j < myartlist.getLength(); j++) {
722 Node artchild = myartlist.item(j);
723 // If it has attributes, then it is an Element (based off API)
724 if (artchild.hasAttributes()) {
725 Element artnode = (Element) artchild;
726
727 String value = artnode.getTextContent().trim();
728 String name = artnode.getAttribute("name"); //NON-NLS
729
730 if (name.equals("ComputerName")) { // NON-NLS
731 compName = value;
732 } else if (name.equals("Domain")) { // NON-NLS
733 domainName = value;
734 }
735 }
736 }
737
738 osInfo.setCompName(compName);
739 osInfo.setDomain(domainName);
740
741 for (Map.Entry<String, String> userMap : getUserNameMap().entrySet()) {
742 String sid = "";
743 try {
744 sid = userMap.getKey();
745 String userName = userMap.getValue();
746 // Accounts in the SAM are all local accounts
747 createOrUpdateOsAccount(regFile, sid, userName, null, null, OsAccountRealm.RealmScope.LOCAL);
748 } catch (TskCoreException | TskDataException | NotUserSIDException ex) {
749 logger.log(Level.WARNING, String.format("Failed to update Domain for existing OsAccount: %s, sid: %s", regFile.getId(), sid), ex);
750 }
751 }
752
753 break;
754 default:
755 for (int j = 0; j < myartlist.getLength(); j++) {
756 Node artchild = myartlist.item(j);
757 // If it has attributes, then it is an Element (based off API)
758 if (artchild.hasAttributes()) {
759 Element artnode = (Element) artchild;
760
761 String value = artnode.getTextContent().trim();
762 Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
763
764 switch (dataType) {
765 case "recentdocs": //NON-NLS
766 // BlackboardArtifact bbart = tskCase.getContentById(orgId).newArtifact(ARTIFACT_TYPE.TSK_RECENT_OBJECT);
767 // bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "RecentActivity", dataType, mtime));
768 // bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME.getTypeID(), "RecentActivity", dataType, mtimeItem));
769 // bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE.getTypeID(), "RecentActivity", dataType, value));
770 // bbart.addAttributes(bbattributes);
771 // @@@ BC: Why are we ignoring this...
772 break;
773 case "usb": //NON-NLS
774 try {
775 Long usbMtime = Long.valueOf("0");
776 if (!artnode.getAttribute("mtime").isEmpty()) {
777 usbMtime = Long.parseLong(artnode.getAttribute("mtime")); //NON-NLS
778 }
779 usbMtime = Long.valueOf(usbMtime.toString());
780 if (usbMtime > 0) {
781 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME, parentModuleName, usbMtime));
782 }
783 String dev = artnode.getAttribute("dev"); //NON-NLS
784 String make = "";
785 String model = dev;
786 if (dev.toLowerCase().contains("vid")) { //NON-NLS
787 USBInfo info = USB_MAPPER.parseAndLookup(dev);
788 if (info.getVendor() != null) {
789 make = info.getVendor();
790 }
791 if (info.getProduct() != null) {
792 model = info.getProduct();
793 }
794 }
795 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE, parentModuleName, make));
796 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL, parentModuleName, model));
797 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_ID, parentModuleName, value));
798 newArtifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_DEVICE_ATTACHED, regFile, bbattributes));
799 } catch (TskCoreException ex) {
800 logger.log(Level.SEVERE, String.format("Error adding device_attached artifact to blackboard for file %d.", regFile.getId()), ex); //NON-NLS
801 }
802 break;
803 case "uninstall": //NON-NLS
804 Long itemMtime = null;
805 try {
806 String mTimeAttr = artnode.getAttribute("mtime");
807 if (mTimeAttr != null && !mTimeAttr.isEmpty()) {
808 itemMtime = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy", US).parse(mTimeAttr).getTime(); //NON-NLS
809 itemMtime /= MS_IN_SEC;
810 }
811 } catch (ParseException ex) {
812 logger.log(Level.SEVERE, "Failed to parse epoch time for installed program artifact.", ex); //NON-NLS
813 }
814
815 try {
816 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME, parentModuleName, value));
817 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME, parentModuleName, itemMtime));
818 BlackboardArtifact bbart = regFile.newDataArtifact(new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_INSTALLED_PROG), bbattributes);
819 newArtifacts.add(bbart);
820 } catch (TskCoreException ex) {
821 logger.log(Level.SEVERE, "Error adding installed program artifact to blackboard.", ex); //NON-NLS
822 }
823 break;
824 case "office": //NON-NLS
825 String officeName = artnode.getAttribute("name"); //NON-NLS
826
827 try {
828 // @@@ BC: Consider removing this after some more testing. It looks like an Mtime associated with the root key and not the individual item
829 if (mtime != null) {
830 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED, parentModuleName, mtime));
831 }
832 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, parentModuleName, officeName));
833 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE, parentModuleName, value));
834 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME, parentModuleName, artnode.getNodeName()));
835 BlackboardArtifact bbart = regFile.newDataArtifact(new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_RECENT_OBJECT), bbattributes);
836
837 newArtifacts.add(bbart);
838 } catch (TskCoreException ex) {
839 logger.log(Level.SEVERE, "Error adding recent object artifact to blackboard.", ex); //NON-NLS
840 }
841 break;
842
843 case "ProcessorArchitecture": //NON-NLS
844 // Architecture is now included under Profiler
845 //try {
846 // String processorArchitecture = value;
847 // if (processorArchitecture.equals("AMD64"))
848 // processorArchitecture = "x86-64";
849
850 // BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_OS_INFO);
851 // bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROCESSOR_ARCHITECTURE.getTypeID(), parentModuleName, processorArchitecture));
852 // bbart.addAttributes(bbattributes);
853 //} catch (TskCoreException ex) {
854 // logger.log(Level.SEVERE, "Error adding os info artifact to blackboard."); //NON-NLS
855 //}
856 break;
857
858 case "ProfileList": //NON-NLS
859 String homeDir = value;
860 String sid = artnode.getAttribute("sid"); //NON-NLS
861 String username = artnode.getAttribute("username"); //NON-NLS
862 String domName = domainName;
863
864 // accounts in profileList can be either domain or local
865 // Assume domain unless the SID was seen before in the SAM (which is only local).
866 OsAccountRealm.RealmScope scope = OsAccountRealm.RealmScope.DOMAIN;
867 if (isDomainIdInSAMList(sid)) {
868 domName = null;
869 scope = OsAccountRealm.RealmScope.LOCAL;
870 }
871
872 try {
873 createOrUpdateOsAccount(regFile, sid, username, homeDir, domName, scope);
874 } catch (TskCoreException | TskDataException | NotUserSIDException ex) {
875 logger.log(Level.SEVERE, String.format("Failed to create OsAccount for file: %s, sid: %s", regFile.getId(), sid), ex);
876 }
877 break;
878
879 case "NtuserNetwork": // NON-NLS
880 try {
881 String localPath = artnode.getAttribute("localPath"); //NON-NLS
882 String remoteName = value;
883
884 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LOCAL_PATH,
885 parentModuleName, localPath));
886 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REMOTE_PATH,
887 parentModuleName, remoteName));
888 BlackboardArtifact bbart = regFile.newDataArtifact(new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_REMOTE_DRIVE), bbattributes);
889 newArtifacts.add(bbart);
890 } catch (TskCoreException ex) {
891 logger.log(Level.SEVERE, "Error adding network artifact to blackboard.", ex); //NON-NLS
892 }
893 break;
894 case "SSID": // NON-NLS
895 String adapter = artnode.getAttribute("adapter"); //NON-NLS
896 try {
897 Long lastWriteTime = Long.parseLong(artnode.getAttribute("writeTime")); //NON-NLS
898 lastWriteTime = Long.valueOf(lastWriteTime.toString());
899 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SSID, parentModuleName, value));
900 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME, parentModuleName, lastWriteTime));
901 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_ID, parentModuleName, adapter));
902 BlackboardArtifact bbart = regFile.newDataArtifact(new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_WIFI_NETWORK), bbattributes);
903 newArtifacts.add(bbart);
904 } catch (TskCoreException ex) {
905 logger.log(Level.SEVERE, "Error adding SSID artifact to blackboard.", ex); //NON-NLS
906 }
907 break;
908 case "shellfolders": // NON-NLS
909 // The User Shell Folders subkey stores the paths to Windows Explorer folders for the current user of the computer
910 // (https://technet.microsoft.com/en-us/library/Cc962613.aspx).
911 // No useful information. Skip.
912 break;
913
914 default:
915 logger.log(Level.SEVERE, "Unrecognized node name: {0}", dataType); //NON-NLS
916 break;
917 }
918 }
919 }
920 break;
921 }
922 } // for
923 return true;
924 } catch (FileNotFoundException ex) {
925 logger.log(Level.WARNING, String.format("Error finding the registry file: %s", regFilePath), ex); //NON-NLS
926 } catch (SAXException ex) {
927 logger.log(Level.WARNING, String.format("Error parsing the registry XML: %s", regFilePath), ex); //NON-NLS
928 } catch (IOException ex) {
929 logger.log(Level.WARNING, String.format("Error building the document parser: %s", regFilePath), ex); //NON-NLS
930 } catch (ParserConfigurationException ex) {
931 logger.log(Level.WARNING, String.format("Error configuring the registry parser: %s", regFilePath), ex); //NON-NLS
932 } finally {
933 try {
934 if (fstream != null) {
935 fstream.close();
936 }
937 } catch (IOException ex) {
938 }
939
940 if (!context.dataSourceIngestIsCancelled()) {
941 postArtifacts(newArtifacts);
942 }
943 }
944 return false;
945 }
946
947 private boolean parseSystemPluginOutput(String regfilePath, AbstractFile regAbstractFile) {
948 File regfile = new File(regfilePath);
949 try (BufferedReader reader = new BufferedReader(new FileReader(regfile))) {
950 String line = reader.readLine();
951 while (line != null) {
952 line = line.trim();
953
954 if (line.toLowerCase().matches("^bam v.*")) {
955 parseBamKey(regAbstractFile, reader, Bundle.Registry_System_Bam());
956 } else if (line.toLowerCase().matches("^bthport v..*")) {
957 parseBlueToothDevices(regAbstractFile, reader);
958 }
959 line = reader.readLine();
960 }
961 return true;
962 } catch (FileNotFoundException ex) {
963 logger.log(Level.WARNING, "Error finding the registry file.", ex); //NON-NLS
964 } catch (IOException ex) {
965 logger.log(Level.WARNING, "Error reading the system hive: {0}", ex); //NON-NLS
966 }
967
968 return false;
969
970 }
971
984 private void parseBlueToothDevices(AbstractFile regFile, BufferedReader reader) throws FileNotFoundException, IOException {
985 List<BlackboardArtifact> bbartifacts = new ArrayList<>();
986 String line = reader.readLine();
987 while ((line != null) && (!line.contains(SECTION_DIVIDER))) {
988 line = reader.readLine();
989
990 if (line != null) {
991 line = line.trim();
992 }
993
994 if ((line != null) && (line.toLowerCase().contains("device unique id"))) {
995 // Columns are seperated by colons :
996 // Data : Values
997 // Record is 4 lines in length (Device Unique Id, Name, Last Seen, LastConnected
998 while (line != null && !line.contains(SECTION_DIVIDER) && !line.isEmpty() && !line.toLowerCase().contains("radio support not found")) {
999 Collection<BlackboardAttribute> attributes = new ArrayList<>();
1000 addBlueToothAttribute(line, attributes, TSK_DEVICE_ID);
1001 line = reader.readLine();
1002 // Name may not exist, check for it to make sure.
1003 if ((line != null) && (line.toLowerCase().contains("name"))) {
1004 addBlueToothAttribute(line, attributes, TSK_NAME);
1005 line = reader.readLine();
1006 }
1007 addBlueToothAttribute(line, attributes, TSK_DATETIME);
1008 line = reader.readLine();
1009 addBlueToothAttribute(line, attributes, TSK_DATETIME_ACCESSED);
1010
1011 try {
1012 bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_BLUETOOTH_PAIRING, regFile, attributes));
1013 } catch (TskCoreException ex) {
1014 logger.log(Level.SEVERE, String.format("Failed to create bluetooth_pairing artifact for file %d", regFile.getId()), ex);
1015 }
1016 // Read blank line between records then next read line is start of next block
1017 reader.readLine();
1018 line = reader.readLine();
1019 }
1020
1021 if (line != null) {
1022 line = line.trim();
1023 }
1024 }
1025 }
1026
1027 if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1028 postArtifacts(bbartifacts);
1029 }
1030 }
1031
1032 private void addBlueToothAttribute(String line, Collection<BlackboardAttribute> attributes, ATTRIBUTE_TYPE attributeType) {
1033 if (line == null) {
1034 return;
1035 }
1036
1037 String tokens[] = line.split(": ");
1038 if (tokens.length > 1 && !tokens[1].isEmpty()) {
1039 String tokenString = tokens[1];
1040 if (attributeType.getDisplayName().toLowerCase().contains("date")) {
1041 String dateString = tokenString.toLowerCase().replace(" z", "");
1042 // date format for plugin Tue Jun 23 10:27:54 2020 Z
1043 SimpleDateFormat dateFormat = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy", US);
1044 Long dateLong = Long.valueOf(0);
1045 try {
1046 Date newDate = dateFormat.parse(dateString);
1047 dateLong = newDate.getTime() / 1000;
1048 } catch (ParseException ex) {
1049 // catching error and displaying date that could not be parsed
1050 // we set the timestamp to 0 and continue on processing
1051 logger.log(Level.WARNING, String.format("Failed to parse date/time %s for Bluetooth Last Seen attribute.", dateString), ex); //NON-NLS
1052 }
1053 attributes.add(new BlackboardAttribute(attributeType, getDisplayName(), dateLong));
1054 } else {
1055 attributes.add(new BlackboardAttribute(attributeType, getDisplayName(), tokenString));
1056 }
1057 }
1058 }
1059
1070 private boolean parseSamPluginOutput(String regFilePath, AbstractFile regAbstractFile, long ingestJobId) {
1071
1072 File regfile = new File(regFilePath);
1073 List<BlackboardArtifact> newArtifacts = new ArrayList<>();
1074 try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(regfile), StandardCharsets.UTF_8))) {
1075 // Read the file in and create a Document and elements
1076 String userInfoSection = "User Information";
1077 String previousLine = null;
1078 String line = bufferedReader.readLine();
1079 Set<Map<String, String>> userSet = new HashSet<>();
1080 Map<String, List<String>> groupMap = null;
1081 while (line != null) {
1082 if (line.contains(SECTION_DIVIDER) && previousLine != null && previousLine.contains(userInfoSection)) {
1083 readUsers(bufferedReader, userSet);
1084 }
1085
1086 if (line.contains(SECTION_DIVIDER) && previousLine != null && previousLine.contains("Group Membership Information")) {
1087 groupMap = readGroups(bufferedReader);
1088 }
1089
1090 previousLine = line;
1091 line = bufferedReader.readLine();
1092 }
1093 Map<String, Map<String, String>> userInfoMap = new HashMap<>();
1094 //load all the user info which was read into a map
1095 for (Map<String, String> userInfo : userSet) {
1096 String sid = userInfo.get(SID_KEY);
1097 userInfoMap.put(sid, userInfo);
1098 addSIDToSAMList(sid);
1099 }
1100
1101 // New OsAccount Code
1102 OsAccountManager accountMgr = tskCase.getOsAccountManager();
1103 HostManager hostMrg = tskCase.getHostManager();
1104 Host host = hostMrg.getHostByDataSource((DataSource) dataSource);
1105
1106 List<OsAccount> existingAccounts = accountMgr.getOsAccounts(host);
1107 for (OsAccount osAccount : existingAccounts) {
1108 Optional<String> optional = osAccount.getAddr();
1109 if (!optional.isPresent()) {
1110 continue;
1111 }
1112
1113 String sid = optional.get();
1114 Map<String, String> userInfo = userInfoMap.remove(sid);
1115 if (userInfo != null) {
1116 addAccountInstance(accountMgr, osAccount, (DataSource) dataSource);
1117 updateOsAccount(osAccount, userInfo, groupMap.get(sid), regAbstractFile, ingestJobId);
1118 }
1119 }
1120
1121 //add remaining userinfos as accounts;
1122 for (Map<String, String> userInfo : userInfoMap.values()) {
1123 OsAccount osAccount = accountMgr.newWindowsOsAccount(userInfo.get(SID_KEY), null, null, host, OsAccountRealm.RealmScope.LOCAL);
1124 accountMgr.newOsAccountInstance(osAccount, (DataSource) dataSource, OsAccountInstance.OsAccountInstanceType.LAUNCHED);
1125 updateOsAccount(osAccount, userInfo, groupMap.get(userInfo.get(SID_KEY)), regAbstractFile, ingestJobId);
1126 }
1127 return true;
1128 } catch (FileNotFoundException ex) {
1129 logger.log(Level.WARNING, "Error finding the registry file.", ex); //NON-NLS
1130 } catch (IOException ex) {
1131 logger.log(Level.WARNING, "Error building the document parser: {0}", ex); //NON-NLS
1132 } catch (TskDataException | TskCoreException ex) {
1133 logger.log(Level.WARNING, "Error updating TSK_OS_ACCOUNT artifacts to include newly parsed data.", ex); //NON-NLS
1134 } catch (OsAccountManager.NotUserSIDException ex) {
1135 logger.log(Level.WARNING, "Error creating OS Account, input SID is not a user SID.", ex); //NON-NLS
1136 } finally {
1137 if (!context.dataSourceIngestIsCancelled()) {
1138 postArtifacts(newArtifacts);
1139 }
1140 }
1141 return false;
1142 }
1143
1155 private void readUsers(BufferedReader bufferedReader, Set<Map<String, String>> users) throws IOException {
1156 String line = bufferedReader.readLine();
1157 //read until end of file or next section divider
1158 String userName = "";
1159 String user_rid = "";
1160 while (line != null && !line.contains(SECTION_DIVIDER)) {
1161 //when a user name field exists read the name and id number
1162 if (line.contains(USERNAME_KEY)) {
1163 String regx = USERNAME_KEY + "\\s*?:";
1164 String userNameAndIdString = line.replaceAll(regx, "");
1165 userName = userNameAndIdString.substring(0, userNameAndIdString.lastIndexOf('[')).trim();
1166 user_rid = userNameAndIdString.substring(userNameAndIdString.lastIndexOf('['), userNameAndIdString.lastIndexOf(']'));
1167 } else if (line.contains(SID_KEY) && !userName.isEmpty()) {
1168 Map.Entry<String, String> entry = getSAMKeyValue(line);
1169
1170 HashMap<String, String> userInfo = new HashMap<>();
1171 userInfo.put(USERNAME_KEY, userName);
1172 userInfo.put(RID_KEY, user_rid);
1173 userInfo.put(entry.getKey(), entry.getValue());
1174
1175 //continue reading this users information until end of file or a blank line between users
1176 line = bufferedReader.readLine();
1177 while (line != null && !line.isEmpty()) {
1178 entry = getSAMKeyValue(line);
1179 if (entry != null) {
1180 userInfo.put(entry.getKey(), entry.getValue());
1181 }
1182 line = bufferedReader.readLine();
1183 }
1184 users.add(userInfo);
1185
1186 userName = "";
1187 }
1188 line = bufferedReader.readLine();
1189 }
1190 }
1191
1201 private void createRecentlyUsedArtifacts(String regFileName, AbstractFile regFile) throws FileNotFoundException, IOException {
1202 File regfile = new File(regFileName);
1203 try (BufferedReader reader = new BufferedReader(new FileReader(regfile))) {
1204 String line = reader.readLine();
1205 while (line != null) {
1206 line = line.trim();
1207
1208 if (line.matches("^adobe v.*")) {
1209 parseAdobeMRUList(regFile, reader, Bundle.Recently_Used_Artifacts_Adobe());
1210 } else if (line.matches("^mpmru v.*")) {
1211 parseMediaPlayerMRUList(regFile, reader, Bundle.Recently_Used_Artifacts_Mediaplayer());
1212 } else if (line.matches("^ArcHistory:")) {
1213 parse7ZipMRU(regFile, reader, Bundle.Recently_Used_Artifacts_ArcHistory());
1214 } else if (line.matches("^applets v.*")) {
1215 parseGenericMRUList(regFile, reader, Bundle.Recently_Used_Artifacts_Applets());
1216 } else if (line.matches("^mmc v.*")) {
1217 parseGenericMRUList(regFile, reader, Bundle.Recently_Used_Artifacts_Mmc());
1218 } else if (line.matches("^winrar v.*")) {
1219 parseWinRARMRUList(regFile, reader, Bundle.Recently_Used_Artifacts_Winrar());
1220 } else if (line.matches("^msoffice v.*")) {
1221 parseOfficeDocs2010MRUList(regFile, reader, Bundle.Recently_Used_Artifacts_Officedocs());
1222 } else if (line.matches("^lxss v.*")) {
1223 parseWSL(regFile, reader, Bundle.Recently_Used_Artifacts_WSL());
1224 }
1225 line = reader.readLine();
1226 }
1227 }
1228 }
1229
1241 private void parseBamKey(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1242 List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1243 String line = reader.readLine();
1244 // Read thru first bam output to get to second bam output which is the same but delimited
1245 while (!line.contains(SECTION_DIVIDER)) {
1246 line = reader.readLine();
1247 line = line.trim();
1248 }
1249 line = reader.readLine();
1250 line = line.trim();
1251 while (!line.contains(SECTION_DIVIDER)) {
1252 // Split the line into it parts based on delimiter of "|"
1253 // 1570493613|BAM|||\Device\HarddiskVolume3\Program Files\TechSmith\Snagit 2018\Snagit32.exe (S-1-5-21-3042408413-2583535980-1301764466-1001)
1254 String tokens[] = line.split("\\|");
1255 Long progRunDateTime = Long.valueOf(tokens[0]);
1256 // Split on " (S-" as this signifies a User SID, if S- not used then may have issues becuase of (x86) in path is valid.
1257 // We can add the S- back to the string that we split on since S- is a valid beginning of a User SID
1258 String fileNameSid[] = tokens[4].split("\\s+\\(S-");
1259 String userSid = "S-" + fileNameSid[1].substring(0, fileNameSid[1].length() - 1);
1260 String userName = getUserNameMap().get(userSid);
1261 if (userName == null) {
1262 userName = userSid;
1263 }
1264 String fileName = fileNameSid[0];
1265 if (fileName.startsWith("\\Device\\HarddiskVolume")) {
1266 // Start at point past the 2nd slash
1267 int fileNameStart = fileName.indexOf('\\', 16);
1268 fileName = fileName.substring(fileNameStart, fileName.length());
1269
1270 }
1271 Collection<BlackboardAttribute> attributes = new ArrayList<>();
1272 attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME, getDisplayName(), fileName));
1273 attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME, getDisplayName(), userName));
1274 attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME, getDisplayName(), progRunDateTime));
1275 attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT, getDisplayName(), comment));
1276
1277 try {
1278 BlackboardArtifact bba = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_PROG_RUN, regFile, attributes);
1279 bbartifacts.add(bba);
1280 bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1281 if (bba != null) {
1282 bbartifacts.add(bba);
1283 }
1284 } catch (TskCoreException ex) {
1285 logger.log(Level.SEVERE, String.format("Failed to create TSK_PROG_RUN artifact for file %d", regFile.getId()), ex);
1286 }
1287 line = reader.readLine();
1288 }
1289 if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1290 postArtifacts(bbartifacts);
1291 }
1292 }
1293
1305 private void parseAdobeMRUList(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1306 List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1307 String line = reader.readLine();
1308 SimpleDateFormat adobePluginDateFormat = new SimpleDateFormat("yyyyMMddHHmmssZ", US);
1309 Long adobeUsedTime = Long.valueOf(0);
1310 while (!line.contains(SECTION_DIVIDER)) {
1311 line = reader.readLine();
1312 line = line.trim();
1313 if (line.matches("^Key name,file name,sDate,uFileSize,uPageCount")) {
1314 line = reader.readLine();
1315 // Columns are
1316 // Key name, file name, sDate, uFileSize, uPageCount
1317 while (!line.contains(SECTION_DIVIDER) && !line.isEmpty()) {
1318 // Split csv line, handles double quotes around individual file names
1319 // since file names can contain commas
1320 String tokens[] = line.split(",(?=([^\"]*\"[^\"]*\")*[^\"]*$)");
1321 String fileName = tokens[1].substring(0, tokens[1].length() - 1);
1322 fileName = fileName.replace("\"", "");
1323 if (fileName.charAt(0) == '/') {
1324 fileName = fileName.substring(1, fileName.length() - 1);
1325 fileName = fileName.replaceFirst("/", ":/");
1326 }
1327 // Check to see if more then 2 tokens, Date may not be populated, will default to 0
1328 if (tokens.length > 2) {
1329 // Time in the format of 20200131104456-05'00'
1330 try {
1331 String fileUsedTime = tokens[2].replaceAll("'", "");
1332 Date usedDate = adobePluginDateFormat.parse(fileUsedTime);
1333 adobeUsedTime = usedDate.getTime() / 1000;
1334 } catch (ParseException ex) {
1335 // catching error and displaying date that could not be parsed
1336 // we set the timestamp to 0 and continue on processing
1337 logger.log(Level.WARNING, String.format("Failed to parse date/time %s for adobe file artifact.", tokens[2]), ex); //NON-NLS
1338 }
1339 }
1340 Collection<BlackboardAttribute> attributes = new ArrayList<>();
1341 attributes.add(new BlackboardAttribute(TSK_PATH, getDisplayName(), fileName));
1342 attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED, getDisplayName(), adobeUsedTime));
1343 attributes.add(new BlackboardAttribute(TSK_COMMENT, getDisplayName(), comment));
1344 try {
1345 BlackboardArtifact bba = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_RECENT_OBJECT, regFile, attributes);
1346 if (bba != null) {
1347 bbartifacts.add(bba);
1348 fileName = fileName.replace("\0", "");
1349 bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1350 if (bba != null) {
1351 bbartifacts.add(bba);
1352 }
1353 }
1354 } catch (TskCoreException ex) {
1355 logger.log(Level.SEVERE, String.format("Failed to create TSK_RECENT_OBJECT artifact for file %d", regFile.getId()), ex);
1356 }
1357 line = reader.readLine();
1358 }
1359 line = line.trim();
1360 }
1361 }
1362 if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1363 postArtifacts(bbartifacts);
1364 }
1365 }
1366
1379 private void parseMediaPlayerMRUList(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1380 List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1381 String line = reader.readLine();
1382 while (!line.contains(SECTION_DIVIDER)) {
1383 line = reader.readLine();
1384 line = line.trim();
1385 if (line.contains("LastWrite")) {
1386 line = reader.readLine();
1387 // Columns are
1388 // FileX -> <Media file>
1389 while (!line.contains(SECTION_DIVIDER) && !line.contains("RecentFileList has no values.")) {
1390 // Split line on "> " which is the record delimiter between position and file
1391 String tokens[] = line.split("> ");
1392 String fileName = tokens[1];
1393 Collection<BlackboardAttribute> attributes = new ArrayList<>();
1394 attributes.add(new BlackboardAttribute(TSK_PATH, getDisplayName(), fileName));
1395 attributes.add(new BlackboardAttribute(TSK_COMMENT, getDisplayName(), comment));
1396 try {
1397 BlackboardArtifact bba = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_RECENT_OBJECT, regFile, attributes);
1398 if (bba != null) {
1399 bbartifacts.add(bba);
1400 bba = createAssociatedArtifact(fileName, bba);
1401 if (bba != null) {
1402 bbartifacts.add(bba);
1403 bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1404 if (bba != null) {
1405 bbartifacts.add(bba);
1406 }
1407 }
1408 }
1409 } catch (TskCoreException ex) {
1410 logger.log(Level.SEVERE, String.format("Failed to create TSK_RECENT_OBJECT artifact for file %d", regFile.getId()), ex);
1411 }
1412 line = reader.readLine();
1413 }
1414 line = line.trim();
1415 }
1416 }
1417 if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1418 postArtifacts(bbartifacts);
1419 }
1420 }
1421
1434 private void parseGenericMRUList(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1435 List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1436 String line = reader.readLine();
1437 while (!line.contains(SECTION_DIVIDER)) {
1438 line = reader.readLine();
1439 line = line.trim();
1440 if (line.contains("LastWrite")) {
1441 line = reader.readLine();
1442 // Columns are
1443 // FileX -> <file>
1444 while (!line.contains(SECTION_DIVIDER) && !line.isEmpty() && !line.contains("Applets")
1445 && !line.contains(("Recent File List"))) {
1446 // Split line on "> " which is the record delimiter between position and file
1447 String tokens[] = line.split("> ");
1448 if (tokens.length > 1) {
1449 String fileName = tokens[1];
1450 Collection<BlackboardAttribute> attributes = new ArrayList<>();
1451 attributes.add(new BlackboardAttribute(TSK_PATH, getDisplayName(), fileName));
1452 attributes.add(new BlackboardAttribute(TSK_COMMENT, getDisplayName(), comment));
1453 try {
1454 BlackboardArtifact bba = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_RECENT_OBJECT, regFile, attributes);
1455 if (bba != null) {
1456 bbartifacts.add(bba);
1457 bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1458 if (bba != null) {
1459 bbartifacts.add(bba);
1460 }
1461 }
1462 } catch (TskCoreException ex) {
1463 logger.log(Level.SEVERE, String.format("Failed to create TSK_RECENT_OBJECT artifact for file %d", regFile.getId()), ex);
1464 }
1465 }
1466 line = reader.readLine();
1467 }
1468 line = line.trim();
1469 }
1470 }
1471 if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1472 postArtifacts(bbartifacts);
1473 }
1474 }
1475
1488 private void parseWinRARMRUList(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1489 List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1490 String line = reader.readLine();
1491 while (!line.contains(SECTION_DIVIDER)) {
1492 line = reader.readLine();
1493 line = line.trim();
1494 if (line.contains("LastWrite")) {
1495 line = reader.readLine();
1496 // Columns are
1497 // FileX -> <Media file>
1498 if (!line.isEmpty()) {
1499 while (!line.contains(SECTION_DIVIDER)) {
1500 // Split line on "> " which is the record delimiter between position and file
1501 String tokens[] = line.split("> ");
1502 String fileName = tokens[1];
1503 Collection<BlackboardAttribute> attributes = new ArrayList<>();
1504 attributes.add(new BlackboardAttribute(TSK_PATH, getDisplayName(), fileName));
1505 attributes.add(new BlackboardAttribute(TSK_COMMENT, getDisplayName(), comment));
1506 try {
1507 BlackboardArtifact bba = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_RECENT_OBJECT, regFile, attributes);
1508 bbartifacts.add(bba);
1509 bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1510 if (bba != null) {
1511 bbartifacts.add(bba);
1512 }
1513 } catch (TskCoreException ex) {
1514 logger.log(Level.SEVERE, String.format("Failed to create TSK_RECENT_OBJECT artifact for file %d", regFile.getId()), ex);
1515 }
1516 line = reader.readLine();
1517 }
1518 }
1519 line = line.trim();
1520 }
1521 }
1522 if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1523 postArtifacts(bbartifacts);
1524 }
1525 }
1526
1539 private void parse7ZipMRU(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1540 List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1541 String line = reader.readLine();
1542 line = line.trim();
1543 if (!line.contains("PathHistory:")) {
1544 while (!line.contains("PathHistory:") && !line.isEmpty()) {
1545 // Columns are
1546 // <fileName>
1547 String fileName = line;
1548 Collection<BlackboardAttribute> attributes = new ArrayList<>();
1549 attributes.add(new BlackboardAttribute(TSK_PATH, getDisplayName(), fileName));
1550 attributes.add(new BlackboardAttribute(TSK_COMMENT, getDisplayName(), comment));
1551 try {
1552 BlackboardArtifact bba = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_RECENT_OBJECT, regFile, attributes);
1553 bbartifacts.add(bba);
1554 bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1555 if (bba != null) {
1556 bbartifacts.add(bba);
1557 }
1558
1559 } catch (TskCoreException ex) {
1560 logger.log(Level.SEVERE, String.format("Failed to create TSK_RECENT_OBJECT artifact for file %d", regFile.getId()), ex);
1561 }
1562 line = reader.readLine();
1563 line = line.trim();
1564 }
1565 }
1566 if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1567 postArtifacts(bbartifacts);
1568 }
1569 }
1570
1583 private void parseOfficeDocs2010MRUList(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1584 List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1585 String line = reader.readLine();
1586 line = line.trim();
1587 // Reading to the SECTION DIVIDER to get next section of records to process. Dates appear to have
1588 // multiple spaces in them that makes it harder to parse so next section will be easier to parse
1589 while (!line.contains(SECTION_DIVIDER)) {
1590 line = reader.readLine();
1591 }
1592 line = reader.readLine();
1593 while (!line.contains(SECTION_DIVIDER)) {
1594 // record has the following format
1595 // 1294283922|REG|||OfficeDocs2010 - F:\Windows_time_Rules_xp.doc
1596 String tokens[] = line.split("\\|");
1597 Long docDate = Long.valueOf(tokens[0]);
1598 String fileNameTokens[] = tokens[4].split(" - ");
1599 if (fileNameTokens[0].contains("MSOffice LastLoginTime")) {
1600 line = reader.readLine();
1601 line = line.trim();
1602 continue;
1603 }
1604 String fileName;
1605 if (fileNameTokens.length > 2) {
1606 fileName = fileNameTokens[2];
1607 } else {
1608 fileName = fileNameTokens[1];
1609 }
1610 if (line.contains(" MRU ")) {
1611 comment = Bundle.Recently_Used_Artifacts_Officedocs();
1612 } else {
1613 comment = Bundle.Recently_Used_Artifacts_Office_Trustrecords();
1614 }
1615 Collection<BlackboardAttribute> attributes = new ArrayList<>();
1616 attributes.add(new BlackboardAttribute(TSK_PATH, getDisplayName(), fileName));
1617 attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED, getDisplayName(), docDate));
1618 attributes.add(new BlackboardAttribute(TSK_COMMENT, getDisplayName(), comment));
1619 try {
1620 BlackboardArtifact bba = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_RECENT_OBJECT, regFile, attributes);
1621 bbartifacts.add(bba);
1622 bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1623 if (bba != null) {
1624 bbartifacts.add(bba);
1625 }
1626 } catch (TskCoreException ex) {
1627 logger.log(Level.SEVERE, String.format("Failed to create TSK_RECENT_OBJECT artifact for file %d", regFile.getId()), ex);
1628 }
1629 line = reader.readLine();
1630 line = line.trim();
1631 }
1632 if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1633 postArtifacts(bbartifacts);
1634 }
1635 }
1636
1649 private void parseWSL(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1650 List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1651 String line = reader.readLine();
1652 line = line.trim();
1653 // Reading to the SECTION DIVIDER to get next section of records to process. Dates appear to have
1654 // multiple spaces in them that makes it harder to parse so next section will be easier to parse
1655 while (!line.contains(SECTION_DIVIDER)) {
1656 line = reader.readLine();
1657 }
1658 line = reader.readLine();
1659 while (!line.contains(SECTION_DIVIDER)) {
1660 // record has the following format
1661 // 1294283922|REG|||LXSS - Alpine - C:\Users<UserName>\AppData\Local\Packages\36828agowa338.AlpineWSL_my43bytklc4nr\LocalStats
1662 String tokens[] = line.split("\\|");
1663 Long docDate = Long.valueOf(tokens[0]);
1664 String fileNameTokens[] = tokens[4].split(" - ");
1665 String filePath = "";
1666 String imagePath = "";
1667 String distro = "";
1668 String kernalCommand;
1669 if (fileNameTokens.length > 3) {
1670 distro = fileNameTokens[1].replaceFirst(" ", "");
1671 filePath = fileNameTokens[2];
1672 imagePath = fileNameTokens[2] + "\\ext4.vhdx";
1673 kernalCommand = fileNameTokens[3];
1674 } else {
1675 distro = fileNameTokens[1].replaceFirst(" ", "");
1676 filePath = fileNameTokens[2];
1677 imagePath = fileNameTokens[2] + "\\ext4.vhdx";
1678 kernalCommand = "";
1679 }
1680 comment = Bundle.Recently_Used_Artifacts_WSL();
1681 Collection<BlackboardAttribute> attributes = new ArrayList<>();
1682
1683 try {
1684 attributes.add(new BlackboardAttribute(TSK_NAME, getDisplayName(), distro));
1685 attributes.add(new BlackboardAttribute(TSK_PATH, getDisplayName(), imagePath));
1686 attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED, getDisplayName(), docDate));
1687 attributes.add(new BlackboardAttribute(getKernalCommandAttribute(), getDisplayName(), kernalCommand));
1688 attributes.add(new BlackboardAttribute(TSK_COMMENT, getDisplayName(), comment));
1689 BlackboardArtifact.Type wslArtifact = getWSLArtifact();
1690 BlackboardArtifact bba = createArtifactWithAttributes(wslArtifact, regFile, attributes);
1691 bbartifacts.add(bba);
1692 } catch (TskCoreException ex) {
1693 logger.log(Level.SEVERE, String.format("Failed to create TSK_RECENT_OBJECT artifact for file %d", regFile.getId()), ex);
1694 }
1695 line = reader.readLine();
1696 line = line.trim();
1697 }
1698 if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1699 postArtifacts(bbartifacts);
1700 }
1701 }
1702
1713 private BlackboardArtifact createAssociatedArtifact(String filePathName, BlackboardArtifact bba) {
1714 String fileName = FilenameUtils.getName(filePathName);
1715 String filePath = FilenameUtils.getPath(filePathName);
1716 List<AbstractFile> sourceFiles;
1717 try {
1718 sourceFiles = currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, fileName, filePath);
1719 if (!sourceFiles.isEmpty()) {
1720 return createAssociatedArtifact(sourceFiles.get(0), bba);
1721 }
1722 } catch (TskCoreException ex) {
1723 // only catching the error and displaying the message as the file may not exist on the
1724 // system anymore
1725 logger.log(Level.WARNING, String.format("Error finding actual file %s. file may not exist", filePathName)); //NON-NLS
1726 }
1727
1728 return null;
1729 }
1730
1741 private Map<String, String> makeUserNameMap(Content dataSource) throws TskCoreException {
1742 Map<String, String> map = new HashMap<>();
1743
1744 for (OsAccount account : tskCase.getOsAccountManager().getOsAccounts(((DataSource) dataSource).getHost())) {
1745 Optional<String> userName = account.getLoginName();
1746 String address = account.getAddr().orElse("");
1747 if (!address.isEmpty()) {
1748 map.put(address, userName.isPresent() ? userName.get() : "");
1749 }
1750 }
1751
1752 return map;
1753 }
1754
1774 private String stripRelativeIdentifierFromSID(String osAccountSID) {
1775 if (osAccountSID.split("-").length > 4) {
1776 int index = osAccountSID.lastIndexOf('-');
1777 return index > 1 ? osAccountSID.substring(0, index) : "";
1778 }
1779 return "";
1780 }
1781
1782 private final List<String> machineSIDs = new ArrayList<>();
1783
1789 private Map<String, String> getUserNameMap() {
1790 if (userNameMap == null) {
1791 // Get a mapping of user sids to user names and save globally so it can be used for other areas
1792 // of the registry, ie: BAM key
1793 try {
1794 userNameMap = makeUserNameMap(dataSource);
1795 } catch (TskCoreException ex) {
1796 logger.log(Level.WARNING, "Unable to create OS Account user name map", ex);
1797 // This is not the end of the world we will just continue without
1798 // user names
1799 userNameMap = new HashMap<>();
1800 }
1801 }
1802
1803 return userNameMap;
1804 }
1805
1816 private BlackboardAttribute getAttributeForArtifact(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) throws TskCoreException {
1817 return artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(type.getTypeID())));
1818 }
1819
1828 void createShellBagArtifacts(AbstractFile regFile, List<ShellBag> shellbags) throws TskCoreException {
1829 List<BlackboardArtifact> artifacts = new ArrayList<>();
1830 try {
1831 for (ShellBag bag : shellbags) {
1832 Collection<BlackboardAttribute> attributes = new ArrayList<>();
1833 attributes.add(new BlackboardAttribute(TSK_PATH, getDisplayName(), bag.getResource()));
1834 attributes.add(new BlackboardAttribute(getKeyAttribute(), getDisplayName(), bag.getKey()));
1835
1836 long time;
1837 time = bag.getLastWrite();
1838 if (time != 0) {
1839 attributes.add(new BlackboardAttribute(getLastWriteAttribute(), getDisplayName(), time));
1840 }
1841
1842 time = bag.getModified();
1843 if (time != 0) {
1844 attributes.add(new BlackboardAttribute(TSK_DATETIME_MODIFIED, getDisplayName(), time));
1845 }
1846
1847 time = bag.getCreated();
1848 if (time != 0) {
1849 attributes.add(new BlackboardAttribute(TSK_DATETIME_CREATED, getDisplayName(), time));
1850 }
1851
1852 time = bag.getAccessed();
1853 if (time != 0) {
1854 attributes.add(new BlackboardAttribute(TSK_DATETIME_ACCESSED, getDisplayName(), time));
1855 }
1856
1857 BlackboardArtifact artifact = createArtifactWithAttributes(getShellBagArtifact(), regFile, attributes);
1858 artifacts.add(artifact);
1859 }
1860 } finally {
1861 if (!context.dataSourceIngestIsCancelled()) {
1862 postArtifacts(artifacts);
1863 }
1864 }
1865 }
1866
1875 private BlackboardArtifact.Type getShellBagArtifact() throws TskCoreException {
1876 if (shellBagArtifactType == null) {
1877 try {
1878 shellBagArtifactType = tskCase.getBlackboard().getOrAddArtifactType(SHELLBAG_ARTIFACT_NAME, Bundle.Shellbag_Artifact_Display_Name());
1879 } catch (BlackboardException ex) {
1880 throw new TskCoreException(String.format("Failed to get shell bag artifact type", SHELLBAG_ARTIFACT_NAME), ex);
1881 }
1882 }
1883
1884 return shellBagArtifactType;
1885 }
1886
1895 private BlackboardArtifact.Type getWSLArtifact() throws TskCoreException {
1896 if (wslArtifactType == null) {
1897 try {
1898 wslArtifactType = tskCase.getBlackboard().getOrAddArtifactType(WSL_ARTIFACT_NAME, Bundle.WSL_Artifact_Display_Name());
1899 } catch (BlackboardException ex) {
1900 throw new TskCoreException(String.format("Failed to get WSL artifact type", WSL_ARTIFACT_NAME), ex);
1901 }
1902 }
1903
1904 return wslArtifactType;
1905 }
1906
1915 private BlackboardAttribute.Type getKernalCommandAttribute() throws TskCoreException {
1916 if (kernalCommandAttributeType == null) {
1917 try {
1918 kernalCommandAttributeType = tskCase.getBlackboard().getOrAddAttributeType(WSL_ATTRIBUTE_KERNAL_COMMAND,
1919 BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
1920 Bundle.WSL_Kernal_Command_Attribute_Display_Name());
1921 } catch (BlackboardException ex) {
1922 // Attribute already exists get it from the case
1923 throw new TskCoreException(String.format("Failed to get custom attribute %s", WSL_ATTRIBUTE_KERNAL_COMMAND), ex);
1924 }
1925 }
1926 return kernalCommandAttributeType;
1927 }
1928
1937 private BlackboardAttribute.Type getLastWriteAttribute() throws TskCoreException {
1938 if (shellBagLastWriteAttributeType == null) {
1939 try {
1940 shellBagLastWriteAttributeType = tskCase.getBlackboard().getOrAddAttributeType(SHELLBAG_ATTRIBUTE_LAST_WRITE,
1941 BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME,
1942 Bundle.Shellbag_Last_Write_Attribute_Display_Name());
1943 } catch (BlackboardException ex) {
1944 // Attribute already exists get it from the case
1945 throw new TskCoreException(String.format("Failed to get custom attribute %s", SHELLBAG_ATTRIBUTE_LAST_WRITE), ex);
1946 }
1947 }
1948 return shellBagLastWriteAttributeType;
1949 }
1950
1959 private BlackboardAttribute.Type getKeyAttribute() throws TskCoreException {
1960 if (shellBagKeyAttributeType == null) {
1961 try {
1962 shellBagKeyAttributeType = tskCase.getBlackboard().getOrAddAttributeType(SHELLBAG_ATTRIBUTE_KEY,
1963 BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
1964 Bundle.Shellbag_Key_Attribute_Display_Name());
1965 } catch (BlackboardException ex) {
1966 throw new TskCoreException(String.format("Failed to get key attribute %s", SHELLBAG_ATTRIBUTE_KEY), ex);
1967 }
1968 }
1969 return shellBagKeyAttributeType;
1970 }
1971
1981 Map<String, List<String>> readGroups(BufferedReader bufferedReader) throws IOException {
1982 Map<String, List<String>> groupMap = new HashMap<>();
1983
1984 String line = bufferedReader.readLine();
1985
1986 int userCount = 0;
1987 String groupName = null;
1988
1989 while (line != null && !line.contains(SECTION_DIVIDER)) {
1990
1991 if (line.contains("Group Name")) {
1992 String value = line.replaceAll("Group Name\\s*?:", "").trim();
1993 groupName = (value.replaceAll("\\[\\d*?\\]", "")).trim();
1994 int startIndex = value.indexOf(" [") + 1;
1995 int endIndex = value.indexOf(']');
1996
1997 if (startIndex != -1 && endIndex != -1) {
1998 String countStr = value.substring(startIndex + 1, endIndex);
1999 userCount = Integer.parseInt(countStr);
2000 }
2001 } else if (line.matches("Users\\s*?:")) {
2002 for (int i = 0; i < userCount; i++) {
2003 line = bufferedReader.readLine();
2004 if (line != null) {
2005 String sid = line.trim();
2006 List<String> groupList = groupMap.get(sid);
2007 if (groupList == null) {
2008 groupList = new ArrayList<>();
2009 groupMap.put(sid, groupList);
2010 }
2011 groupList.add(groupName);
2012 }
2013 }
2014 groupName = null;
2015 }
2016 line = bufferedReader.readLine();
2017 }
2018 return groupMap;
2019 }
2020
2029 private Map.Entry<String, String> getSAMKeyValue(String line) {
2030 int index = line.indexOf(':');
2031 Map.Entry<String, String> returnValue = null;
2032 String key = null;
2033 String value = null;
2034
2035 if (index != -1) {
2036 key = line.substring(0, index).trim();
2037 if (index + 1 < line.length()) {
2038 value = line.substring(index + 1).trim();
2039 } else {
2040 value = "";
2041 }
2042
2043 } else if (line.contains("-->")) {
2044 key = line.replace("-->", "").trim();
2045 value = "true";
2046 }
2047
2048 if (key != null) {
2049 returnValue = new AbstractMap.SimpleEntry<>(key, value);
2050 }
2051
2052 return returnValue;
2053 }
2054
2055 @Override
2056 public void process(Content dataSource, DataSourceIngestModuleProgress progressBar) {
2057 this.dataSource = dataSource;
2058
2059 progressBar.progress(Bundle.Progress_Message_Analyze_Registry());
2060 analyzeRegistryFiles(context.getJobId());
2061 }
2062
2066 private class RegOutputFiles {
2067
2068 public String autopsyPlugins = "";
2069 public String fullPlugins = "";
2070 }
2071
2084 private void createOrUpdateOsAccount(AbstractFile file, String sid, String userName, String homeDir, String domainName, OsAccountRealm.RealmScope realmScope) throws TskCoreException, TskDataException, NotUserSIDException {
2085 OsAccountManager accountMgr = tskCase.getOsAccountManager();
2086 HostManager hostMrg = tskCase.getHostManager();
2087 Host host = hostMrg.getHostByDataSource((DataSource) dataSource);
2088
2089 Optional<OsAccount> optional = accountMgr.getWindowsOsAccount(sid, null, null, host);
2090 OsAccount osAccount;
2091 if (!optional.isPresent()) {
2092 osAccount = accountMgr.newWindowsOsAccount(sid, userName != null && userName.isEmpty() ? null : userName, domainName, host, realmScope);
2093 accountMgr.newOsAccountInstance(osAccount, (DataSource) dataSource, OsAccountInstance.OsAccountInstanceType.LAUNCHED);
2094 } else {
2095 osAccount = optional.get();
2096 addAccountInstance(accountMgr, osAccount, (DataSource) dataSource);
2097 if (userName != null && !userName.isEmpty()) {
2098 OsAccountUpdateResult updateResult = accountMgr.updateCoreWindowsOsAccountAttributes(osAccount, null, userName, (domainName == null || domainName.isEmpty()) ? null : domainName, host);
2099 osAccount = updateResult.getUpdatedAccount().orElse(osAccount);
2100 }
2101 }
2102
2103 if (homeDir != null && !homeDir.isEmpty()) {
2104 List<OsAccountAttribute> attributes = new ArrayList<>();
2105 String dir = homeDir.replaceFirst("^(%\\w*%)", "");
2106 dir = dir.replace("\\", "/");
2107 attributes.add(createOsAccountAttribute(TSK_HOME_DIR, dir, osAccount, host, file));
2108 accountMgr.addExtendedOsAccountAttributes(osAccount, attributes);
2109 }
2110
2111 }
2112
2120 private void addEmailAccount(AbstractFile regFile, String emailAddress, long ingestJobId) {
2121 try {
2122 currentCase.getSleuthkitCase()
2123 .getCommunicationsManager()
2124 .createAccountFileInstance(Account.Type.EMAIL,
2125 emailAddress, getRAModuleName(), regFile,
2126 Collections.emptyList(),
2127 ingestJobId);
2128 } catch (TskCoreException ex) {
2129 logger.log(Level.SEVERE,
2130 String.format("Error adding email account with value "
2131 + "%s, to the case database for file %s [objId=%d]",
2132 emailAddress, regFile.getName(), regFile.getId()), ex);
2133 }
2134 }
2135
2144 private Long parseRegRipTime(String value) {
2145 try {
2146 return REG_RIPPER_TIME_FORMAT.parse(value).getTime() / MS_IN_SEC;
2147 } catch (ParseException ex) {
2148 logger.log(Level.SEVERE, String.format("Failed to parse reg rip time: %s", value));
2149 }
2150 return null;
2151 }
2152
2165 private void updateOsAccount(OsAccount osAccount, Map<String, String> userInfo, List<String> groupList, AbstractFile regFile, long ingestJobId) throws TskDataException, TskCoreException, NotUserSIDException {
2166 Host host = ((DataSource) dataSource).getHost();
2167 SimpleDateFormat regRipperTimeFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy 'Z'", US);
2168 regRipperTimeFormat.setTimeZone(getTimeZone("GMT"));
2169
2170 List<OsAccountAttribute> attributes = new ArrayList<>();
2171
2172 Long creationTime = null;
2173
2174 String value = userInfo.get(ACCOUNT_CREATED_KEY);
2175 if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) {
2176 creationTime = parseRegRipTime(value);
2177 }
2178
2179 value = userInfo.get(LAST_LOGIN_KEY);
2180 if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) {
2181 Long time = parseRegRipTime(value);
2182 if (time != null) {
2183 attributes.add(createOsAccountAttribute(TSK_DATETIME_ACCESSED,
2184 parseRegRipTime(value),
2185 osAccount, host, regFile));
2186 }
2187 }
2188
2189 String loginName = null;
2190 value = userInfo.get(USERNAME_KEY);
2191 if (value != null && !value.isEmpty()) {
2192 loginName = value;
2193 }
2194
2195 value = userInfo.get(LOGIN_COUNT_KEY);
2196 if (value != null && !value.isEmpty()) {
2197 attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
2198 Integer.parseInt(value),
2199 osAccount, host, regFile));
2200 }
2201
2202 // From regripper the possible values for this key are
2203 // "Default Admin User", "Custom Limited Acct"
2204 // and "Default Guest Acct"
2205 value = userInfo.get(ACCOUNT_TYPE_KEY);
2206 if (value != null && !value.isEmpty() && value.toLowerCase().contains("admin")) {
2207 attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_IS_ADMIN,
2208 1, osAccount, host, regFile));
2209 }
2210
2211 value = userInfo.get(USER_COMMENT_KEY);
2212 if (value != null && !value.isEmpty()) {
2213 attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_DESCRIPTION,
2214 value, osAccount, host, regFile));
2215 }
2216
2217 value = userInfo.get(INTERNET_NAME_KEY);
2218 if (value != null && !value.isEmpty()) {
2219 addEmailAccount(regFile, value, ingestJobId);
2220
2221 attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_EMAIL,
2222 value, osAccount, host, regFile));
2223 }
2224
2225 // FULL_NAME_KEY and NAME_KEY appear to be the same value.
2226 String fullName = null;
2227 value = userInfo.get(FULL_NAME_KEY);
2228 if (value != null && !value.isEmpty()) {
2229 fullName = value;
2230 } else {
2231 value = userInfo.get(NAME_KEY);
2232 if (value != null && !value.isEmpty()) {
2233 fullName = value;
2234 }
2235 }
2236
2237 value = userInfo.get(PWD_RESET_KEY);
2238 if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) {
2239 Long time = parseRegRipTime(value);
2240 if (time != null) {
2241 attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_PASSWORD_RESET,
2242 time, osAccount, host, regFile));
2243 }
2244 }
2245
2246 value = userInfo.get(SECURITY_QUESTION_1);
2247 if (value != null && !value.isEmpty()) {
2248 BlackboardAttribute.Type securityQuestionAttributeType = null;
2249 try {
2250 securityQuestionAttributeType = tskCase.getBlackboard().getOrAddAttributeType(SAM_SECURITY_QUESTION_1,
2251 BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
2252 Bundle.Sam_Security_Question_1_Attribute_Display_Name());
2253 } catch (BlackboardException ex) {
2254 throw new TskCoreException(String.format("Failed to get key attribute %s", SAM_SECURITY_QUESTION_1), ex);
2255 }
2256 attributes.add(createOsAccountAttribute(securityQuestionAttributeType, value, osAccount, host, regFile));
2257 }
2258
2259 value = userInfo.get(SECURITY_ANSWER_1);
2260 if (value != null && !value.isEmpty()) {
2261 BlackboardAttribute.Type securityAnswerAttributeType = null;
2262 try {
2263 securityAnswerAttributeType = tskCase.getBlackboard().getOrAddAttributeType(SAM_SECURITY_ANSWER_1,
2264 BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
2265 Bundle.Sam_Security_Answer_1_Attribute_Display_Name());
2266 } catch (BlackboardException ex) {
2267 throw new TskCoreException(String.format("Failed to get key attribute %s", SAM_SECURITY_ANSWER_1), ex);
2268 }
2269 attributes.add(createOsAccountAttribute(securityAnswerAttributeType, value, osAccount, host, regFile));
2270 }
2271
2272 value = userInfo.get(SECURITY_QUESTION_2);
2273 if (value != null && !value.isEmpty()) {
2274 BlackboardAttribute.Type securityQuestionAttributeType = null;
2275 try {
2276 securityQuestionAttributeType = tskCase.getBlackboard().getOrAddAttributeType(SAM_SECURITY_QUESTION_2,
2277 BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
2278 Bundle.Sam_Security_Question_2_Attribute_Display_Name());
2279 } catch (BlackboardException ex) {
2280 throw new TskCoreException(String.format("Failed to get key attribute %s", SAM_SECURITY_QUESTION_2), ex);
2281 }
2282 attributes.add(createOsAccountAttribute(securityQuestionAttributeType, value, osAccount, host, regFile));
2283 }
2284
2285 value = userInfo.get(SECURITY_ANSWER_2);
2286 if (value != null && !value.isEmpty()) {
2287 BlackboardAttribute.Type securityAnswerAttributeType = null;
2288 try {
2289 securityAnswerAttributeType = tskCase.getBlackboard().getOrAddAttributeType(SAM_SECURITY_ANSWER_2,
2290 BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
2291 Bundle.Sam_Security_Answer_2_Attribute_Display_Name());
2292 } catch (BlackboardException ex) {
2293 throw new TskCoreException(String.format("Failed to get key attribute %s", SAM_SECURITY_ANSWER_2), ex);
2294 }
2295 attributes.add(createOsAccountAttribute(securityAnswerAttributeType, value, osAccount, host, regFile));
2296 }
2297
2298 value = userInfo.get(SECURITY_QUESTION_3);
2299 if (value != null && !value.isEmpty()) {
2300 BlackboardAttribute.Type securityQuestionAttributeType = null;
2301 try {
2302 securityQuestionAttributeType = tskCase.getBlackboard().getOrAddAttributeType(SAM_SECURITY_QUESTION_3,
2303 BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
2304 Bundle.Sam_Security_Question_2_Attribute_Display_Name());
2305 } catch (BlackboardException ex) {
2306 throw new TskCoreException(String.format("Failed to get key attribute %s", SAM_SECURITY_QUESTION_3), ex);
2307 }
2308 attributes.add(createOsAccountAttribute(securityQuestionAttributeType, value, osAccount, host, regFile));
2309 }
2310
2311 value = userInfo.get(SECURITY_ANSWER_3);
2312 if (value != null && !value.isEmpty()) {
2313 BlackboardAttribute.Type securityAnswerAttributeType = null;
2314 try {
2315 securityAnswerAttributeType = tskCase.getBlackboard().getOrAddAttributeType(SAM_SECURITY_ANSWER_3,
2316 BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
2317 Bundle.Sam_Security_Answer_3_Attribute_Display_Name());
2318 } catch (BlackboardException ex) {
2319 throw new TskCoreException(String.format("Failed to get key attribute %s", SAM_SECURITY_ANSWER_3), ex);
2320 }
2321 attributes.add(createOsAccountAttribute(securityAnswerAttributeType, value, osAccount, host, regFile));
2322 }
2323
2324 value = userInfo.get(PASSWORD_HINT);
2325 if (value != null && !value.isEmpty()) {
2326 attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_PASSWORD_HINT,
2327 value, osAccount, host, regFile));
2328 }
2329
2330 value = userInfo.get(PWD_FAILE_KEY);
2331 if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) {
2332 Long time = parseRegRipTime(value);
2333 if (time != null) {
2334 attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_PASSWORD_FAIL,
2335 time, osAccount, host, regFile));
2336 }
2337 }
2338
2339 String settingString = getSettingsFromMap(PASSWORD_SETTINGS_FLAGS, userInfo);
2340 if (!settingString.isEmpty()) {
2341 attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_PASSWORD_SETTINGS,
2342 settingString, osAccount, host, regFile));
2343 }
2344
2345 settingString = getSettingsFromMap(ACCOUNT_SETTINGS_FLAGS, userInfo);
2346 if (!settingString.isEmpty()) {
2347 attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_ACCOUNT_SETTINGS,
2348 settingString, osAccount, host, regFile));
2349 }
2350
2351 settingString = getSettingsFromMap(ACCOUNT_TYPE_FLAGS, userInfo);
2352 if (!settingString.isEmpty()) {
2353 attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_FLAG,
2354 settingString, osAccount, host, regFile));
2355 }
2356
2357 if (groupList != null && groupList.isEmpty()) {
2358 String groups = groupList.stream()
2359 .map(String::valueOf)
2360 .collect(Collectors.joining(", "));
2361
2362 attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_GROUPS,
2363 groups, osAccount, host, regFile));
2364 }
2365
2366 // add the attributes to account.
2367 OsAccountManager accountMgr = tskCase.getOsAccountManager();
2368 accountMgr.addExtendedOsAccountAttributes(osAccount, attributes);
2369
2370 // update the loginname
2371 accountMgr.updateCoreWindowsOsAccountAttributes(osAccount, null, loginName, null, host);
2372
2373 // update other standard attributes - fullname, creationdate
2374 accountMgr.updateStandardOsAccountAttributes(osAccount, fullName, null, null, creationTime);
2375
2376 }
2377
2386 private String getSettingsFromMap(String[] keys, Map<String, String> map) {
2387 List<String> settingsList = new ArrayList<>();
2388 for (String setting : keys) {
2389 if (map.containsKey(setting)) {
2390 settingsList.add(setting);
2391 }
2392 }
2393
2394 if (!settingsList.isEmpty()) {
2395 return settingsList.stream()
2396 .map(String::valueOf)
2397 .collect(Collectors.joining(", "));
2398 }
2399
2400 return "";
2401 }
2402
2414 private OsAccountAttribute createOsAccountAttribute(BlackboardAttribute.Type type, String value, OsAccount osAccount, Host host, AbstractFile file) {
2415 return osAccount.new OsAccountAttribute(type, value, osAccount, host, file);
2416 }
2417
2429 private OsAccountAttribute createOsAccountAttribute(BlackboardAttribute.ATTRIBUTE_TYPE type, String value, OsAccount osAccount, Host host, AbstractFile file) {
2430 return osAccount.new OsAccountAttribute(new BlackboardAttribute.Type(type), value, osAccount, host, file);
2431 }
2432
2444 private OsAccountAttribute createOsAccountAttribute(BlackboardAttribute.ATTRIBUTE_TYPE type, Long value, OsAccount osAccount, Host host, AbstractFile file) {
2445 return osAccount.new OsAccountAttribute(new BlackboardAttribute.Type(type), value, osAccount, host, file);
2446 }
2447
2459 private OsAccountAttribute createOsAccountAttribute(BlackboardAttribute.ATTRIBUTE_TYPE type, Integer value, OsAccount osAccount, Host host, AbstractFile file) {
2460 return osAccount.new OsAccountAttribute(new BlackboardAttribute.Type(type), value, osAccount, host, file);
2461 }
2462
2473 private void addAccountInstance(OsAccountManager accountMgr, OsAccount osAccount, DataSource dataSource) throws TskCoreException {
2474 accountMgr.newOsAccountInstance(osAccount, dataSource, OsAccountInstance.OsAccountInstanceType.LAUNCHED);
2475 }
2476
2482 private void addSIDToSAMList(String sid) {
2483 String relativeID = stripRelativeIdentifierFromSID(sid);
2484 if (!relativeID.isEmpty() && !samDomainIDsList.contains(relativeID)) {
2485 samDomainIDsList.add(relativeID);
2486 }
2487 }
2488
2497 private boolean isDomainIdInSAMList(String osAccountSID) {
2498 String relativeID = stripRelativeIdentifierFromSID(osAccountSID);
2499 return samDomainIDsList.contains(relativeID);
2500 }
2501
2502 // Structure to keep the OSInfo meta data so that only one instance
2503 // of TSK_OS_INFO is created per RA run.
2504 private class OSInfo {
2505 private String compName = null;
2506 private String progName = "Windows";
2507 private String processorArchitecture = null;
2508 private String tempDir = null;
2509 private String domain = null;
2510 private Long installtime = null;
2511 private String systemRoot = null;
2512 private String productId = null;
2513 private String regOwner = null;
2514 private String regOrg = null;
2515
2516 private OSInfo() {}
2517
2518 void createOSInfo() {
2519 try{
2520 String parentModuleName = RecentActivityExtracterModuleFactory.getModuleName();
2521 ArrayList<BlackboardArtifact> results = tskCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_OS_INFO, context.getDataSource().getId());
2522
2523 if (results.isEmpty()) {
2524 Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
2525 if (compName != null && !compName.isEmpty()) {
2526 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, parentModuleName, compName));
2527 }
2528 if (domain != null && !domain.isEmpty()) {
2529 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN, parentModuleName, domain));
2530 }
2531 if (progName != null && !progName.isEmpty()) {
2532 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME, parentModuleName, progName));
2533 }
2534 if (processorArchitecture != null && !processorArchitecture.isEmpty()) {
2535 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROCESSOR_ARCHITECTURE, parentModuleName, processorArchitecture));
2536 }
2537 if (tempDir != null && !tempDir.isEmpty()) {
2538 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TEMP_DIR, parentModuleName, tempDir));
2539 }
2540 if (installtime != null) {
2541 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME, parentModuleName, installtime));
2542 }
2543 if (systemRoot != null && !systemRoot.isEmpty()) {
2544 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH, parentModuleName, systemRoot));
2545 }
2546 if (productId != null && !productId.isEmpty()) {
2547 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PRODUCT_ID, parentModuleName, productId));
2548 }
2549 if (regOwner != null && !regOwner.isEmpty()) {
2550 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_OWNER, parentModuleName, regOwner));
2551 }
2552 if (regOrg != null && !regOrg.isEmpty()) {
2553 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ORGANIZATION, parentModuleName, regOrg));
2554 }
2555
2556 postArtifact(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_OS_INFO, context.getDataSource(), bbattributes));
2557 }
2558 } catch (TskCoreException ex) {
2559 logger.log(Level.SEVERE, "Failed to create default OS_INFO artifact", ex); //NON-NLS
2560 }
2561 }
2562
2563 void setCompName(String compName) {
2564 if(this.compName == null || this.compName.isEmpty()) {
2565 this.compName = compName;
2566 }
2567 }
2568
2569 void setOsName(String progName) {
2570 if(progName != null && !progName.isEmpty()) {
2571 this.progName = progName;
2572 }
2573 }
2574
2575 void setProcessorArchitecture(String processorArchitecture) {
2576 if(this.processorArchitecture == null || this.processorArchitecture.isEmpty()) {
2577 this.processorArchitecture = processorArchitecture;
2578 }
2579 }
2580
2581 void setTempDir(String tempDir) {
2582 if(this.tempDir == null || this.tempDir.isEmpty()) {
2583 this.tempDir = tempDir;
2584 }
2585 }
2586
2587 void setDomain(String domain) {
2588 if(this.domain == null || this.domain.isEmpty()) {
2589 this.domain = domain;
2590 }
2591 }
2592
2593 void setInstalltime(Long installtime) {
2594 if(this.domain == null) {
2595 this.installtime = installtime;
2596 }
2597 }
2598
2599 void setSystemRoot(String systemRoot) {
2600 if(this.systemRoot == null || this.systemRoot.isEmpty()) {
2601 this.systemRoot = systemRoot;
2602 }
2603 }
2604
2605 void setProductId(String productId) {
2606 if(this.productId == null || this.productId.isEmpty()) {
2607 this.productId = productId;
2608 }
2609 }
2610
2611 void setRegOwner(String regOwner) {
2612 if(this.regOwner == null || this.regOwner.isEmpty()) {
2613 this.regOwner = regOwner;
2614 }
2615 }
2616
2617 void setRegOrg(String regOrg) {
2618 if(this.regOrg == null || this.regOrg.isEmpty()) {
2619 this.regOrg = regOrg;
2620 }
2621 }
2622 }
2623
2624}
List< AbstractFile > findFiles(String fileName)
static int execute(ProcessBuilder processBuilder)
synchronized static Logger getLogger(String name)
Definition Logger.java:124
static DocumentBuilder getDocumentBuilder()
Definition XMLUtil.java:63
static< T > long writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, Future< T > worker, boolean source)

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.