پرش به محتوای اصلی
آسیب‌پذیری‌های سایت

Command Injection چیست؟ بررسی تزریق دستورات سیستم‌عامل و روش‌های جلوگیری

Command Injection یا OS Command Injection زمانی رخ می‌دهد که ورودی غیرقابل اعتماد وارد فرمان سیستم‌عامل شود و بتواند ساختار یا رفتار آن را تغییر دهد. این ضعف با CWE-78 شناخته می‌شود و بسته به سطح دسترسی Application می‌تواند محرمانگی، یکپارچگی و دسترس‌پذیری Server را تحت تأثیر قرار دهد. بهترین راه جلوگیری از Command Injection حذف استفاده غیرضروری از Shell، استفاده از APIهای داخلی زبان، جداسازی Executable و Argumentها، Allowlist ورودی و اجرای Process با Least Privilege است.

تیم امنیت رخنه‌کاو ۴۵ دقیقه مطالعه انتشار:

Command Injection یا OS Command Injection نوعی آسیب‌پذیری امنیتی است که زمانی رخ می‌دهد که یک برنامه، داده‌ای غیرقابل اعتماد را وارد فرمان سیستم‌عامل کند و بدون جداسازی مناسب میان «داده» و «دستور»، آن را برای اجرا به Shell یا سیستم‌عامل بفرستد. در چنین شرایطی ورودی کاربر ممکن است به‌جای اینکه صرفاً یک پارامتر عادی باشد، معنی کنترلی پیدا کند و رفتار فرمان اصلی را تغییر دهد.

در یک وب‌سایت آسیب‌پذیر، پیامد این ضعف می‌تواند بسیار جدی باشد؛ زیرا فرمان با سطح دسترسی همان Process یا Service Account اجرا می‌شود. بنابراین بسته به Permission برنامه، مهاجم ممکن است بتواند فایل‌ها را بخواند یا تغییر دهد، به سرویس‌های داخلی دسترسی پیدا کند، عملیات غیرمجاز انجام دهد یا در موارد شدید کنترل گسترده‌تری روی Server به دست آورد.

OWASP راهکار اصلی جلوگیری از OS Command Injection را بسیار روشن بیان می‌کند: تا حد امکان اصلاً فرمان سیستم‌عامل را از داخل برنامه اجرا نکنید و به‌جای آن از APIها و Libraryهای داخلی زبان استفاده کنید. برای مثال اگر زبان برنامه‌نویسی Function مشخصی برای ساخت Directory، پردازش فایل یا انجام Network Operation دارد، استفاده از آن بسیار امن‌تر از ساختن یک Command String و ارسال آن به Shell است.

از دید CWE، این ضعف با شناسه CWE-78 و عنوان Improper Neutralization of Special Elements used in an OS Command شناخته می‌شود. MITRE توضیح می‌دهد این آسیب‌پذیری در برنامه‌هایی اهمیت ویژه دارد که مهاجم دسترسی مستقیم به سیستم‌عامل ندارد اما می‌تواند از طریق Application روی فرمان‌هایی که سیستم اجرا می‌کند اثر بگذارد.

در این مقاله رخنه‌کاو بررسی می‌کنیم Command Injection چیست، چگونه ایجاد می‌شود، چه تفاوتی با Code Injection و SQL Injection دارد، چرا استفاده نادرست از system، exec، shell_exec و APIهای مشابه خطرناک است، چه معماری‌هایی بیشتر در معرض خطر هستند و چگونه می‌توان با حذف Shell، جداسازی Argumentها، Allowlist، Least Privilege، Container Hardening و Security Testing جلوی آن را گرفت.

Command Injection چیست؟

Command Injection زمانی رخ می‌دهد که Application یک فرمان سیستم‌عامل را با استفاده از Input خارجی ایجاد کند و مهاجم بتواند Structure یا رفتار همان فرمان را تغییر دهد.

مثلاً فرض کنید یک Application برای بررسی وضعیت یک Host از یک ابزار سیستم‌عامل استفاده می‌کند.

برنامه انتظار دارد User فقط مقدار ساده‌ای مانند نام Host یا IP Address وارد کند.

اگر Developer چنین Inputی را مستقیماً به String فرمان اضافه کند، دیگر Browser و Application تنها تعیین‌کننده رفتار نیستند؛ Shell نیز Input را Parse می‌کند.

از دید Application ممکن است Input فقط یک String باشد.

اما از دید Shell، همان String می‌تواند شامل Syntax و Characterهایی با معنی ویژه باشد.

ریشه اصلی Command Injection همین اختلاف معناست:

Application فکر می‌کند ورودی «داده» است.

Shell ممکن است بخشی از آن را «دستور» تفسیر کند.

OWASP Command Injection را حمله‌ای معرفی می‌کند که هدف آن اجرای فرمان‌های دلخواه سیستم‌عامل از طریق Application آسیب‌پذیر است.

چرا Command Injection بسیار خطرناک است؟

شدت Command Injection به سطح دسترسی Process بستگی دارد.

اگر Web Application با یک User محدود اجرا شود، مهاجم نیز معمولاً در همان محدوده محدود خواهد بود.

اما اگر Application یا Worker با Privilege بالا اجرا شود، Impact می‌تواند بسیار بیشتر باشد.

یک Command Injection بالقوه می‌تواند سه اصل اصلی امنیت را تحت تأثیر قرار دهد.

محرمانگی یا Confidentiality

اگر Process اجازه خواندن Fileهای حساس را داشته باشد، داده‌هایی مانند Configuration، Secret یا اطلاعات Application ممکن است در معرض خطر قرار گیرند.

یکپارچگی یا Integrity

فرمان سیستم‌عامل می‌تواند باعث تغییر File، Configuration، Data یا Environment شود.

دسترس‌پذیری یا Availability

فرمان‌های سیستم‌عامل می‌توانند CPU، Memory، Disk، Process یا Serviceها را تحت تأثیر قرار دهند و در مواردی باعث اختلال سرویس شوند.

به همین دلیل Command Injection معمولاً یک Vulnerability با Impact بالا محسوب می‌شود.

جایگاه Command Injection در OWASP Top 10

در OWASP Top 10:2025 دسته Injection با شناسه A05 معرفی شده است و CWE-78 مربوط به OS Command Injection در این خانواده قرار می‌گیرد. OWASP برای Injection توصیه می‌کند در صورت امکان داده از Command یا Query کاملاً جدا شود و اگر این جداسازی ممکن نیست، Positive Server-side Input Validation اعمال شود.

این موضوع اهمیت یک اصل بنیادی را نشان می‌دهد:

امنیت Injection با «تشخیص Input بد» شروع نمی‌شود.

با جلوگیری از ترکیب Data و Command شروع می‌شود.

اگر Architecture از ابتدا اجازه ندهد Input User وارد Syntax یک Command شود، بخش بزرگی از Attack Surface حذف می‌شود.

CWE-78 چیست؟

CWE-78 مشخصاً به Improper Neutralization of Special Elements used in an OS Command اشاره دارد.

یعنی Application قصد دارد Command سیستم‌عامل بسازد و اجرا کند، اما ورودی غیرقابل اعتماد به‌درستی Neutralize یا از Syntax فرمان جدا نشده است.

MITRE هشدار می‌دهد این ضعف می‌تواند در Web Applicationهایی رخ دهد که User دسترسی مستقیم به سیستم‌عامل ندارد اما Input او به Command منتقل می‌شود. اگر Application با Privilege بالا اجرا شود، مهاجم ممکن است فرمان‌هایی را با سطح دسترسی‌ای اجرا کند که خودش مستقیماً در اختیار نداشته است.

در فهرست CWE Top 25 سال ۲۰۲۵ نیز CWE-78 در میان ضعف‌های مهم نرم‌افزاری قرار گرفته است که نشان می‌دهد این مشکل هنوز صرفاً یک Vulnerability تاریخی نیست و در Software مدرن نیز اهمیت دارد. Command Injection چگونه ایجاد می‌شود؟

Command Injection چگونه ایجاد می‌شود؟

معمولاً زنجیره آسیب‌پذیری از چند مرحله ساده تشکیل می‌شود.

Application یک Input دریافت می‌کند.

این Input ممکن است از:

فرم وب،

URL Parameter،

HTTP Header،

API Body،

نام File،

Database Record،

Message Queue،

یا حتی Data دریافت‌شده از API دیگر

بیاید.

Developer سپس Input را به یک Command String اضافه می‌کند.

