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

Copyright © 2012-2022 Basis Technology. Generated on: Tue Jun 27 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.