許多人習慣於讓Outlook記住密碼,收郵件時便不必每次都輸入郵箱密碼,一切讓Outlook代勞。但時間一長,馬虎的人會把自己的郵箱密碼忘記,這樣就無法重新設定或者登入Web介面收取郵件了。Outlook絕對不會告訴你郵箱的密碼是多少,即使你找到了註冊表中Outlook儲存體帳戶和密碼資訊的索引值,由於密碼資訊都是加密儲存的,你還是無法提取密碼。我們的對策就是針對郵箱服務中安全機制最薄弱的環節採取行動……
眾所周知,POP3協議本質上是一種明文協議,也就是說,雖然Outlook本機存放區的密碼是加密的,但當它串連到POP3伺服器準備收取郵件時,必須以明文的形式提供密碼。因此,只要我們開發一個POP3伺服器(不必是功能完善的POP3伺服器,只要騙過Outlook即可),讓Outlook從該伺服器收取郵件,Outlook就會乖乖地交出加密得嚴嚴實實的密碼。實際上,這種辦法不僅適用於Outlook,而且適用於所有使用POP3的郵件客戶程式,如Outlook Express、Foxmail等。
一、構造POP3伺服器
下面我們要用VS.NET 2003和C#開發一個“偽”POP3伺服器——之所以說它“偽”,那是因為它只有極其有限的功能,只進行到騙出郵箱密碼就停止。
啟動VS.NET 2003,建立一個C#項目,項目的模板選擇“控制台應用程式”,將項目命名為PServer,點擊“確定”建立項目,1所示:
圖1 建立C#項目
VS.NET自動建立PServer名稱空間、 Class1類和Main函數骨架。在Class1.cs檔案的頂端using System語句之後加入下列三個語句:
using System.Net;
using System.Net.Sockets;
using System.Text;
接下來的任務就是修改Main函數,使它作為一個POP3伺服器監聽來自Outlook的請求,當Outlook嘗試串連這個PServer伺服器時,根據POP3協議的要求,我們確認一下Outlook使用者提供的帳戶名稱並要求提供密碼,Outlook提供密碼後,我們在控制台上輸出密碼,這樣就算完成了任務!
在Main函數中,我們的第一個任務是啟動一個POP3伺服器。為此,我們要用System.Net.Sockets名稱空間定義的類建立一個ipEndPoint,讓一個TCP伺服器監聽該端點,接收來自用戶端的請求:
// 在127.0.0.1(本地機器)上建立一個TCP伺服器,監聽
// 110連接埠的請求(110是POP3伺服器的預設連接埠)
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"),110);
TcpListener tcpServer = new TcpListener(ipEndPoint);
tcpServer.Start();
// 等待來自POP3客戶程式(如Outlook)的串連請求
TcpClient tcpClient = tcpServer.AcceptTcpClient();
當一個POP3客戶程式串連該伺服器時,伺服器必須按照POP3協議的要求對客戶程式作出應答。根據POP3協議RFC 1939規範的定義,伺服器首先要做的是返回一個歡迎資訊:
// 向客戶程式返回歡迎資訊
NetworkStream ns = tcpClient.GetStream();
byte[] outbytes = Encoding.ASCII.GetBytes("+OK Welcome" + Environment.NewLine);
ns.Write(outbytes,0,outbytes.Length);
客戶程式接收到歡迎資訊後,同樣也會按照POP3協議的要求發送帳戶名稱。我們把這個帳戶名稱記錄下來以便以後使用,代碼如下:
// 接收和記錄郵箱帳戶名稱
byte[] userBytes = new byte[255];
ns.Read(userBytes,0,userBytes.Length);
收到帳戶名稱資訊後,我們要告訴Outlook說這個名稱沒有問題,客戶程式一收到這個資訊就會發送密碼,然後我們再把密碼也記錄下來。實現代碼是:
// 告訴客戶程式帳戶名稱正確
outbytes = Encoding.ASCII.GetBytes("+OK" + Environment.NewLine);
ns.Write(outbytes,0,outbytes.Length);
// 接收和記錄帳戶密碼
byte[] pwdBytes = new byte[255];
ns.Read(pwdBytes,0,pwdBytes.Length);
接下來要做的就是擷取位元組數組的內容,將它們轉換成字串,然後輸出到控制台:
// 在控制台上顯示出帳戶名稱、密碼
Console.WriteLine("帳戶名稱:" + Encoding.ASCII.GetString(userBytes));
Console.WriteLine("帳戶密碼:" + Encoding.ASCII.GetString(pwdBytes));
既然已經獲得了密碼,伺服器的任務已經完成了,現在可以關閉它。強行關閉伺服器會導致客戶程式顯示錯誤資訊,不過這裡我們並不在乎。關閉伺服器的代碼是:
// 關閉伺服器
ns.Close();
tcpClient.Close();
tcpServer.Stop();
將上面的所有代碼依次輸入Main函數,編譯一下就得到了一個PServer.exe執行檔案,它就是我們的偽POP3伺服器。PServer.exe體積很小,發行版只有16 KB。
二、獲得密碼
首先啟動PServer.exe,讓我們的偽POP3伺服器開始監聽來自客戶程式的請求。
啟動Outlook,點擊菜單“工具→電子郵件帳戶”,選擇“查看或更改現有電子郵件帳戶”,找到要恢複密碼的電子郵件帳戶,點擊“更改”開啟它的屬性對話方塊,2,把POP3伺服器設定為localhost:
圖2 更改Outlook電子郵件帳戶
在Outlook中接收一下郵件,3所示,Outlook 將報告說伺服器中斷了串連,不必理睬。
圖3 Outlook已經把密碼發送到偽POP3伺服器了
現在PServer.exe已經得到帳戶的密碼了,4所示,abc帳戶的密碼原來是abcdefg:
圖4 偽POP3伺服器返回的使用者名稱和密碼
三、利用嗅探工具
基於POP3密碼在網路上以明文形式傳遞這一事實,我們還可以利用嗅探工具分析TCP/IP通訊過程獲得帳戶密碼。如果你沒有VS.NET開發工具,那麼可以用這種辦法獲得密碼。即使你擁有VS.NET,也可以用嗅探工具瞭解POP3通訊的詳細情況,加深對POP3通訊的理解,這對我們用編程的方式利用POP3協議大有好處。
能夠分析TCP/IP通訊過程的嗅探工具很多,Ethereal就是一款著名的免費跨平台分析工具。下面我們就以它為例,看看POP3通訊步驟和截獲POP3密碼的過程。
從http://www.ethereal.com/distribution/win32/下載WinPcap驅動程式和Ethereal的Windows版軟體包(兩者大小分別約300 KB和8.1 MB),安裝WinPcap,再安裝Ethereal。
啟動Ethereal,選擇菜單Capture→Start,在圖5介面中,Interface欄選擇與Internet通訊的那塊網卡,點擊OK。
圖5 Ethereal
啟動Outlook,用遺忘密碼的帳戶收一下郵件(不必將帳戶的POP3伺服器改成localhost),然後在Ethereal中點擊Stop按鈕。圖6顯示了一次實驗的結果:
圖6 嗅探結果
Ethereal的嗅探結果詳細地顯示了Outlook與伺服器通訊的過程。正如我們前面介紹的,從No 6(圖七最左欄的編號)記錄開始,客戶程式和伺服器之間建立了POP3通訊聯絡:No 6伺服器應答說OK,表示伺服器運行正常,可以提供服務,No 7客戶程式發送一個請求USER ltt,即告知伺服器郵箱帳戶的名稱ltt,No 8是TCP通訊資料,在此我們不必理會,No 9記錄伺服器應答說“+OK”(帳戶名稱沒問題),並要求提供ltt帳戶的密碼,No 10記錄客戶程式發送訊息“PASS llll”,其中llll就是要尋找的密碼,No 11記錄伺服器回答說OK,No 12記錄客戶程式發送請求STAT,STAT命令要求伺服器以規範的格式返回郵件數量、佔用空間,No 13記錄伺服器回答說郵件數量0、佔用空間0,最後,No 14記錄客戶程式發送QUIT結束會話請求,No 15記錄伺服器結束會話——這就是一次完整的POP3通訊過程。
遇到密碼丟失的情況,動動腦筋另闢蹊徑,其實你自己就能夠把握一切。
來源程式可以在 這裡 下載。