Application Command نهایی را به یک Shell یا API اجرای Process می‌دهد.

Shell آن را Parse می‌کند.

اگر User بتواند Syntax فرمان را تحت تأثیر قرار دهد، Command Injection ممکن می‌شود.

مهم‌ترین نکته این است که «منبع Input» فقط User مستقیم نیست.

حتی اطلاعات ذخیره‌شده در Database نیز می‌توانند Untrusted باشند.

برای مثال ممکن است نام File چند ساعت قبل توسط یک User ذخیره شده باشد و بعد یک Background Worker آن را وارد Command کند.

این حالت Stored Command Injection محسوب می‌شود.

Shell چیست و چرا در Command Injection مهم است؟

Shell محیطی است که Commandها را تفسیر و اجرا می‌کند.

نمونه‌های معروف عبارت‌اند از:

Bash

sh

PowerShell

cmd.exe

هر Shell مجموعه‌ای از Syntaxها و Operatorهای خاص خودش دارد.

مشکل زمانی ایجاد می‌شود که Application Stringی را بسازد و آن را برای تفسیر به Shell بدهد.

در این حالت Shell باید تشخیص دهد:

نام Program چیست؟

Argument چیست؟

کدام Character فقط بخشی از Text است؟

کدام Character معنی کنترلی دارد؟

هرچه Application کمتر از Shell استفاده کند، Attack Surface کمتر می‌شود.

تفاوت اجرای مستقیم Process با اجرای Shell

این تفاوت یکی از مهم‌ترین مفاهیم جلوگیری از Command Injection است.

در مدل اول، Application به سیستم می‌گوید:

این Executable را اجرا کن.

این Argumentها را جداگانه به آن بده.

در مدل دوم، Application یک String کامل ایجاد می‌کند و می‌گوید:

این Text را به Shell بده و اجازه بده Shell خودش آن را تفسیر کند.

مدل دوم خطرناک‌تر است.

چرا؟

زیرا Shell علاوه بر اجرای Program، Syntax خاص خودش را نیز تفسیر می‌کند.

اگر بتوان Command را بدون Shell و با Argument Array اجرا کرد، بخش بزرگی از خطر Syntax Injection حذف می‌شود.

چرا String Concatenation خطرناک است؟

یکی از رایج‌ترین Anti-patternها در Command Injection ساختن Command با Concatenation است.

برای مثال Conceptually:

Program + UserInput

در نگاه اول ساده است.

اما Input دیگر فقط یک Parameter نیست.

بخشی از زبان Shell شده است.

مشکل مشابه SQL Injection است؛ در SQL Injection داده User وارد Query Language می‌شود.

در Command Injection داده User وارد Command Language سیستم‌عامل می‌شود.

اصل دفاعی در هر دو یکسان است:

Data را از Code یا Command جدا کنید.

Command Injection با Code Injection چه تفاوتی دارد؟

این دو اصطلاح نزدیک‌اند اما یکسان نیستند.

Command Injection

مهاجم روی Commandی که توسط سیستم‌عامل یا Shell اجرا می‌شود اثر می‌گذارد.

هدف Runtime سیستم‌عامل است.

Code Injection

مهاجم Code مربوط به زبان یا Runtime Application را وارد یا اجرا می‌کند.

مثلاً ممکن است Code Injection در Context PHP، JavaScript، Python یا Template Engine رخ دهد.

CWE-78 مخصوص OS Command Injection است، در حالی که Code Injection معمولاً با CWEهای دیگری مانند CWE-94 بررسی می‌شود.

هر Command Injection نوعی Injection است، اما هر Code Injection لزوماً Command Injection نیست. تفاوت Command Injection و SQL Injection

تفاوت Command Injection و SQL Injection

SQL Injection روی Database Query Language اثر می‌گذارد.

Command Injection روی سیستم‌عامل یا Shell.

در SQL Injection هدف ممکن است:

SELECT

UPDATE

DELETE

یا Query Logic

باشد.

در Command Injection هدف Process و Operating System است.

راهکارهای دفاعی نیز متفاوت‌اند.

برای SQL Injection از Parameterized Query استفاده می‌کنیم.

برای Command Injection، بهترین راه این است که Shell را حذف کنیم و از API داخلی یا Process API با Argumentهای جدا استفاده کنیم.

تفاوت Command Injection و Argument Injection

این تفاوت مهم‌تر از چیزی است که به نظر می‌رسد.

گاهی User نمی‌تواند Command جدیدی ایجاد کند اما می‌تواند Argumentهای Program اصلی را تغییر دهد.

این حالت Argument Injection نامیده می‌شود.

مثلاً Application یک ابزار مشخص را اجرا می‌کند، اما User می‌تواند Optionهایی به همان ابزار بدهد که Developer انتظار آن‌ها را نداشته است.

بنابراین حتی اگر Special Characterهای Shell Escape شوند، هنوز ممکن است ورودی User به‌عنوان Option خطرناک Program تفسیر شود.

این نکته نشان می‌دهد Escaping به‌تنهایی همیشه کافی نیست.

Allowlist و Semantic Validation همچنان لازم هستند.

ورودی‌های رایج خطرناک در Command Injection

هر Dataای که به Command می‌رسد باید Untrusted فرض شود مگر خلاف آن ثابت شده باشد.

مثلاً:

نام Host

نام Domain

IP Address

نام File

Path

Archive Name

Image Name

Video Format

Printer Name

Username

Network Interface

Backup Identifier

Service Name

Container Name

مقادیر Configuration

User-controlled Environment Variable

همگی ممکن است وارد Command شوند.

مشکل از نوع Data نیست.

مشکل از این است که Data چگونه مصرف می‌شود.

سناریوهای رایج Command Injection در وب‌سایت‌ها

ابزارهای شبکه

برنامه‌ای که برای Diagnostic ابزار سیستم‌عامل اجرا می‌کند.

مثلاً بررسی Host یا DNS.

اگر Input مستقیماً به Command منتقل شود، Risk ایجاد می‌شود.

تبدیل تصویر

بعضی Applicationها برای پردازش تصویر Program خارجی اجرا می‌کنند.

اگر File Name یا Optionهای پردازش مستقیم از User گرفته شوند، باید بسیار دقیق بررسی شوند.

تبدیل ویدئو و صوت

برنامه‌های Media معمولاً ابزارهای Native را از Worker اجرا می‌کنند.

Argumentها باید کاملاً جدا و Allowlisted باشند.

Backup و Restore

Application ممکن است برای Archive کردن Directory یا Database از Utilityهای سیستم استفاده کند.

Path و File Name در اینجا حساس هستند.

PDF Generation

بعضی سیستم‌ها ابزارهای Command-line برای تبدیل HTML یا Document به PDF اجرا می‌کنند.

URL، File Path و Optionها باید کنترل شوند.

Git و DevOps

Dashboardهای Deployment گاهی Commandهای Git، Docker یا Kubernetes را اجرا می‌کنند.

این بخش‌ها به دلیل Privilege بالا بسیار حساس هستند. Command Injection در PHP چگونه رخ می‌دهد؟

Command Injection در PHP

PHP Functionهای متعددی برای اجرای Program دارند.

از جمله:

system()

exec()

shell_exec()

passthru()

Backtick Operator

و proc_open().

PHP Manual درباره system() و exec() هشدار می‌دهد که اگر Data کاربر وارد Command می‌شود، باید از مکانیزم‌های Escaping مناسب استفاده شود.

اما راهکار بهتر، مطابق OWASP، حذف Command Execution در صورت امکان است.

shell_exec چرا حساس است؟

PHP تعریف می‌کند shell_exec() فرمان را از طریق Shell اجرا کرده و Output کامل را برمی‌گرداند.

همین «از طریق Shell» بخش مهم Risk است.

اگر Application صرفاً می‌خواهد File را Copy، Rename یا Delete کند، استفاده از Functionهای File System PHP معمولاً گزینه بسیار مناسب‌تری نسبت به اجرای Utility سیستم‌عامل است.

escapeshellarg چیست؟

PHP تابع escapeshellarg() را برای Escape کردن یک Argument منفرد ارائه می‌کند.

این Function String را به شکلی Quote می‌کند که Shell آن را به‌عنوان یک Argument واحد در نظر بگیرد. PHP Manual مشخصاً می‌گوید این Function برای Escape کردن Argumentهایی که از User Input می‌آیند و به توابع Shell داده می‌شوند طراحی شده است.

با این حال escapeshellarg() جای Validation را نمی‌گیرد.

