Lizarding About With Log Parser Lizard

Use Log Parser Lizard toi quickly search through millions of rows of logs

Lizarding About With Log Parser Lizard

I've recently been playing about with Request Filtering which is an interesting add-on for IIS7 onwards. I'll blog about that soon, but I have had so much fun as a result of switching on Request Filtering I thought I'd write about some of the consequences first.

It allows you to set up rules, so certain requests are filtered out before they even get to your site, resulting in less load and a supposedly safer system. Lets say we want to filter out a URL or query string that contains the word "script" as shown in the link below.<script>alert('attacked')</script>

I won't go into the mechanics of Request Filtering yet, but lets just say that the filter would return a http 404

To the attacker, 404 just means not found but in the IIS logs we can discover the subcode. Anyone that has taken a look into an IIS log knows that they can be hell. They're long, text based and not really for human consumption.

Step Foward Log Parser Lizard

Microsoft released a command line tool way back in the mid 00's called Log Parser that used SQL style syntax to query text based log files. Log Lizard takes this a step further by adding a really simple GUI.

It's very cheap too. Download from here

What Logs Can It Read?
It can read text based log files such as IIS, HTTP, Event, SQL Error and lots more too. Some logs need a bit more effort on your part to configure the file (e.g SQL Logs) but once it works you are able to save your query for future use.

You can see form this image that there are actually loads of logs that it can use straight out of the box:


SELECT sc-status As Status,sc-substatus AS SubStatus,COUNT(sc-substatus) As SubStatusCount,CASE sc-substatus
WHEN 1 THEN 'Site Not Found'
WHEN 2 THEN 'ISAPI or CGI restriction'
WHEN 3 THEN 'MIME type restriction'
WHEN 4 THEN 'No handler configured'
WHEN 9 THEN 'File attribute hidden'
WHEN 16 THEN 'DAV request sent to the static file handler'
WHEN 17 THEN ' Dynamic content mapped to the static file handler via a wildcard MIME mapping'
WHEN 20 THEN ' Too Many URL Segments'
--5-19 below are Request Filtering
WHEN 5 THEN 'URL Sequence Denied'
WHEN 6 THEN 'Verb Denied'
WHEN 7 THEN 'File extension denied'
WHEN 8 THEN 'Hidden Namespace'
WHEN 10 THEN 'Request Header Too Long'
WHEN 11 THEN 'URL Double Escaped'
WHEN 12 THEN 'URL Has High Bit Chars'
WHEN 13 THEN 'Content Length Too Large'
WHEN 14 THEN 'URL Too Long'
WHEN 15 THEN 'Query String Too Long'
WHEN 18 THEN 'Query String Sequence Denied'
WHEN 19 THEN 'Denied by Filtering Rule'
END AS SubStatusDescription
FROM #IISW3C# WHERE sc-status = 404 GROUP BY Status , SubStatus ORDER BY Status


Here we can see the sub-statuses, the count and the description. A full list of sub-statuses and their description can be found here

Other Queries

The following is a list of queries that have been gathered together from various sources, some I have written, most have been written by others, but all are useful. Give them ago and start to love parsing logs.

To get full use of the logs, ensure that all relevant fields are being saved into the log (e.g by default many fields are not saved). See here to configure logging

Bytes Per File Extension

MUL(PROPSUM(sc-bytes),100.0) AS PercentageOfBytes,  
Div(Sum(sc-bytes),1024) as AmountOfMbBytes  
GROUP BY Extension  
ORDER BY PercentageOfBytes DESC  

Win32 Error Codes and Description

SELECT sc-win32-status As Win32-Status,  
WIN32_ERROR_DESCRIPTION(sc-win32-status) as Description,  
COUNT(*) AS Hits  
WHERE Win32-Status<>0  
GROUP BY Win32-Status  
ORDER BY Win32-Status ASC  

Blocked File Extensions (404.7)

WHERE sc-status = 404 and sc-substatus = 7   --file extension denied  
ORDER BY Extension DESC  

Files Accessed Over the Web (HTTP 200)

SELECT DISTINCT TO_LOWERCASE(cs-uri-stem) AS URL, Count(*) AS Hits  
WHERE sc-status=200  

