2013-04-12 32 views
5

Có (tương thích) cách để spoof (như root) các unix socket (socket hệ thống tập tin)thông tin ngang hàng mà có thể thu được bằng cách getsockopt(), tùy chọn SO_PEERCRED?Ổ cắm UNIX: Có thể giả mạo getockopt() SO_PEERCRED không?

Bối cảnh:
tôi cần phải kết nối với một ứng dụng máy chủ (mà tôi không thể sửa đổi) mà kiểm tra UID của quá trình này kết nối với nó qua SO_PEERCRED. Tôi muốn giả mạo thông tin để có thể để kết nối với ứng dụng làm gốc, quá.

CẬP NHẬT

Để làm rõ các câu hỏi:
tôi đang tìm kiếm một cách không xâm lấn mà server thấy một peer cụ thể UID/GID. Solutions đang nản mà cần phải thay đổi kernel (hoặc mất việc sử dụng các module kernel) hoặc được thay đổi quá trình máy chủ hoặc nó tải/quá trình liên kết trong bất kỳ cách nào (LD_PRELOAD, chặn cuộc gọi hệ thống vv).

Về cơ bản, giải pháp sẽ hoạt động khi chạy trên bất kỳ máy chủ Linux nào (hoặc unix nói chung) mà không có bất kỳ yêu cầu đặc biệt nào. Quá trình máy chủ có thể đang chạy.

+1

Nếu bạn là 'root', tại sao không chỉ' setuid'? Bạn có thể làm điều đó từ một quy trình con được kiểm soát hoàn toàn để bạn có thể tránh thực sự mất đặc quyền. – nneonneo

+0

Tôi không chắc chắn, nhưng dưới Linux có một giá trị bát phân được đặt trước cờ trong '/ proc//fdinfo/'. – alk

+1

Bạn có thể kiểm soát sự bắt đầu của quá trình máy chủ, tức là, bạn có thể sử dụng LD_PRELOAD để sửa đổi hàm thư viện/syscall thunk để thay đổi thông tin đăng nhập được báo cáo không? –

Trả lời

-1

No. Lý do là cơ chế cung cấp UID và GID của đồng đẳng là nội bộ vào hạt nhân và bạn không thể giả mạo hạt nhân! Hạt nhân sử dụng PID của peer để suy ra các thông tin quan trọng của peer. Điều này xảy ra khi một bên thực hiện một connect trên ổ cắm. Xem cuộc gọi đến copy_peercred() từ unix_stream_connect() trong net/unix/af_unix.c. Không có cách nào mà peer có thể thay đổi dữ liệu mà nó gửi hoặc socket sẽ thuyết phục kernel rằng PID của peer không phải là nó. Điều này khác với các ổ cắm AF_INET trong đó hạt nhân không có kiến ​​thức nội bộ về quy trình của người ngang hàng và chỉ có thể thấy dữ liệu trong các tiêu đề gói IP mà peer gửi.

Điều duy nhất bạn có thể làm để có hiệu ứng này là đặt UID hiệu quả của quy trình ngang hàng thành gốc hoặc bất kỳ UID/GID nào bạn muốn, và bạn cần có mật khẩu gốc hoặc đặc quyền sudo.

+1

Nhưng bạn * có thể giả mạo hạt nhân - làm gốc, bạn có thể sửa đổi hành vi của hạt nhân đang chạy bằng cách tải một mô-đun. –

+0

@ChrisStratton: Không có mô-đun nào bạn viết có thể thay đổi hành vi của các ổ cắm miền Unix. –

+0

Bạn bị ** nhầm lẫn khi tin tưởng điều đó. Cách tiếp cận dễ nhất sẽ là tạo ra một mô-đun sẽ chỉ đạo lại cuộc gọi hệ thống tại điểm công văn ngay sau khi nhập vào hạt nhân, nhưng thay đổi nội bộ của việc triển khai socket unix miền cuối cùng cũng là một lựa chọn. Hãy nhớ rằng, một cái gì đó không được xuất khẩu không được bảo vệ *, nó chỉ đơn thuần là * khó định vị * - và không phải tất cả những gì khó khăn khi nguồn mở và các cài đặt xây dựng có thể đã biết. –

3

Bạn đang đi đúng hướng. Một tiến trình gốc có các đặc quyền để giả mạo những thứ như thế này, vấn đề chỉ là SO_PEERCRED không cung cấp cơ chế hoặc API cho một quy trình để xác định danh tính nào nên được trình bày cho đồng đẳng.

Hai điều bạn có thể làm:

  1. Tạm thả root (setreuid(desired,-1)) khi bạn thực hiện cuộc gọi connect. Một kết nối unix-domain được đóng dấu với các thông tin của peer tại thời điểm quá trình gọi là connect (và listen theo cách khác). SO_PEERCRED không cho bạn biết thông tin đăng nhập của đồng đẳng tại thời điểm hiện tại. Sau đó, bạn có thể tiếp tục root.

  2. Tốt hơn, hãy sử dụng một API khác. API thông báo cho phép một quá trình chọn những gì xác định để trình bày cho một peer. Gọi số sendmsg với số struct cmsg có chứa thông tin xác thực bạn muốn gửi. Hạt nhân sẽ bỏ qua thông tin xác thực được chỉ định bởi người dùng không có đặc quyền và luôn đảm bảo mặt bên kia nhìn thấy danh tính thực tế, nhưng quy trình đặc quyền có thể giả vờ là bất kỳ ai khác. Đây là một kết hợp tốt hơn cho nhu cầu của bạn, bởi vì bỏ và lấy lại gốc là một hoạt động nguy hiểm và trong trường hợp này là không cần thiết. Google cho "SCM_CREDENTIALS" (hoặc "man-K" cho nó trên hệ thống của bạn) để lấy mẫu mã.

+1

Nếu máy chủ không đặt tùy chọn socket SO_PASSCRED và đọc thông tin đăng nhập thì giải pháp 2 sẽ không hoạt động. Nếu nó chỉ sử dụng SO_PEERCRED thì bạn bị mắc kẹt với xác thực PID đơn giản, một lần. Đối với ví dụ SO_PEERCRED, hãy xem http://man7.org/tlpi/code/online/dist/sockets/scm_cred_recv.c.html. Trong mọi trường hợp, đối với root để sử dụng SCM_CREDENTIALS cho đặc quyền thấp hơn là khó "giả mạo". –

+1

OK, gọi nó là "mạo danh" rồi ... Ngoài ra, tôi có vẻ nhớ rằng nếu bạn gửi một số thông tin đăng nhập, bạn không cần phải đặt SO_PASSCRED ở đầu kia; họ chỉ nên đến với bạn trong đầu ra 'recvmsg'. Có lẽ đó là hệ điều hành phụ thuộc? Tôi không có xu hướng sử dụng Linux. SO_PASSCRED thường là khi bạn muốn đọc thông tin đăng nhập nhưng bên kia không viết chúng; nó báo cho hạt nhân cung cấp cho bạn thông tin đăng nhập của người ngang hàng với mỗi thông điệp (đặc biệt tốt cho các ổ cắm DGRAM). –

+1

Đọc ví dụ: "Chúng tôi phải đặt tùy chọn socket SO_PASSCRED để nhận thông tin đăng nhập". Tương tự cũng đúng đối với BSD/FreeBSD trong đó tùy chọn được gọi là SCM_CREDS. –

Các vấn đề liên quan