ممکن است Argument از نظر Shell یک Argument واحد باشد ولی Program مقصد همان Argument را به‌عنوان Option خطرناک تفسیر کند.

پس دو سؤال جدا داریم:

آیا Input می‌تواند Shell Syntax را تغییر دهد؟

آیا Input می‌تواند رفتار Program مقصد را به‌شکل ناخواسته تغییر دهد؟

هر دو باید پاسخ داده شوند.

escapeshellcmd چیست؟

PHP تابع escapeshellcmd() را نیز دارد که Characterهایی را که ممکن است برای تغییر ساختار Command استفاده شوند Escape می‌کند.

اما این Function نیز مجوز استفاده بی‌قیدوشرط از User Input نیست.

در Bug Tracker رسمی PHP نیز توضیح داده شده که Escaping Command Characterها لزوماً Argument Injection را حل نمی‌کند، زیرا Space و Option Semantics می‌توانند همچنان رفتار Program را تحت تأثیر قرار دهند.

بنابراین در معماری امن باید اول بپرسیم:

آیا اصلاً به Shell نیاز داریم؟

اگر پاسخ خیر است، Escaping دیگر موضوع اصلی نیست.

Command Injection در Python

Python برای اجرای Process از Module استاندارد subprocess استفاده می‌کند.

نکته مهم Security این است که اجرای Process با Argumentهای جداگانه با اجرای String از طریق Shell تفاوت دارد.

مستندات رسمی Python درباره استفاده از shell=True به بخش Security Considerations ارجاع می‌دهد، زیرا در این Mode مسئولیت Quote کردن صحیح Meta-characterها برعهده Application قرار می‌گیرد.

در نتیجه برای داده غیرقابل اعتماد، مدل امن‌تر معمولاً این است:

Executable مشخص باشد.

Argumentها به‌صورت جداگانه ارسال شوند.

Shell در میان نباشد.

Validation انجام شود.

Command Injection در Node.js

Node.js نیز APIهای مختلفی در child_process دارد.

exec() Command را از طریق Shell اجرا می‌کند.

در مقابل APIهایی که Executable و Argumentها را جدا دریافت می‌کنند، در بسیاری از کاربردها Attack Surface کمتری دارند.

مستندات رسمی Node.js تصریح می‌کنند child_process.exec() از Shell برای اجرای Command استفاده می‌کند.

بنابراین اگر Application فقط نیاز دارد یک Binary مشخص را با چند Argument محدود اجرا کند، ساختن یک Command String و سپردن آن به Shell معمولاً انتخاب مناسبی نیست.

Command Injection در Java

در Java معمولاً ProcessBuilder یا Process API برای اجرای Program خارجی استفاده می‌شود.

رویکرد امن‌تر این است که Executable و Argumentها به شکل ساختاریافته تعریف شوند، نه اینکه یک Command Line کامل با User Input ساخته و به Shell داده شود.

حتی در این حالت باید Argument Validation انجام شود.

مثلاً اگر یک Argument باید فقط عدد باشد، همان Rule دقیق روی آن اعمال شود.

اصل مهم این است:

Process API باید Command Structure را Application تعیین کند.

User فقط Valueهای محدود و مورد انتظار را فراهم کند.

Command Injection در .NET

در .NET نیز ProcessStartInfo برای اجرای Process استفاده می‌شود.

Propertyهایی مانند UseShellExecute تعیین می‌کنند Process چگونه Launch شود. Microsoft توضیح می‌دهد با UseShellExecute=false Process به شکل متفاوتی از Shell Integration اجرا می‌شود و امکان Redirect کردن Streamها فراهم می‌شود.

برای Security، باید میان «اجرای Program مشخص» و «ارسال Text برای تفسیر توسط Shell» تفاوت قائل شد.

هر جا Shell حذف شود، سطح تفسیر Input نیز کمتر می‌شود.

آیا حذف Shell تمام خطر را از بین می‌برد؟

خیر.

حذف Shell بخش بسیار مهمی از Attack Surface را حذف می‌کند، اما Argument Injection همچنان ممکن است.

فرض کنید Program مشخصی اجرا می‌شود و User یک File Name وارد می‌کند.

اگر Program مقصد File Nameهایی که با Option Prefix شروع می‌شوند به‌عنوان Option در نظر بگیرد، رفتار ناخواسته ممکن است ایجاد شود.

بنابراین بعد از حذف Shell، Allowlist و Semantic Validation همچنان لازم‌اند.

Input Validation مناسب برای Command Injection

Validation باید Positive یا Allowlist-based باشد.

به‌جای این سؤال:

«چه Characterهایی خطرناک هستند؟»

بهتر است بپرسید:

«مقدار معتبر دقیقاً چه شکلی است؟»

اگر Input قرار است IPv4 باشد:

فقط IPv4 معتبر Accept شود.

اگر ID است:

فقط Integer مثبت.

اگر File Name است:

Character Set، Length و Extension مشخص.

اگر Format انتخابی است:

از Enumeration ثابت استفاده شود.

این مدل بسیار امن‌تر از Blocklist است.

OWASP نیز برای شرایطی که جداسازی کامل Data و Command ممکن نیست، Positive Server-side Input Validation را توصیه می‌کند.

چرا Blocklist ضعیف است؟

Blocklist معمولاً فهرستی از Characterها یا Wordهای «بد» است.

اما Shellها و Programها Syntaxهای زیادی دارند.

همچنین:

Encoding

Platform

Locale

Shell Version

Program Optionها

می‌توانند رفتار را تغییر دهند.

Blocklist معمولاً باید همه حالت‌های خطرناک آینده را پیش‌بینی کند.

Allowlist فقط باید Input مورد نیاز Business را تعریف کند.

به همین دلیل Allowlist قابل دفاع‌تر است.

اگر فقط چند گزینه معتبر داریم چه کنیم؟

بهترین حالت این است که User اصلاً String Command تولید نکند.

فرض کنید User باید یکی از سه Operation را انتخاب کند:

فشرده‌سازی

استخراج

بررسی

Application می‌تواند مقدار User را به یک Enumeration داخلی Map کند.

User:

operation=extract

Application:

Enum.EXTRACT

Backend سپس Function یا Argument ثابت خودش را انتخاب می‌کند.

در این مدل User هیچ‌وقت Syntax واقعی Command را کنترل نمی‌کند.

Shell Escape چه زمانی کاربرد دارد؟

Escaping زمانی یک Defense ثانویه است که واقعاً مجبوریم Shell را استفاده کنیم.

اما اولویت دفاعی بهتر است چنین باشد:

API داخلی زبان

سپس Process Execution بدون Shell

سپس Argument Allowlist

و در نهایت Escaping مناسب Context.

OWASP نیز Avoid کردن OS Command را Defense اصلی معرفی می‌کند.

چرا Generic Sanitization کافی نیست؟

تابع عمومی Sanitization نمی‌تواند همه Contextها را ایمن کند.

Escape مناسب برای:

HTML

با Escape مناسب برای:

SQL

یا:

Shell

فرق دارد.

حتی Shellهای مختلف Syntax متفاوتی دارند.

بنابراین چیزی به نام:

sanitize(userInput)

که برای تمام Contextها Security ایجاد کند، وجود ندارد.

Validation باید Domain-specific و Escaping باید Context-specific باشد.

Command Injection و Path Validation

گاهی User Input Path فایل است.

Developer فقط Command Injection را بررسی می‌کند اما Path Traversal را فراموش می‌کند.

یک Input ممکن است از نظر Shell Safe باشد اما Application را به File غیرمجاز هدایت کند.

پس اگر Input Path است باید همزمان:

Command Safety

Path Canonicalization

Directory Allowlist

Permission

بررسی شوند.

Security Controlها جای یکدیگر را نمی‌گیرند.

Command Injection و File Upload

File Upload یکی از منابع رایج Input خطرناک است.

ممکن است User نام File را کنترل کند.

سپس Background Worker همان نام را به:

Image Converter

Video Encoder

Archive Utility

Antivirus Scanner

یا PDF Tool

بدهد.

Best Practice این است که File Upload با نام تصادفی Server-side ذخیره شود و Original File Name فقط Metadata باشد.

در نتیجه Worker مجبور نیست Name کنترل‌شده توسط User را به Program خارجی بدهد.

Command Injection در Image Processing

پردازش Media یک Attack Surface مهم است.

حتی اگر Application خودش Shell نسازد، Library پردازش تصویر ممکن است Internally Process خارجی اجرا کند.

