Posts Tagged ‘Script’

Dienstag, 13. Dezember 2016

mitmproxy: Server-Antworten umschreiben (oder: M6 Geoblocker umgehen)

Heute durfte ich für einen Kollegen in den USA eine im Internet als Stream verfügbare M6 News-Sendung rippen.

Geoblocker

Damit ich an die m3u8-Datei des Streams herankam, musste ich aber zuerst die Geo-Sperre umgehen. Die Web-Site frägt nämlich beim Aufruf (gleich zweimal) ab, in welchem Land sich der Surfer befindet. Hierzu ruft der JavaScript-Code der Web-Site folgende zwei URLs auf:

Als Antwort erhält der Browser folgenden JSON-Code zurück (IP anonymisiert):

{"offset":"2","isp":"Andreas Fink","areas":[10],"country_code":"CH","asn":"AS6775","ip":"85.195.0.0"}

Diese Antwort bewegt den Player dazu, folgende Fehlermeldung anzuzeigen:

M6 6play Geoblock

mitmproxy installieren und konfigurieren

Der erste Task war somit klar: Ich musste mit dem quelloffenen Tool mitmproxy alle HTTP(S)-Requests meines iPads proxyifizieren und dann obige JSON-Antwort mit einer validen Antwort ersetzen, so wie sie über einen französischen ISP erfolgen würde.

mitmproxy hatte ich bereits auf meinem lokalen Linux-Server konfiguriert, weshalb ich auf dem iPad in den Netzwerkeinstellungen den Proxy nur noch erfassen musste: 10.0.X.Y:8888.

Auf dem Linux-Server startete ich mitmproxy folgendermassen:

# mitmproxy -p 8888

Als nächstes musste ich noch das mitmproxy-Zertifikat auf dem iPad installieren, damit HTTPS-Verbindungen entschlüsselt und umgeschrieben werden können. Hierzu reicht es, auf dem iPad die folgende URL aufzurufen …

mitm.it

… und den Anweisungen zu folgen (ACHTUNG: Sicherheitssensitive Personen löschen das Zertifikat nach der Verwendung wieder vom iPad. Es findet sich unter Settings > General > Profiles).

Inline-Script zum Umschreiben von Antworten

Damit ich vom Proxy-Server empfangene Antworten der M6-Server umschreiben konnte, musste ich nun noch ein mitmproxy Inline-Script einbauen, welches Aufrufe auf die oben genannten URLs abfängt und nach meinem Gusto umschreibt.

Hierzu legte ich unter /tmp/m6-geoip.py folgendes Python-Script ab:

import json

def response(context, flow):
	f = open('/tmp/mitm.log','a+')
	url = flow.request.get_url()
	f.write('URL "' + url  + '"' + "\n")

	if url.endswith('geoInfo') or url.endswith('geoInfos'):
		f.write('    matched' + "\n")
		data = json.loads(flow.response.content)
		# {"offset":"2","isp":"Andreas Fink","areas":[10],"country_code":"CH","asn":"AS6775","ip":"85.195.0.0"}
		# {"offset":"2","isp":"QSC AG","areas":[1,2,3,10,11],"country_code":"FR","asn":"AS20676","ip":"92.222.83.58"} via http://www.franceproxy.net
		#data["country_code"] = "FR"
		#jsonOut = json.dumps(data)
		jsonOut = '{"offset":"2","isp":"QSC AG","areas":[1,2,3,10,11],"country_code":"FR","asn":"AS20676","ip":"92.222.83.58"}'
		flow.response.content = jsonOut
		f.write("    " + jsonOut + "\n")
	f.close()

Tipp 1: Da selten Leute vom Himmel gefallen sind, welche ein Script auf Anhieb richtig hingekriegt haben, hilft es zum Debugging, statt mitmproxy mitmdump zu verwenden:

# mitmdump -e -p 8888 -s "/tmp/m6-geoip.py"

Bei Python-Problemen mit dem Inline-Script wird der Stack Trace und die Fehlermeldung direkt auf der Kommandozeile ausgegeben.

Tipp 2: Die Ausgabe aller URLs in eine Log-Datei resultiert in Performance-Einbussen, kann für das Debugging aber sehr nützlich sein.

Anschliessend startete ich den mitmproxy neu:

# mitmproxy -p 8888 -s "/tmp/m6-geoip.py"

JSON-Quelle

Doch von wo hatte ich den JSON-String?

Nach etwas Googeln fand ich folgenden Proxy-Service:

www.franceproxy.net

Gibt man dort eine der obigen URLs ein, erhält man als Antwort den JSON-Code, welchen ich dann auch für die Umgehung des Geoblockers verwendete.

Kostenloser Tipp an die Web-Entwickler von M6: Die Geo-Location eines Aufrufs prüft man nicht im JavaScript auf dem Client, sondern auf dem Server.

Der erneute Versuch im Web-Browser

Ich lud die Web-Seite auf dem iPad erneut — erhielt zwar eine Fehlermeldung, dass trotzdem irgendetwas schief gelaufen war, doch im mitmproxy-Log fand sich die sehnlichst gesuchte URL zur m3u8-Datei:

lb.cdn.m6web.fr

Daraus — und mit Informationen der aktuellsten Sendung, welche sich auch für Schweizer streamen lässt — leitete ich die tatsächliche URL zur Master-Playlist ab:

e112.cdn.m6web.fr

Von dieser Datei war es dann nur noch ein Katzensprung zur m3u8-Datei mit dem Stream mit der höchsten Bit-Rate:

e112.cdn.m6web.fr

Und so lud ich den Stream dann mit ffmpeg herunter:

$ ffmpeg -protocol_whitelist file,http,https,tcp,tls -i "http://e112.cdn.m6web.fr/usp/mb_sd3/2/8/1/Le-1945_c11636016_19-45-du-dimanche-11/Le-1945_c11636016_19-45-du-dimanche-11_unpnp.ism/Le-1945_c11636016_19-45-du-dimanche-11_unpnp-audio_fra=93468-video_eng=1501000.m3u8" video.mp4

Tags: , , , , , , , , ,
Labels: IT

Keine Kommentare | neuen Kommentar verfassen

Dienstag, 16. Dezember 2014

YCombinator Hacker News Evergreen-Artikel automatisiert zu Instapaper senden

Im November 2014 publizierte Ben Autrey auf Contextly eine Liste der am höchsten bewerteten Hacker News-Artikel aller Zeiten.

Da er in seinem Blog-Post nicht direkt auf die eigentlichen Artikel, sondern nur auf die Hacker News-Kommentarseite verwies, investierte ich gestern einige Zeit, um die eigentlichen Artikel automatisiert meinem Instapaper-Konto hinzuzufügen.

Das Ergebnis inklusive einer Textdatei mit allen Links auf die eigentlichen Artikel (urls-articles.txt) finden interessierte Zeitgenossen in meinem Github-Repository.

Tags: , , , , , , , ,
Labels: Programmierung

Keine Kommentare | neuen Kommentar verfassen

Sonntag, 26. Januar 2014

Shell-Script-Befehl auf STDOUT ausgeben und danach ausführen

Viele meiner Scripts sind mit hoher Verbosität programmiert, damit ich während der Entwicklung weiss, wo allfällig die Ausführung abbricht. Hierzu gehört auch, dass ich komplexe Befehle vor der Ausführung ausgebe. Damit kann ich den Befehl kopieren und beim Debugging manuell auf der Kommandozeile ausführen, um vielleicht weitere Hinweise auf das Problem zu erhalten.

Doch wie macht man das, wenn man bspw. bei rsync Pfadangaben mit Leerschlägen drin hat, die vom Tool dann auch effektiv erkannt und verarbeitet werden sollen? Hier die Lösung:

...
$SOURCE="/Users/mario/Pictures/iPhoto Library/"
$DEST="/Volume/Sicherungs Ordner mit vielen Leerzeichen/"
...
COMMAND="rsync $OPTS \"$SOURCE\" \"$DEST\""
...
echo "Executing '$COMMAND' ..."
...
eval $COMMAND
...

Die ganze Chose steht und fällt mit eval. Wird nur $COMMAND ausgeführt, stolpert rsync über die ordentlich mit Anführungszeichen versehenen Pfade mit Leerzeichen.

Tags: , , , , ,
Labels: Linux

Keine Kommentare | neuen Kommentar verfassen

Sonntag, 26. Januar 2014

Shell-Scripte mit vielen Optionen

Komplexe Shell-Scripte, welche ein Unix-Tool mit unzähligen Optionen aufrufen, muss man ab und zu debuggen. Damit dies möglichst einfach funktioniert, habe ich mir angewöhnt, die Optionen so zu notieren, damit ich jede einzelne Option mit einem Tastendruck auskommentieren kann:

...
OPTS=""
OPTS="$OPTS --verbose"
OPTS="$OPTS --archive"
OPTS="$OPTS --no-owner"
OPTS="$OPTS --no-group"
#OPTS="$OPTS --delete" # WILL DESTROY EVERYTHING! DO NOT UNCOMMENT
OPTS="$OPTS --progress"
...
rsync $OPTS "$SOURCE" "$DESTINATION"
...

Tags: , , ,
Labels: Linux

Keine Kommentare | neuen Kommentar verfassen

Samstag, 24. November 2012

Text in PDFs greppen

Da haben also die SBB einen Wettbewerb online, welcher die Eingabe von Ticketnummern erfordert. Und gleichzeitig habe ich Quittungen von über SBB Mobile georderte Tickets für Geschäftsreisen auf meinem Computer abgelegt.

Was macht man da? Richtig, man filtert die PDFs nach den geforderten Ticket-Nummern, und zwar so:

pdftotext

Ich gehe davon aus, dass jeder Terminal.app-Hacker macports installiert hat

Man benötigt zuerst einmal das in xpdf enthaltene Tool pdftotext:

# port install xpdf-tools

Shell-Magic

Nachdem das Tool installiert ist, navigiert man in den Ordner, welcher die PDFs enthält und gibt folgenden Befehl ein:

$ for i in *.pdf; do pdftotext "$i"; done;

Die in PDFs enthaltenen Textzeichen werden extrahiert und automatisch in eine Textdatei mit Endung .txt gespeichert, welche denselben Basename trägt wie die PDF-Datei.

Nun kann ich problemlos greppen:

$ cat *.txt | grep "OT"

… und schon erhalte ich eine schöne Liste in der Form

OT 0000 0000 0000
OT 0000 0000 0000
OT 0000 0000 0000
OT 0000 0000 0000
OT 0000 0000 0000
OT 0000 0000 0000
OT 0000 0000 0000
OT 0000 0000 0000
OT 0000 0000 0000
OT 0000 0000 0000
OT 0000 0000 0000

Tags: , , , , , , ,
Labels: IT

1 Kommentar | neuen Kommentar verfassen