Copy Link
Add to Bookmark
Report
5x06 Manejo de Spywares (Part. 1)
((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
))))))))))))))S)i)e)n)t)e))l)o))p)r)o)h)i)b)i)d)o)))))))))))))))))))
((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
http://kshezine.org
%#############################%
% Manejo de Spywares. Part. I %
% =========================== %
% by NiEtZsChE-2k % c0pyrigth 2001
%#############################% ==============
" WAR IS OVER!. NO WAR IF YOU WANT IT ". John Lennon ´1969.
Zaratustra is reloaded...
Uebermensch is reloaded...
->INDICE
^^^^^^
øøøøøøøøøøøøøøøøøøøøøøøøøøøøøøø|
|
. INTRODUCCION |
. CONCEPTO DE SPYWARE |
. FUNCIONAMIENTO DE SPYWARES |
. CARNIVORE |
. ALTIVORE |
. CONFIGURACION Y MANEJO |
. APROVECHANDO SPYWARES |
. SEGURIDAD ANTE SPYWARES |
. LEYES... (puaj!) |
. DESPEDIDA |
øøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøø
--------------------------------
- Introduccion
************
Wenas a todos, como estan?.
como veis aqui estamos de nuevo, y esta vez trataremos un tema interesante
dentro del area del hacking y seguridad. Primero y principal,puede ser que os
resulte conocida la palabra: SPYWARE. Pues si, muchos de vosotros ya sabeis,
pero puede ser que nunca hallan trabajado con ellos, etc. por ello es que este
tema lo desarrollare en dos partes, con el objetivo de enseñaros el uso,
configuracion, y las cualidades de los spywares. Pues entonces vayamos al
grano, y a jugar con estos bichitos..., hehe.
- Concepto de Spyware
*******************
Bien, un spyware, claro esta lo que significa, "soft de espionaje", si,
justamente esa es la mision y el objetivo de todo spyware, son herramientas
dedicadas al espionaje en internet, solo que estas a partir de ser
configuradas y ya parametrizadas actuan autmaticamente, espiando y siguiendo
rastros del comportamiento de un determinado nodo perteneciente a una red, en
nuestro caso, Internet. Los spywares, son en su mayoria codigos escritos en C,
que traen consigo ficheros de configuracion, los cuales, son configurados y
una vez compilados es solo instalarlo en un determinado portal, nodo, que este
en contacto con otros nodos, o bien dejarlo activo y que espie los movimientos
de otro nodo cualquiera. Pues es ese el concepto basico de un spyware, y para
que son utilizados? simple..., localizar criminales ciberneticos, interceptar
informacion "sensible", monitorear los movimientos de un sospechoso..., etc.
los "007" de internet...
- Funcionamiento de spywares
**************************
Los spywares funcionan en su mayoria, con metodos de rastreo a traves de
direcciones de ips, es decir, cuando teneis el spyware, simplemente es
compilar el code, tocar algunos ficheros de configuracion, modificar ciertos
valores, indicar direcciones ips a ser rastreada,(todo esto lo trataremos mas
adelante) etc. pues justamente es asi como se basa el funionamiento de la
mayoria de los spywares, le colocais una direccion ip a ser rastreada, y el
soft quedara a la espera que ese direccion ip este conectado a la red, una vez
hecho, el soft comenzara a monitorear todos los movimientos de ese nodo, ya
sea desde capturar y filtrar infromacion, mails, negociaciones con servicios,
etc.
- Carnivore
*********
El carnivore (carnivoro), es conocido como uno de los spywares mas eficaces y
que fue escrito exclusivamente para el FBI, con el objetivo de rastrear
criminales..., en lo que se refiere al area de "delitos informaticos",
terrorismo,etc. Los chicos del FBI, simplemente configuran este spyware a su
antojo, y lo parametrizan a un seguimiento y rastreo en especial, podriamos
ejemplificar esto, por el hecho que la gente y organizaciones de
investigacion, han instalado el carnivore especialmente en portales, y en los
principales servidores de correo, con el objetivo de filtrar emails con
cabezeras y cadenas del tipo: "terrorismo", "hack", "bin laden", etc. es decir
cualquier palabra de ese tipo, el mail sera filtrado y guardado, para luego
ser analizado por el personal del FBI, es decir en pocas palabras se llama:
violar la privacidad de la gente. Si, lamentablemente se han instalado redes
secretas de espionaje, a base de spywares, sniffers, etc. con el principal
ejemplo del grupo de investigacion ECHELON, que atenta contra la privacidad
personal en internet, violando asi ciertos derechos del usuario. Pues tenemos
un pequeño detalle que todas estas redes de espionaje, el uso del carnivore en
los servidores de correo y portales, etc. por mas que que atenten contra
nuestra privacidad, ellos se encuentran totalmente cubiertos bajo determinadas
"leyes", que legalizan todas sus acciones, ESTO ES EL COLMO... bien ya sabeis
como funcionan, actuan, en lineas generales los spywares, especialmente el
polemico CARNIVORE. Para profundizar un poco en este analisis, quiero detallar
uno de los varios usos del CARNIVORE, como ser el de "seguir" ips, de tal
forma de espiar sus movimientos, que sitios visita, si manda mails,
(filtrarlos), captar negociaciones telnet, login/pass..., etc. como veran, es
tan fantastico como fatal... pero tenemos un cierto detalle..., resulta que
como sabran los chicos del FBI, no habran liberado los codigos del CARNIVORE,
hehe..., los tienen guardados bajo 7 llaves...,hehe. Pues no os preocupeis,
porque si bien en lineas generales hay pocos spywares eficientes tenemos una
joyita, que podriamos decir que es como si fuese el "hermano" del CARNIVORE,
este spyware que usaremos que es practicamente identico al CARNIVORE, se llama
ALTIVORE,el cual trataremos a continuacion. NO SE VAYAN QUE AUN HAY MAS !!,
xDD
- ALTIVORE
********
Bien, como hemos dicho anteriormente este spyware es muy similar al carnivore
ya que ofrece muchas opciones para ser "explotadas". bien primero os dejare el
code a continuacion:
--------------------------cut here------------------------------
/*
Copyright (c) 2000, Network ICE
All rights reserved.
Use or posession of this code implies agreement with the license
agreement set forth at:
http://www.networkice.com/altivore/altivore-license.html
ALTIVORE v0.9.3
This is a sample program containing some of the features of the
features of the FBI's "Carnivore" program. It is intended to serve
as a point of discussion about Carnivore features. It has not been
thoroughly tested and contains numerous bugs.
This may also serve as an "alternative" for ISPs who do not wish to
install a black-box from the FBI. Court orders demanding data from
the ISP do not necessarily require that Carnivore must be used if
the ISP is able to obtain the data in another manner.
This software may also be useful in network management, such as
backing up data or sniffing a consumer's dial-up connection when
they are reporting problems to customer support.
HOW TO USE THIS SOFTWARE
This software must be compiled and linked with the libpcap library.
Libpcap must likewise be installed on the system in order to for
this to run.
This software has been compiled and briefly tested under Windows
and Linux. It should run on pretty much any system with some minor
adjustments.
Windows Compilation
Download WINPCAP developers kit from:
http://netgroup-serv.polito.it/winpcap/
Point the include directory to "WPdpack/include" and link with the
libraries "libpcap.lib", "user32.lib", and "wsock32.lib".
Linux Compilation
gcc altivore.c -lpcap -Ipcap -o altivore
Note: libpcap broken on RedHat 6.2
WHAT DATA IS COLLECTED?
This module was written to match the FBI's solicitation for
indepedent technical review of Carnivore that was published on
August 25, 2000. Attachment 1 of that document describes several
scenarios for Carnivore usage.
Throughout this document, the term "Alice" refers to the criminal
suspect whose email is being monitored. The term "Bob" refers to
the person Alice is communicating with. The sections below can be
copied/pasted into the file "altivore.ini", which this program uses
to store its configuration information.
[1.1 email header pen-register]
;Monitors all the email headers to and from Alice's
;account. This does not capture the "Subject:" field,
;which is considered by courts to be part of the "data"
;rather than the "call records". This should be
;deployed on or near the email server that processes
;Alice's mail.
mode = email-headers
email.address = alice@example.com
logfile = alice.txt
[1.2 HTTP pen-register from dial-up user]
;Monitors the IP address of web-sites the user visits.
;A complication in this is that the user dials-up and
;receives a unique IP address each time. We monitor
;the dial-up password protocol known as "RADIUS" in
;order to trigger when Alice logs on and in order to
;find out what IP address she is using. This should be
;deployed on a segment behind the bank of dialup servers
;as well as where it can sniff the RADIUS packets. This
;version of Carnivore only monitors Accounting packets;
;you may have to enable this feature in order to get
;this to work right.
mode = server-access
radius.account = alice@example.com
server.port = 80
logfile = alice.csv
[1.3 FTP pen-register from dial-up user]
;Same as above, but monitors FTP instead of HTTP.
mode = server-access
radius.account = alice@example.com
server.port = 80
logfile = alice.csv
[2.1 email content-wiretap]
;Instead of capturing just the headers, this scenario
;captures the full contents of the email
mode = email-content
email.address = alice@example.com
tracefile = alice.tcp
[2.2 email content-wiretap]
;Captures the full content to/from a specific IP
;address. This is the same as running the freeware
;product called TCPDUMP. Example:
; tcpdump -w tracefile.tcp host 192.0.2.189
mode = ip-content
ip.address = 192.0.2.189
tracefile = alice.tcp
DESIGN
No reassembly/reordering
This software does not support IP fragmentation or TCP segment
reordering. As a result, it may miss some emails or accidentally
include segments from other people's emails. This is a crucial
area of discussion; fragmentation issues are an important flaw
in many products, and is likely a flaw of Carnivore as well.
Little SMTP server state
Altivore only monitors a little bit of SMTP server state (it is
impossible to fully support SMTP state without reassembly and
re-ording of fragments). As a result, it may indvertently capture
email not belonging to Alice (the suspect). For example, if the
system is unable to determine when an email message ends, it may
accidentally capture subsequent emails transfered across the same
SMTP connection. It is believed that this is a problem with the
FBI's Carnivore as well.
RADIUS incomplete
This RADIUS parsing code has only been tested at a few ISPs. This
is a concern in some deployments because it won't work. One way
arround this is to force RADIUS Accounting during deployment.
More work on RADIUS decoding needs to be done with Altivore.
Evidence Authentication
Evidence handling is a big concern. Altivore and Carnivore really
should support MD5, PGP, or X.509 private-key signing in order to
fully authenticate files. This would detect later unauthorized
tampering of the evidence.
ALTIVORE VS. NETWORK ICE
Network ICE is a leading software vendor of products similar to
this technology. The "sniff" network traffic looking for signs of
hacker activity in order to protect customer networks. Our primary
competitive advantages are our stateful protocol decoding features
and high-speed sniffing. This means we can monitor gigabit networks
with full packet reassembly and application protocol state.
In contrast, Carnivore was probably written using many of the same
short-cuts that our competitors have taken. We've written Altivore
using similar short-cuts in order to demonstrate the problems with
this approach. We've included a small amount of state in order to
show why stateful inspection is needed in this class of products.
*/
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
/* Links to the libpcap library, standard library on Windows and
* UNIX for sniffing.*/
#include <pcap.h>
#define HASH_ENTRIES 1024
#define ADD_IF_NOT_FOUND 1
#define IGNORE_IF_NOT_FOUND 0
#define TCP_TO_SERVER 0x100
#define TCP_FROM_SERVER 0x000
/** Maximum length of an email address. Portions of the address
* longer than this length are ignored. */
#define MAX_ADDRESS_LENGTH 1024
/** Maximum number of recipients. More recipients than this are
* ignored. */
#define MAX_RECIPIENTS 100
#undef TRUE
#define TRUE 1
#undef FALSE
#define FALSE 0
/** For pretty printing IP addresses */
#define _XIP(a,n) (int)(((a)>>(n))&0xFF)
#define P_IP_ADDR(a) _XIP(a,24), _XIP(a,16), _XIP(a,8), _XIP(a,0)
/**
* TCP/IP protocol extraction stuff.
*/
#define ex8(p,f) ((p)[f])
#define ex16(p,f) ((p)[f] << 8 | (p)[f+1])
#define ex32(p,f) ((ex16(p,f)<<16) | ex16(p,f+2))
#define IP_VERSION(p,f) ((ex8(p,f+0) >> 4) & 0x0F)
#define IP_SIZEOF_HDR(p,f) ((ex8(p,f+0) & 0x0F) * 4)
#define IP_TOTALLENGTH(p,f) ex16(p,f+2)
#define IP_PROTOCOL(p,f) ex8(p,f+9)
#define IP_SRC(p,f) ex32(p,f+12)
#define IP_DST(p,f) ex32(p,f+16)
#define TCP_SRC(p,f) ex16(p,f+0)
#define TCP_DST(p,f) ex16(p,f+2)
#define TCP_SEQNO(p,f) ex32(p,f+4)
#define TCP_ACKNO(p,f) ex32(p,f+8)
#define TCP_FLAGS(p,f) (ex8(p,f+13)&0x3F)
#define TCP_SIZEOF_HDR(p,f) (((ex8(p,f+12)>>4) & 0x0f)*4)
#define TCP_FIN 1
#define TCP_SYN 2
#define TCP_RST 4
#define FREE(x) if (x) free(x)
/**
* A utility function for assigning strings. It solves several
* string handling issues, such as copying over "counted strings"
* rather than NUL-terminated strings.
*/
static void
setString(char **r_str, const void *vstr, int offset, int len)
{
const char *str = vstr; /*kludge: avoid warnings*/
if (*r_str)
free(*r_str);
if (str == NULL) {
*r_str = NULL;
return;
}
if (len == -1)
len = strlen((const char*)str);
*r_str = (char*)malloc(len+1);
memcpy(*r_str, str+offset, len);
(*r_str)[len] = '\0';
}
/** Case-insensitive memcmp() */
static int
memcasecmp(const void *lhs, const void *rhs, int length)
{
int i;
for (i=0; i<length; i++) {
if (tolower(((char*)lhs)[i]) != tolower(((char*)rhs)[i]))
return -1;
}
return 0;
}
/** Utility for case-insensitive comparisons*/
static int
startsWith(const char lhs[], const char rhs[])
{
int len = strlen(lhs);
if ((int)strlen(rhs) < len)
len = strlen(rhs);
return memcmp(lhs, rhs, len) == 0;
}
/**
* Encapsulates the idea of an array of nul terminated strings. Use
* straXXXX() functions.
*/
struct stringarray {
char **str;
int length;
int max;
};
typedef struct stringarray stringarray;
/** stringarray.straAddElement()
* Appends a string onto the end of an array of strings.
*/
void
straAddElement(stringarray *lhs, const char rhs[])
{
if (lhs->length + 1 >= lhs->max) {
int new_max = lhs->max * 2 + 1;
char **new_array = (char**)malloc(sizeof(char*)*(new_max));
if (lhs->str) {
memcpy( new_array,
lhs->str,
sizeof(new_array[0])*lhs->length);
free(lhs->str);
}
lhs->str = new_array;
lhs->max = new_max;
}
lhs->str[lhs->length] = strdup(rhs);
lhs->length++;
}
/**
* These are the several modes that Carnivore/Altivore can run as.
* See the explanation above for more information on how to
* configure these modes.
*/
enum {
/** Capture the headers of email to a text file */
mode_email_headers = 1,
/** Capture just the addresses to/from Alice */
mode_email_addresses,
/** Record accesses to servers with a specific TCP port. */
mode_server_access,
/** Record the full email content for Alice's email*/
mode_email_content,
/** Record a full sniffer trace for the indicated
* IP address. */
mode_ip_content
};
#define MODE(carn, m) ((carn)->mode == m)
static const char *modeNames[] = {"unspecified", "email-headers",
"email-addresses", "server-access", "email-content",
"ip-content", 0};
int
parseMode(const char modeName[])
{
int i;
for (i=0; modeNames[i]; i++) {
if (strcmp(modeName, modeNames[i]) == 0)
return i;
}
return 0;
}
struct intlist {
int list[32];
int count;
};
typedef struct intlist intlist;
/**
* The root object for the Carnivore system.
*/
struct Carnivore
{
/** What mode of operation we are in */
int mode;
/** The name of the sniffer compatible tracefile that data will
* be copied to (when doing full-content wiretaps).*/
char *tracefile;
FILE *fp_trace;
/** Logfile for text information. */
char *logfile;
/** A list of IP addresses to filter for. This is used when a
* court order specifies IP addresses. TODO: allow ranges and
* more IP addresses.*/
intlist ip;
/** Contains a list of ports that we will use in order to
* monitor when a certain type of server has been accessed.
*/
intlist port;
/** TCP/IP connection table for maintaining session state*/
struct TcpCnxn *cxTable[HASH_ENTRIES];
int cxId;
/** Whether or not we should save the last frame to a file */
int do_filter;
/** Whether or not we should remove this connection from
* our list. */
int do_remove;
/** A list of email addresses. We compare these addresses to
* emails as they go by in order to determine if we need to
* make a copy. */
stringarray email_addresses;
/** A list of RADIUS account names that we should monitor
* when doing IP wiretaps. */
stringarray radius_accounts;
/** An array of tracefiles that we will read in order to test
* the system. They must be in tcpdump/libpcap format. */
stringarray testinput;
/** An array of adapter names that we need to open in
* promiscuous mode. */
stringarray interfaces;
};
typedef struct Carnivore Carnivore;
/**
* Test to see if either the source or destination IP address is
* being filtered for. If we are filtering for this IP address,
* then we'll likely save it to a file. Note that we are doing a
* linear search through the array on the assumption that we are
* filtering only a few IP addresses, often just a single one.
*/
int
has_integer(intlist *ip, int ip1, int ip2)
{
int i;
for (i=0; i<ip->count; i++) {
if (ip->list[i] == ip1 || ip->list[i] == ip2)
return 1;
}
return 0;
}
/** Adds the specified IP address to the list of addresses that we
* are filtering for. This may be a configured IP address or one
* that is auto-configured by the RADIUS parsing. */
void
add_integer(intlist *ip, int ip_address)
{
if (ip_address == 0)
return; /*ignore empty IP addresses*/
if (has_integer(ip, ip_address, ip_address))
return; /*ignore duplicates*/
if (ip->count < sizeof(ip->list)/sizeof(int)) {
ip->list[ip->count] = ip_address;
ip->count++;
}
}
/** Delete an IP address from the list of filters. This is called
* when the RADIUS parsing determines that the monitored user has
* hung up. */
void
del_integer(intlist *ip, int ip_address)
{
int i;
for (i=0; i<ip->count; i++) {
if (ip->list[i] == ip_address) {
memmove(ip->list+i, ip->list+i+1,
(ip->count - i - 1)*sizeof(int));
ip->count--;
}
}
}
/** matchName()
* Tests to see if the desired email address should be filtered
* for. This is presumably the email address of somebody that we
* have a court-order to monitor.
*/
int
matchName(const char addr[], int addr_len, stringarray *list)
{
int i;
if (addr == NULL)
return 0;
for (i=0; i<list->length; i++) {
int lhs_len = strlen(list->str[i]);
if (list->str[i][0] == '*') {
/*match end of string, e.g. allow specification of
* "*@suspect.com" to match any emails for a domain*/
if (addr_len >= lhs_len - 1) {
const char *new_lhs = list->str[i]+1;
const char *new_addr = addr+addr_len-lhs_len+1;
if (memcasecmp(new_lhs, new_addr, lhs_len-1) == 0)
return TRUE;
}
}
else if (addr_len == lhs_len
&& memcasecmp(list->str[i], addr, addr_len) == 0)
return TRUE;
}
return FALSE;
}
/**
* A TCP connection entry. We maintain one of these for every
* outstanding connection that we might be tracking. This contains
* the basic TCP info, as well as some higher level protocol info
* for SMTP.
*/
struct TcpCnxn
{
/** Each new connection is identified with a unique ID */
int msg_id;
int server_ip;
int client_ip;
int server_port;
int client_port;
int server_seqno;
int client_seqno;
struct TcpCnxn *next;
time_t creation_time;
char *sender;
int sender_matches;
char *recipient;
stringarray recipients;
/** Whether or not we should save the email message for this
* connection. */
int do_filter;
/** Whether we should filter this one frame. We need this in
* order to capture the trailing dot that ends an email message.
*/
int filter_one_frame;
/** Whether or not we should remove this connection entry at
* the next opportunity. */
int do_remove;
/** Whether we are parsing the 'envelope' or the message
* itself. */
int state;
};
typedef struct TcpCnxn TcpCnxn;
/**
* Create a hash entry for our table. The hash entry is based
* only on the IP addresses and port numbers. The exact
* hash algorithm is unimportant, and should be adjusted over
* time to produce the best results. Note that since we've
* already converted the (src,dst) to (srvr,clnt), we don't
* need to make the hash symmetric.
*/
int
cxHash(TcpCnxn *cx)
{
int result = 0;
result = abs((cx->server_ip ^ (cx->client_ip*2))
^ ((cx->server_port<<16) | cx->client_port));
return result % HASH_ENTRIES;
}
/**
* Compares two connection objects in order to see if they are the
* same one. Only IP address and TCP port info is used in this
* comparison.
*/
int
cxEquals(TcpCnxn *lhs, TcpCnxn *rhs)
{
if (lhs->server_ip != rhs->server_ip)
return 0;
if (lhs->client_ip != rhs->client_ip)
return 0;
if (lhs->server_port != rhs->server_port)
return 0;
if (lhs->client_port != rhs->client_port)
return 0;
return 1;
}
/**
* Looks up a TCP connection object within our table. If not found,
* it may add it (depending upon a parameter).
* @param carn
* This object.
* @param rhs
* A copy of the connection object we are looking up (we simply
* pull out the address/ports from this to compare them).
* @param add_if_not_found
* Whether we should add a new connection object if we cannot
* find an existing one. It is important that we only add
* connection objects during a SYN/SYN-ACK in order to avoid
* accidentally getting state in the middle of the connection.
*/
TcpCnxn *
cxLookup(Carnivore *carn, TcpCnxn *rhs, int add_if_not_found)
{
int h = cxHash(rhs);
TcpCnxn **r_cx = &carn->cxTable[h];
for (;;) {
if (*r_cx == NULL) {
/* The connection object wasn't found. If this was
* a SYN or SYN-ACK, then we'll need to add this
* connection. */
if (add_if_not_found) {
*r_cx = (TcpCnxn*)malloc(sizeof(TcpCnxn));
memset(*r_cx, 0, sizeof(**r_cx));
(*r_cx)->server_ip = rhs->server_ip;
(*r_cx)->client_ip = rhs->client_ip;
(*r_cx)->server_port = rhs->server_port;
(*r_cx)->client_port = rhs->client_port;
(*r_cx)->server_seqno = rhs->server_seqno;
(*r_cx)->client_seqno = rhs->client_seqno;
(*r_cx)->creation_time = time(0);
}
return *r_cx;
}
if (cxEquals(*r_cx, rhs))
return *r_cx;
else
r_cx = &(*r_cx)->next;
}
}
/**
* Resets the SMTP protocol info back to a known state. It is
* important that this be as delicate as possible: it should reset
* data at the slightest provocation in order to avoid accidentally
* capturing somebody else's email.
*/
void
cxResetMsg(TcpCnxn *cx)
{
cx->do_filter = FALSE; /*don't capture these emails*/
if (cx->sender) {
free(cx->sender);
cx->sender = NULL;
}
cx->sender_matches = FALSE;
if (cx->recipients.length) {
int i;
for (i=0; i<cx->recipients.length; i++)
free(cx->recipients.str[i]);
free(cx->recipients.str);
cx->recipients.str = NULL;
memset(&cx->recipients, 0, sizeof(cx->recipients));
}
}
/**
* Removes a TCP connection object from our table. This is called
* whenever we reach the end of SMTP processing, the TCP connection
* closes, or when we timeout and clean up a connection.
*/
void
cxRemove(Carnivore *carn, TcpCnxn *rhs)
{
int h = cxHash(rhs);
TcpCnxn **r_cx = &carn->cxTable[h];
for (;;) {
if (*r_cx == NULL)
break; /*not found*/
else if (cxEquals(*r_cx, rhs)) {
TcpCnxn *cx = *r_cx;
*r_cx = cx->next;
cxResetMsg(cx);
free(cx);
break;
}
else
r_cx = &(*r_cx)->next;
}
}
/** Writes a little-endian integer to the buffer */
void
writeint(unsigned char hdr[], int offset, int x)
{
hdr[offset+0] = (unsigned char)(x>>0);
hdr[offset+1] = (unsigned char)(x>>8);
hdr[offset+2] = (unsigned char)(x>>16);
hdr[offset+3] = (unsigned char)(x>>24);
}
/**
* Saves the current packet to a TCPDUMP compatible file. Note
* that I could use the built-in libpcap file saving mechanism
* but I want to eventually at digital-signatures, so I'll be
* doing strange stuff with the file in the future.
*/
void
carnSavePacket(Carnivore *carn, const unsigned char buf[],
int orig_len, time_t timestamp, int usecs)
{
unsigned char hdr[16];
int snap_len = orig_len;
/* We were triggered to save the frame, now turn this off.
* The SMTP state engine will have to revalidate the next
* packet in order to make sure we should be saving it. */
carn->do_filter = FALSE;
/* Exit from this function (without saving content) if we
* are not running in the appropriate mode.*/
switch (carn->mode) {
case mode_email_content:
case mode_ip_content:
break;
default:
return;
}
if (carn->tracefile == NULL)
return; /*no filename*/
/*Open the tracefile if need be*/
if (carn->fp_trace == NULL) {
struct stat s = {0};
if (stat(carn->tracefile, &s) == 0) {
/*Ooops, it already exists. Maybe we crashed before?
* We should not put the header on the file if it
* already exists */
carn->fp_trace = fopen(carn->tracefile, "a+b");
} else {
/*Create a new one.*/
carn->fp_trace = fopen(carn->tracefile, "wb");
if (carn->fp_trace) {
/*create a file header*/
static const char *foo =
"\xD4\xC3\xB2\xA1" /*MAGIC*/
"\x02\x00\x04\x00" /*major/minor version*/
"\x00\x00\x00\x00" /*this timezone (GMT)*/
"\x00\x00\x00\x00" /*sig figs */
"\xDC\x05\x00\x00" /*snap length*/
"\x01\x00\x00\x00"; /*link type*/
if (fwrite(foo, 1, 24, carn->fp_trace) != 24) {
int xxx = errno;
fclose(carn->fp_trace);
carn->fp_trace = NULL;
errno = xxx;
}
}
}
if (carn->fp_trace == NULL) {
perror(carn->tracefile);
return;
}
}
/* Write the frame to the file */
writeint(hdr, 0, ((int)timestamp));
writeint(hdr, 4, usecs); /*microseconds*/
writeint(hdr, 8, snap_len); /*snapped size of frame*/
writeint(hdr, 12, orig_len); /*original size of frame*/
fwrite(hdr, 1, 16, carn->fp_trace);
fwrite(buf, 1, snap_len, carn->fp_trace);
}
/**
* Prints some text to the logfile.
*/
void
logprint(Carnivore *carn, const char fmt[], ...)
{
FILE *fp;
struct stat s = {0};
va_list marker;
if (carn->logfile == NULL)
return;
if (stat(carn->logfile,&s) == 0)
fp = fopen(carn->logfile, "a");
else
fp = fopen(carn->logfile, "w");
if (fp == NULL) {
perror(carn->logfile);
return;
}
va_start(marker, fmt);
vfprintf(fp, fmt, marker);
va_end(marker);
fclose(fp);
}
/**
* For logging purposes, we frequently need to grab the current
* time. This function formats the current GMT time in ISO
* format. BUG: the time should really be retrieved from the
* packet, not the system time (in case we read from tracefiles
* rather the live network).
*/
void
formatNow(char tbuf[], int sizeof_tbuf)
{
time_t now = time(0);
struct tm *tmptr = gmtime(&now); /*must be GMT*/
if (tmptr == NULL)
strcpy(tbuf, "err");
else
strftime(tbuf, sizeof_tbuf, "%Y-%m-%d %H:%M:%S", tmptr);
}
/**
* This function captures just the email addresses.
*/
void
carnPenEmail(Carnivore *carn, const char sender[],
const unsigned char rcpt[], int offset, int length)
{
char tbuf[64];
if (!MODE(carn, mode_email_addresses))
return; /*not recording email addresses*/
if (carn->logfile == NULL)
return; /*no logfile specified by user*/
if (sender == NULL)
sender = "(nul)";
/*format time: eg. 2000-08-24 08:23:59*/
formatNow(tbuf, sizeof(tbuf));
logprint(carn, "%s, %s, %.*s\n", tbuf, sender,
length, rcpt+offset);
printf("%s, %s, %.*s\n", tbuf, sender,
length, rcpt+offset);
}
enum {
parsing_envelope, parsing_message
};
/**
* Tests to see if the TCP packet data starts with the specified
* command.
*/
int
SMTP_COMMAND(const unsigned char buf[], int offset,
int max_offset, const char cmd[])
{
int cmd_length = strlen(cmd);
int line_length = max_offset-offset;
if (line_length < cmd_length)
return FALSE;
if (memcasecmp(buf+offset, cmd, cmd_length) != 0)
return FALSE;
offset += cmd_length;
/*TODO: test for some boundary conditions*/
return TRUE;
}
/**
* Tests to see if the email body contains a dot '.' on a blank
* line by itself.
*/
int
SMTP_IS_DOT(const unsigned char buf[], int offset, int max_offset)
{
int i;
char last_char = '\0';
for (i=offset; i<max_offset; i++) {
char c = buf[i];
if (c == '.') {
if (i+1 < max_offset
&& (buf[i+1] == '\n' || buf[i+1] == '\r')
&& (last_char == '\n' || last_char == '\r')) {
return TRUE;
}
}
last_char = c;
}
return FALSE;
}
static const char *MAIL_FROM = "MAIL FROM:";
static const char *RCPT_TO = "RCPT TO:";
/**
* Processes the email address in a RCPT TO: or MAIL FROM:
*/
void
match_email(Carnivore *carn, const char *cmd,
const unsigned char buf[], int offset, int max_offset,
TcpCnxn *cx)
{
int length = -1;
int address_matched = FALSE;
/* See if this starts with RCPT TO: or MAIL FROM:, and then
* skip beyond it. */
if (!SMTP_COMMAND(buf, offset, max_offset, cmd))
return;
offset += strlen(cmd);
/* Skip beyond leading whitespace and the initial '<' character
* (if they exist). */
while (offset < max_offset
&& (isspace(buf[offset]) || buf[offset] == '<'))
offset++;
/* Figure out how long the email address is */
for (length=0; offset+length<max_offset; length++) {
char c = (char)buf[offset+length];
if (c == '\r' || c == '\n' || c == '>')
break;
}
if (length < 0)
return;
if (MODE(carn, mode_email_addresses) && cmd == MAIL_FROM ) {
/* If we are doing a pen-register style capturing of email
* addresses, then save off the SOURCE email address. */
if (cx->sender)
free(cx->sender);
cx->sender = (char*)malloc(length+1);
memcpy(cx->sender, buf+offset, length);
cx->sender[length] = '\0';
}
/* See if the email addresses match */
if (matchName((char*)buf+offset, length,
&carn->email_addresses)) {
cx->do_filter = TRUE;
address_matched = TRUE;
}
if (cmd == MAIL_FROM) {
if (address_matched)
cx->sender_matches = TRUE;
} else if (cmd == RCPT_TO) {
if (address_matched || cx->sender_matches)
carnPenEmail(carn, cx->sender, buf, offset, length);
}
}
/**
* Read the number of remaining characters in the line.
*/
int
readLine(const unsigned char buf[], int offset, int max_offset)
{
int length = 0;
while (offset + length < max_offset) {
char c = buf[offset+length];
length++;
if (c == '\n')
break;
}
return length;
}
/**
* Examine the line from the packet in order to determine whether
* it constitutes a legal RFC822 email header. We stop processing
* data at the end of the headers.
*/
int
isEmailHeader(const unsigned char buf[], int offset, int max_offset)
{
int leading_space = 0;
int saw_colon = 0;
while (offset < max_offset && isspace(buf[offset])) {
offset++; /*strip leading whitespace*/
leading_space++;
}
if (offset >= max_offset)
return FALSE; /*empty lines are not a header*/
if (buf[offset] == '>')
return FALSE;
while (offset < max_offset) {
if (buf[offset] == ':')
saw_colon = TRUE;
offset++;
}
if (saw_colon)
return TRUE;
if (leading_space)
return TRUE;
return FALSE;
}
/**
* This function processes a single TCP segment sent by the client
* to the SMTP server.
*/
int
sniffSmtp(Carnivore *carn, TcpCnxn *rhs, int tcp_flags,
const unsigned char buf[], int offset, int max_offset)
{
TcpCnxn *cx;
int length;
/* Lookup the TCP connection record to see if we are saving
* packets on the indicated TCP connection. */
cx = cxLookup(carn, rhs, IGNORE_IF_NOT_FOUND);
/* Process data within this TCP segment */
length = max_offset - offset;
if (length > 0) {
if (cx == NULL) {
/* Add a record for this connection whenever we see a
* an address in an envelope. */
if (SMTP_COMMAND(buf, offset, max_offset, "RCPT TO:"))
cx = cxLookup(carn, rhs, ADD_IF_NOT_FOUND);
if (SMTP_COMMAND(buf, offset, max_offset, "MAIL FROM:"))
cx = cxLookup(carn, rhs, ADD_IF_NOT_FOUND);
}
if (cx != NULL) {
switch (cx->state) {
case parsing_envelope:
match_email(carn, MAIL_FROM,
buf, offset, max_offset, cx);
match_email(carn, RCPT_TO,
buf, offset, max_offset, cx);
if (SMTP_COMMAND(buf, offset, max_offset, "DATA")) {
if (cx->do_filter)
cx->state = parsing_message;
else
cx->do_remove = TRUE;
}
if (SMTP_COMMAND(buf, offset, max_offset, "QUIT"))
cx->do_remove = TRUE;
if (SMTP_COMMAND(buf, offset, max_offset, "RSET"))
cx->do_remove = TRUE;
if (SMTP_COMMAND(buf, offset, max_offset, "ERST"))
cx->do_remove = TRUE;
break;
case parsing_message:
if (MODE(carn, mode_email_headers)) {
int i;
char tbuf[64];
formatNow(tbuf, sizeof(tbuf));
logprint(carn, "--- %08X->%08X %s ---\n",
cx->client_ip, cx->server_ip, tbuf);
/*Parse just the headers from the first packet*/
for (i=offset; i<max_offset; i++) {
int len;
len = readLine(buf, offset, max_offset);
if (!isEmailHeader(buf, offset, offset+len))
break;
if (len > 8 &&
startsWith((char*)buf+offset, "Subject:"))
logprint(carn, "Subject: <removed>\n");
else {
/*Write line to log file*/
logprint(carn, "%.*s", len, buf+offset);
}
offset += len;
}
logprint(carn,"---EOM---\n");
cx->do_remove = TRUE;
cx->do_filter = FALSE;
carn->do_filter = FALSE;
}
if (SMTP_IS_DOT(buf, offset, max_offset))
cx->do_remove = TRUE;
break;
}
}
}
if (cx) {
if (cx->do_filter)
carn->do_filter = TRUE;
if (cx->filter_one_frame) {
carn->do_filter = TRUE;
cx->filter_one_frame = FALSE;
}
if (cx->do_remove
|| (tcp_flags & TCP_RST) || (tcp_flags & TCP_FIN))
cxRemove(carn, rhs);
}
return 0;
}
/**
* RADIUS protocol information we parse out of a packet. In the
* future versions of this software, we are going to need to
* store these records over time; for now, we just parse the
* protocol into this normalized structure.
*/
struct RadiusRecord
{
int radius_client;
int radius_server;
int nas_ip;
int nas_port;
int direction;
int code;
int xid;
int status;
char *user_name;
char *caller_id;
char *called_phone;
char *session_id;
int ip_address;
int session_duration;
};
typedef struct RadiusRecord RadiusRecord;
/** Frees the allocated information */
void
radFree(RadiusRecord *rad)
{
FREE(rad->user_name);
FREE(rad->caller_id);
FREE(rad->called_phone);
FREE(rad->session_id);
}
/**
* Process a single RADIUS command that we saw on the network.
* For right now, we are primarily going to process radius
* accounting packets, as these are the ones most likely to give
* us solid information.
*/
void
radProcess(Carnivore *carn, RadiusRecord *rad)
{
enum {account_start=1, account_stop=2};
if (rad->code == 4 || rad->code == 5) {
/* ACCOUNTING packet: This packet contains an accounting
* record. Accounting records will often contains IP address
* assignments that normal authentication packets won't.*/
if (rad->user_name && matchName(rad->user_name,
strlen(rad->user_name), &carn->radius_accounts)) {
/* Found Alice! Therefore, we going add add Alice's
* IP address to the list of IP addresses currently
* being filtered. Conversely, if this is a stop
* packet, then we will delete the IP address from
* our list. */
if (rad->status == account_start)
add_integer(&carn->ip, rad->ip_address);
else {
/* Default: any unknown accounting message should
* trigger us to stop capturing data. If we make a
* mistake, we should err on the side of not
* collecting data. */
del_integer(&carn->ip, rad->ip_address);
}
carn->do_filter = TRUE; /*capture this packet*/
}
/* Double-check: Look to see if the IP address belongs to
* another person.*/
else if (has_integer(&carn->ip, rad->ip_address, 0)) {
/* The names did not match, yet we have seen some sort
* of packet dealing with the account that we are
* monitoring. This is bad -- it indicates that we might
* have dropped a packet somewhere. Therefore, we are
* going to immediately drop this packet.*/
del_integer(&carn->ip, rad->ip_address);
carn->do_filter = TRUE; /*capture this packet*/
}
}
}
/**
* This function sniffs RADIUS packets off the network, then passes
* the processed RADIUS information to another function that
* deals with the content.
*/
int
sniffRadius(Carnivore *carn, int ip_src, int ip_dst,
const unsigned char buf[], int offset, int max_offset)
{
RadiusRecord recx = {0};
RadiusRecord *rad = &recx;
const static int minimum_length = 20;
int code;
int xid;
int radius_length;
int i;
if (carn->radius_accounts.length == 0)
return 0; /*not scanning radius*/
if (max_offset - offset <= minimum_length)
return 0; /*corrupt*/
/* Parse the RADIUS header info and verify */
code = ex8(buf, offset+0);
if (code < 1 || code > 5)
return 0; /*unknown command/operationg*/
xid = ex8(buf, offset+1);
radius_length = ex16(buf, offset+2);
if (offset + radius_length > max_offset)
return 0; /*packet corrupt*/
else if (offset + radius_length < minimum_length)
return 0; /*packet corrupt*/
else if (max_offset > offset + radius_length)
max_offset = offset + radius_length; /*ignore padding*/
/* Verify the attributes field */
for (i=offset+minimum_length; i<max_offset-2; /*nul*/) {
/*int type = buf[i];*/
int len = buf[i+1];
if (i+len > max_offset)
return 0;
i += len;
}
/* Grab the IP addresses of the client (the Network Access
* Server like Livingston) and the RADIUS authentication
* server. */
if (code == 1 || code == 4) {
rad->radius_client = ip_src;
rad->radius_server = ip_dst;
} else {
rad->radius_client = ip_dst;
rad->radius_server = ip_src;
}
rad->code = code;
rad->xid = xid;
/* Parse the attributes field */
for (i=offset+minimum_length; i<max_offset-2; ) {
int type = buf[i];
int len = buf[i+1];
int data_offset = i+2;
if (i+len > max_offset)
break;
i += len;
len -= 2;
switch (type) {
case 1: /*User-Name*/
/*Lots of names appear to have a trailing nul that we
*should strip from the end of the name.*/
if (len > 1 && buf[data_offset+len-1] == '\0')
len--;
setString(&rad->user_name, buf, data_offset, len);
break;
case 2: /*User-Password*/
break;
case 4: /*NAS-IP-Address*/
rad->nas_ip = ex32(buf,data_offset);
break;
case 5: /*NAS-Port*/
rad->nas_port = ex32(buf,data_offset);
break;
case 8: /*Framed-IP-Address*/
rad->ip_address = ex32(buf,data_offset);
break;
case 19: /*Callback-Number*/
case 20: /*Callback-Id*/
/*TODO: sounds like something we might want to record*/
break;
case 30: /*Called-Station-Id*/
/*Find out the phone number of the NAS. This could be
*important in cases where the evidence will later be
*correlated with phone records.*/
setString(&rad->called_phone, buf, data_offset, len);
break;
case 31: /*Calling-Station-Id*/
/*True "trap-and-trace"! Assuming that caller-id is
*enabled, this will reveal the phone number of the
*person dialing in.*/
setString(&rad->caller_id, buf, data_offset, len);
break;
case 40: /*Acct-Status-Type*/
/*When scanning accounting packets, this is critical in
*order to be able to detect when the service starts and
*stops.*/
rad->status = ex32(buf,data_offset);
if (rad->status < 1 || 8 < rad->status)
rad->status = 2; /*STOP if unknown*/
break;
case 44: /*Acct-Session-Id*/
setString(&rad->session_id, buf, data_offset, len);
break;
case 46: /*Acct-Session-Time*/
/*Could be interesting information to collect*/
if (len == 4)
rad->session_duration = ex32(buf,data_offset);
break;
}
}
/* The data was parsed from the RADIUS packet, now process that
* data in order to trigger on the suspect.*/
radProcess(carn, rad);
radFree(rad);
return 0;
}
struct iphdr {
int offset;
int proto;
int src;
int dst;
int data_offset;
int max_offset;
};
struct tcphdr {
int offset;
int src;
int dst;
int seqno;
int ackno;
int flags;
int data_offset;
};
/**
* This packet is called for each packet received from the wire
* (or from test input). This function will parse the packet into
* the consituent IP and TCP headers, then find which stream the
* packet belongs to, then parse the remaining data according
* to that stream.
*/
int
sniffPacket(Carnivore *carn, const unsigned char buf[],
int max_offset, time_t timestamp, int usecs)
{
struct iphdr ip;
struct tcphdr tcp;
TcpCnxn cn;
/* Make sure that we have a frame long enough to hold the
* Ethernet(14), IP(20), and UDP(8) or TCP(20) headers */
if (max_offset < 14 + 20 + 20)
return 1; /* packet fragment too small */
if (ex16(buf,12) != 0x0800)
return 1; /*not IP ethertype */
/*IP*/
ip.offset = 14; /*sizeof ethernet_header*/
if (IP_VERSION(buf,ip.offset) != 4)
return 1;
ip.proto = IP_PROTOCOL(buf,ip.offset);
ip.src = IP_SRC(buf,ip.offset);
ip.dst = IP_DST(buf,ip.offset);
ip.data_offset = ip.offset + IP_SIZEOF_HDR(buf,ip.offset);
if (max_offset > IP_TOTALLENGTH(buf,ip.offset) + ip.offset)
ip.max_offset = IP_TOTALLENGTH(buf,ip.offset) + ip.offset;
else
ip.max_offset = max_offset;
/* If sniffing somebody's IP address, then sift for it */
if (MODE(carn, mode_ip_content)
&& has_integer(&carn->ip, ip.src, ip.dst))
carn->do_filter = TRUE;
if (ip.proto == 6) {
/*TCP*/
tcp.offset = ip.data_offset;
tcp.dst = TCP_DST(buf,tcp.offset);
tcp.src = TCP_SRC(buf,tcp.offset);
tcp.flags = TCP_FLAGS(buf,tcp.offset);
tcp.seqno = TCP_SEQNO(buf,tcp.offset);
tcp.ackno = TCP_ACKNO(buf,tcp.offset);
tcp.data_offset = tcp.offset
+ TCP_SIZEOF_HDR(buf,tcp.offset);
if (MODE(carn, mode_server_access)) {
/* We are watching for when the user attempts to access
* servers of a specific type (HTTP, FTP, etc.). This
* only tracks SYNs; though we could change the code
* to track all packets. */
if ((tcp.flags & TCP_SYN)
&& has_integer(&carn->ip, ip.src, ip.src)
&& has_integer(&carn->ip, tcp.dst, tcp.dst)) {
char tbuf[64];
formatNow(tbuf, sizeof(tbuf));
logprint(carn, "%s, %d.%d.%d.%d, %d.%d.%d.%d, %d\n",
tbuf, P_IP_ADDR(ip.src), P_IP_ADDR(ip.dst),
tcp.dst);
}
}
else
switch (tcp.dst) {
case 25:
cn.server_ip = ip.dst;
cn.client_ip = ip.src;
cn.server_port = tcp.dst;
cn.client_port = tcp.src;
cn.server_seqno = tcp.ackno;
cn.client_seqno = tcp.seqno;
sniffSmtp(carn, &cn, tcp.flags | TCP_TO_SERVER,
buf, tcp.data_offset, ip.max_offset);
break;
}
} else if (ip.proto == 17) {
/*UDP*/
tcp.offset = ip.data_offset;
tcp.dst = TCP_DST(buf,tcp.offset);
tcp.src = TCP_SRC(buf,tcp.offset);
tcp.data_offset = tcp.offset + 8;
if (tcp.dst == 1812 || tcp.dst == 1813
|| tcp.dst == 1645 || tcp.dst == 1646
|| tcp.src == 1812 || tcp.src == 1813
|| tcp.src == 1645 || tcp.src == 1646) {
/* This looks like a RADIUS packet, either using the
* old port number or the new one. We are going to
* track both RADIUS authentication packets as well
* as accounting packets (depending upon whwere we
* are tapped into the network, we might see one,
* the other, or both).*/
sniffRadius(carn, ip.src, ip.dst,
buf, tcp.data_offset, ip.max_offset);
}
}
/* If one of the filters was successful, then save this packet
* to the tracefile. This is only done*/
if (carn->do_filter)
carnSavePacket(carn, buf, max_offset, timestamp, usecs);
return 0;
}
/**
* A callback function that handles each packet as the 'libpcap'
* subsystem receives it from the network.
*/
void pcapHandlePacket(unsigned char *carn,
const struct pcap_pkthdr *framehdr, const unsigned char *buf)
{
int max_offset = framehdr->caplen;
sniffPacket((Carnivore*)carn, buf, max_offset,
framehdr->ts.tv_sec, framehdr->ts.tv_usec);
}
/**
* Sets the mode of operation according to the input parameter.
*/
void
carnSetMode(Carnivore *carn, const char *value)
{
if (startsWith(value, "email-head"))
carn->mode = mode_email_headers;
else if (startsWith(value, "email-addr"))
carn->mode = mode_email_headers;
else if (startsWith(value, "server-access"))
carn->mode = mode_server_access;
else if (startsWith(value, "email-content"))
carn->mode = mode_email_content;
else if (startsWith(value, "ip-content"))
carn->mode = mode_ip_content;
else
carn->mode = -1;
}
/**
* Parses the IP address. I use this rather than the sockets
* inet_addr() for portability reasons.
*/
int
my_inet_addr(const char addr[])
{
int num = 0;
int offset=0;
while (addr[offset] && !isalnum(addr[offset]))
offset++;
for (; addr[offset]; offset++) {
char c = addr[offset];
if (isdigit(c))
num = (num&0xFFFFFF00) | (((num&0xFF)*10) + (c - '0'));
else if (c == '.')
num <<= 8;
else
break;
}
return num;
}
/**
* Reads in the configuration from a a file such as "altivore.ini".
*/
void
carnReadConfiguration(Carnivore *carn, const char filename[])
{
FILE *fp;
fp = fopen(filename, "r");
if (fp == NULL)
perror(filename);
else {
char line[1024];
/* For all lines within the file */
while (fgets(line, sizeof(line), fp)) {
char *name = line;
char *value;
while (*name && isspace(*name))
name++; /*strip leading whitespace*/
if (*name == '\0' || ispunct(*name))
continue;/*ignore blank lines and comments*/
value = strchr(name, '=');
if (value == NULL)
continue; /*ignore when no equals sign*/
else
value++; /*skip the equals itself*/
while (*value && isspace(*value))
value++; /*strip leading whitespace*/
while (*value && isspace(value[strlen(value)-1]))
value[strlen(value)-1] = '\0'; /*strip trailing WS*/
if (startsWith(name, "mode"))
carn->mode = parseMode(value);
else if (startsWith(name, "email.address"))
straAddElement(&carn->email_addresses, value);
else if (startsWith(name, "radius.account"))
straAddElement(&carn->radius_accounts, value);
else if (startsWith(name, "ip.address"))
add_integer(&carn->ip, my_inet_addr(value));
else if (startsWith(name, "tracefile"))
setString(&carn->tracefile, value, 0, -1);
else if (startsWith(name, "logfile"))
setString(&carn->logfile, value, 0, -1);
else if (startsWith(name, "testinput"))
straAddElement(&carn->testinput, value);
else if (startsWith(name, "interface"))
straAddElement(&carn->interfaces, value);
else if (startsWith(name, "server.port"))
add_integer(&carn->ip, strtol(value,0,0));
else
fprintf(stderr, "bad param: %s\n", line);
}
fclose(fp);
}
}
/**
* Process a test input file.
*/
void
processFile(Carnivore *carn, const char filename[])
{
char errbuf[1024]; /*TODO: how long should this be?*/
pcap_t *hPcap;
/* Open the file */
hPcap = pcap_open_offline(filename, errbuf);
if (hPcap == NULL) {
fprintf(stderr, "%s: %s\n", filename, errbuf);
return; /*ignore this file and go onto next*/
}
/* Pump packets through it */
for (;;) {
int packets_read = pcap_dispatch(
hPcap, /*handle to PCAP*/
10, /*next 10 packets*/
pcapHandlePacket, /*callback*/
(unsigned char*)carn /*canivore*/
);
if (packets_read == 0)
break;
}
/* Close the file and go onto the next one */
pcap_close(hPcap);
}
/**
* Sniff the wire for packets and process them using the libpcap
* interface
*/
void
processPackets(Carnivore *carn, const char devicename[])
{
int traffic_seen = FALSE;
int total_packets_processed = 0;
pcap_t *hPcap;
char errbuf[1024];
hPcap = pcap_open_live( (char*)devicename,
2000, /*snap len*/
1, /*promiscuous*/
10, /*10-ms read timeout*/
errbuf
);
if (hPcap == NULL) {
fprintf(stderr, "%s: %s\n", devicename, errbuf);
return;
}
/* Pump packets through it */
for (;;) {
int packets_read;
packets_read = pcap_dispatch(
hPcap, /*handle to PCAP*/
10, /*next 10 packets*/
pcapHandlePacket, /*callback*/
(unsigned char*)carn /*canivore*/
);
total_packets_processed += packets_read;
if (!traffic_seen && total_packets_processed > 0) {
fprintf(stderr, "Traffic seen\n");
traffic_seen = TRUE;
}
}
/* Close the file and go onto the next one */
pcap_close(hPcap);
}
/*----------------------------------------------------------------*/
int
main(int argc, char *argv[])
{
int i;
Carnivore *carn;
printf("--- ALTIVORE ---\n");
printf("Copyright (c) 2000 by Network ICE Corporation\n");
printf("Public disclosure of the source code does not\n");
printf("constitute a license to use this software.\n");
printf("Use \"altivore -?\" for help.\n");
/* Create the carnivore subsystem */
carn = (Carnivore*)malloc(sizeof(Carnivore));
memset(carn, 0, sizeof(*carn));
/* Read configuration info from "altivore.ini". */
carnReadConfiguration(carn, "altivore.ini");
/* Parse all the options from the command-line. Normally,
* you wouldn't have any command-line options, you would
* simply use the configuration file above. */
for (i=1; i<argc; i++) {
if (argv[i][0] != '-')
straAddElement(&carn->email_addresses, argv[i]);
else switch (argv[i][1]) {
case 'h':
add_integer(&carn->ip, my_inet_addr(argv[i]+2));
break;
case 'i':
straAddElement(&carn->interfaces, argv[i]+2);
break;
case 'l':
setString(&carn->logfile, argv[i]+2, 0, -1);
break;
case 'm':
carn->mode = parseMode(argv[i]+2);
break;
case 'p':
add_integer(&carn->port, strtol(argv[i]+2,0,0));
break;
case 'r':
straAddElement(&carn->testinput, argv[i]+2);
break;
case 'w':
setString(&carn->tracefile, argv[i]+2, 0, -1);
break;
case '?':
printf("Options:\n"
"<email-address> address to filter for, e.g.:\n"
" rncury@telnet.com.br (exact match)\n"
" *@altivore.com (partial match)\n"
" * (match all emails)\n"
);
printf("-h<ip-address>\n"
"\tIP of host to sniff\n");
printf("-i<devicename>\n"
"\tNetwork interface to sniff on\n");
printf("-l<logfile>\n"
"\tText-output logging\n");
printf("-m<mode>\n"
"\tMode to run in, see docs\n");
printf("-p<port>\n"
"\tServer port to filter on\n");
printf("-r<tracefile>\n"
"\tTest input\n");
printf("-w<tracefile>\n"
"\tEvidence tracefile to write packets to\n");
return 1;
default:
fprintf(stderr, "Unknown parm: %s\n", argv[i]);
break;
}
}
/* Print the configuration for debugging purposes */
printf("\tmode = %s\n", modeNames[carn->mode]);
if (carn->tracefile)
printf("\ttracefile = %s\n", carn->tracefile);
if (carn->logfile)
printf("\tlogfile = %s\n", carn->logfile);
for (i=0; i<carn->ip.count; i++)
printf("\tip = %d.%d.%d.%d\n", P_IP_ADDR(carn->ip.list[i]));
for (i=0; i<carn->port.count; i++)
printf("\tport = %d\n", carn->port.list);
for (i=0; i<carn->email_addresses.length; i++)
printf("\temail.address = %s\n", carn->email_addresses.str[i]);
for (i=0; i<carn->radius_accounts.length; i++)
printf("\tradius.accounts = %s\n", carn->radius_accounts.str[i]);
for (i=0; i<carn->testinput.length; i++)
printf("\ttestinput = %s\n", carn->testinput.str[i]);
for (i=0; i<carn->interfaces.length; i++)
printf("\tinterface = %s\n", carn->interfaces.str[i]);
/* Testing only: user can specify tracefiles containing network
* traffic for test purposes. */
if (carn->testinput.length > 0) {
int i;
for (i=0; i<carn->testinput.length; i++)
processFile(carn, carn->testinput.str[i]);
return 0;
}
/* Open adapters and rea*/
if (carn->interfaces.length > 0) {
/*TODO: allow multiple adapters to be opened*/
char *devicename = carn->interfaces.str[0];
processPackets(carn, devicename);
} else {
char *devicename;
char errbuf[1024];
devicename = pcap_lookupdev(errbuf);
if (devicename == NULL)
fprintf(stderr, "%s\n", errbuf);
else
processPackets(carn, devicename);
}
return 0;
}
--------------------------cut here------------------------------
- Configuracion y Manejo
**********************
Una vez que ya tenemos el code, es cuestion de compilarlo y listo, para ello
creamos un directorio llamado "altivore", copiamos el codigo y lo compilamos
alli:
# mkdir /altivore
-luego compilamos el code:
gcc altivore.c -lpcap -lpcap -o altivore
./altivore
-Alli ya tendriamos el altivore listo para ser usado. Pero antes de ello
debemos configurarlo y parametrizarlo a nuestras necesidades y situacion es
decir, definir los nodos que seran rastreados y espiados por el altivore. para
ello crearemos un fichero "altivore.ini", donde sera alli que le definiremos
toda la configuracion, es decir el proggie hara uso de dicho fichero para
trabajar. pues el altivore.ini, seria de este modo, ya sabeis os abris
cualquier editor vi, emacs,etc. y editais esto, luego lo guardais como
"altivore.ini" (en el mismo directorio donde tienen el programa) :
*Altivore.ini*
---------------cut here-------------------
[1.1 email header pen-register]
mode = email-headers
email.address = pepe@ejemplo.com
logfile = pepe.txt
[1.2 HTTP pen-register from dial-up user]
mode = server-access
radius.account = pepe@ejemplo.com
server.port = 80
logfile = pepe.csv
[1.3 FTP pen-register from dial-up user]
mode = server-access
radius.account = pepe@ejemplo.com
server.port = 80
logfile = pepe.csv
[2.1 email content-wiretap]
mode = email-content
email.address = pepe@ejemplo.com
tracefile = pepe.tcp
[2.2 email content-wiretap]
mode = ip-content
ip.address = xxx.xxx.xxx.x (ip de pepe)
tracefile = pepe.tcp
---------------cut here--------------------
Como veis en el fichero que coloque arriba, "altivore.ini", se encuentra
divido en varios bloques, las cuales deben reemplazarse por la informacion del
nodo a ser rastreado, logico..., por otra parte tambien podeis quitar algun
bloque que no os interese, para ello simplemente comentais dicho bloque o
linea con un ";". como ven, alli se encuentran varias funciones que el
altivore ejecutara, ya sabeis para los que todavia no han entendido en partes
como "pepe@ejemplo.com" deben reemplazarlo por el email de la victima que sera
rastreada, como asi tambien en partes como dice "ip.address = xxx.xxx.xxx.x"
debe ser reemplazado, por el ip real de la victima.... (elemental watson!!):P
una vez que hayais ajustado a vuestras medidas la configuracion del altivore,
entraremos a analizar el funcionamiento de cada bloque del fichero, con el
objetivo de comprender el funcionamiento basico de este spyware. En el primer
bloque, seran capturados la cabezera de todos los mails que son enviados y
recibidos por la victima, justamente se creara un fichero con toda esa
informacion, el fichero tendra esta estructura:
---------------------------------------------------
---C0A8C27->C8F67678 2001-01-
03 11 :03:34 ---
Sender: root
---EOM---
--- C0A8C83F->C8F67678 2001-01.
03 11 :04:15 ---
Message-ID
<001501c07575$96eb4b80$3fc8a8c0@email.com>
From = ?iso-8859-
1?Q?Rog=fulano_nerd?=<fulano@email.com>
To: "Mengano nerd"
<mengano@email.com>
References:
<000c01c07575$61c815a0$3fc8a8c0@email.com>
<3A530706.938BFFBC@email.com>
Subject: <removed>
Date: wed, 3 feb 2001 09:09:06
0200
MIME-Version: 1.0
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: 8bit
X-priority: 3
X-MSMail-Priority: Normal
X-Mailer: Microsoft Outlook Express
5.50.4133.2400
X-MimeOLE: Produced By Microsoft
MimeOLE V5.50.4133.2400
---EOM---
como vimos, el altivore, ha capturado diferentes datos respecto de la victima
en lo referente a envios y recepciones de correo, solo en ese bloque ya
tenemos bastante informacion del espiado..., por ello es que digo que el
altivore es tan fantastico como fatal... Luego en el segundo y tercer bloque
tendremos que el altivore capturara informacion respecto de los sitios webs y
ftps los cuales la victima visite..., ahora esto funcionara siempre y cuando
la victima utilize una conexion Dial-up, ya que el el spyware localiza al
usuario a traves del metodo de autentificado RADIUS. En el cuarto bloque el
altivore captura los mails de la victima de forma integra, pudiendo acceder a
la cabezera y contenidos del mail..., funcionaria tanto para el envio de
correo como la recepcion del mismo. ;) veamos ahora un ejemplo de este ultimo
bloque, donde son expuestos una serie de datos interesantes y mejor aun, si se
esta llevando a cabo la obtencion del perfil de un rastreo:
-----------------------------------------------------------------
Received: from fulano
(ded|146.telnet.com
[xxx.xxx.xxx.x])
by server.algo.com
(8.10.1/8.10.1) with SMTP id
lokura1245 for
<mengano@email.com>; Thu, 28
Dec 2001 19:50:20 -0201
From: "fulano"
<fulano@email.com>
To: "mengano"
<mengano@email.com>
Subject: RE: BRBRBJSALKEHJDHSJDHJS*&(
Date: Thu, 28 Dec 2001 19:55:05 -0201
Message-ID:
<WDHFJWHJFKSDHFKDAFFBFHGHJFHJFJF
AA.fulano@email.com>
MIME-Version: 1.0
Content-Type: text/plain
charset="iso-8859-1"
Content-Transfer-Encoding: 8bit
X-priority: 3 (Normal)
X-MSMail-Priority: Normal
X-Mailer: Microsoft Outlook IMO, Build 9.0.2416 (9.0.2911.0)
Importance: Normal
X-MimeOLE: Produced By Microsoft
MimeOLE V5.50.4133.2400
In-reply-To:
<3A4BB5E8.BC9002C6@email.com>
X-UIDL: X'V"j48!!';+!!
to nada,
----Original Message----
From: root [mailto:root]On Behalf Of Fulano
Sent: friday, 28 dec 2001 19:52
T -K:Q
Subject: Re:BRBRBJSALKEHJDHSJDHJS*&(
-------------------------------------------------
Bien, alli tenemos muucha info respecto de la victima solamente a partir de
ese bloque, luego en el ultimo bloque podemos hacer que el spyware funcione
simplemente como un sniffer, capturando y filtrando todos los packets pero
esta tecnica es basada justamente en la direccion ip de la victima, adopta un
funcionamiento muy similar al tcpdump, que en tal caso podriamos hacer
exactamente lo mismo combinandolo con el tcpdump utlizando estos parametros:
# tcpdump -w tracefile.tcp host ip
ejemplo:
-------
# tcpdump -w tracefile.tcp server1.hackme.com 200.199.115.6
lo mas interesante de este ultimo metodo es que con el podriamos capturar todo
tipo de info..., como ser passwords de cuentas de email, negociaciones telnet
(login/pass) y FTP... del usuario del usuario que estemos "analizando"... ;) ,
cosa que desarrollaremos posteiormente combinandolo con netcat.
-----------------------------------------------------------------------------
NOTA: el tcpdump, viene incluido en la mayoria de las distribuciones linux
---- es solo llamarlo desde un terminal. para aquellos que no lo tengan, lo
podran conseguir en cualquier site de hack.
-----------------------------------------------------------------------------
Como estuvimos analizando en los diversos bloques del Spyware, incluso en el
ultimo metodo que tratamos, hemos percibido que esta herramienta es muy
potente a la hora de "investigar" a nuestra victima, al punto de poder espiar
y seguir todos sus movimientos..., como asi tambien obtener claves de acceso,
emails, ftps, etc, etc..., es muchisisma la informacion que podemos obtener a
partir del ALTIVORE, como tambien son muchisimas las opciones que podemos ir
explotando al maximo, simplemente con esto les he dado una iniciativa para que
se introduzcan en el seno de esta herramienta, para los que esteis interesados
en obtener mas info de este excelente spyware, como tambien el site y mas
opciones, simplemente lean los comentarios del codigo, alli tienen los sitios
webs, y mas info sobre el altivore. ;)
- Aprovechando Spywares
*********************
Como vimos hasta el momento y como ya os he explicado, los spywares tienen
infinidad de usos, algunos los hemos analizado aqui, pero justamente queria
hacer enfasis en el objetivo principal de usar spywares, primero y principal
podriamos decir que estas herramientas son imparciales es decir, podrian ser
usadas por grupos secretos de investigacion, por un sysadmin, o por un hacker.
Pienso que el primer caso ya lo hemos visto, el grupo ECHELON, que se dedica a
rastrear criminales potenciales por la red, es decir, no cabe la menor duda
que para usar este metodo simplemente es parametrizar el spyware e instalarlo
en servidores de correo y que escuchen en determiandos puertos, normalmente
serian el 25 (SMTP), el 110 (POP3) o bien el 143 (imapd), como tambien en
sites webs, importantes que el sospechoso pueda llegar a visitar instalado en
el 80 (HTTP), claro esta, que no solo seria esto...., sino que a parte se
efectuarian mas configuraciones con el objetivo de optimizar el rastreo... por
otro lado, un sysadmin podria emplear el ALTIVORE, para que rastree algun ip
en especial, es decir, algun ip sospechoso que este involucrado en los logs
del sistema, para ello el sysadmin apuntaria el spyware al estudio de ese ip y
como hemos visto el altivore facilitaria muchisimo el rastreo del invasor. Por
ultimo caso, los spywares podrian ser usados en el caso del ALTIVORE con el
objetivo que cualquier hacker, quiera rastrear su victima seguir sus
movimientos, como tambien sniffar packets dirigidos a su victima, o peor aun
captar claves de acceso, que eso facilitaria mucho mas un posible ataque...
como hemos visto el uso de un spyware, es justamente adaptarlo a vuestras
situaciones y "necesidades", y logico explotar al maximo el mismo para llegar
a nuestros obejtivos..., saber interpretar la informacion es muy importante,
ya que una simple cadena de caracteres nos podrian dar mucha informacion, que
pueda ser empleada para un determinando footprinting que estemos efectuando
acerca de un sistema. Con esto espero que hayais entendido las diversas
utilidades y el provecho que le podemos sacar a los spywares...
- Seguridad ante Spywares
***********************
Es muy bonito atacar..., pero tambien es importante no ser atacado..., con
esto quiero decir que es de suma importancia saber como protegerse de los
spywares. no hare una guia acerca de anonimicidad en la red, eso lo trataremos
en posteriores ediciones, ahora simplemente hare una reseña rapida y general
para protegernos de los spywares. Principalmente empezemos por enviar nuestro
correo encripatado, eso es importantisimo, como?, pues usando PGP, para mas
info: www.pgp.com ;) enviando nuestro correo encriptado no tendremos problemas
en que violen o accedan al contenido de nuestro correo enviado o recibido. por
otro lado es importante asegurarnos que nuestro servidor de correo envie
automaticamente los correos encripatados, las empresas ChainMail ofrecen
dichos servicios: <http://www.chainmailinc.com>. tambien tenemos este otro
server, Sigaba, <http://www.sigaba.com>. Ofrecen softwares de criptografia,
etc. Pero tenemos un detalle importante, como hemos visto, el altivore no
accederia al contenido de nuestro correo o en caso de que acceda estaria
encriptado, pero de todos modos el spyware obtendria otros datos, como ser: la
proveniencia del mail, adonde fue enviado, fecha, etc. para evitar que el
spyware filtre la cabezera de los correos, un servidor ya ha creado varias
tecnicas y metodos para evitar ese rastreo, con el objetivo de ocultar todos
esos datos, para mas info: <www.privada.net>.
- Leyes...
********
El tema de las leyes, ya sabeis que es un tema que odio, es decir detesto la
abogacia, pero bueno debemos tratar este tema ya que es de suma importancia.
Como sabemos la red secreta ECHELON dirigida por grupos como el FBI, no cabe
la menor duda que estos chicos estan violando la privacidad de miles de
personas en internet, sin embargo estan cubiertos bajo leyes que justifican y
legalizan las acciones de ECHELON. Pero como sabemos eso esta determinado solo
para los grupos secretos de "investigacion", es decir saben que el uso de
spywares y sniffers, es un tanto "ilegal" para las leyes, ya que se encuentra
calificado como "hurto" de informacion privada, y como vosotros ya sabeis los
abogados son muy habiles para crear penas y articulos ficticios que te
declaren culpable... Con esto quiero dejar en claro, que en caso que decidas
usar spywares, no trendras apoyo de ninguna ley, ya que es uno de los delitos
informaticos mas penados, por tanto en caso que decidas usar dichas
herramientas, haslo con servers o victimas que no sean potenciales, ya que de
modo contrario, invertirian el dinero, en coimas, comprando jueces, fabricando
leyes, etc. con el objetivo de meterte bajo rejas, asi que piensa bien lo que
haces y con quien lo haces... No quiero intimidar a nadie, claro que los
hackers usan spywares, pero usalos bien por ello que recuerden esta frase:
" El hombre arriesga su propia vida cada vez que elige y eso lo hace libre "
- Despedida
*********
Una vez mas me despido de vosotros, espero que les haya sido util este
articulo hare posteriores ediciones analizando Spywares, en esta primera parte
me concentre en que comprendais el funcionamiento y concepto de un spyware,
como usarlos, configurarlos, y poder sacar el maximo provecho de los mismos.
ya sabeis cualquier cosa, dudas, criticas, comentarios, etc. me los enviais al
mail:
<zaratustra@linuxmail.org>
como siempre salu2 a la gente del I.H.T y de L.U.T, bien ha sido todo por hoy,
nos vemos en la proxima, lean ksh, lean libros, hagan sexo y escuchen rock and
roll, ;)
BYE.
" There is only one way to kill capitalism by taxes, taxes, and more taxes."
-- Karl Marx
<zaratustra retorna a sus Montañas...>
by [NiEtZsChE-2k]
°°°°°°°°°°°°°°°°°
((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
))))))))))))))S)i)e)n)t)e))l)o))p)r)o)h)i)b)i)d)o)))))))))))))))))))
((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((
http://kshezine.org