بنابراین علاوه بر Code خود Application باید Dependency Architecture نیز بررسی شود.

موارد مهم:

Library Version

External Delegate

File Type

Argument Construction

Temporary Path

Privilege Worker

Network Access

Command Injection در Backup Scripts

پنل‌های مدیریت گاهی Backup Path، Database Name یا File Name را از User می‌گیرند و به Shell Script ارسال می‌کنند.

این کار بسیار حساس است چون Backup Process معمولاً Permission نسبتاً زیادی دارد.

راهکار بهتر:

Backup Operationها ثابت باشند.

Pathها از Configuration داخلی انتخاب شوند.

User فقط Identifier محدود انتخاب کند.

Process با User جدا و محدود اجرا شود.

Command Injection در DevOps Panelها

Deployment Panel، CI/CD و Internal Tools خطر ویژه‌ای دارند.

این برنامه‌ها ممکن است به:

Docker

Git

SSH

Systemctl

Kubernetes

Cloud CLI

دسترسی داشته باشند.

یک Command Injection در چنین محیطی می‌تواند Impact بسیار بزرگ‌تری از یک Web Worker معمولی داشته باشد.

Internal بودن Tool به معنی امن بودن نیست.

کاربر داخلی، Compromised Account یا SSRF می‌تواند ورودی ناامن ایجاد کند.

Least Privilege چگونه Impact را کاهش می‌دهد؟

حتی بهترین Validation ممکن است Bug داشته باشد.

در نتیجه Process باید حداقل Permission لازم را داشته باشد.

یک Web Application نباید:

Root

Administrator

یا User بسیار Privileged

باشد مگر ضرورت واقعی وجود داشته باشد.

اگر Worker فقط باید فایل‌های داخل یک Directory را پردازش کند، دسترسی آن نیز باید در همان حد باشد.

Least Privilege باعث می‌شود یک Injection احتمالی Blast Radius کمتری داشته باشد.

اجرای Web Server با Root چرا خطرناک است؟

اگر Command Injection در Process دارای Root رخ دهد، مهاجم بالقوه از Permission بسیار بالایی برخوردار است.

مدل امن‌تر:

Master Process در صورت نیاز Privilege اولیه داشته باشد.

Workerهای Request با User محدود اجرا شوند.

Directoryها Permission حداقلی داشته باشند.

Service Accountها جدا باشند.

این اصل مستقل از Framework است.

Container چگونه کمک می‌کند؟

Container Vulnerability را حذف نمی‌کند.

ولی می‌تواند Impact را محدود کند.

یک Container مناسب می‌تواند:

Non-root باشد.

Read-only Filesystem داشته باشد.

Capabilityهای اضافی نداشته باشد.

Mount محدود داشته باشد.

Network Policy داشته باشد.

CPU و Memory Limit داشته باشد.

در این صورت Command Injection داخل Container الزاماً به کنترل Host منجر نمی‌شود.

البته Container Misconfiguration می‌تواند این مزیت را از بین ببرد.

AppArmor و SELinux

Mandatory Access Controlهایی مانند:

AppArmor

SELinux

می‌توانند مشخص کنند یک Process حتی در صورت Compromise به چه Fileها و Resourceهایی دسترسی داشته باشد.

این ابزارها Fix Command Injection نیستند.

ولی یک Defense in Depth قدرتمند هستند.

اگر Application فقط باید یک Binary خاص را اجرا کند، Policy سیستم‌عامل می‌تواند Scope آن را محدود کند.

Egress Filtering

اگر Process نیازی به Internet Access ندارد، چرا باید بتواند آزادانه Connection خروجی برقرار کند؟

Network Egress Restriction می‌تواند Impact Post-exploitation را کاهش دهد.

مثلاً Worker پردازش تصویر ممکن است فقط نیاز داشته باشد:

File بخواند.

File جدید بنویسد.

هیچ نیاز Network نداشته باشد.

در این صورت Network Access می‌تواند کاملاً محدود شود.

Secret Management

Secretها نباید به‌صورت گسترده در:

Environment Variable

Fileهای قابل خواندن

Home Directory

Command Line

وجود داشته باشند.

اگر Service Command Injection داشته باشد، هر Secret قابل دسترس Process ممکن است در Risk قرار گیرد.

اصل بهتر:

Secret فقط به Componentی داده شود که واقعاً به آن نیاز دارد.

Command Injection و Environment Variables

گاهی Command ثابت است اما Environment Variable از User یا Data غیرقابل اعتماد ساخته می‌شود.

Program مقصد ممکن است Environment Variableها را در Behavior خودش استفاده کند.

بنابراین Attack Surface فقط Argumentهای Command نیست.

Current Directory، PATH، Environment و Configuration نیز باید کنترل شوند.

چرا PATH اهمیت دارد؟

اگر Application Program را فقط با نام کوتاه اجرا کند، سیستم ممکن است براساس PATH دنبال Binary بگردد.

اگر Environment به‌شکل ناامن قابل تغییر باشد، ممکن است Program دیگری Resolve شود.

در سیستم حساس بهتر است مسیر Executable مشخص و قابل اعتماد باشد.

همچنین Directoryهای قابل نوشتن توسط User نباید در Search Path سرویس Privileged قرار داشته باشند.

Working Directory

Working Directory نیز بخشی از Execution Context است.

برنامه خارجی ممکن است Fileهای Relative را از Current Directory بخواند.

پس Directory اجرای Process باید مشخص و کنترل‌شده باشد.

این موضوع مخصوصاً در Workerهای File Processing اهمیت دارد.

Timeout برای Processهای خارجی

Program خارجی ممکن است Hang کند.

حتی بدون Injection، یک Input پیچیده می‌تواند Tool را مدت زیادی درگیر کند.

Application باید:

Timeout

Process Termination

CPU Limit

Memory Limit

داشته باشد.

این اقدامات علاوه بر Security، Reliability را نیز افزایش می‌دهند.

محدود کردن Output

فرمان خارجی ممکن است Output بسیار بزرگی تولید کند.

اگر Application آن را بدون Limit در Memory نگه دارد، DoS ممکن است رخ دهد.

پس هنگام اجرای Process باید:

Output Limit

Error Stream Management

Timeout

در نظر گرفته شوند.

Command Execution فقط موضوع Injection نیست.

Logging مناسب

برای Process Execution بهتر است اطلاعات زیر ثبت شوند:

نام Operation منطقی

Executable مورد استفاده

Execution Result

Exit Code

Duration

User یا Job ID

اما Log کردن Raw Input یا Secretها می‌تواند خودش Information Disclosure ایجاد کند.

همچنین بهتر است Full Command Line حاوی Token یا Password در Log قرار نگیرد.

آیا Command Output باید به User نمایش داده شود؟

معمولاً نه به‌صورت خام.

Output سیستم‌عامل ممکن است شامل:

File Path

Username

Version

Internal Hostname

Error Stack

Sensitive Configuration

باشد.

User باید Message مناسب Business را ببیند.

جزئیات فنی داخل Log محافظت‌شده قرار بگیرند.

Error Message و Command Injection

گاهی Vulnerability مستقیماً Command Output را برنمی‌گرداند، اما Error Message اطلاعات زیادی درباره System می‌دهد.

برای مثال:

Path Binary

Operating System

Shell Type

Working Directory

Internal File

این Data می‌تواند Reconnaissance را آسان‌تر کند.

Secure Error Handling باید همراه Injection Prevention باشد.

Command Injection در WordPress

WordPress Core به‌طور معمول برای بسیاری از Operationهای وب نیازی به اجرای Shell Command ندارد.

اما Plugin و Theme سفارشی ممکن است این کار را انجام دهند.

خصوصاً Pluginهای:

Backup

Image Optimization

Video Conversion

Server Management

Migration

Git Deployment

Security Scanner

PDF Generation

ممکن است Program خارجی اجرا کنند.

در Code Review باید به Functionهای اجرای Process در PHP توجه ویژه شود.

آیا disable_functions در PHP راهکار است؟

PHP می‌تواند بعضی Functionها را در Configuration محدود کند.

این می‌تواند Defense in Depth باشد.

برای مثال Environmentی که هیچ نیاز واقعی به اجرای Command ندارد، می‌تواند سطح اجرای Program خارجی را محدود کند.

اما disable_functions جای Secure Coding نیست.

اگر Application واقعاً به Process Execution نیاز داشته باشد، باید Design صحیح داشته باشد.

همچنین Dependencyها ممکن است نیاز مشروع داشته باشند.

