--- Begin Message ---
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",
--- End Message ---