masscan-mark-ii/src/in-report.c

398 lines
11 KiB
C

#include "in-report.h"
#include "masscan-app.h"
#include "crypto-base64.h"
#include "proto-x509.h"
#include "proto-banout.h"
#include "smack.h"
#include "util-malloc.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
struct CNDB_Entry {
unsigned ip;
char *name;
struct CNDB_Entry *next;
};
struct CNDB_Database {
struct CNDB_Entry *entries[65536];
};
/***************************************************************************
***************************************************************************/
static struct CNDB_Database *db = NULL;
/***************************************************************************
***************************************************************************/
static const char *
cndb_lookup(unsigned ip)
{
const struct CNDB_Entry *entry;
if (db == NULL)
return 0;
entry = db->entries[ip&0xFFFF];
while (entry && entry->ip != ip)
entry = entry->next;
if (entry)
return entry->name;
else {
return 0;
}
}
/***************************************************************************
***************************************************************************/
static void
cndb_add(unsigned ip, const unsigned char *name, size_t name_length)
{
struct CNDB_Entry *entry;
if (name_length == 0)
return;
if (db == NULL) {
db = CALLOC(1, sizeof(*db));
}
entry = MALLOC(sizeof(*entry));
entry->ip =ip;
entry->name = MALLOC(name_length+1);
memcpy(entry->name, name, name_length+1);
entry->name[name_length] = '\0';
entry->next = db->entries[ip&0xFFFF];
db->entries[ip&0xFFFF] = entry;
}
/***************************************************************************
***************************************************************************/
#if 0
static void
cndb_add_cn(unsigned ip, const unsigned char *data, size_t length)
{
size_t offset = 0;
size_t name_offset;
size_t name_length;
if (length < 7)
return;
/*cipher:0x39 , safe-we1.dyndns.org*/
if (memcmp(data+offset, "cipher:", 7) != 0)
return;
offset += 7;
/* skip to name */
while (offset < length && data[offset] != ',')
offset++;
if (offset >= length)
return;
else
offset++; /* skip ',' */
while (offset < length && data[offset] == ' ')
offset++;
if (offset >= length)
return;
/* we should have a good name */
name_offset = offset;
while (offset < length && data[offset] != ',')
offset++;
name_length = offset - name_offset;
/* now insert into database */
cndb_add(ip, data+name_offset, name_length);
}
#endif
/***************************************************************************
***************************************************************************/
#if 0
static unsigned
found(const char *str, size_t str_len, const unsigned char *p, size_t length)
{
size_t i;
if (str_len > length)
return 0;
for (i=0; i<length; i++) {
if (str[0] == p[i] && memcmp(str, p+i, str_len) == 0)
return 1;
}
return 0;
}
#endif
enum {
XUnknown,
XNas,
XWiFi,
XFW,
X509,
XCom,
XVM,
XCam,
XVPN,
XPBX,
Xprint,
Xdefault,
XMail,
Xadmin,
Xav,
Xpot,
Xbox,
Xend
};
unsigned counts[32];
static void
print_counts()
{
unsigned i;
const char *count_names[] = {
"Unknown", "NAS", "WiFi", "FW", "X509",
"Conf", "VM", "Cam", "VPN", "PBX", "Printer",
"default", "mail", "admin", "AV", "honeypot", "box",
0, "", "", ""};
printf("----counts----\n");
for (i=0; i<Xend; i++) {
printf("%10u %s\n", counts[i], count_names[i]);
}
printf("---------------\n");
assert(count_names[i] == NULL);
}
struct Names {
unsigned code;
unsigned length;
const char *name;
} mynames[] = {
/* raspberry pi */
/* issuer[Debian */
{XNas, 9, "nasend~~]"},
{XPBX, 13, "issuer[iPECS]"},
{Xav, 13, "issuer[McAfee"},
{Xadmin,14, "issuer[webmin]"},
{Xadmin,14, "issuer[Webmin "},
{Xprint,15, "subject[HP-IPG]"},
{XNas, 16, "issuer[LaCie SA]"},
{XWiFi, 16, "subject[OpenWrt]"},
{Xadmin,16, "issuer[Puppet CA"},
{Xav, 16, "issuer[Kaspersky"},
{XFW, 17, "subject[Fortinet]"},
{XFW, 17, "issuer[ICC-FW CA]"},
{XCam, 17, "issuer[HIKVISION]"},
{Xprint,17, "subject[SHARP MX-"},
{X509, 18, "issuer[GANDI SAS]"},
{XFW, 18, "subject[FortiGate]"},
{XFW, 18, "issuer[watchguard]"},
{XVM, 18, "issuer[VMware Inc]"},
{Xbox, 19, "issuer[eBox Server]"},
{XFW, 19, "subject[WatchGuard]"},
{X509, 19, "issuer[RapidSSL CA]"},
{X509, 19, "issuer[AddTrust AB]"},
{XCom, 19, "issuer[Cisco SSCA2]"},
{XCom, 19, "subject[Cisco SSCA2]"},
{Xdefault,19,"issuer[v] issuer[v]"},
{X509, 20, "issuer[Register.com]"},
{X509, 20, "issuer[Thawte, Inc.]"},
{X509, 20, "issuer[thawte, Inc.]"},
{XMail, 20, "issuer[EQ-MT-RAPTOR]"},
{X509, 20, "issuer[DigiCert Inc]"},
{X509, 21, "issuer[TERENA SSL CA]"},
{XFW, 21, "issuer[WatchGuard CA]"},
{XVPN, 21, "issuer[OpenVPN Web CA"},
{X509, 21, "issuer[GeoTrust Inc.]"},
{XNas, 21, "issuer[TS Series NAS]"},
{XCom, 21, "subject[Polycom Inc.]"},
{XFW, 21, "issuer[Fortinet Ltd.]"},
{XNas, 21, "issuer[Synology Inc.]"},
{Xdefault,21,"issuer[XX] issuer[XX]"},
{XWiFi, 21, "2Wire]Gateway Device]"},
{X509, 21, "subject[DigiCert Inc]"},
{XCam, 22, "issuer[SamsungTechwin]"},
{X509, 22, "issuer[TAIWAN-CA INC.]"},
{X509, 22, "issuer[GeoTrust, Inc.]"},
{X509, 22, "issuer[ValiCert, Inc.]"},
{0, 22, "issuer[Apache Friends]"},
{X509, 22, "issuer[VeriSign, Inc.]"},
{X509, 22, "issuer[Cybertrust Inc]"},
{XCam, 23, "subject[HiTRON SYSTEMS]"},
{XFW, 23, "issuer[SonicWALL, Inc.]"},
{XFW, 23, "issuer[Future Systems.]"},
{XCom, 23, "issuer[Polycom Root CA]"},
{X509, 24, "issuer[AlphaSSL CA - G2]"},
{X509, 24, "issuer[GlobalSign nv-sa]"},
{XVPN, 24, "SonicWALL, Inc.]SSL-VPN]"},
{X509, 25, "issuer[Comodo CA Limited]"},
{X509, 25, "issuer[COMODO CA Limited]"},
{X509, 25, "issuer[GoDaddy.com, Inc.]"},
{Xbox, 26, "subject[Barracuda Networks]"},
{X509, 26, "issuer[Equifax Secure Inc.]"},
{X509, 28, "issuer[Gandi Standard SSL CA]"},
{X509, 28, "issuer[The USERTRUST Network]"},
{XCom, 28, "subject[Polycom] subject[VSG]"},
{X509, 28, "issuer[EuropeanSSL Server CA]"},
{0, 28, "issuer[SuSE Linux Web Server]"},
{XWiFi, 29, "issuer[CradlePoint Technology]"},
{XVPN, 29, "SonicWALL]Secure Remote Access]"},
{Xdefault,29,"subject[SomeOrganizationalUnit]"},
{Xdefault,29,"issuer[Internet Widgits Pty Ltd]"},
{X509, 30, "issuer[Network Solutions L.L.C.]"},
{X509, 30, "issuer[The Go Daddy Group, Inc.]"},
{Xpot, 30, "issuer[Nepenthes Development Team]"},
{X509, 30, "issuer[WoSign Class 1 DV Server CA]"},
{XCom, 30, "issuer[Polycom Equipment Policy CA]"},
{X509, 30, "issuer[Starfield Technologies, Inc.]"},
{X509, 30, "issuer[Certum Certification Authority]"},
{XNas, 30, "subject[Fujitsu CELVIN(R) NAS Server]"},
{XVPN, 35, "SonicWALL, Inc.]Secure Remote Access]"},
{X509, 40, "issuer[Secure Digital Certificate Signing]"},
{X509, 40, "issuer[Equifax Secure Certificate Authority]"},
{XVM, 40, "subject[VMware ESX Server Default Certificate]"},
{XCam, 40, "issuer[Cisco Systems] issuer[Cisco Manufacturing CA]"},
{0,0, 0}
};
static struct SMACK *global_xnames;
static void
xname_init(void)
{
unsigned i;
global_xnames = smack_create("readscan-x509-names", 0);
for (i=0; mynames[i].name; i++) {
const char *pattern = mynames[i].name;
unsigned len = mynames[i].length;
unsigned id = mynames[i].code;
smack_add_pattern( global_xnames,
pattern,
len,
id,
0
);
}
smack_compile(global_xnames);
}
/***************************************************************************
***************************************************************************/
static unsigned
found_type(const unsigned char *banner, size_t banner_length)
{
size_t id;
unsigned state = 0;
unsigned offset = 0;
/*for (i=0; mynames[i].name; i++) {
if (found(mynames[i].name, mynames[i].length, banner, banner_length))
return 1;
}*/
id = smack_search_next( global_xnames,
&state,
banner,
&offset,
(unsigned)banner_length);
if (id == SMACK_NOT_FOUND)
return 0;
counts[id]++;
return 1;
}
void
readscan_report( unsigned ip,
unsigned app_proto,
unsigned char **r_data,
size_t *r_data_length)
{
size_t data_length = *r_data_length;
unsigned char *data = *r_data;
if (app_proto == PROTO_X509_CERT) {
unsigned char *der = MALLOC(data_length);
struct CertDecode x;
size_t der_length;
struct BannerOutput banout[1];
const unsigned char *banner;
size_t banner_length;
banout_init(banout);
der_length = base64_decode(der, data_length, data, data_length);
x509_decode_init(&x, data_length);
x.is_capture_issuer = 1;
x.is_capture_subject = 1;
x509_decode(&x, der, der_length, banout);
banner = banout_string(banout, PROTO_SSL3);
banner_length = banout_string_length(banout, PROTO_SSL3);
if (banner_length) {
if (!found_type(banner, banner_length))
cndb_add(ip, banner, banner_length);
}
banout_release(banout);
/*} else if (0 && app_proto == PROTO_SSL3) {
cndb_add(ip, data, data_length);*/
} else if (app_proto == PROTO_VULN) {
const char *name = cndb_lookup(ip);
if (data_length == 15 && memcmp(data, "SSL[heartbeat] ", 15) == 0)
return;
if (name && strlen(name) < 300) {
//printf("vuln=%s\n", name);
((char*)data)[data_length] = ' ';
memcpy((char*)data+data_length+1, name, strlen(name)+1);
data_length += strlen(name)+1;
}
/* kludge */
if (data_length == 31 && memcmp(data, "SSL[heartbeat] SSL[HEARTBLEED] ", 31) == 0)
return;
}
}
void
readscan_report_init(void)
{
if (global_xnames == NULL)
xname_init();
}
void
readscan_report_print(void)
{
print_counts();
}