تغییر Configuration باید ابتدا در Staging تست شود.

WordPress Hosting Hardening

برای سایت WordPress بهتر است:

PHP-FPM با User محدود اجرا شود.

هر سایت Hosting User جدا داشته باشد.

File Permission حداقلی باشد.

Shell Access Web User محدود باشد.

Container یا Jail در Hostingهای حساس بررسی شود.

Pluginهای غیرضروری حذف شوند.

Backup/Media Pluginهای دارای External Process به‌روز باشند.

WooCommerce و Command Injection

WooCommerce Core معمولاً نیازی به اجرای Shell برای عملیات عادی Checkout ندارد.

اما Extensionهای Third-party ممکن است:

Invoice Generator

ERP Sync

Export Tool

Backup

Image Processor

داشته باشند.

خصوصاً Storeهایی که Integration سفارشی دارند باید Custom Code را Review کنند.

هر Function اجرای Process باید دلیل Business واضح داشته باشد.

Secure by Design برای Command Execution

یکی از بهترین روش‌ها ایجاد یک Service داخلی محدود برای Operationهای سیستم است.

به‌جای اینکه Controller مستقیماً Command بسازد، می‌تواند مثلاً Functionی داشته باشد:

GenerateThumbnail(imageId)

این Function فقط:

File متعلق به همان ID را پیدا می‌کند.

Path را خودش تولید می‌کند.

Program ثابت را انتخاب می‌کند.

Optionهای ثابت را استفاده می‌کند.

User Input هیچ‌گاه Command Syntax نمی‌شود.

این معماری بسیار قابل دفاع‌تر است.

Wrapper امن برای Process Execution

سازمان می‌تواند یک Wrapper مرکزی ایجاد کند.

مثلاً تمام Processها فقط از طریق یک Module داخلی اجرا شوند.

Wrapper می‌تواند:

Shell را ممنوع کند.

Executable Allowlist داشته باشد.

Argument Type Validation انجام دهد.

Timeout اجباری داشته باشد.

Output Limit داشته باشد.

Audit Log تولید کند.

Environment را پاک‌سازی کند.

در این حالت احتمال اینکه Developer جدید به‌صورت اتفاقی Command Injection ایجاد کند کمتر می‌شود.

Threat Modeling

در Threat Modeling برای هر Feature بپرسید:

آیا Process خارجی اجرا می‌شود؟

چه کسی Executable را انتخاب می‌کند؟

چه کسی Argument را کنترل می‌کند؟

Data از کجا می‌آید؟

آیا Shell در مسیر است؟

Process چه Permissionی دارد؟

Network Access دارد؟

چه Fileهایی می‌تواند بخواند؟

اگر Input غیرمنتظره باشد چه می‌شود؟

این سؤال‌ها Vulnerability را قبل از Production آشکار می‌کنند.

Code Review برای Command Injection

Search کردن Functionهای اجرای Command اولین قدم خوبی است.

در PHP:

system

exec

shell_exec

passthru

proc_open

Backticks

در Python:

subprocess

os.system

در Node.js:

child_process

در Java:

ProcessBuilder

Runtime execution APIs

در .NET:

ProcessStartInfo

اما فقط Function Name کافی نیست.

باید Data Flow بررسی شود.

Input User ممکن است پنج Function قبل‌تر وارد سیستم شده باشد.

SAST برای Command Injection

Static Analysis Tool می‌تواند مسیر User Input تا Command Sink را شناسایی کند.

مفهوم Source و Sink در اینجا مهم است.

Source:

Input غیرقابل اعتماد.

Sink:

API اجرای Process.

اگر Data بدون Validation مناسب از Source به Sink برسد، Tool ممکن است Finding ایجاد کند.

SAST بسیار مفید است اما Context Business را کامل نمی‌فهمد.

Manual Review همچنان ضروری است.

DAST برای Command Injection

Dynamic Testing باید بسیار محتاطانه و فقط روی Environment مجاز انجام شود.

هدف تست دفاعی بهتر است اثبات کنترل Input باشد، نه اجرای عملیات مخرب.

در Staging می‌توان بررسی کرد:

Inputهای نامعتبر Reject می‌شوند؟

Argumentها به‌صورت منفرد پردازش می‌شوند؟

Shell فعال نیست؟

Program فقط Optionهای مجاز را می‌پذیرد؟

به‌جای اجرای Commandهای واقعی غیرمجاز، رفتار Validation و Process Audit Log بررسی شود.

Unit Test امنیتی

برای Functionی که Process خارجی اجرا می‌کند Test بنویسید.

برای مثال بررسی شود:

Input خارج از Allowlist Reject شود.

String طولانی Reject شود.

نام File غیرمعتبر Reject شود.

Operation ناشناخته Reject شود.

Executable ثابت باقی بماند.

Argument Count تغییر نکند.

Shell غیرفعال باشد.

این Testها از Regression جلوگیری می‌کنند.

Integration Test

Unit Test ممکن است فقط Code را بررسی کند.

Integration Test باید Configuration واقعی:

Container

Operating System

Executable Version

Environment

را نیز پوشش دهد.

ممکن است Code امن باشد اما Wrapper Production از Shell استفاده کند.

Security Test باید Environment واقعی را تا حد ممکن شبیه‌سازی کند.

Dependency Security

گاهی Vulnerability در Library ثالث است.

Application فقط یک Function ساده را صدا می‌زند اما Library در پشت صحنه Command می‌سازد.

بنابراین:

Dependency Update

CVE Monitoring

SBOM

Software Composition Analysis

اهمیت دارند.

به‌خصوص Pluginهای Media و Document Conversion باید به‌روز باشند.

آیا Validation با Regex کافی است؟

اگر Regex دقیقاً Business Format را تعریف کند، می‌تواند بخشی از راهکار باشد.

مثلاً Input باید فقط:

A-Z

a-z

0-9

و حداکثر ۳۰ Character

باشد.

اما Regexی که صرفاً چند Character خطرناک را منع کند، Blocklist محسوب می‌شود و کافی نیست.

Validation باید تعریف کند چه چیزی مجاز است، نه اینکه چند نمونه خطرناک را حدس بزند.

Unicode و Encoding

Validation باید پس از Normalization مناسب انجام شود.

Characterهای Unicode ممکن است ظاهر مشابه ولی Representation متفاوت داشته باشند.

همچنین Encoding چندمرحله‌ای می‌تواند Validation Layerها را پیچیده کند.

در ورودی‌هایی مانند File Name بهتر است Character Set موردنیاز محدود باشد.

Input Length

Length Limit یک Control ساده و مؤثر است.

اگر Hostname حداکثر طول منطقی مشخص دارد، پذیرش Input چند ده هزار Character منطقی نیست.

Limit باعث کاهش:

Parser Complexity

Log Pollution

Resource Abuse

می‌شود.

Type Safety

اگر Input عدد است، آن را زود به Integer تبدیل کنید.

اگر Boolean است، Boolean واقعی.

اگر Operation یکی از چند مقدار است، Enum.

هرچه Data مدت کمتری به شکل String آزاد در Application بچرخد، Injection Surface کمتر می‌شود.

آیا Prepared Command مثل Prepared Statement داریم؟

در Shell دقیقاً معادل Prepared Statement SQL به همان شکل عمومی وجود ندارد.

اما Process APIهایی که Executable و Argument List را جداگانه دریافت می‌کنند، از نظر معماری نقش مشابهی دارند:

Command Structure و Data جدا هستند.

به همین دلیل این APIها ترجیح داده می‌شوند.

Shell Command Escaping در Windows و Linux

Escaping Shell به Platform وابسته است.

قواعد Bash با cmd.exe و PowerShell یکسان نیست.

همین مسئله دلیل دیگری است که نباید Security Architecture را صرفاً بر Escaping String بنا کرد.

یک برنامه Cross-platform می‌تواند در هر OS رفتار متفاوتی داشته باشد.

Process API با Argument Separation معمولاً قابل پیش‌بینی‌تر است.

PowerShell

PowerShell یک Shell بسیار قدرتمند است.

ارسال User Input به یک PowerShell Command String می‌تواند خطر بزرگی باشد.

اگر Application نیاز به Automation ویندوز دارد، بهتر است:

Operationهای مشخص و محدود تعریف شوند.

Parameterها Typed و Allowlisted باشند.

Script ثابت باشد.

User نتواند Script Body تولید کند.

Batch و Shell Scriptهای داخلی

گاهی Developer می‌گوید:

