CVE-2022-41985
An authentication bypass vulnerability exists in the Authentication functionality of Weston Embedded uC-FTPs v 1.98.00. A specially crafted set of network packets can lead to authentication bypass and denial of service. An attacker can send a sequence of unauthenticated 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
8.6 - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H
CWE-303 - Incorrect Implementation of Authentication Algorithm
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 a FTP client connects to uC-FTPs and sends the USER
command, this causes the internal state variable ftp_session.CtrlState
to change from FTPs_STATE_LOGOUT
to FTPs_STATE_GOTUSER
. If the command following the USER
command is any command whose context state within the FTPs_Cmd
structure is DEF_OFF
for the FTPs_STATE_GOTUSER
state, the uC-FTPs will reply to the client indicating that there was a bad command sequence, but will proceed to set the internal state variable ftp_session.CtrlState
to FTPs_STATE_LOGIN
, bypassing the authentication function. Any following commands requiring authentication will be executed as if by an authenticated user. For commands that require the function BuildPath
to be called, this sequence of packets will result in a DoS of the server, because the authentication callback function which was never called is responsible for setting the variables ftp_session->BasePath
and ftp_session->RelPath
.
Consider the following code snippet when the USER
command is processed:
case FTP_CMD_USER:
p_cmd_arg = FTPs_FindArg(&ftp_session->CtrlCmdArgs);
if (*p_cmd_arg != (CPU_CHAR)0) {
Str_Copy_N(ftp_session->User, p_cmd_arg, sizeof(ftp_session->User));
ftp_session->CtrlState = FTPs_STATE_GOTUSER;
FTPs_SendReply(ftp_session->CtrlSockID, FTP_REPLY_NEEDPASSWORD, (CPU_CHAR *)0);
} else {
FTPs_SendReply(ftp_session->CtrlSockID, FTP_REPLY_PARMSYNTAXERR, (CPU_CHAR *)0);
}
break
Next, if a command is not authorized with the state FTPs_STATE_GOTUSER
, the internal state will be set to FTPs_STATE_LOGIN
after responding with an error message to the client:
if (FTPs_Cmd[ftp_session.CtrlCmd].CmdCntxt[ftp_session.CtrlState] == DEF_OFF) {
if (ftp_session.CtrlState == FTPs_STATE_LOGOUT) {
FTPs_SendReply(ftp_session.CtrlSockID, FTP_REPLY_NOTLOGGEDIN, (CPU_CHAR *)0);
} else {
FTPs_SendReply(ftp_session.CtrlSockID, FTP_REPLY_CMDBADSEQUENCE, (CPU_CHAR *)0);
ftp_session.CtrlState = FTPs_STATE_LOGIN;
}
continue;
}
Thread 3 "app" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff759d700 (LWP 13533)]
__strlen_avx2 () at ../sysdeps/x86_64/multiarch/strlen-avx2.S:65
65 ../sysdeps/x86_64/multiarch/strlen-avx2.S: No such file or directory.
(gdb) i r
rax 0x20 32
rbx 0x7ffff7e18b13 140737352141587
rcx 0x1 1
rdx 0x1 1
rsi 0x7ffff759c738 140737343244088
rdi 0x1 1
rbp 0x7ffff759c770 0x7ffff759c770
rsp 0x7ffff759c1f8 0x7ffff759c1f8
r8 0xffffffff 4294967295
r9 0x0 0
r10 0x55555555f993 93824992278931
r11 0x1 1
r12 0x7ffff759c790 140737343244176
r13 0x55555555f992 93824992278930
r14 0x7ffff759c910 140737343244560
r15 0x73 115
rip 0x7ffff7f2a6e5 0x7ffff7f2a6e5 <__strlen_avx2+21>
eflags 0x10287 [ CF PF SF 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 __strlen_avx2 () at ../sysdeps/x86_64/multiarch/strlen-avx2.S:65
#1 0x00007ffff7e1ad15 in __vfprintf_internal (s=s@entry=0x7ffff759c790, format=format@entry=0x55555555f992 "%s",
ap=ap@entry=0x7ffff759c910, mode_flags=mode_flags@entry=0) at vfprintf-internal.c:1688
#2 0x00007ffff7e2df9a in __vsnprintf_internal (string=0x55555556450a <Mem_Heap+810> "", maxlen=<optimized out>,
format=0x55555555f992 "%s", args=args@entry=0x7ffff759c910, mode_flags=mode_flags@entry=0) at vsnprintf.c:114
#3 0x00007ffff7e03df6 in __GI___snprintf (s=<optimized out>, maxlen=<optimized out>, format=<optimized out>)
at snprintf.c:31
#4 0x0000555555557904 in FTPs_BuildPath (full_abs_path=0x5555555641e0 <Mem_Heap> "", full_abs_path_len=260,
full_rel_path=0x555555564300 <Mem_Heap+288> "", full_rel_path_len=260,
parent_abs_path=0x555555564405 <Mem_Heap+549> "", parent_abs_path_len=260,
cur_entry=0x55555556450a <Mem_Heap+810> "", cur_entry_len=260, base_path=0x7ffff759cbe4 "",
rel_path=0x7ffff759cce4 "", new_path=0x55555555f98e ".") at Source/ftp-s.c:1384
#5 0x000055555555886d in FTPs_ProcessCtrlCmd (ftp_session=0x7ffff759cb70) at Source/ftp-s.c:2052
#6 0x000055555555741f in FTPs_CtrlTask (p_arg=0x7ffff7d9dec0) at Source/ftp-s.c:1007
#7 0x00007ffff7f9c609 in start_thread (arg=<optimized out>) at pthread_create.c:477
#8 0x00007ffff7ec1133 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
(gdb)
Modify the check in ftp-s.c
to check that ftp_session.CtrlState != FTPs_STATE_LOGIN
rather than the previous comparison, which was ftp_session.CtrlState == FTPs_STATE_LOGOUT
. This change allows for proper handling of the FTPs_STATE_GOTUSER
state.
2022-12-13 - Vendor Disclosure
2023-02-24 - Vendor Patch Release
2023-05-10 - Public Release
Discovered by Kelly Leuschner of Cisco Talos.