Python 实现SSH 双因子认证

2015-02-04 14,558

一:问题描述

由于SSH默认是没有双因子认证的,暴力破解SSH服务是最常见的问题。Google的双因子认证设置又太繁琐了。

用Python的pam-python模块写一个简单的实现邮箱验证和记录登录失败密码的功能。

ssh

二:测试系统

os: ubuntu 10.04

python版本:2.7

a) 安装libpam-python

root@ubuntu:~# apt-get install libpam-python
root@ubuntu:~# usermod root -c '#aaaaa@qq.com'

b) 复制脚本到/lib/security/

root@ubuntu:~# cp def_brute_ssh.py /lib/security/

实现代码如下:

import string,random,spwd
import pwd,syslog,crypt
import smtplib
from  email.mime.text import MIMEText
from  email.header import Header

def auth_log(msg):
	syslog.openlog(facility=syslog.LOG_AUTH)
	syslog.syslog("SSH Attack: " + msg)
	syslog.closelog()

def check_pw(user, password):
	hashed_pw = spwd.getspnam(user)[1]
	return crypt.crypt(password, hashed_pw) == hashed_pw

def send2mail(random_num, reciver):
        sender = 'aaaaa@qq.com'
        subject = 'active num'
        username = 'bbbbb@qq.com'
        password = 'passwordofb'

        msg = MIMEText('hi, the number is: ' + random_num)
        msg['Subject'] = Header(subject, 'utf-8')

        smtp = smtplib.SMTP()
        smtp.connect('smtp.qq.com')
        smtp.login(username,password)
        smtp.sendmail(sender, reciver, msg.as_string())
        smtp.quit()
	return 0

def get_mail(user):
	try:
		comments = pwd.getpwnam(user).pw_gecos
		return comments.split('#')[1]
	except Exception:
		return -1

def gen_pin(user,mail):
	random_num = ''.join([i for i in random.sample(string.digits+string.ascii_letters, 8)])
	return random_num if send2mail(random_num, mail) == 0 else -1

def pam_sm_authenticate(pamh, flags, argv):
	try:
		user = pamh.get_user()
		mail = get_mail(user)
	except 	pamh.exception, e:
		return e.pam_result

	if user is None or mail == -1:
		msg = pamh.Message(pamh.PAM_ERROR_MSG, "user isn't exist or the comment is not correct")
		pamh.conversation(msg)
		return pamh.PAM_ABORT

	pin = gen_pin(user,mail)
	if pin == -1:
		msg = pamh.Message(pamh.PAM_ERROR_MSG, "Please check mail server")
		pamh.conversation(msg)
		return pamh.PAM_ABORT

	for attemp in range(0,3):
		msg = pamh.Message(pamh.PAM_PROMPT_ECHO_OFF, "Enter the random pin:")
		resp = pamh.conversation(msg)

		if resp.resp == pin:
			try:
				resp = pamh.conversation(pamh.Message(pamh.PAM_PROMPT_ECHO_OFF,'Password:'))
			except pamh.exception, e:
				return e.pam_result
			
			if not check_pw(user, resp.resp):
				auth_log("Remote Host: %s %s:%s" % (pamh.rhost, user, resp.resp))
				return pamh.PAM_AUTH_ERR
			return pamh.PAM_SUCCESS
		else:
			continue

	return pamh.PAM_AUTH_ERR

def pam_sm_setcred(pamh, flags, argv):
	return pamh.PAM_SUCCESS

def pam_sm_acct_mgmt(pamh, flags, argv):
	return pamh.PAM_SUCCESS

def pam_sm_open_session(pamh, flags, argv):
	return pamh.PAM_SUCCESS

def pam_sm_close_session(pamh, flags, argv):
	return pamh.PAM_SUCCESS

def pam_sm_chauthtok(pamh, flags, argv):
	return pamh.PAM_SUCCESS

c)设置/etc/pam.d/sshd

root@ubuntu:/etc/pam.d# grep -v '^#' sshd | sed /^$/d
auth	requisite	pam_python.so	def_brute_ssh.py
account    required     pam_nologin.so
@include common-account
@include common-session
session    optional     pam_motd.so # [1]
session    optional     pam_mail.so standard noenv # [1]
session    required     pam_limits.so
session    required     pam_env.so # [1]
session    required     pam_env.so user_readenv=1 envfile=/etc/default/locale
@include common-password

d) 设置sshd配置文件(ChallengeResponseAuthentication 改为yes)

root@ubuntu:/etc/pam.d# grep -v '^#' /etc/ssh/sshd_config | sed '/^$/d'
Port 22
Protocol 2
UsePrivilegeSeparation yes
KeyRegenerationInterval 3600
ServerKeyBits 768
SyslogFacility AUTH
LogLevel INFO
LoginGraceTime 120
PermitRootLogin yes
StrictModes yes
PermitEmptyPasswords no
ChallengeResponseAuthentication yes    这个是必须打开的
PasswordAuthentication no
X11Forwarding yes
X11DisplayOffset 10
PrintMotd no
PrintLastLog yes
TCPKeepAlive yes
AcceptEnv LANG LC_*
Subsystem sftp /usr/lib/openssh/sftp-server
UsePAM yes

e) 重启ssh服务 service ssh restart

f) 与hostdeny共同抗拒ssh爆破

root@ubuntu:~#wget http://ftp.jaist.ac.jp/pub/sourceforge/d/de/denyhosts/denyhosts/2.6/DenyHosts-2.6.tar.gz
root@ubuntu:~# tar xvf DenyHost-2.6.tar.gz && cd DenyHost-2.6 && python setup.py install
root@ubuntu:/usr/share/denyhosts# cp denyhosts.cfg-dist denyhosts.cfg && cp daemon-control-dist daemon-control
root@ubuntu:/usr/share/denyhosts# ./daemon-control start
root@ubuntu:/usr/share/denyhosts# ln -s /usr/share/denyhosts/daemon-control /etc/init.d/denyhost
root@ubuntu:~# echo "service denyhost start" >> /etc/rc.local

来个效果图:

11

记录的日志:

1

查看封掉的ip:  root@ubuntu:~#cat -n /etc/hosts.deny

三:tips

改改可以记录root的密码,也可以实现一个ssh后门。

参考链接:

http://pam-python.sourceforge.net/doc/html/

http://pam-python.sourceforge.net/

 

【作者:jianzhen-lab.com尖针实验室  投稿:cvAring 】

 

 

本文作者:cnvring

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/4606.html

Tags:
评论  (0)
快来写下你的想法吧!

cnvring

文章数:1 积分: 3

安全问答社区

安全问答社区

脉搏官方公众号

脉搏公众号