Package: ckermit Version: 416~beta12-1 Severity: grave Tags: security patch upstream Justification: user security hole X-Debbugs-Cc: Debian Security Team <[email protected]>
This security issue is a bit weird in that the behavior I'm covering here is somewhat documented and was an explicit choice by upstream Kermit authors some years back, which lingers today. (ckermit has been around since the 1980s and security expectations were different then) Kermit, in its default configuration, permits a remote system to make changes to, and retrieve data from, the local one. A malicious remote could damage the local system. This is roughly akin to connecting to a FTP server where the FTP server can also extract files from you, or change arbitrary files on your system, without your involvement. In the default configuration, a remote system can: - change the working directory on the local - overwrite files in the current working directory on the local - download any arbitrary file from the local system Of course, by replacing files like .bashrc or such, a malicious remote could easily cause malicious code to be executed on the local. Also, secret exfiltration is easily possible with this. This seems, to me, to be a pretty critical security issue. The components of it are somewhat documented in kermit help text. I will admit to writing some time back, at https://www.complete.org/kermit/, that "If you connect to untrusted remote systems, I recommend running disable all to prevent the remote from doing much to your local system other than sending files. For instance, rcd is enabled by default and allows the remote to change the directory for you to receive files." But I didn't go the step further to question why this should be so and think through the security process. A simple patch will prevent it. The normal mode of using kermit is to run the kermit command on your local system. Then, within kermit, you connect to a remote host in some way; perhaps with ssh, or maybe with a serial line or something. Then you can run kermit on the remote to interact with it. In some cases, in fact, the local kermit will automatically send "kermit -r" (when sending files to the remote) or "kermit -x" (when receiving files from the remote) to put the remote kermit in an appropriate receive or server mode. When kermit is in server mode, you can issue certain REMOTE commands to it. REMOTE CD, REMOTE DELETE, REMOTE SEND, etc. These are all fine in the usual case, where your local system is controlling a remote. Further detail: The remote system can send a series of bytes (actually a Kermit packet) that can put the local system into server mode also. This capability is typically used to automatically start a file transfer when you type "kermit -s filename" to the remote (or a similar SEND at a kermit prompt on the remote). This is governed by the SET TERMINAL AUTODOWNLOAD setting. The help text states: SET TERMINAL AUTODOWNLOAD { ON, OFF, ERROR { STOP, CONTINUE } } Enables/disables automatic switching into file-transfer mode when a valid Kermit or ZMODEM packet of the appropriate type is received during CONNECT mode. Default is OFF. When TERMINAL AUTODOWNLOAD is ON, the TERMINAL AUTODOWNLOAD ERROR setting tells what to do if an error occurs during a file transfer or other protocol operation initiated by the terminal emulator: STOP (the default) means to remain in command mode so you can see what happened; CONTINUE means to resume the CONNECT session (e.g. so a far-end script can continue its work). This is actually incorrect about the default; the default is ON, as SHOW TERMINAL shows "Autodownload: on, error stop". Autodownload doesn't just mean the system will automatically download a file; it means it can automatically enter server mode also. SET FILE COLLISION is set to BACKUP by default. This combines to make a nasty security situation. For instance, let's do a test. The user is sitting at keyboardhost and is logging in to remotehost. First, we'll prepare a test directory: jgoerzen@keyboardhost:/$ cd /tmp jgoerzen@keyboardhost:/tmp$ mkdir keyboardhosttest jgoerzen@keyboardhost:/tmp$ cd keyboardhosttest jgoerzen@keyboardhost:/tmp/keyboardhosttest$ echo 'Test file' > file1 jgoerzen@keyboardhost:/tmp/keyboardhosttest$ cd / Now, we'll fire up kermit and ssh to a remote: jgoerzen@keyboardhost:/$ kermit (/) C-Kermit>ssh remotehost jgoerzen@remotehost:~$ Now, we'll make a new test file: jgoerzen@remotehost:~$ cd /tmp jgoerzen@remotehost:/tmp$ echo 'Hi' > file1 And fire up kermit on the remote host, running inside the ssh session that is inside our local kermit: jgoerzen@remotehost:/tmp$ kermit (/tmp/) C-Kermit> Right now, our local kermit can't receive a bare file because its CWD is /, which it doesn't have permission for. We can, in fact, see this: (/tmp/) C-Kermit>pwd /tmp (/tmp/) C-Kermit>remote pwd Return to your local Kermit and give a SERVER command. KERMIT READY TO SEND SERVER COMMAND... ---------------------------------------------------- Entering server mode on ssh -e none remotehost Type Ctrl-C to quit. C-Kermit server done ---------------------------------------------------- / (/tmp/) C-Kermit> Now we can issue a command *ON REMOTEHOST* to change the directory on keyboardhost: (/tmp/) C-Kermit>remote cd /tmp/keyboardhosttest And now we can send our own file: (/tmp/) C-Kermit>send file1 Return to your local Kermit and give a RECEIVE command. KERMIT READY TO SEND... SENT: [/tmp/file1] To: [/tmp/keyboardhosttest/file1] (OK) In a new terminal window on the local machine, we see: jgoerzen@keyboardhost:~$ ls -l /tmp/keyboardhosttest/ total 2 -rw-r--r-- 1 jgoerzen jgoerzen 3 Dec 4 07:24 file1 -rw-rw-r-- 1 jgoerzen jgoerzen 10 Dec 4 07:22 file1.~1~ We have just allowed the remote machine to overwrite a file in an arbitrary location on the local machine. We can't delete it though: (/tmp/) C-Kermit>remote del test1 Return to your local Kermit and give a SERVER command. KERMIT READY TO SEND SERVER COMMAND... Entering server mode on ssh -e none remotehost Type Ctrl-C to quit. C-Kermit server done Even though this looks like it was successful, it wasn't. Can remotehost extract arbitrary files from keyboardhost? Yes, it turns out: (/tmp/) C-Kermit>get /bin/bash or (/tmp/) C-Kermit>remote cd /bin (/tmp/) C-Kermit>get bash both work. ckcmai.c defines: #ifndef NOSERVER /* Server services: 0 = disabled 1 = enabled in local mode 2 = enabled in remote mode 3 = enabled in both local and remote modes only as initial (default) values. */ int en_xit = 2; /* EXIT */ int en_cwd = 3; /* CD/CWD */ int en_cpy = 3; /* COPY */ int en_del = 2; /* DELETE */ int en_mkd = 3; /* MKDIR */ int en_rmd = 2; /* RMDIR */ int en_dir = 3; /* DIRECTORY */ int en_fin = 3; /* FINISH */ int en_get = 3; /* GET */ #ifndef NOPUSH int en_hos = 2; /* HOST enabled */ #else int en_hos = 0; /* HOST disabled */ #endif /* NOPUSH */ int en_ren = 3; /* RENAME */ int en_sen = 3; /* SEND */ int en_set = 3; /* SET */ int en_spa = 3; /* SPACE */ int en_typ = 3; /* TYPE */ int en_who = 3; /* WHO */ #ifdef datageneral /* Data General AOS/VS can't do this */ int en_bye = 0; /* BYE */ #else int en_bye = 2; /* PCs in local mode... */ #endif /* datageneral */ int en_asg = 3; /* ASSIGN */ int en_que = 3; /* QUERY */ int en_ret = 2; /* RETRIEVE */ int en_mai = 3; /* MAIL */ int en_pri = 3; /* PRINT */ int en_ena = 3; /* ENABLE */ #else int en_xit = 0, en_cwd = 0, en_cpy = 0, en_del = 0, en_mkd = 0, en_rmd = 0, en_dir = 0, en_fin = 0, en_get = 0, en_hos = 0, en_ren = 0, en_sen = 0, en_set = 0, en_spa = 0, en_typ = 0, en_who = 0, en_bye = 0, en_asg = 0, en_que = 0, en_ret = 0, en_mai = 0, en_pri = 0, en_ena = 0; #endif /* NOSERVER */ SHOW SERVER duplicates this: Function: Status: GET Enabled SEND Enabled MAIL Enabled PRINT Enabled REMOTE ASSIGN Enabled REMOTE CD/CWD Enabled REMOTE COPY Enabled REMOTE DELETE Remote only REMOTE DIRECTORY Enabled REMOTE HOST Remote only REMOTE QUERY Enabled REMOTE MKDIR Enabled REMOTE RMDIR Remote only REMOTE RENAME Enabled REMOTE SET Enabled REMOTE SPACE Enabled REMOTE TYPE Enabled REMOTE WHO Enabled BYE Remote only FINISH Enabled EXIT Remote only ENABLE Enabled keyboardhost can issue a "REMOTE DEL" to remotehost, but remotehost can't issue a "REMOTE DEL" to keyboardhost. So we can see that the remote system is able to control keyboardhost by issuing any command where the enable mode is 1 or 3 in ckcmai.c. Therefore, by changing these defaults, the issues can be mitigated. Note that "remote only" means the situation in which a kermit is in "remote server" mode. This would be the case for the system you have ssh'd to, not the local system you're sitting at. https://www.kermitproject.org/ckututor.html describes: "To upload files (send them from your desktop computer to the remote Unix computer) do the same thing, but use the -g (GET) option instead of -s on the remote computer: kermit -g somefile.txt . This causes your local Kermit to enter server mode; then the remote Kermit program requests the named file and the local Kermit sends it and returns automatically to Connect state when done. " https://www.columbia.edu/~fdc/misc/kermit-file-transfer-overview.html The attached patch adjusts these defaults. I have verified that the remote system can no longer control the local one in that way, but the local one can still control the remote one. This keeps all the usual use cases intact while avoiding a more complex fate with DISABLE ALL. The one that it might break is kermit -g filename, executed on the remote, which would normally cause the local system to transmit the given file. Of course, this is one of the most serious exfiltration risks. The same transfer can easily (actually, MORE easily) be initiated on the local system, without allowing the remote to have control, using the local SEND command, so this is hardly a regression. With the patch, SHOW SERVER now shows: Function: Status: GET Remote only SEND Remote only MAIL Remote only PRINT Remote only REMOTE ASSIGN Remote only REMOTE CD/CWD Remote only REMOTE COPY Remote only REMOTE DELETE Remote only REMOTE DIRECTORY Remote only REMOTE HOST Remote only REMOTE QUERY Remote only REMOTE MKDIR Remote only REMOTE RMDIR Remote only REMOTE RENAME Remote only REMOTE SET Remote only REMOTE SPACE Remote only REMOTE TYPE Remote only REMOTE WHO Remote only BYE Remote only FINISH Remote only EXIT Remote only ENABLE Remote only A remote can still initiate a transfer to the local and give a filename to save it in. This patch also disables the default "collision" mode, which allows the remote to overwrite a local file (and renames the original local file). There may still be some reason for concern for allowing the remote to place a file with an arbitrary name in the local's CWD, but this is also the behavior for zmodem (in lrzsz), and some CLI HTTP clients that follow redirects and use the resulting name for the local. It may not be ideal but it seems to match the generally expected behavior. -- System Information: Debian Release: 13.2 APT prefers stable-updates APT policy: (500, 'stable-updates'), (500, 'stable-security'), (500, 'stable') Architecture: amd64 (x86_64) Kernel: Linux 6.12.57+deb13-amd64 (SMP w/16 CPU threads; PREEMPT) Kernel taint flags: TAINT_PROPRIETARY_MODULE, TAINT_OOT_MODULE, TAINT_UNSIGNED_MODULE Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), LANGUAGE not set Shell: /bin/sh linked to /usr/bin/dash Init: systemd (via /run/systemd/system) LSM: AppArmor: enabled Versions of packages ckermit depends on: ii debconf [debconf-2.0] 1.5.91 ii libc6 2.41-12 ii libncurses6 6.5+20250216-2 ii libpam0g 1.7.0-5 ii libssl3t64 3.5.4-1~deb13u1 ii libtinfo6 6.5+20250216-2 Versions of packages ckermit recommends: ii openssh-client [ssh-client] 1:10.0p1-7 Versions of packages ckermit suggests: pn openbsd-inetd | inet-superserver <none> -- debconf information excluded
commit dc4be0e1d17c674df976dd41c6fa381c767aa76d Author: John Goerzen <[email protected]> Date: Thu Dec 4 07:46:09 2025 -0600 Work around security issues Disable insecure remote commands for local users Also reject overwrites by default diff --git a/ckcmai.c b/ckcmai.c index a84b9cb..39a5049 100644 --- a/ckcmai.c +++ b/ckcmai.c @@ -724,7 +724,7 @@ struct ck_p ptab[NPROTOS] = { /* Initialize the Kermit part ... */ #ifdef VMS /* Default filename collision action */ XYFX_X, /* REPLACE for VAX/VMS */ #else - XYFX_B, /* BACKUP for everybody else */ + XYFX_D, /* REJECT for everybody else */ #endif /* VMS */ #ifdef OS2 /* Flag for file name conversion */ @@ -1574,37 +1574,37 @@ char * remdest = NULL; only as initial (default) values. */ int en_xit = 2; /* EXIT */ -int en_cwd = 3; /* CD/CWD */ -int en_cpy = 3; /* COPY */ +int en_cwd = 2; /* CD/CWD */ +int en_cpy = 2; /* COPY */ int en_del = 2; /* DELETE */ -int en_mkd = 3; /* MKDIR */ +int en_mkd = 2; /* MKDIR */ int en_rmd = 2; /* RMDIR */ -int en_dir = 3; /* DIRECTORY */ -int en_fin = 3; /* FINISH */ -int en_get = 3; /* GET */ +int en_dir = 2; /* DIRECTORY */ +int en_fin = 2; /* FINISH */ +int en_get = 2; /* GET */ #ifndef NOPUSH int en_hos = 2; /* HOST enabled */ #else int en_hos = 0; /* HOST disabled */ #endif /* NOPUSH */ -int en_ren = 3; /* RENAME */ -int en_sen = 3; /* SEND */ -int en_set = 3; /* SET */ -int en_spa = 3; /* SPACE */ -int en_typ = 3; /* TYPE */ -int en_who = 3; /* WHO */ +int en_ren = 2; /* RENAME */ +int en_sen = 2; /* SEND */ +int en_set = 2; /* SET */ +int en_spa = 2; /* SPACE */ +int en_typ = 2; /* TYPE */ +int en_who = 2; /* WHO */ #ifdef datageneral /* Data General AOS/VS can't do this */ int en_bye = 0; /* BYE */ #else int en_bye = 2; /* PCs in local mode... */ #endif /* datageneral */ -int en_asg = 3; /* ASSIGN */ -int en_que = 3; /* QUERY */ +int en_asg = 2; /* ASSIGN */ +int en_que = 2; /* QUERY */ int en_ret = 2; /* RETRIEVE */ -int en_mai = 3; /* MAIL */ -int en_pri = 3; /* PRINT */ -int en_ena = 3; /* ENABLE */ +int en_mai = 2; /* MAIL */ +int en_pri = 2; /* PRINT */ +int en_ena = 2; /* ENABLE */ #else int en_xit = 0, en_cwd = 0, en_cpy = 0, en_del = 0, en_mkd = 0, en_rmd = 0, en_dir = 0, en_fin = 0, en_get = 0, en_hos = 0, en_ren = 0, en_sen = 0, diff --git a/ckuus2.c b/ckuus2.c index 3e8bd45..cc3da82 100644 --- a/ckuus2.c +++ b/ckuus2.c @@ -4138,12 +4138,12 @@ static char *hmxyf[] = { "SET FILE COLLISION option", " Tells what to do when a file arrives that has the same name as", " an existing file. The options are:", -" BACKUP (default) - Rename the old file to a new, unique name and store", +" BACKUP - Rename the old file to a new, unique name and store", " the incoming file under the name it was sent with.", " OVERWRITE - Overwrite (replace) the existing file; doesn't work for", " a Kermit server unless you also tell it to ENABLE DELETE.", " APPEND - Append the incoming file to the end of the existing file.", -" REJECT - Refuse and/or discard the incoming file (= DISCARD).", +" REJECT (default) - Refuse and/or discard the incoming file (= DISCARD).", " RENAME - Give the incoming file a unique name.", " UPDATE - Accept the incoming file only if newer than the existing file.", " ", @@ -7929,7 +7929,7 @@ static char *hxyterm[] = { "SET TERMINAL AUTODOWNLOAD { ON, OFF, ERROR { STOP, CONTINUE } }", " enables/disables automatic switching into file-transfer mode when a Kermit", " or ZMODEM file transfer has been detected during CONNECT mode or while", -" an INPUT command is active. Default is OFF.", +" an INPUT command is active. Default is ON.", #else "SET TERMINAL AUTODOWNLOAD { ON, OFF, ERROR { STOP, CONTINUE } }", " enables/disables automatic switching into file-transfer mode when a Kermit",

