Skip to content

Commit 13b5bce

Browse files
author
foreverneilyoung
committed
Working
1 parent 2cf6055 commit 13b5bce

File tree

1 file changed

+126
-0
lines changed

1 file changed

+126
-0
lines changed

fritzcap.py

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
#!/usr/bin/python
2+
# -*- coding: iso-8859-1 -*-
3+
#################################################################################
4+
# Simple FritzCap python port
5+
# Simplifies generation and examination of traces taken from AVM FritzBox and/or SpeedPort
6+
# Traces can be examined using WireShark
7+
# (c) neil.young 2010 (spongebob.squarepants in http://www.ip-phone-forum.de/)
8+
# based on the Windows GUI exe with same name
9+
##################################################################################
10+
11+
import urllib, re, timeit, hashlib, sys, datetime, os
12+
13+
sys.path.append('core')
14+
15+
from tracer import Tracer
16+
from pcap_parse import PcapParser
17+
from g711_decoder import G711Decoder
18+
19+
# Configuration (just change here) ###############################################
20+
boxname = 'speedport.ip' # or ip (also fritz.box)
21+
password = 'yourpassword' # your password, adapt
22+
protocol = 'https' # or http
23+
capfolder = 'captures' # plus subfolders according to day, month, year, hour, minute
24+
capfile = 'capture.cap' # name of capture file
25+
login_required = True # set to 0 if no login is required
26+
##################################################################################
27+
28+
# Commands
29+
default_login = 'getpage=../html/de/menus/menu2.html&errorpage=../html/index.html&var:lang=de&var:pagename=home&var:menu=home&=&login:command/password=%s'
30+
sid_challenge = 'getpage=../html/login_sid.xml'
31+
sid_login = 'login:command/response=%s&getpage=../html/login_sid.xml'
32+
start = '?start=1&start1=Start'
33+
stop = '?stop=1&stop1=Stop'
34+
35+
36+
# Main work horse G.711 extraction/mix
37+
def runparser():
38+
g711 = G711Decoder(capfile, mix=1, linearize=1)
39+
PcapParser(capfile, g711.decode).parse()
40+
g711.finalize()
41+
42+
# Main
43+
def main():
44+
45+
global capfile
46+
47+
capture = True # Audio debug shortcut
48+
extract_audio = True # Extract audio if available
49+
50+
SID = '' # Required later
51+
52+
if capture:
53+
54+
# Attempt to login
55+
if login_required:
56+
57+
try:
58+
# Try to get a session id SID
59+
sid = urllib.urlopen(protocol + '://' + boxname + '/cgi-bin/webcm?' + sid_challenge)
60+
if sid.getcode() == 200:
61+
# Read and parse the response in order to get the challenge (not a full blown xml parser)
62+
challenge = re.search('<Challenge>(.*?)</Challenge>', sid.read()).group(1)
63+
64+
# Create a UTF-16LE string from challenge + '-' + password, non ISO-8859-1 characters will except here (e.g. EUR)
65+
challenge_bf = (challenge + '-' + password).decode('iso-8859-1').encode('utf-16le')
66+
67+
# Calculate the MD5 hash
68+
m = hashlib.md5()
69+
m.update(challenge_bf)
70+
71+
# Make a byte response string from challenge + '-' + md5_hex_value
72+
response_bf = challenge + '-' + m.hexdigest().lower()
73+
74+
# Answer the challenge
75+
login = urllib.urlopen(protocol + '://' + boxname + '/cgi-bin/webcm', sid_login % response_bf)
76+
77+
if login.getcode() == 200:
78+
SID = re.search('<SID>(.*?)</SID>', login.read()).group(1)
79+
print "Login OK, SID %s" % SID
80+
else:
81+
print "Could not login"
82+
return
83+
except:
84+
# Legacy login
85+
command = urllib.urlopen(protocol + '://' + boxname + '/cgi-bin/webcm', default_login % password)
86+
response = command.read()
87+
# Right now I don't know how to check the result of a login operation. So I just search for the errorMessage
88+
if command.getcode() == 200:
89+
try:
90+
result = urllib.unquote(re.search('<p class="errorMessage">(.*?)</p>', response).group(1).decode('iso-8859-1')).replace("&nbsp;"," ")
91+
except:
92+
result = ''
93+
print 'Login attempt was made. %s' % result
94+
95+
96+
# Create capfile folder
97+
folder = capfolder + '/' + (datetime.datetime.now().strftime('%d%m%Y%H%M'))
98+
capfile = folder + '/' + capfile
99+
if not os.path.exists(folder):
100+
os.makedirs(folder)
101+
102+
# Start tracer thread, wait for console input to stop
103+
if SID != '':
104+
Tracer(protocol + '://' + boxname + '/cgi-bin/capture_notimeout' + start + "&sid=%s" % SID, capfile).start()
105+
else:
106+
Tracer(protocol + '://' + boxname + '/cgi-bin/capture_notimeout' + start, capfile).start()
107+
108+
print 'Trace started, abandon with <ENTER>'
109+
raw_input()
110+
# Clean stop
111+
print 'Stopping trace'
112+
if SID != '':
113+
urllib.urlopen(protocol + '://' + boxname + '/cgi-bin/capture_notimeout' + stop + "&sid=%s" % SID)
114+
else:
115+
urllib.urlopen(protocol + '://' + boxname + '/cgi-bin/capture_notimeout' + stop)
116+
print 'Capture done'
117+
118+
# Parse the captured file
119+
if extract_audio:
120+
print 'Extracting audio...'
121+
print timeit.Timer('runparser()', 'from __main__ import runparser').timeit(number=1), "seconds"
122+
# runparser()
123+
print 'All done'
124+
125+
if __name__ == '__main__':
126+
main()

0 commit comments

Comments
 (0)