Permalink
Browse files

Web UI (#173)

* add index and snares page

* add session-info page

* add session-filters page

* add session-stats

* update snare and snares page

* add filters input

* Update UI
list to strings

* Add interactive filtering

* show filters

* add static files

* implement inheritance

* minor fixes

* use congif for port and ip

* add filter example on hover

* add missing import

* start tannerweb easily

* add dependencies

* fix filter bug

* make filter example notable
  • Loading branch information...
rnehra01 authored and afeena committed Jul 20, 2017
1 parent e82d5e4 commit fc629f030e78e76a120558b265c6f5b8540a1e8b
View
@@ -0,0 +1,9 @@
#!/usr/bin/python3.5
from tanner.web import server
def main():
tannerweb = server.TannerWebServer()
tannerweb.start()
if __name__ == "__main__":
main()
View
@@ -1,5 +1,6 @@
aiohttp>=2.0
aiomysql
aiohttp_jinja2
docker
elizabeth==0.3.27
yarl
@@ -8,3 +9,4 @@ asyncio_redis
uvloop
pymongo
pylibinjection
jinja2
View
@@ -9,6 +9,6 @@
author_email='glastopf@public.honeynet.org',
url='https://github.com/mushorg/tanner',
packages=find_packages(exclude=['*.pyc']),
scripts=['bin/tanner'],
scripts=['bin/tanner', 'bin/tannerweb'],
data_files=[('/opt/tanner/data/',['tanner/data/dorks.pickle'])]
)
View
@@ -1,6 +1,7 @@
import json
import logging
import operator
import asyncio_redis
from aiohttp import web
View
@@ -8,6 +8,7 @@
'user_dorks': '/opt/tanner/data/user_dorks.pickle',
'vdocs': '/opt/tanner/data/vdocs.json'},
'TANNER': {'host': '0.0.0.0', 'port': 8090},
'WEB': {'host': '0.0.0.0', 'port': 8091},
'REDIS': {'host': 'localhost', 'port': 6379, 'poolsize': 80, 'timeout': 1},
'EMULATORS': {'root_dir': '/opt/tanner',
'emulator_enabled': {'sqli': True, 'rfi': True, 'lfi': True, 'xss': True, 'cmd_exec': True}
@@ -12,6 +12,7 @@ def setUp(self):
'user_dorks': '/tmp/user_tanner/data/user_dorks.pickle',
'vdocs': '/tmp/user_tanner/data/vdocs.json'},
'TANNER': {'host': '0.0.0.0', 'port': '9000'},
'WEB': {'host': '0.0.0.0', 'port': '9001'},
'REDIS': {'host': 'localhost', 'port': '1337', 'poolsize': '40', 'timeout': '5'},
'EMULATORS': {'root_dir': '/tmp/user_tanner'},
'SQLI': {'type':'SQLITE', 'db_name': 'user_tanner_db', 'host':'localhost', 'user':'user_name', 'password':'user_pass'},
@@ -57,6 +58,7 @@ def test_get_when_file_dont_exists(self):
'user_dorks': '/opt/tanner/data/user_dorks.pickle',
'vdocs': '/opt/tanner/data/vdocs.json'},
'TANNER': {'host': '0.0.0.0', 'port': 8090},
'WEB': {'host': '0.0.0.0', 'port': 8091},
'REDIS': {'host': 'localhost', 'port': 6379, 'poolsize': 80, 'timeout': 1},
'EMULATORS': {'root_dir': '/opt/tanner'},
'SQLI': {'type':'SQLITE', 'db_name': 'tanner_db', 'host':'localhost', 'user':'root', 'password':'user_pass'},
View
No changes.
View
@@ -0,0 +1,100 @@
import asyncio
import aiohttp_jinja2
import jinja2
import logging
from aiohttp import web
from tanner import api, redis_client
from tanner.config import TannerConfig
class TannerWebServer:
def __init__(self):
self.logger = logging.getLogger('tanner.web.tannerwebserver')
self.api = None
self.redis_client = None
@aiohttp_jinja2.template('index.html')
async def handle_index(self, request):
return
@aiohttp_jinja2.template('snares.html')
async def handle_snares(self, request):
snares = await self.api.return_snares()
return {
'snares' : snares
}
@aiohttp_jinja2.template('snare.html')
async def handle_snare(self, request):
snare_uuid = request.match_info['snare_uuid']
return{
'snare' : snare_uuid
}
@aiohttp_jinja2.template('snare-stats.html')
async def handle_snare_stats(self, request):
snare_uuid = request.match_info['snare_uuid']
snare_stats = await self.api.return_snare_stats(snare_uuid)
return {
'snare_stats' : snare_stats
}
@aiohttp_jinja2.template('sessions.html')
async def handle_sessions(self, request):
snare_uuid = request.match_info['snare_uuid']
params = request.url.query
applied_filters = {'snare_uuid': snare_uuid}
try:
if 'filters' in params:
for filt in params['filters'].split():
applied_filters[filt.split(':')[0]] = filt.split(':')[1]
if 'start_time' in applied_filters:
applied_filters['start_time'] = float(applied_filters['start_time'])
if 'end_time' in applied_filters:
applied_filters['end_time'] = float(applied_filters['end_time'])
except Exception as e:
self.logger.error('Filter error : %s' % e)
result = 'Invalid filter definition'
else:
sess_uuids = await self.api.return_sessions(applied_filters)
sessions = []
for sess_uuid in sess_uuids:
sess = await self.api.return_session_info(sess_uuid)
sessions.append(sess)
result = sessions
return {
'sessions' : result
}
@aiohttp_jinja2.template('session.html')
async def handle_session_info(self, request):
sess_uuid = request.match_info['sess_uuid']
session = await self.api.return_session_info(sess_uuid)
return {
'session' : session
}
def setup_routes(self, app):
app.router.add_get('/', self.handle_index)
app.router.add_get('/snares', self.handle_snares)
app.router.add_resource('/snare/{snare_uuid}').add_route('GET', self.handle_snare)
app.router.add_resource('/snare-stats/{snare_uuid}').add_route('GET', self.handle_snare_stats)
app.router.add_resource('/session/{sess_uuid}').add_route('GET', self.handle_session_info)
app.router.add_resource('/{snare_uuid}/sessions').add_route('GET', self.handle_sessions)
app.router.add_static('/static/', path='tanner/web/static')
def create_app(self, loop):
app = web.Application(loop= loop)
aiohttp_jinja2.setup(app,
loader= jinja2.FileSystemLoader('tanner/web/templates'))
self.setup_routes(app)
return app
def start(self):
loop = asyncio.get_event_loop()
self.redis_client = loop.run_until_complete(redis_client.RedisClient.get_redis_client())
self.api = api.Api(self.redis_client)
app = self.create_app(loop)
host = TannerConfig.get('WEB', 'host')
port = TannerConfig.get('WEB', 'port')
web.run_app(app, host=host, port=port)
@@ -0,0 +1,14 @@
table {
border-collapse: collapse;
width: 80%;
}
th, td {
padding: 8px;
text-align: left;
border-bottom: 1px solid #ddd;
}
tr:hover{
background-color:#f5f5f5
}
@@ -0,0 +1,13 @@
function findGetParameter(parameterName) {
var result = null,
tmp = [];
location.search
.substr(1)
.split("&")
.forEach(function (item) {
tmp = item.split("=");
if (tmp[0] === parameterName) result = decodeURIComponent(tmp[1]);
});
return result;
}
document.getElementById('filters').value = findGetParameter("filters");
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}{% endblock %} - Tanner Web</title>
<link rel="stylesheet" type="text/css" href="/static/css/styles.css">
</head>
<body>
<div id="content">
{% block content%}
{% endblock%}
</div>
<div id="footer">
{% block footer%}
{% endblock%}
</div>
</body>
</html>
@@ -0,0 +1,5 @@
{% extends "base.html" %}
{% block title %}Home{% endblock %}
{% block content %}
Tanner Web
{% endblock %}
@@ -0,0 +1,92 @@
{% extends "base.html" %}
{% block title %}Session({{session.sess_uuid}}){% endblock %}
{% block content %}
<body>
<h3 align="center">SESSION INFO</h3>
<table align="center">
<tr>
<th style="width: 20%">Key</th>
<th>Value</th>
</tr>
<tr>
<td><b>UUID</b></td>
<td>{{session.sess_uuid}}</td>
</tr>
<tr>
<td><b>IP</b></td>
<td><a href="/{{session.snare_uuid}}/sessions?filters=peer_ip:{{session.peer_ip}}">{{session.peer_ip}}</a></td>
</tr>
<tr>
<td><b>Port</b></td>
<td>{{session.peer_port}}</td>
</tr>
<tr>
<td><b>User Agents</b></td>
<td>{{session.user_agent}}</td>
</tr>
<tr>
<td><b>Snare UUID</b></td>
<td>{{session.snare_uuid}}</td>
</tr>
<tr>
<td><b>Start time</b></td>
<td><a href="/{{session.snare_uuid}}/sessions?filters=start_time:{{session.start_time}}">{{session.start_time}}</a></td>
</tr>
<tr>
<td><b>End time</b></td>
<td><a href="/{{session.snare_uuid}}/sessions?filters=end_time:{{session.end_time}}">{{session.end_time}}</a></td>
</tr>
<tr>
<td><b>Requests/sec</b></td>
<td>{{session.requests_in_second}}</td>
</tr>
<tr>
<td><b>Time between requests</b></td>
<td>{{session.approx_time_between_requests}}</td>
</tr>
<tr>
<td><b>Paths</b></td>
<td>{{session.accepted_paths}}</td>
</tr>
<tr>
<td><b>Errors</b></td>
<td>{{session.errors}}</td>
</tr>
<tr>
<td><b>Hidden Links</b></td>
<td>{{session.hidden_links}}</td>
</tr>
<tr>
<td><b>Attack types</b></td>
<td>
{% for attack in session.attack_types %}
<a href="/{{session.snare_uuid}}/sessions?filters=attack_types:{{attack}}">{{attack}}</a><br>
{% endfor %}
</td>
</tr>
<tr>
<td><b>Paths</b></td>
<td>
{% for path in session.paths %}
{{path}} <br>
{% endfor %}
</td>
</tr>
<tr>
<td><b>Cookies</b></td>
<td>
{% for key, val in session.cookies.items() %}
{{key}} : {{val}} <br>
{% endfor %}
</td>
</tr>
<tr>
<td><b>Possible Owners</b></td>
<td>
{% for owner in session.possible_owners %}
<a href="/{{session.snare_uuid}}/sessions?filters=possible_owners:{{owner}}">{{owner}}</a><br>
{% endfor %}
</td>
</tr>
</table>
{% endblock %}
@@ -0,0 +1,30 @@
{% extends "base.html" %}
{% block title %}Snare Sessions{% endblock %}
{% block content %}
<h3 align="center">SNARE-SESSIONS</h3>
<div align="center">
<form>
<b>Filters:</b> <input size="80" type="text" name="filters" id="filters">
<input type="submit" value="Apply"> <i title="E.g - peer_ip:172.25.23.1, possible_owner:attacker
See the docs for more filters.">How?</i>
</form>
</div>
<table align="center">
<tr>
<th style="width: 20%">No</th>
<th>Session-uuid</th>
<th>IP</th>
<th>Owner</th>
</tr>
{% for sess in sessions %}
<tr>
<td>{{loop.index}}</td>
<td><a href="/session/{{sess.sess_uuid}}">{{sess.sess_uuid}}</a></td>
<td>{{sess.peer_ip}}</td>
<td>{{sess.possible_owners|join(',')}}</td>
</tr>
{% endfor %}
</table>
<script src="/static/js/site.js"></script>
</script>
{% endblock %}
@@ -0,0 +1,27 @@
{% extends "base.html" %}
{% block title %}SNARE-STATS{% endblock %}
{% block content %}
<h3 align="center">SNARE-STATS</h3>
<table align="center">
<tr>
<th style="width: 20%">Key</th>
<th>Value</th>
</tr>
<tr>
<td><b>No of Sessions</b></td>
<td>{{snare_stats.total_sessions}}</td>
</tr>
<tr>
<td><b>Total Duration</b></td>
<td>{{snare_stats.total_duration}}</td>
</tr>
<tr>
<td><b>Attack Frequency</b></td>
<td>
{% for key, val in snare_stats.attack_frequency.items() %}
{{key}} : {{val}} <br>
{% endfor %}
</td>
</tr>
</table>
{% endblock %}
@@ -0,0 +1,7 @@
{% extends "base.html" %}
{% block title %}Snare({{snare}}){% endblock %}
{% block content %}
<h3 align="center">{{snare}}</h3>
<h4 align="center"><a href="/snare-stats/{{snare}}">Snare-Stats</a></h4>
<h4 align="center"><a href="/{{snare}}/sessions">Sessions</a></h4>
{% endblock %}
Oops, something went wrong.

0 comments on commit fc629f0

Please sign in to comment.