前一段时间我服务器申必被暴力攻击ssh, 连续十几天尝试密码, 身份验证日志里面一天的记录就有十几万行, 突然想到这不是字典的最好来源吗!
搜了一下好像openssh本身不带记录的…
于是就修改openssh的源码, 然后打包成了一个docker镜像, 在这里记录一下过程.
准备镜像
基础镜像
docker pull centos:8
docker run -it centos:8
在这里本来想用ubuntu的基础镜像的, 但是后面编译openssh遇到了缺少依赖库的问题, 好像是少libcrypto的库, 尝试装但是没成功, 就改用centos的镜像了.
然后在容器里面装编译环境, 发现yum源竟然是废的…
换成阿里云.
cd /etc/yum.repos.d/
sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
cd /
yum clean all
yum makecache
装基础工具.
yum install wget
yum install gcc-c++
yum install vim
yum install make
准备修改openssh源码, 我用的9.0p1, 大家可以看一下官网上最新的版本号再拉.
mkdir /dict.build
cd /dict/build
wget https://mirror.leaseweb.com/pub/OpenBSD/OpenSSH/portable/openssh-9.0p1.tar.gz
tar -zxvf openssh-9.0p1.tar.gz
cd openssh-9.0p1
cp auth-passwd.c auth-passwd.c.old
vim auth-passwd.c
现在这个auth-passwd.c
文件里面就是负责验证密码的函数, 我们给他里面这个叫做auth_password
的函数修改一下. 吐槽: 这文件码风也太丑陋了, 作为一个信竞生我实在是品鉴不来!
/*
* This function will never return true, just record username and password in dictionary file.
*/
int auth_password(struct ssh *ssh, const char *password){
Authctxt *authctxt = ssh->authctxt;
// append to file
FILE *fp_dict = fopen("/dict.txt", "a");
fprintf(fp_dict, "%s %s\n", authctxt->user, password);
fclose(fp_dict);
return 0;
}
现在这个函数的功能就是, 收到一个请求, 记录下来请求的用户名和口令, 写进/dict.txt
文件里面, 同时保证不给攻击者留下任何骇入的可能(永远返回失败).
出于OIer的敏感, 我觉着这样写文件可能速度会比较慢, 不过无所谓了(逃
保存退出.
现在回到shell, 编译openssh, 还需要先装几个依赖库
yum -y install zlib zlib-devel
yum -y install openssl-devel
呃, 然后我们要把编译出来的东西放在一个确定的目录, 我选择/dict.openssh/
, 有了这个目录再编译.
# 目录可以改成你自己选的地方
mkdir /dict.openssh
./configure --sysconfdir=/dict.openssh/ --without-zlib-version-check --with-md5-passwords --prefix=/dict.openssh/
make
make install
然后你发现有个报错, 但是不是编译时报错, 是运行时报错, 说少个sshd用户还是啥的, 解决办法就是编辑/etc/passwd
, 加入一句sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
然后就可以运行sshd
命令了, 注意PATH.
/dict.openssh/sbin/sshd
top
命令查看发现sshd已经在运行了.
kill掉, 编辑/dict.openssh/sshd_config
LoginGraceTime 1m
MaxAuthTries 10
MaxSessions 10
让他每次尝试的次数多一点.
写个/run.sh
#!/bin/bash
/dict.openssh/sbin/sshd
bash
整理一下编译剩余的东西, 把g++啥都删了, 退出容器, 打包镜像.
docker commit -a="catium" --change='CMD ["/run.sh"]' e218ed114514 catium/dict-openssh:release
可惜是centos的基础镜像, 体积有点大…
测试
先把正常的ssh换个端口, 换成不常用的, 把22端口留给诱饵.
docker run -p 22:22 -itd catium/dict-openssh:release
然后再宿主机里面ssh连接22端口, 随便输账号密码, 都会denie.
进容器一看, 已经记录下来了.
如果再做点修改, 大概可以做到直接对接mysql之类的数据库, 我就懒得弄了.
挂着容器大概1小时, 就收集了300多组口令, 还是挺好用的.