CURLOPT_SSLENGINE loads arbitrary shared objects
Chưa có ai nhận issue này.
- Ngôn ngữ chính
- C
- Star
- 40.4k
- Fork
- 8.2k
- Merge trung bình
- 2 ngày 13 giờ
- Pull request đã merge (30 ngày)
- 96
Mô tả
Description
ext/curl extension passes CURLOPT_SSLENGINE directly to libcurl. When the OpenSSL backend is used, libcurl forwards the value to OpenSSL's dynamic engine loader, ultimately calling dlopen() on the path. This allows executing native code from PHP code subject to open_basedir / `disable_functions (which are not security boundaries anyway).
This libcurl option is documented in https://curl.se/libcurl/c/CURLOPT_SSLENGINE.html. When libcurl is built with OpenSSL, this calls ENGINE_by_id:
static CURLcode ossl_set_engine(struct Curl_easy *data, const char *name)
{
#ifdef USE_OPENSSL_ENGINE
CURLcode result = CURLE_SSL_ENGINE_NOTFOUND;
ENGINE *e = ENGINE_by_id(name);
// (...)
}
Internally, if OpenSSL can't find the engine in the default path, it loads the dynamic engine support and uses control commands to load id:
if (strcmp(id, "dynamic")) {
if ((load_dir = ossl_safe_getenv("OPENSSL_ENGINES")) == NULL)
load_dir = ossl_get_enginesdir();
iterator = ENGINE_by_id("dynamic");
if (!iterator || !ENGINE_ctrl_cmd_string(iterator, "ID", id, 0) || !ENGINE_ctrl_cmd_string(iterator, "DIR_LOAD", "2", 0) || !ENGINE_ctrl_cmd_string(iterator, "DIR_ADD", load_dir, 0) || !ENGINE_ctrl_cmd_string(iterator, "LIST_ADD", "1", 0) || !ENGINE_ctrl_cmd_string(iterator, "LOAD", NULL, 0))
goto notfound;
return iterator;
}
Then the dynamic loader uses DSO_load with the absolute path as the second parameter merge:
char *merge = DSO_merge(ctx->dynamic_dso, ctx->DYNAMIC_LIBNAME, s);
if (!merge)
return 0;
if (DSO_load(ctx->dynamic_dso, merge, NULL, 0)) {
Internally, DSO_load calls dlfcn_load, which in turn calls dlopen and loads the library:
static int dlfcn_load(DSO *dso)
{
// (...)
char *filename = DSO_convert_filename(dso, NULL);
// (...)
ptr = dlopen(filename, flags);
I have a patch that prevents any path separator in this option, but that may be too restrictive? I'll open a PR later this week if not.
PHP Version
PHP 8.6.0-dev (cli) (built: May 10 2026 23:58:07) (NTS)
Copyright © The PHP Group and Contributors
Zend Engine v4.6.0-dev, Copyright © Zend by Perforce
with Zend OPcache v8.6.0-dev, Copyright ©, by Zend by Perforce
Operating System
No response
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Hướng nghiên cứu
Bắt đầu từ phần xử lý CURLOPT_SSLENGINE trong ext/curl và theo dõi cách giá trị của nó được truyền đến libcurl và trình nạp engine của OpenSSL. Xem lại hành vi được ghi nhận của tùy chọn này và xác định một hạn chế an toàn đối với việc nạp dựa trên đường dẫn; công việc được coi là hoàn tất khi hồi quy đã được kiểm thử và việc nạp các shared object tùy ý bị ngăn chặn mà không làm hỏng các mã định danh engine được hỗ trợ.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- c
- Lĩnh vực
- security
- Loại issue
- Lỗi
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức độ hoạt động
- Ít trao đổi
- Độ rõ ràng
- Khá rõ ràng
- Mức phù hợp với người mới
- 45/100