1 poin oleh GN⁺ 4 jam lalu | 1 komentar | Bagikan ke WhatsApp
  • Pada image container minimal, curl atau wget sering tidak tersedia, sehingga berguna punya cara alternatif untuk memeriksa konektivitas layanan internal tanpa memasang paket
  • Redireksi Bash /dev/tcp/host/port dapat membuka socket TCP, sehingga kita bisa menulis langsung string permintaan HTTP/1.1 dan membaca responsnya
  • /dev/tcp bukan path filesystem melainkan fitur internal Bash, jadi ls /dev/tcp atau pendekatan akses file biasa dari shell lain tidak akan berfungsi
  • Metode ini adalah teknik debugging sederhana yang tidak menangani redirect, respons chunked, kompresi, retry, atau TLS, dan tanpa Connection: close cat bisa terus menunggu
  • Untuk pekerjaan HTTP sehari-hari, curl tetap yang tepat, tetapi di container kecil yang sulit ditambahi tool, cara ini cukup untuk pemeriksaan koneksi cepat

Menulis permintaan HTTP dengan file descriptor Bash

  • Perlu memeriksa apakah endpoint /health dari layanan lain di jaringan Docker internal bisa diakses, tetapi image tidak memiliki curl atau wget
  • Bash dapat menghubungkan socket TCP ke file descriptor, sehingga kita bisa menulis dan mengirim permintaan HTTP secara langsung seperti berikut
exec 3<>/dev/tcp/service/8642
printf 'GET /health HTTP/1.1\r\nHost: service\r\nConnection: close\r\n\r\n' >&3
cat <&3
  • service harus berupa nama host yang dapat di-resolve dan dijangkau dari lokasi eksekusi
    • Bisa berupa nama container atau layanan yang disetel di jaringan Docker
    • Nama DNS yang dapat di-resolve juga bisa digunakan
    • Host dan port harus disesuaikan dengan lingkungan
  • Output respons mencakup status line, header, baris kosong, dan body sekaligus
  • Untuk menambahkan header, cukup tambahkan baris lain yang diakhiri \r\n sebelum baris kosong penutup permintaan
exec 3<>/dev/tcp/service/8642
printf 'GET /v1/models HTTP/1.1\r\nHost: service\r\nAuthorization: Bearer %s\r\nConnection: close\r\n\r\n' "$API_KEY" >&3
cat <&3

Mengapa /dev/tcp bukan file sungguhan

  • /dev/tcp bukan file perangkat nyata, melainkan redireksi yang ditangani Bash
    • Karena path tersebut tidak ada di disk, ls /dev/tcp akan gagal
    • Menjalankan cat /dev/tcp/... di shell lain juga akan menghasilkan error
  • Menurut manual Bash, pada /dev/tcp/host/port, jika host adalah nama host atau alamat internet yang valid dan port adalah nomor port integer atau nama layanan, Bash akan mencoba membuka socket TCP
  • Bash melakukan lookup DNS dan connect(2), lalu exec 3<> menghubungkan socket ke file descriptor 3 agar bisa dibaca dan ditulis

Bukan pengganti klien HTTP, melainkan alat pemeriksaan sementara

  • Pendekatan ini bukan klien HTTP sungguhan, sehingga tidak menangani redirect, respons chunked, kompresi, retry, TLS, dan sebagainya
  • Header Connection: close itu penting
    • Tanpanya, server bisa mempertahankan koneksi sesuai perilaku default HTTP/1.1
    • Dalam kasus itu, cat <&3 bisa menunggu EOF dan tidak pernah selesai
  • Membungkusnya dengan sesuatu seperti timeout 6 bash -c '...' juga berguna untuk berjaga-jaga jika koneksi tidak ditutup
  • /dev/tcp membuka socket mentah, jadi ini hanya berlaku untuk HTTP plaintext; untuk https, diperlukan openssl s_client
  • Ini bukan fitur POSIX melainkan fitur Bash, jadi tidak bisa digunakan di dash yang menjadi /bin/sh di Debian atau di zsh; Anda harus memanggil bash secara langsung
  • Saat build Bash, ini adalah opsi compile-time yang diaktifkan dengan --enable-net-redirections
  • Kesimpulannya, ini bukan alat umum untuk menggantikan curl, melainkan cocok untuk memeriksa konektivitas dengan cepat di container kecil tempat Anda tidak bisa menambahkan instalasi

