1
0
mirror of https://github.com/nmap/nmap.git synced 2026-01-27 00:29:03 +00:00

Make gathered CPE codes available to NSE.

CPEs are available at host.os (for the ones from OS fingerprinting) and
port.version.cpe (for the version detection ones).

This patch also fix a memory leak that David noticed in
PortList::setServiceProbeResults().
This commit is contained in:
henri
2012-01-13 10:24:19 +00:00
parent b6b2b21e2f
commit 487c08ff63
6 changed files with 86 additions and 24 deletions

View File

@@ -1,5 +1,11 @@
# Nmap Changelog ($Id$); -*-text-*-
o [NSE] Made gathered CPE codes available to NSE. [Henri]
o [NSE] Fixed a memory leak in PortList::setServiceProbeResults() noticed and
reported by David. The leak was triggered by set_port_version calls from NSE.
[Henri]
o [NSE] Added http-generator.nse by Michael Kohl, which gets version
information for web applications that set the "generator" meta
element.

View File

@@ -1630,6 +1630,12 @@ LUALIB_API int luaopen_openssl(lua_State *L) {
<option>-O</option> option, then
<literal>host.os</literal> is <literal>nil</literal>.
</para>
<para>
Additionally the table can contain CPE codes for the detected
operating system. These codes, as described in
<ulink url="http://cpe.mitre.org">the official CPE specification
</ulink> all start with the <literal>cpe:/</literal> prefix.
</para>
</listitem>
</varlistentry>
@@ -1890,6 +1896,15 @@ LUALIB_API int luaopen_openssl(lua_State *L) {
<literal>nil</literal> if <literal>rpc_status</literal> is
anything other than <literal>good_prog</literal>.</entry>
</row>
<row>
<entry align="left"><literal>cpe</literal></entry>
<entry>List of CPE codes for the detected service. As described in the
<ulink url="http://cpe.mitre.org">official CPE specification</ulink> these strings
all start with the <literal>cpe:/</literal> prefix.</entry>
</row>
</tbody></tgroup></table>
</listitem>

View File

@@ -32,6 +32,8 @@ static const int NSE_PROTOCOL[] = {IPPROTO_TCP, IPPROTO_UDP, IPPROTO_SCTP};
void set_version (lua_State *L, const struct serviceDeductions *sd)
{
size_t i;
setsfield(L, -1, "name", sd->name);
setnfield(L, -1, "name_confidence", sd->name_confidence);
setsfield(L, -1, "product", sd->product);
@@ -61,6 +63,13 @@ void set_version (lua_State *L, const struct serviceDeductions *sd)
setnfield(L, -1, "rpc_lowver", sd->rpc_lowver);
setnfield(L, -1, "rpc_highver", sd->rpc_highver);
}
lua_newtable(L);
for (i = 0; i < sd->cpe.size(); i++) {
lua_pushstring(L, sd->cpe[i]);
lua_rawseti(L, -2, i+1);
}
lua_setfield(L, -2, "cpe");
}
/* set some port state information onto the
@@ -179,7 +188,8 @@ void set_hostinfo(lua_State *L, Target *currenths) {
FPR->overall_results == OSSCAN_SUCCESS && FPR->num_perfect_matches > 0 &&
FPR->num_perfect_matches <= 8 )
{
int i;
int i, classno;
const OS_Classification_Results *OSR = FPR->getOSClassification();
lua_newtable(L);
// this will run at least one time and at most 8 times, see if condition
@@ -187,6 +197,15 @@ void set_hostinfo(lua_State *L, Target *currenths) {
lua_pushstring(L, FPR->matches[i]->OS_name);
lua_rawseti(L, -2, i+1);
}
for (classno = 0; classno < OSR->OSC_num_matches; classno++) {
size_t j;
for (j = 0; j < OSR->OSC[classno]->cpe.size(); j++) {
lua_pushstring(L, OSR->OSC[classno]->cpe[j]);
lua_rawseti(L, -2, ++i);
}
}
lua_setfield(L, -2, "os");
}
}
@@ -508,6 +527,7 @@ static int l_set_port_version (lua_State *L)
Target *target;
Port *p;
Port port;
std::vector<const char *> cpe;
enum service_tunnel_type tunnel = SERVICE_TUNNEL_NONE;
enum serviceprobestate probestate =
opversion[luaL_checkoption(L, 3, "hardmatched", ops)];
@@ -537,14 +557,23 @@ static int l_set_port_version (lua_State *L)
else
luaL_argerror(L, 2, "invalid value for port.version.service_tunnel");
lua_getfield(L, 4, "cpe");
if (!lua_istable(L, -1))
luaL_error(L, "port.version 'cpe' field must be a table");
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
cpe.push_back(lua_tostring(L, -1));
}
if (o.servicescan)
target->ports.setServiceProbeResults(p->portno, p->proto,
probestate, name, tunnel, product,
version, extrainfo, hostname, ostype, devicetype, NULL, NULL, NULL, NULL);
version, extrainfo, hostname, ostype, devicetype,
(cpe.size() > 0) ? &cpe : NULL, NULL);
else
target->ports.setServiceProbeResults(p->portno, p->proto,
probestate, name, tunnel, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
NULL, NULL, NULL, NULL, NULL, NULL);
return 0;
}

View File

@@ -115,7 +115,7 @@ Port::Port() {
state_reason_init(&reason);
}
void Port::freeService() {
void Port::freeService(bool del_service) {
if (service != NULL) {
std::vector<char *>::iterator it;
@@ -137,7 +137,10 @@ void Port::freeService() {
free(service->service_fp);
for (it = service->cpe.begin(); it != service->cpe.end(); it++)
free(*it);
delete service;
service->cpe.clear();
if (del_service)
delete service;
}
}
@@ -336,8 +339,9 @@ void PortList::setServiceProbeResults(u16 portno, int protocol,
enum serviceprobestate sres, const char *sname,
enum service_tunnel_type tunnel, const char *product, const char *version,
const char *extrainfo, const char *hostname, const char *ostype,
const char *devicetype, const char *cpe_a, const char *cpe_h, const char *cpe_o,
const char *devicetype, const std::vector<const char *> *cpe,
const char *fingerprint) {
std::vector<char *>::iterator it;
Port *port;
char *p;
@@ -370,6 +374,8 @@ void PortList::setServiceProbeResults(u16 portno, int protocol,
// port->serviceprobe_results = sres;
port->service->service_tunnel = tunnel;
port->freeService(false);
if (sname)
port->service->name = strdup(sname);
else
@@ -387,15 +393,15 @@ void PortList::setServiceProbeResults(u16 portno, int protocol,
port->service->ostype = cstringSanityCheck(ostype, 32);
port->service->devicetype = cstringSanityCheck(devicetype, 32);
p = cstringSanityCheck(cpe_a, 80);
if (p != NULL)
port->service->cpe.push_back(p);
p = cstringSanityCheck(cpe_h, 80);
if (p != NULL)
port->service->cpe.push_back(p);
p = cstringSanityCheck(cpe_o, 80);
if (p != NULL)
port->service->cpe.push_back(p);
if (cpe) {
std::vector<const char *>::const_iterator cit;
for (cit = cpe->begin(); cit != cpe->end(); cit++) {
p = cstringSanityCheck(*cit, 80);
if (p != NULL)
port->service->cpe.push_back(p);
}
}
}
/* Sets the results of an RPC scan. if rpc_status is not
@@ -498,7 +504,7 @@ PortList::~PortList() {
if(port_list[proto]) {
for(i=0; i < port_list_count[proto]; i++) { // free every Port
if(port_list[proto][i]) {
port_list[proto][i]->freeService();
port_list[proto][i]->freeService(true);
delete port_list[proto][i];
}
}

View File

@@ -178,7 +178,7 @@ class Port {
public:
Port();
void freeService();
void freeService(bool del_service);
void getNmapServiceName(char *namebuf, int buflen, const char *rpcinfo) const;
u16 portno;
@@ -267,7 +267,7 @@ class PortList {
const char *version, const char *hostname,
const char *ostype, const char *devicetype,
const char *extrainfo,
const char *cpe_a, const char *cpe_h, const char *cpe_o,
const std::vector<const char *> *cpe,
const char *fingerprint);
// pass in an allocated struct serviceDeductions (don't worry about initializing, and

View File

@@ -2536,6 +2536,15 @@ list<ServiceNFO *>::iterator svc;
for(svc = SG->services_finished.begin(); svc != SG->services_finished.end(); svc++) {
if ((*svc)->probe_state != PROBESTATE_FINISHED_NOMATCH) {
vector<const char *> cpe;
if (*(*svc)->cpe_a_matched)
cpe.push_back((*svc)->cpe_a_matched);
if (*(*svc)->cpe_h_matched)
cpe.push_back((*svc)->cpe_h_matched);
if (*(*svc)->cpe_o_matched)
cpe.push_back((*svc)->cpe_o_matched);
(*svc)->target->ports.setServiceProbeResults((*svc)->portno, (*svc)->proto,
(*svc)->probe_state,
(*svc)->probe_matched,
@@ -2546,15 +2555,13 @@ list<ServiceNFO *>::iterator svc;
*(*svc)->hostname_matched? (*svc)->hostname_matched : NULL,
*(*svc)->ostype_matched? (*svc)->ostype_matched : NULL,
*(*svc)->devicetype_matched? (*svc)->devicetype_matched : NULL,
*(*svc)->cpe_a_matched? (*svc)->cpe_a_matched : NULL,
*(*svc)->cpe_h_matched? (*svc)->cpe_h_matched : NULL,
*(*svc)->cpe_o_matched? (*svc)->cpe_o_matched : NULL,
(cpe.size() > 0) ? &cpe : NULL,
shouldWePrintFingerprint(*svc) ? (*svc)->getServiceFingerprint(NULL) : NULL);
} else {
(*svc)->target->ports.setServiceProbeResults((*svc)->portno, (*svc)->proto,
(*svc)->probe_state, NULL,
(*svc)->tunnel, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL,
NULL,
(*svc)->getServiceFingerprint(NULL));
}
}
@@ -2600,8 +2607,7 @@ static void remove_excluded_ports(AllProbes *AP, ServiceGroup *SG) {
PROBESTATE_EXCLUDED, NULL,
SERVICE_TUNNEL_NONE,
"Excluded from version scan", NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL);
NULL, NULL, NULL, NULL, NULL, NULL);
SG->services_remaining.erase(i);
SG->services_finished.push_back(svc);