1 /*
2  * The Sleuth Kit
3  *
4  * Contact: Brian Carrier [carrier <at> sleuthkit [dot] org]
5  * Copyright (c) 2011-2012 Basis Technology Corporation. All Rights
6  * reserved.
7  *
8  * This software is distributed under the Common Public License 1.0
9  */
10 
11 /**
12  * \file SummaryReport.cpp
13  * Contains the implementation of a function that creates a blackboard artifacts report.
14  */
15 
16 // TSK Framework includes
17 #include "tsk/framework/utilities/TskUtilities.h"
18 #include "tsk/framework/services/TskServices.h"
19 
20 // Poco includes
21 #include "Poco/FileStream.h"
22 
23 // C/C++ standard library includes
24 #include <string>
25 #include <sstream>
26 
27 namespace
28 {
29     // Convert reserved HTML characters to HTML entities
HTMLEncode(const std::string & str)30     std::string HTMLEncode(const std::string &str)
31     {
32         std::string convertedStr;
33         for (size_t i = 0; i < str.size(); i++)
34         {
35             if (str[i] == '<')
36                 convertedStr.append("&lt;");
37             else if (str[i] == '>')
38                 convertedStr.append("&gt;");
39             else if (str[i] == '&')
40                 convertedStr.append("&amp;");
41             else if (str[i] == '"')
42                 convertedStr.append("&quot;");
43             else if (str[i] == '\'')
44                 convertedStr.append("&apos;");
45             else
46                 convertedStr += str[i];
47         }
48         return convertedStr;
49     }
50 
addStyle(Poco::FileOutputStream & out)51     void addStyle(Poco::FileOutputStream &out)
52     {
53         out << "<style type=\"text/css\">" << std::endl <<
54             "table.gridtable {" << std::endl <<
55             "font-family: verdana,arial,sans-serif;" << std::endl <<
56             "font-size:11px;" << std::endl <<
57             "color:#333333;" << std::endl <<
58             "border-width: 1px;" << std::endl <<
59             "border-color: #666666;" << std::endl <<
60             "border-collapse: collapse;" << std::endl <<
61             "}" << std::endl <<
62             "table.gridtable th {" << std::endl <<
63             "border-width: 1px;" << std::endl <<
64             "padding: 8px;" << std::endl <<
65             "border-style: solid;" << std::endl <<
66             "border-color: #666666;" << std::endl <<
67             "background-color: #dedede;" << std::endl <<
68             "}" << std::endl <<
69             "table.gridtable td {" << std::endl <<
70             "border-width: 1px;" << std::endl <<
71             "padding: 8px;" << std::endl <<
72             "border-style: solid;" << std::endl <<
73             "border-color: #666666;" << std::endl <<
74             "background-color: #ffffff;" << std::endl <<
75             "}" << std::endl <<
76             "h1 {" << std::endl <<
77             "font-size: 1.5em;" << std::endl <<
78             "color: #000000;" << std::endl <<
79             "font-family: Arial, sans-serif;" << std::endl <<
80             "}" << std::endl <<
81 
82             "h2 {" << std::endl <<
83             "font-size: 1.2em;" << std::endl <<
84             "color: #000000;" << std::endl <<
85             "font-family: Arial, sans-serif;" << std::endl <<
86             "}" << std::endl <<
87 
88             "h3 {" << std::endl <<
89             "margin-left: 0;" << std::endl <<
90             "margin-bottom: 0;" << std::endl <<
91             "font-size: 1.0em;" << std::endl <<
92             "color: #000000;" << std::endl <<
93             "font-family: Arial, sans-serif;" << std::endl <<
94             "}" << std::endl <<
95             "</style>" << std::endl;
96     }
97 
writeReport(Poco::FileOutputStream & out)98     void writeReport(Poco::FileOutputStream &out)
99     {
100             out << "<html>" << std::endl;
101             out << "<head>" << std::endl;
102             out << "<meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />" << std::endl;
103             addStyle(out);
104 
105             out << "<title>Report</title>" << std::endl;
106             out << "</head>" << std::endl;
107             out << "<body>" << std::endl;
108 
109             TskBlackboard &blackboard = TskServices::Instance().getBlackboard();
110             TskImgDB &imgdb = TskServices::Instance().getImgDB();
111             std::stringstream condition;
112 
113             out << "<h1>Sleuth Kit Framework Summary Report</h1>" << std::endl;
114             std::vector<std::string> names = imgdb.getImageNames();
115             out << "<h2>Image Path: " << names.front() << "</h2>" << std::endl;
116 
117             out << "<h2>Image Layout</h2>" << std::endl;
118             std::list<TskVolumeInfoRecord> volumeInfoList;
119             imgdb.getVolumeInfo(volumeInfoList);
120 
121             std::list<TskFsInfoRecord> fsInfoList;
122             imgdb.getFsInfo(fsInfoList);
123             TskFsInfoRecord fsInfo;
124 
125             if (fsInfoList.size() == 0)
126             {
127                 out << "<em>NO FILE SYSTEMS FOUND IN THE DISK IMAGE.</em>" << std::endl;
128             }
129 
130             out << "<table class=\"gridtable\">" << std::endl;
131             out << "<thead>" << std::endl;
132             out << "<tr>" << std::endl;
133             out << "<th>Start Sector</th>" << std::endl;
134             out << "<th>End Sector</th>" << std::endl;
135             out << "<th>Partition Type</th>" << std::endl;
136             out << "<th>Detected FS</th>" << std::endl;
137             out << "</tr>" << std::endl;
138             out << "</thead>" << std::endl;
139 
140             for (list<TskVolumeInfoRecord>::const_iterator iter = volumeInfoList.begin(); iter != volumeInfoList.end(); iter++)
141             {
142                 const TskVolumeInfoRecord & vol_info = *iter;
143                 out << "<tr>" << std::endl;
144                 out << "<td>" << vol_info.sect_start << "</td>" << std::endl;
145                 out << "<td>" << (vol_info.sect_start + vol_info.sect_len) - 1 << "</td>" << std::endl;
146                 out << "<td>" << vol_info.description << "</td>" << std::endl;
147 
148                 for (list<TskFsInfoRecord>::const_iterator iter2 = fsInfoList.begin(); iter2 != fsInfoList.end(); iter2++)
149                 {
150                     fsInfo = (*iter2);
151                     if(fsInfo.vol_id == vol_info.vol_id)
152                     {
153                         const char* fsName = tsk_fs_type_toname((TSK_FS_TYPE_ENUM)fsInfo.fs_type);
154                         if (!fsName)
155                         {
156                             out << "<td>Name of file system type is unknown.</td>" << std::endl;
157                             LOGERROR("writeReport: Name of file system type is unknown.");
158                         }
159                         else
160                         {
161                             out << "<td>" << fsName << "</td>" << std::endl;
162                         }
163                     }
164                 }
165 
166                 out << "</tr>" << std::endl;
167             }
168             out << "</table>" << std::endl;
169 
170             out << "<h2>File Categories</h2>" << std::endl;
171             out << "<table class=\"gridtable\">" << std::endl;
172 
173             out << "<tr>" << std::endl;
174             condition.str("");
175             condition << "WHERE files.dir_type = " << TSK_FS_NAME_TYPE_REG
176                       << " AND files.type_id = " << TskImgDB::IMGDB_FILES_TYPE_FS;
177             out << "<td><b>File System:</b></td>";
178             out << "<td>" << imgdb.getFileCount(condition.str()) << "</td>" << std::endl;
179             out << "</tr>" << std::endl;
180 
181             out << "<tr>" << std::endl;
182             condition.str("");
183             condition << "WHERE files.dir_type = " << TSK_FS_NAME_TYPE_REG
184                       << " AND files.type_id = " << TskImgDB::IMGDB_FILES_TYPE_DERIVED;
185             out << "<td><b>Derived:</b></td>";
186             out << "<td>" << imgdb.getFileCount(condition.str()) << "</td>" << std::endl;
187             out << "</tr>" << std::endl;
188 
189             out << "<tr>" << std::endl;
190             condition.str("");
191             condition << "WHERE files.dir_type = " << TSK_FS_NAME_TYPE_REG
192                       << " AND files.type_id = " << TskImgDB::IMGDB_FILES_TYPE_CARVED;
193             out << "<td><b>Carved:</b></td>";
194             out << "<td>" << imgdb.getFileCount(condition.str()) << "</td>" << std::endl;
195             out << "</tr>" << std::endl;
196 
197             out << "<tr>" << std::endl;
198             condition.str("");
199             condition << "WHERE files.dir_type = " << TSK_FS_NAME_TYPE_REG
200                       << " AND files.type_id = " << TskImgDB::IMGDB_FILES_TYPE_UNUSED;
201             out << "<td><b>Contiguous Unallocated Sectors:</b></td>";
202             out << "<td>" << imgdb.getFileCount(condition.str()) << "</td>" << std::endl;
203             out << "</tr>" << std::endl;
204 
205             out << "<tr>" << std::endl;
206             condition.str("");
207             condition << "WHERE files.dir_type = " << TSK_FS_NAME_TYPE_REG;
208             out << "<td><b>Total Files:</b></td>";
209             out << "<td><b>" << imgdb.getFileCount(condition.str()) << "</b></td>" << std::endl;
210             out << "</tr>" << std::endl;
211 
212             out << "<tr>" << std::endl;
213             out << "</table>" << std::endl;
214 
215             std::vector<TskBlackboardArtifact> artifacts = blackboard.getMatchingArtifacts("ORDER BY artifact_type_id");
216             std::vector<TskBlackboardArtifact>::iterator it;
217             int currentArtType = -1;
218             std::vector<int> attrTypeIDs;
219             out << "<h2>Blackboard Artifacts</h2>" << std::endl;
220             for (it = artifacts.begin(); it != artifacts.end(); it++)
221             {
222                 if (currentArtType != it->getArtifactTypeID())
223                 {
224                     if (currentArtType != -1)
225                     {
226                         out << "</tbody>" << std::endl << "</table>" << std::endl;
227                     }
228                     currentArtType = it->getArtifactTypeID();
229                     out << "<h3>" << it->getDisplayName() << "</h3>" << std::endl;
230                     attrTypeIDs = blackboard.findAttributeTypes(currentArtType);
231                     out << "<table class=\"gridtable\">" << std::endl;
232                     out << "<thead>" << std::endl;
233                     out << "<tr>" << std::endl;
234                     out << "<th>File Name</th>" << std::endl;
235                     for (size_t i = 0; i < attrTypeIDs.size(); i++)
236                     {
237                         out << "<th>" << blackboard.attrTypeIDToTypeDisplayName(attrTypeIDs[i]) << "</th>" << std::endl;
238                     }
239                     out << "</tr>" << std::endl << "</thead>" << std::endl;
240                     out << "<tbody>" << std::endl;
241                 }
242                 out << "<tr>" << std::endl;
243                 out << "<td>" << imgdb.getFileName(it->getObjectID()) << "</td>" << std::endl;
244                 std::vector<TskBlackboardAttribute> attrs = it->getAttributes();
245 
246                 for (size_t j = 0; j < attrTypeIDs.size(); j++)
247                 {
248                     TskBlackboardAttribute * attr;
249                     bool found = false;
250                     for (size_t k = 0; k < attrs.size(); k++)
251                     {
252                         if (attrs[k].getAttributeTypeID() == attrTypeIDs[j])
253                         {
254                             attr = &attrs[k];
255                             found = true;
256                             break;
257                         }
258                     }
259                     if (!found)
260                     {
261                         out << "<td/>" << std::endl;
262                     }
263                     else
264                     {
265                         out << "<td>";
266                         std::vector<unsigned char> bytes;
267                         switch(attr->getValueType())
268                         {
269                             case TSK_BYTE:
270                                 bytes = attr->getValueBytes();
271                                 for(size_t k = 0; k < bytes.size(); k++)
272                                     out << bytes[k];
273                                 out << "</td>" << std::endl;
274                                 break;
275 
276                             case TSK_DOUBLE:
277                                 out << attr->getValueDouble() << "</td>" << std::endl;
278                                 break;
279 
280                             case TSK_INTEGER:
281                                 out << attr->getValueInt() << "</td>" << std::endl;
282                                 break;
283 
284                             case TSK_LONG:
285                                 out << attr->getValueLong() << "</td>" << std::endl;
286                                 break;
287 
288                             case TSK_STRING:
289                                 std::string encoded = HTMLEncode(attr->getValueString());
290                                 out << encoded << "</td>" << std::endl;
291                                 break;
292                         }
293                     }
294                 }
295                 out << "</tr>" << std::endl;
296             }
297             if (artifacts.size() > 0)
298             {
299                 out << "</tbody>" << std::endl << "</table>" << std::endl;
300             }
301             out << "</body>" << std::endl;
302             out << "</html>" << std::endl;
303     }
304 }
305 
306 namespace TskSummaryReport
307 {
generateReport(const std::string & reportPath)308     void generateReport(const std::string &reportPath)
309     {
310         Poco::FileOutputStream out(reportPath, std::ios::out | std::ios::trunc);
311         writeReport(out);
312     }
313 }
314