«User Input به Shell نمی‌رود؛ به Script خودمان می‌رود.»

اما اگر Script Argument را بدون Quote یا Validation استفاده کند، Vulnerability فقط به یک Layer پایین‌تر منتقل شده است.

تمام Chain باید Review شود.

Web Application

→ Wrapper Script

→ Utility

هر سه Layer می‌توانند Interpretation داشته باشند.

Remote Command Execution و Command Injection

Command Injection می‌تواند به Remote Command Execution منجر شود.

اما این دو اصطلاح دقیقاً یکی نیستند.

RCE نتیجه یا Capability است.

Command Injection یک Root Cause مشخص است.

ممکن است RCE از:

Unsafe Deserialization

Memory Corruption

Template Injection

یا Code Injection

نیز ایجاد شود.

بنابراین در گزارش امنیتی بهتر است Root Cause دقیق مشخص شود.

Command Injection بدون Output

گاهی فرمان اجرا می‌شود اما Output به User نمایش داده نمی‌شود.

این موضوع Vulnerability را از بین نمی‌برد.

Application ممکن است Side Effect ایجاد کند.

همچنین Log، Timing یا Network Behavior ممکن است تغییر کند.

برای دفاع، نباید صرفاً بررسی کنیم آیا Output Command در HTTP Response دیده می‌شود یا نه.

Blind Command Injection

به شرایطی گفته می‌شود که نتیجه مستقیم Command به Response برنمی‌گردد.

از دید مدافع، Detection باید شامل:

Process Monitoring

Unexpected Child Process

Network Egress

File System Change

Audit Log

باشد.

Endpoint Detection می‌تواند در شناسایی رفتار غیرعادی کمک کند.

Process Monitoring

روی Server حساس می‌توان بررسی کرد Web Worker چه Child Processهایی ایجاد می‌کند.

اگر Application عادی فقط یک Binary مشخص را اجرا می‌کند، اجرای Binary جدید باید Event امنیتی محسوب شود.

ابزارهای EDR، Auditd یا سیستم‌های Monitoring می‌توانند چنین رفتارهایی را ثبت کنند.

Allowlist Executable

اگر Application فقط به دو Program خارجی نیاز دارد، دلیلی ندارد Web Worker اجازه اجرای هر Binary سیستم را داشته باشد.

در معماری‌های حساس می‌توان Execution Policy را محدود کرد.

این کار می‌تواند با:

Container

MAC Policy

Service Design

Wrapper

انجام شود.

Read-only Root Filesystem

برای Workerهای قابل Containerize شدن، Read-only Filesystem می‌تواند Impact را کاهش دهد.

Directoryهای Temporary موردنیاز جدا Mount شوند.

این کار مانع تمام Attackها نیست، ولی تغییر Application File یا Binary را سخت‌تر می‌کند.

Network Segmentation

Web Worker نباید به تمام Databaseها و Internal Network دسترسی داشته باشد.

اگر فقط یک Service مشخص لازم است، Network Policy باید همان را Allow کند.

Command Injection در Service دارای Network Access گسترده Impact بیشتری دارد.

Authentication و Authorization همچنان مهم‌اند

ممکن است Endpoint آسیب‌پذیر فقط برای Admin باشد.

این موضوع Risk را کاهش می‌دهد اما Vulnerability را حذف نمی‌کند.

Admin Account ممکن است Compromise شود.

CSRF یا سایر ضعف‌ها ممکن است Operation را Trigger کنند.

Input Handling باید مستقل از Role امن باشد.

CSRF و Command Injection

اگر Endpoint Command Execution آسیب‌پذیر باشد و CSRF نیز داشته باشد، Risk ترکیبی می‌تواند بیشتر شود.

اما CSRF Protection به‌تنهایی Command Injection را Fix نمی‌کند.

هر لایه هدف خودش را دارد.

WAF و Command Injection

WAF می‌تواند Patternهای مشکوک را Block کند.

اما WAF Fix اصلی نیست.

دلایل:

Encoding Variation

Shell Variation

Application Context

Internal Input

Stored Input

می‌توانند Detection را دور بزنند.

Root Cause باید در Code و Architecture رفع شود.

آیا Character Filtering کافی است؟

خیر.

حتی اگر چند Shell Metacharacter شناخته‌شده حذف شوند، Program ممکن است از Argumentهای خطرناک استفاده کند.

همچنین Shell و OS متفاوت Syntax متفاوت دارند.

هدف باید حذف Interpretation باشد.

نه رقابت با تمام Syntaxهای ممکن.

بهترین ترتیب دفاعی

رویکرد امن را می‌توان این‌گونه خلاصه کرد:

ابتدا بررسی کنید آیا می‌توان بدون Command کار را انجام داد.

اگر بله، از Library/API استفاده کنید.

اگر نه، Shell را حذف و Executable را مستقیم اجرا کنید.

Argumentها را جداگانه بدهید.

Allowlist و Type Validation اعمال کنید.

Process را با Least Privilege اجرا کنید.

Execution Context را محدود کنید.

Logging و Monitoring داشته باشید.

این دقیقاً با اولویت OWASP برای Avoid کردن OS Command مستقیم همسو است. چک‌لیست جلوگیری از Command Injection

چک‌لیست جلوگیری از Command Injection

  • تا حد امکان از اجرای Command سیستم‌عامل خودداری شود و API یا Library داخلی زبان جایگزین شود.
  • اگر اجرای Process لازم است، Shell در صورت امکان حذف شود.
  • Executable توسط Application ثابت و از مسیر قابل اعتماد انتخاب شود.
  • Argumentها جدا از Command Structure ارسال شوند.
  • User اجازه انتخاب نام Executable نداشته باشد مگر از Allowlist بسیار محدود.
  • Input با Positive Allowlist و Ruleهای Business اعتبارسنجی شود.
  • Type Conversion زودهنگام برای Integer، Boolean و Enum انجام شود.
  • File Name و Path با Ruleهای مستقل Path Traversal بررسی شوند.
  • Original File Name مستقیماً به Command خارجی داده نشود.
  • Argumentهایی که می‌توانند Option Program محسوب شوند محدود شوند.
  • از Blocklist Character به‌عنوان دفاع اصلی استفاده نشود.
  • در صورت اجبار به استفاده از Shell، Escaping متناسب با همان Shell و Context انجام شود.
  • Process با User غیرprivileged اجرا شود.
  • Web Application با Root یا Administrator اجرا نشود.
  • File System Permission حداقلی باشد.
  • Secretهای غیرضروری در دسترس Process نباشند.
  • Environment Variableها و PATH کنترل شوند.
  • Working Directory مشخص و امن باشد.
  • Egress Network تا حد نیاز محدود شود.
  • Container بدون Root و با Capability حداقلی اجرا شود.
  • در صورت امکان Read-only Filesystem استفاده شود.
  • Timeout برای Processهای خارجی تعریف شود.
  • Memory و CPU Limit اعمال شود.
  • حجم Output Process محدود باشد.
  • Error Output خام مستقیماً به User نمایش داده نشود.
  • Full Command حاوی Secret در Log ثبت نشود.
  • Child Processهای غیرمنتظره Monitor شوند.
  • Codebase برای system، exec، shell_exec، subprocess، child_process و APIهای مشابه Review شود.
  • SAST برای Data Flow از User Input به Process Execution فعال باشد.
  • Dependencyهایی که Process خارجی اجرا می‌کنند شناسایی و به‌روز شوند.
  • Unit Test برای Inputهای نامعتبر نوشته شود.
  • Security Test روی Staging یا Lab مجاز انجام شود.
  • هر Feature جدید که Process خارجی اجرا می‌کند Threat Modeling شود.
  • Shell Script و Wrapperهای داخلی نیز جداگانه Review شوند.
  • Authorization Endpointهای حساس مستقل از Input Validation برقرار باشد.
  • WAF فقط Layer مکمل باشد و جای Fix اصلی را نگیرد.

چک‌لیست Command Injection برای WordPress

در یک سایت WordPress بهتر است ابتدا Pluginها و Custom Codeهایی را پیدا کنید که Program خارجی اجرا می‌کنند.

موارد حساس معمولاً شامل:

Backup Plugin

Media Converter

Image Optimizer

Migration Tool

PDF Generator

Security Scanner

Deployment Integration

هستند.

اگر هیچ Feature سایت نیاز به Process Execution ندارد، Environment Hosting می‌تواند اجرای بعضی Functionهای PHP را محدود کند.

همچنین بهتر است PHP-FPM برای هر Site با User جدا اجرا شود.

