CVE-2022-46377,CVE-2022-46378
An out-of-bounds read vulnerability exists in the PORT command parameter extraction functionality of Weston Embedded uC-FTPs v 1.98.00. A specially-crafted set of network packets can lead to denial of service. An attacker can send packets to trigger this vulnerability.
The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.
Weston Embedded uC-FTPs v 1.98.00
uC-FTPs - https://weston-embedded.com/micrium/overview
6.5 - CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H
CWE-823 - Use of Out-of-range Pointer Offset
uC-FTPs is Micrium’s FTP server. It is designed to be used on embedded systems running the µC/OS-II or µC/OS-III RTOS kernels. This FTP server implements part of the following RFCs: RFC 959, RFC 2389, Draft IETF.
When an authenticated user sends the PORT
command to uC-FTPs with no arguments, the server attempts to find an ascii digit within the network buffer when extracting the ip address argument and the port argument. If no ascii digit is found, it will infinitely increment the pointer until the pointer accesses unmapped memory. This bug results in a denial of service in any case where unmapped memory is accessed prior to an ascii digit being read from memory.
The portion of the code responsible for extracting the IP address from the PORT
command expects to find an ascii digit within the network buffer.
for (i = 0; i <= 3; i++) {
dig = ASCII_IsDig(*ftp_session->CtrlCmdArgs);
while ((dig == DEF_NO) && (ftp_session->CtrlCmdArgs != (CPU_CHAR *)0)) {
ftp_session->CtrlCmdArgs++;
dig = ASCII_IsDig(*ftp_session->CtrlCmdArgs);
}
p_addr[i] = Str_ParseNbr_Int32U(ftp_session->CtrlCmdArgs, &ftp_session->CtrlCmdArgs, 10);
}
Thread 3 "app" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff759d700 (LWP 8653)]
FTPs_ProcessCtrlCmd (ftp_session=0x7ffff759cb70) at Source/ftp-s.c:1913
1913 dig = ASCII_IsDig(*ftp_session->CtrlCmdArgs);
(gdb) i r
rax 0x555555588000 93824992444416
rbx 0x0 0
rcx 0xe6 230
rdx 0x555555588000 93824992444416
rsi 0x7ffff759cb78 140737343245176
rdi 0x0 0
rbp 0x7ffff759cb10 0x7ffff759cb10
rsp 0x7ffff759ca80 0x7ffff759ca80
r8 0x0 0
r9 0xf 15
r10 0x55555555f95d 93824992278877
r11 0x0 0
r12 0x7ffff7d9ddde 140737351638494
r13 0x7ffff7d9dddf 140737351638495
r14 0x7ffff7d9dde0 140737351638496
r15 0x7ffff759cfc0 140737343246272
rip 0x5555555584c7 0x5555555584c7 <FTPs_ProcessCtrlCmd+1958>
eflags 0x10206 [ PF IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
k0 0x0 0
k1 0x0 0
k2 0x0 0
k3 0x0 0
k4 0x0 0
k5 0x0 0
k6 0x0 0
k7 0x0 0
(gdb) bt
#0 FTPs_ProcessCtrlCmd (ftp_session=0x7ffff759cb70) at Source/ftp-s.c:1913
#1 0x00005555555573ff in FTPs_CtrlTask (p_arg=0x7ffff7d9dec0) at Source/ftp-s.c:1007
#2 0x00007ffff7f9c609 in start_thread (arg=<optimized out>) at pthread_create.c:477
#3 0x00007ffff7ec1133 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
The while loop responsible for incrementing the ftp_session->CtrlCmdArgs
should also terminate in the case where a NULL
byte is read from the network buffer. The network buffer is guaranteed to contain a NULL
byte because the caller FTPs_CtrlTask
explicitly places one at the end of received network data. Example bugfix below:
for (i = 0; i <= 3; i++) {
dig = ASCII_IsDig(*ftp_session->CtrlCmdArgs);
while ((dig == DEF_NO) && (ftp_session->CtrlCmdArgs != (CPU_CHAR *)0) && (*ftp_session->CtrlCmdArgs != 0)) {
ftp_session->CtrlCmdArgs++;
dig = ASCII_IsDig(*ftp_session->CtrlCmdArgs);
}
p_addr[i] = Str_ParseNbr_Int32U(ftp_session->CtrlCmdArgs, &ftp_session->CtrlCmdArgs, 10);
}
The portion of the code responsible for extracting the port number from the PORT
command expects to find an ascii digit within the network buffer.
for (i = 0; i <= 1; i++) {
dig = ASCII_IsDig(*ftp_session->CtrlCmdArgs);
while ((dig == DEF_NO) && (ftp_session->CtrlCmdArgs != 0)) {
ftp_session->CtrlCmdArgs++;
dig = ASCII_IsDig(*ftp_session->CtrlCmdArgs);
}
p_port[i] = Str_ParseNbr_Int32U(ftp_session->CtrlCmdArgs, &ftp_session->CtrlCmdArgs, 10);
}
Core was generated by `./app'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 FTPs_ProcessCtrlCmd (ftp_session=0x7f19f6bf1b70) at Source/ftp-s.c:1921
1921 dig = ASCII_IsDig(*ftp_session->CtrlCmdArgs);
[Current thread is 1 (Thread 0x7f19f6bf2700 (LWP 8975))]
(gdb) i r
rax 0x56184ef03000 94662403567616
rbx 0x0 0
rcx 0xe6 230
rdx 0x56184ef03000 94662403567616
rsi 0x7f19f6bf1b78 139749490629496
rdi 0x0 0
rbp 0x7f19f6bf1b10 0x7f19f6bf1b10
rsp 0x7f19f6bf1a80 0x7f19f6bf1a80
r8 0x0 0
r9 0x19 25
r10 0x56184eefb95d 94662403537245
r11 0x0 0
r12 0x7f19f73f2dde 139749499022814
r13 0x7f19f73f2ddf 139749499022815
r14 0x7f19f73f2de0 139749499022816
r15 0x7f19f6bf1fc0 139749490630592
rip 0x56184eef457f 0x56184eef457f <FTPs_ProcessCtrlCmd+2142>
eflags 0x10206 [ PF IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
k0 0x0 0
k1 0x0 0
k2 0x0 0
k3 0x0 0
k4 0x0 0
k5 0x0 0
k6 0x0 0
k7 0x0 0
(gdb) bt
#0 FTPs_ProcessCtrlCmd (ftp_session=0x7f19f6bf1b70) at Source/ftp-s.c:1921
#1 0x000056184eef33ff in FTPs_CtrlTask (p_arg=0x7f19f73f2ec0) at Source/ftp-s.c:1007
#2 0x00007f19f75f1609 in start_thread (arg=<optimized out>) at pthread_create.c:477
#3 0x00007f19f7516133 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
The while loop responsible for incrementing the ftp_session->CtrlCmdArgs
should also terminate in the case where a NULL
byte is read from the network buffer. The network buffer is guaranteed to contain a NULL
byte because the caller FTPs_CtrlTask
explicitly places one at the end of received network data. Example bugfix below:
for (i = 0; i <= 1; i++) {
dig = ASCII_IsDig(*ftp_session->CtrlCmdArgs);
while ((dig == DEF_NO) && (ftp_session->CtrlCmdArgs != 0) && (*ftp_session->CtrlCmdArgs != 0)) {
ftp_session->CtrlCmdArgs++;
dig = ASCII_IsDig(*ftp_session->CtrlCmdArgs);
}
p_port[i] = Str_ParseNbr_Int32U(ftp_session->CtrlCmdArgs, &ftp_session->CtrlCmdArgs, 10);
}
2022-12-13 - Vendor Disclosure
2023-02-24 - Vendor Patch Release
2023-05-10 - Public Release
Discovered by Kelly Leuschner of Cisco Talos.