-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4dc31ef
commit 1b765b6
Showing
3 changed files
with
212 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
from tornado.web import RequestHandler | ||
import json | ||
from time import time | ||
import firebase_admin | ||
from firebase_admin import credentials | ||
from firebase_admin import db | ||
from urllib.parse import urlparse | ||
from requests import post | ||
|
||
|
||
cred = credentials.Certificate('ids-hackathor-636a3e9f4e4c.json') | ||
firebase_admin.initialize_app(cred, { | ||
'databaseURL': 'https://ids-hackathor.firebaseio.com/' | ||
}) | ||
ref = db.reference('') | ||
|
||
with open('payloads.json', encoding="utf8") as f: | ||
loaded = json.load(f) | ||
XSS = loaded['XSS'] | ||
TRAVERS = loaded['TRAVERS'] | ||
|
||
VIRUSTOTAL = '66a5fb757b258c33502762d5b0f494111d7cc70032cfcf115336ad837a13b9ea' | ||
DOMAIN = "bilkent.com" | ||
|
||
|
||
def send_ref(ip, param, val, type): | ||
ref.push({ | ||
"ip": ip, | ||
"type": type, | ||
"query_key": param, | ||
"query_val": val, | ||
"timestamp": time() | ||
}) | ||
|
||
|
||
def not_same_domain(url): | ||
url = urlparse(url).netloc | ||
index = url.find("@") | ||
if index != -1: | ||
url = url[index + 1:] | ||
return url != DOMAIN | ||
|
||
|
||
class AnalyzeQuery(RequestHandler): | ||
def initialize(self): | ||
pass | ||
|
||
|
||
async def get(self): | ||
result = db.reference('').get() | ||
self.write(result) | ||
|
||
async def post(self): | ||
params = json.loads(self.request.body) | ||
ip = self.request.remote_addr | ||
for param, val in params.items(): | ||
# XSS | ||
for pload in XSS: | ||
if pload in val: | ||
send_ref(ip, param, val, 'XSS') | ||
break | ||
# SQLi | ||
if "'" in val and ('and' in val.lower() or 'or' in val.lower()) or '--' in val: | ||
send_ref(ip, param, val, 'SQLi') | ||
# CRLF | ||
if '%0d' in val.lower() or '%0a' in val.lower(): | ||
send_ref(ip, param, val, 'CRLF') | ||
# OPEN Redirect | ||
if len([i for i in ['url', 'redirect', 'next'] if i in param.lower()]) > 0 \ | ||
and not_same_domain(val): | ||
send_ref(ip, param, val, 'Open Redirect') | ||
# Path Traversal | ||
for pload in TRAVERS: | ||
if pload in val: | ||
send_ref(ip, param, val, 'Path Traversal') | ||
break | ||
|
||
return params | ||
|
||
|
||
class ViralUrls(RequestHandler): | ||
def initialize(self): | ||
pass | ||
|
||
async def post(self): | ||
params = json.loads(self.request.body) | ||
malicious = [] | ||
for url in params: | ||
post("https://www.virustotal.com/vtapi/v2/url/scan", data={'apikey': VIRUSTOTAL, 'url': url}) | ||
res = post("https://www.virustotal.com/vtapi/v2/url/report", data={'apikey': VIRUSTOTAL, 'resource': url}) | ||
for i in res.json()['scans'].values(): | ||
if i['detected']: | ||
malicious.append(url) | ||
break | ||
|
||
return self.write(malicious) | ||
|
||
|
||
class CSRF(RequestHandler): | ||
|
||
def initialize(self,handlers): | ||
self.report = handlers["report"] | ||
|
||
async def post(self): | ||
params = json.loads(self.request.body) | ||
self.report(params) | ||
pass | ||
# TODO: send websocket req like: | ||
# The form params['formName'] at params['location'] can be CSRF vulnerable! | ||
|
||
|
||
|
||
class IntrusionDetection(RequestHandler): | ||
|
||
|
||
def initialize(self): | ||
pass | ||
|
||
async def get(self): | ||
params = json.loads(self.request.body) | ||
# TODO | ||
#Get endpoint from params | ||
#increment visit times | ||
#check query params for fuzzy search or intrusion | ||
#send alert in case found | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from ids_service import * | ||
|
||
|
||
if __name__ == '__main__': | ||
service = IDSService() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import asyncio | ||
from api_endpoints import * | ||
from tornado.ioloop import IOLoop | ||
from tornado.platform.asyncio import AsyncIOMainLoop | ||
from tornado.web import Application | ||
from tornado.httpclient import AsyncHTTPClient | ||
from SangomaUtils.sangoma_authenticators import * | ||
import json | ||
from time import time | ||
from urllib.parse import urlparse | ||
import firebase_admin | ||
from firebase_admin import credentials | ||
from firebase_admin import db | ||
from requests import post | ||
from SangomaUtils.sangoma_authenticators import * | ||
import asyncio | ||
|
||
WEBSOCKETS_PORT = 6666 | ||
TORNADO_PORT = 5555 | ||
TORNADO_DEBUG = True | ||
|
||
G = {} # Global Dictionary | ||
|
||
class IDSService: | ||
def __init__(self): | ||
global G | ||
import SangomaUtils.sangoma_authenticators | ||
SangomaUtils.sangoma_authenticators.setG(G) | ||
self.start_websocket_server(WEBSOCKETS_PORT) | ||
self.application = self.start_tornado() | ||
|
||
|
||
def start_websocket_server(self,port): | ||
global G | ||
import SangomaUtils.sangoma_authenticators | ||
SangomaUtils.sangoma_authenticators.setG(G) | ||
"""accepts connections from incoming lambda function requests""" | ||
services_authenticator = MonitoringServiceAuthenticator() | ||
services_message_manager = MessageManagerWebsocketFromServices() | ||
G['lambda_connection_handler'] = ConnectionHandler(authenticator=services_authenticator, | ||
message_manager=services_message_manager) | ||
G['lambda_connection_handler'].accept_connections(port=port) | ||
|
||
|
||
def start_tornado(self): | ||
""" | ||
Starts a Tornado server with specific endpoints specified in the dictionary endpoints. | ||
Each endpoint should have a respective Handler Class implemented in tge tornado_endpoints module. | ||
To initialize the members of the Handler Classes you pass a dictionary after the Class Argument. | ||
:return: Tornado application that was created | ||
""" | ||
|
||
|
||
urls = [ | ||
("/api/query", AnalyzeQuery), | ||
("/api/csrf" , CSRF, dict( | ||
handlers={"report": MessageManagerWebsocketFromServices.report_to_connections})), | ||
('/api/viralurls', ViralUrls) | ||
] | ||
|
||
print("Started Tornado") | ||
AsyncIOMainLoop().install() # Allows to use Asyncio main event loop ; https://www.tornadoweb.org/en/branch4.5/asyncio.html | ||
app = Application(urls, debug=TORNADO_DEBUG) | ||
app.listen(TORNADO_PORT) | ||
IOLoop.current().start() | ||
return app | ||
|
||
|
||
class MessageManagerWebsocketFromServices: | ||
|
||
async def process_message(self, connection_and_msg): | ||
'''look at the incoming event (message/command), determine its priority and add it to the eventQ saved | ||
in the global obejct G.''' | ||
|
||
@staticmethod | ||
def report_to_connections(event): | ||
global G | ||
print(G['lambda_connection_handler'].connections) | ||
for connection in G['lambda_connection_handler'].connections: | ||
asyncio.ensure_future(G['lambda_connection_handler'].connections[connection].send(event)) |