Web Root Permission حداقلی باشد.

Pluginهای قدیمی حذف شوند.

Dependencyهای Native به‌روز شوند.

Cron Jobهای سفارشی Review شوند.

هر Scriptی که WordPress Data را به Shell می‌فرستد باید بررسی شود.

به‌ویژه Custom Pluginهایی که با:

File Name

Domain

URL

Path

یا Server Utility

کار می‌کنند.

Code Review عملی از دید دفاعی

هنگام Review هر Process Execution پنج سؤال اصلی بپرسید.

اول:

آیا واقعاً اجرای Program خارجی لازم است؟

دوم:

آیا Shell در مسیر است؟

سوم:

کدام بخش Command توسط User کنترل می‌شود؟

چهارم:

آیا همان Data Allowlist و Type Validation دارد؟

پنجم:

اگر Validation شکست خورد، Process اجرا می‌شود یا Fail Closed؟

اگر پاسخ سؤال اول «خیر» باشد، بهترین Fix حذف Process Execution است.

مثال طراحی ناامن

فرض کنید Application برای Resize کردن تصویر:

نام File و Width را از User بگیرد.

سپس Command String بسازد.

این Design چند مشکل دارد.

File Name کنترل‌شده است.

Width String آزاد است.

Shell وجود دارد.

Executable ممکن است براساس PATH Resolve شود.

مدل بهتر این است:

Application File را با ID داخلی پیدا کند.

Width را Integer و داخل Range مشخص Validate کند.

Executable ثابت باشد.

Argumentها جدا باشند.

Process با User محدود اجرا شود.

در این مدل User هیچ Command Stringی تولید نمی‌کند.

مثال طراحی امن‌تر برای Ping Feature

اگر Feature فقط نیاز دارد Online بودن Host مشخصی را بررسی کند، ممکن است اصلاً نیاز به Utility سیستم‌عامل وجود نداشته باشد.

Library Network زبان می‌تواند:

DNS Resolve

TCP Connection

HTTP Request

انجام دهد.

در این حالت Command Injection Surface کاملاً حذف می‌شود.

این همان دلیل اصلی توصیه OWASP برای استفاده از API داخلی به جای OS Command است.

مثال طراحی امن‌تر برای ساخت Directory

OWASP مثال ساده‌ای ارائه می‌کند:

به‌جای اجرای Command سیستم برای ایجاد Directory، از Function داخلی زبان مانند mkdir() استفاده کنید.

مزیت این روش فقط Escape کمتر نیست.

اصلاً Shell وجود ندارد که Input را به‌عنوان Language Syntax تفسیر کند.

این تفاوت معماری بسیار مهم است.

مثال طراحی امن‌تر برای Archive

اگر Language دارای Library معتبر Archive است، استفاده از آن معمولاً از ساخت Command Line برای Utility سیستم امن‌تر است.

اگر استفاده از Utility اجباری است:

Executable ثابت باشد.

Input Fileها از ID داخلی Resolve شوند.

Output Path توسط Server ساخته شود.

Optionها از Enumeration ثابت انتخاب شوند.

Timeout وجود داشته باشد.

Worker محدود باشد.

Command Injection و Secure SDLC

جلوگیری واقعی فقط یک Fix در Code نیست.

باید در چرخه توسعه وارد شود.

Requirement:

آیا External Process لازم است؟

Design:

چگونه Shell حذف شود؟

Implementation:

Argument Separation.

Code Review:

Source-to-Sink Analysis.

Testing:

Negative Input.

Deployment:

Least Privilege.

Operations:

Process Monitoring.

این مدل باعث می‌شود Vulnerability قبل از Production متوقف شود.

NIST و اصل Least Privilege

اگرچه Command Injection با CWE و OWASP به‌صورت مستقیم تعریف می‌شود، اصول توسعه امن مانند Least Privilege و محدود کردن Capabilityهای Software از پایه‌های Secure Software Development هستند.

وقتی Application فقط Permission لازم را دارد، یک Bug منفرد کمتر می‌تواند کل Server را در اختیار مهاجم قرار دهد.

پس Prevention و Impact Reduction باید همزمان اجرا شوند.

خطاهای رایج توسعه‌دهندگان

«فقط Admin می‌تواند این Input را وارد کند»

Admin Account نیز ممکن است Compromise شود.

Input همچنان باید امن باشد.

«WAF جلوی Characterهای خطرناک را می‌گیرد»

WAF Context کامل Command را نمی‌داند.

«از escapeshellarg استفاده کرده‌ایم، پس تمام شد»

ممکن است Argument Injection همچنان وجود داشته باشد.

«روی Linux امن است»

Shell Injection مسئله Cross-platform است؛ فقط Syntax فرق می‌کند.

«Command Output نمایش داده نمی‌شود»

Blind Command Injection همچنان خطرناک است.

«Process داخل Container است»

Container فقط Blast Radius را کاهش می‌دهد.

«Input از Database آمده»

Stored Data نیز می‌تواند Untrusted باشد.

«Regex چند Character را حذف می‌کند»

Blocklist دفاع اصلی مناسبی نیست.

آیا Command Injection قابل تشخیص از Log است؟

گاهی بله.

نشانه‌های احتمالی:

Child Process غیرمنتظره

Process Tree غیرعادی

Execution Toolی که Application معمولاً استفاده نمی‌کند

Network Connection از Web Worker

File Change غیرمنتظره

Execution Errorهای متوالی

ورودی‌هایی که Validation Failure دارند

اما هیچ نشانه منفردی اثبات قطعی نیست.

Monitoring باید Baseline رفتار معمول سیستم را بشناسد.

Response Incident

اگر احتمال Command Injection Exploitation وجود دارد، فقط Code Patch کافی نیست.

باید فرض کرد Process با Permission خودش ممکن است مورد سوءاستفاده قرار گرفته باشد.

لازم است:

Logها حفظ شوند.

Process Tree بررسی شود.

File Integrity بررسی شود.

Credentialهای قابل دسترسی ارزیابی شوند.

Outbound Connectionها بررسی شوند.

Secretهای در معرض خطر Rotate شوند.

Vulnerability Fix شود.

سپس Retest انجام شود.

اگر Web Process Privilege بالا داشته، Scope Incident باید گسترده‌تر بررسی شود.

آیا Restart Server کافی است؟

خیر.

Restart ممکن است Process مهاجم را متوقف کند، اما Vulnerability باقی می‌ماند.

همچنین Persistence احتمالی یا تغییر File ممکن است باقی مانده باشد.

Root Cause باید Fix شود.

آیا Antivirus Command Injection را متوقف می‌کند؟

نه به‌عنوان دفاع اصلی.

اگر Application یک Command قانونی سیستم را اجرا کند، ممکن است Antivirus هیچ Malware File مشخصی نبیند.

Endpoint Protection می‌تواند Behavior مشکوک را شناسایی کند، اما Secure Application Design جایگزین ندارد.

آیا CSP جلوی Command Injection را می‌گیرد؟

خیر.

CSP Browser-side است.

Command Injection Server-side و در Context سیستم‌عامل رخ می‌دهد.

آیا CORS جلوی Command Injection را می‌گیرد؟

خیر.

CORS کنترل Cross-Origin Browser Access است.

حتی API با CORS کاملاً صحیح می‌تواند Command Injection داشته باشد.

آیا CSRF Token کافی است؟

خیر.

CSRF Token مانع بعضی Requestهای Cross-site می‌شود.

اما اگر User مجاز Input مخرب وارد کند، Command Injection همچنان وجود دارد.

آیا 2FA کمکی می‌کند؟

2FA برای حفاظت Account بسیار مهم است، اما Input Processing را امن نمی‌کند.

اگر Admin احراز هویت‌شده از Feature آسیب‌پذیر استفاده کند، 2FA تغییری در Command Parsing ایجاد نمی‌کند.

سوالات متداول درباره Command Injection

Command Injection چیست؟

Command Injection آسیب‌پذیری‌ای است که در آن ورودی غیرقابل اعتماد روی فرمان سیستم‌عامل اثر می‌گذارد و Application ممکن است Command ناخواسته اجرا کند.

OS Command Injection یعنی چه؟

نام کامل همان خانواده آسیب‌پذیری است و تمرکز آن روی Commandهای Operating System است.

CWE مربوط به Command Injection چیست؟

CWE-78 یا Improper Neutralization of Special Elements used in an OS Command.

Command Injection در OWASP Top 10 کجاست؟

در OWASP Top 10:2025 زیر دسته A05 – Injection قرار می‌گیرد.

بهترین روش جلوگیری از Command Injection چیست؟

OWASP توصیه می‌کند تا حد امکان از فراخوانی مستقیم OS Command جلوگیری و از APIها و Libraryهای داخلی زبان استفاده شود.

آیا Escaping به‌تنهایی کافی است؟

خیر. Escaping ممکن است Shell Injection را کاهش دهد اما Argument Injection و Logic Abuse همچنان ممکن است وجود داشته باشند.

escapeshellarg در PHP چه می‌کند؟

یک Argument را برای استفاده در Functionهای Shell Quote و Escape می‌کند تا به‌عنوان یک Argument واحد تفسیر شود.

escapeshellcmd چیست؟

Characterهای خاصی که می‌توانند Structure فرمان را تغییر دهند Escape می‌کند. اما این Function نیز جای Allowlist و Design بدون Shell را نمی‌گیرد.

آیا shell_exec خطرناک است؟

خود Function به‌تنهایی Vulnerability نیست، اما چون Command را از طریق Shell اجرا می‌کند، استفاده از Input غیرقابل اعتماد در آن نیازمند کنترل بسیار دقیق است.

exec در PHP آسیب‌پذیر است؟

صرف استفاده از exec() آسیب‌پذیری نیست. Vulnerability زمانی ایجاد می‌شود که Input غیرقابل اعتماد بتواند Command یا Argumentهای غیرمجاز را کنترل کند.

آیا system() خطرناک است؟

همانند سایر Functionهای Process Execution، باید User Input از Command جدا شود. PHP Manual نیز برای User-supplied Data هشدار امنیتی دارد. تفاوت Command Injection و Code Injection

تفاوت Command Injection و Code Injection چیست؟

Command Injection سیستم‌عامل یا Shell را هدف می‌گیرد؛ Code Injection Runtime یا زبان برنامه را.

تفاوت SQL Injection و Command Injection چیست؟

SQL Injection روی Query Database و Command Injection روی فرمان سیستم‌عامل اثر می‌گذارد.

Argument Injection چیست؟

حالتی است که User Command جدید نمی‌سازد اما می‌تواند Option یا Argumentهایی به Program بدهد که Behavior آن را تغییر دهد.

آیا استفاده از ProcessBuilder امن است؟

استفاده از Executable و Argumentهای جدا معمولاً از Shell String امن‌تر است، اما Argumentها همچنان باید Validate شوند.

آیا Python shell=True خطرناک است؟

اگر Input غیرقابل اعتماد وارد Command شود Risk بالا می‌رود. مستندات Python نیز برای استفاده از Shell به Security Considerations اشاره می‌کند.

آیا Node.js exec از Shell استفاده می‌کند؟

بله، مستندات رسمی Node.js توضیح می‌دهند child_process.exec() Command را از طریق Shell اجرا می‌کند.

آیا WAF از Command Injection جلوگیری می‌کند؟

می‌تواند یک Layer کمکی باشد ولی جای Fix برنامه را نمی‌گیرد.

آیا Container کافی است؟

خیر. Container می‌تواند Impact را محدود کند، اما Vulnerability داخل Application همچنان باید برطرف شود.

Least Privilege چه کمکی می‌کند؟

باعث می‌شود Command احتمالی فقط با Permission محدود Process اجرا شود و Blast Radius کاهش پیدا کند.

آیا Command Injection فقط در Linux است؟

خیر. Windows، Linux، Unix و Environmentهای مختلف می‌توانند این Risk را داشته باشند.

آیا WordPress ممکن است Command Injection داشته باشد؟

Custom Plugin، Theme یا Extensionی که Program سیستم‌عامل را با Input غیرقابل اعتماد اجرا کند می‌تواند Vulnerable باشد.

آیا WordPress Core برای جلوگیری از آن کافی است؟

اگر Vulnerability در Plugin یا Server Integration باشد، Core به‌تنهایی آن را حل نمی‌کند.

چگونه Command Injection را تست کنیم؟

در Environment مجاز و ترجیحاً Staging، Data Flow تا Process Execution، Validation، Argument Separation و Shell Usage بررسی شود. تست نباید با Command مخرب روی سیستم Production انجام شود.

آیا Command Injection همیشه RCE است؟

Command Injection می‌تواند قابلیت اجرای Command ایجاد کند، اما Scope واقعی به Permission Process، Environment و محدودیت سیستم بستگی دارد.

جمع‌بندی

Command Injection یکی از جدی‌ترین ضعف‌های خانواده Injection است؛ زیرا مرز میان Web Application و Operating System را هدف قرار می‌دهد.

ریشه مشکل معمولاً ساده است:

Application می‌خواهد کاری در سیستم انجام دهد.

برای این کار Command String می‌سازد.

بخشی از String از User یا Data غیرقابل اعتماد می‌آید.

Shell آن String را دوباره به‌عنوان یک زبان تفسیر می‌کند.

از همین نقطه Data ممکن است تبدیل به Command شود.

بهترین دفاع این نیست که هر Character خطرناک Shell را پیدا و Block کنیم.

بهترین دفاع این است که اصلاً Input User وارد Shell Language نشود.

به همین دلیل OWASP در OS Command Injection Defense Cheat Sheet اولین گزینه را Avoid کردن Direct OS Command اعلام می‌کند و استفاده از Library Functionها را ترجیح می‌دهد.

اگر Application نیاز دارد Directory ایجاد کند، از API File System استفاده کند.

اگر Network Check نیاز دارد، از Network Library استفاده کند.

اگر Archive نیاز دارد، از Library امن استفاده کند.

هر بار که Shell حذف می‌شود، یک Parser و یک زبان اضافی از مسیر Input حذف می‌شود.

در شرایطی که اجرای Process خارجی واقعاً اجتناب‌ناپذیر است، Executable باید ثابت باشد و Argumentها به‌صورت ساختاریافته و جدا ارسال شوند.

User نباید Command Line بسازد.

User نباید مسیر Executable را انتخاب کند.

User نباید Argument آزاد و نامحدود داشته باشد.

Input باید Positive Allowlist داشته باشد.

Data Type باید مشخص باشد.

Enum به‌جای String آزاد استفاده شود.

Fileها با ID داخلی Resolve شوند.

در PHP، Functionهایی مانند escapeshellarg() و escapeshellcmd() ابزارهای مهمی هستند، اما نباید به‌عنوان مجوز ساخت Command از Input کاربر دیده شوند. مستندات PHP نیز آن‌ها را برای Context مشخص Shell تعریف می‌کنند، در حالی که OWASP همچنان Avoid کردن OS Command را راهکار اصلی می‌داند.

همزمان Application باید فرض کند هیچ Validationی کامل نیست.

به همین دلیل Process باید با Least Privilege اجرا شود.

Web Worker نباید Root باشد.

File System Access باید محدود باشد.

Network Egress فقط به Destinationهای لازم باز باشد.

Container باید Non-root و تا حد امکان Read-only باشد.

Secretهای غیرضروری نباید در Environment Process وجود داشته باشند.

Process Execution باید Timeout و Resource Limit داشته باشد.

در سایت‌های WordPress نیز تمرکز اصلی باید روی Pluginها و Integrationهایی باشد که Process خارجی اجرا می‌کنند.

وجود WordPress به‌تنهایی Command Injection ایجاد نمی‌کند.

اما Backup Plugin، Image Optimizer، PDF Generator، Video Converter، Migration Tool یا Custom Integration ممکن است Data را به Utility سیستم‌عامل منتقل کند.

سؤال صحیح در Security Review این است:

«آیا داده‌ای که User می‌تواند روی آن اثر بگذارد، در نهایت به API اجرای Process می‌رسد؟»

اگر پاسخ بله است، سؤال بعدی باید این باشد:

«آیا می‌توان Shell یا Process خارجی را کاملاً حذف کرد؟»

و اگر پاسخ باز هم خیر است:

«آیا Executable، Argument، Permission، Environment و Resourceها همگی به حداقل لازم محدود شده‌اند؟»

Command Injection زمانی بسیار سخت‌تر می‌شود که Application هیچ Command String قابل کنترل توسط User تولید نکند.

این همان اصل ساده‌ای است که تقریباً تمام دفاع‌های مؤثر به آن برمی‌گردند:

داده کاربر باید داده باقی بماند؛ نه اینکه در هیچ مرحله‌ای به دستور سیستم‌عامل تبدیل شود.

مطالب مرتبط