มีวิธีสำหรับกระบวนการที่ไม่ใช่รูทเพื่อเชื่อมโยงกับพอร์ต "สิทธิพิเศษ" บน Linux หรือไม่?


389

มันน่ารำคาญมากที่มีข้อ จำกัด นี้ในกล่องพัฒนาของฉันเมื่อไม่มีผู้ใช้คนอื่นนอกจากฉัน

ฉันรู้วิธีการแก้ปัญหามาตรฐานแต่ไม่มีใครทำสิ่งที่ฉันต้องการ:

  1. authbind (เวอร์ชันในการทดสอบ Debian, 1.0, รองรับ IPv4 เท่านั้น)
  2. การใช้ iptables REDIRECT เป้าหมายเพื่อเปลี่ยนเส้นทางพอร์ตต่ำไปยังพอร์ตสูง (ตาราง "nat" ยังไม่ได้ใช้งานสำหรับ ip6tables, รุ่น IPv6 ของ iptables)
  3. sudo (การทำงานในฐานะรูทเป็นสิ่งที่ฉันพยายามหลีกเลี่ยง)
  4. SELinux (หรือคล้ายกัน) (นี่เป็นเพียงกล่อง dev ของฉันฉันไม่ต้องการที่จะเพิ่มความซับซ้อนเป็นพิเศษ)

มีsysctlตัวแปรง่ายๆที่อนุญาตให้กระบวนการที่ไม่ใช่รูทเชื่อมโยงกับพอร์ต "สิทธิพิเศษ" (พอร์ตน้อยกว่า 1024) บน Linux หรือไม่หรือฉันโชคไม่ดี?

แก้ไข: ในบางกรณีคุณสามารถใช้ความสามารถในการทำเช่นนี้


5
จากประสบการณ์ของฉันเหตุผลหนึ่งที่พยายามทำสิ่งนี้คือเขียนเว็บเซิร์ฟเวอร์แทนที่จะใช้ Apache (หรือ lighttpd)
S.Lott

ฉันได้เพิ่มสิ่ง setcap ในคำตอบของฉันไปที่stackoverflow.com/questions/277991/…ที่
Paul Tomblin

15
เพราะในกรณีนี้ฉันใช้ IPv6 ซึ่งเป็นสาเหตุการแก้ปัญหา "ปกติ" บางอย่าง (การแก้ไขอัตโนมัติและ iptables REDIRECT) ไม่ทำงานสำหรับฉัน
Jason Creighton


คำตอบ:


392

โอเคขอบคุณคนที่ชี้ให้เห็นความสามารถและCAP_NET_BIND_SERVICEความสามารถของระบบ หากคุณมีเคอร์เนลเมื่อเร็ว ๆ นี้เป็นไปได้ที่จะใช้สิ่งนี้เพื่อเริ่มบริการที่ไม่ใช่รูท แต่เชื่อมโยงพอร์ตต่ำ คำตอบสั้น ๆ คือคุณ:

setcap 'cap_net_bind_service=+ep' /path/to/program

และทุกเวลาprogramจะถูกดำเนินการหลังจากนั้นมันจะมีCAP_NET_BIND_SERVICEความสามารถ อยู่ในแพคเกจเดเบียนsetcaplibcap2-bin

