Skip to content

Instantly share code, notes, and snippets.

@lietu
Created March 29, 2024 23:50
Show Gist options
  • Save lietu/9f01eb7cb47a893341883c03b24682f6 to your computer and use it in GitHub Desktop.
Save lietu/9f01eb7cb47a893341883c03b24682f6 to your computer and use it in GitHub Desktop.
Scan system for libraries and binaries potentially affected by any unknown liblzma vulnerabilities. Tested on Python 3.11
import asyncio
import os
import shutil
import subprocess
from pathlib import Path
# Base configuration
LIB_DIRS = ["/lib", "/lib32", "/usr/lib", "/usr/lib32"]
BIN_DIRS = [
"/bin",
"/sbin",
"/usr/bin",
"/usr/sbin",
"/usr/local/bin",
"/usr/local/sbin",
]
COMPROMISED_LIBS = {"/usr/lib/liblzma.so.5", "/usr/lib32/liblzma.so.5"}
# ---- SCRIPT LOGIC ---- #
def resolve(path_str) -> str:
return str(Path(path_str).resolve().absolute())
LDD = shutil.which("ldd")
_COMPROMISED_LIBS = {resolve(path) for path in COMPROMISED_LIBS}
# Resolve all libraries to scan
ALL_SYSTEM_LIBS = set()
for lib_dir in LIB_DIRS:
lib_path = Path(lib_dir)
for found_lib in lib_path.glob("**/*.so*"):
ALL_SYSTEM_LIBS.add(resolve(found_lib.absolute()))
# Resolve all binaries to scan
ALL_BINS = set()
for bin_dir in BIN_DIRS:
bin_path = Path(bin_dir)
for found_bin in bin_path.glob("**/*"):
ALL_BINS.add(resolve(found_bin))
# Counters
AFFECTED_BINARIES = 0
SAFE_BINARIES = 0
# Shell colors
CYAN = "\033[96m"
GREEN = "\033[92m"
YELLOW = "\033[93m"
RED = "\033[91m"
ENDC = "\033[0m"
async def uses_compromised_lib(full_path_to_check: str) -> bool:
proc = subprocess.run(
[LDD, full_path_to_check],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
for line in proc.stdout.decode().splitlines():
if line.strip() == "not a dynamic executable":
return False
# Each line looks like one of these:
# linux-vdso.so.1 (0x0000000000123abc)
# liblzma.so.5 => /usr/lib/liblzma.so.5 (0x0000000000123abc)
# /lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x0000000000123abc)
parts = line.split("=>")
if len(parts) > 1:
resolved = resolve(parts[1].strip().split(" ")[0])
if resolved in _COMPROMISED_LIBS:
return True
return False
async def find_compromised_lib_usage():
"""
Recursively search for libraries that may be affected
"""
print("Searching for other libraries using compromised libraries known of so far...")
found_more = False
for lib_to_check in ALL_SYSTEM_LIBS:
if lib_to_check not in _COMPROMISED_LIBS:
if await uses_compromised_lib(lib_to_check):
_COMPROMISED_LIBS.add(lib_to_check)
found_more = True
print(f"{YELLOW}{lib_to_check}{ENDC} is potentially compromised")
if found_more:
await find_compromised_lib_usage()
async def find_compromised_libs():
print("Scanning for libraries")
await find_compromised_lib_usage()
print("")
async def find_compromised_bins():
global AFFECTED_BINARIES, SAFE_BINARIES
print("Scanning for binaries")
for bin_to_check in sorted(ALL_BINS):
path_to_check = Path(bin_to_check)
if path_to_check.is_file() and os.access(bin_to_check, os.X_OK):
if await uses_compromised_lib(bin_to_check):
print(f"{RED}{bin_to_check}{ENDC} is potentially compromised")
AFFECTED_BINARIES += 1
else:
SAFE_BINARIES += 1
print("")
async def main():
await find_compromised_libs()
await find_compromised_bins()
print(
f"Found {RED}{len(_COMPROMISED_LIBS):,}{ENDC} potentially compromised libraries "
f"of {CYAN}{len(ALL_SYSTEM_LIBS):,}{ENDC} total"
)
print(
f"Found {RED}{AFFECTED_BINARIES:,}{ENDC} potentially affected binaries "
f"of {CYAN}{len(ALL_BINS):,}{ENDC} total"
)
print(f"Probably safe binaries: {GREEN}{SAFE_BINARIES:,}{ENDC}")
if __name__ == "__main__":
asyncio.run(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment