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 
424  // Index the report content so that it will be available for keyword search.
425  KeywordSearchService searchService = Lookup.getDefault().lookup(KeywordSearchService.class);
426  if (null == searchService) {
427  logger.log(Level.WARNING, "Keyword search service not found. Report will not be indexed");
428  } else {
429  searchService.index(report);
430  report.close();
431  }
432  } catch (TskCoreException e) {
433  this.addErrorMessage("Error adding regripper output as Autopsy report: " + e.getLocalizedMessage()); //NON-NLS
434  }
435  }
436  // delete the hive
437  regFileNameLocalFile.delete();
438  }
439 
440  // RA can be run on non-window images. We are going to assume that
441  // the data source was from windows if there was registry files.
442  // Therefore we will only create the OSInfo object if there are
443  // registry files.
444  if(allRegistryFiles.size() > 0) {
445  osInfo.createOSInfo();
446  }
447 
448  try {
449  if (logFile != null) {
450  logFile.close();
451  }
452  } catch (IOException ex) {
453  logger.log(Level.SEVERE, null, ex);
454  }
455  }
456 
464  private RegOutputFiles ripRegistryFile(String regFilePath, String outFilePathBase) {
465  String autopsyType = ""; // Type argument for rr for autopsy-specific modules
466  String fullType; // Type argument for rr for full set of modules
467 
468  RegOutputFiles regOutputFiles = new RegOutputFiles();
469 
470  if (regFilePath.toLowerCase().contains("system")) { //NON-NLS
471  autopsyType = "autopsysystem"; //NON-NLS
472  fullType = "system"; //NON-NLS
473  } else if (regFilePath.toLowerCase().contains("software")) { //NON-NLS
474  autopsyType = "autopsysoftware"; //NON-NLS
475  fullType = "software"; //NON-NLS
476  } else if (regFilePath.toLowerCase().contains("ntuser")) { //NON-NLS
477  autopsyType = "autopsyntuser"; //NON-NLS
478  fullType = "ntuser"; //NON-NLS
479  } else if (regFilePath.toLowerCase().contains("sam")) { //NON-NLS
480  //fullType sam output files are parsed for user information
481  fullType = "sam"; //NON-NLS
482  } else if (regFilePath.toLowerCase().contains("security")) { //NON-NLS
483  fullType = "security"; //NON-NLS
484  } else if (regFilePath.toLowerCase().contains("usrclass")) { //NON-NLS
485  fullType = "usrclass"; //NON-NLS
486  } else {
487  return regOutputFiles;
488  }
489 
490  // run the autopsy-specific set of modules
491  if (!autopsyType.isEmpty()) {
492  regOutputFiles.autopsyPlugins = outFilePathBase + "-autopsy.txt"; //NON-NLS
493  String errFilePath = outFilePathBase + "-autopsy.err.txt"; //NON-NLS
494  logger.log(Level.INFO, "Writing RegRipper results to: {0}", regOutputFiles.autopsyPlugins); //NON-NLS
495  executeRegRipper(rrCmd, rrHome, regFilePath, autopsyType, regOutputFiles.autopsyPlugins, errFilePath);
496  }
497  if (context.dataSourceIngestIsCancelled()) {
498  return regOutputFiles;
499  }
500 
501  // run the full set of rr modules
502  if (!fullType.isEmpty()) {
503  regOutputFiles.fullPlugins = outFilePathBase + "-full.txt"; //NON-NLS
504  String errFilePath = outFilePathBase + "-full.err.txt"; //NON-NLS
505  logger.log(Level.INFO, "Writing Full RegRipper results to: {0}", regOutputFiles.fullPlugins); //NON-NLS
506  executeRegRipper(rrFullCmd, rrFullHome, regFilePath, fullType, regOutputFiles.fullPlugins, errFilePath);
507  try {
508  scanErrorLogs(errFilePath);
509  } catch (IOException ex) {
510  logger.log(Level.SEVERE, String.format("Unable to run RegRipper on %s", regFilePath), ex); //NON-NLS
511  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "ExtractRegistry.execRegRip.errMsg.failedAnalyzeRegFile", this.getDisplayName(), regFilePath));
512  }
513  }
514  return regOutputFiles;
515  }
516 
517  private void scanErrorLogs(String errFilePath) throws IOException {
518  File regfile = new File(errFilePath);
519  try (BufferedReader reader = new BufferedReader(new FileReader(regfile))) {
520  String line = reader.readLine();
521  while (line != null) {
522  line = line.trim();
523  if (line.toLowerCase().contains("error") || line.toLowerCase().contains("@inc")) {
524  logger.log(Level.WARNING, "Regripper file {0} contains errors from run", errFilePath); //NON-NLS
525 
526  }
527  line = reader.readLine();
528  }
529  }
530  }
531 
532  private void executeRegRipper(List<String> regRipperPath, Path regRipperHomeDir, String hiveFilePath, String hiveFileType, String outputFile, String errFile) {
533  try {
534  List<String> commandLine = new ArrayList<>();
535  for (String cmd : regRipperPath) {
536  commandLine.add(cmd);
537  }
538  commandLine.add("-r"); //NON-NLS
539  commandLine.add(hiveFilePath);
540  commandLine.add("-f"); //NON-NLS
541  commandLine.add(hiveFileType);
542 
543  ProcessBuilder processBuilder = new ProcessBuilder(commandLine);
544  processBuilder.directory(regRipperHomeDir.toFile()); // RegRipper 2.8 has to be run from its own directory
545  processBuilder.redirectOutput(new File(outputFile));
546  processBuilder.redirectError(new File(errFile));
547  ExecUtil.execute(processBuilder, new DataSourceIngestModuleProcessTerminator(context, true));
548  } catch (IOException ex) {
549  logger.log(Level.SEVERE, String.format("Error running RegRipper on %s", hiveFilePath), ex); //NON-NLS
550  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "ExtractRegistry.execRegRip.errMsg.failedAnalyzeRegFile", this.getDisplayName(), hiveFilePath));
551  }
552  }
553 
554  // @@@ VERIFY that we are doing the right thing when we parse multiple NTUSER.DAT
563  private boolean parseAutopsyPluginOutput(String regFilePath, AbstractFile regFile) {
564  FileInputStream fstream = null;
565  List<BlackboardArtifact> newArtifacts = new ArrayList<>();
566  String parentModuleName = RecentActivityExtracterModuleFactory.getModuleName();
567  try {
568  // Read the file in and create a Document and elements
569  File regfile = new File(regFilePath);
570  fstream = new FileInputStream(regfile);
571  String regString = new Scanner(fstream, "UTF-8").useDelimiter("\\Z").next(); //NON-NLS
572  String startdoc = "<?xml version=\"1.0\"?><document>"; //NON-NLS
573  String result = regString.replaceAll("----------------------------------------", "");
574  result = result.replaceAll("\\n", ""); //NON-NLS
575  result = result.replaceAll("\\r", ""); //NON-NLS
576  result = result.replaceAll("'", "&apos;"); //NON-NLS
577  result = result.replaceAll("&", "&amp;"); //NON-NLS
578  result = result.replace('\0', ' '); // NON-NLS
579  String enddoc = "</document>"; //NON-NLS
580  String stringdoc = startdoc + result + enddoc;
581  DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
582  Document doc = builder.parse(new InputSource(new StringReader(stringdoc)));
583 
584  // cycle through the elements in the doc
585  Element oroot = doc.getDocumentElement();
586  NodeList children = oroot.getChildNodes();
587  int len = children.getLength();
588  for (int i = 0; i < len; i++) {
589 
590  if (context.dataSourceIngestIsCancelled()) {
591  return false;
592  }
593 
594  Element tempnode = (Element) children.item(i);
595 
596  String dataType = tempnode.getNodeName();
597  NodeList timenodes = tempnode.getElementsByTagName("mtime"); //NON-NLS
598  Long mtime = null;
599  if (timenodes.getLength() > 0) {
600  Element timenode = (Element) timenodes.item(0);
601  String etime = timenode.getTextContent().trim();
602  //sometimes etime will be an empty string and therefore can not be parsed into a date
603  if (etime != null && !etime.isEmpty()) {
604  try {
605  mtime = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy", US).parse(etime).getTime();
606  String Tempdate = mtime.toString();
607  mtime = Long.valueOf(Tempdate) / MS_IN_SEC;
608  } catch (ParseException ex) {
609  logger.log(Level.WARNING, "Failed to parse epoch time when parsing the registry.", ex); //NON-NLS
610  }
611  }
612  }
613 
614  NodeList artroots = tempnode.getElementsByTagName("artifacts"); //NON-NLS
615  if (artroots.getLength() == 0) {
616  // If there isn't an artifact node, skip this entry
617  continue;
618  }
619 
620  Element artroot = (Element) artroots.item(0);
621  NodeList myartlist = artroot.getChildNodes();
622 
623  // If all artifact nodes should really go under one Blackboard artifact, need to process it differently
624  switch (dataType) {
625  case "WinVersion": //NON-NLS
626  String version = "";
627  String systemRoot = "";
628  String productId = "";
629  String regOwner = "";
630  String regOrg = "";
631  Long installtime = null;
632  for (int j = 0; j < myartlist.getLength(); j++) {
633  Node artchild = myartlist.item(j);
634  // If it has attributes, then it is an Element (based off API)
635  if (artchild.hasAttributes()) {
636  Element artnode = (Element) artchild;
637 
638  String value = artnode.getTextContent();
639  if (value != null) {
640  value = value.trim();
641  }
642  String name = artnode.getAttribute("name"); //NON-NLS
643  if (name == null) {
644  continue;
645  }
646  switch (name) {
647  case "ProductName": // NON-NLS
648  version = value;
649  break;
650  case "CSDVersion": // NON-NLS
651  // This is dependant on the fact that ProductName shows up first in the module output
652  version = version + " " + value;
653  break;
654  case "SystemRoot": //NON-NLS
655  systemRoot = value;
656  break;
657  case "ProductId": //NON-NLS
658  productId = value;
659  break;
660  case "RegisteredOwner": //NON-NLS
661  regOwner = value;
662  break;
663  case "RegisteredOrganization": //NON-NLS
664  regOrg = value;
665  break;
666  case "InstallDate": //NON-NLS
667  if (value != null && !value.isEmpty()) {
668  try {
669  installtime = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyyZ", US).parse(value + "+0000").getTime();
670  String Tempdate = installtime.toString();
671  installtime = Long.valueOf(Tempdate) / MS_IN_SEC;
672  } catch (ParseException e) {
673  logger.log(Level.WARNING, "RegRipper::Conversion on DateTime -> ", e); //NON-NLS
674  }
675  }
676  break;
677  default:
678  break;
679  }
680  }
681  }
682 
683  osInfo.setOsName(version);
684  osInfo.setInstalltime(installtime);
685  osInfo.setSystemRoot(systemRoot);
686  osInfo.setProductId(productId);
687  osInfo.setRegOwner(regOwner);
688  osInfo.setRegOrg(regOrg);
689  break;
690  case "Profiler": // NON-NLS
691  String os = "";
692  String procArch = "";
693  String tempDir = "";
694  for (int j = 0; j < myartlist.getLength(); j++) {
695  Node artchild = myartlist.item(j);
696  // If it has attributes, then it is an Element (based off API)
697  if (artchild.hasAttributes()) {
698  Element artnode = (Element) artchild;
699 
700  String value = artnode.getTextContent().trim();
701  String name = artnode.getAttribute("name"); //NON-NLS
702  switch (name) {
703  case "OS": // NON-NLS
704  os = value;
705  break;
706  case "PROCESSOR_ARCHITECTURE": // NON-NLS
707  procArch = value;
708  break;
709  case "PROCESSOR_IDENTIFIER": //NON-NLS
710  break;
711  case "TEMP": //NON-NLS
712  tempDir = value;
713  break;
714  default:
715  break;
716  }
717  }
718  }
719 
720  osInfo.setOsName(os);
721  osInfo.setProcessorArchitecture(procArch);
722  osInfo.setTempDir(tempDir);
723  break;
724  case "CompName": // NON-NLS
725  for (int j = 0; j < myartlist.getLength(); j++) {
726  Node artchild = myartlist.item(j);
727  // If it has attributes, then it is an Element (based off API)
728  if (artchild.hasAttributes()) {
729  Element artnode = (Element) artchild;
730 
731  String value = artnode.getTextContent().trim();
732  String name = artnode.getAttribute("name"); //NON-NLS
733 
734  if (name.equals("ComputerName")) { // NON-NLS
735  compName = value;
736  } else if (name.equals("Domain")) { // NON-NLS
737  domainName = value;
738  }
739  }
740  }
741 
742  osInfo.setCompName(compName);
743  osInfo.setDomain(domainName);
744 
745  for (Map.Entry<String, String> userMap : getUserNameMap().entrySet()) {
746  String sid = "";
747  try {
748  sid = userMap.getKey();
749  String userName = userMap.getValue();
750  // Accounts in the SAM are all local accounts
751  createOrUpdateOsAccount(regFile, sid, userName, null, null, OsAccountRealm.RealmScope.LOCAL);
752  } catch (TskCoreException | TskDataException | NotUserSIDException ex) {
753  logger.log(Level.WARNING, String.format("Failed to update Domain for existing OsAccount: %s, sid: %s", regFile.getId(), sid), ex);
754  }
755  }
756 
757  break;
758  default:
759  for (int j = 0; j < myartlist.getLength(); j++) {
760  Node artchild = myartlist.item(j);
761  // If it has attributes, then it is an Element (based off API)
762  if (artchild.hasAttributes()) {
763  Element artnode = (Element) artchild;
764 
765  String value = artnode.getTextContent().trim();
766  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
767 
768  switch (dataType) {
769  case "recentdocs": //NON-NLS
770  // BlackboardArtifact bbart = tskCase.getContentById(orgId).newArtifact(ARTIFACT_TYPE.TSK_RECENT_OBJECT);
771  // bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "RecentActivity", dataType, mtime));
772  // bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME.getTypeID(), "RecentActivity", dataType, mtimeItem));
773  // bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE.getTypeID(), "RecentActivity", dataType, value));
774  // bbart.addAttributes(bbattributes);
775  // @@@ BC: Why are we ignoring this...
776  break;
777  case "usb": //NON-NLS
778  try {
779  Long usbMtime = Long.valueOf("0");
780  if (!artnode.getAttribute("mtime").isEmpty()) {
781  usbMtime = Long.parseLong(artnode.getAttribute("mtime")); //NON-NLS
782  }
783  usbMtime = Long.valueOf(usbMtime.toString());
784  if (usbMtime > 0) {
785  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME, parentModuleName, usbMtime));
786  }
787  String dev = artnode.getAttribute("dev"); //NON-NLS
788  String make = "";
789  String model = dev;
790  if (dev.toLowerCase().contains("vid")) { //NON-NLS
791  USBInfo info = USB_MAPPER.parseAndLookup(dev);
792  if (info.getVendor() != null) {
793  make = info.getVendor();
794  }
795  if (info.getProduct() != null) {
796  model = info.getProduct();
797  }
798  }
799  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE, parentModuleName, make));
800  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL, parentModuleName, model));
801  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_ID, parentModuleName, value));
802  newArtifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_DEVICE_ATTACHED, regFile, bbattributes));
803  } catch (TskCoreException ex) {
804  logger.log(Level.SEVERE, String.format("Error adding device_attached artifact to blackboard for file %d.", regFile.getId()), ex); //NON-NLS
805  }
806  break;
807  case "uninstall": //NON-NLS
808  Long itemMtime = null;
809  try {
810  String mTimeAttr = artnode.getAttribute("mtime");
811  if (mTimeAttr != null && !mTimeAttr.isEmpty()) {
812  itemMtime = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy", US).parse(mTimeAttr).getTime(); //NON-NLS
813  itemMtime /= MS_IN_SEC;
814  }
815  } catch (ParseException ex) {
816  logger.log(Level.SEVERE, "Failed to parse epoch time for installed program artifact.", ex); //NON-NLS
817  }
818 
819  try {
820  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME, parentModuleName, value));
821  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME, parentModuleName, itemMtime));
822  BlackboardArtifact bbart = regFile.newDataArtifact(new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_INSTALLED_PROG), bbattributes);
823  newArtifacts.add(bbart);
824  } catch (TskCoreException ex) {
825  logger.log(Level.SEVERE, "Error adding installed program artifact to blackboard.", ex); //NON-NLS
826  }
827  break;
828  case "office": //NON-NLS
829  String officeName = artnode.getAttribute("name"); //NON-NLS
830 
831  try {
832  // @@@ BC: Consider removing this after some more testing. It looks like an Mtime associated with the root key and not the individual item
833  if (mtime != null) {
834  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED, parentModuleName, mtime));
835  }
836  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, parentModuleName, officeName));
837  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE, parentModuleName, value));
838  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME, parentModuleName, artnode.getNodeName()));
839  BlackboardArtifact bbart = regFile.newDataArtifact(new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_RECENT_OBJECT), bbattributes);
840 
841  newArtifacts.add(bbart);
842  } catch (TskCoreException ex) {
843  logger.log(Level.SEVERE, "Error adding recent object artifact to blackboard.", ex); //NON-NLS
844  }
845  break;
846 
847  case "ProcessorArchitecture": //NON-NLS
848  // Architecture is now included under Profiler
849  //try {
850  // String processorArchitecture = value;
851  // if (processorArchitecture.equals("AMD64"))
852  // processorArchitecture = "x86-64";
853 
854  // BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_OS_INFO);
855  // bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROCESSOR_ARCHITECTURE.getTypeID(), parentModuleName, processorArchitecture));
856  // bbart.addAttributes(bbattributes);
857  //} catch (TskCoreException ex) {
858  // logger.log(Level.SEVERE, "Error adding os info artifact to blackboard."); //NON-NLS
859  //}
860  break;
861 
862  case "ProfileList": //NON-NLS
863  String homeDir = value;
864  String sid = artnode.getAttribute("sid"); //NON-NLS
865  String username = artnode.getAttribute("username"); //NON-NLS
866  String domName = domainName;
867 
868  // accounts in profileList can be either domain or local
869  // Assume domain unless the SID was seen before in the SAM (which is only local).
870  OsAccountRealm.RealmScope scope = OsAccountRealm.RealmScope.DOMAIN;
871  if (isDomainIdInSAMList(sid)) {
872  domName = null;
873  scope = OsAccountRealm.RealmScope.LOCAL;
874  }
875 
876  try {
877  createOrUpdateOsAccount(regFile, sid, username, homeDir, domName, scope);
878  } catch (TskCoreException | TskDataException | NotUserSIDException ex) {
879  logger.log(Level.SEVERE, String.format("Failed to create OsAccount for file: %s, sid: %s", regFile.getId(), sid), ex);
880  }
881  break;
882 
883  case "NtuserNetwork": // NON-NLS
884  try {
885  String localPath = artnode.getAttribute("localPath"); //NON-NLS
886  String remoteName = value;
887 
888  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LOCAL_PATH,
889  parentModuleName, localPath));
890  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REMOTE_PATH,
891  parentModuleName, remoteName));
892  BlackboardArtifact bbart = regFile.newDataArtifact(new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_REMOTE_DRIVE), bbattributes);
893  newArtifacts.add(bbart);
894  } catch (TskCoreException ex) {
895  logger.log(Level.SEVERE, "Error adding network artifact to blackboard.", ex); //NON-NLS
896  }
897  break;
898  case "SSID": // NON-NLS
899  String adapter = artnode.getAttribute("adapter"); //NON-NLS
900  try {
901  Long lastWriteTime = Long.parseLong(artnode.getAttribute("writeTime")); //NON-NLS
902  lastWriteTime = Long.valueOf(lastWriteTime.toString());
903  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SSID, parentModuleName, value));
904  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME, parentModuleName, lastWriteTime));
905  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_ID, parentModuleName, adapter));
906  BlackboardArtifact bbart = regFile.newDataArtifact(new BlackboardArtifact.Type(ARTIFACT_TYPE.TSK_WIFI_NETWORK), bbattributes);
907  newArtifacts.add(bbart);
908  } catch (TskCoreException ex) {
909  logger.log(Level.SEVERE, "Error adding SSID artifact to blackboard.", ex); //NON-NLS
910  }
911  break;
912  case "shellfolders": // NON-NLS
913  // The User Shell Folders subkey stores the paths to Windows Explorer folders for the current user of the computer
914  // (https://technet.microsoft.com/en-us/library/Cc962613.aspx).
915  // No useful information. Skip.
916  break;
917 
918  default:
919  logger.log(Level.SEVERE, "Unrecognized node name: {0}", dataType); //NON-NLS
920  break;
921  }
922  }
923  }
924  break;
925  }
926  } // for
927  return true;
928  } catch (FileNotFoundException ex) {
929  logger.log(Level.WARNING, String.format("Error finding the registry file: %s", regFilePath), ex); //NON-NLS
930  } catch (SAXException ex) {
931  logger.log(Level.WARNING, String.format("Error parsing the registry XML: %s", regFilePath), ex); //NON-NLS
932  } catch (IOException ex) {
933  logger.log(Level.WARNING, String.format("Error building the document parser: %s", regFilePath), ex); //NON-NLS
934  } catch (ParserConfigurationException ex) {
935  logger.log(Level.WARNING, String.format("Error configuring the registry parser: %s", regFilePath), ex); //NON-NLS
936  } finally {
937  try {
938  if (fstream != null) {
939  fstream.close();
940  }
941  } catch (IOException ex) {
942  }
943 
944  if (!context.dataSourceIngestIsCancelled()) {
945  postArtifacts(newArtifacts);
946  }
947  }
948  return false;
949  }
950 
951  private boolean parseSystemPluginOutput(String regfilePath, AbstractFile regAbstractFile) {
952  File regfile = new File(regfilePath);
953  try (BufferedReader reader = new BufferedReader(new FileReader(regfile))) {
954  String line = reader.readLine();
955  while (line != null) {
956  line = line.trim();
957 
958  if (line.toLowerCase().matches("^bam v.*")) {
959  parseBamKey(regAbstractFile, reader, Bundle.Registry_System_Bam());
960  } else if (line.toLowerCase().matches("^bthport v..*")) {
961  parseBlueToothDevices(regAbstractFile, reader);
962  }
963  line = reader.readLine();
964  }
965  return true;
966  } catch (FileNotFoundException ex) {
967  logger.log(Level.WARNING, "Error finding the registry file.", ex); //NON-NLS
968  } catch (IOException ex) {
969  logger.log(Level.WARNING, "Error reading the system hive: {0}", ex); //NON-NLS
970  }
971 
972  return false;
973 
974  }
975 
988  private void parseBlueToothDevices(AbstractFile regFile, BufferedReader reader) throws FileNotFoundException, IOException {
989  List<BlackboardArtifact> bbartifacts = new ArrayList<>();
990  String line = reader.readLine();
991  while ((line != null) && (!line.contains(SECTION_DIVIDER))) {
992  line = reader.readLine();
993 
994  if (line != null) {
995  line = line.trim();
996  }
997 
998  if ((line != null) && (line.toLowerCase().contains("device unique id"))) {
999  // Columns are seperated by colons :
1000  // Data : Values
1001  // Record is 4 lines in length (Device Unique Id, Name, Last Seen, LastConnected
1002  while (line != null && !line.contains(SECTION_DIVIDER) && !line.isEmpty() && !line.toLowerCase().contains("radio support not found")) {
1003  Collection<BlackboardAttribute> attributes = new ArrayList<>();
1004  addBlueToothAttribute(line, attributes, TSK_DEVICE_ID);
1005  line = reader.readLine();
1006  // Name may not exist, check for it to make sure.
1007  if ((line != null) && (line.toLowerCase().contains("name"))) {
1008  addBlueToothAttribute(line, attributes, TSK_NAME);
1009  line = reader.readLine();
1010  }
1011  addBlueToothAttribute(line, attributes, TSK_DATETIME);
1012  line = reader.readLine();
1013  addBlueToothAttribute(line, attributes, TSK_DATETIME_ACCESSED);
1014 
1015  try {
1016  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_BLUETOOTH_PAIRING, regFile, attributes));
1017  } catch (TskCoreException ex) {
1018  logger.log(Level.SEVERE, String.format("Failed to create bluetooth_pairing artifact for file %d", regFile.getId()), ex);
1019  }
1020  // Read blank line between records then next read line is start of next block
1021  reader.readLine();
1022  line = reader.readLine();
1023  }
1024 
1025  if (line != null) {
1026  line = line.trim();
1027  }
1028  }
1029  }
1030 
1031  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1032  postArtifacts(bbartifacts);
1033  }
1034  }
1035 
1036  private void addBlueToothAttribute(String line, Collection<BlackboardAttribute> attributes, ATTRIBUTE_TYPE attributeType) {
1037  if (line == null) {
1038  return;
1039  }
1040 
1041  String tokens[] = line.split(": ");
1042  if (tokens.length > 1 && !tokens[1].isEmpty()) {
1043  String tokenString = tokens[1];
1044  if (attributeType.getDisplayName().toLowerCase().contains("date")) {
1045  String dateString = tokenString.toLowerCase().replace(" z", "");
1046  // date format for plugin Tue Jun 23 10:27:54 2020 Z
1047  SimpleDateFormat dateFormat = new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy", US);
1048  Long dateLong = Long.valueOf(0);
1049  try {
1050  Date newDate = dateFormat.parse(dateString);
1051  dateLong = newDate.getTime() / 1000;
1052  } catch (ParseException ex) {
1053  // catching error and displaying date that could not be parsed
1054  // we set the timestamp to 0 and continue on processing
1055  logger.log(Level.WARNING, String.format("Failed to parse date/time %s for Bluetooth Last Seen attribute.", dateString), ex); //NON-NLS
1056  }
1057  attributes.add(new BlackboardAttribute(attributeType, getDisplayName(), dateLong));
1058  } else {
1059  attributes.add(new BlackboardAttribute(attributeType, getDisplayName(), tokenString));
1060  }
1061  }
1062  }
1063 
1074  private boolean parseSamPluginOutput(String regFilePath, AbstractFile regAbstractFile, long ingestJobId) {
1075 
1076  File regfile = new File(regFilePath);
1077  List<BlackboardArtifact> newArtifacts = new ArrayList<>();
1078  try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(regfile), StandardCharsets.UTF_8))) {
1079  // Read the file in and create a Document and elements
1080  String userInfoSection = "User Information";
1081  String previousLine = null;
1082  String line = bufferedReader.readLine();
1083  Set<Map<String, String>> userSet = new HashSet<>();
1084  Map<String, List<String>> groupMap = null;
1085  while (line != null) {
1086  if (line.contains(SECTION_DIVIDER) && previousLine != null && previousLine.contains(userInfoSection)) {
1087  readUsers(bufferedReader, userSet);
1088  }
1089 
1090  if (line.contains(SECTION_DIVIDER) && previousLine != null && previousLine.contains("Group Membership Information")) {
1091  groupMap = readGroups(bufferedReader);
1092  }
1093 
1094  previousLine = line;
1095  line = bufferedReader.readLine();
1096  }
1097  Map<String, Map<String, String>> userInfoMap = new HashMap<>();
1098  //load all the user info which was read into a map
1099  for (Map<String, String> userInfo : userSet) {
1100  String sid = userInfo.get(SID_KEY);
1101  userInfoMap.put(sid, userInfo);
1102  addSIDToSAMList(sid);
1103  }
1104 
1105  // New OsAccount Code
1106  OsAccountManager accountMgr = tskCase.getOsAccountManager();
1107  HostManager hostMrg = tskCase.getHostManager();
1108  Host host = hostMrg.getHostByDataSource((DataSource) dataSource);
1109 
1110  List<OsAccount> existingAccounts = accountMgr.getOsAccounts(host);
1111  for (OsAccount osAccount : existingAccounts) {
1112  Optional<String> optional = osAccount.getAddr();
1113  if (!optional.isPresent()) {
1114  continue;
1115  }
1116 
1117  String sid = optional.get();
1118  Map<String, String> userInfo = userInfoMap.remove(sid);
1119  if (userInfo != null) {
1120  addAccountInstance(accountMgr, osAccount, (DataSource) dataSource);
1121  updateOsAccount(osAccount, userInfo, groupMap.get(sid), regAbstractFile, ingestJobId);
1122  }
1123  }
1124 
1125  //add remaining userinfos as accounts;
1126  for (Map<String, String> userInfo : userInfoMap.values()) {
1127  OsAccount osAccount = accountMgr.newWindowsOsAccount(userInfo.get(SID_KEY), null, null, host, OsAccountRealm.RealmScope.LOCAL);
1128  accountMgr.newOsAccountInstance(osAccount, (DataSource) dataSource, OsAccountInstance.OsAccountInstanceType.LAUNCHED);
1129  updateOsAccount(osAccount, userInfo, groupMap.get(userInfo.get(SID_KEY)), regAbstractFile, ingestJobId);
1130  }
1131  return true;
1132  } catch (FileNotFoundException ex) {
1133  logger.log(Level.WARNING, "Error finding the registry file.", ex); //NON-NLS
1134  } catch (IOException ex) {
1135  logger.log(Level.WARNING, "Error building the document parser: {0}", ex); //NON-NLS
1136  } catch (TskDataException | TskCoreException ex) {
1137  logger.log(Level.WARNING, "Error updating TSK_OS_ACCOUNT artifacts to include newly parsed data.", ex); //NON-NLS
1138  } catch (OsAccountManager.NotUserSIDException ex) {
1139  logger.log(Level.WARNING, "Error creating OS Account, input SID is not a user SID.", ex); //NON-NLS
1140  } finally {
1141  if (!context.dataSourceIngestIsCancelled()) {
1142  postArtifacts(newArtifacts);
1143  }
1144  }
1145  return false;
1146  }
1147 
1159  private void readUsers(BufferedReader bufferedReader, Set<Map<String, String>> users) throws IOException {
1160  String line = bufferedReader.readLine();
1161  //read until end of file or next section divider
1162  String userName = "";
1163  String user_rid = "";
1164  while (line != null && !line.contains(SECTION_DIVIDER)) {
1165  //when a user name field exists read the name and id number
1166  if (line.contains(USERNAME_KEY)) {
1167  String regx = USERNAME_KEY + "\\s*?:";
1168  String userNameAndIdString = line.replaceAll(regx, "");
1169  userName = userNameAndIdString.substring(0, userNameAndIdString.lastIndexOf('[')).trim();
1170  user_rid = userNameAndIdString.substring(userNameAndIdString.lastIndexOf('['), userNameAndIdString.lastIndexOf(']'));
1171  } else if (line.contains(SID_KEY) && !userName.isEmpty()) {
1172  Map.Entry<String, String> entry = getSAMKeyValue(line);
1173 
1174  HashMap<String, String> userInfo = new HashMap<>();
1175  userInfo.put(USERNAME_KEY, userName);
1176  userInfo.put(RID_KEY, user_rid);
1177  userInfo.put(entry.getKey(), entry.getValue());
1178 
1179  //continue reading this users information until end of file or a blank line between users
1180  line = bufferedReader.readLine();
1181  while (line != null && !line.isEmpty()) {
1182  entry = getSAMKeyValue(line);
1183  if (entry != null) {
1184  userInfo.put(entry.getKey(), entry.getValue());
1185  }
1186  line = bufferedReader.readLine();
1187  }
1188  users.add(userInfo);
1189 
1190  userName = "";
1191  }
1192  line = bufferedReader.readLine();
1193  }
1194  }
1195 
1205  private void createRecentlyUsedArtifacts(String regFileName, AbstractFile regFile) throws FileNotFoundException, IOException {
1206  File regfile = new File(regFileName);
1207  try (BufferedReader reader = new BufferedReader(new FileReader(regfile))) {
1208  String line = reader.readLine();
1209  while (line != null) {
1210  line = line.trim();
1211 
1212  if (line.matches("^adoberdr v.*")) {
1213  parseAdobeMRUList(regFile, reader, Bundle.Recently_Used_Artifacts_Adobe());
1214  } else if (line.matches("^mpmru v.*")) {
1215  parseMediaPlayerMRUList(regFile, reader, Bundle.Recently_Used_Artifacts_Mediaplayer());
1216  } else if (line.matches("^trustrecords v.*")) {
1217  parseOfficeTrustRecords(regFile, reader, Bundle.Recently_Used_Artifacts_Office_Trustrecords());
1218  } else if (line.matches("^ArcHistory:")) {
1219  parse7ZipMRU(regFile, reader, Bundle.Recently_Used_Artifacts_ArcHistory());
1220  } else if (line.matches("^applets v.*")) {
1221  parseGenericMRUList(regFile, reader, Bundle.Recently_Used_Artifacts_Applets());
1222  } else if (line.matches("^mmc v.*")) {
1223  parseGenericMRUList(regFile, reader, Bundle.Recently_Used_Artifacts_Mmc());
1224  } else if (line.matches("^winrar v.*")) {
1225  parseWinRARMRUList(regFile, reader, Bundle.Recently_Used_Artifacts_Winrar());
1226  } else if (line.matches("^officedocs2010 v.*")) {
1227  parseOfficeDocs2010MRUList(regFile, reader, Bundle.Recently_Used_Artifacts_Officedocs());
1228  }
1229  line = reader.readLine();
1230  }
1231  }
1232  }
1233 
1245  private void parseBamKey(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1246  List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1247  String line = reader.readLine();
1248  // Read thru first bam output to get to second bam output which is the same but delimited
1249  while (!line.contains(SECTION_DIVIDER)) {
1250  line = reader.readLine();
1251  line = line.trim();
1252  }
1253  line = reader.readLine();
1254  line = line.trim();
1255  while (!line.contains(SECTION_DIVIDER)) {
1256  // Split the line into it parts based on delimiter of "|"
1257  // 1570493613|BAM|||\Device\HarddiskVolume3\Program Files\TechSmith\Snagit 2018\Snagit32.exe (S-1-5-21-3042408413-2583535980-1301764466-1001)
1258  String tokens[] = line.split("\\|");
1259  Long progRunDateTime = Long.valueOf(tokens[0]);
1260  // Split on " (S-" as this signifies a User SID, if S- not used then may have issues becuase of (x86) in path is valid.
1261  // We can add the S- back to the string that we split on since S- is a valid beginning of a User SID
1262  String fileNameSid[] = tokens[4].split("\\s+\\(S-");
1263  String userSid = "S-" + fileNameSid[1].substring(0, fileNameSid[1].length() - 1);
1264  String userName = getUserNameMap().get(userSid);
1265  if (userName == null) {
1266  userName = userSid;
1267  }
1268  String fileName = fileNameSid[0];
1269  if (fileName.startsWith("\\Device\\HarddiskVolume")) {
1270  // Start at point past the 2nd slash
1271  int fileNameStart = fileName.indexOf('\\', 16);
1272  fileName = fileName.substring(fileNameStart, fileName.length());
1273 
1274  }
1275  Collection<BlackboardAttribute> attributes = new ArrayList<>();
1276  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME, getDisplayName(), fileName));
1277  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME, getDisplayName(), userName));
1278  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME, getDisplayName(), progRunDateTime));
1279  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT, getDisplayName(), comment));
1280 
1281  try {
1282  BlackboardArtifact bba = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_PROG_RUN, regFile, attributes);
1283  bbartifacts.add(bba);
1284  bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1285  if (bba != null) {
1286  bbartifacts.add(bba);
1287  }
1288  } catch (TskCoreException ex) {
1289  logger.log(Level.SEVERE, String.format("Failed to create TSK_PROG_RUN artifact for file %d", regFile.getId()), ex);
1290  }
1291  line = reader.readLine();
1292  }
1293  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1294  postArtifacts(bbartifacts);
1295  }
1296  }
1297 
1309  private void parseAdobeMRUList(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1310  List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1311  String line = reader.readLine();
1312  SimpleDateFormat adobePluginDateFormat = new SimpleDateFormat("yyyyMMddHHmmssZ", US);
1313  Long adobeUsedTime = Long.valueOf(0);
1314  while (!line.contains(SECTION_DIVIDER)) {
1315  line = reader.readLine();
1316  line = line.trim();
1317  if (line.matches("^Key name,file name,sDate,uFileSize,uPageCount")) {
1318  line = reader.readLine();
1319  // Columns are
1320  // Key name, file name, sDate, uFileSize, uPageCount
1321  while (!line.contains(SECTION_DIVIDER)) {
1322  // Split csv line, handles double quotes around individual file names
1323  // since file names can contain commas
1324  String tokens[] = line.split(",(?=([^\"]*\"[^\"]*\")*[^\"]*$)");
1325  String fileName = tokens[1].substring(0, tokens[1].length() - 1);
1326  fileName = fileName.replace("\"", "");
1327  if (fileName.charAt(0) == '/') {
1328  fileName = fileName.substring(1, fileName.length() - 1);
1329  fileName = fileName.replaceFirst("/", ":/");
1330  }
1331  // Check to see if more then 2 tokens, Date may not be populated, will default to 0
1332  if (tokens.length > 2) {
1333  // Time in the format of 20200131104456-05'00'
1334  try {
1335  String fileUsedTime = tokens[2].replaceAll("'", "");
1336  Date usedDate = adobePluginDateFormat.parse(fileUsedTime);
1337  adobeUsedTime = usedDate.getTime() / 1000;
1338  } catch (ParseException ex) {
1339  // catching error and displaying date that could not be parsed
1340  // we set the timestamp to 0 and continue on processing
1341  logger.log(Level.WARNING, String.format("Failed to parse date/time %s for adobe file artifact.", tokens[2]), ex); //NON-NLS
1342  }
1343  }
1344  Collection<BlackboardAttribute> attributes = new ArrayList<>();
1345  attributes.add(new BlackboardAttribute(TSK_PATH, getDisplayName(), fileName));
1346  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED, getDisplayName(), adobeUsedTime));
1347  attributes.add(new BlackboardAttribute(TSK_COMMENT, getDisplayName(), comment));
1348  try {
1349  BlackboardArtifact bba = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_RECENT_OBJECT, regFile, attributes);
1350  if (bba != null) {
1351  bbartifacts.add(bba);
1352  fileName = fileName.replace("\0", "");
1353  bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1354  if (bba != null) {
1355  bbartifacts.add(bba);
1356  }
1357  }
1358  } catch (TskCoreException ex) {
1359  logger.log(Level.SEVERE, String.format("Failed to create TSK_RECENT_OBJECT artifact for file %d", regFile.getId()), ex);
1360  }
1361  line = reader.readLine();
1362  }
1363  line = line.trim();
1364  }
1365  }
1366  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1367  postArtifacts(bbartifacts);
1368  }
1369  }
1370 
1383  private void parseMediaPlayerMRUList(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1384  List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1385  String line = reader.readLine();
1386  while (!line.contains(SECTION_DIVIDER)) {
1387  line = reader.readLine();
1388  line = line.trim();
1389  if (line.contains("LastWrite")) {
1390  line = reader.readLine();
1391  // Columns are
1392  // FileX -> <Media file>
1393  while (!line.contains(SECTION_DIVIDER) && !line.contains("RecentFileList has no values.")) {
1394  // Split line on "> " which is the record delimiter between position and file
1395  String tokens[] = line.split("> ");
1396  String fileName = tokens[1];
1397  Collection<BlackboardAttribute> attributes = new ArrayList<>();
1398  attributes.add(new BlackboardAttribute(TSK_PATH, getDisplayName(), fileName));
1399  attributes.add(new BlackboardAttribute(TSK_COMMENT, getDisplayName(), comment));
1400  try {
1401  BlackboardArtifact bba = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_RECENT_OBJECT, regFile, attributes);
1402  if (bba != null) {
1403  bbartifacts.add(bba);
1404  bba = createAssociatedArtifact(fileName, bba);
1405  if (bba != null) {
1406  bbartifacts.add(bba);
1407  bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1408  if (bba != null) {
1409  bbartifacts.add(bba);
1410  }
1411  }
1412  }
1413  } catch (TskCoreException ex) {
1414  logger.log(Level.SEVERE, String.format("Failed to create TSK_RECENT_OBJECT artifact for file %d", regFile.getId()), ex);
1415  }
1416  line = reader.readLine();
1417  }
1418  line = line.trim();
1419  }
1420  }
1421  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1422  postArtifacts(bbartifacts);
1423  }
1424  }
1425 
1438  private void parseGenericMRUList(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1439  List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1440  String line = reader.readLine();
1441  while (!line.contains(SECTION_DIVIDER)) {
1442  line = reader.readLine();
1443  line = line.trim();
1444  if (line.contains("LastWrite")) {
1445  line = reader.readLine();
1446  // Columns are
1447  // FileX -> <file>
1448  while (!line.contains(SECTION_DIVIDER) && !line.isEmpty() && !line.contains("Applets")
1449  && !line.contains(("Recent File List"))) {
1450  // Split line on "> " which is the record delimiter between position and file
1451  String tokens[] = line.split("> ");
1452  if (tokens.length > 1) {
1453  String fileName = tokens[1];
1454  Collection<BlackboardAttribute> attributes = new ArrayList<>();
1455  attributes.add(new BlackboardAttribute(TSK_PATH, getDisplayName(), fileName));
1456  attributes.add(new BlackboardAttribute(TSK_COMMENT, getDisplayName(), comment));
1457  try {
1458  BlackboardArtifact bba = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_RECENT_OBJECT, regFile, attributes);
1459  if (bba != null) {
1460  bbartifacts.add(bba);
1461  bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1462  if (bba != null) {
1463  bbartifacts.add(bba);
1464  }
1465  }
1466  } catch (TskCoreException ex) {
1467  logger.log(Level.SEVERE, String.format("Failed to create TSK_RECENT_OBJECT artifact for file %d", regFile.getId()), ex);
1468  }
1469  }
1470  line = reader.readLine();
1471  }
1472  line = line.trim();
1473  }
1474  }
1475  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1476  postArtifacts(bbartifacts);
1477  }
1478  }
1479 
1492  private void parseWinRARMRUList(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1493  List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1494  String line = reader.readLine();
1495  while (!line.contains(SECTION_DIVIDER)) {
1496  line = reader.readLine();
1497  line = line.trim();
1498  if (line.contains("LastWrite")) {
1499  line = reader.readLine();
1500  // Columns are
1501  // FileX -> <Media file>
1502  if (!line.isEmpty()) {
1503  while (!line.contains(SECTION_DIVIDER)) {
1504  // Split line on "> " which is the record delimiter between position and file
1505  String tokens[] = line.split("> ");
1506  String fileName = tokens[1];
1507  Collection<BlackboardAttribute> attributes = new ArrayList<>();
1508  attributes.add(new BlackboardAttribute(TSK_PATH, getDisplayName(), fileName));
1509  attributes.add(new BlackboardAttribute(TSK_COMMENT, getDisplayName(), comment));
1510  try {
1511  BlackboardArtifact bba = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_RECENT_OBJECT, regFile, attributes);
1512  bbartifacts.add(bba);
1513  bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1514  if (bba != null) {
1515  bbartifacts.add(bba);
1516  }
1517  } catch (TskCoreException ex) {
1518  logger.log(Level.SEVERE, String.format("Failed to create TSK_RECENT_OBJECT artifact for file %d", regFile.getId()), ex);
1519  }
1520  line = reader.readLine();
1521  }
1522  }
1523  line = line.trim();
1524  }
1525  }
1526  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1527  postArtifacts(bbartifacts);
1528  }
1529  }
1530 
1543  private void parse7ZipMRU(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1544  List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1545  String line = reader.readLine();
1546  line = line.trim();
1547  if (!line.contains("PathHistory:")) {
1548  while (!line.contains("PathHistory:") && !line.isEmpty()) {
1549  // Columns are
1550  // <fileName>
1551  String fileName = line;
1552  Collection<BlackboardAttribute> attributes = new ArrayList<>();
1553  attributes.add(new BlackboardAttribute(TSK_PATH, getDisplayName(), fileName));
1554  attributes.add(new BlackboardAttribute(TSK_COMMENT, getDisplayName(), comment));
1555  try {
1556  BlackboardArtifact bba = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_RECENT_OBJECT, regFile, attributes);
1557  bbartifacts.add(bba);
1558  bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1559  if (bba != null) {
1560  bbartifacts.add(bba);
1561  }
1562 
1563  } catch (TskCoreException ex) {
1564  logger.log(Level.SEVERE, String.format("Failed to create TSK_RECENT_OBJECT artifact for file %d", regFile.getId()), ex);
1565  }
1566  line = reader.readLine();
1567  line = line.trim();
1568  }
1569  }
1570  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1571  postArtifacts(bbartifacts);
1572  }
1573  }
1574 
1587  private void parseOfficeDocs2010MRUList(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1588  List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1589  String line = reader.readLine();
1590  line = line.trim();
1591  // Reading to the SECTION DIVIDER to get next section of records to process. Dates appear to have
1592  // multiple spaces in them that makes it harder to parse so next section will be easier to parse
1593  while (!line.contains(SECTION_DIVIDER)) {
1594  line = reader.readLine();
1595  }
1596  line = reader.readLine();
1597  while (!line.contains(SECTION_DIVIDER)) {
1598  // record has the following format
1599  // 1294283922|REG|||OfficeDocs2010 - F:\Windows_time_Rules_xp.doc
1600  String tokens[] = line.split("\\|");
1601  Long docDate = Long.valueOf(tokens[0]);
1602  String fileNameTokens[] = tokens[4].split(" - ");
1603  String fileName = fileNameTokens[1];
1604  Collection<BlackboardAttribute> attributes = new ArrayList<>();
1605  attributes.add(new BlackboardAttribute(TSK_PATH, getDisplayName(), fileName));
1606  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED, getDisplayName(), docDate));
1607  attributes.add(new BlackboardAttribute(TSK_COMMENT, getDisplayName(), comment));
1608  try {
1609  BlackboardArtifact bba = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_RECENT_OBJECT, regFile, attributes);
1610  bbartifacts.add(bba);
1611  bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1612  if (bba != null) {
1613  bbartifacts.add(bba);
1614  }
1615  } catch (TskCoreException ex) {
1616  logger.log(Level.SEVERE, String.format("Failed to create TSK_RECENT_OBJECT artifact for file %d", regFile.getId()), ex);
1617  }
1618  line = reader.readLine();
1619  line = line.trim();
1620  }
1621  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1622  postArtifacts(bbartifacts);
1623  }
1624  }
1625 
1638  private void parseOfficeTrustRecords(AbstractFile regFile, BufferedReader reader, String comment) throws FileNotFoundException, IOException {
1639  String userProfile = regFile.getParentPath();
1640  userProfile = userProfile.substring(0, userProfile.length() - 1);
1641  List<BlackboardArtifact> bbartifacts = new ArrayList<>();
1642  SimpleDateFormat pluginDateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy", US);
1643  Long usedTime = Long.valueOf(0);
1644  String line = reader.readLine();
1645  while (!line.contains(SECTION_DIVIDER)) {
1646  line = reader.readLine();
1647  line = line.trim();
1648  usedTime = Long.valueOf(0);
1649  if (!line.contains("**") && !line.contains("----------") && !line.contains("LastWrite")
1650  && !line.contains(SECTION_DIVIDER) && !line.isEmpty() && !line.contains("TrustRecords")
1651  && !line.contains("VBAWarnings =")) {
1652  // Columns are
1653  // Date : <File Name>/<Website>
1654  // Split line on " : " which is the record delimiter between position and file
1655  String fileName = null;
1656  String tokens[] = line.split(" : ");
1657  fileName = tokens[1];
1658  fileName = fileName.replace("%USERPROFILE%", userProfile);
1659  // Time in the format of Wed May 31 14:33:03 2017 Z
1660  try {
1661  String fileUsedTime = tokens[0].replaceAll(" Z", "");
1662  Date usedDate = pluginDateFormat.parse(fileUsedTime);
1663  usedTime = usedDate.getTime() / 1000;
1664  } catch (ParseException ex) {
1665  // catching error and displaying date that could not be parsed
1666  // we set the timestamp to 0 and continue on processing
1667  logger.log(Level.WARNING, String.format("Failed to parse date/time %s for TrustRecords artifact.", tokens[0]), ex); //NON-NLS
1668  }
1669  Collection<BlackboardAttribute> attributes = new ArrayList<>();
1670  attributes.add(new BlackboardAttribute(TSK_PATH, getDisplayName(), fileName));
1671  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED, getDisplayName(), usedTime));
1672  attributes.add(new BlackboardAttribute(TSK_COMMENT, getDisplayName(), comment));
1673  try {
1674  BlackboardArtifact bba = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_RECENT_OBJECT, regFile, attributes);
1675  bbartifacts.add(bba);
1676  bba = createAssociatedArtifact(FilenameUtils.normalize(fileName, true), bba);
1677  if (bba != null) {
1678  bbartifacts.add(bba);
1679  }
1680  } catch (TskCoreException ex) {
1681  logger.log(Level.SEVERE, String.format("Failed to create TSK_RECENT_OBJECT artifact for file %d", regFile.getId()), ex);
1682  }
1683  line = line.trim();
1684  }
1685  }
1686  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1687  postArtifacts(bbartifacts);
1688  }
1689  }
1690 
1701  private BlackboardArtifact createAssociatedArtifact(String filePathName, BlackboardArtifact bba) {
1702  String fileName = FilenameUtils.getName(filePathName);
1703  String filePath = FilenameUtils.getPath(filePathName);
1704  List<AbstractFile> sourceFiles;
1705  try {
1706  sourceFiles = currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, fileName, filePath);
1707  if (!sourceFiles.isEmpty()) {
1708  return createAssociatedArtifact(sourceFiles.get(0), bba);
1709  }
1710  } catch (TskCoreException ex) {
1711  // only catching the error and displaying the message as the file may not exist on the
1712  // system anymore
1713  logger.log(Level.WARNING, String.format("Error finding actual file %s. file may not exist", filePathName)); //NON-NLS
1714  }
1715 
1716  return null;
1717  }
1718 
1729  private Map<String, String> makeUserNameMap(Content dataSource) throws TskCoreException {
1730  Map<String, String> map = new HashMap<>();
1731 
1732  for (OsAccount account : tskCase.getOsAccountManager().getOsAccounts(((DataSource) dataSource).getHost())) {
1733  Optional<String> userName = account.getLoginName();
1734  String address = account.getAddr().orElse("");
1735  if (!address.isEmpty()) {
1736  map.put(address, userName.isPresent() ? userName.get() : "");
1737  }
1738  }
1739 
1740  return map;
1741  }
1742 
1762  private String stripRelativeIdentifierFromSID(String osAccountSID) {
1763  if (osAccountSID.split("-").length > 4) {
1764  int index = osAccountSID.lastIndexOf('-');
1765  return index > 1 ? osAccountSID.substring(0, index) : "";
1766  }
1767  return "";
1768  }
1769 
1770  private final List<String> machineSIDs = new ArrayList<>();
1771 
1777  private Map<String, String> getUserNameMap() {
1778  if (userNameMap == null) {
1779  // Get a mapping of user sids to user names and save globally so it can be used for other areas
1780  // of the registry, ie: BAM key
1781  try {
1782  userNameMap = makeUserNameMap(dataSource);
1783  } catch (TskCoreException ex) {
1784  logger.log(Level.WARNING, "Unable to create OS Account user name map", ex);
1785  // This is not the end of the world we will just continue without
1786  // user names
1787  userNameMap = new HashMap<>();
1788  }
1789  }
1790 
1791  return userNameMap;
1792  }
1793 
1804  private BlackboardAttribute getAttributeForArtifact(BlackboardArtifact artifact, BlackboardAttribute.ATTRIBUTE_TYPE type) throws TskCoreException {
1805  return artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(type.getTypeID())));
1806  }
1807 
1816  void createShellBagArtifacts(AbstractFile regFile, List<ShellBag> shellbags) throws TskCoreException {
1817  List<BlackboardArtifact> artifacts = new ArrayList<>();
1818  try {
1819  for (ShellBag bag : shellbags) {
1820  Collection<BlackboardAttribute> attributes = new ArrayList<>();
1821  attributes.add(new BlackboardAttribute(TSK_PATH, getDisplayName(), bag.getResource()));
1822  attributes.add(new BlackboardAttribute(getKeyAttribute(), getDisplayName(), bag.getKey()));
1823 
1824  long time;
1825  time = bag.getLastWrite();
1826  if (time != 0) {
1827  attributes.add(new BlackboardAttribute(getLastWriteAttribute(), getDisplayName(), time));
1828  }
1829 
1830  time = bag.getModified();
1831  if (time != 0) {
1832  attributes.add(new BlackboardAttribute(TSK_DATETIME_MODIFIED, getDisplayName(), time));
1833  }
1834 
1835  time = bag.getCreated();
1836  if (time != 0) {
1837  attributes.add(new BlackboardAttribute(TSK_DATETIME_CREATED, getDisplayName(), time));
1838  }
1839 
1840  time = bag.getAccessed();
1841  if (time != 0) {
1842  attributes.add(new BlackboardAttribute(TSK_DATETIME_ACCESSED, getDisplayName(), time));
1843  }
1844 
1845  BlackboardArtifact artifact = createArtifactWithAttributes(getShellBagArtifact(), regFile, attributes);
1846  artifacts.add(artifact);
1847  }
1848  } finally {
1849  if (!context.dataSourceIngestIsCancelled()) {
1850  postArtifacts(artifacts);
1851  }
1852  }
1853  }
1854 
1863  private BlackboardArtifact.Type getShellBagArtifact() throws TskCoreException {
1864  if (shellBagArtifactType == null) {
1865  try {
1866  shellBagArtifactType = tskCase.getBlackboard().getOrAddArtifactType(SHELLBAG_ARTIFACT_NAME, Bundle.Shellbag_Artifact_Display_Name());
1867  } catch (BlackboardException ex) {
1868  throw new TskCoreException(String.format("Failed to get shell bag artifact type", SHELLBAG_ARTIFACT_NAME), ex);
1869  }
1870  }
1871 
1872  return shellBagArtifactType;
1873  }
1874 
1883  private BlackboardAttribute.Type getLastWriteAttribute() throws TskCoreException {
1884  if (shellBagLastWriteAttributeType == null) {
1885  try {
1886  shellBagLastWriteAttributeType = tskCase.getBlackboard().getOrAddAttributeType(SHELLBAG_ATTRIBUTE_LAST_WRITE,
1887  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME,
1888  Bundle.Shellbag_Last_Write_Attribute_Display_Name());
1889  } catch (BlackboardException ex) {
1890  // Attribute already exists get it from the case
1891  throw new TskCoreException(String.format("Failed to get custom attribute %s", SHELLBAG_ATTRIBUTE_LAST_WRITE), ex);
1892  }
1893  }
1894  return shellBagLastWriteAttributeType;
1895  }
1896 
1905  private BlackboardAttribute.Type getKeyAttribute() throws TskCoreException {
1906  if (shellBagKeyAttributeType == null) {
1907  try {
1908  shellBagKeyAttributeType = tskCase.getBlackboard().getOrAddAttributeType(SHELLBAG_ATTRIBUTE_KEY,
1909  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
1910  Bundle.Shellbag_Key_Attribute_Display_Name());
1911  } catch (BlackboardException ex) {
1912  throw new TskCoreException(String.format("Failed to get key attribute %s", SHELLBAG_ATTRIBUTE_KEY), ex);
1913  }
1914  }
1915  return shellBagKeyAttributeType;
1916  }
1917 
1927  Map<String, List<String>> readGroups(BufferedReader bufferedReader) throws IOException {
1928  Map<String, List<String>> groupMap = new HashMap<>();
1929 
1930  String line = bufferedReader.readLine();
1931 
1932  int userCount = 0;
1933  String groupName = null;
1934 
1935  while (line != null && !line.contains(SECTION_DIVIDER)) {
1936 
1937  if (line.contains("Group Name")) {
1938  String value = line.replaceAll("Group Name\\s*?:", "").trim();
1939  groupName = (value.replaceAll("\\[\\d*?\\]", "")).trim();
1940  int startIndex = value.indexOf(" [") + 1;
1941  int endIndex = value.indexOf(']');
1942 
1943  if (startIndex != -1 && endIndex != -1) {
1944  String countStr = value.substring(startIndex + 1, endIndex);
1945  userCount = Integer.parseInt(countStr);
1946  }
1947  } else if (line.matches("Users\\s*?:")) {
1948  for (int i = 0; i < userCount; i++) {
1949  line = bufferedReader.readLine();
1950  if (line != null) {
1951  String sid = line.trim();
1952  List<String> groupList = groupMap.get(sid);
1953  if (groupList == null) {
1954  groupList = new ArrayList<>();
1955  groupMap.put(sid, groupList);
1956  }
1957  groupList.add(groupName);
1958  }
1959  }
1960  groupName = null;
1961  }
1962  line = bufferedReader.readLine();
1963  }
1964  return groupMap;
1965  }
1966 
1975  private Map.Entry<String, String> getSAMKeyValue(String line) {
1976  int index = line.indexOf(':');
1977  Map.Entry<String, String> returnValue = null;
1978  String key = null;
1979  String value = null;
1980 
1981  if (index != -1) {
1982  key = line.substring(0, index).trim();
1983  if (index + 1 < line.length()) {
1984  value = line.substring(index + 1).trim();
1985  } else {
1986  value = "";
1987  }
1988 
1989  } else if (line.contains("-->")) {
1990  key = line.replace("-->", "").trim();
1991  value = "true";
1992  }
1993 
1994  if (key != null) {
1995  returnValue = new AbstractMap.SimpleEntry<>(key, value);
1996  }
1997 
1998  return returnValue;
1999  }
2000 
2001  @Override
2002  public void process(Content dataSource, DataSourceIngestModuleProgress progressBar) {
2003  this.dataSource = dataSource;
2004 
2005  progressBar.progress(Bundle.Progress_Message_Analyze_Registry());
2006  analyzeRegistryFiles(context.getJobId());
2007  }
2008 
2012  private class RegOutputFiles {
2013 
2014  public String autopsyPlugins = "";
2015  public String fullPlugins = "";
2016  }
2017 
2030  private void createOrUpdateOsAccount(AbstractFile file, String sid, String userName, String homeDir, String domainName, OsAccountRealm.RealmScope realmScope) throws TskCoreException, TskDataException, NotUserSIDException {
2031  OsAccountManager accountMgr = tskCase.getOsAccountManager();
2032  HostManager hostMrg = tskCase.getHostManager();
2033  Host host = hostMrg.getHostByDataSource((DataSource) dataSource);
2034 
2035  Optional<OsAccount> optional = accountMgr.getWindowsOsAccount(sid, null, null, host);
2036  OsAccount osAccount;
2037  if (!optional.isPresent()) {
2038  osAccount = accountMgr.newWindowsOsAccount(sid, userName != null && userName.isEmpty() ? null : userName, domainName, host, realmScope);
2039  accountMgr.newOsAccountInstance(osAccount, (DataSource) dataSource, OsAccountInstance.OsAccountInstanceType.LAUNCHED);
2040  } else {
2041  osAccount = optional.get();
2042  addAccountInstance(accountMgr, osAccount, (DataSource) dataSource);
2043  if (userName != null && !userName.isEmpty()) {
2044  OsAccountUpdateResult updateResult = accountMgr.updateCoreWindowsOsAccountAttributes(osAccount, null, userName, (domainName == null || domainName.isEmpty()) ? null : domainName, host);
2045  osAccount = updateResult.getUpdatedAccount().orElse(osAccount);
2046  }
2047  }
2048 
2049  if (homeDir != null && !homeDir.isEmpty()) {
2050  List<OsAccountAttribute> attributes = new ArrayList<>();
2051  String dir = homeDir.replaceFirst("^(%\\w*%)", "");
2052  dir = dir.replace("\\", "/");
2053  attributes.add(createOsAccountAttribute(TSK_HOME_DIR, dir, osAccount, host, file));
2054  accountMgr.addExtendedOsAccountAttributes(osAccount, attributes);
2055  }
2056 
2057  }
2058 
2066  private void addEmailAccount(AbstractFile regFile, String emailAddress, long ingestJobId) {
2067  try {
2068  currentCase.getSleuthkitCase()
2069  .getCommunicationsManager()
2070  .createAccountFileInstance(Account.Type.EMAIL,
2071  emailAddress, getRAModuleName(), regFile,
2072  Collections.emptyList(),
2073  ingestJobId);
2074  } catch (TskCoreException ex) {
2075  logger.log(Level.SEVERE,
2076  String.format("Error adding email account with value "
2077  + "%s, to the case database for file %s [objId=%d]",
2078  emailAddress, regFile.getName(), regFile.getId()), ex);
2079  }
2080  }
2081 
2090  private Long parseRegRipTime(String value) {
2091  try {
2092  return REG_RIPPER_TIME_FORMAT.parse(value).getTime() / MS_IN_SEC;
2093  } catch (ParseException ex) {
2094  logger.log(Level.SEVERE, String.format("Failed to parse reg rip time: %s", value));
2095  }
2096  return null;
2097  }
2098 
2111  private void updateOsAccount(OsAccount osAccount, Map<String, String> userInfo, List<String> groupList, AbstractFile regFile, long ingestJobId) throws TskDataException, TskCoreException, NotUserSIDException {
2112  Host host = ((DataSource) dataSource).getHost();
2113  SimpleDateFormat regRipperTimeFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy 'Z'", US);
2114  regRipperTimeFormat.setTimeZone(getTimeZone("GMT"));
2115 
2116  List<OsAccountAttribute> attributes = new ArrayList<>();
2117 
2118  Long creationTime = null;
2119 
2120  String value = userInfo.get(ACCOUNT_CREATED_KEY);
2121  if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) {
2122  creationTime = parseRegRipTime(value);
2123  }
2124 
2125  value = userInfo.get(LAST_LOGIN_KEY);
2126  if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) {
2127  Long time = parseRegRipTime(value);
2128  if (time != null) {
2129  attributes.add(createOsAccountAttribute(TSK_DATETIME_ACCESSED,
2130  parseRegRipTime(value),
2131  osAccount, host, regFile));
2132  }
2133  }
2134 
2135  String loginName = null;
2136  value = userInfo.get(USERNAME_KEY);
2137  if (value != null && !value.isEmpty()) {
2138  loginName = value;
2139  }
2140 
2141  value = userInfo.get(LOGIN_COUNT_KEY);
2142  if (value != null && !value.isEmpty()) {
2143  attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
2144  Integer.parseInt(value),
2145  osAccount, host, regFile));
2146  }
2147 
2148  // From regripper the possible values for this key are
2149  // "Default Admin User", "Custom Limited Acct"
2150  // and "Default Guest Acct"
2151  value = userInfo.get(ACCOUNT_TYPE_KEY);
2152  if (value != null && !value.isEmpty() && value.toLowerCase().contains("admin")) {
2153  attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_IS_ADMIN,
2154  1, osAccount, host, regFile));
2155  }
2156 
2157  value = userInfo.get(USER_COMMENT_KEY);
2158  if (value != null && !value.isEmpty()) {
2159  attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_DESCRIPTION,
2160  value, osAccount, host, regFile));
2161  }
2162 
2163  value = userInfo.get(INTERNET_NAME_KEY);
2164  if (value != null && !value.isEmpty()) {
2165  addEmailAccount(regFile, value, ingestJobId);
2166 
2167  attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_EMAIL,
2168  value, osAccount, host, regFile));
2169  }
2170 
2171  // FULL_NAME_KEY and NAME_KEY appear to be the same value.
2172  String fullName = null;
2173  value = userInfo.get(FULL_NAME_KEY);
2174  if (value != null && !value.isEmpty()) {
2175  fullName = value;
2176  } else {
2177  value = userInfo.get(NAME_KEY);
2178  if (value != null && !value.isEmpty()) {
2179  fullName = value;
2180  }
2181  }
2182 
2183  value = userInfo.get(PWD_RESET_KEY);
2184  if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) {
2185  Long time = parseRegRipTime(value);
2186  if (time != null) {
2187  attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_PASSWORD_RESET,
2188  time, osAccount, host, regFile));
2189  }
2190  }
2191 
2192  value = userInfo.get(SECURITY_QUESTION_1);
2193  if (value != null && !value.isEmpty()) {
2194  BlackboardAttribute.Type securityQuestionAttributeType = null;
2195  try {
2196  securityQuestionAttributeType = tskCase.getBlackboard().getOrAddAttributeType(SAM_SECURITY_QUESTION_1,
2197  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
2198  Bundle.Sam_Security_Question_1_Attribute_Display_Name());
2199  } catch (BlackboardException ex) {
2200  throw new TskCoreException(String.format("Failed to get key attribute %s", SAM_SECURITY_QUESTION_1), ex);
2201  }
2202  attributes.add(createOsAccountAttribute(securityQuestionAttributeType, value, osAccount, host, regFile));
2203  }
2204 
2205  value = userInfo.get(SECURITY_ANSWER_1);
2206  if (value != null && !value.isEmpty()) {
2207  BlackboardAttribute.Type securityAnswerAttributeType = null;
2208  try {
2209  securityAnswerAttributeType = tskCase.getBlackboard().getOrAddAttributeType(SAM_SECURITY_ANSWER_1,
2210  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
2211  Bundle.Sam_Security_Answer_1_Attribute_Display_Name());
2212  } catch (BlackboardException ex) {
2213  throw new TskCoreException(String.format("Failed to get key attribute %s", SAM_SECURITY_ANSWER_1), ex);
2214  }
2215  attributes.add(createOsAccountAttribute(securityAnswerAttributeType, value, osAccount, host, regFile));
2216  }
2217 
2218  value = userInfo.get(SECURITY_QUESTION_2);
2219  if (value != null && !value.isEmpty()) {
2220  BlackboardAttribute.Type securityQuestionAttributeType = null;
2221  try {
2222  securityQuestionAttributeType = tskCase.getBlackboard().getOrAddAttributeType(SAM_SECURITY_QUESTION_2,
2223  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
2224  Bundle.Sam_Security_Question_2_Attribute_Display_Name());
2225  } catch (BlackboardException ex) {
2226  throw new TskCoreException(String.format("Failed to get key attribute %s", SAM_SECURITY_QUESTION_2), ex);
2227  }
2228  attributes.add(createOsAccountAttribute(securityQuestionAttributeType, value, osAccount, host, regFile));
2229  }
2230 
2231  value = userInfo.get(SECURITY_ANSWER_2);
2232  if (value != null && !value.isEmpty()) {
2233  BlackboardAttribute.Type securityAnswerAttributeType = null;
2234  try {
2235  securityAnswerAttributeType = tskCase.getBlackboard().getOrAddAttributeType(SAM_SECURITY_ANSWER_2,
2236  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
2237  Bundle.Sam_Security_Answer_2_Attribute_Display_Name());
2238  } catch (BlackboardException ex) {
2239  throw new TskCoreException(String.format("Failed to get key attribute %s", SAM_SECURITY_ANSWER_2), ex);
2240  }
2241  attributes.add(createOsAccountAttribute(securityAnswerAttributeType, value, osAccount, host, regFile));
2242  }
2243 
2244  value = userInfo.get(SECURITY_QUESTION_3);
2245  if (value != null && !value.isEmpty()) {
2246  BlackboardAttribute.Type securityQuestionAttributeType = null;
2247  try {
2248  securityQuestionAttributeType = tskCase.getBlackboard().getOrAddAttributeType(SAM_SECURITY_QUESTION_3,
2249  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
2250  Bundle.Sam_Security_Question_2_Attribute_Display_Name());
2251  } catch (BlackboardException ex) {
2252  throw new TskCoreException(String.format("Failed to get key attribute %s", SAM_SECURITY_QUESTION_3), ex);
2253  }
2254  attributes.add(createOsAccountAttribute(securityQuestionAttributeType, value, osAccount, host, regFile));
2255  }
2256 
2257  value = userInfo.get(SECURITY_ANSWER_3);
2258  if (value != null && !value.isEmpty()) {
2259  BlackboardAttribute.Type securityAnswerAttributeType = null;
2260  try {
2261  securityAnswerAttributeType = tskCase.getBlackboard().getOrAddAttributeType(SAM_SECURITY_ANSWER_3,
2262  BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
2263  Bundle.Sam_Security_Answer_3_Attribute_Display_Name());
2264  } catch (BlackboardException ex) {
2265  throw new TskCoreException(String.format("Failed to get key attribute %s", SAM_SECURITY_ANSWER_3), ex);
2266  }
2267  attributes.add(createOsAccountAttribute(securityAnswerAttributeType, value, osAccount, host, regFile));
2268  }
2269 
2270  value = userInfo.get(PASSWORD_HINT);
2271  if (value != null && !value.isEmpty()) {
2272  attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_PASSWORD_HINT,
2273  value, osAccount, host, regFile));
2274  }
2275 
2276  value = userInfo.get(PWD_FAILE_KEY);
2277  if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) {
2278  Long time = parseRegRipTime(value);
2279  if (time != null) {
2280  attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_PASSWORD_FAIL,
2281  time, osAccount, host, regFile));
2282  }
2283  }
2284 
2285  String settingString = getSettingsFromMap(PASSWORD_SETTINGS_FLAGS, userInfo);
2286  if (!settingString.isEmpty()) {
2287  attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_PASSWORD_SETTINGS,
2288  settingString, osAccount, host, regFile));
2289  }
2290 
2291  settingString = getSettingsFromMap(ACCOUNT_SETTINGS_FLAGS, userInfo);
2292  if (!settingString.isEmpty()) {
2293  attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_ACCOUNT_SETTINGS,
2294  settingString, osAccount, host, regFile));
2295  }
2296 
2297  settingString = getSettingsFromMap(ACCOUNT_TYPE_FLAGS, userInfo);
2298  if (!settingString.isEmpty()) {
2299  attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_FLAG,
2300  settingString, osAccount, host, regFile));
2301  }
2302 
2303  if (groupList != null && groupList.isEmpty()) {
2304  String groups = groupList.stream()
2305  .map(String::valueOf)
2306  .collect(Collectors.joining(", "));
2307 
2308  attributes.add(createOsAccountAttribute(ATTRIBUTE_TYPE.TSK_GROUPS,
2309  groups, osAccount, host, regFile));
2310  }
2311 
2312  // add the attributes to account.
2313  OsAccountManager accountMgr = tskCase.getOsAccountManager();
2314  accountMgr.addExtendedOsAccountAttributes(osAccount, attributes);
2315 
2316  // update the loginname
2317  accountMgr.updateCoreWindowsOsAccountAttributes(osAccount, null, loginName, null, host);
2318 
2319  // update other standard attributes - fullname, creationdate
2320  accountMgr.updateStandardOsAccountAttributes(osAccount, fullName, null, null, creationTime);
2321 
2322  }
2323 
2332  private String getSettingsFromMap(String[] keys, Map<String, String> map) {
2333  List<String> settingsList = new ArrayList<>();
2334  for (String setting : keys) {
2335  if (map.containsKey(setting)) {
2336  settingsList.add(setting);
2337  }
2338  }
2339 
2340  if (!settingsList.isEmpty()) {
2341  return settingsList.stream()
2342  .map(String::valueOf)
2343  .collect(Collectors.joining(", "));
2344  }
2345 
2346  return "";
2347  }
2348 
2360  private OsAccountAttribute createOsAccountAttribute(BlackboardAttribute.Type type, String value, OsAccount osAccount, Host host, AbstractFile file) {
2361  return osAccount.new OsAccountAttribute(type, value, osAccount, host, file);
2362  }
2363 
2375  private OsAccountAttribute createOsAccountAttribute(BlackboardAttribute.ATTRIBUTE_TYPE type, String value, OsAccount osAccount, Host host, AbstractFile file) {
2376  return osAccount.new OsAccountAttribute(new BlackboardAttribute.Type(type), value, osAccount, host, file);
2377  }
2378 
2390  private OsAccountAttribute createOsAccountAttribute(BlackboardAttribute.ATTRIBUTE_TYPE type, Long value, OsAccount osAccount, Host host, AbstractFile file) {
2391  return osAccount.new OsAccountAttribute(new BlackboardAttribute.Type(type), value, osAccount, host, file);
2392  }
2393 
2405  private OsAccountAttribute createOsAccountAttribute(BlackboardAttribute.ATTRIBUTE_TYPE type, Integer value, OsAccount osAccount, Host host, AbstractFile file) {
2406  return osAccount.new OsAccountAttribute(new BlackboardAttribute.Type(type), value, osAccount, host, file);
2407  }
2408 
2419  private void addAccountInstance(OsAccountManager accountMgr, OsAccount osAccount, DataSource dataSource) throws TskCoreException {
2420  accountMgr.newOsAccountInstance(osAccount, dataSource, OsAccountInstance.OsAccountInstanceType.LAUNCHED);
2421  }
2422 
2428  private void addSIDToSAMList(String sid) {
2429  String relativeID = stripRelativeIdentifierFromSID(sid);
2430  if (!relativeID.isEmpty() && !samDomainIDsList.contains(relativeID)) {
2431  samDomainIDsList.add(relativeID);
2432  }
2433  }
2434 
2443  private boolean isDomainIdInSAMList(String osAccountSID) {
2444  String relativeID = stripRelativeIdentifierFromSID(osAccountSID);
2445  return samDomainIDsList.contains(relativeID);
2446  }
2447 
2448  // Structure to keep the OSInfo meta data so that only one instance
2449  // of TSK_OS_INFO is created per RA run.
2450  private class OSInfo {
2451  private String compName = null;
2452  private String progName = "Windows";
2453  private String processorArchitecture = null;
2454  private String tempDir = null;
2455  private String domain = null;
2456  private Long installtime = null;
2457  private String systemRoot = null;
2458  private String productId = null;
2459  private String regOwner = null;
2460  private String regOrg = null;
2461 
2462  private OSInfo() {}
2463 
2464  void createOSInfo() {
2465  try{
2466  String parentModuleName = RecentActivityExtracterModuleFactory.getModuleName();
2467  ArrayList<BlackboardArtifact> results = tskCase.getBlackboardArtifacts(ARTIFACT_TYPE.TSK_OS_INFO, context.getDataSource().getId());
2468 
2469  if (results.isEmpty()) {
2470  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
2471  if (compName != null && !compName.isEmpty()) {
2472  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, parentModuleName, compName));
2473  }
2474  if (domain != null && !domain.isEmpty()) {
2475  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN, parentModuleName, domain));
2476  }
2477  if (progName != null && !progName.isEmpty()) {
2478  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME, parentModuleName, progName));
2479  }
2480  if (processorArchitecture != null && !processorArchitecture.isEmpty()) {
2481  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROCESSOR_ARCHITECTURE, parentModuleName, processorArchitecture));
2482  }
2483  if (tempDir != null && !tempDir.isEmpty()) {
2484  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TEMP_DIR, parentModuleName, tempDir));
2485  }
2486  if (installtime != null) {
2487  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME, parentModuleName, installtime));
2488  }
2489  if (systemRoot != null && !systemRoot.isEmpty()) {
2490  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH, parentModuleName, systemRoot));
2491  }
2492  if (productId != null && !productId.isEmpty()) {
2493  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PRODUCT_ID, parentModuleName, productId));
2494  }
2495  if (regOwner != null && !regOwner.isEmpty()) {
2496  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_OWNER, parentModuleName, regOwner));
2497  }
2498  if (regOrg != null && !regOrg.isEmpty()) {
2499  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ORGANIZATION, parentModuleName, regOrg));
2500  }
2501 
2502  postArtifact(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_OS_INFO, context.getDataSource(), bbattributes));
2503  }
2504  } catch (TskCoreException ex) {
2505  logger.log(Level.SEVERE, "Failed to create default OS_INFO artifact", ex); //NON-NLS
2506  }
2507  }
2508 
2509  void setCompName(String compName) {
2510  if(this.compName == null || this.compName.isEmpty()) {
2511  this.compName = compName;
2512  }
2513  }
2514 
2515  void setOsName(String progName) {
2516  if(progName != null && !progName.isEmpty()) {
2517  this.progName = progName;
2518  }
2519  }
2520 
2521  void setProcessorArchitecture(String processorArchitecture) {
2522  if(this.processorArchitecture == null || this.processorArchitecture.isEmpty()) {
2523  this.processorArchitecture = processorArchitecture;
2524  }
2525  }
2526 
2527  void setTempDir(String tempDir) {
2528  if(this.tempDir == null || this.tempDir.isEmpty()) {
2529  this.tempDir = tempDir;
2530  }
2531  }
2532 
2533  void setDomain(String domain) {
2534  if(this.domain == null || this.domain.isEmpty()) {
2535  this.domain = domain;
2536  }
2537  }
2538 
2539  void setInstalltime(Long installtime) {
2540  if(this.domain == null) {
2541  this.installtime = installtime;
2542  }
2543  }
2544 
2545  void setSystemRoot(String systemRoot) {
2546  if(this.systemRoot == null || this.systemRoot.isEmpty()) {
2547  this.systemRoot = systemRoot;
2548  }
2549  }
2550 
2551  void setProductId(String productId) {
2552  if(this.productId == null || this.productId.isEmpty()) {
2553  this.productId = productId;
2554  }
2555  }
2556 
2557  void setRegOwner(String regOwner) {
2558  if(this.regOwner == null || this.regOwner.isEmpty()) {
2559  this.regOwner = regOwner;
2560  }
2561  }
2562 
2563  void setRegOrg(String regOrg) {
2564  if(this.regOrg == null || this.regOrg.isEmpty()) {
2565  this.regOrg = regOrg;
2566  }
2567  }
2568  }
2569 
2570 }

Copyright © 2012-2022 Basis Technology. Generated on: Thu Oct 6 2022
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.