Overused Scripts by Day
A script (e.g. js or aspx) that is highly overused may be suspicious.

SELECT TO_STRING(TO_TIMESTAMP(date, time), 'yyyy-MM-dd') AS Day,  
cs-uri-stem, COUNT(*) AS Total  
WHERE (sc-status<400 or sc-status>=500) AND (TO_LOWERCASE(cs-uri-stem) LIKE '%.asp%'  
TO_LOWERCASE(cs-uri-stem) LIKE '%.exe%'  
TO_LOWERCASE(cs-uri-stem) LIKE '%.js%')  
GROUP BY Day, cs-uri-stem  
ORDER BY cs-uri-stem  

High Number of Hits to Single Page by One IP

--possible evidence of attacks 
SELECT DISTINCT date, cs-uri-stem, c-ip, Count(*) AS Hits  
GROUP BY date, c-ip, cs-uri-stem  
HAVING Hits>50  
ORDER BY Hits Desc  

Excessive Errors

--This may be a sign of attack
SELECT date, QUANTIZE(time, 3600) AS hour, sc-status,sc-substatus, Count(*) AS Errors  
WHERE sc-status>=400  
GROUP BY date, hour, sc-status,sc-substatus  
HAVING Errors>25  

Excessive HTTP 500

--This may be a sign that SQL injection is being attempted or exploited.
SELECT cs-uri-query, Count(*) AS Total  
WHERE sc-status>=500  
GROUP BY cs-uri-query  

Non Standard UserAgents

--Possible attack by automated tools or other hacker tools
SELECT DISTINCT cs(User-Agent)  
WHERE TO_LOWERCASE(cs(User-Agent)) NOT LIKE '%mozilla%' AND TO_LOWERCASE(cs(User-Agent)) NOT LIKE '%opera%'  
ORDER BY cs(User-Agent)  

Bytes Sent To Client

SELECT cs-uri-stem, Count(*) as Hits, AVG(sc-bytes) AS Avg, Max(sc-bytes) AS Max, Min(sc-bytes) AS Min, Sum(sc-bytes) AS Total  
WHERE TO_LOWERCASE(cs-uri-stem) LIKE '%.asp%'  
TO_LOWERCASE(cs-uri-stem) LIKE '%.exe%'  
GROUP BY cs-uri-stem  
ORDER BY cs-uri-stem 

HTTP errors ordered by URL and Status

SELECT cs-uri-stem AS Url, sc-status AS Status, COUNT(*) AS Errors  
WHERE (sc-status >= 400)  
GROUP BY Url, Status  

Page Hits By IP Address

SELECT c-ip, count(c-ip) as requestcount  
WHERE  cs-uri-stem like '%.aspx%'  
GROUP BY c-ip  
ORDER BY count(c-ip) desc  

Requests By IP Address

SELECT c-ip, count(c-ip) as requestcount  
GROUP BY c-ip  
ORDER BY count(c-ip) desc  

Top Browsers

SELECT to_int(mul(100.0,PropCount(*))) as Percent, count(*) as TotalHits, cs(User-Agent) as Browser  
GROUP BY Browser  
ORDER BY Totalhits desc  

Top Images – Hits, Time & bandwidth

SELECT Top 100 StrCat(Extract_Path(TO_Lowercase(cs-uri-stem)),'/') AS RequestedPath,  
Extract_filename(To_Lowercase(cs-uri-stem)) As RequestedFile, Count(*) AS Hits, Max(time-taken) As MaxTime, Avg(time-taken) As AvgTime, Max(sc-bytes) As BytesSent  
WHERE  (Extract_Extension(To_Lowercase(cs-uri-stem)) IN 'gif';'jpg';'png';'svg')) AND (sc-status = 200)  
GROUP BY To_Lowercase(cs-uri-stem)  
ORDER BY BytesSent, Hits, MaxTime DESC  

Broken Links on Sites That Refer To Your Site

SELECT DISTINCT cs(Referer) as Referer, cs-uri-stem as Url  
cs(Referer) IS NOT NULL AND  
sc-status = 404 AND  
(sc-substatus IS NULL OR sc-substatus=0)

Part 2 of this article is here

Sources and Further Reading

Lots more queries