1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-26 17:39:03 +00:00

o Added initial SCTP port scanning support to Nmap. SCTP is

a layer 4 protocol used mostly for telephony related applications.
  This brings the following new features:
  o SCTP INIT chunk port scan (-sY): open ports return an INIT-ACK
    chunk, closed ones an ABORT chunk.  This is the SCTP equivalent
    of a TCP SYN stealth scan.
  o SCTP COOKIE-ECHO chunk port scan (-sZ): open ports are silent,
    closed ports return an ABORT chunk.
  o SCTP INIT chunk ping probes (-PY): host discovery using SCTP
    INIT chunk packets.
  o SCTP-specific IP protocol scan (-sO -p sctp).
  o SCTP-specific traceroute support (--traceroute).
  o The ability to use the deprecated Adler32 algorithm as specified
    in RFC 2960 instead of CRC32C from RFC 4960 (--adler32).
  o 42 well-known SCTP ports were added to the nmap-services file.
  Part of the work on SCTP support was kindly sponsored by
  Compass Security AG, Switzerland.  [Daniel Roethlisberger]
This commit is contained in:
daniel
2009-06-03 23:15:45 +00:00
parent 99c4008c03
commit 50830f7488
36 changed files with 1333 additions and 152 deletions

View File

@@ -170,6 +170,8 @@ static const char *pspectype2ascii(int type) {
return "TCP";
case PS_UDP:
return "UDP";
case PS_SCTP:
return "SCTP";
case PS_PROTO:
return "IP Proto";
case PS_ICMP:
@@ -200,11 +202,16 @@ struct IPExtraProbeData_udp {
u16 sport;
};
struct IPExtraProbeData_sctp {
u16 sport;
};
struct IPExtraProbeData {
u16 ipid; /* host byte order */
union {
struct IPExtraProbeData_tcp tcp;
struct IPExtraProbeData_udp udp;
struct IPExtraProbeData_sctp sctp;
} pd;
};
@@ -227,12 +234,36 @@ public:
/* Pass an arp packet, including ethernet header. Must be 42bytes */
void setARP(u8 *arppkt, u32 arplen);
// The 4 accessors below all return in HOST BYTE ORDER
// source port used if TCP or UDP
// source port used if TCP, UDP or SCTP
u16 sport() {
return (mypspec.proto == IPPROTO_TCP)? probes.IP.pd.tcp.sport : probes.IP.pd.udp.sport; }
// destination port used if TCP or UDP
u16 dport() {
return (mypspec.proto == IPPROTO_TCP)? mypspec.pd.tcp.dport : mypspec.pd.udp.dport; }
switch (mypspec.proto) {
case IPPROTO_TCP:
return probes.IP.pd.tcp.sport;
case IPPROTO_UDP:
return probes.IP.pd.udp.sport;
case IPPROTO_SCTP:
return probes.IP.pd.sctp.sport;
default:
return 0;
}
/* not reached */
}
// destination port used if TCP, UDP or SCTP
u16 dport() {
switch (mypspec.proto) {
case IPPROTO_TCP:
return mypspec.pd.tcp.dport;
case IPPROTO_UDP:
return mypspec.pd.udp.dport;
case IPPROTO_SCTP:
return mypspec.pd.sctp.dport;
default:
/* dport() can get called for other protos if we
* get ICMP responses during IP proto scans. */
return 0;
}
/* not reached */
}
u16 ipid() { return probes.IP.ipid; }
u32 tcpseq(); // TCP sequence number if protocol is TCP
/* Number, such as IPPROTO_TCP, IPPROTO_UDP, etc. */
@@ -395,6 +426,9 @@ public:
/* The index of the next UDP port in o.ping_udpprobes to probe during ping
scan. */
int next_udpportpingidx;
/* The index of the next SCTP port in o.ping_protoprobes to probe during ping
scan. */
int next_sctpportpingidx;
/* The index of the next IP protocol in o.ping_protoprobes to probe during ping
scan. */
int next_protoportpingidx;
@@ -574,6 +608,7 @@ public:
stype scantype;
bool tcp_scan; /* scantype is a type of TCP scan */
bool udp_scan;
bool sctp_scan; /* scantype is a type of SCTP scan */
bool prot_scan;
bool ping_scan; /* Includes trad. ping scan & arp scan */
bool ping_scan_arp; /* ONLY includes arp ping scan */
@@ -667,7 +702,7 @@ static void init_ultra_timing_vals(ultra_timing_vals *timing,
struct ultra_scan_performance_vars *perf,
struct timeval *now);
/* Take a buffer, buf, of size bufsz (32 bytes is sufficient) and
/* Take a buffer, buf, of size bufsz (64 bytes is sufficient) and
writes a short description of the probe (arg1) into buf. It also returns
buf. */
static char *probespec2ascii(const probespec *pspec, char *buf, unsigned int bufsz) {
@@ -694,6 +729,20 @@ static char *probespec2ascii(const probespec *pspec, char *buf, unsigned int buf
case PS_UDP:
Snprintf(buf, bufsz, "udp to port %hu", pspec->pd.udp.dport);
break;
case PS_SCTP:
switch (pspec->pd.sctp.chunktype) {
case SCTP_INIT:
Strncpy(flagbuf, "INIT", sizeof(flagbuf));
break;
case SCTP_COOKIE_ECHO:
Strncpy(flagbuf, "COOKIE-ECHO", sizeof(flagbuf));
break;
default:
Strncpy(flagbuf, "(unknown)", sizeof(flagbuf));
}
Snprintf(buf, bufsz, "sctp to port %hu; chunk: %s", pspec->pd.sctp.dport,
flagbuf);
break;
case PS_PROTO:
Snprintf(buf, bufsz, "protocol %u", (unsigned int) pspec->proto);
break;
@@ -755,6 +804,7 @@ void UltraProbe::setIP(u8 *ippacket, u32 iplen, const probespec *pspec) {
struct ip *ipv4 = (struct ip *) ippacket;
struct tcp_hdr *tcp = NULL;
struct udp_hdr *udp = NULL;
struct sctp_hdr *sctp = NULL;
type = UP_IP;
if (ipv4->ip_v != 4)
@@ -772,6 +822,10 @@ void UltraProbe::setIP(u8 *ippacket, u32 iplen, const probespec *pspec) {
assert(iplen >= (unsigned) ipv4->ip_hl * 4 + 8);
udp = (struct udp_hdr *) ((u8 *) ipv4 + ipv4->ip_hl * 4);
probes.IP.pd.udp.sport = ntohs(udp->uh_sport);
} else if (ipv4->ip_p == IPPROTO_SCTP) {
assert(iplen >= (unsigned) ipv4->ip_hl * 4 + 12);
sctp = (struct sctp_hdr *) ((u8 *) ipv4 + ipv4->ip_hl * 4);
probes.IP.pd.sctp.sport = ntohs(sctp->sh_sport);
}
mypspec = *pspec;
@@ -1022,9 +1076,11 @@ static bool pingprobe_is_appropriate(const UltraScanInfo *USI,
return USI->scantype == CONNECT_SCAN || (USI->ping_scan && USI->ptech.connecttcpscan);
case(PS_TCP):
case(PS_UDP):
case(PS_SCTP):
return (USI->tcp_scan && USI->scantype != CONNECT_SCAN) ||
USI->udp_scan ||
(USI->ping_scan && (USI->ptech.rawtcpscan || USI->ptech.rawudpscan));
USI->sctp_scan ||
(USI->ping_scan && (USI->ptech.rawtcpscan || USI->ptech.rawudpscan || USI->ptech.rawsctpscan));
case(PS_PROTO):
return USI->prot_scan || (USI->ping_scan && USI->ptech.rawprotoscan);
case(PS_ICMP):
@@ -1043,6 +1099,7 @@ static int scantype_no_response_means(stype scantype) {
case ACK_SCAN:
case WINDOW_SCAN:
case CONNECT_SCAN:
case SCTP_INIT_SCAN:
return PORT_FILTERED;
case UDP_SCAN:
case IPPROT_SCAN:
@@ -1050,6 +1107,7 @@ static int scantype_no_response_means(stype scantype) {
case FIN_SCAN:
case MAIMON_SCAN:
case XMAS_SCAN:
case SCTP_COOKIE_ECHO_SCAN:
return PORT_OPENFILTERED;
case PING_SCAN:
case PING_SCAN_ARP:
@@ -1068,6 +1126,7 @@ HostScanStats::HostScanStats(Target *t, UltraScanInfo *UltraSI) {
next_ackportpingidx = 0;
next_synportpingidx = 0;
next_udpportpingidx = 0;
next_sctpportpingidx = 0;
next_protoportpingidx = 0;
sent_icmp_ping = false;
sent_icmp_mask = false;
@@ -1342,8 +1401,9 @@ UltraScanInfo::~UltraScanInfo() {
Basically, any scan type except pure TCP connect scans are raw. */
bool UltraScanInfo::isRawScan() {
return scantype != CONNECT_SCAN
&& (tcp_scan || udp_scan || prot_scan || ping_scan_arp
|| (ping_scan && (ptech.rawicmpscan || ptech.rawtcpscan || ptech.rawudpscan || ptech.rawprotoscan)));
&& (tcp_scan || udp_scan || sctp_scan || prot_scan || ping_scan_arp
|| (ping_scan && (ptech.rawicmpscan || ptech.rawtcpscan || ptech.rawudpscan
|| ptech.rawsctpscan || ptech.rawprotoscan)));
}
/* A circular buffer of the incompleteHosts. nextIncompleteHost() gives
@@ -1439,8 +1499,8 @@ void UltraScanInfo::Init(vector<Target *> &Targets, struct scan_lists *pts, styp
scantype = scantp;
SPM = new ScanProgressMeter(scantype2str(scantype));
send_rate_meter.start(&now);
tcp_scan = udp_scan = prot_scan = ping_scan = noresp_open_scan = false;
ping_scan_arp = false;
tcp_scan = udp_scan = sctp_scan = prot_scan = false;
ping_scan = noresp_open_scan = ping_scan_arp = false;
memset((char *) &ptech, 0, sizeof(ptech));
switch(scantype) {
case FIN_SCAN:
@@ -1458,6 +1518,10 @@ void UltraScanInfo::Init(vector<Target *> &Targets, struct scan_lists *pts, styp
noresp_open_scan = true;
udp_scan = true;
break;
case SCTP_INIT_SCAN:
case SCTP_COOKIE_ECHO_SCAN:
sctp_scan = true;
break;
case IPPROT_SCAN:
noresp_open_scan = true;
prot_scan = true;
@@ -1469,6 +1533,8 @@ void UltraScanInfo::Init(vector<Target *> &Targets, struct scan_lists *pts, styp
ptech.rawicmpscan = 1;
if (o.pingtype & PINGTYPE_UDP)
ptech.rawudpscan = 1;
if (o.pingtype & PINGTYPE_SCTP_INIT)
ptech.rawsctpscan = 1;
if (o.pingtype & PINGTYPE_TCP) {
if (o.isr00t && o.af() == AF_INET)
ptech.rawtcpscan = 1;
@@ -1554,6 +1620,8 @@ unsigned int UltraScanInfo::numProbesPerHost()
numprobes = ports->tcp_count;
} else if (udp_scan) {
numprobes = ports->udp_count;
} else if (sctp_scan) {
numprobes = ports->sctp_count;
} else if (prot_scan) {
numprobes = ports->prot_count;
} else if (ping_scan_arp) {
@@ -1568,6 +1636,8 @@ unsigned int UltraScanInfo::numProbesPerHost()
}
if (ptech.rawudpscan)
numprobes += ports->udp_ping_count;
if (ptech.rawsctpscan)
numprobes += ports->sctp_ping_count;
if (ptech.rawicmpscan) {
if (o.pingtype & PINGTYPE_ICMP_PING)
numprobes++;
@@ -1755,7 +1825,7 @@ int UltraScanInfo::removeCompletedHosts() {
hss->target->targetipstr(), num_outstanding_probes,
num_outstanding_probes == 1 ? "probe" : "probes");
if (o.debugging > 3) {
char tmpbuf[32];
char tmpbuf[64];
std::list<UltraProbe *>::iterator iter;
for (iter = hss->probes_outstanding.begin(); iter != hss->probes_outstanding.end(); iter++)
log_write(LOG_PLAIN, "* %s\n", probespec2ascii((probespec *) (*iter)->pspec(), tmpbuf, sizeof(tmpbuf)));
@@ -1796,6 +1866,8 @@ int determineScanGroupSize(int hosts_scanned_so_far,
if (o.UDPScan())
groupsize = 128;
else if (o.SCTPScan())
groupsize = 128;
else if (o.TCPScan()) {
groupsize = MAX(1024 / (ports->tcp_count ? ports->tcp_count : 1), 64);
if (ports->tcp_count > 1000 && o.timing_level <= 4) {
@@ -1877,7 +1949,23 @@ static int get_next_target_probe(UltraScanInfo *USI, HostScanStats *hss,
pspec->type = PS_UDP;
pspec->proto = IPPROTO_UDP;
pspec->pd.udp.dport = USI->ports->udp_ports[hss->next_portidx++];
return 0;
} else if (USI->sctp_scan) {
if (hss->next_portidx >= USI->ports->sctp_count)
return -1;
pspec->type = PS_SCTP;
pspec->proto = IPPROTO_SCTP;
pspec->pd.sctp.dport = USI->ports->sctp_ports[hss->next_portidx++];
switch (USI->scantype) {
case SCTP_INIT_SCAN:
pspec->pd.sctp.chunktype = SCTP_INIT;
break;
case SCTP_COOKIE_ECHO_SCAN:
pspec->pd.sctp.chunktype = SCTP_COOKIE_ECHO;
break;
default:
assert(0);
}
return 0;
} else if (USI->prot_scan) {
if (hss->next_portidx >= USI->ports->prot_count)
@@ -1922,6 +2010,13 @@ static int get_next_target_probe(UltraScanInfo *USI, HostScanStats *hss,
return 0;
}
}
if (USI->ptech.rawsctpscan && hss->next_sctpportpingidx < USI->ports->sctp_ping_count) {
pspec->type = PS_SCTP;
pspec->proto = IPPROTO_SCTP;
pspec->pd.sctp.dport = USI->ports->sctp_ping_ports[hss->next_sctpportpingidx++];
pspec->pd.sctp.chunktype = SCTP_INIT;
return 0;
}
if (USI->ptech.rawicmpscan) {
pspec->type = PS_ICMP;
pspec->proto = IPPROTO_ICMP;
@@ -1971,6 +2066,10 @@ int HostScanStats::freshPortsLeft() {
if (next_portidx >= USI->ports->udp_count)
return 0;
return USI->ports->udp_count - next_portidx;
} else if (USI->sctp_scan) {
if (next_portidx >= USI->ports->sctp_count)
return 0;
return USI->ports->sctp_count - next_portidx;
} else if (USI->prot_scan) {
if (next_portidx >= USI->ports->prot_count)
return 0;
@@ -1990,6 +2089,8 @@ int HostScanStats::freshPortsLeft() {
}
if (USI->ptech.rawudpscan && next_udpportpingidx < USI->ports->udp_ping_count)
num_probes += USI->ports->udp_ping_count - next_udpportpingidx;
if (USI->ptech.rawsctpscan && next_sctpportpingidx < USI->ports->sctp_ping_count)
num_probes += USI->ports->sctp_ping_count - next_sctpportpingidx;
if (USI->ptech.rawicmpscan) {
if ((o.pingtype & PINGTYPE_ICMP_PING) && !sent_icmp_ping)
num_probes++;
@@ -2337,16 +2438,16 @@ void HostScanStats::getTiming(struct ultra_timing_vals *tmng) {
/* Define a score for a ping probe, for the purposes of deciding whether one
probe should be preferred to another. The order, from most preferred to least
preferred, is
Raw TCP (not filtered, not SYN to an open port)
Raw TCP/SCTP (not filtered, not SYN/INIT to an open port)
ICMP information queries (echo request, timestamp request, netmask req)
ARP
Raw TCP (SYN to an open port)
UDP, IP protocol, or other ICMP (including filtered TCP)
Raw TCP/SCTP (SYN/INIT to an open port)
UDP, IP protocol, or other ICMP (including filtered TCP/SCTP)
TCP connect
Anything else
Raw TCP SYN to an open port is given a low preference because of the risk of
SYN flooding (this is the only case where the port state is considered). The
probe passed to this function is assumed to have received a positive
Raw TCP SYN / SCTP INIT to an open port is given a low preference because of the
risk of SYN flooding (this is the only case where the port state is considered).
The probe passed to this function is assumed to have received a positive
response, that is, it should not have set a port state just by timing out. */
static unsigned int pingprobe_score(const probespec *pspec, int state) {
unsigned int score;
@@ -2360,6 +2461,14 @@ static unsigned int pingprobe_score(const probespec *pspec, int state) {
else
score = 6;
break;
case PS_SCTP:
if (state == PORT_FILTERED) /* Received an ICMP error. */
score = 2;
else if (state == PORT_OPEN || state == PORT_UNKNOWN)
score = 3;
else
score = 6;
break;
case PS_ICMP:
if(pspec->pd.icmp.type==ICMP_ECHO || pspec->pd.icmp.type==ICMP_MASK || pspec->pd.icmp.type==ICMP_TSTAMP)
score = 5;
@@ -2418,6 +2527,9 @@ static bool ultrascan_port_pspec_update(UltraScanInfo *USI,
} else if (pspec->type == PS_UDP) {
proto = IPPROTO_UDP;
portno = pspec->pd.udp.dport;
} else if (pspec->type == PS_SCTP) {
proto = IPPROTO_SCTP;
portno = pspec->pd.sctp.dport;
} else assert(0);
/* First figure out the current state */
@@ -2492,7 +2604,9 @@ double HostScanStats::cc_scale() {
/* Boost the scan delay for this host, usually because too many packet
drops were detected. */
void HostScanStats::boostScanDelay() {
unsigned int maxAllowed = (USI->tcp_scan)? o.maxTCPScanDelay() : o.maxUDPScanDelay();
unsigned int maxAllowed = USI->tcp_scan ? o.maxTCPScanDelay() :
USI->udp_scan ? o.maxUDPScanDelay() :
o.maxSCTPScanDelay();
if (sdn.delayms == 0)
sdn.delayms = (USI->udp_scan)? 50 : 5; // In many cases, a pcap wait takes a minimum of 80ms, so this matters little :(
else sdn.delayms = MIN(sdn.delayms * 2, MAX(sdn.delayms, 1000));
@@ -2640,7 +2754,7 @@ static void ultrascan_host_probe_update(UltraScanInfo *USI, HostScanStats *hss,
if (rcvdtime != NULL && adjust_ping
&& pingprobe_is_better(probe->pspec(), PORT_UNKNOWN, &hss->target->pingprobe, hss->target->pingprobe_state)) {
if (o.debugging > 1) {
char buf[32];
char buf[64];
probespec2ascii(probe->pspec(), buf, sizeof(buf));
log_write(LOG_PLAIN, "Changing ping technique for %s to %s\n", hss->target->targetipstr(), buf);
}
@@ -2727,7 +2841,7 @@ static void ultrascan_port_probe_update(UltraScanInfo *USI, HostScanStats *hss,
if (rcvdtime != NULL && adjust_ping
&& pingprobe_is_better(probe->pspec(), newstate, &hss->target->pingprobe, hss->target->pingprobe_state)) {
if (o.debugging > 1) {
char buf[32];
char buf[64];
probespec2ascii(probe->pspec(), buf, sizeof(buf));
log_write(LOG_PLAIN, "Changing ping technique for %s to %s\n", hss->target->targetipstr(), buf);
}
@@ -2922,6 +3036,9 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
struct eth_nfo *ethptr = NULL;
u8 *tcpops = NULL;
u16 tcpopslen = 0;
u32 vtag = 0;
char *chunk = NULL;
int chunklen = 0;
if (USI->ethsd) {
memcpy(eth.srcmac, hss->target->SrcMACAddress(), 6);
@@ -2984,6 +3101,45 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
send_ip_packet(USI->rawsd, ethptr, packet, packetlen);
free(packet);
}
} else if (pspec->type == PS_SCTP) {
switch (pspec->pd.sctp.chunktype) {
case SCTP_INIT:
chunklen = sizeof(struct sctp_chunkhdr_init);
chunk = (char*)safe_malloc(chunklen);
sctp_pack_chunkhdr_init(chunk, SCTP_INIT, 0, chunklen,
get_random_u32()/*itag*/,
32768, 10, 2048,
get_random_u32()/*itsn*/);
vtag = 0;
break;
case SCTP_COOKIE_ECHO:
chunklen = sizeof(struct sctp_chunkhdr_cookie_echo) + 4;
chunk = (char*)safe_malloc(chunklen);
*((u32*)((char*)chunk + sizeof(struct sctp_chunkhdr_cookie_echo))) =
get_random_u32();
sctp_pack_chunkhdr_cookie_echo(chunk, SCTP_COOKIE_ECHO, 0, chunklen);
vtag = get_random_u32();
break;
default:
assert(0);
}
for(decoy = 0; decoy < o.numdecoys; decoy++) {
packet = build_sctp_raw(&o.decoys[decoy], hss->target->v4hostip(),
o.ttl, ipid, IP_TOS_DEFAULT, false,
o.ipoptions, o.ipoptionslen,
sport, pspec->pd.sctp.dport,
vtag, chunk, chunklen,
o.extra_payload, o.extra_payload_length,
&packetlen);
if (decoy == o.decoyturn) {
probe->setIP(packet, packetlen, pspec);
probe->sent = USI->now;
}
hss->probeSent(packetlen);
send_ip_packet(USI->rawsd, ethptr, packet, packetlen);
free(packet);
}
free(chunk);
} else if (pspec->type == PS_PROTO) {
for(decoy = 0; decoy < o.numdecoys; decoy++) {
switch(pspec->proto) {
@@ -3022,6 +3178,24 @@ static UltraProbe *sendIPScanProbe(UltraScanInfo *USI, HostScanStats *hss,
o.extra_payload, o.extra_payload_length,
&packetlen);
break;
case IPPROTO_SCTP:
{
struct sctp_chunkhdr_init chunk;
sctp_pack_chunkhdr_init(&chunk, SCTP_INIT, 0,
sizeof(struct sctp_chunkhdr_init),
get_random_u32()/*itag*/,
32768, 10, 2048,
get_random_u32()/*itsn*/);
packet = build_sctp_raw(&o.decoys[decoy], hss->target->v4hostip(),
o.ttl, ipid, IP_TOS_DEFAULT, false,
o.ipoptions, o.ipoptionslen,
sport, o.magic_port,
0UL, (char*)&chunk,
sizeof(struct sctp_chunkhdr_init),
o.extra_payload, o.extra_payload_length,
&packetlen);
}
break;
default:
packet = build_ip_raw(&o.decoys[decoy], hss->target->v4hostip(),
@@ -3087,7 +3261,8 @@ static void sendNextScanProbe(UltraScanInfo *USI, HostScanStats *hss) {
else if (pspec.type == PS_CONNECTTCP)
sendConnectScanProbe(USI, hss, pspec.pd.tcp.dport, 0, 0);
else if (pspec.type == PS_TCP || pspec.type == PS_UDP
|| pspec.type == PS_PROTO || pspec.type == PS_ICMP)
|| pspec.type == PS_SCTP || pspec.type == PS_PROTO
|| pspec.type == PS_ICMP)
sendIPScanProbe(USI, hss, &pspec, 0, 0);
else
assert(0);
@@ -3164,7 +3339,7 @@ static void doAnyRetryStackRetransmits(UltraScanInfo *USI) {
available */
static void sendPingProbe(UltraScanInfo *USI, HostScanStats *hss) {
if (o.debugging > 1) {
char tmpbuf[32];
char tmpbuf[64];
log_write(LOG_PLAIN, "Ultrascan PING SENT to %s [%s]\n", hss->target->targetipstr(),
probespec2ascii(&hss->target->pingprobe, tmpbuf, sizeof(tmpbuf)));
}
@@ -3172,7 +3347,8 @@ static void sendPingProbe(UltraScanInfo *USI, HostScanStats *hss) {
sendConnectScanProbe(USI, hss, hss->target->pingprobe.pd.tcp.dport, 0,
hss->nextPingSeq(true));
} else if (hss->target->pingprobe.type == PS_TCP || hss->target->pingprobe.type == PS_UDP
|| hss->target->pingprobe.type == PS_PROTO || hss->target->pingprobe.type == PS_ICMP) {
|| hss->target->pingprobe.type == PS_SCTP || hss->target->pingprobe.type == PS_PROTO
|| hss->target->pingprobe.type == PS_ICMP) {
sendIPScanProbe(USI, hss, &hss->target->pingprobe, 0, hss->nextPingSeq(true));
} else if (hss->target->pingprobe.type == PS_ARP) {
sendArpScanProbe(USI, hss, 0, hss->nextPingSeq(true));
@@ -3191,7 +3367,7 @@ static void sendGlobalPingProbe(UltraScanInfo *USI) {
assert(hss != NULL);
if (o.debugging > 1) {
char tmpbuf[32];
char tmpbuf[64];
log_write(LOG_PLAIN, "Ultrascan GLOBAL PING SENT to %s [%s]\n", hss->target->targetipstr(),
probespec2ascii(&hss->target->pingprobe, tmpbuf, sizeof(tmpbuf)));
}
@@ -3248,6 +3424,9 @@ static void retransmitProbe(UltraScanInfo *USI, HostScanStats *hss,
} else if (probe->protocol() == IPPROTO_UDP) {
newProbe = sendIPScanProbe(USI, hss, probe->pspec(), probe->tryno + 1,
0);
} else if (probe->protocol() == IPPROTO_SCTP) {
newProbe = sendIPScanProbe(USI, hss, probe->pspec(), probe->tryno + 1,
0);
} else if (probe->protocol() == IPPROTO_ICMP) {
newProbe = sendIPScanProbe(USI, hss, probe->pspec(), probe->tryno + 1,
0);
@@ -3910,6 +4089,73 @@ static bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
}
}
goodone = true;
}
} else if (ip->ip_p == IPPROTO_SCTP && !USI->prot_scan) {
struct sctp_hdr *sctp = (struct sctp_hdr *) ((u8 *) ip + ip->ip_hl * 4);
struct sctp_chunkhdr *chunk = (struct sctp_chunkhdr *) ((u8 *) sctp + 12);
/* Now ensure this host is even in the incomplete list */
memset(&sin, 0, sizeof(sin));
sin.sin_addr.s_addr = ip->ip_src.s_addr;
sin.sin_family = AF_INET;
hss = USI->findHost((struct sockaddr_storage *) &sin);
if (!hss) continue; // Not from a host that interests us
setTargetMACIfAvailable(hss->target, &linkhdr, ip, 0);
probeI = hss->probes_outstanding.end();
listsz = hss->num_probes_outstanding();
goodone = false;
/* Find the probe that provoked this response. */
for (probenum = 0; probenum < listsz && !goodone; probenum++) {
probeI--;
probe = *probeI;
if (o.af() != AF_INET || probe->protocol() != IPPROTO_SCTP)
continue;
/* Ensure the connection info matches. */
if (probe->dport() != ntohs(sctp->sh_sport)
|| probe->sport() != ntohs(sctp->sh_dport)
|| hss->target->v4sourceip()->s_addr != ip->ip_dst.s_addr)
continue;
/* Sometimes we get false results when scanning localhost with
-p- because we scan localhost with src port = dst port and
see our outgoing packet and think it is a response. */
if (probe->dport() == probe->sport() &&
ip->ip_src.s_addr == ip->ip_dst.s_addr &&
probe->ipid() == ntohs(ip->ip_id))
continue; /* We saw the packet we ourselves sent */
if (!probe->isPing()) {
/* Now that response has been matched to a probe, I interpret it */
if (USI->scantype == SCTP_INIT_SCAN) {
if (chunk->sch_type == SCTP_INIT_ACK) {
newstate = PORT_OPEN;
current_reason = ER_INITACK;
} else if (chunk->sch_type == SCTP_ABORT) {
newstate = PORT_CLOSED;
current_reason = ER_ABORT;
} else {
if (o.debugging)
error("Received response with unexpected SCTP chunks: %02x",
chunk->sch_type);
break;
}
} else if (USI->scantype == SCTP_COOKIE_ECHO_SCAN) {
if (chunk->sch_type == SCTP_ABORT) {
newstate = PORT_CLOSED;
current_reason = ER_ABORT;
} else {
if (o.debugging)
error("Received response with unexpected SCTP chunks: %02x",
chunk->sch_type);
break;
}
}
}
goodone = true;
}
} else if (ip->ip_p == IPPROTO_ICMP) {
@@ -3922,8 +4168,10 @@ static bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
requiredbytes = /* IPlen*/ 4 * ip->ip_hl +
/* ICMPLen */ 8 +
/* IP2 Len */ 4 * ip2->ip_hl;
if (USI->tcp_scan || USI->udp_scan)
requiredbytes += 8; /* UDP hdr, or TCP hdr up to seq # */
if (USI->tcp_scan || USI->udp_scan || USI->sctp_scan) {
/* UDP hdr, or TCP hdr up to seq #, or SCTP hdr up to vtag */
requiredbytes += 8;
}
/* prot scan has no headers coming back, so we don't reserve the
8 xtra bytes */
if (bytes < requiredbytes) {
@@ -3939,6 +4187,9 @@ static bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
if (USI->udp_scan && ip2->ip_p != IPPROTO_UDP)
continue;
if (USI->sctp_scan && ip2->ip_p != IPPROTO_SCTP)
continue;
/* ensure this packet relates to a packet to the host
we are scanning ... */
memset(&sin, 0, sizeof(sin));
@@ -3969,9 +4220,14 @@ static bool get_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
ntohs(tcp->th_dport) != probe->dport() ||
ntohl(tcp->th_seq) != probe->tcpseq())
continue;
} else if (ip2->ip_p == IPPROTO_SCTP && !USI->prot_scan) {
struct sctp_hdr *sctp = (struct sctp_hdr *) ((u8 *) ip2 + ip2->ip_hl * 4);
if (ntohs(sctp->sh_sport) != probe->sport() ||
ntohs(sctp->sh_dport) != probe->dport())
continue;
} else if (ip2->ip_p == IPPROTO_UDP && !USI->prot_scan) {
/* TODO: IPID verification */
struct udp_hdr *udp = (struct udp_hdr *) ((u8 *) ip2 + ip->ip_hl * 4);
struct udp_hdr *udp = (struct udp_hdr *) ((u8 *) ip2 + ip2->ip_hl * 4);
if (ntohs(udp->uh_sport) != probe->sport() ||
ntohs(udp->uh_dport) != probe->dport())
continue;
@@ -4382,9 +4638,55 @@ static int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
/* Did we fail to find a probe? */
if (probenum >= listsz)
continue;
} else if (ip2->ip_p == IPPROTO_SCTP && USI->ptech.rawsctpscan) {
/* The response was based our SCTP probe */
if ((unsigned) ip2->ip_hl * 4 + 8 > bytes)
continue;
struct sctp_hdr *sctp = (struct sctp_hdr *) ((u8 *) ip2 + ip2->ip_hl * 4);
/* Search for this host on the incomplete list */
memset(&sin, 0, sizeof(sin));
sin.sin_addr.s_addr = ip2->ip_dst.s_addr;
sin.sin_family = AF_INET;
hss = USI->findHost((struct sockaddr_storage *) &sin);
if (!hss) continue; // Not referring to a host that interests us
setTargetMACIfAvailable(hss->target, &linkhdr, ip, 0);
probeI = hss->probes_outstanding.end();
listsz = hss->num_probes_outstanding();
for(probenum = 0; probenum < listsz; probenum++) {
probeI--;
probe = *probeI;
if (o.af() != AF_INET || probe->protocol() != IPPROTO_SCTP)
continue;
if (!allow_ipid_match(probe->ipid(), ntohs(ip2->ip_id)))
continue;
/* Ensure the connection info matches. */
if (probe->dport() != ntohs(sctp->sh_dport) ||
probe->sport() != ntohs(sctp->sh_sport) ||
hss->target->v4sourceip()->s_addr != ip->ip_dst.s_addr)
continue;
/* Sometimes we get false results when scanning localhost with
-p- because we scan localhost with src port = dst port and
see our outgoing packet and think it is a response. */
if (probe->dport() == probe->sport() &&
ip->ip_src.s_addr == ip->ip_dst.s_addr &&
probe->ipid() == ntohs(ip->ip_id))
continue; /* We saw the packet we ourselves sent */
/* If we made it this far, we found it. We don't yet know if it's
going to change a host state (goodone) or not. */
break;
}
/* Did we fail to find a probe? */
if (probenum >= listsz)
continue;
} else if (!USI->ptech.rawprotoscan) {
if (o.debugging)
error("Got ICMP response to a packet which was not TCP, UDP, or ICMP");
error("Got ICMP response to a packet which was not TCP, UDP, SCTP or ICMP");
continue;
}
@@ -4575,6 +4877,52 @@ static int get_ping_pcap_result(UltraScanInfo *USI, struct timeval *stime) {
if (o.debugging)
log_write(LOG_STDOUT, "In response to UDP-ping, we got UDP packet back from %s port %hu (trynum = %d)\n", inet_ntoa(ip->ip_src), htons(udp->uh_sport), trynum);
}
} else if (ip->ip_p == IPPROTO_SCTP && USI->ptech.rawsctpscan) {
struct sctp_hdr *sctp = (struct sctp_hdr *) (((char *) ip) + 4 * ip->ip_hl);
struct sctp_chunkhdr *chunk = (struct sctp_chunkhdr *) ((u8 *) sctp + 12);
/* Search for this host on the incomplete list */
memset(&sin, 0, sizeof(sin));
sin.sin_addr.s_addr = ip->ip_src.s_addr;
sin.sin_family = AF_INET;
hss = USI->findHost((struct sockaddr_storage *) &sin);
if (!hss) continue; // Not from a host that interests us
probeI = hss->probes_outstanding.end();
listsz = hss->num_probes_outstanding();
goodone = false;
for(probenum = 0; probenum < listsz && !goodone; probenum++) {
probeI--;
probe = *probeI;
if (o.af() != AF_INET || probe->protocol() != IPPROTO_SCTP)
continue;
/* Ensure the connection info matches. */
if (probe->dport() != ntohs(sctp->sh_sport) ||
probe->sport() != ntohs(sctp->sh_dport) ||
hss->target->v4sourceip()->s_addr != ip->ip_dst.s_addr)
continue;
/* Sometimes we get false results when scanning localhost with
-p- because we scan localhost with src port = dst port and
see our outgoing packet and think it is a response. */
if (probe->dport() == probe->sport() &&
ip->ip_src.s_addr == ip->ip_dst.s_addr &&
probe->ipid() == ntohs(ip->ip_id))
continue; /* We saw the packet we ourselves sent */
goodone = true;
newstate = HOST_UP;
if (chunk->sch_type == SCTP_INIT_ACK) {
current_reason = ER_INITACK;
} else if (chunk->sch_type == SCTP_ABORT) {
current_reason = ER_ABORT;
} else {
current_reason = ER_UNKNOWN;
if (o.debugging)
log_write(LOG_STDOUT, "Received scan response with unexpected SCTP chunks: n/a");
}
}
} else if (!USI->ptech.rawprotoscan) {
if (o.debugging > 2)
error("Received packet with protocol %d; ignoring.", ip->ip_p);
@@ -4701,18 +5049,18 @@ static void begin_sniffer(UltraScanInfo *USI, vector<Target *> &Targets) {
pcap_filter="dst host ";
pcap_filter+=inet_ntoa(Targets[0]->v4source());
}
} else if(USI->tcp_scan || USI->udp_scan || USI->ping_scan) {
/* Handle udp and tcp with one filter. */
} else if(USI->tcp_scan || USI->udp_scan || USI->sctp_scan || USI->ping_scan) {
/* Handle udp, tcp and sctp with one filter. */
if (doIndividual){
pcap_filter="dst host ";
pcap_filter+=inet_ntoa(Targets[0]->v4source());
pcap_filter+=" and (icmp or ((tcp or udp) and (";
pcap_filter+=" and (icmp or ((tcp or udp or sctp) and (";
pcap_filter+=dst_hosts;
pcap_filter+=")))";
}else{
pcap_filter="dst host ";
pcap_filter+=inet_ntoa(Targets[0]->v4source());
pcap_filter+=" and (icmp or tcp or udp)";
pcap_filter+=" and (icmp or tcp or udp or sctp)";
}
}else assert(0);
if (o.debugging > 2) log_write(LOG_PLAIN, "Pcap filter: %s\n", pcap_filter.c_str());
@@ -5243,11 +5591,13 @@ void pos_scan(Target *target, u16 *portarray, int numports, stype scantype) {
/* Make sure we have ports left to scan */
while(1) {
if (doingOpenFiltered) {
rsi.rpc_current_port = target->ports.nextPort(rsi.rpc_current_port, TCPANDUDP,
rsi.rpc_current_port = target->ports.nextPort(rsi.rpc_current_port,
TCPANDUDPANDSCTP,
PORT_OPENFILTERED);
} else {
rsi.rpc_current_port = target->ports.nextPort(rsi.rpc_current_port,
TCPANDUDP, PORT_OPEN);
TCPANDUDPANDSCTP,
PORT_OPEN);
if (!rsi.rpc_current_port && !o.servicescan) {
doingOpenFiltered = true;
continue;