- Checksum database Go dan public module proxy dapat menerima bahkan repositori yang tidak memiliki kode Go, sehingga tercipta jalur untuk memuat data repositori Git arbitrer ke infrastruktur Go lalu mengunduhnya kembali
- Permintaan
sum.golang.org/lookup/$module@$versionakan mengambil dari server asal saat menemukan versi modul yang belum tercatat, dan dalam proses ini zip repositori tersebut juga disediakan diproxy.golang.org - Repositori Ruby milik Homebrew dan fork repositori Rust ditemukan di checksum database, dan eksperimen mendaftarkan repositori tanpa berkas Go sekalipun dengan pseudo-version berhasil dilakukan
- Zip modul dibatasi maksimum 500 MiB baik dalam bentuk terkompresi maupun tidak terkompresi, tetapi ukuran ini masih cukup besar untuk melewati batas unduhan di mesin pengembang/CI/CD, menyimpan payload, dan mengimplementasikan C2
- Dari sekitar 1,59 juta jalur unik di
sum.golang.org, sekitar 1,51 juta adalah jalur GitHub atau sekitar 95%, yang sekaligus memperlihatkan ketergantungan ekosistem Go pada GitHub dan potensi penyalahgunaan public proxy
Repositori non-Go yang ditemukan di Go checksum database
- Saat menelusuri checksum database milik Go,
github.com/homebrew/homebrew-coremuncul sangat sering di tabelmodulesgithub.com/homebrew/homebrew-core: 39.438github.com/Homebrew/homebrew-core: 30.896github.com/concourse/concourse: 25.372github.com/openshift/release: 24.065github.com/cilium/cilium: 22.138
- Repositori Homebrew dikenal menggunakan Ruby, dan baik di repositori maupun berkas hasil kloning tidak ditemukan
go.modatau berkas sumber Go - Perbedaan huruf besar/kecil dijelaskan oleh aturan case encoding di dokumentasi Go
- Huruf besar dienkode sebagai
!dan huruf kecil terkait, sehinggaexample.com/Mdanexample.com/mdapat disimpan bersama bahkan pada sistem berkas yang tidak membedakan huruf besar/kecil
- Huruf besar dienkode sebagai
github.com/Edu4rdSHL/rust-headless-chromejuga muncul di checksum database meski merupakan fork repositori Rust yang tidak terkait Go
Cara /lookup mengambil repositori
- Menurut Go Modules Reference dalam dokumentasi modul Go, saat memeriksa checksum database, perintah Go terlebih dahulu mengambil data rekaman dari endpoint
/lookup - Jika versi modul belum tercatat di log, checksum database akan mencoba mengambil modul tersebut dari server asal sebelum memberikan respons
- Format endpoint adalah
$base/lookup/$module@$version- Mengembalikan nomor rekaman log untuk
$versiondari$module, barisgo.sum, dan deskripsi tree yang ditandatangani
- Mengembalikan nomor rekaman log untuk
- Saat pseudo-version untuk
github.com/homebrew/homebrew-corediminta, checksum record dan hashgo.moddikembalikan - Jika repositori tidak memiliki tag versi, aturan pseudo-version milik Go akan digunakan
Eksperimen mendaftarkan modul Go baru
- Setelah membuat modul Go baru
github.com/gdbinit/fluxmatter, status pendaftarannya diperiksa melalui permintaanlookup - Pencarian
@latestmengembalikan kesalahan bahwa itu bukan canonical versionbad request: version "latest" is not canonical
- Pencarian
@v0.0.0mengembalikan kesalahan bahwa revision tersebut tidak dikenalnot found: ... invalid version: unknown revision v0.0.0
- Namun setelah checksum database disinkronkan lagi dan diperiksa ulang, modul tersebut ternyata sudah terdaftar
github.com/gdbinit/fluxmatter|v0.0.0-20240524163826-a7e64ffd69f2|2024-05-24T16:40:51.203837Z
proxy.golang.org/github.com/gdbinit/fluxmatter/@latestmengembalikan pseudo-version dan informasi asal GitHub, dan berkas zip untuk versi tersebut juga bisa diunduh serta diverifikasi kompresinya- Pada proses seeding awal, tidak perlu menentukan versi yang tepat; cukup dengan kueri lookup yang berisi jalur modul dan nilai yang tampak seperti versi
Repositori tanpa kode Go juga dimuat ke public proxy
- Eksperimen yang sama berhasil dilakukan dengan repositori
github.com/gdbinit/readmemyang sama sekali tidak memiliki kode Go - Permintaan
lookupmemang mengembalikan kesalahan bahwa revisionv0.0.0tidak dikenal, tetapi checksum database tetap mencatatnya sebagai pseudo-versiongithub.com/gdbinit/readmem|v0.0.0-20131006075740-407cb0a56933|2024-05-24T16:45:35.88456Z
@latestdiproxy.golang.orgmengembalikan pseudo-version repositori tersebut dan informasi asal Git- Zip yang diunduh tidak berisi berkas Go, melainkan
Entitlements.plist,README, berkas proyek Xcode,main.c, dan lainnya - Eksperimen ini menggunakan repositori GitHub, tetapi jika VCS lain berfungsi, hal serupa mungkin juga dapat dilakukan di situs hosting lain
Ketergantungan pada GitHub dan batas ukuran
- Jumlah jalur unik di checksum database adalah 1.591.375, dan di antaranya 1.515.957 jalur berupa
github.com% - Sekitar 95% dari jalur unik dihosting di GitHub {p:95}
- Angka ini adalah statistik mentah yang belum menghapus fork atau target yang sebenarnya bukan kode Go
- Zip modul Go tunduk pada File path and size constraints
- berkas zip modul maksimal 500 MiB
- total ukuran berkas dalam bentuk tidak terkompresi juga maksimal 500 MiB
- berkas
go.modmaksimal 16 MiB - berkas
LICENSEjuga maksimal 16 MiB
- Batas ini ditujukan untuk meredam serangan denial of service terhadap pengguna, proxy, dan bagian lain dari ekosistem modul
- Namun 500 MiB tetap cukup besar bila mempertimbangkan potensi penyalahgunaan
Skenario penyalahgunaan yang mungkin
- Public Go proxy dapat dipakai untuk melewati pembatasan tujuan unduhan pada mesin pengembang atau server CI/CD
- Dengan asumsi tidak ada
GOPROXYprivat - Malware dapat mengunggah payload ke repositori lalu mengunduhnya dari proxy saat dibutuhkan
- Bahkan jika sumber asli hilang, entri checksum database mungkin hanya menyisakan jejak kecil
- Dengan asumsi tidak ada
- DoS terhadap
proxy.golang.orgmungkin tidak mudah dijalankan- Proxy dapat dipaksa mengunduh repositori Git arbitrer
- Salah satu serangan yang mungkin adalah mengumpulkan banyak URL GitHub lalu mengirim banyak permintaan ke API
lookup - Implementasi server tidak diketahui, tetapi mungkin ada pembatasan paralel seperti work queue
- Perlindungan bandwidth di sisi GitHub juga mungkin aktif
- Ada juga kemungkinan DoS yang menargetkan penyimpanan, tetapi ini masih sebatas dugaan
- C2 (command and control) dapat dibuat dengan mudah di atas
proxy.golang.org- Kueri
@latestdapat digunakan untuk menemukan versi terbaru modul tertentu - Payload bisa berupa berkas biasa, atau disembunyikan di dalam
go.modmaupun berkas sumber Go - Untuk menghindari penggunaan satu repositori saja, dapat digunakan module DGA
- Kueri
Alur unduhan C2
- Agar implant dapat menerima perintah, langkah-langkah berikut cukup dilakukan
- minta
https://proxy.golang.org/module_path/@latest - ambil pseudo-version atau version dari hasil JSON
- unduh zip lewat
https://proxy.golang.org/module_path/@v/version.zip - ekstrak isi zip dan parse perintah
- minta
- Alur ini cukup sederhana hingga bisa diimplementasikan dalam kurang dari 300 baris kode Go
Kesimpulan dan pertanyaan yang tersisa
- Checksum database dan proxy Go, sesuai prosedur yang terdokumentasi, dapat mengambil dan menyimpan modul yang belum tercatat dari server asal
- Kondisi saat ini tampaknya belum terlihat sebagai masalah serius bagi infrastruktur Go, tetapi cukup mudah disalahgunakan dan masih ada ruang untuk perbaikan
- Mungkin ada alasan yang terdokumentasi atau tidak dipublikasikan mengapa repositori non-Go boleh masuk ke proxy dan checksum database
- Untuk memastikan apakah ini sudah disalahgunakan seseorang, perlu menyelidiki sekitar 1,6 juta repositori unik dan sekitar 22 juta entri berdasarkan database lokal terbaru
- Mengapa sebagian proyek non-Go yang valid berada di database masih menjadi pertanyaan terbuka
1 komentar
Komentar Hacker News
Layanan online tempat pengguna mengunggah materi dan materi itu terlihat publik pada akhirnya akan dipakai untuk command-and-control, pelanggaran hak cipta, dan hosting CSAM
Hal ini terutama berlaku untuk layanan yang sulit diblokir karena punya kegunaan penting selain file hosting; ini sudah terjadi di Twitter[1], Telegram[2], dan infrastruktur kunci PGP[3], belum lagi target yang sudah jelas seperti GitHub
[1] https://pentestlab.blog/2017/09/26/command-and-control-twitt...
[2] https://www.blazeinfosec.com/post/leveraging-telegram-as-a-c...
[3] https://torrentfreak.com/openpgp-keyservers-now-store-irremo...
Untuk Gmail, kredensial dibagikan agar orang bisa login, lalu membaca lampiran yang telah diunggah lewat IMAP
Saya dulu bekerja di Google SAD-SRE (Spam, Abuse, Delivery)
File juga bisa di-encode ke Base64 lalu dimasukkan ke dalam string kode Python
Saya seorang Googler dan ini pendapat pribadi; saya tidak terlalu paham bidang ini
Saya berharap tim Go sudah berkolaborasi dengan pihak GCP dan Drive, karena hosting file berbahaya adalah masalah yang selalu ditangani Google
Ini tidak terlalu berbeda dari endpoint lain yang sudah diizinkan Google untuk menerima data arbitrer dari orang
Google sangat mahir mengelola infrastruktur lewat tim pusat dan membagikannya ke seluruh perusahaan. Kecuali aplikasi messenger, tentu. Ini murni dugaan, tetapi tim Go mungkin menggunakan blob storage internal, dan mungkin juga ada tim infrastruktur internal yang otomatis menangani mitigasi penyalahgunaan serta pemindaian file
Di PyPI juga ada cukup banyak proyek non-Python
Python membutuhkan kemampuan mendistribusikan wheel, yaitu biner hasil kompilasi, karena pengguna mungkin tidak bisa mengompilasi kode library sendiri
Kode seperti itu sering ditulis dalam C, tetapi Golang[1] juga bisa, dan meski saya tidak menemukan contohnya, saya rasa saya pernah melihatnya dipakai untuk mendistribusikan aplikasi, bukan library
Menulis aplikasi dalam C, mengunggahnya ke PyPI, lalu menyuruh pengguna menginstalnya dengan
pip installitu cukup keren[1] https://github.com/popatam/gopy_build_wheel_example
Di Linux,
lspun pada dasarnya bisa dianggap ditulis dengan Python, jadi mungkin lebih baik tidak memainkan permainan seperti inipipmulai mengharuskan paket diunduh dari dalam lingkungan seperti venv/virtualenv/pipenv/pyenv, kegunaan seperti ini mungkin jauh lebih bermanfaatpip install cmake, dan biner proprietari juga bisa sepertipip install nvidia-cudnn-cu12Itu salah satu alasan saya bisa sepenuhnya meninggalkan Homebrew
Mungkin ini pemikiran yang naif, tetapi saya tidak tahu apa bedanya dengan mengunggah file ke repositori GitHub
Apakah bedanya cuma GitHub mewajibkan pembuatan akun? Di GitHub juga bisa menyimpan data arbitrer, dan tidak ada batas 500MB
Sistem modul CUE akhirnya mulai dirilis, dan MVS mirip dengan Go, tetapi dibangun di atas infrastruktur OCI
Jika Anda tertarik pada sistem manajemen dependensi, ini beberapa tautan yang layak dilihat
proposal: https://github.com/cue-lang/proposal/tree/main/designs/modul...
custom registry: https://cuelang.org/docs/tutorial/working-with-a-custom-modu...
road map: https://github.com/orgs/cue-lang/projects/10/views/8
Mulai 0.9.0-alpha-5, modul diaktifkan secara default: https://github.com/cue-lang/cue/releases/tag/v0.9.0-alpha.5
Di Go Sum, proyek Trillian menopang transparency log: https://github.com/google/trillian
Rencananya CUE akan memanfaatkan opsi OCI seperti attestation
Saya sempat bereksperimen dengan ide menumpangi, atau lebih tepatnya menyalahgunakan, golang proxy dan sumdb untuk membuat log transparansi gratis bagi checksum dari URL arbitrer
https://getsum.pub/
Jika yang diinginkan hanya log transparansi publik, instance rekor publik dari proyek sigstore jauh lebih cocok
https://www.sigstore.dev/
https://docs.sigstore.dev/logging/overview/
Mungkin saya yang bodoh, tapi saya tidak paham persis apa masalahnya di sini
Memang agak boros jika proxy meng-cache repositori non-Go, tetapi bahkan tanpa itu pun, kalau kita bisa membuatnya meng-cache repositori Go, bukankah pada akhirnya kita tetap bisa memaksanya menyimpan data arbitrer?
Kalau saya tidak melewatkan sesuatu, ini terdengar seperti bukan masalah besar sama sekali
Hal baru di sini tampaknya hanya bahwa proxy publik yang tidak aman menerima apa yang akan diproksikan lalu menyediakannya secara publik dengan cara yang juga tidak aman
Tulisan itu mengatakan bahwa beberapa jaringan yang diawasi mungkin lebih memercayai URL golang proxy daripada URL web arbitrer, sehingga ini bisa dipakai untuk melewati filter reputasi dan semacamnya, tetapi cara seperti itu sudah banyak, dan pendekatan ini tidak terlihat istimewa
Agak di luar topik, tetapi melihat domainnya membuat saya curiga ada permainan kata yang tidak enak, jadi saya memeriksa put.as, dan isinya kurang lebih seperti yang saya duga
Ini isu yang sudah dikenal: https://github.com/golang/go/issues/31866
.moddan.godi root?Dia dan Aaron membuat Athens, dan sejauh yang saya tahu Marwan menulis implementasi awal protokol unduhan Go yang kemudian menjadi dasar Athens
Hal menarik dari isu ini adalah bahwa Athens sudah menggunakan perintah
go mod download -jsonyang disebutkan sebagai pemeriksaan awal untuk validasi modulPada dasarnya, jika sebuah repositori lolos sebagai modul yang dipahami oleh perintah modul Go, Athens akan menyajikannya
Kalau mau mengatakannya dengan istilah yang lebih terlarang, kita harus bisa membuat versi modul, pseudo-version, dan
+incompatible, serta membuat checksum yang valid untuk modul itu dan dependensinyaChecksum modul saat ini berkaitan dengan penyertaan
.mod, semua file, dan tiap dependensi secara rekursifJadi seperti yang dikatakan penulis, hanya dengan program Go yang sangat dasar pun, secara desain kita bisa mendapatkan banyak ruang untuk file arbitrer
W3C telah meletakkan dasar agar segala sesuatu di web bisa di-cache secara kuat, jadi aneh kalau cache proxy serbaguna jumlahnya sangat sedikit
Apakah para penerbit mengirim respons seperti
Cache-Control: max-ageyang pendek atauVary: Cookiepadahal tidak perlu?Apakah ISP membayar biaya transit terlalu mahal dibanding peering?
Misalnya, pada situs non-HTTPS, proxy ISP bisa menyisipkan iklan
Unduhan perangkat lunak biasanya punya tanda tangan dan checksum, tetapi konten arbitrer umumnya tidak punya itu