Sangat menyebalkan memiliki batasan ini pada kotak pengembangan saya, ketika tidak akan ada pengguna selain saya.
Saya mengetahui solusi standar , tetapi tidak ada yang melakukan persis apa yang saya inginkan:
- authbind (Versi dalam pengujian Debian, 1.0, hanya mendukung IPv4)
- Menggunakan target iptables REDIRECT untuk mengarahkan ulang port rendah ke port tinggi (tabel "nat" belum diterapkan untuk ip6tables, versi iptables IPv6)
- sudo (Menjalankan sebagai root adalah apa yang saya coba hindari)
- SELinux (atau serupa). (Ini hanya kotak dev saya, saya tidak ingin memperkenalkan banyak kompleksitas tambahan.)
Apakah ada beberapa sysctl
variabel sederhana untuk memungkinkan proses non-root untuk mengikat ke port "istimewa" (port kurang dari 1024) di Linux, atau apakah saya hanya kurang beruntung?
EDIT: Dalam beberapa kasus, Anda dapat menggunakan kemampuan untuk melakukan ini.
Jawaban:
Oke, terima kasih kepada orang-orang yang menunjukkan kemampuan sistem dan
CAP_NET_BIND_SERVICE
kemampuan. Jika Anda memiliki kernel terbaru, memang mungkin untuk menggunakan ini untuk memulai layanan sebagai port non-root tetapi mengikat rendah. Jawaban singkatnya adalah Anda melakukannya:Dan kemudian kapan saja
program
dieksekusi setelah itu akan memilikiCAP_NET_BIND_SERVICE
kemampuan.setcap
ada dalam paket debianlibcap2-bin
.Sekarang untuk peringatan:
program
yang memiliki hak istimewa sepertisetcap
atausuid
. Jadi jika Andaprogram
menggunakan sendiri.../lib/
, Anda mungkin harus melihat ke opsi lain seperti penerusan porta.Sumber:
setcap
.Catatan: RHEL pertama kali menambahkan ini di v6 .
sumber
/usr/bin/java
dan kemudian akan membuka kemampuan untuk aplikasi java yang berjalan pada sistem. Kemampuan yang terlalu buruk juga tidak dapat diatur per pengguna./etc/security/capability.conf
di Debian / Ubuntu ada bantuan?Anda dapat melakukan redirect port. Inilah yang saya lakukan untuk server kebijakan Silverlight yang berjalan pada kotak Linux
sumber
/etc/network/if-up.d/firewall
.Cara standar adalah membuat mereka "setuid" sehingga mereka mulai sebagai root, dan kemudian mereka membuang privilege root itu segera setelah mereka terikat ke port tetapi sebelum mereka mulai menerima koneksi ke sana. Anda dapat melihat contoh yang bagus dari itu dalam kode sumber untuk Apache dan INN. Saya diberitahu bahwa Lighttpd adalah contoh bagus lainnya.
Contoh lain adalah Postfix, yang menggunakan banyak daemon yang berkomunikasi melalui pipa, dan hanya satu atau dua di antaranya (yang sangat sedikit kecuali menerima atau memancarkan byte) dijalankan sebagai root dan sisanya dijalankan pada privilege yang lebih rendah.
sumber
binfmt_misc
dan bendera 'C'; Saya tidak yakin tentang yang lain.)Atau tambal kernel Anda dan hapus centangnya.
(Opsi pilihan terakhir, tidak disarankan).
Di
net/ipv4/af_inet.c
, hapus dua baris yang bertuliskandan kernel tidak akan memeriksa port privilege lagi.
sumber
Anda dapat mengatur terowongan SSH lokal, mis. Jika Anda ingin port 80 mencapai aplikasi Anda terikat 3000:
Ini memiliki keuntungan bekerja dengan server skrip, dan menjadi sangat sederhana.
sumber
sudo nc -l 80 | nc localhost 3000
Pembaruan 2017:
Gunakan authbind
Jauh lebih baik daripada CAP_NET_BIND_SERVICE atau kernel khusus.
Authbind memberikan kepercayaan kepada pengguna / grup dan memberikan kontrol atas akses per-port, dan mendukung IPv4 dan IPv6 (dukungan IPv6 telah ditambahkan pada akhir-akhir ini).
Install:
apt-get install authbind
Konfigurasikan akses ke port yang relevan, mis. 80 dan 443 untuk semua pengguna dan grup:
Jalankan perintah Anda melalui
authbind
(tentukan secara opsional
--deep
atau argumen lain, lihat halaman manual):misalnya
Sebagai tindak lanjut dari rekomendasi Joshua yang luar biasa (= tidak disarankan kecuali Anda tahu apa yang Anda lakukan) untuk meretas kernel:
Saya pertama kali mempostingnya di sini .
Sederhana. Dengan kernel normal atau lama, Anda tidak.
Seperti yang ditunjukkan oleh yang lain, iptables dapat meneruskan sebuah port.
Seperti yang ditunjukkan oleh yang lain, CAP_NET_BIND_SERVICE juga dapat melakukan pekerjaan itu.
Tentu saja CAP_NET_BIND_SERVICE akan gagal jika Anda meluncurkan program Anda dari skrip, kecuali jika Anda menetapkan batas pada penerjemah shell, yang tidak ada gunanya, Anda bisa menjalankan layanan Anda sebagai root ...
misalnya untuk Java, Anda harus menerapkannya ke JAVA JVM
Jelas, itu berarti program Java apa pun dapat mengikat port sistem.
Dito untuk mono / .NET.
Saya juga cukup yakin xinetd bukan yang terbaik dari ide.
Tetapi karena kedua metode ini adalah peretasan, mengapa tidak hanya mengangkat batas dengan mengangkat batasan?
Tidak ada yang mengatakan Anda harus menjalankan kernel normal, jadi Anda bisa menjalankan kernel Anda sendiri.
Anda cukup mengunduh sumber untuk kernel terbaru (atau yang sama dengan yang Anda miliki saat ini). Setelah itu, Anda pergi ke:
Di sana Anda mencari baris ini
dan ubah ke
jika Anda tidak ingin memiliki situasi ssh tidak aman, Anda mengubahnya menjadi ini: #define PROT_SOCK 24
Secara umum, saya akan menggunakan pengaturan terendah yang Anda butuhkan, misalnya 79 untuk http, atau 24 saat menggunakan SMTP pada port 25.
Itu saja.
Kompilasi kernel, dan instal.
Mulai ulang.
Selesai - batas bodoh itu PERLU, dan itu juga berfungsi untuk skrip.
Inilah cara Anda mengompilasi kernel:
https://help.ubuntu.com/community/Kernel/Compile
Singkatnya, gunakan iptables jika Anda ingin tetap aman, kompilasi kernel jika Anda ingin memastikan pembatasan ini tidak pernah mengganggu Anda lagi.
sumber
Kemampuan file tidak ideal, karena mereka dapat rusak setelah pembaruan paket.
Solusi ideal, IMHO, adalah kemampuan untuk membuat shell dengan
CAP_NET_BIND_SERVICE
set yang dapat diwarisi .Berikut cara yang agak berbelit-belit untuk melakukan ini:
capsh
utilitas dapat ditemukan dalam paket libcap2-bin di distribusi Debian / Ubuntu. Inilah yang terjadi:sg
mengubah ID grup yang efektif menjadi ID pengguna daemon. Ini diperlukan karenacapsh
membuat GID tidak berubah dan kami jelas tidak menginginkannya.$DAEMONUSER
--keep=1
), kecuali diturunkancap_net_bind_service
Hasilnya adalah proses dengan pengguna dan grup tertentu, dan
cap_net_bind_service
hak istimewa.Sebagai contoh, baris dari
ejabberd
skrip startup:sumber
capsh
melakukan apa pun selain "tidak dapat mengeksekusi file biner" saat menggunakan opsi--
atau==
. Saya ingin tahu apa yang saya lewatkan.--
diteruskan ke/bin/bash
, jadi Anda mungkin ingin mencobanya-c 'your command'
. Sayangnya, saya sepertinya mengalami masalah yang sama dengan @Cyberax, karena saya mendapatkan "izin ditolak" ketika mencobabind
.--gid
bukansg
(atau--user
yang set--uid
,--gid
dan--groups
):sudo capsh --caps='cap_net_bind_service+eip cap_setpcap,cap_setuid,cap_setgid+ep' --keep=1 --user="$service_user" --addamb=cap_net_bind_service -- -c 'exec $service $service_args'
Untuk beberapa alasan tidak ada yang menyebutkan tentang menurunkan sysctl net.ipv4.ip_unprivileged_port_start dengan nilai yang Anda butuhkan. Contoh: Kita perlu mengikat aplikasi kita ke port 443.
Beberapa orang mungkin mengatakan, ada masalah keamanan potensial: pengguna yang tidak memiliki hak sekarang dapat mengikat ke port istimewa lainnya (444-1024). Tetapi Anda dapat mengatasi masalah ini dengan mudah dengan iptables, dengan memblokir port lain:
Perbandingan dengan metode lain. Metode ini:
Tergantung pada situasinya, saya akan memilih antara sysctl, CAP, authbind dan iptables-redirect. Dan ini luar biasa karena kami memiliki begitu banyak pilihan.
sumber
Dua kemungkinan sederhana lainnya:
Ada solusi lama (tidak modis) untuk "a daemon yang mengikat port rendah dan kontrol tangan ke daemon Anda". Ini disebut inetd (atau xinetd). Kontra adalah:
Pro:
Alternatif lain: proxy yang diretas (netcat atau bahkan sesuatu yang lebih kuat ) dari port istimewa ke beberapa port bernomor tinggi sewenang-wenang di mana Anda dapat menjalankan daemon target Anda. (Netcat jelas bukan solusi produksi, tetapi "hanya kotak dev saya", kan?). Dengan cara ini Anda dapat terus menggunakan versi server yang mampu jaringan, hanya perlu root / sudo untuk memulai proxy (saat boot), tidak akan mengandalkan kapabilitas yang kompleks / berpotensi rapuh.
sumber
"Pemecahan masalah standar" saya menggunakan socat sebagai pengalih ruang-pengguna:
Berhati-hatilah karena ini tidak akan menjadi masalah, forking itu mahal tapi itu cara socat bekerja.
sumber
Linux mendukung kemampuan untuk mendukung izin yang lebih halus daripada hanya "aplikasi ini dijalankan sebagai root". Salah satu kemampuan itu
CAP_NET_BIND_SERVICE
adalah tentang mengikat ke port istimewa (<1024).Sayangnya saya tidak tahu bagaimana cara mengeksploitasi itu untuk menjalankan aplikasi sebagai non-root saat masih memberikannya
CAP_NET_BIND_SERVICE
(mungkin menggunakansetcap
, tetapi pasti ada solusi yang ada untuk ini).sumber
Saya tahu ini adalah pertanyaan lama, tetapi sekarang dengan kernel terbaru (> = 4.3) akhirnya ada jawaban yang bagus untuk ini - kemampuan sekitar.
Jawaban cepatnya adalah mengambil salinan libcap versi terbaru (yang belum dirilis) dari git dan mengompilasinya. Salin
progs/capsh
biner yang dihasilkan di suatu tempat (/usr/local/bin
merupakan pilihan yang baik). Kemudian, sebagai root, mulailah program Anda denganAgar, kita
cap_net_bind_service
kemampuan ke set yang diwarisi & ambientbash -c 'your-command'
(karenacapsh
secara otomatis memulai bash dengan argumen setelah--
)Ada banyak hal yang terjadi di bawah tenda di sini.
Pertama, kami menjalankan sebagai root, jadi secara default, kami mendapatkan set lengkap kemampuan. Termasuk dalam ini adalah kemampuan untuk beralih uid & gid dengan
setuid
dansetgid
syscalls. Namun, biasanya ketika sebuah program melakukan ini, ia kehilangan set kemampuannya - ini adalah cara lama menjatuhkan root dengansetuid
masih bekerja. The--keep=1
bendera mengatakancapsh
untuk mengeluarkanprctl(PR_SET_KEEPCAPS)
syscall, yang menonaktifkan menjatuhkan kemampuan ketika mengubah pengguna. Perubahan pengguna yang sebenarnyacapsh
terjadi dengan--user
flag, yang berjalansetuid
dansetgid
.Masalah berikutnya yang perlu kita selesaikan adalah bagaimana mengatur kemampuan dengan cara yang dijalankan setelah kita
exec
menjadi anak-anak kita. Sistem kapabilitas selalu memiliki seperangkat kapabilitas 'yang diwarisi', yang merupakan "seperangkat kapabilitas yang dipertahankan di seluruh execve (2)" [ kapabilitas (7) ]. Sementara ini terdengar seperti itu memecahkan masalah kami (hanya mengaturcap_net_bind_service
kemampuan untuk diwarisi, kan?), Ini sebenarnya hanya berlaku untuk proses istimewa - dan proses kami tidak istimewa lagi, karena kami sudah mengubah pengguna (dengan--user
bendera).Set kemampuan ambient baru mengatasi masalah ini - itu adalah "seperangkat kemampuan yang dipertahankan di seluruh (2) program yang tidak diistimewakan." Dengan meletakkan
cap_net_bind_service
di ambient set, ketikacapsh
exec adalah program server kami, program kami akan mewarisi kemampuan ini dan dapat mengikat pendengar ke port rendah.Jika Anda tertarik untuk mempelajari lebih lanjut, halaman manual kemampuan menjelaskan ini dengan sangat rinci. Menjalankan
capsh
melaluistrace
juga sangat informatif!sumber
--addamb
bendera diperkenalkan dengan libcap 2,26. Sistem saya memiliki 2,25 dan saya harus membangun dari sumber.TLDR: Untuk "jawabannya" (seperti yang saya lihat), lompat ke bagian >> TLDR << dalam jawaban ini.
OK, saya sudah menemukan jawabannya (untuk yang sebenarnya kali ini), jawaban untuk pertanyaan ini, dan jawaban saya ini juga merupakan cara meminta maaf karena mempromosikan jawaban lain (baik di sini maupun di twitter) yang saya pikir adalah "yang terbaik ", tetapi setelah mencobanya, ternyata saya salah tentang itu. Belajarlah dari kesalahan anak-anak saya: jangan mempromosikan sesuatu sampai Anda benar-benar mencobanya sendiri!
Sekali lagi, saya meninjau semua jawaban di sini. Saya sudah mencoba beberapa dari mereka (dan memilih untuk tidak mencoba yang lain karena saya tidak suka solusinya). Saya berpikir bahwa solusinya adalah menggunakan
systemd
dengan yangCapabilities=
danCapabilitiesBindingSet=
pengaturan. Setelah bergulat dengan ini selama beberapa waktu, saya menemukan bahwa ini bukan solusi karena:Kemampuan dimaksudkan untuk membatasi proses root!
Seperti yang dikatakan OP dengan bijak, selalu yang terbaik untuk menghindari itu (untuk semua dasmon Anda jika memungkinkan!).
Anda tidak dapat menggunakan opsi terkait Kemampuan dengan
User=
danGroup=
dalamsystemd
file unit, karena kemampuan SELALU diatur ulang ketikaexecev
(atau apa pun fungsinya) dipanggil. Dengan kata lain, saatsystemd
fork dan drop permsnya, kapabilitas direset. Tidak ada jalan lain untuk hal ini, dan semua logika yang mengikat dalam kernel adalah dasar di sekitar uid = 0, bukan kemampuan. Ini berarti bahwa kecil kemungkinan Kapabilitas akan menjadi jawaban yang tepat untuk pertanyaan ini (setidaknya dalam waktu dekat). Kebetulan,setcap
seperti yang disebutkan orang lain, bukanlah solusi. Itu tidak berfungsi untuk saya, tidak berfungsi dengan baik dengan skrip, dan itu akan diatur ulang kapan pun file berubah.Dalam pertahanan saya yang sedikit, saya menyatakan (dalam komentar yang sekarang saya hapus), bahwa saran iptables James (yang juga disebutkan oleh OP), adalah "solusi terbaik ke-2". :-P
>> TLDR <<
Solusinya adalah menggabungkan
systemd
denganiptables
perintah on-the-fly , seperti ini ( diambil dari DNSChain ):Di sini kita mencapai yang berikut:
iptables
systemd
membersihkan aturan firewall untuk kami, pastikan untuk menghapusnya ketika daemon tidak berjalan.systemd
diklaim), konon bahkan jika daemon dikompromikan dan ditetapkanuid=0
.iptables
masih, sayangnya, utilitas yang cukup jelek dan sulit digunakan. Jika daemon sedang mendengarkaneth0:0
alih-aliheth0
, misalnya, perintahnya sedikit berbeda .sumber
eth0:0
lagi kecuali mereka memiliki distribusi Linux yang sangat kuno . Mereka telah ditinggalkan selama bertahun-tahun dan pada akhirnya akan pergi.# Generated by SolusVM
AmbientCapabilities=CAP_NET_BIND_SERVICE
bekerja dengan sangat baik untuk saya dalam kombinasi denganUser=
.systemd adalah pengganti sysvinit yang memiliki opsi untuk meluncurkan daemon dengan kemampuan spesifik. Options Capabilities =, CapabilityBoundingSet = di manual systemd.exec (5) .
sumber
systemd
.Port redirect paling masuk akal bagi kami, tetapi kami mengalami masalah di mana aplikasi kami akan menyelesaikan url secara lokal yang juga perlu dirutekan ulang; (itu berarti Anda heboh ).
Ini juga akan memungkinkan Anda untuk dialihkan ketika mengakses url pada mesin lokal.
sumber
Linux modern mendukung
/sbin/sysctl -w net.ipv4.ip_unprivileged_port_start=0
.sumber
Dengan systemd, Anda hanya perlu sedikit memodifikasi layanan Anda untuk menerima soket yang sudah diaktifkan.
Anda nantinya dapat menggunakan systemd socket activ .
Tidak diperlukan kemampuan, iptables atau trik lain.
Ini adalah konten file systemd yang relevan dari contoh server http python sederhana ini
Mengajukan
httpd-true.service
Mengajukan
httpd-true.socket
sumber
Saat memulai:
Kemudian Anda dapat mengikat ke port yang Anda tuju.
sumber
--to-port
adaman iptables
hanya menyebutkan--to-ports
(jamak).systemd
.Gunakan utilitas privbind : memungkinkan aplikasi yang tidak terjangkau mengikat ke port yang dipesan.
sumber
Ada juga 'djb way'. Anda dapat menggunakan metode ini untuk memulai proses Anda sebagai root berjalan pada port apa pun di bawah tcpserver, maka itu akan menyerahkan kontrol proses kepada pengguna yang Anda tentukan segera setelah proses dimulai.
Untuk info lebih lanjut, lihat: http://thedjbway.b0llix.net/daemontools/uidgid.html
sumber
Karena OP hanya pengembangan / pengujian, solusi yang kurang dari ramping mungkin membantu:
setcap dapat digunakan pada juru bahasa skrip untuk memberikan kemampuan pada skrip. Jika setcaps pada biner interpreter global tidak dapat diterima, buat salinan biner lokal (setiap pengguna dapat) dan dapatkan root untuk setcap pada salinan ini. Python2 (setidaknya) berfungsi dengan baik dengan salinan lokal juru bahasa di pohon pengembangan skrip Anda. Suid tidak diperlukan sehingga pengguna root dapat mengontrol kemampuan apa yang dapat diakses oleh pengguna.
Jika Anda perlu melacak pembaruan sistem ke penerjemah, gunakan skrip shell seperti berikut untuk menjalankan skrip Anda:
sumber
Saya mencoba metode iptables PREROUTING REDIRECT. Pada kernel yang lebih tua, sepertinya jenis aturan ini tidak didukung untuk IPv6 . Tetapi ternyata sekarang didukung di ip6tables v1.4.18 dan Linux kernel v3.8.
Saya juga menemukan bahwa PREROUTING REDIRECT tidak berfungsi untuk koneksi yang dimulai di dalam mesin. Untuk bekerja untuk koneksi dari mesin lokal, tambahkan aturan OUTPUT juga - lihat pengalihan port iptables yang tidak berfungsi untuk localhost . Misalnya sesuatu seperti:
Saya juga menemukan bahwa PREROUTING REDIRECT juga memengaruhi paket yang diteruskan . Yaitu, jika mesin juga meneruskan paket antar antarmuka (mis. Jika itu bertindak sebagai titik akses Wi-Fi yang terhubung ke jaringan Ethernet), maka aturan iptables juga akan menangkap koneksi klien yang terhubung ke tujuan Internet, dan mengarahkan mereka ke mesin. Bukan itu yang saya inginkan — saya hanya ingin mengarahkan kembali koneksi yang diarahkan ke mesin itu sendiri. Saya menemukan saya bisa membuatnya hanya mempengaruhi paket yang ditujukan ke kotak, dengan menambahkan
-m addrtype --dst-type LOCAL
. Misalnya sesuatu seperti:Satu kemungkinan lainnya adalah menggunakan penerusan port TCP. Misalnya menggunakan
socat
:Namun satu kelemahan dengan metode itu adalah, aplikasi yang mendengarkan pada port 8080 kemudian tidak tahu alamat sumber koneksi yang masuk (misalnya untuk logging atau keperluan identifikasi lainnya).
sumber
Jawab pada 2015 / Sep:
ip6tables sekarang mendukung IPV6 NAT: http://www.netfilter.org/projects/iptables/files/changes-iptables-1.4.17.txt
Anda membutuhkan kernel 3.7+
Bukti:
sumber