@lightless
2017-04-07T17:25:33.000000Z
字数 3239
阅读 1142
未分类
上篇文章中提出了一个基于docker的蜜罐系统设计,仅仅是将攻击者的流量引入到蜜罐中,但这是不够的,我们要发起反击,将攻击的流量打回去!为什么想这么做呢?记得很久以前参加某个安全沙龙的时候,某个安全专家提出了一个十分猥琐的思路,大意是,如果你发现有一个IP在持续的对你的SSH(以SSH为例,其他服务类似)进行爆破,有一种可能是这个IP被别人种马并自动进行对其他主机的爆破,以便传播自己,在这种情况下,爆破所用的字典很大可能上是固定的,也就是说,你用这个IP爆破过来的流量反爆破回去,很有可能爆破成功XD,于是很自然的就想将这个思路用到蜜罐上了。
以前也尝试过写通过某些很挫的方法记录用户SSH登录的账号密码,但是奈何太菜了,只能记录正确的账号密码,那些爆破失败的密码是没有办法记录的。最近知道了PAM这个东西,工作中也在使用,于是学习了一番。
PAM的全称是Pluggable Authentication Modules for Linux,大概就是一个插件化的认证模块,每个程序可以通过配置文件调用不同的认证模块,以便于达到认证的目的。先排出两个参考资料,已经讲的十分详细了:
The Linux-PAM Guides
Using Pluggable Authentication Modules (PAM)
PAM的配置文件一般放在/etc/pam.d/
文件夹中,例如login
程序的PAM配置文件为/etc/pam.d/login
。
PAM配置文件有固定的格式,一般如下:
module_interface control_flag module_name module_arguments
module_interface
代表的是认证过程中不同的阶段,目前总共有四种:
每个PAM的模块都可以提供多种interface,例如pam_unix.so
就可以提供上面四种所有的interface。
例如下面这个配置,则是将pam_unix.so配置到auth interface。
auth required pam_unix.so
模块的interface指令是可以被堆叠的(原文: stacked),例如reboot的配置:
[root@VM-UBUNTU ~]# cat /etc/pam.d/reboot
#%PAM-1.0
# pam_rootok用于检查当前用户是否为root,检查的方法是查看UID是否为0。如果检查成功,则直接返回成功,不会进行其他的检查。
auth sufficient pam_rootok.so
# pam_console.so模块用于认证用户,如果用户登录到console中了,会检查/etc/security/console.app/这个文件夹中有没有一个`reboot`文件,如果检查通过,则继续向下检查。
auth required pam_console.so
#auth include system-auth
# pam_permit.so允许root或任何登录到console中的用户执行reboot操作。
account required pam_permit.so
每个模块被执行后都只会有两种返回值:成功或失败。ControlFlag
则为了说明当PAM返回了某个结果的时候,应当如何继续认证。换句话说,当堆叠了很多模块的时候,ControlFlag则决定了这次认证中返回值的重要程度。
常见的总共有五种ControlFlag
:
因为我们要记录用户的账户与密码,所以需要一个在auth interface阶段的PAM,根据文档我们也可以看出,需要实现两个方法:
#define PAM_SM_AUTH
#include <security/pam_modules.h>
PAM_EXTERN int pam_sm_authenticate( pamh,
flags,
argc,
argv);
PAM_EXTERN int pam_sm_setcred( pamh,
flags,
argc,
argv);
第二个pam_sm_setcred
方法我们并不关心,所以在代码中简单的返回PAM_SUCCESS就可以了。
/*
* Auth阶段的其他的PAM Interface,不用关心
* */
PAM_EXTERN int
pam_sm_setcred(pam_handle_t *pam_handle, int flags, int argc, const char **argv) {
(void)pam_handle;
(void)flags;
(void)argc;
(void)argv;
return (PAM_SUCCESS);
}
然后就要实现pam_sm_authenticate
方法了,我们在这个方法里要做的事情其实很简单,获取用户名,获取密码,然后记录到文件中。
获取用户名可以通过pam_get_user
实现,而密码可以通过pam_get_authtok
实现,实在是太简单了。代码大概长这个样子:
PAM_EXTERN int
pam_sm_authenticate(pam_handle_t *pam_handle, int flags, int argc, const char **argv) {
const char *username = NULL;
const char *password = NULL;
// get username
int pam_err = pam_get_user(pam_handle, &username, NULL);
if (pam_err != PAM_SUCCESS) {
return pam_err;
}
syslog(LOG_ERR, "Get username: %s", username);
// get password
pam_err = pam_get_authtok(pam_handle, PAM_AUTHTOK, &password, NULL);
if (pam_err != PAM_SUCCESS) {
return PAM_SYSTEM_ERR;
}
syslog(LOG_ERR, "password: %s", password);
write_file(username, password);
return PAM_SUCCESS;
}
其中write_file函数是把username和password拼接起来并写入到文件中。完整的代码已经放到github上了,有兴趣的同学可以去玩一玩,地址:https://github.com/LiGhT1EsS/pam_my_unix