ตอนนี้สำหรับ caveats:

  1. คุณจะต้องมีเคอร์เนลอย่างน้อย 2.6.24
  2. สิ่งนี้จะไม่ทำงานหากไฟล์ของคุณเป็นสคริปต์ (เช่นใช้บรรทัด #! เพื่อเปิดตัวล่าม) ในกรณีนี้เท่าที่ฉันเข้าใจคุณจะต้องใช้ความสามารถในการปฏิบัติการล่ามเองซึ่งแน่นอนว่าเป็นฝันร้ายด้านความปลอดภัยเนื่องจากโปรแกรมใด ๆ ที่ใช้ล่ามนั้นจะมีความสามารถ ฉันไม่สามารถหาวิธีทำความสะอาดและแก้ไขปัญหานี้ได้อย่างง่ายดาย
  3. ลินุกซ์จะปิด LD_LIBRARY_PATH ใด ๆprogramที่ได้ยกระดับสิทธิ์เหมือนหรือsetcap suidดังนั้นหากคุณprogramใช้มันเอง.../lib/คุณอาจต้องดูตัวเลือกอื่นเช่นการส่งต่อพอร์ต

แหล่งข้อมูล:

หมายเหตุ: RHEL แรกเพิ่มใน v6


3
วิธีแก้ปัญหาบางส่วนสำหรับสคริปต์: สร้างสำเนาของล่าม (เช่นทุบตี) มอบความสามารถ แต่ จำกัด การเข้าถึงสำเนาให้ผู้ใช้ที่ต้องการ แน่นอนผู้ใช้เหล่านั้นจะต้องเชื่อถือได้ แต่พวกเขาสามารถเปลี่ยนสคริปต์ได้
Erich Kitzmueller

3
นอกเหนือจากแพ็คเกจเดเบียน (ไบนารี) ดังกล่าวแล้วเว็บไซต์ของนักพัฒนาก็คือFriedhoff.org/posixfilecaps.htmlเอกสาร / งานนำเสนอที่เกี่ยวข้อง / ฯลฯ ...
RandomNickName42

1
ใน suse SLES 11.1 ฉันต้องเพิ่มเคอร์เนล param file_caps = 1 เพื่อ grub menu.lst เพื่อให้มันใช้งานได้
Shay

2
ใช่ @ C. รอสเพราะมันจะต้องถูกนำไปใช้/usr/bin/javaและจากนั้นจะเปิดความสามารถในการที่แอพพลิเคชั่นจาวาใด ๆ ที่ทำงานบนระบบ ไม่สามารถตั้งค่าความสามารถที่แย่เกินไปต่อผู้ใช้
joeytwiddle

5
การตั้งค่า setcap ยังคงมีอยู่ตลอดการบูตเครื่องใหม่หรือไม่ หากไม่มีสถานที่มาตรฐานที่จะวางกฎนี้เพื่อให้มันทำงานในระหว่างการเริ่มต้นระบบ? อยู่/etc/security/capability.confใน Debian / Ubuntu ความช่วยเหลือใด ๆ
joeytwiddle

34

คุณสามารถทำการเปลี่ยนเส้นทางพอร์ตได้ นี่คือสิ่งที่ฉันทำเพื่อเซิร์ฟเวอร์นโยบาย Silverlight ที่ทำงานบนกล่อง Linux

iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 943 -j REDIRECT --to-port 1300

5
น่าเสียดายที่นี่ใช้งานได้สำหรับการเชื่อมต่อที่กำหนดเส้นทางเท่านั้นไม่ใช่จากเครื่องโลคอล
zbyszek

@ Joetwiddle ฉันคิดว่ามันอยู่ในสคริปต์ที่ทำงาน (เริ่มต้น) เซิร์ฟเวอร์ของคุณ แต่ฉันอาจจะผิด ฉันต้องการทราบเช่นกัน: P
Camilo Martin

@CamiloMartin ดูอีกครั้งเอกสาร Debianที่เชื่อมโยงจากคำถามแนะนำให้วางไว้ในสคริปต์ไฟร์วอลล์ของคุณหรือสร้าง/etc/network/if-up.d/firewallขึ้นที่
joeytwiddle

8
@zbyszek สิ่งนี้สามารถทำงานได้สำหรับการเชื่อมต่อเครื่องท้องถิ่นโดยมีกฎ iptables เพิ่มเติม: stackoverflow.com/a/31795603/1356953
00500005

ในเมล็ดเก่าดูเหมือนว่านี้ไม่ได้รับการสนับสนุนสำหรับ IPv6 แต่เห็นได้ชัดว่าได้รับการสนับสนุนใน ip6tables v1.4.18 และ Linux kernel v3.8
Craig McQueen

31

วิธีมาตรฐานคือการทำให้พวกเขา "setuid" เพื่อให้พวกเขาเริ่มต้นเป็นรูทและจากนั้นพวกเขาก็ทิ้งสิทธิพิเศษของรูทนั้นทันทีที่พวกเขาผูกพันกับพอร์ต แต่ก่อนที่พวกเขาจะเริ่มยอมรับการเชื่อมต่อกับมัน คุณสามารถดูตัวอย่างที่ดีของมันในซอร์สโค้ดสำหรับ Apache และ INN ฉันบอกแล้วว่า Lighttpd เป็นอีกตัวอย่างที่ดี

อีกตัวอย่างหนึ่งคือ Postfix ซึ่งใช้ daemons หลายตัวที่สื่อสารผ่านไพพ์และมีเพียงหนึ่งหรือสองอันเท่านั้น (ซึ่งมีน้อยมากยกเว้นการยอมรับหรือปล่อยไบต์) ที่รันเป็น root และส่วนที่เหลือจะรันด้วยสิทธิ์ต่ำกว่า


1
น่าสนใจว่านี่ใช้ไม่ได้กับ Linux เวอร์ชันล่าสุด (อาจเป็นเพียง Ubuntu) โดยไม่ตั้งค่า CAP_SETUID ดังนั้นหากคุณต้องการ setuid คุณจะต้องตั้งค่าความสามารถนี้อยู่ดี
Matt

การปล่อยรูทบ็อกเป็นวิธีที่เหมาะสมในการทำเช่นนี้ แม้ว่าจะไม่จำเป็นต้องตั้งค่า setuid หากคุณได้เริ่มต้น / เริ่มต้น / systemd เริ่มบริการ
Michael Hampton

2
นี่เป็นเรื่องยากหากโปรแกรมเขียนด้วยภาษาที่ตีความหรือล่าม bytecode เช่น C # (Mono), Java, Python (เห็นได้ชัด Perl ได้ทำมันผ่านbinfmt_miscและ 'C' ธง; ผมไม่แน่ใจว่าเกี่ยวกับคนอื่น.)
เครกแมก

น้อยมากยกเว้นการปล่อยไบต์ที่ไม่ได้ทำน้อยมาก
Ryan

หากคุณตั้งค่าไบนารี setuid มันจะทำงานเป็นกระบวนการรูท อย่างไรก็ตามคำถามถามว่าจะทำให้สำเร็จได้อย่างไรโดยไม่ต้องใช้ไบนารีของคุณเป็นกระบวนการรูท การแก้ปัญหานี้คือคำตอบสำหรับคำถามที่แตกต่างกล่าวคือ: "ผู้ใช้ที่ไม่มีสิทธิพิเศษสามารถมีกระบวนการผูกกับพอร์ตที่มีสิทธิ์" ได้อย่างไร แต่นี่ไม่ใช่คำถามที่ถูกวางไว้ IMHO?
Michael Beer

24

หรือแก้ไขเคอร์เนลของคุณและลบการตรวจสอบ

(ตัวเลือกสุดท้ายไม่แนะนำ)

ในnet/ipv4/af_inet.cลบสองบรรทัดที่อ่าน

      if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
              goto out;

และเคอร์เนลจะไม่ตรวจสอบพอร์ตพิเศษอีกต่อไป


22
ความคิดที่แย่มากด้วยเหตุผลหลายประการ
Adam Lassek

24
นี่เป็นความคิดที่ไม่ดี แต่จะได้ผลจริง และแน่นอนทำให้ฉันหัวเราะ
Oto Brglez

23
แน่นอนมันเป็นความคิดที่ไม่ดี นั่นเป็นเหตุผลที่ฉันพูดสุดท้าย จุดโอเพ่นซอร์สคือถ้ามันไม่ทำงานตามที่คุณต้องการคุณสามารถเปลี่ยนได้
โจชัว

18
ฉันไม่แน่ใจว่าทำไมคุณถึงถูกโหวต ผู้เขียนมัลแวร์ไม่สนใจพอร์ตที่พวกเขาฟังและพวกเขาก็ยินดีที่จะเปิดพอร์ตที่มากกว่า 1024 ดูเหมือนว่าสำหรับฉันว่าพอร์ตทั้งหมดควรต้องมีสิทธิ์หรือไม่ควรมีพอร์ต และการกำหนดให้รูทต้องเปิดพอร์ตที่ต่ำกว่า 1024 หมายความว่าคุณมีแอพพลิเคชั่นที่มีความเสี่ยงสูงซึ่งทำงานเหมือนรูท ที่ดูเหมือนว่าจริงๆความคิดที่โง่ให้ฉัน บางทีฉันอาจจะพลาดบางสิ่งบางอย่างที่นี่ ...
jww

9
ย้อนกลับไปในวันนั้นมีการใช้พอร์ต <1024 ในโปรโตคอล UNIX ถึง UNIX เพื่อพิสูจน์ว่ารหัสที่ใช้งานในส่วนอื่น ๆ นั้นทำงานเหมือนรูท สิ่งนี้ทำหน้าที่ได้ดีพอสมควรสำหรับชุดเซิร์ฟเวอร์ UNIX ที่มีความปลอดภัยทั่วไป
Joshua

22

คุณสามารถตั้งค่าอุโมงค์ SSH ในพื้นที่ได้เช่นถ้าคุณต้องการให้พอร์ต 80 ตีแอพของคุณถึง 3000:

sudo ssh $USERNAME@localhost -L 80:localhost:3000 -N

สิ่งนี้มีความได้เปรียบในการทำงานกับเซิร์ฟเวอร์สคริปต์และใช้งานง่ายมาก


1
ฉันชอบส่วนตัว ง่ายมากที่จะเปิดและปิดและไม่จำเป็นต้องมีการเปลี่ยนแปลงทั้งระบบ ความคิดที่ดี!
Dan Passaro

มันอัศจรรย์มาก. โดยคำตอบที่ง่ายที่สุด
michaelsnowden

1
ฉันคาดหวังว่าสิ่งนี้จะมีราคาแพงพอสมควรและไม่ใช่ความคิดที่ดีในสถานการณ์ที่มีข้อ จำกัด ด้านประสิทธิภาพ แต่ฉันไม่สามารถมั่นใจได้หากไม่ทำการทดสอบ การเข้ารหัส SSH มีค่าใช้จ่ายที่ไม่ใช่ศูนย์
lahwran

3
สิ่งนี้สามารถทำได้ด้วย netcat โดยไม่มีค่าใช้จ่าย ssh:sudo nc -l 80 | nc localhost 3000
Bugster

1
คุณกำลังเข้ารหัส + ถอดรหัสสำหรับการย้ายข้อมูลไปยังพอร์ตอื่นบนเครื่องเดียวกันหรือไม่ นอกจากนี้ยังใช้ไม่ได้กับทราฟฟิก UDP
Daniel F

19

อัปเดต 2017:

ใช้การตรวจสอบอัตโนมัติ


ดีกว่า CAP_NET_BIND_SERVICE หรือเคอร์เนลที่กำหนดเอง

  • CAP_NET_BIND_SERVICE ให้ความเชื่อถือกับไบนารี แต่ไม่ได้ให้การควบคุมการเข้าถึงแบบต่อพอร์ต
  • Authbind มอบความไว้วางใจให้กับผู้ใช้ / กลุ่มและให้การควบคุมการเข้าถึงต่อพอร์ตและสนับสนุนทั้ง IPv4 และ IPv6 (การสนับสนุน IPv6 ได้รับการเพิ่มในช่วงปลายปี)

    1. ติดตั้ง: apt-get install authbind

    2. กำหนดค่าการเข้าถึงพอร์ตที่เกี่ยวข้องเช่น 80 และ 443 สำหรับผู้ใช้และกลุ่มทั้งหมด:

      sudo touch / etc / authbind / byport / 80
      sudo touch / etc / authbind / byport / 443
      sudo chmod 777 / etc / authbind / byport / 80
      sudo chmod 777 / etc / authbind / byport / 443

    3. เรียกใช้งานคำสั่งของคุณผ่านauthbind
      (ระบุ--deepหรือเลือกอาร์กิวเมนต์อื่นดูที่หน้าหลัก):

      authbind --deep /path/to/binary command line args
      

      เช่น

      authbind --deep java -jar SomeServer.jar
      

ติดตามการแนะนำของ Joshua (= ไม่แนะนำเว้นแต่คุณจะรู้ว่าคุณทำอะไร) แนะนำให้แฮ็คเคอร์เนล:

ฉันโพสต์ไว้ที่นี่เป็นครั้งแรกที่นี่

ง่าย ด้วยเคอร์เนลปกติหรือเก่าคุณทำไม่ได้
ตามที่คนอื่น ๆ ชี้ให้เห็น iptables สามารถส่งต่อพอร์ต
ตามที่คนอื่น ๆ ชี้ให้เห็น CAP_NET_BIND_SERVICE ก็สามารถทำงานได้เช่นกัน
แน่นอนว่า CAP_NET_BIND_SERVICE จะล้มเหลวถ้าคุณเปิดโปรแกรมจากสคริปต์เว้นแต่ว่าคุณตั้งค่า cap บนตัวแปลเชลล์ซึ่งไม่มีจุดหมายคุณสามารถเรียกใช้บริการของคุณในฐานะ root ...
เช่นสำหรับ Java คุณต้องใช้มัน ถึง JAVA JVM

sudo /sbin/setcap 'cap_net_bind_service=ep' /usr/lib/jvm/java-8-openjdk/jre/bin/java

เห็นได้ชัดว่านั่นหมายความว่าโปรแกรม Java ใด ๆ สามารถผูกพอร์ตระบบได้
Dito สำหรับโมโน /. NET

ฉันค่อนข้างมั่นใจว่า xinetd ไม่ใช่คนที่ดีที่สุดของความคิด
แต่เนื่องจากทั้งสองวิธีมีแฮ็กทำไมไม่ยกระดับ จำกัด ด้วยการยกข้อ จำกัด ?
ไม่มีใครบอกว่าคุณต้องใช้เคอร์เนลปกติดังนั้นคุณสามารถรันเคอร์เนลของคุณเองได้

คุณเพียงแค่ดาวน์โหลดแหล่งที่มาสำหรับเคอร์เนลล่าสุด (หรือที่คุณมีอยู่ในปัจจุบัน) หลังจากนั้นคุณไปที่:

/usr/src/linux-<version_number>/include/net/sock.h:

คุณค้นหาบรรทัดนี้

/* Sockets 0-1023 can't be bound to unless you are superuser */
#define PROT_SOCK       1024

และเปลี่ยนเป็น

#define PROT_SOCK 0

หากคุณไม่ต้องการมีสถานการณ์ที่ไม่ปลอดภัย ssh คุณต้องเปลี่ยนเป็น: #define PROT_SOCK 24

โดยทั่วไปฉันจะใช้การตั้งค่าต่ำสุดที่คุณต้องการเช่น 79 สำหรับ http หรือ 24 เมื่อใช้ SMTP บนพอร์ต 25

นั่นคือทั้งหมด
รวบรวมเคอร์เนลและติดตั้ง
Reboot
เสร็จสิ้น - ข้อ จำกัด ที่โง่คือ GONE และสามารถใช้ได้กับสคริปต์ด้วย

นี่คือวิธีที่คุณรวบรวมเคอร์เนล:

https://help.ubuntu.com/community/Kernel/Compile

# You can get the kernel-source via package linux-source, no manual download required
apt-get install linux-source fakeroot

mkdir ~/src
cd ~/src
tar xjvf /usr/src/linux-source-<version>.tar.bz2
cd linux-source-<version>

# Apply the changes to PROT_SOCK define in /include/net/sock.h

# Copy the kernel config file you are currently using
cp -vi /boot/config-`uname -r` .config

# Install ncurses libary, if you want to run menuconfig
apt-get install libncurses5 libncurses5-dev

# Run menuconfig (optional)
make menuconfig

# Define the number of threads you wanna use when compiling (should be <number CPU cores> - 1), e.g. for quad-core
export CONCURRENCY_LEVEL=3
# Now compile the custom kernel
fakeroot make-kpkg --initrd --append-to-version=custom kernel-image kernel-headers

# And wait a long long time

cd ..

สรุปใช้ iptables ถ้าคุณต้องการรักษาความปลอดภัยรวบรวมเคอร์เนลถ้าคุณต้องการให้แน่ใจว่าข้อ จำกัด นี้ไม่รบกวนคุณอีก


เหตุผลใดสำหรับ downvote ผู้เกลียดชังหรือคำสั่งเคอร์เนลที่คอมไพล์ไม่ทำงาน?
Stefan Steiger

4
การปรับเปลี่ยนเคอร์เนลทำให้การอัปเดตในอนาคตเจ็บปวดยิ่งขึ้น ฉันจะไม่ทำเช่นนี้เพราะฉันรู้ว่าฉันขี้เกียจเกินกว่าจะอัพเดทเคอร์เนลของฉันอย่างสม่ำเสมอ เป็นเรื่องดีที่เป็นไปได้ในทางทฤษฎี แต่มันไม่ใช่ตัวเลือกที่ทำงานได้ในหลายสถานการณ์
kritzikratzi

อาจเป็นวิธีที่ปลอดภัยกว่านี้คือการเปลี่ยน chmod 777 / etc / authbind / byport / 80 โดย chmod 544 / etc / authbind / byport / 23 กว่า chown ล็อกอิน: กลุ่ม / etc / authbind / byport / 23
Jérôme B

18

ความสามารถของไฟล์นั้นไม่เหมาะอย่างยิ่งเนื่องจากสามารถแตกหลังจากการอัปเดตแพ็คเกจ

ทางออกที่ดีที่สุด IMHO ควรเป็นความสามารถในการสร้างเชลล์ที่สืบทอดได้ CAP_NET_BIND_SERVICEชุดที่ได้

นี่เป็นวิธีที่ค่อนข้างซับซ้อนในการทำสิ่งนี้:

sg $DAEMONUSER "capsh --keep=1 --uid=`id -u $DAEMONUSER` \
     --caps='cap_net_bind_service+pei' -- \
     YOUR_COMMAND_GOES_HERE"

capshยูทิลิตี้สามารถพบได้ในแพคเกจ libcap2-bin ในการกระจาย Debian / Ubuntu นี่คือสิ่งที่เกิดขึ้น:

  • sgเปลี่ยน ID กลุ่มที่มีประสิทธิภาพเป็นของผู้ใช้ daemon สิ่งนี้จำเป็นเนื่องจากcapshใบ GID ไม่เปลี่ยนแปลงและเราไม่ต้องการ
  • ชุดบิต 'รักษาความสามารถในการเปลี่ยนโพสต์'
  • เปลี่ยน UID เป็น $DAEMONUSER
  • วางตัวพิมพ์ใหญ่ทั้งหมด (ในขณะนี้ตัวพิมพ์ใหญ่ทั้งหมดยังคงอยู่เนื่องจาก--keep=1) ยกเว้นที่สืบทอดได้cap_net_bind_service
  • เรียกใช้งานคำสั่งของคุณ ('-' เป็นตัวคั่น)

ผลลัพธ์เป็นกระบวนการที่มีผู้ใช้และกลุ่มที่ระบุและcap_net_bind_serviceสิทธิ์ใช้งาน

ตัวอย่างเช่นบรรทัดจากejabberdสคริปต์เริ่มต้น:

sg $EJABBERDUSER "capsh --keep=1 --uid=`id -u $EJABBERDUSER` --caps='cap_net_bind_service+pei' -- $EJABBERD --noshell -detached"

และมันใช้งานไม่ได้จริง แคปไม่ได้ถูกสงวนไว้เหนือสวิตช์ ID ผู้ใช้ มันจะทำงานถ้าคุณต้องการที่จะเรียกใช้เป็นราก แต่ด้วยความสามารถทั้งหมดลดลง
Cyberax

หากฉันลองฉันจะได้รับ "ไม่สามารถเรียกใช้ไฟล์ไบนารี่" ที่จริงแล้วฉันไม่สามารถcapshทำอะไรอื่นนอกจาก "ไม่สามารถเรียกใช้ไฟล์ไบนารี" เมื่อใช้--หรือ==ตัวเลือก ฉันสงสัยว่าฉันหายไปไหน
Craig McQueen

@CraigMcQueen ทุกอย่างหลังจากที่--ถูกส่งผ่านไปดังนั้นคุณอาจต้องการที่จะลองกับ/bin/bash -c 'your command'อนิจจาฉันดูเหมือนจะประสบปัญหาเช่นเดียวกับ @Cyberax เพราะผมได้รับอนุญาต "ปฏิเสธ" bindเมื่อพยายามที่จะ
อาเมียร์

เพื่อให้ทำงานได้โดยไม่ต้องตั้งค่าความสามารถของไฟล์ (หรือเรียกใช้ในฐานะ root) คุณจะต้องใช้ความสามารถรอบข้างตามที่อธิบายไว้ในคำตอบ Unix.SEนี้ นอกจากนี้คุณยังสามารถใช้--gidแทนsg(หรือ--userที่ชุด--uid, --gidและ--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'
Kevinoid

18

ด้วยเหตุผลบางอย่างไม่มีใครพูดถึงการลด sysctl net.ipv4.ip_unprivileged_port_start ให้เป็นค่าที่คุณต้องการ ตัวอย่าง: เราต้องผูกแอพของเรากับพอร์ต 443

sysctl net.ipv4.ip_unprivileged_port_start=443

บางคนอาจพูดว่ามีปัญหาด้านความปลอดภัยที่อาจเกิดขึ้น: ผู้ใช้ที่ไม่มีสิทธิพิเศษตอนนี้อาจผูกกับพอร์ตพิเศษอื่น ๆ (444-1024) แต่คุณสามารถแก้ปัญหานี้ได้อย่างง่ายดายด้วย iptables โดยบล็อกพอร์ตอื่น ๆ :

iptables -I INPUT -p tcp --dport 444:1024 -j DROP
iptables -I INPUT -p udp --dport 444:1024 -j DROP

เปรียบเทียบกับวิธีอื่น ๆ วิธีนี้:

  • จากจุดหนึ่งคือ (IMO) ปลอดภัยยิ่งกว่าการตั้งค่า CAP_NET_BIND_SERVICE / setuid เนื่องจากแอปพลิเคชันไม่ได้ตั้งค่าเลยแม้แต่บางส่วน (ความสามารถจริง ๆ ) ตัวอย่างเช่นหากต้องการจับภาพแอปพลิเคชันที่เปิดใช้งานความสามารถคุณจะต้องเปลี่ยน sysctl fs.suid_dumpable (ซึ่งนำไปสู่ปัญหาความปลอดภัยอื่น ๆ ที่อาจเกิดขึ้น) นอกจากนี้เมื่อมีการตั้งค่า CAP / suid / ไดเรกทอรี proc / PID ผู้ใช้ที่ไม่ใช่รูทของคุณจะไม่มีข้อมูล / การควบคุมกระบวนการทำงานที่สมบูรณ์ตัวอย่างเช่นผู้ใช้จะไม่สามารถ (ในกรณีทั่วไป) เพื่อตรวจสอบว่าการเชื่อมต่อใดเป็นของแอปพลิเคชันผ่าน / proc / PID / fd / (netstat -aptn | grep PID)
  • มีข้อเสียด้านความปลอดภัย: ในขณะที่แอปของคุณ (หรือแอพใด ๆ ที่ใช้พอร์ต 443-1024) ไม่ทำงานด้วยเหตุผลบางประการแอปอื่นอาจใช้พอร์ต แต่ปัญหานี้ยังสามารถนำไปใช้กับ CAP / suid (ในกรณีที่คุณตั้งไว้บนล่ามเช่น java / nodejs) และ iptables-redirect ใช้วิธี systemd-socket เพื่อแยกปัญหานี้ ใช้วิธีการ authbind เพื่ออนุญาตการผูกผู้ใช้พิเศษเท่านั้น
  • ไม่จำเป็นต้องตั้งค่า CAP / suid ทุกครั้งที่คุณปรับใช้แอปพลิเคชันเวอร์ชันใหม่
  • ไม่ต้องการการสนับสนุน / แก้ไขแอปพลิเคชันเช่นวิธี systemd-socket
  • ไม่ต้องการสร้างใหม่เคอร์เนล (หากรุ่นที่รันรองรับการตั้งค่า sysctl นี้)
  • LD_PRELOAD ไม่ชอบวิธี authbind / privbind ซึ่งอาจส่งผลต่อประสิทธิภาพความปลอดภัยพฤติกรรม (ไม่ได้ทดสอบเลย) ในส่วนที่เหลือ authbind เป็นวิธีที่ยืดหยุ่นและปลอดภัยจริงๆ
  • การ overtect iptables วิธี REDIRECT / DNAT เนื่องจากไม่จำเป็นต้องมีการแปลที่อยู่, การติดตามสถานะการเชื่อมต่อ, ฯลฯ ซึ่งจะเห็นได้เฉพาะในระบบที่โหลดสูงเท่านั้น

ขึ้นอยู่กับสถานการณ์ฉันจะเลือกระหว่าง sysctl, CAP, authbind และ iptables-redirect และนี่คือสุดยอดที่เรามีตัวเลือกมากมาย


2
ขอบคุณสำหรับคำตอบที่ยอดเยี่ยม! ปรากฏว่าฟังก์ชั่นนี้ปรากฏขึ้นครั้งแรกในLinux 4.11 ในเดือนเมษายน 2017ดังนั้นจึงไม่ได้เกิดขึ้นในปี 2009 เมื่อฉันถามคำถามนี้เป็นครั้งแรก ฉันได้ทำการทดสอบอย่างรวดเร็วและดูเหมือนว่าจะใช้งานได้กับ IPV6 แม้ว่า "ipv4" จะอยู่ในชื่อ sysctl
Jason Creighton

15

ความเป็นไปได้ง่าย ๆ อีกสองประการ:

มีวิธีแก้ปัญหาแบบเก่า (ล้าสมัย) สำหรับ "daemon ที่ผูกกับพอร์ตต่ำและมือควบคุม daemon ของคุณ" มันเรียกว่า inetd (หรือ xinetd) ข้อเสียคือ:

  • daemon ของคุณต้องการคุยกับ stdin / stdout (ถ้าคุณไม่ควบคุม daemon - ถ้าคุณไม่มีแหล่งที่มา - นี่อาจเป็น showstopper แม้ว่าบริการบางอย่างอาจมีการตั้งค่าความเข้ากันได้ของ inetd)
  • กระบวนการ daemon ใหม่ถูกแยกสำหรับทุกการเชื่อมต่อ
  • มันเป็นลิงค์เพิ่มเติมหนึ่งเดียวในห่วงโซ่

ข้อดี:

  • พร้อมใช้งานบน UNIX เก่า ๆ
  • เมื่อดูแลระบบของคุณตั้งค่าไว้คุณก็พร้อมที่จะพัฒนาต่อไป (เมื่อคุณสร้าง daemon ขึ้นใหม่คุณอาจสูญเสียความสามารถใน setcap หรือไม่แล้วคุณจะต้องกลับไปที่ผู้ดูแลระบบของคุณ "ได้โปรด .. . ")
  • daemon ไม่ต้องกังวลเกี่ยวกับเครือข่ายสิ่งนั้นเพียงแค่ต้องพูดคุยกับ stdin / stdout
  • สามารถกำหนดค่าให้รัน daemon ของคุณในฐานะผู้ใช้ที่ไม่ใช่รูทได้ตามที่ร้องขอ

อีกทางเลือกหนึ่ง: พร็อกซีที่ถูกแฮ็ก (netcat หรือแม้กระทั่งบางอย่างที่มีประสิทธิภาพมากกว่า ) จากพอร์ตที่มีสิทธิพิเศษไปยังพอร์ตที่มีหมายเลขสูงตามอำเภอใจซึ่งคุณสามารถเรียกใช้ภูตเป้าหมายของคุณได้ (Netcat ไม่ใช่โซลูชั่นการผลิต แต่ "เพียงกล่อง dev ของฉัน" ใช่ไหม?) วิธีนี้คุณสามารถใช้เซิร์ฟเวอร์รุ่นที่รองรับเครือข่ายของคุณต่อไปได้เพียงต้องการรูท / sudo เพื่อเริ่มต้นพร็อกซี (ตอนบูต) ไม่ต้องพึ่งพาความสามารถที่ซับซ้อน / เปราะบาง


1
คำแนะนำที่ดี ด้วยเหตุผลบางอย่างฉันไม่ได้คิดว่าจะใช้ inetd ยกเว้นว่าบริการที่เป็นปัญหานั้นใช้ UDP ดังนั้นจึงซับซ้อนกว่าบริการ TCP เล็กน้อย ฉันมีวิธีแก้ปัญหาทำงานได้ในขณะนี้ด้วย setcap แต่ฉันจะต้องให้ความคิดนี้
เจสันเครตัน

สำหรับตัวเลือกที่สองคุณสามารถเริ่มใช้งาน proxy โดยใช้ inetd ... (แต่ IPTables มีค่าใช้จ่ายต่ำกว่า ... )
Gert van den Berg

14

"วิธีแก้ปัญหามาตรฐาน" ของฉันใช้ socat เป็นตัวเปลี่ยนเส้นทางพื้นที่ผู้ใช้:

socat tcp6-listen:80,fork tcp6:8080

ระวังว่าสิ่งนี้จะไม่ขยายขนาดการตีนั้นมีราคาแพง แต่ก็เป็นวิธีการทำงานของโซคอท


13

Linux รองรับความสามารถในการรองรับการอนุญาตที่ละเอียดยิ่งกว่า "แอปพลิเคชันนี้ทำงานเหมือนรูท" หนึ่งในความสามารถเหล่านั้นCAP_NET_BIND_SERVICEเกี่ยวข้องกับการเชื่อมต่อกับพอร์ตพิเศษ (<1024)

น่าเสียดายที่ฉันไม่รู้ว่าจะใช้ประโยชน์จากสิ่งนั้นอย่างไรเพื่อเรียกใช้แอปพลิเคชั่นที่ไม่ใช่รูทในขณะที่ยังคงให้ใช้งานCAP_NET_BIND_SERVICE(อาจใช้setcapแต่มีข้อผูกมัดว่าเป็นโซลูชันที่มีอยู่สำหรับสิ่งนี้)


จะไม่ทำงานกับสคริปต์หรือโปรแกรม JVM / โมโนเดี่ยว ๆ
Stefan Steiger

13

ฉันรู้ว่านี่เป็นคำถามเก่า แต่ตอนนี้ด้วยเมล็ด (> = 4.3) เมื่อเร็ว ๆ นี้ในที่สุดก็มีคำตอบที่ดีสำหรับความสามารถนี้ - ความสามารถรอบข้าง

คำตอบอย่างรวดเร็วคือการคัดลอก libcap เวอร์ชันล่าสุด (ยังไม่ได้เผยแพร่) รุ่นล่าสุดจากคอมไพล์และคอมไพล์ คัดลอกprogs/capshไบนารีที่เกิดขึ้นที่ไหนสักแห่ง ( /usr/local/binเป็นตัวเลือกที่ดี) จากนั้นในฐานะ root ให้เริ่มโปรแกรมของคุณด้วย

/usr/local/bin/capsh --keep=1 --user='your-service-user-name' \
    --inh='cap_net_bind_service' --addamb='cap_net_bind_service' \ 
    -- -c 'your-program'

เพื่อที่เราจะได้

  • ประกาศว่าเมื่อเราสลับผู้ใช้เราต้องการรักษาความสามารถในปัจจุบันของเรา
  • การสลับผู้ใช้และกลุ่มเป็น 'your-service-user-name'
  • การเพิ่มcap_net_bind_serviceความสามารถให้กับชุด & บรรยากาศที่สืบทอด
  • ทางแยกbash -c 'your-command'(เนื่องจากcapshเริ่มอัตโนมัติทุบตีด้วยข้อโต้แย้งหลังจาก--)

มีหลายอย่างเกิดขึ้นภายใต้ประทุนที่นี่

ประการแรกเราทำงานเป็น root ดังนั้นโดยค่าเริ่มต้นเราได้รับชุดของความสามารถเต็มรูปแบบ รวมอยู่ในนี้คือความสามารถในการสลับ UID และ GID กับsetuidและsetgidsyscalls อย่างไรก็ตามโดยปกติเมื่อโปรแกรมทำสิ่งนี้มันจะสูญเสียความสามารถของชุด - ซึ่งเป็นวิธีการแบบเดิมในการปล่อยรูทที่setuidยังทำงานอยู่ --keep=1ธงบอกว่าcapshการออกprctl(PR_SET_KEEPCAPS)syscall ซึ่งปิดการใช้งานลดลงของความสามารถในเมื่อมีการเปลี่ยนแปลงผู้ใช้ การเปลี่ยนแปลงที่เกิดขึ้นจริงของผู้ใช้โดยcapshที่เกิดขึ้นกับ--userธงซึ่งวิ่งและsetuidsetgid

ปัญหาต่อไปที่เราต้องแก้ไขคือวิธีการตั้งค่าความสามารถในวิธีการดำเนินการหลังจากที่execลูกหลานของเรา ระบบความสามารถมักจะมีชุดของความสามารถ 'ที่สืบทอดมา' ซึ่งก็คือ "ชุดของความสามารถที่เก็บรักษาไว้ใน execve (2)" [ ความสามารถ (7) ] ในขณะที่ฟังดูเหมือนว่าจะแก้ปัญหาของเรา (เพียงแค่ตั้งค่าcap_net_bind_serviceความสามารถในการสืบทอดใช่มั้ย) สิ่งนี้ใช้กับกระบวนการที่ได้รับการยกเว้นเท่านั้น - กระบวนการของเราไม่ได้รับการยกเว้นอีกต่อไปเพราะเราเปลี่ยนผู้ใช้--userแล้ว

ชุดความสามารถรอบข้างใหม่แก้ปัญหานี้ได้ - มันคือ "ชุดของความสามารถที่ถูกสงวนไว้ในโปรแกรม execve (2) ของโปรแกรมที่ไม่ได้รับสิทธิพิเศษ" ด้วยการใส่cap_net_bind_serviceชุดแอมเบียนต์เมื่อเอ็กซีcapshคิวต์เป็นโปรแกรมเซิร์ฟเวอร์ของเราโปรแกรมของเราจะสืบทอดความสามารถนี้และสามารถผูกฟังไว้กับพอร์ตต่ำ

หากคุณสนใจที่จะเรียนรู้เพิ่มเติมหน้าคู่มือความสามารถจะอธิบายรายละเอียดที่ดีนี้ วิ่งcapshผ่านstraceยังเป็นข้อมูลมาก!


การ--addambแนะนำให้รู้จักกับ libcap 2.26 ระบบของฉันมี 2.25 และฉันต้องสร้างจากแหล่งที่มา
สีเขียว

12

TLDR: สำหรับ "คำตอบ" (ตามที่เห็น) ข้ามไปที่ส่วน >> TLDR << ในคำตอบนี้

ตกลงฉันคิดออก (สำหรับจริงเวลานี้) คำตอบสำหรับคำถามนี้และคำตอบของฉันนี้ยังเป็นวิธีการขอโทษสำหรับการส่งเสริม คำตอบอื่น (ทั้งที่นี่และ Twitter) ที่ฉันคิดว่าเป็น "ดีที่สุด "แต่หลังจากลองแล้วก็พบว่าฉันเข้าใจผิดเกี่ยวกับเรื่องนั้น เรียนรู้จากเด็ก ๆ ที่ผิดพลาด: อย่าโปรโมตบางอย่างจนกว่าคุณจะลองด้วยตัวเอง!

อีกครั้งฉันตรวจสอบคำตอบทั้งหมดที่นี่ ฉันลองแล้วบางคน (และเลือกที่จะไม่ลองคนอื่นเพราะฉันไม่ชอบวิธีแก้ปัญหา) ฉันคิดว่าวิธีแก้ปัญหาคือใช้systemdกับมันCapabilities=และCapabilitiesBindingSet=การตั้งค่า หลังจากต่อสู้กับสิ่งนี้มาระยะหนึ่งฉันก็ค้นพบว่านี่ไม่ใช่วิธีแก้ปัญหาเพราะ:

ความสามารถมีวัตถุประสงค์เพื่อ จำกัด กระบวนการรูท!

ตามที่ระบุไว้อย่างชาญฉลาดมันเป็นเสมอควรหลีกเลี่ยงสิ่งนั้น (สำหรับภูตของคุณถ้าเป็นไปได้!)

คุณไม่สามารถใช้ตัวเลือกความสามารถที่เกี่ยวข้องกับUser=และGroup=ในsystemdไฟล์หน่วยเนื่องจากความสามารถจะถูกรีเซ็ตเสมอเมื่อมีการเรียกexecev(หรือฟังก์ชันใด ๆ ) กล่าวอีกนัยหนึ่งเมื่อยกsystemdและลดความต่อเนื่องความสามารถจะถูกรีเซ็ต ไม่มีวิธีแก้ไขปัญหานี้และตรรกะการเชื่อมโยงทั้งหมดในเคอร์เนลเป็นพื้นฐานรอบ uid = 0 ไม่ใช่ความสามารถ ซึ่งหมายความว่าไม่น่าเป็นไปได้ว่าความสามารถจะเป็นคำตอบที่ถูกต้องสำหรับคำถามนี้ (อย่างน้อยทุกเวลาไม่นาน) อนึ่งsetcapตามที่คนอื่น ๆ ได้กล่าวถึงไม่ใช่วิธีแก้ปัญหา มันใช้งานไม่ได้สำหรับฉันมันใช้งานไม่ได้กับสคริปต์และมันก็ถูกรีเซ็ตทุกครั้งที่มีการเปลี่ยนแปลงไฟล์

ในการป้องกันน้อยของฉันฉันทำรัฐ (ในความคิดเห็นที่ฉันได้ลบตอนนี้) ว่าคำแนะนำiptablesของเจมส์(ซึ่ง OP ยังกล่าวถึง) เป็น "ทางออกที่ดีที่สุดที่สอง" :-P

>> TLDR <<

ทางออกคือการรวมsystemdกับiptablesคำสั่งon-the-fly เช่นนี้ ( นำมาจาก DNSChain ):

[Unit]
Description=dnschain
After=network.target
Wants=namecoin.service

[Service]
ExecStart=/usr/local/bin/dnschain
Environment=DNSCHAIN_SYSD_VER=0.0.1
PermissionsStartOnly=true
ExecStartPre=/sbin/sysctl -w net.ipv4.ip_forward=1
ExecStartPre=-/sbin/iptables -D INPUT -p udp --dport 5333 -j ACCEPT
ExecStartPre=-/sbin/iptables -t nat -D PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 5333
ExecStartPre=/sbin/iptables -A INPUT -p udp --dport 5333 -j ACCEPT
ExecStartPre=/sbin/iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 5333
ExecStopPost=/sbin/iptables -D INPUT -p udp --dport 5333 -j ACCEPT
ExecStopPost=/sbin/iptables -t nat -D PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 5333
User=dns
Group=dns
Restart=always
RestartSec=5
WorkingDirectory=/home/dns
PrivateTmp=true
NoNewPrivileges=true
ReadOnlyDirectories=/etc

# Unfortunately, capabilities are basically worthless because they're designed to restrict root daemons. Instead, we use iptables to listen on privileged ports.
# Capabilities=cap_net_bind_service+pei
# SecureBits=keep-caps

[Install]
WantedBy=multi-user.target

ที่นี่เราบรรลุสิ่งต่อไปนี้:

  • daemon รับฟัง 5333 แต่การเชื่อมต่อนั้นได้รับการยอมรับใน 53 ด้วยขอบคุณ iptables
  • เราสามารถรวมคำสั่งในไฟล์หน่วยเองและทำให้เราช่วยลดอาการปวดหัวของผู้คน systemdล้างกฎไฟร์วอลล์สำหรับเราตรวจสอบให้แน่ใจว่าได้ลบออกเมื่อ daemon ไม่ทำงาน
  • เราไม่เคยทำงานเป็นรากและเราจะทำให้เป็นไปไม่ได้ (อย่างน้อยการเพิ่มสิทธิ์systemdอ้างว่า) uid=0ที่คาดคะเนแม้ว่าภูตถูกบุกรุกและชุด

iptablesยังคงเป็นที่น่าเสียดายค่อนข้างเป็นสาธารณูปโภคที่น่าเกลียดและยากต่อการใช้งาน หากภูตจะฟังบนeth0:0แทนeth0ตัวอย่างเช่นคำสั่งที่มีความแตกต่างกันเล็กน้อย


2
ไม่มีใครควรใช้นามแฝงแบบเก่า ๆeth0:0อีกต่อไปเว้นแต่พวกเขาจะมีการกระจาย Linux โบราณจริงๆ พวกเขาเลิกใช้มาหลายปีแล้วและจะหายไปในที่สุด
Michael Hampton

1
ฉันคิดว่าคุณหมายถึง OpenVZ (SolusVM เป็นแผงควบคุม) และใช่ OpenVZ ทำสิ่งต่างๆมากมายผิดพลาดการเชื่อมต่อเครือข่ายเป็นหนึ่งในนั้น
Michael Hampton

1
ไม่ฉันหมายถึงโดย SolusVM จาก / etc / network / interfaces:# Generated by SolusVM
Greg Slepak

1
ยังไม่เป็น OpenVZ ... อย่างน้อยฉันไม่ได้ใช้ VPS ของฉัน
Greg Slepak

7
ขอบคุณสำหรับการชี้ให้เห็นถึงคุณสมบัติความสามารถของ systemd อย่างไรก็ตามไม่จำเป็นต้องใช้ iptables ที่ซับซ้อนเมื่อ systemd เริ่มไบนารีโดยตรง (ไม่ใช่สคริปต์) การตั้งค่าการทำงานอย่างสมบูรณ์ดีสำหรับฉันในการทำงานร่วมกับAmbientCapabilities=CAP_NET_BIND_SERVICE User=
Ruud

11

systemdคือการเปลี่ยน sysvinit ซึ่งมีตัวเลือกในการเปิด daemon ที่มีความสามารถเฉพาะ ตัวเลือกความสามารถ =, CapabilityBoundingSet = ในsystemd.exec (5) manpage


2
ก่อนหน้านี้ฉันแนะนำคำตอบนี้ แต่หลังจากลองแล้วตอนนี้ฉันทำไม่ได้ ดูคำตอบของฉันsystemdหาทางเลือกที่ใช้ยังคง
Greg Slepak

10

การเปลี่ยนเส้นทางพอร์ตทำให้เราใช้งานได้ดีที่สุด แต่เราพบปัญหาที่แอปพลิเคชันของเราจะแก้ไข URL ภายในเครื่องที่จำเป็นต้องส่งเส้นทางอีกครั้ง (นั่นหมายความว่าคุณชินดิง )

สิ่งนี้จะช่วยให้คุณสามารถเปลี่ยนเส้นทางเมื่อเข้าถึง url บนเครื่องโลคอล

iptables -A PREROUTING -t nat -p tcp --dport 80 -j REDIRECT --to-port 8080
iptables -A OUTPUT -t nat -p tcp --dport 80 -j REDIRECT --to-port 8080


8

ด้วย systemd คุณเพียงแค่ต้องปรับเปลี่ยนบริการของคุณเล็กน้อยเพื่อรับซ็อกเก็ตที่เปิดใช้งานล่วงหน้า

ภายหลังคุณสามารถใช้systemd ซ็อกเก็ตเปิดใช้งาน

ไม่มีความสามารถ iptables หรือเทคนิคอื่น ๆ ที่จำเป็น

นี่คือเนื้อหาของไฟล์ systemd ที่เกี่ยวข้องจากตัวอย่างของเซิร์ฟเวอร์ python httpแบบง่าย

ไฟล์ httpd-true.service

[Unit]
Description=Httpd true 

[Service]
ExecStart=/usr/local/bin/httpd-true
User=subsonic

PrivateTmp=yes

ไฟล์ httpd-true.socket

[Unit]
Description=HTTPD true

[Socket]
ListenStream=80

[Install]
WantedBy=default.target

7

เมื่อเริ่มต้น:

iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080

จากนั้นคุณสามารถผูกพอร์ตที่คุณส่งต่อ


ไม่--to-portอยู่? man iptablesกล่าวถึงเท่านั้น--to-ports(พหูพจน์)
Abdull

ive สังเกตเห็นความแตกต่างบางอย่างและฉันได้กระโดดไปรอบ ๆ
James

ดูคำตอบนี้systemdสำหรับวิธีการรวมนี้กับ
Greg Slepak

3

ใช้ยูทิลิตีprivbind : อนุญาตให้แอปพลิเคชันที่ไม่มีสิทธิพิเศษเชื่อมโยงกับพอร์ตที่สงวนไว้


3

นอกจากนี้ยังมี 'djb way' คุณสามารถใช้วิธีนี้เพื่อเริ่มกระบวนการของคุณในฐานะรูทที่รันบนพอร์ตใด ๆ ภายใต้ tcpserver จากนั้นจะควบคุมกระบวนการให้กับผู้ใช้ที่คุณระบุทันทีหลังจากกระบวนการเริ่มต้น

#!/bin/sh

UID=$(id -u username)
GID=$(id -g username)
exec tcpserver -u "${UID}" -g "${GID}" -RHl0 0 port /path/to/binary &

สำหรับข้อมูลเพิ่มเติมโปรดดูที่: http://thedjbway.b0llix.net/daemontools/uidgid.html


1

เนื่องจาก OP เป็นเพียงการพัฒนา / ทดสอบการแก้ปัญหาที่น้อยกว่าจึงอาจมีประโยชน์:

setcap สามารถใช้กับล่ามของสคริปต์เพื่อมอบความสามารถให้กับสคริปต์ หาก setcaps บนไบนารีตัวแปลทั่วโลกไม่เป็นที่ยอมรับให้สร้างสำเนาโลคัลของไบนารี (ผู้ใช้สามารถทำได้) และรับรูทเพื่อ setcap บนสำเนานี้ Python2 (อย่างน้อย) ทำงานอย่างถูกต้องกับสำเนาของล่ามในแผนผังการพัฒนาสคริปต์ของคุณ ไม่จำเป็นต้องมี suid ดังนั้นผู้ใช้รูทสามารถควบคุมความสามารถที่ผู้ใช้สามารถเข้าถึงได้

หากคุณต้องการติดตามการอัปเดตทั้งระบบของล่ามให้ใช้เชลล์สคริปต์ดังต่อไปนี้เพื่อเรียกใช้สคริปต์ของคุณ:

#!/bin/sh
#
#  Watch for updates to the Python2 interpreter

PRG=python_net_raw
PRG_ORIG=/usr/bin/python2.7

cmp $PRG_ORIG $PRG || {
    echo ""
    echo "***** $PRG_ORIG has been updated *****"
    echo "Run the following commands to refresh $PRG:"
    echo ""
    echo "    $ cp $PRG_ORIG $PRG"
    echo "    # setcap cap_net_raw+ep $PRG"
    echo ""
    exit
}

./$PRG $*

1

ฉันลองวิธี IPTables PREROUTING REDIRECT ในเมล็ดเก่าดูเหมือนว่าประเภทของกฎนี้ไม่ได้รับการสนับสนุนสำหรับ IPv6 แต่เห็นได้ชัดว่าตอนนี้ได้รับการสนับสนุนใน ip6tables v1.4.18 และ Linux kernel v3.8

ฉันยังพบว่า PREROUTING REDIRECT ไม่ทำงานสำหรับการเชื่อมต่อที่เริ่มต้นภายในเครื่อง ในการทำงานสำหรับ conections จากเครื่องท้องถิ่นให้เพิ่มกฎการส่งออกยัง - ดูการเปลี่ยนเส้นทางพอร์ต iptables ไม่ทำงานสำหรับ localhost เช่นบางสิ่งเช่น:

iptables -t nat -I OUTPUT -o lo -p tcp --dport 80 -j REDIRECT --to-port 8080

ฉันยังพบว่า PREROUTING REDIRECT ยังส่งผลกระทบต่อแพ็กเก็ตที่ส่งต่ออีกด้วย นั่นคือหากเครื่องกำลังส่งต่อแพ็กเก็ตระหว่างอินเทอร์เฟซ (เช่นหากทำหน้าที่เป็นจุดเชื่อมต่อ Wi-Fi ที่เชื่อมต่อกับเครือข่ายอีเธอร์เน็ต) กฎ iptables จะจับการเชื่อมต่อของลูกค้าไปยังปลายทางอินเทอร์เน็ต เครื่องจักร. นั่นไม่ใช่สิ่งที่ฉันต้องการ - ฉันเพียงต้องการเปลี่ยนเส้นทางการเชื่อมต่อที่ถูกนำไปยังเครื่องเท่านั้น -m addrtype --dst-type LOCALผมพบว่าผมสามารถทำให้มันมีผลเฉพาะกับแพ็คเก็ตที่ส่งไปยังกล่องโดยการเพิ่ม เช่นบางสิ่งเช่น:

iptables -A PREROUTING -t nat -p tcp --dport 80 -m addrtype --dst-type LOCAL -j REDIRECT --to-port 8080

ความเป็นไปได้อีกอย่างหนึ่งคือการใช้การส่งต่อพอร์ต TCP เช่นใช้socat:

socat TCP4-LISTEN:www,reuseaddr,fork TCP4:localhost:8080

อย่างไรก็ตามข้อเสียอย่างหนึ่งของวิธีการนี้คือแอปพลิเคชั่นที่รับฟังพอร์ต 8080 นั้นไม่ทราบที่อยู่ต้นทางของการเชื่อมต่อขาเข้า (เช่นการบันทึกหรือวัตถุประสงค์ในการระบุตัวตนอื่น ๆ )


0

ตอบที่ 2558 / กันยายน:

ip6tables รองรับ IPV6 NAT แล้ว: http://www.netfilter.org/projects/iptables/files/changes-iptables-1.4.17.txt

คุณจะต้องใช้เคอร์เนล 3.7+

พิสูจน์:

[09:09:23] root@X:~ ip6tables -t nat -vnL
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 REDIRECT   tcp      eth0   *       ::/0                 ::/0                 tcp dpt:80 redir ports 8080
    0     0 REDIRECT   tcp      eth0   *       ::/0                 ::/0                 tcp dpt:443 redir ports 1443

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 6148 packets, 534K bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain POSTROUTING (policy ACCEPT 6148 packets, 534K bytes)
 pkts bytes target     prot opt in     out     source               destination
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.