tag:blogger.com,1999:blog-324657152024-03-05T22:51:45.289+01:00seccure.cloudMariuszhttp://www.blogger.com/profile/05214488888247283501noreply@blogger.comBlogger12125tag:blogger.com,1999:blog-32465715.post-73260653436630905962024-02-21T20:46:00.001+01:002024-02-21T20:47:57.412+01:00Asset Inventory for Security Teams<span style="font-family: arial;"> <span> </span>The identification of all assets in any organisation is critical for several reasons. From a security point of view, this is essential for implementing proper protection. It enables organisations to establish appropriate security controls, access management policies, and incident response procedures to safeguard assets.<br /> <span> </span>I have created scripts that simplify the tasks associated with managing GCP Asset Inventory. I used Resource Manager and Cloud Asset APIs in order to create a central database. The choice of a spreadsheet interface was deliberate, driven by its simplicity. But it’s easy to switch to storing data in a database like big query or cloud sql. It’s also easy to use Looker Studio to present the results. <br /> <span> </span>I created 3 scripts at my <a href="https://github.com/Prevenity/Cloud-Security" target="_blank">GitHub project</a> [1]. 00_main.gs - main script which setup asset inventory. 01_GCP_VM.gs - script used to manage information about compute engines and 02_GCP_GKE.gs - script used to manage information about GKE clusters and workloads. <br /><br />Setup steps:<br /><ol style="text-align: left;"><li>Prepare the following information:</li><ol><li>GCP ORG ID</li><li>ID of spreadsheet for cache database (just create new spreadsheet)</li><li>ID of spreadsheet for inventory database (just create a new spreadsheet)</li></ol><li>Create a new project in Google Apps Script and place 3 files from my Github project. It is also required to create a Service Account in GCP with a role which can collect information from the GCP Resource Manager. The full setup is more complex and it can be a topic for a separate article). </li><li>Provide information from point 1 to 00_main.gs</li><li>Configure config_scope in 00_main.gs. At the moment supported features are: Compute Engines (COMPUTE_ENGINES) and GKE Clusters (GKE_CLUSTERS) including Pods and Deployments.</li><li>Run setup_cache_db() - in this step a temporary database of assets is created.</li><li>OPTIONAL STEP: set priorities for GKE clusters (it is important when you have a prod and non-prod environment, non-prod must have lower priority). You can set priorities in cache.db.</li><li>Run function run_asset_inventory from main.gs file - in this step script collects information about all assets and stores it in cache.db.</li><li>Run setup_inventory_db function - in this step final asset inventory db is created. </li><li>Run run_scheduled_scan_vm_asset_inventory function from 01_GCP_VM.gs and run_scheduled_scan_gke_asset_inventory function from 02_GCP_GKE.gs. Both scripts copy information from cache.db to main inventory.</li><li>The final step is creation triggers in the App Script console.</li></ol><br />Source:</span><div><span style="font-family: arial;"><br /></span><div><div><span style="font-family: arial;">[1] - <a href="https://github.com/Prevenity/Cloud-Security">https://github.com/Prevenity/Cloud-Security</a></span></div></div></div>Mariuszhttp://www.blogger.com/profile/05214488888247283501noreply@blogger.com0tag:blogger.com,1999:blog-32465715.post-40858441368772703562023-01-15T20:46:00.001+01:002023-01-15T20:46:03.471+01:00Monitoring of operating system versions in Google Workspace<p style="text-align: justify;"><span style="font-family: Arial; white-space: pre-wrap;">Let’s continue the presentation of examples of use event logs from Google Workspace. Today I’ll describe how to use event logs to check and notify users about outdated versions of the operating system. The idea is to inform users via email that newer versions of the operating systems are available to install. Described methods work for all popular operating systems - e.g. MacOS, Windows, Linux, iOS or Android. </span></p><span id="docs-internal-guid-811779f6-7fff-8705-30ec-d51e8704e632"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: justify;"><span style="font-family: Arial; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space: pre-wrap;">Keep in mind that this method only notify users and/or administrators. The next step is to enforce installation of the new version. MDM systems can enforce such installation or we can use Google Workspace Context-Aware Access to prohibit older versions. </span></p><div style="text-align: justify;"><br /></div><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: justify;"><span style="font-family: Arial; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space: pre-wrap;">Described use case: User just after login to Google Workspace receives notification via email that newer version of the operating system is available.</span></p><div style="text-align: justify;"><br /></div><div style="text-align: left;"><span style="font-family: helvetica;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space: pre-wrap;">Source code described here is available at github repository: </span><a href="https://github.com/Prevenity/Cloud-Security">https://github.com/Prevenity/Cloud-Security</a></span></div><div style="text-align: justify;"><br /></div><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: justify;"><span style="font-family: Arial; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space: pre-wrap;">The main function is main_version_monitor(). The first function is read_dates(). The function is using a spreadsheet to store the date of the last execution of the script. The main function should be executed at least every 5-10 minutes in order to notify users as soon as possible. We use the last execution date because in the next function read_events() is calling AdminReports.Activities.list() GSuite API which retrieves a list of activities. The read_events() collect 6 types of data from Google Workspace events: DEVICE_TYPE, DEVICE_MODEL, OS_VERSION, SERIAL_NUMBER, date and email of user. </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><span style="font-family: courier;"><span style="font-size: x-small;"> try {<br /> response = AdminReports.Activities.list(<br /> userKeyA, //”all”<br /> applicationNameA, //”mobile”<br /> optionalArgsA<br /> );<br /><br /> } </span></span></span><div><span><span style="font-family: courier;"><span style="font-size: x-small;">catch (error) {<br /> Logger.log(error);<br /> }</span></span></span><div><span><span style="font-family: courier;"><span style="font-size: x-small;">...<br /><br /> if (params_event[zm4].name == "DEVICE_TYPE")<br /> device_type_vod = params_event[zm4].value;<br /> if (params_event[zm4].name == "DEVICE_MODEL")<br /> device_model_vod = params_event[zm4].value;<br /> if (params_event[zm4].name == "OS_VERSION")<br /> os_version_vod = params_event[zm4].value;<br /> if (params_event[zm4].name == "SERIAL_NUMBER”<br /> serial_id_vod = params_event[zm4].value;<br /><br />…<br /><br />table_mobile.push([<br /> event_temp.actor.email,<br /> event_temp.actor.callerType,<br /> event_temp.id.time,<br /> serial_id_vod,<br /> device_type_vod,<br /> device_model_vod,<br /> os_version_vod]);</span></span></span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div><span style="font-family: courier; font-size: x-small;"><br /></span></div><div style="text-align: justify;"><span id="docs-internal-guid-0b05e222-7fff-2c70-b701-237641755c76"><span style="font-family: Arial; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space: pre-wrap;">The next important function is compare_version_v2(). As you can see we are able to collect from the Device Action event information about the version of the operating system. Now, we have to inform the function which operating systems are approved. We are using a spreadsheet as a database of approved versions. An example is below:</span></span></div><div><span style="font-family: Arial;"><span style="font-size: 11.333333px; white-space: pre-wrap;"><br /></span></span></div><div><span style="font-family: Arial;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAwpe5MQ_G3u6Mko8sxue56F91o4n8kg7HB8dVUjKtPMjJ0wdWnzMwRJUJAIWlreVEodN9bIl7amKc9owdFQRGMfEOXZt6aKJOPzczp4AufhgVXbZdpo8fBNyQnsU6QEfX38bJOnG6zke3dQGG3cDCT_6CvvOn2npqmGi_18FqCk5EMVkyU38/s662/supported_version.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="48" data-original-width="662" height="46" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAwpe5MQ_G3u6Mko8sxue56F91o4n8kg7HB8dVUjKtPMjJ0wdWnzMwRJUJAIWlreVEodN9bIl7amKc9owdFQRGMfEOXZt6aKJOPzczp4AufhgVXbZdpo8fBNyQnsU6QEfX38bJOnG6zke3dQGG3cDCT_6CvvOn2npqmGi_18FqCk5EMVkyU38/w640-h46/supported_version.png" width="640" /></a></div><div><span style="font-family: Arial;"><br /></span></div></span><span id="docs-internal-guid-0ac4545b-7fff-c969-2f1a-643a7feb21c9"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space: pre-wrap;">Function is quite simple:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: courier; font-size: x-small;">function compare_version_v2(version_to_check){</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: courier; font-size: x-small;">var handler_to_file = open_spreadsheet_file("", "supported versions");</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: courier; font-size: x-small;">for(var zmx = 1; zmx<handler_to_file[10].length;zmx++ )</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: courier; font-size: x-small;">{</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: courier; font-size: x-small;"> if(handler_to_file[10][zmx] == version_to_check)</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: courier; font-size: x-small;"> return true</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: courier; font-size: x-small;">}</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: courier; font-size: x-small;"> return false;</span></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: courier; font-size: x-small;">}</span></span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space: pre-wrap;">Finally, we have to prepare a message which will be sent via email.</span></p></span><br class="Apple-interchange-newline" /><span style="font-family: Arial;"><span style="font-size: 11.333333px; white-space: pre-wrap;"><br /></span></span><span><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-ligatures: normal; font-variant-numeric: normal; font-variant-position: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"><span style="white-space: normal;"></span><br class="Apple-interchange-newline" style="white-space: normal;" /></span></span></p></span><br class="Apple-interchange-newline" /></div></div>Mariuszhttp://www.blogger.com/profile/05214488888247283501noreply@blogger.com0tag:blogger.com,1999:blog-32465715.post-7040759352634960442022-11-06T21:58:00.004+01:002022-11-07T14:07:48.561+01:00Using IP geolocation to detect suspicious logins to GSuite<p><span style="font-family: "Helvetica Neue"; font-size: 13px;">Today I will describe how to detect suspicious login activities to Google Workspace.</span></p>
<p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px; min-height: 15px;"><br /></p>
<p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px;">I am using AdminReports.Activities.list API (<a href="https://developers.google.com/admin-sdk/reports/reference/rest/v1/activities/list"><span style="color: #dca10d;">https://developers.google.com/admin-sdk/reports/reference/rest/v1/activities/list</span></a>) from my Apps Script script (<a href="https://script.google.com/home"><span style="color: #dca10d;">https://script.google.com/home</span></a>). To limit results I will filter only login applications (<a href="https://developers.google.com/admin-sdk/reports/reference/rest/v1/activities/list#ApplicationName"><span style="color: #dca10d;">https://developers.google.com/admin-sdk/reports/reference/rest/v1/activities/list#ApplicationName</span></a>). According to documentation the Login application’s activity reports return information about different types of Login activity events. The most important events are: login_failure and login_success.</p>
<p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px; min-height: 15px;"><br /></p>
<p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px;">Below function returns 4 fields (email of user, event name, event time and source IP address). we have to provide two parameters to our function - start date and end date. It is important to store end date in order to provide this value during next call.</p><div><br /></div><div><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;">function Logins(starts, ends) {</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> var pageToken, responseX;</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> var userKey = "all";</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> var applicationName = "login";</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> var table = [];</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"><br /></span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> do {</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> var optionalArgs = {</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> maxResults: 20,</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> startTime: starts,</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> endTime: ends,</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> pageToken: pageToken,</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> };</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> responseX = AdminReports.Activities.list(</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> userKey,</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> applicationName,</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> optionalArgs</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> );</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> var activities = responseX.items;</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> if (activities && activities.length > 0) {</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> for (i = 0; i < activities.length; i++) {</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> var activity = activities[i];</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> if (</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> activity.events[0].name == "login_failure" ||</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> activity.events[0].name == "login_success"</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> )</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> table.push([</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> activity.actor.email,</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> activity.events[0].name,</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> activity.id.time,</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> activity.ipAddress,</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> ]);</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> }</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> } else {</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> Logger.log("No logins found.");</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> }</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"><br /></span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> pageToken = responseX.nextPageToken;</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> } while (pageToken);</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"><br /></span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> return table;</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;">}</span></p><p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px;"><br /></p><p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px;">I also had to create function responsible for retrieving GEO IP values (City, Country and continent). I decided to us <a href="http://ipbase.com"><span style="color: #dca10d;">ipbase.com</span></a> database via API but you can choose any other geo ip database.</p><p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px; min-height: 15px;"><br /></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;">function example_function(){</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px; min-height: 15px;"><span style="font-family: courier; font-size: x-small;"><br /></span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;">var result_from_logins = Logins(“2022-10-06T19:23:13.280Z”, “2022-10-07T19:23:13.280Z”);</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;">var geo_ip_data = getIpGeolocationData(result_from_logins[counter][3],'CITY, COUNTRY');</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;">Logger.log(geo_ip_data);</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;">}</span></p><p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px; min-height: 15px;"><br /></p><p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px;">A part of function getIpGeolocationData is presented below:</p><p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px; min-height: 15px;"><br /></p><p style="font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier;">ipData = isBlank(ip)? getResponseJsonData('https://api.ipbase.com/v2/info') : getResponseJsonData('https://api.ipbase.com/v2/info?ip=' + ip);</span></p><p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px; min-height: 15px;"><br /></p><p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px;">Result is returned as JSON. In Apps Script fetch method is used from UrlFetchApp class to call ipbase API.</p><p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px;"><br /></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;">function getResponseJsonData(url) {</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> if (isBlank(url)) return;</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"><br /></span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> let response = UrlFetchApp.fetch(url, {</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> headers: {</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> apikey: APIKEY,</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> },</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> });</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"><br /></span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> let json = response.getContentText();</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;"> return JSON.parse(json);</span></p><p style="font-stretch: normal; line-height: normal; margin: 0px;"><span style="font-family: courier; font-size: x-small;">}</span></p><div><br /></div><div><p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px;">Results can be written to spreadsheet or send directly to the SOC team. I am writing data to spreadsheet where each tab contain suspicious activities from one day. It is also possible to filter countries and email address to limit false alarms then SOC team can focus only on admin accounts and logon events from some countries.</p><p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px;"><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUqtmqED6uq_6YSbEtaFXTLbvRYqb0NdTdjdH5jMaEhjvxBeMPTb8IOAD1DFDLvlgVtXrw4Ajcg9ByGz1Pf4bISj9soF0D9Q8ZB5ndueP2qY6TXKSRuStzgIt2Xp1csQso07Co4r2wEX3TETyJp0Mq76q1-7GRSbaARTE-Bx0rFb_xeWjBsqQ/s1608/geoip.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="524" data-original-width="1608" height="130" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUqtmqED6uq_6YSbEtaFXTLbvRYqb0NdTdjdH5jMaEhjvxBeMPTb8IOAD1DFDLvlgVtXrw4Ajcg9ByGz1Pf4bISj9soF0D9Q8ZB5ndueP2qY6TXKSRuStzgIt2Xp1csQso07Co4r2wEX3TETyJp0Mq76q1-7GRSbaARTE-Bx0rFb_xeWjBsqQ/w400-h130/geoip.png" width="400" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px;"><br /></p><p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px;"><br /></p><p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px;"><br /></p><p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px;">References:</p><p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px;">[1] <a href="https://github.com/Prevenity/Cloud-Security/tree/master/Apps%20Script">https://github.com/Prevenity/Cloud-Security/tree/master/Apps%20Script</a></p><p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px;">[2] <a href="https://developers.google.com/admin-sdk/reports/reference/rest/v1/activities/list"><span style="color: #dca10d;">https://developers.google.com/admin-sdk</span></a></p><p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px;"><br /></p><p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px;"><br /></p></div><p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px;"><br /></p><p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px;"><br /></p></div>Mariuszhttp://www.blogger.com/profile/05214488888247283501noreply@blogger.com0tag:blogger.com,1999:blog-32465715.post-56318563952563634902022-11-06T21:37:00.000+01:002022-11-06T21:37:20.664+01:00Cloud Security<p><span style="font-family: "Helvetica Neue"; font-size: 13px;">I come back after a quite long break in publishing posts. During last 4 years I was engaged in building a bank in the cloud. SSDLC, security of CI/CD, workspace security including mobile devices, cloud security, k8s security, security monitoring, access control or identity protection are in area on my responsibility. I am going to publish at this site posts related to listed topics. Source code used by me is stored at this repo: </span><span style="color: #dca10d; font-family: "Helvetica Neue"; font-size: 13px;"><a href="https://github.com/prevenity" style="font-family: "Helvetica Neue"; font-size: 13px;">https://github.com/prevenity</a>.</span></p>
<p style="font-family: "Helvetica Neue"; font-size: 13px; font-stretch: normal; line-height: normal; margin: 0px;">As you can see I’ve also changed domain name to the .cloud as I will mostly focus on cloud security topics. </p>Mariuszhttp://www.blogger.com/profile/05214488888247283501noreply@blogger.com0tag:blogger.com,1999:blog-32465715.post-53663057981403145282010-12-28T00:38:00.001+01:002010-12-28T00:43:27.321+01:00Breaking PIN for software tokensSoftware tokens usually use PIN for accessing token functions. Some vendors avoid implementing methods of validating PIN within an application. PIN is validated implicitly by validating dynamic password or response value generated by the application. It is possible because PIN is hashed and then the result (key) is used to decrypt a main key. Next, the main key is used by the application to generate OTP. So when the wrong PIN is provided, the application will decrypt incorrect key and will generate not valid OTP. <br />
<br />
But under some conditions it is possible to find out the right PIN code. First of all, we have to obtain at least one valid OTP. For time based tokens we have to know the time when the valid OTP was generated. For counter based tokens we have to find out the counter value. It can be a problem so the attack is more effective when we know an approximate value of the counter for corresponding OTP. The counter is stored in local database of the application and usually we are able to modify the content.<br />
<br />
The last step is to perform brute force attack and to compare the values of two dynamic passwords. After every try we have to recover the previous value of the counter (for counter based tokens) or set the right time (for time based tokens).<br />
<br />
The attack is very difficult to perform against mobile devices with offline software tokens. We have to have an access to local database of mobile device and capture valid OPT which is send via network.Mariuszhttp://www.blogger.com/profile/05214488888247283501noreply@blogger.com0tag:blogger.com,1999:blog-32465715.post-88784699637215860392010-06-15T23:51:00.003+02:002010-06-15T23:59:47.980+02:00Two-Factor Transaction AuthenticationMore and more banks to mitigate banking frauds implement new methods of authenticating electronic transactions. Few methods rely on the customer's mobile phone. It looks that today the most popular are SMS messages and software challenge response tokens. Both methods can help in detecting the Man in the Browser attack. And in both cases the customer is able to verify details of transaction during making a payment. <br />
<br />
A discussion about which method is "better" seems to be quite interesting. One of such discussion takes place on the OWASP-POLAND mailing list. What "the better" mean? It is tricky to justify which method is "better" because banks must consider several factors. Security is important but system has to be customer-friendly and inexpensive. <br />
<br />
I am not going to write here about attack vectors and all pros & cons but in my opinion method which is based on SMS messages has more advantages. <br />
<br />
The customer can receive SMS message with transaction details including full destination account number, an amount and an authentication code (valid only for particular transaction). The code is used by the customer to confirm the transaction. When the customer submits authentication code to online banking system then the bank will consider that the customer has just verified transaction details and accepted the payment.<br />
<br />
The second method is not customer-friendly enough and can have security issues. I have to emphasize here that I do not have knowledge about all solutions which are available on the market and it is possible that some solutions work in different way and offer different level of security.<br />
<br />
As I mentioned, the second method is based on software challenge response tokens. An application (software token) is installed on the customer's mobile phone. Bank and the customer shares the same secret key which is used to generate and verify challenge and response codes.<br />
<br />
When the customer makes a payment, the bank's application generates the challenge by using destination account number, an algorithm and a secret key. Only few digits from destination account number are used to create the challenge. Of course all destination account number can be used but then the challenge will be too long. The customer submits the challenge to the mobile phone and after acceptance, details about transaction are displayed on the screen (but only selected digits from destination account number) - the challenge, the algorithm and the secret key are used to calculate and display such information. Sometimes bank requires from the customer to submit additional information like the amount of payment. And then this value is used to calculate the response. In next step, the customer submits the response code to internet banking application. When everything is fine, the bank will accept the transaction. It is a little bit complicated, isn’t it?<br />
<br />
I'm going to write more about algorithms in next article. Here let's just focus on numbers.<br />
So why such system can have more secure issues than SMS messages? All because of the challenge code length. Limitation of challenge code length does not allow to display all numbers of destination account. For example, in 6-digit challenge it is possible to “hide” only 4 digits from destination account number.<br />
<br />
We can imagine an attack vector where an intruder will use different account numbers which contain the same 4 digits like original destination account number. It is important to mention about the length of IBAN notation of destination account number. The IBAN consists of the Country Code, a 2-digit checksum, a Bank code and the account number. The account number in Poland has 16 digits.<br />
<br />
Now, let’s try to calculate the probability of above attack vector. I will use the formula for classical probability P(A) = n (A) / n (S). <br />
Below calculations are performed for the attack where victim and mule accounts have the same Bank code. It is very popular scenario used by frauders. Calculation are done for 4, 5 and 6 digits. Also, I checked if showing first 2-digit checksum from destination account number decreases the risk of the attack.<br />
<br />
In addition to the formula I created the Python script to compare results. The script generates the valid account numbers.<br />
<br />
Variant 1A – last 4 digits are extracted from the challenge and displayed on mobile phone. Probability is 1:10000. It means that we have to have 10000 accounts to perform a successful attack. Few valid account numbers:<br />
<br />
PL50101000000000000000008765<br />
PL98101000000000000000018765<br />
PL49101000000000000000028765<br />
PL97101000000000000000038765<br />
PL48101000000000000000048765<br />
PL96101000000000000000058765<br />
PL47101000000000000000068765<br />
PL95101000000000000000078765<br />
PL46101000000000000000088765<br />
PL94101000000000000000098765<br />
…<br />
<br />
Variant 1B – first 2 and last 2 digits are extracted from the challenge and displayed on mobile phone. It is important to emphasize that the checksum is only used to verify if an account number is correct. It is not related to security and we can notice that probability of attack is the same 1:10000. The result received from my script is presented below:<br />
<br />
PL50101000000000000000008765<br />
PL50101000000000000000018465<br />
PL50101000000000000000028165<br />
PL50101000000000000000037865<br />
PL50101000000000000000047565<br />
PL50101000000000000000057265<br />
PL50101000000000000000066965<br />
PL50101000000000000000076665<br />
PL50101000000000000000086365<br />
PL50101000000000000000096065<br />
...<br />
Variant 2A – last 5 digits. Probability is 1: 100000. Few examples of valid account numbers:<br />
<br />
PL94101000000000000000098765<br />
PL89101000000000000000198765<br />
PL84101000000000000000298765<br />
PL79101000000000000000398765<br />
PL74101000000000000000498765<br />
PL69101000000000000000598765<br />
PL64101000000000000000698765<br />
PL59101000000000000000798765<br />
PL54101000000000000000898765<br />
PL49101000000000000000998765<br />
...<br />
<br />
Variant 2B – first 2 and last 3 digits. Probability is 1: 1:100000. The same is for Variant 2A. <br />
<br />
PL50101000000000000000008765<br />
PL50101000000000000000105765<br />
PL50101000000000000000202765<br />
PL50101000000000000000299765<br />
PL50101000000000000000396765<br />
PL50101000000000000000493765<br />
PL50101000000000000000590765<br />
PL50101000000000000000687765<br />
PL50101000000000000000784765<br />
...<br />
<br />
Variant 3A – last 6 digits. Probability is 1:1000000.<br />
<br />
PL89101000000000000000198765<br />
PL39101000000000000001198765<br />
PL86101000000000000002198765<br />
PL36101000000000000003198765<br />
PL83101000000000000004198765<br />
...<br />
<br />
Variant 3B – first 2 digits and last 4 digits. Probability is 1:1000000.<br />
<br />
PL50101000000000000000008765<br />
PL50101000000000000000978765<br />
PL50101000000000000001948765<br />
PL50101000000000000002918765<br />
...<br />
<br />
Above examples show that the risk of attack is very low but the situation can change when we consider that destination account is in different bank and/or that few last digits have value 0 (what sometimes can be true).Mariuszhttp://www.blogger.com/profile/05214488888247283501noreply@blogger.com0tag:blogger.com,1999:blog-32465715.post-84570104354214260912010-06-03T00:11:00.007+02:002010-06-04T22:44:16.542+02:00Internet Banking Security<div style="font-family: Verdana,sans-serif; text-align: justify;">Last few months I was engaged in projects related to internet banking security. I was performing analysis of various variants of malicious software called “banking Trojans” and spent a lot of time playing with fraud detection systems. Currently I am involved in another project related to new methods of transaction authentication. In the meantime I was invited to workshops for the police officers and prosecutors. </div><div style="font-family: Verdana,sans-serif; text-align: justify;">I would like to share some materials (in Polish) that I prepared for these workshops. I hope that it can be useful for some of you. First document is available at <a href="http://forensic.seccure.net/pdf/warsztat_banking_malware.pdf">http://forensic.seccure.net</a></div>Mariuszhttp://www.blogger.com/profile/05214488888247283501noreply@blogger.com0tag:blogger.com,1999:blog-32465715.post-23922556999213286672009-05-17T01:38:00.008+02:002009-05-17T01:47:46.691+02:00Anti-forensic techniques in malware<div align="justify"><span style="font-family:verdana;"><span >It is not a surprise that anti-forensic techniques are being used by malware writers to increase the examiner’s time. Few weeks ago I was analyzing malware for the customer (the malware has been identified by VirusTotal as Zbot-Trojan). I noticed quite interesting behavior of the malicious code.</span> </span></div><p align="justify"><br /> </p><div align="justify"><span style="font-family:verdana;">The malware self-modify file attributes - MAC times of file which contain malicious code are modified during installation & execution (system startup). This is an example of anti forensic method which makes the creation of Timeline Activity less valuable.</span><span style="font-family:verdana;"><br /></div></span><p align="justify"><br /> </p><div align="justify"><span style="font-family:verdana;">Trojan is using GetFileTIme() and SetFileTime() API which are exported by kernel32.dll. MAC times of malware executable file are set to MAC times of an operating system library – ntdll.dll file.<br /></div></span><br /><br /><div align="justify"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuGWXKaBo9UF2GoTIFrv8Nu9g8t5hV04U5C3ovYwO3l-0qmo3xn2DGMXuuUrjMjqotmRIWDlMPtmORe_5EIaEnkR9O5jHhNIG0DGynilQgfohg298NEIOa0to4zPshClk54CG7Hg/s1600-h/code_file_get_set.png"><img id="BLOGGER_PHOTO_ID_5336570583371391298" style="DISPLAY: block; MARGIN: 0px auto 10px; WIDTH: 400px; CURSOR: hand; HEIGHT: 193px; TEXT-ALIGN: center" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuGWXKaBo9UF2GoTIFrv8Nu9g8t5hV04U5C3ovYwO3l-0qmo3xn2DGMXuuUrjMjqotmRIWDlMPtmORe_5EIaEnkR9O5jHhNIG0DGynilQgfohg298NEIOa0to4zPshClk54CG7Hg/s400/code_file_get_set.png" border="0" /></a><br /><img id="BLOGGER_PHOTO_ID_5336571545243845346" style="DISPLAY: block; MARGIN: 0px auto 10px; WIDTH: 400px; CURSOR: hand; HEIGHT: 40px; TEXT-ALIGN: center" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0KfBd-npw94rrbOFFk-S7dSpsZr6Hn84tRDvhrhZsSOTzH96o8fhXPFEIo2-budZhks5HWsPsp-yySrfEQLEYGDALt0vYmVXFFkR_UeMpOaTdsM3ep8V1i3BHz25MzLzrSH0F9A/s400/set.png" border="0" /><span style="font-family:verdana;">We can still use time related information from MFT but above activity can lead to misinterpret results of reconstructed timeline activity.</span></div>Mariuszhttp://www.blogger.com/profile/05214488888247283501noreply@blogger.com3tag:blogger.com,1999:blog-32465715.post-79697328452012700072007-08-24T09:39:00.000+02:002007-08-24T10:39:54.640+02:00<div align="justify"><br /></div><p align="justify"><strong>Persistence of documents on file systems</strong></p><p align="justify">Persistence of data on storage media is always an interesting topic. No one can predict how long deleted file will be stored on hard disk.<br />Sometimes during investigation it is necessary to present at court the history of resident documents or deleted documents. Today I would like to discuss the behavior of Microsoft Word application and how it influences on creating timeline history of information. Some mentioned behaviors are the same for other applications like AutoCAD. I will focus on method of creating timeline history of documents which were edited by the users in the past. I this article I’ve used the NTFS file system but similar behavior can be observed on FATx file systems. Analyzing data from documents metadata are out of the scope of this document.<br /></p><p align="justify">1. General behavior of Microsoft Word<br /></p><p align="justify">Let’s say that we already have a file on local file system. It means that several clusters are allocated for storing the content of the file. For better explanation I will use particular cluster numbers. Our file has at least one run list which starts at cluster number 0x15ca0 (89248).<br />When we add or remove at least one character to/from the doc file and save changes then a new MFT entry and new clusters will be allocated for storing metadata and content of the updated file. New allocated FILE entry will store the original name of the file. The FILE entry with the previous version of the file is also updated because the file is renamed into ~WRL????.tmp. At this time we have 2 allocated FILE entries which points to different clusters. (There are more changes in the FILE entry but there are not so important at this stage – of course MAC times are always useful ;)).<br />If we close the file, the MFT entry and clusters of ~WRL????.tmp file will be freed. It means that the operating system can overwrite content of entry and clusters at any time. The picture below shows clusters (previously reserved for first version of our file) which now are marked as unused. As I mentioned above the first cluster number is 0x15ca0.</p><p align="justify"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhu8D_C9eyQrCVBQP2PDYLei1DnTnspRD6lsttS1CLIwDmSR8QvjgW4yBgn70cD3VZYj6Tp4PtLwZ6_cvVZ5rLQYPfEWOVU6jcqnInh7lGeG2N3P2HWHBn99JdZ7NFpQ7lJnDwYqw/s1600-h/photo1.jpg"><img id="BLOGGER_PHOTO_ID_5102178396872301890" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhu8D_C9eyQrCVBQP2PDYLei1DnTnspRD6lsttS1CLIwDmSR8QvjgW4yBgn70cD3VZYj6Tp4PtLwZ6_cvVZ5rLQYPfEWOVU6jcqnInh7lGeG2N3P2HWHBn99JdZ7NFpQ7lJnDwYqw/s320/photo1.jpg" border="0" /></a>The content of updated file is now stored at new clusters. The first cluster of the first run list is 0x15cef (89327).<br />When we repeat above activity (1. open file, 2. change something and finally, 3. close it), the situation will be the same. It means that new entry in the MFT will be allocated (very often the MFT entry freed previously are allocated once again, so only 2 FILE entries are usually used concurrently – I observed this behavior only for the MFT entries – not for clusters). Also new clusters will be allocated for updated file and the old clusters will be freed. In this case we can still recover previous files, even after hours or days, but as always, there is a risk that free clusters which contain previous versions of file will be simply allocated by the operating system.<br />Anyhow, we have to use data carving techniques to find all doc files on the file system (as we know the header of the doc file is well known ;)).<br /></p><p align="justify">2. The save button (ctrl + S) during editing documents</p><div align="justify">Every “save process” invoked by the user will create new file on the file system – the previous one is renamed with the following prefix ~WRL. For example: dokument.doc file is being edited for some period of time and the user had saved changes in the content 4 times. The result is presented below:</div><div align="justify"><br /></div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiP8VeH_oUbFgNm-VAHH2336okUjoEqseidpVluqmcE2UqqagRlmO4RiM-ZPakIm1hItTsxJteXBgwT9RU5klSMdGflSOtyEXfcHbYTmFEVBmnZMOHsozdfgLCkGncasz-Zac1P8Q/s1600-h/photo2.jpg"><img id="BLOGGER_PHOTO_ID_5102179419074518370" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiP8VeH_oUbFgNm-VAHH2336okUjoEqseidpVluqmcE2UqqagRlmO4RiM-ZPakIm1hItTsxJteXBgwT9RU5klSMdGflSOtyEXfcHbYTmFEVBmnZMOHsozdfgLCkGncasz-Zac1P8Q/s400/photo2.jpg" border="0" /> <p align="justify"></a>The above statements are true only when the user had changed the content of the document before invoking “save process” (save process = press the button save or press CTRL + S).<br />As we can see all created files are visible during “editing session”. The content of each of file is stored at different allocated run lists. It also means that each file has its own (allocated) FILE entry in the MFT. </p>The part of the MFT is presented below:<br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDOwkKqBCqRT5faGhVa6Qt9in9xdyNlz6PEul6fEnAlTYZbozp616kYFtT4fsWSiaoxcgXNQd8NXd4LIztFeBoNbNJyyD5qBp6OHVy_-Kn4yMAtofPW5J-FC8oKlT0IwCita0ZGQ/s1600-h/photo3.jpg"><img id="BLOGGER_PHOTO_ID_5102179522153733490" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDOwkKqBCqRT5faGhVa6Qt9in9xdyNlz6PEul6fEnAlTYZbozp616kYFtT4fsWSiaoxcgXNQd8NXd4LIztFeBoNbNJyyD5qBp6OHVy_-Kn4yMAtofPW5J-FC8oKlT0IwCita0ZGQ/s400/photo3.jpg" border="0" /></a><br /><br />The dokument.doc is allocated on clusters where the first cluster has number = 0x15c3b (89147). The ~WRL0003.tmp starts from 0xfaa8 (64168). The ~WRL0005.tmp starts from 0x15b06 (88838). The ~WRL0656.tmp starts from 0x15bee (89070). The last one - ~WRL1188.tmp starts from 0x15ba1 (88993).<br /><br />When the file is closed by the user only one file will stay visible – document.doc. Rests of documents are deleted automatically. Delete means that the entries in the MFT and clusters are freed.<br /><div align="justify"><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUKkUVm1PeVDzgoDyMaLOVaSoTI6lf2TFDS923hPDUc0BKseYNbZrEoSB1Um0GDQng5ef8l8yiDe3lNGSL1WpZL4SGSfRNUvK0QgSwUeI3FxbHoU55Ab5SRKKRrspf1advNkm_mw/s1600-h/photo4.jpg"><img id="BLOGGER_PHOTO_ID_5102179651002752386" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUKkUVm1PeVDzgoDyMaLOVaSoTI6lf2TFDS923hPDUc0BKseYNbZrEoSB1Um0GDQng5ef8l8yiDe3lNGSL1WpZL4SGSfRNUvK0QgSwUeI3FxbHoU55Ab5SRKKRrspf1advNkm_mw/s400/photo4.jpg" border="0" /></a>Such behavior allows us to trace the document history. We can easily recover each file because we can identify FILE entries in the MFT. We can also create the timeline history by analyzing MAC times which are written inside FILE entries. It is worth to mention that above entries and clusters can be allocated by other users or process (because there are not allocated).</div><br /><br />3. Auto-save option<br /><br /><br /><div align="justify">There is one more place from which documents edited (in the past) by users can be recovered. Microsoft Word has auto-save feature enable by default. This feature creates the copy of documents being edited. The default settings are presented below:</div><div align="justify"> </div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggtnGO9mhFJEXIcIhokhUE4TQA4ZUSFc_Xbd53Tir0mo1fi2gB9AjoMVWqIzjvH_VHG87-T-FyCaUMfz01evFTDGWoiyQNJeiSKHTJ7zK9J5k6T6QzakRNEiuZf59nAE3rUYJzhw/s1600-h/photo5.jpg"><img id="BLOGGER_PHOTO_ID_5102179852866215314" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggtnGO9mhFJEXIcIhokhUE4TQA4ZUSFc_Xbd53Tir0mo1fi2gB9AjoMVWqIzjvH_VHG87-T-FyCaUMfz01evFTDGWoiyQNJeiSKHTJ7zK9J5k6T6QzakRNEiuZf59nAE3rUYJzhw/s400/photo5.jpg" border="0" /></a><br /><div align="justify">When the file is open & the content of file was modified, Microsoft Word will create the copy in “safe location” defined in “File Locations” tab. The name of the file is “AutoRecovery save of <original>.asd”.<br />When the user modify the content of the file, after some period of time (10 minutes by default), Microsoft Word automatically will save changes in new file with the same name (“AutoRecovery save of <original>.asd”) and will free clusters which contain the content of old file. Also the FILE entry of the MFT is freed. In brief the behavior is similar to activities described in first part of this article – General behavior of Microsoft Word. The only difference is that Microsoft Word closes and opens .asd file in background. It is worth to mention that each time new clusters are allocated, so the same content of file is at least in 2 different locations on file systems (original and backup location).</div>Mariuszhttp://www.blogger.com/profile/05214488888247283501noreply@blogger.com0tag:blogger.com,1999:blog-32465715.post-1157713435048428802006-09-08T12:35:00.000+02:002006-09-14T16:40:41.936+02:00Partial file matching in host intrusion prevention systems<div style="text-align: justify;font-family:verdana;"><span style="font-size:85%;">A few weeks ago Jesse Kornblum released the <span style="font-weight: bold;">SSdeep</span> <a href="http://ssdeep.sourceforge.net/">[1]</a> tool. The main propose of this tool is to identify similar files by calculating hashes and comparing those hash values to the known values computed previously and stored in database.<br />T</span><span style="font-size:85%;">he big difference between SSdeep and other well-known tools to generate hash values (like md5sum) is that SSdeep calculates hash values for small chunks of target file. So if someone modifies only few bytes of a file, the new calculated hash value will be similar to the previous one <a href="http://www.dfrws.org/2006/proceedings/12-Kornblum.pdf">[2]</a>.<br /><br /><span style="font-size:78%;">49152:1xY5ndv7xb2OnhONkVCUDNl3lBB6U0ahgyFFvebjj:1xsdvH9RbMU0HyFFve3j,"gg.exe"<br />49152:PxY5ndv7xb2OnhONkVCUDNl3lBB6U0ahKvFBvebjj:PxsdvH9RbMU0VvFBve3j,"gg.exe"</span><br /><br />The main features (altered document matching and partial file matching) of the SSdeep are very helpful during forensic analysis. But you can also use partial file matching feature in host intrusion prevention systems. You can use this function to disable execution of specific programs.</span></div><p style="text-align: justify;" class="MsoNormal"><span style="font-size:85%;"><span lang="EN-US" style="font-family:Tahoma;"><span style="font-family:verdana;">It was rather useless to use “normal” hash values in IPS to prevent execution because such solution can be easily cheated. After changing even one byte in executable file the new hash value is completely different. As you can guess there are a lot of places in an executable file which can be modified and the exe file still will be executed without any problems.</span><o:p></o:p></span></span></p> <p class="MsoNormal" style="text-align: justify;"><span style="font-size:85%;"><span lang="EN-US" style="font-family:Tahoma;"><span style="font-weight: bold;">Before one byte modification:</span><o:p></o:p></span></span></p> <p class="MsoNormal" style="text-align: justify;"><span style="font-size:85%;"><span lang="DE" style="font-family:Tahoma;">C:\ssdeep>md5sum gg.exe<o:p></o:p><br /><span style="font-style: italic;">\0323de930ed3e8e0552843db7e16dab7 *C:\\ssdeep\\gg.exe</span><o:p></o:p></span></span></p> <p class="MsoNormal" style="text-align: justify;"><span style="font-size:85%;"><span lang="EN-US" style="font-family:Tahoma;"><span style="font-weight: bold;">After one byte modification:</span><o:p></o:p></span></span></p> <p class="MsoNormal" style="text-align: justify;"><span style="font-size:85%;"><span lang="EN-US" style="font-family:Tahoma;">C:\ssdeep>md5sum gg.exe<o:p></o:p><br /><span style="font-style: italic;">\bfa5aed4078c2a316786c1e7cb1e4f8e *C:\\ssdeep\\gg.exe</span><o:p></o:p></span></span></p> <p class="MsoNormal" style="text-align: justify;"><span style="font-size:85%;"><span lang="EN-US" style="font-family:Tahoma;"><!--[if !supportEmptyParas]--> <o:p></o:p></span></span></p> <p class="MsoNormal" style="text-align: justify;"><span style="font-size:85%;"><span lang="EN-US" style="font-family:Tahoma;">As mentioned above the SSDeep generates has values for small blocks of target file. So few modifications of target file will not change the whole value of generated hash as it is presented below:<o:p></o:p></span></span></p> <p class="MsoNormal" style="text-align: justify;"><span style="font-size:85%;"><span lang="EN-US" style="font-family:Tahoma;"><!--[if !supportEmptyParas]--> <o:p></o:p></span></span></p> <p class="MsoNormal" style="text-align: justify;"><span style="font-size:85%;"><span lang="EN-US" style="font-family:Tahoma;"><span style="font-weight: bold;">Before modifications:</span><o:p></o:p></span></span></p> <p class="MsoNormal" style="text-align: justify;"><span style="font-size:85%;"><span lang="EN-US" style="font-family:Tahoma;">C:\ssdeep>ssdeep -l gg.exe<o:p></o:p><br />ssdeep,1.0--blocksize:hash:hash,filename<o:p></o:p><br /><span style="font-style: italic;">49152:PxY5ndv7xb2OnhONkVCUDNl3lBB6U0ahKvFBvebjj:PxsdvH9RbMU0VvFBve3j,"gg.exe"</span></span></span></p> <p class="MsoNormal" style="text-align: justify;"><span style="font-size:85%;"><span lang="EN-US" style="font-family:Tahoma;">C:\ssdeep>ssdeep gg.exe > sum.txt<o:p></o:p><br />C:\ssdeep>ssdeep -m sum.txt gg.exe<o:p></o:p><br />C:\ssdeep\gg.exe matches C:\ssdeep\gg.exe <span style="color: rgb(255, 102, 102);">(100)</span><o:p></o:p></span></span></p> <p class="MsoNormal" style="text-align: justify;"><span style="font-size:85%;"><span lang="EN-US" style="font-family:Tahoma;"><!--[if !supportEmptyParas]--> <o:p></o:p></span></span></p> <p class="MsoNormal" style="text-align: justify;"><span style="font-size:85%;"><span lang="EN-US" style="font-family:Tahoma;"><span style="font-weight: bold;">After few modifications in .rsrc section:</span><o:p></o:p></span></span></p> <p class="MsoNormal" style="text-align: justify;"><span style="font-size:85%;"><span lang="EN-US" style="font-family:Tahoma;">C:\ssdeep>ssdeep -l gg.exe<o:p></o:p><br />ssdeep,1.0--blocksize:hash:hash,filename<o:p></o:p><br /><span style="font-style: italic;">49152:1xY5ndv7xb2OnhONkVCUDNl3lBB6U0ahgyFFvebjj:1xsdvH9RbMU0HyFFve3j,"gg.exe"</span><o:p></o:p></span></span></p> <p class="MsoNormal" style="text-align: justify;"><span style="font-size:85%;"><span lang="EN-US" style="font-family:Tahoma;">C:\ssdeep>ssdeep -m sum.txt -p gg.exe<o:p></o:p><br />C:\ssdeep\gg.exe matches C:\ssdeep\gg.exe <span style="color: rgb(255, 0, 0);">(91)</span><o:p></o:p></span></span></p> <div style="text-align: justify;"> </div><p style="text-align: justify;font-family:verdana;" class="MsoBodyText"><span style="font-size:85%;">Additionally, the percentage value of similarity is generated (value in brackets).<br /><span lang="EN-US">By setting the value to 60 or 70 we can implement quite effective method of blocking execution of specific files.</span></span></p><div style="text-align: justify;"> </div><p style="text-align: justify;" class="MsoNormal"><span lang="EN-US" style="font-family:Tahoma;"><span style=";font-family:verdana;font-size:85%;" >This solution could block the execution of particular program and even new versions of it because very often new releases are based on the previous one.</span> <o:p></o:p></span></p> <span style="font-size:78%;">Useful links:<br /></span> <p class="MsoNormal" style="text-align: justify;"><span style="font-size:78%;"><span lang="EN-US" style="font-family:Tahoma;">[1] <a href="http://ssdeep.sourceforge.net/">http://ssdeep.sourceforge.net/</a></span></span></p><p class="MsoNormal" style="text-align: justify;"><span style="font-size:78%;"><span lang="EN-US" style="font-family:Tahoma;">[2] <a href="http://www.dfrws.org/2006/proceedings/12-Kornblum.pdf">http://www.dfrws.org/2006/proceedings/12-Kornblum.pdf</a></span></span><span style="font-size:85%;"><span style=";font-family:Tahoma;font-size:12;" lang="EN-US" ></span></span></p><span style="font-size:78%;"></span>Mariuszhttp://www.blogger.com/profile/05214488888247283501noreply@blogger.com0tag:blogger.com,1999:blog-32465715.post-1156240431822748782006-08-22T11:45:00.000+02:002006-08-22T12:46:28.030+02:00Grsecurity and forensic analysis<p class="MsoNormal" style="font-family:verdana;"><span style="font-family:verdana;font-size:85%;">A few weeks ago a new version of <span style="FONT-WEIGHT: bold">grsecurity 2.1.9</span> was released </span><a href="http://www.grsecurity.net/news.php#grsec219"><span style="font-family:verdana;font-size:85%;">[1]</span></a><span style="font-family:verdana;font-size:85%;">. It is worth to mention about it because one new features affect how Linux physical memory forensic analysis will be performed. </span></p><p class="MsoNormal" style="font-family:verdana;"><span style="font-family:verdana;font-size:85%;">Firstly, all physical memory pages which are freed are overwritten. During freeing page frames, a new <span style="FONT-WEIGHT: bold">PaX</span> feature zeroes out them. It means that it will be impossible to recover content of pages such as memory mapped files from memory images which represent <span style="FONT-WEIGHT: bold">/dev/mem</span> or <span style="FONT-WEIGHT: bold">/proc/kcore</span>. Still, we can use methods of analysis which are based on interpreting internal kernel structures or trying to detect and recover hidden data </span><a href="http://forensic.seccure.net/pdf/mburdach_digital_forensics_of_physical_memory.pdf"><span style="font-family:verdana;font-size:85%;">[2]</span></a><span style="font-family:verdana;font-size:85%;">.</span></p><p class="MsoNormal" style="font-family:verdana;"><span style="font-family:verdana;font-size:85%;">Secondly, swap areas can be encrypted. It means that creating bit-by-bit copy of swap space partition from hard disk which was removed from compromised machine is useless.<?xml:namespace prefix = o /><o:p></o:p> </span></p><p class="MsoNormal" style="font-family:verdana;"><span style="font-family:verdana;font-size:85%;">Useful links:</span><span style="font-family:verdana;"><br /></span><span style="font-family:verdana;"><span style="font-size:78%;">[1] </span><a href="http://www.grsecurity.net/news.php#grsec219"><span style="font-size:78%;">http://www.grsecurity.net/news.php#grsec219</span></a><br /></span><span style="font-family:verdana;"><span style="font-size:78%;">[2] </span><a href="http://forensic.seccure.net/pdf/mburdach_digital_forensics_of_physical_memory.pdf"><span style="font-size:78%;">http://forensic.seccure.net/pdf/mburdach_digital_forensics_of_physical_memory.pdf</span></a></span></p>Mariuszhttp://www.blogger.com/profile/05214488888247283501noreply@blogger.com0tag:blogger.com,1999:blog-32465715.post-1156172335724329912006-08-21T16:26:00.000+02:002006-08-22T10:38:30.093+02:00“Memory forensics” related debugger extension DLLs for Microsoft Debuggers<div style="text-align: justify;"><span style=";font-family:verdana;font-size:85%;" >One of the biggest problem with Windows “memory forensics” related tools is that such tools have to be updated concurrently because of new version of operating system or service pack. I’m thinking about offsets to fields inside various internal kernel structures which can vary. It is obvious that sooner or later you will have to use description of some internal structures to find digital evidence. If you write your own script or tool to parse a physical memory image you will have to take into consideration this problem. Even if you prepare signatures to grep some objects you will need information about offsets. Now just think about generic solution which is based on using symbols which can be download automatically or manually from Microsoft servers. Instead of hard coding information about Windows internal kernel structures and offsets for various versions of operating systems you just write one code for all of them. Firstly, your code is smaller (you can avoid many mistakes, too). Secondly, you can save a lot of time. So if you are lazy this solutions will be exactly for you :).<br /><br /></span><span style=";font-family:verdana;font-size:85%;" >I decided to take a look closer at Microsoft Debugging Tools for Windows and debugger extensions which can be used by MS Debuggers and allow to use new debugger commands. </span><span style=";font-family:verdana;font-size:85%;" ><br /><br />As we should know physical memory device objects (<span style="font-weight: bold;">\\.\PhysicalMemory</span> and <span style="font-weight: bold;">\\.\DebugMemory</span>) in Windows operating systems represent a raw data. It is impossible to load an image of such device object into WinDbg or KD because this file will be not recognized by Debuggers. Fortunately, you can convert raw data to recognizable format (crashdump format). A part of dump header format is described by Andreas Schuster at <a href="http://computer.forensikblog.de/en/2006/03/dmp_file_structure.html">[1]</a>. </span><span style="font-size:85%;"><br /><br /></span><span style=";font-family:verdana;font-size:85%;" >The next step is to download Debugging Tools for Windows and Symbols from <a href="http://www.microsoft.com/whdc/devtools/debugging/default.mspx">[2]</a>. If you have a direct access to the Internet you will not have to download Symbols because the debugger tool downloads Symbols for you automatically.</span><span style="font-size:85%;"><br /><br /></span><span style=";font-family:verdana;font-size:85%;" >Debugger extension commands are exposed by DLLs. A short description about how to write new debugger commands can be found in the debugger.chm file which is installed with Debugging Tools for Windows (You have to use custom installation to install examples). </span><span style="font-size:85%;"><br /><br /></span><span style=";font-family:verdana;font-size:85%;" >An environment described above can be used to perform offline analysis of physical memory dumps. In the other hand debugger extension DLLs can be used to verify system integrity on a live system. You have to use the livekd tool from <a href="http://www.sysinternals.com/Utilities/LiveKd.html">[3]</a> </span><span style=";font-family:verdana;font-size:85%;" >to load and execute commands exported by dll extensions.</span><span style="font-size:85%;"><br /><br /></span><span style=";font-family:verdana;font-size:85%;" >A few useful functions which allow you to resolve Symbols or find out the offset are described below.</span><span style="font-size:85%;"><br /></span></div><ol><li><span style="font-weight: bold;font-family:verdana;font-size:85%;" >GetOffsetByName(Symbol, Address)</span><span style=";font-family:verdana;font-size:85%;" >, where the Symbol is the name of symbol like PsInitialSystemProcess or PsLoadedModuleList. The address of requested symbol is returned by the Address parameter.</span></li><li><span style=";font-family:verdana;font-size:85%;" ><span style="font-weight: bold;">GetSymbolTypeId(Symbol, TypeId, Module)</span>, </span><span style=";font-family:verdana;font-size:85%;" >where the TypeId is an index within PDB file which is associated with the Module.</span></li></ol><span style=";font-family:verdana;font-size:85%;" >After that you can call other functions which take the TypeId and Module as parameters:</span><span style="font-size:85%;"><br /></span><ul><li><span style=";font-family:verdana;font-size:85%;" ><span style="font-weight: bold;">GetTypeSize(Module, TypeId, Size)</span> to receive size of requested internal structure,</span></li><li><span style=";font-family:verdana;font-size:85%;" ><span style="font-weight: bold;">GetFieldName(Module, TypeId, Iteration, Name, MAX_PATH, NULL)</span> to receive the Name of field pointed by a number = the Iteration,</span></li><li><span style=";font-family:verdana;font-size:85%;" >or <span style="font-weight: bold;">GetFieldOffset(Module, TypeId, Name, Offset)</span> to receive the offset of requested field defined by the Name.</span></li></ul><span style="font-size:85%;"><br /></span><span style=";font-family:verdana;font-size:85%;" >I wrote the function “offset(structname, fieldname)” which receives the offset to requested field of requested structure.</span><span style="font-size:85%;"><br /><br /></span><span style=";font-family:courier new;font-size:85%;" >ULONG offset(CHAR *structname, CHAR *fieldname)</span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" >{</span><span style="font-size:85%;"><br /><br /></span><span style=";font-family:courier new;font-size:85%;" > ULONG64 Module;</span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" > ULONG i1, TypeId;</span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" > CHAR Name[MAX_PATH];</span><span style="font-size:85%;"><br /><br /></span> <span style=";font-family:courier new;font-size:85%;" > g_ExtSymbols->GetSymbolTypeId(structname, &TypeId, &amp;amp;amp;amp;Module);</span><span style="font-size:85%;"><br /><br /></span> <span style=";font-family:courier new;font-size:85%;" > for (i1=0; ;i1++) {</span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" > HRESULT Hr1;</span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" > ULONG Offset=0;</span><span style="font-size:85%;"><br /><br /></span><span style=";font-family:courier new;font-size:85%;" > Hr1 = g_ExtSymbols->GetFieldName(Module, TypeId, i1, Name, MAX_PATH, NULL);</span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" > if (Hr1 == S_OK) {</span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" > g_ExtSymbols->GetFieldOffset(Module, TypeId, Name, &Offset);</span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" > if (strcmp(Name,fieldname) == 0) {</span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" > return Offset;</span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" > }</span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" > } </span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" > else </span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" > if (Hr1 == E_INVALIDARG) {</span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" > break;</span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" > } </span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" > else {</span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" > dprintf("GetFieldName Failed %lx\n", Hr1);</span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" > break;</span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" > }</span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" >}</span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" >return 0;</span><span style="font-size:85%;"><br /></span><span style=";font-family:courier new;font-size:85%;" >}</span><span style="font-size:85%;"><br /></span><span style=";font-family:verdana;font-size:85%;" ><br />You can call this function in the following way: </span><span style="font-size:85%;"><br /></span><span style="font-weight: bold;font-family:verdana;font-size:85%;" >ULONG OffsetAPL = offset("_EPROCESS","ActiveProcessLinks");</span><span style="font-size:85%;"><br /><br /></span><span style=";font-family:verdana;font-size:85%;" >Of course it is enough to use “dt _EPROCESS” command to receive the same result so now something more useful. At my website <span style="color: rgb(255, 0, 0);">http://forensic.seccure.net</span> <a href="http://forensic.seccure.net/tools/hidden.zip">[4]</a></span><span style=";font-family:verdana;font-size:85%;" > you can find the extension dll called hidden.dll which allows to detect all hidden processes – even hidden by the DKOM method. The command to call proper function is “!</span><full path="" to="" directory="" with="" dll="" file=""><span style=";font-family:verdana;font-size:85%;" >"full path to directory with hidden.dll file"hidden. </span></full><span style=";font-family:Tahoma;font-size:12;" lang="EN-US" ></span><full path="" to="" directory="" with="" dll="" file=""><span style=";font-family:verdana;font-size:85%;" >allprocesses”. For example: “kd>!c:\temp\hidden.allprocesses”</span><span style="font-size:85%;"><br /><br /></span><span style=";font-family:verdana;font-size:85%;" >You can record in external file all executed commands and results by using the command “.logappend “c:\forensics.log””.</span><span style="font-size:85%;"><br /><br /></span><span style=";font-family:verdana;font-size:85%;" >As I mention above dll extensions can be executed at any version of Windows operating system. On a live system you have to use the livekd tool <a href="http://www.sysinternals.com/Utilities/LiveKd.html">[3]</a>.</span><span style="font-size:85%;"><br /><br /></span><span style=";font-family:verdana;font-size:85%;" >Useful links:</span><br /><span style=";font-family:verdana;font-size:78%;" >[1] <a href="http://computer.forensikblog.de/en/2006/03/dmp_file_structure.html">http://computer.forensikblog.de/en/2006/03/dmp_file_structure.html</a></span><span style="font-size:78%;"><br /></span><span style=";font-family:verdana;font-size:78%;" >[2] <a href="http://www.microsoft.com/whdc/devtools/debugging/default.mspx">http://www.microsoft.com/whdc/devtools/debugging/default.mspx</a></span><span style="font-size:78%;"><br /></span><span style=";font-family:verdana;font-size:78%;" >[3] <a href="http://www.sysinternals.com/Utilities/LiveKd.html">http://www.sysinternals.com/Utilities/LiveKd.html</a></span><span style="font-size:78%;"><br /></span><span style="font-family:verdana;"><span style="font-size:78%;">[4] <a href="http://forensic.seccure.net/tools/hidden.zip">http://forensic.seccure.net/tools/hidden.zip</a></span> </span><br /></full>Mariuszhttp://www.blogger.com/profile/05214488888247283501noreply@blogger.com0