I have attached my final program which works on both FreeBSD 2.x and
FreeBSD 3.x (I don't have a FreeBSD 4.x box to test this on yet).

On FreeBSD 2.x one must be root to run this (to read /dev/kmem), but
on FreeBSD 3.x any user can run this.

I would argue that this is a potential security vulnerability. Some
clever user may be able to exploit this for some protocols to determine
the lengths of usernames and passwords (admittedly this is unlikely to
work with telnet unless in line mode). The sysctl calls that extract
things like TCP control blocks should require privileged access
(although the downside of this is that programs like netstat would have
to be setuid).


-- 
Dr Graham Wheeler                        E-mail: [EMAIL PROTECTED]
Director, Research and Development       WWW:    http://www.cequrux.com
CEQURUX Technologies                     Phone:  +27(21)423-6065
Firewalls/VPN Specialists                Fax:    +27(21)424-3656
#include <stdio.h>
#include <fcntl.h>
#include <kvm.h>
#include <nlist.h>

#include <sys/types.h>
#include <sys/socket.h>
#if (__FreeBSD__ > 2)
#include <sys/socketvar.h>
#endif

#include <net/route.h>

#include <netinet/in.h>
#include <netinet/in_pcb.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#define TCPSTATES
#include <netinet/tcp_fsm.h>
#define TCPTIMERS
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>
#if (__FreeBSD__ > 2)
#include <sys/sysctl.h>
#include <netinet/in_pcb.h>
#endif

//----------------------------------------------------------------

void Display(struct inpcb *inpcb, struct tcpcb *tcpcb)
{
    if (tcpcb->t_state >= TCPS_ESTABLISHED && tcpcb->t_state < TCP_NSTATES)
    {
        printf("%17s:%-5d ", inet_ntoa(inpcb->inp_laddr.s_addr),
                        ntohs(inpcb->inp_lport));
        printf("%17s:%-5d ", inet_ntoa(inpcb->inp_faddr.s_addr), 
                        ntohs(inpcb->inp_fport));
        printf("[%10s] tx: %10lu rx: %10lu\n",
                        tcpstates[tcpcb->t_state],
                        (u_long)tcpcb->snd_nxt - (u_long)tcpcb->iss,
                        (u_long)tcpcb->rcv_nxt - (u_long)tcpcb->irs);
    }
}

#if (__FreeBSD__ <= 2)

struct nlist nml[] = {
#define N_TCB           0
        { "_tcb" },
        0
};

void Process_IP_CB(kvm_t *kmem, struct inpcb *inpcb)
{
    struct tcpcb tcpcb;
    if (kvm_read(kmem, (long)inpcb->inp_ppcb, (char*)&tcpcb, sizeof(tcpcb))>0)
        Display(inpcb, &tcpcb);
}

void Process_IP_CBs(kvm_t *kvm)
{
    struct inpcb in_pcb;
    long off = nml[N_TCB].n_value;
    if (kvm_read(kvm, off, (char *) &in_pcb, sizeof (struct inpcb))>0)
    {
        long prev = off;
        while (in_pcb.inp_list.le_next != (struct inpcb *)off)
        {
            long next = (long)in_pcb.inp_list.le_next;
            if (kvm_read(kvm, next, (char*)&in_pcb, sizeof(struct inpcb)) < 0 ||
                (long)in_pcb.inp_list.le_prev != prev) // lost sync
                    break;
            Process_IP_CB(kvm, &in_pcb);
            prev = next;
        }
    }
}
#endif

main(int argc, char **argv)
{
#if (__FreeBSD__ > 2)
    int len = 0;
    if (sysctlbyname("net.inet.tcp.pcblist", 0, &len, 0, 0)<0)
        perror("sysctlbyname");
    else
    {
        char *buf = (char*)malloc(len);
        if (buf == 0)
            perror("malloc");
        else if (sysctlbyname("net.inet.tcp.pcblist", buf, &len, 0, 0)<0)
            perror("sysctlbyname");
        else
        {
            struct xinpgen *xig, *oxig;
            oxig = xig = (struct xinpgen*)buf;
            for (xig = (struct xinpgen*)(((char*)xig)+xig->xig_len) ;
                 xig->xig_len > sizeof(struct xinpgen);
                 xig = (struct xinpgen*)(((char*)xig)+xig->xig_len))
            {
                struct tcpcb *tcpcb = & ((struct xtcpcb*)xig)->xt_tp;
                struct inpcb *inpcb = & ((struct xtcpcb*)xig)->xt_inp;

                if (inpcb->inp_gencnt <= oxig->xig_gen)
                    Display(inpcb, tcpcb);
            }
        }
        if (buf) free(buf);
    }
#else
    kvm_t *kvm = kvm_open(0,0,0,0,0);
    if (kvm)
    {
        if (kvm_nlist(kvm, nml) < 0)
            perror("kvm_nlist");
        else
        {
            Process_IP_CBs(kvm);
            kvm_close(kvm);
        }
    }
    else perror("kvm_open");
#endif
}


Reply via email to