platform/libinjection/misc/logscanner2.py

214 lines
6.1 KiB
Python
Raw Normal View History

2019-08-16 14:42:40 +00:00
#!/usr/bin/env python
import datetime
import json
import sys
from urlparse import *
import urllib
import libinjection
from tornado import template
from tornado.escape import *
import re
import calendar
months = {
'Jan':'01',
'Feb':'02',
'Mar':'03',
'Apr':'04',
'May':'05',
'Jun':'06',
'Jul':'07',
'Aug':'08',
'Sep':'09',
'Oct':'10',
'Nov':'11',
'Dec':'12'
}
# "time_iso8601":"2013-08-04T03:51:18+00:00"
def parse_date(datestr):
elems = (
datestr[7:11],
months[datestr[3:6]],
datestr[0:2],
datestr[12:14],
datestr[15:17],
datestr[18:20],
)
return ( "{0}-{1}-{2}T{3}:{4}:{5}+00:00".format(*elems), calendar.timegm( [ int(i) for i in elems] ) )
apachelogre = re.compile(r'^(\S*) (\S*) (\S*) \[([^\]]+)\] \"([^"\\]*(?:\\.[^"\\]*)*)\" (\S*) (\S*) \"([^"\\]*(?:\\.[^"\\]*)*)\" \"([^"]*)\" \"([^"]*)\"')
def parse_apache(line):
mo = apachelogre.match(line)
if not mo:
return None
(time_iso, timestamp) = parse_date(mo.group(4))
try:
(method, uri, protocol) = mo.group(5).split(' ', 2)
except ValueError:
(method, uri, protocol) = ('-', '-', '-')
data = {
'remote_addr': mo.group(1),
'time_iso8601': time_iso,
'timestamp' : timestamp,
'request_protocol': protocol,
'request_method': method,
'request_uri': uri,
'request_length': '',
'request_time': '',
'status': mo.group(6),
'bytes_sent': '',
'body_bytes-sent': int(mo.group(7)),
'http_referrer': mo.group(8),
'http_user_agent': mo.group(9),
'ssl_cipher': '',
'ssl_protocol': ''
}
return data
# http://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks-in-python
def chunks(l, n):
"""
Yield successive n-sized chunks from l.
"""
for i in xrange(0, len(l), n):
yield l[i:i+n]
def breakify(s):
output = ""
for c in chunks(s, 40):
output += c
if ' ' not in c:
output += ' '
return output
def doline(line):
line = line.replace("\\x", "%").strip()
try:
data = json.loads(line)
except ValueError, e:
data = parse_apache(line)
if data is None:
sys.stderr.write("BAD LINE: {0}\n".format(line))
return None
if not data.get('request_uri','').startswith("/diagnostics"):
return None
urlparts = urlparse(data['request_uri'])
if len(urlparts.query) == 0:
return None
qsl = [ x.split('=', 1) for x in urlparts.query.split('&') ]
target = None
for k,v in qsl:
if k == 'id':
target = v
break
if target is None:
#print "no 'id'"
return None
# part one, normal decode
target = urllib.unquote_plus(target)
# do it again, but preserve '+'
target = urllib.unquote(target)
sstate = libinjection.sqli_state()
# BAD the string created by target.encode is stored in
# sstate but not reference counted, so it can get
# deleted by python
# libinjection.sqli_init(sstate, target.encode('utf-8'), 0)
# instead make a temporary var in python
# with the same lifetime as sstate (above)
try:
targetutf8 = target.encode('utf-8')
#targetutf8 = target
except UnicodeDecodeError, e:
targetutf8 = target
#if type(target) == str:
# sys.stderr.write("Target is a string\n")
#if type(target) == unicode:
# sys.stderr.write("Target is unicde\n")
#sys.stderr.write("OOps: {0}\n".format(e))
#sys.stderr.write("Encode error: {0}\n".format(target))
try:
libinjection.sqli_init(sstate, targetutf8, 0)
except TypeError:
sys.stderr.write("fail in decode: {0}".format(targetutf8))
if type(target) == str:
sys.stderr.write("Target is a string\n")
if type(target) == unicode:
sys.stderr.write("Target is unicde\n")
return None
sqli = bool(libinjection.is_sqli(sstate))
return (target, sqli, sstate.fingerprint, data['remote_addr'])
if __name__ == '__main__':
s = """
174.7.27.149 - - [29/Jul/2013:01:30:19 +0000] "GET /diagnostics?id=x|x||1&type=fingerprints HTTP/1.1" 200 1327 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.72 Safari/537.36" "-"
"""
s = """
{"timestamp":1371091563,"remote_ip":"219.110.171.2","request":"/diagnostics?id=1+UNION+ALL+SELECT+1<<<&type=fingerprints","method":"GET","status":200,"user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/536.30.1 (KHTML, like Gecko) Version/6.0.5 Safari/536.30.1","referrer":"https://libinjection.client9.com/diagnostics","duration_usec":160518 }
{"timestamp":1371091563,"remote_ip":"219.110.171.2","request":"/diagnostics?id=2+UNION+ALL+SELECT+1<<<&type=fingerprints","method":"GET","status":200,"user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/536.30.1 (KHTML, like Gecko) Version/6.0.5 Safari/536.30.1","referrer":"https://libinjection.client9.com/diagnostics","duration_usec":160518 }
"""
if len(sys.argv) == 2:
fh = open(sys.argv[1], 'r')
else:
fh = sys.stdin
targets = set()
table = []
for line in fh:
parts = doline(line.strip())
if parts is None:
continue
# help it render in HTML
if parts[0] in targets:
continue
else:
targets.add(parts[0])
# add link
# add form that might render ok in HTML
# is sqli
# fingerprint
table.append( (
"/diagnostics?id=" + url_escape(parts[0]),
breakify(parts[0].replace(',', ', ').replace('/*', ' /*')),
parts[1],
parts[2],
parts[3]
)
)
table = reversed(table)
loader = template.Loader(".")
txt = loader.load("logtable.html").generate(
table=table,
now = str(datetime.datetime.now()),
ssl_protocol='',
ssl_cipher=''
)
print txt