पाठ 12 / 28

Command Injection और Path Traversal

मॉडल आउटपुट कभी shell से न दें, और file पहुँच सीमित करें।

Shell = हमलावर के पाठ का व्याख्याकार

यदि tool मॉडल आउटपुट जोड़कर shell command बनाता है ("cat " + filename shell से चलाया), तो ;, &&, | और backticks जैसे अक्षर हमलावर को अतिरिक्त commands जोड़ने देते हैं। बचाव: shell उपयोग न करें; programs को argument list से बुलाएँ ताकि हर मान एक ही argument रहे; कौन-सी commands और मान स्वीकार्य हैं उनकी allow-list रखें; credentials रहित sandbox में चलाएँ। Files के लिए असली path निकालें (.. और symlinks अनुसरित करके) और जाँचें कि वह अनुमत base folder के भीतर रहता है; absolute paths अस्वीकार करें। उदाहरण shell=True call में injected echo चलता दिखाते हैं, सुरक्षित allow-list जाँच, और path guard जो ../ और absolute paths रोकता है जबकि हानिरहित sub/../notes.txt की अनुमति देता है।

shell=True बनाम argument list, चलाकर

मैंने यह सादे Python 3 (सिर्फ़ standard library) से चलाया। यहाँ सारे हमले स्थानीय डेटा पर हानिरहित प्रदर्शन हैं, कोई असली system उपयोग नहीं हुआ। shell=True के साथ, semicolon के बाद का पाठ दूसरी command के रूप में चलता है और INJECTED छापता है। सुरक्षित रूप माँगे नाम को allow-list से जाँचता है और argument list के साथ echo चलाता है, इसलिए पूरी string अस्वीकृत होती है (या अनुमत नाम के लिए एक सादा argument माना जाता है)। यहाँ command हानिरहित echo है।

import subprocess

model_output = "report.txt; echo INJECTED"
unsafe = subprocess.run("echo reading " + model_output, shell=True, capture_output=True, text=True)
print("UNSAFE (shell=True):", unsafe.stdout.strip().replace("\n", " | "))

ALLOWED = {"report.txt", "summary.txt"}
def safe_read(name):
    if name not in ALLOWED: return f"refused: {name!r} is not an allowed file"
    return subprocess.run(["echo", "reading", name], capture_output=True, text=True).stdout.strip()   # no shell, argument list
print("SAFE   :", safe_read(model_output))
print("SAFE ok:", safe_read("report.txt"))

Output:

UNSAFE (shell=True): reading report.txt | INJECTED
SAFE   : refused: 'report.txt; echo INJECTED' is not an allowed file
SAFE ok: reading report.txt

File paths सीमित करना, चलाकर

मैंने यह सादे Python 3 (सिर्फ़ standard library) से चलाया। यहाँ सारे हमले स्थानीय डेटा पर हानिरहित प्रदर्शन हैं, कोई असली system उपयोग नहीं हुआ। Guard हर path resolve करके जाँचता है कि वह अनुमत folder के भीतर रहता है। notes.txt और sub/../notes.txt उसी अनुमत file पर resolve होते हैं, जबकि ../secret.txt और /etc/passwd रुकते हैं।

import os, tempfile

def safe_open(base, user_path):
    full = os.path.realpath(os.path.join(base, user_path))
    if os.path.commonpath([os.path.realpath(base), full]) != os.path.realpath(base):
        return "blocked: path escapes the allowed folder"
    return "ok: " + os.path.relpath(full, os.path.realpath(base))

with tempfile.TemporaryDirectory() as base:
    open(os.path.join(base, "notes.txt"), "w").write("hello")
    for p in ("notes.txt", "../secret.txt", "sub/../notes.txt", "/etc/passwd"):
        print(f"{p:20} -> {safe_open(base, p)}")

Output:

notes.txt            -> ok: notes.txt
../secret.txt        -> blocked: path escapes the allowed folder
sub/../notes.txt     -> ok: notes.txt
/etc/passwd          -> blocked: path escapes the allowed folder

Subprocesses की जगह library calls पसंद करें

यदि Python function काम कर सके, तो उसे बुलाना shells और argument parsing से पूरी तरह बचाता है।

त्वरित जाँच: Argument list से program बुलाना shell=True से सुरक्षित क्यों है?

  • यह GPUs पर तेज़ चलता है
  • हर मान एक ही argument रहता है और shell syntax के रूप में कभी व्याख्यायित नहीं होता
  • यह आउटपुट छिपाता है
  • Shells अवैध हैं
Answer

हर मान एक ही argument रहता है और shell syntax के रूप में कभी व्याख्यायित नहीं होता — Shell के बिना ; और && जैसे अक्षरों का कोई विशेष अर्थ नहीं।