1 komentar

 
GN⁺ 4 jam lalu
Komentar Hacker News
  • Saat masih kecil di akhir 90-an, saya kaget ketika tahu bahwa dengan telnet kita bisa terhubung ke port 80, 25, dan 110 lalu berbicara langsung dengan server
    Kita bisa mengetik sendiri permintaan sederhana seperti GET / HTTP/1.1, atau mengirim email lewat port 25 dengan HELO, mail-from, dan mail-to, lalu mengambil daftar kotak surat dan pesan individual lewat POP3
    Pengalaman ini menjadi awal dari kesadaran bahwa “tidak ada sihir”, dan bahwa semua bagian komputer dibuat oleh manusia serta pada tingkat tertentu bisa dipahami jika mau berusaha
    Di masa depan mungkin sebagian besar akan diserahkan ke agen, tetapi bagi orang yang ingin mempelajari cara kerja sebenarnya tanpa filter model dan pagar pengaman, tampaknya masih akan ada celah-celah menarik di berbagai sistem

    • Pada masa belum ada DKIM/SPF dan autentikasi server SMTP masih longgar, kita bisa mengirim email dengan alamat seperti jacques.chirac@elysee.fr dan terlihat seperti hacker di depan teman-teman
    • Saat itu bukan hanya DKIM maupun SPF yang belum ada, tetapi juga sebagian besar server SMTP adalah open relay yang menerima email dari siapa pun untuk dikirim ke siapa pun
    • Pada akhirnya semuanya cuma file teks
      Strukturnya hanyalah tumpukan singkatan di atas berbagai cara untuk membuat, mengirim, dan membaca file teks terstruktur
      Suatu hari saya sadar bahwa database pun pada dasarnya adalah file teks, dan saya sampai harus duduk diam sejenak
    • Pada abad lalu, saat membaca dan mengirim email pribadi di kantor, saya menangani semuanya dengan masuk ke POP3 dan SMTP masing-masing lewat telnet
    • Di HTTP/2 cara seperti ini tidak bisa dipakai, tetapi untungnya hampir semua server masih bisa berbicara HTTP/1
      TLS juga tidak bisa dengan telnet, dan banyak server hanya mengembalikan redirect untuk permintaan HTTP
      Kalau mengganti telnet dengan openssl s_client, kita memang bisa menyalurkan teks di dalam TLS, tetapi rasanya agak seperti akal-akalan
      Sayang juga karena banyak protokol modern lebih memilih encoding biner, sehingga makin sulit diutak-atik di level wire tanpa alat khusus
      Meski begitu, sepertinya akan selalu ada orang yang suka mendalaminya; seperti menyalakan api dengan tongkat atau membakar batu bata tanah liat, teknik lama itu menyenangkan dan kadang benar-benar berguna
      Bahkan AI justru mempermudah eksperimen, karena tanpa harus membongkar RFC kita bisa bertanya ke LLM dan mempelajari, misalnya, sebagian besar perintah IMAP yang umum
  • Di zsh, selain /dev/tcp milik Bash, ada juga modul zsh/net/tcp dan zsh/zftp
    https://zsh.sourceforge.io/Doc/Release/TCP-Function-System.h...
    https://zsh.sourceforge.io/Doc/Release/Zsh-Modules.html#The-...
    https://zsh.sourceforge.io/Doc/Release/Zftp-Function-System....

  • Di Plan 9 ada /net, sistem berkas sintetis sungguhan, sehingga pekerjaan seperti ini dan bahkan lebih dari itu bisa dilakukan dari program apa pun
    Dengan me-mount /net milik mesin lain lewat protokol 9P, itu bahkan bisa dipakai seperti VPN dadakan, dan hal ini bisa diuji di Linux lewat 9front
    Di pustaka Go juga masih terlihat jejak /net bergaya Plan 9, tampaknya ini warisan Rob Pike

  • Ini bekerja dengan baik di example.com
    Buka dengan exec 3<>/dev/tcp/example.com/80, kirim printf 'GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n' >&3, lalu jalankan cat <&3, maka akan keluar HTTP/1.1 200 OK
    Sekarang sudah terlalu sedikit domain yang tidak memaksa HTTPS, jadi untuk pengujian seperti ini ujung-ujungnya orang pergi ke example.com

    • Saat portal captive WiFi publik bermasalah, example.com juga berguna
      Jika di browser kita membuka http://example.com, kita akan diarahkan kembali ke halaman portal captive sehingga bisa menyelesaikan lagi prosedur akses internet
    • Kita juga bisa menaruh line break sungguhan di dalam printf
      \r memang seharusnya ada, tetapi tanpa itu pun tetap berjalan
  • Bisa juga bercanda bahwa kalau ingin berbicara dengan komputer teman, semua orang memakai bash -i >& /dev/tcp/IP/PORT 0>&1

  • Bash bukanlah yang "berbicara" HTTP, melainkan memungkinkan pembukaan soket TCP
    Yang dilakukan di sini adalah berbicara HTTP secara langsung; ini oke untuk pengujian atau debugging, dan seru kalau dicoba manual, tetapi memakai klien HTTP palsu seperti ini di lingkungan tanpa pengawasan pada akhirnya akan jadi bumerang
    Kode mainan ini bisa rusak karena tidak mem-parsing HTTP dengan benar
    Tentu saja, Anda juga bisa menulis klien HTTP/1.1 yang lengkap dengan Bash, dan bahkan membuat server HTTP Bash murni: https://github.com/bahamas10/bash-web-server
    Pilihan yang tidak segila itu biasanya adalah nc, dan umumnya itu lebih bijak

    • Ungkapan "server HTTP lengkap dengan Bash murni" sebenarnya tidak akurat
      Bash tidak bisa listen pada soket TCP/UDP untuk menerima koneksi masuk
      Proyek bash-web-server membangun socket listener dalam C, lalu memuatnya secara dinamis saat runtime sebagai modul “bawaan” untuk menyediakan fungsi tersebut
      [0] https://github.com/bahamas10/bash-web-server/tree/main/loada...
    • Koreksinya benar, dan karena ungkapan di tulisan itu berlebihan, saya akan memperbaruinya agar lebih akurat
      nc atau alat sejenis keluarga netcat memang pilihan yang lebih baik, tetapi image yang saya pakai saat itu tidak memiliki alat seperti itu
    • Tidak segila itu juga
      Saya sudah mengetik request HTTP dengan tangan sejak sebelum HTTP/1.1 dan header Host yang wajib ada
      Memakainya untuk tujuan serius memang tindakan gila, dan hal yang sama berlaku untuk membuat server web dengan Bash, tetapi untuk pengujian cepat ini cukup bagus
    • Seseorang bahkan membuat server Minecraft Bash murni
      https://sdomi.pl/weblog/15-witchcraft-minecraft-server-in-ba...
    • Ada juga framework mirip Rails untuk Bash: https://github.com/jneen/balls
  • Saya belajar soal ini setelah melihat tim Bauhinia memakainya saat menyelesaikan soal CTF
    Itu CTF bertahap; mula-mula mereka mendapatkan shell system lewat rantai ROP, tetapi lingkungannya pada dasarnya seperti penjara yang tidak bisa menjalankan apa pun selain Bash
    Yang bisa dipakai hanya read dan cat, jadi mereka menggunakan cat /dev/tcp, lalu mengarahkannya ke terminal virtual, membacanya, mendapatkan URL sistem internal, dan menemukan flag

  • Saya menemukan cara ini saat memeriksa koneksi antar-kontainer di jaringan Docker internal, ketika image tersebut tidak punya curl maupun wget
    Yang mengejutkan adalah Bash punya /dev/tcp, jadi dengan sedikit sihir shell kita bisa membuat sesuatu yang mirip request HTTP
    Misalnya buka dengan exec 3<>/dev/tcp/service/8642, kirim printf 'GET /health HTTP/1.1\r\nHost: service\r\nConnection: close\r\n\r\n' >&3, lalu jalankan cat <&3
    Di sini service adalah nama host tujuan koneksi, dan 8642 adalah port yang ingin diajak bicara dengan HTTP

    • Ini memang keren, tetapi saya penasaran apakah ada kekurangan jika kita cukup memakai image yang mendukung curl
      Saya tidak terpikir kekurangannya, dan menurut saya itu hampir wajib bahkan untuk image produksi
  • Dulu pada Debian lama dan distro turunan Debian, fitur ini tidak bekerja karena akses TCP melalui berkas virtual dinonaktifkan secara default
    Setahu saya, sikap itu berubah pada 2009 dan fiturnya diaktifkan; ada diskusi dan tautan di Bug #146464
    <https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=146464#37>
    Selain ini, ada banyak cara lain untuk mengakses fungsi jaringan langsung dari alat shell, seperti curl, wget, perintah HEAD dan GET milik Perl, netcat/nc, socat, telnet, dan lain-lain

  • Saya masih ingat saat remaja mengejutkan orang dengan mengirim pesan menyeramkan ke /dev/ptty mereka memakai echo
    Pesan yang saya kirim muncul seperti sihir di terminal mereka yang sedang terbuka
    Sampai sekarang saya tidak tahu kenapa lab komputer itu membuat tiap klien memakai akun yang berbeda sehingga tidak dikunci, dan mungkin itu memang keterbatasan VAX saat itu