Mailing List Archive

Proposed schema for the backend database for Nessus
More food for thought (or for discussion, whatever you prefer)

I have designed a schema (E/R diagram) based on the discussion on the
list and my original ideas. I would like to know if this one holds all
the information a user might pretty much need. Does it? If it does I
can turn into SQL and start coding around^Winside Nessus to test it a bit.

Some things I want to mark:

- the ExecutedPlugins table is there in order to note down all plugins
that have been executed in a given session ID regardless of wether or
not a vulnerability has been discovered

- I have included a KnowledgeBase table which is pretty much free-text.
The information in the Knowledgebase is probably redundant with the
(organised) information in the rest of the schema. I still haven't got
around to analyse the KB code, though, and I want to take a proper look
at it.

- I'm not sure if user information (and location, i.e. IP address from
the nessus-client) should separated from the session information. The
Session table should probably be merged with the UserSessions table.

- The DetectedService is a separate table intented for port-scanner
plugins. Notice that an open port (of whatever protocol) is not in
itself a vulnerability. This information, however, is useful for
analysis (i.e. to answer questions like: which servers have port 389
(ldap) open in my network?)

- Translations are not considered (yet) because translators of plugins
would just need to drop-in replacements of the Nessus-plugin table
changing the description/solution information. Reports generated then
would include the translated descriptions.

You will see there is no such thing as a "report" in this schema. Other
proposals (from front-ends) include directly the report information into
the database. I'm not doing this since it is already redundant. If you
check carefully, a report on a given session is just all the
vulnerabilities that have been detected in a given session. I.e.

SELECT Nessus-plugin.Description, Vulnerability.Type,
Vulnerability.AdditionalInformation from Vulnerability, ExecutedPlugins,
NessusPlugin where Vulnerability.ExecutionID =
ExecutedPlugins.ExecutionID AND
ExecutedPlugins.PluginID=NessusPlugin.PluginID AND
ExecutedPlugins.SessionID="A GIVEN SESSION"

Does this make sense at all? :-)

Comments on the schema appreciated.

Regards

Javi
Re: Proposed schema for the backend database for Nessus [ In reply to ]
fbr wrote:

>Javier,
>
>Couldn't the Plugin-CVE and Plugin-BID be merged into just an Plugin reference
>table? This would allow you to link in information from other sources
>besides the two already listed. Maybe the table should be called
>plugin_reference, and have the columns Plugin-id, Type, and Value.
>
I believe this is the same idea behind the OSVDB. However, I don't like
for several reasons:

- you cannot impose syntax restrictions based on the table. Example:
Plugin-CVE.Value has to be "CVE|CAN-\d+-\d+" while Plugin-BID.Value is
just "\d+". So you have to define them as text or character(255).
Imposing syntax restrictions provides a mechanism, in the long run, to
avoid database corruption due to improper information being entered.
That's just IMHO.

- if you want to do a union between, say, CVE and the Nessus-plugins
there is going to be a lot of overhead due to the other references. I.e.:
SELECT * from Plugin-CVE, CVE where Plugin-CVE.Value = CVE.ID
is going to be less overhead than
SELECT * from Plugin_reference, CVE where Plugin_reference.Type='CVE'
and Plugin_reference.Value = CVE.ID

I'm not sure if there are valid reasons, however, feel free to discuss
them. I'm open to suggestions ...

>
>You could also normalize out many other things in this schema such as
>Nessus-plugin.category,type, etc...
>
Yes, that can be done. Thanks for pointing it out.

Javi
Re: Proposed schema for the backend database for Nessus [ In reply to ]
Alex Zimin wrote:

>>You will see there is no such thing as a "report" in this schema. Other
>>proposals (from front-ends) include directly the report information into
>> the database. I'm not doing this since it is already redundant. If you
>>check carefully, a report on a given session is just all the
>>vulnerabilities that have been detected in a given session. I.e.
>>
>>SELECT Nessus-plugin.Description, Vulnerability.Type,
>>Vulnerability.AdditionalInformation from Vulnerability, ExecutedPlugins,
>> NessusPlugin where Vulnerability.ExecutionID =
>>ExecutedPlugins.ExecutionID AND
>>ExecutedPlugins.PluginID=NessusPlugin.PluginID AND
>>ExecutedPlugins.SessionID="A GIVEN SESSION"
>>
>>Does this make sense at all? :-)
>>
>>
>
>It will not be too difficult to generate a report based on provided
>tables, however I want to notice one thing.
>About month ago Renaud did a clean up of the plugins and several plugins
>were removed, due to the same functionality included in different plugins
>
>If plugin table would not contain outdated plugin data, it will not be
>possible to generate proper report.
>
There's no reason why the Nessus-plugin table would not be able to
contain outdated data. As long as pluginIDs are not reused whenever they
are removed (are they?) you can have all the information there. Since
you create this information with your first Nessus installation and
update it regularly you are going to have always both the old plugins
and the (updated) new ones...

>Should we add a table which would list substituded plugins in case old
>plugins would be replaced with a new plugins, with better functionality?
>
>Table structure will be very simple
>
>PluginID (original pluginID)
>SubstPluginID (new PluginID)
>SubstitutionDate (optional)
>
That's not a bad idea, it would make report generation more complex, though.

>In this case report will be generated and will display the description of
>the substituted plugin.
>
But that description might not be proper or valid. Take for example that
the 'default_accounts' plugin (10328) is substituted by the hydra plugin
(10909) which checks, not only telnet but many other services (not that
it's going to happen). Even if the end functionality is the same, if you
are not providing a proper username/password file for hydra then you
might not detect (i.e. bruteforce) and account that the previous plugin
did detect (it provides an 'accounts.txt' file which includes some
common user/password combinations).

So, not only would the output information differ the results as well as
the references (CAN-1999-0502 for 10328) might even do too..

>
>Or maybe even just add SubsPluginID and Date to the Nessus-Plugins table,
>but in this case we may have too much garbage in that table.
>
Yes. I guess this "feature" is not going to be used all the time, just
in some specific locations.

>
>Does it make sense?
>
>
>
Yes it does and you've brought up a valid issue. I'm not sure if Renaud
has reused plugin-ids after removing them for whatever reason (Renaud?).

Regards

Javi

PS: If someone can provide comparison of plugins from the different
Nessus releases I would be more than grateful (and the 'nessus-extract'
tool would be useful here, hint, hint...)
Re: Proposed schema for the backend database for Nessus [ In reply to ]
Javier Fernandez-Sanguino wrote:
> More food for thought (or for discussion, whatever you prefer)
(...)
>
> Comments on the schema appreciated.
>

Just wanted to let you know that I'm still analysing the database issue
but have no available time this week to work on it. Hopefully next week
I'll be able to start coding something useful.

In the meantime feel free to forward me any comments on the proposed
database schema if you have not yet done so.

Regards


Javi
Re: Proposed schema for the backend database for Nessus [ In reply to ]
I've been working on some modifications to Javier's proposal for a database
schema, and I thought I'd share with the group what I've done so far.

I've posted to a tarball
(http://mywebpages.comcast.net/earnoth/proposed_nessus_db_schema.tgz)
with a bunch of stuff:
proposed_nessus_db_schema.v1.dia - Javier's original diagram drawn with Dia
proposed_nessus_db_schema.v1.mysql - Javier's original design for MySQL
proposed_nessus_db_schema.v1.pgsql - Javier's original design for PostgreSQL
proposed_nessus_db_schema.v1.png - Image of Javier's original diagram in Dia
proposed_nessus_db_schema.v2.dia - Diagram with my changes, drawn with Dia
proposed_nessus_db_schema.v2.mysql -Design with my changes for MySQL
proposed_nessus_db_schema.v2.pgsql - Design with my changes for PostgreSQL
proposed_nessus_db_schema.v2.png - Image diagram with my changes in Dia

In case you've never heard of Dia, it's a Visio-like diagraming program. You
can find it here - http://www.lysator.liu.se/~alla/dia/home.html. The
drawings I made were with the UML drawing tools (Class & Constraint,
specifically).

The sql statements (*pgsql, *mysql) were created with a script I wrote called
Dia2SQLpy. The script takes the Dia UML diagrams and produces either a mysql
or postgresql create statement.
You can find it's homepage here -
http://honeypotdiary.org/earnoth/html/modules.php?name=Content&pa=showpage&pid=16
If you visit, please be patient, it will take a while for the page to load.

Here's the list of changes I made, and my reasoning:
================================================================================
Deleted ExecutionID column from Vulnerability table.
Deleted fk relationship Vulnerability_ExecutedPlugins_ExecutionID.
Created PluginID column in Vulnerability table.
Created fk relationship Vulnerability_NessusPlugins_PluginID.
--------------------------------------------------------------------------------
A plugin will address a given vulnerability. ExecutedPlugins relates plugins
to sessions. Vulnerabilities are related to plugins regardless of scans
performed.

================================================================================
Deleted PluginCVE table, added CVE column to Vulnerability table.
--------------------------------------------------------------------------------
A CVE names a vulnerability, not a Plugin. Plugins may reference
vulnerabilities through the CVE number, but CVE's are not published against
Nessus plugins.
A CVE entry only accounts for a single vulnerability. As such, each
vulnerability listed in the Vulnerability table should only need one entry.

================================================================================
Deleted BID, added BugtraqID column to Vulnerability table.
--------------------------------------------------------------------------------
Same reasoning as CVE

================================================================================
Deleted IsFalsePositive column from Vulnerability table.
Added IsFalsePositive column to ExecutedPlugins table.
--------------------------------------------------------------------------------
In keeping with the model that differentiates a vulnerability from the
execution iof a plugin n a session, a false positive is an aspect of a scan,
not the vulnerability.

================================================================================
Deleted DetectedService_NessusPlugin_PluginID fk relationship.
Deleted Services_ExecutedPlugins_ServiceID fk relationship.
Reversed Services_DetectedService_ServiceID fk relationship.
Deleted ServiceID column from ExecutedPlugins table.
Deleted PluginID column from DetecteService table.
Created ServiceID column to NessusPlugin table.
Created NessusPlugin_Services_ServiceID fk relationship.
--------------------------------------------------------------------------------
A plugin will only probe a vulnerability in a single service. As such,
linking each NessusPlugin row will have an associated row in the Services
table, regardless of any scan run with the plugin (ExecutedPlugins).

================================================================================
Created NessusVersion column in Session table.
--------------------------------------------------------------------------------
It might be useful to know what version of Nessus was used in a given scan

================================================================================
Added FoundVulnerable column to ExecutedPlugins table.
Deleted PluginID column from Vulnerability table.
Added VulnerabilityID column to NessusPlugin table.
Added Description column to Vulnerability table.
Deleted Vulnerability_NessusPlugin_PluginID fk reference.
Created NessusPlugin_Vulnerability_VulnerabilityID fk reference.
--------------------------------------------------------------------------------
Furthering the seperation of the Vulnerability, Plugin, and scan sessions
concepts.

--------------------------------------------------------------------------------
Other thoughts:

There may be an issue with the NessusPlugin table. Due to the nature of all
the columns specified there, each one demands a large varchar() datatype.
However, having too large of a max row size can be problematic. However, the
plugin is a discrete conceptual unit, so the columns all make sense to be in
that table.

Should ExecutedPlugins have timestamps as it does now? That is, does nessus
record when each plugin is stopped & started? If not, then the StartTime &
EndTime should probably be removed from ExecutedPlugins.
--------------------------------------------------------------------------------

Any comments on these thoughts would be very welcome.

--
Eric I. Arnoth CISSP (http://www.isc2.org)
earnoth@comcast.net
http://mywebpages.comcast.net/earnoth
¤ø,¸¸,ø¤º°*°º¤ø,¸¸,ø¤ø,¸¸,ø¤º°*°º¤ø,¸¸,ø¤ø,¸¸,ø¤º°*°º¤ø,¸¸,ø¤ø,¸¸,ø¤º°*°º¤ø,¸¸,ø
On Thursday 16 January 2003 03:59, Javier Fernandez-Sanguino wrote:
> Alex Zimin wrote:
> >>You will see there is no such thing as a "report" in this schema. Other
> >>proposals (from front-ends) include directly the report information into
> >> the database. I'm not doing this since it is already redundant. If you
> >>check carefully, a report on a given session is just all the
> >>vulnerabilities that have been detected in a given session. I.e.
> >>
> >>SELECT Nessus-plugin.Description, Vulnerability.Type,
> >>Vulnerability.AdditionalInformation from Vulnerability, ExecutedPlugins,
> >> NessusPlugin where Vulnerability.ExecutionID =
> >>ExecutedPlugins.ExecutionID AND
> >>ExecutedPlugins.PluginID=NessusPlugin.PluginID AND
> >>ExecutedPlugins.SessionID="A GIVEN SESSION"
> >>
> >>Does this make sense at all? :-)
> >
> >It will not be too difficult to generate a report based on provided
> >tables, however I want to notice one thing.
> >About month ago Renaud did a clean up of the plugins and several plugins
> >were removed, due to the same functionality included in different plugins
> >
> >If plugin table would not contain outdated plugin data, it will not be
> >possible to generate proper report.
>
> There's no reason why the Nessus-plugin table would not be able to
> contain outdated data. As long as pluginIDs are not reused whenever they
> are removed (are they?) you can have all the information there. Since
> you create this information with your first Nessus installation and
> update it regularly you are going to have always both the old plugins
> and the (updated) new ones...
>
> >Should we add a table which would list substituded plugins in case old
> >plugins would be replaced with a new plugins, with better functionality?
> >
> >Table structure will be very simple
> >
> >PluginID (original pluginID)
> >SubstPluginID (new PluginID)
> >SubstitutionDate (optional)
>
> That's not a bad idea, it would make report generation more complex,
> though.
>
> >In this case report will be generated and will display the description of
> >the substituted plugin.
>
> But that description might not be proper or valid. Take for example that
> the 'default_accounts' plugin (10328) is substituted by the hydra plugin
> (10909) which checks, not only telnet but many other services (not that
> it's going to happen). Even if the end functionality is the same, if you
> are not providing a proper username/password file for hydra then you
> might not detect (i.e. bruteforce) and account that the previous plugin
> did detect (it provides an 'accounts.txt' file which includes some
> common user/password combinations).
>
> So, not only would the output information differ the results as well as
> the references (CAN-1999-0502 for 10328) might even do too..
>
> >Or maybe even just add SubsPluginID and Date to the Nessus-Plugins table,
> >but in this case we may have too much garbage in that table.
>
> Yes. I guess this "feature" is not going to be used all the time, just
> in some specific locations.
>
> >Does it make sense?
>
> Yes it does and you've brought up a valid issue. I'm not sure if Renaud
> has reused plugin-ids after removing them for whatever reason (Renaud?).
>
> Regards
>
> Javi
>
> PS: If someone can provide comparison of plugins from the different
> Nessus releases I would be more than grateful (and the 'nessus-extract'
> tool would be useful here, hint, hint...)
Re: Proposed schema for the backend database for Nessus [ In reply to ]
Eric Arnoth wrote:
> I've been working on some modifications to Javier's proposal for a database
> schema, and I thought I'd share with the group what I've done so far.

That's great. See my comments below.

> > I've posted to a tarball
>
(...)
>
> The sql statements (*pgsql, *mysql) were created with a script I wrote called
> Dia2SQLpy. The script takes the Dia UML diagrams and produces either a mysql
> or postgresql create statement.

Cool. I'll take this into account. I've worked with Dia before, could
you please send this script to the Dia upstream developers so they
include it in the contrib/ section of it?

>
> Here's the list of changes I made, and my reasoning:
> ================================================================================
> Deleted ExecutionID column from Vulnerability table.
> Deleted fk relationship Vulnerability_ExecutedPlugins_ExecutionID.
> Created PluginID column in Vulnerability table.
> Created fk relationship Vulnerability_NessusPlugins_PluginID.
> --------------------------------------------------------------------------------
> A plugin will address a given vulnerability. ExecutedPlugins relates plugins
> to sessions. Vulnerabilities are related to plugins regardless of scans
> performed.

The fact is, you've gotten this wrong IMHO.
Vulnerabilities are associated with hosts. That is, the vulnerability
table are vulnerabilities that have been _found_ while testing a host.
Not "theoric" vulnerabilities.

Why are ExecutedPlugins and Vulnerabilities separated then? Because you
can execute a plugin against a host but don't detect any vulnerability
associated with it.

The "AdditionalInformation" stuff is a placeholder for information that
a Plugin might have retrieved from a host. Sample: banners from a telnet
server, open shares from a Netbios host. That's the main reasoning of
having an

"executedplugin -> vulnerability"

Maybe I should have named it "Detected_Vulnerability" and not just
"Vulnerability". However, the point is: I want an easy way to determine
the exact # of vulnerabilties in my infraestructure. I can then link
this to a ticket-based management system that provides me with a view
with which vulnerabilities are still "open" (i.e. have not been fixed by
the admins) and issue a ticket whenever I find a vulnerability.


>
> ================================================================================
> Deleted PluginCVE table, added CVE column to Vulnerability table.
> --------------------------------------------------------------------------------
> A CVE names a vulnerability, not a Plugin. Plugins may reference
> vulnerabilities through the CVE number, but CVE's are not published against
> Nessus plugins.
> A CVE entry only accounts for a single vulnerability. As such, each
> vulnerability listed in the Vulnerability table should only need one entry.

Not correct.

>
> ================================================================================
> Deleted BID, added BugtraqID column to Vulnerability table.
> --------------------------------------------------------------------------------
> Same reasoning as CVE

Ditto. There are three wrong assumptions here:

- a vulnerability is a "theoric" one. Which is not, it's one that has
been detected
- there is always one CVE entry for each Bugtraq entry
- there is always one CVE/Bugtraq entry for each plugin.

As a matter of fact there are plugins which test more than a given
vulnerability. NASL won't allow this to be placed in the reports just
yet, but should do in the future.

>
> ================================================================================
> Deleted IsFalsePositive column from Vulnerability table.
> Added IsFalsePositive column to ExecutedPlugins table.
> --------------------------------------------------------------------------------
> In keeping with the model that differentiates a vulnerability from the
> execution iof a plugin n a session, a false positive is an aspect of a scan,
> not the vulnerability.
>
Since this assumption of vulnerability not associated with plugin
execution is false (or at least not properly understood), I'm afraid
this shouldn't be done either.


> ================================================================================
> Deleted DetectedService_NessusPlugin_PluginID fk relationship.
> Deleted Services_ExecutedPlugins_ServiceID fk relationship.
> Reversed Services_DetectedService_ServiceID fk relationship.
> Deleted ServiceID column from ExecutedPlugins table.
> Deleted PluginID column from DetecteService table.
> Created ServiceID column to NessusPlugin table.
> Created NessusPlugin_Services_ServiceID fk relationship.
> --------------------------------------------------------------------------------
> A plugin will only probe a vulnerability in a single service. As such,
> linking each NessusPlugin row will have an associated row in the Services
> table, regardless of any scan run with the plugin (ExecutedPlugins).
>
That's not correct. There might be plugins which test more than one
service. Simple example: a port scanner or the hydra brute force
scanner. You cannot have a 1:1 relationship between plugins and
services, that's just not correct.


> ================================================================================
> Created NessusVersion column in Session table.
> --------------------------------------------------------------------------------
> It might be useful to know what version of Nessus was used in a given scan
>
Yes. This one might be useful.


> ================================================================================
> Added FoundVulnerable column to ExecutedPlugins table.
> Deleted PluginID column from Vulnerability table.
> Added VulnerabilityID column to NessusPlugin table.
> Added Description column to Vulnerability table.
> Deleted Vulnerability_NessusPlugin_PluginID fk reference.
> Created NessusPlugin_Vulnerability_VulnerabilityID fk reference.
> --------------------------------------------------------------------------------
> Furthering the seperation of the Vulnerability, Plugin, and scan sessions
> concepts.
>
Since vulnerabilities are not "generic" ones but specific ones. There
is no way you can do these changes. Note that you could have this schema
and add it whatever additional information you want to (for example
CERT's/CVE's/Bugtraq's database) which would provide the detailed
description information you are talking about.


> --------------------------------------------------------------------------------
> Other thoughts:
>
> There may be an issue with the NessusPlugin table. Due to the nature of all
> the columns specified there, each one demands a large varchar() datatype.
> However, having too large of a max row size can be problematic. However, the
> plugin is a discrete conceptual unit, so the columns all make sense to be in
> that table.

I'm not sure this is an issue. I have the whole plugin information in a
table with this schema and I'm not seeing problems with this.

>
> Should ExecutedPlugins have timestamps as it does now? That is, does nessus
> record when each plugin is stopped & started? If not, then the StartTime &
> EndTime should probably be removed from ExecutedPlugins.

Nessusd should (check Michael's code) introduce this information in the
database:

- right after calling a plugin -> make an SQL insert
- right after finishing a plugin call -> make an SQL update

If the nessus server fails you can still see which plugins were not
finished by checking which ones do not have an end time. This
information is also useful to make estimates of how much a scan will
take place, given the same condition. I.e. determine roughly how much on
average a plugin against a given host will run.

However, it might make sense to add a column for the nessus server to
add to the database when a given plugin was killed or did not end
correctly (maybe a boolean?)


How about adding the .dia and .mysql, .pgsql files in the Nessus CVS
source so we can keep track of what changes have been done to the schema?

Regards


Javi
Re: Proposed schema for the backend database for Nessus [ In reply to ]
Javier Fernandez-Sanguino wrote:

> Nessusd should (check Michael's code) introduce this information in the
> database:

Of course, I meant William (Heinbockel), not Michael, sorry.

Javi
Re: Proposed schema for the backend database for Nessus [ In reply to ]
On Tuesday 11 February 2003 05:04, Javier Fernandez-Sanguino wrote:
> Cool. I'll take this into account. I've worked with Dia before, could
> you please send this script to the Dia upstream developers so they
> include it in the contrib/ section of it?
Thanks for the suggestion. I'm looking into that.

> > Here's the list of changes I made, and my reasoning:
> > =========================================================================
> >======= Deleted ExecutionID column from Vulnerability table.
> > Deleted fk relationship Vulnerability_ExecutedPlugins_ExecutionID.
> > Created PluginID column in Vulnerability table.
> > Created fk relationship Vulnerability_NessusPlugins_PluginID.
> > -------------------------------------------------------------------------
> >------- A plugin will address a given vulnerability. ExecutedPlugins
> > relates plugins to sessions. Vulnerabilities are related to plugins
> > regardless of scans performed.
>
> The fact is, you've gotten this wrong IMHO.
Okay, your opinion is noted...care for a little debate? :-)

> Vulnerabilities are associated with hosts. That is, the vulnerability
> table are vulnerabilities that have been _found_ while testing a host.
> Not "theoric" vulnerabilities.
I can understand what you're shooting for, but I think it's the wrong approach
to get there. True, a host may have a given vulnerability and we want Nessus
to tell us that for each case. However, a vulnerability is still a discrete
entity (a condition of a piece of software). That's not saying it's
"theoretic", theoretic is when the vulnerability is determined through
analysis but no *known* exploit exists. By placing making an fk relationship
from the Plugin table to the Vulnerability table, we're maintaining the
proper relationship of two differnt entities.

> Why are ExecutedPlugins and Vulnerabilities separated then? Because you
> can execute a plugin against a host but don't detect any vulnerability
> associated with it.
That's why a boolean column value called "FoundVulnerable" or some such thing
should be in the ExecutedPlugins table...because it's an attribute (the
result) of the action of running the plugin (which is what the
ExecutedPlugins table represents).

> The "AdditionalInformation" stuff is a placeholder for information that
> a Plugin might have retrieved from a host. Sample: banners from a telnet
> server, open shares from a Netbios host.
If you want to store data gathered during a plugin, just make it a column of
the ExecutedPlugins table. It's a much more logical place for it, since that
table is the record of a moment in time - each row representing some given
state of the system we're scanning.

> That's the main reasoning of having an "executedplugin -> vulnerability"
Unfortunately, this is putting the cart before the horse. What we have here
is a hierarchical relationship between two entities and one state. A
vulnerability is discovered. Renaurd et al write a plugin against it. You
and I run our Nessus scanners against our respective networks, executing the
plugin, where we get a postive or negative. That's the hierarchical order of
these three things...to express it any other way is incorrect.

> Maybe I should have named it "Detected_Vulnerability" and not just
> "Vulnerability". However, the point is: I want an easy way to determine
> the exact # of vulnerabilties in my infraestructure.
To have a table that gets rows for every vulnerability on every host is
wasteful. Let's make up an example (which you can find at
http://mywebpages.comcast.net/earnoth/example.tar! ;) where there are three
hosts who all have the same two plugins executed against them (let's just
arbitrarily pick "WS FTP overflows" (CAN-2001-1021) and "Canna Overflow"
(CVE-2000-0584). Let's now pretend that all three are vulnerable to both.
Now the Vulnerability table is going to be populated with no less than four
duplicate rows. Now lets imagine this for a scan against 200 hosts where
there are common vulnerabilities between hosts (let's pick an average of 40
per host). That scales out to about 7,960 (200*40 - 40) duplicate rows that
store redunant data. This a terrible waste of space.

So what do we buy with the space we're throwing away?

To get the vulnerabilities for a host in the original v->e->p schema, we might
use something like this:
--------------------------------------------------------------------------------
jefferson8:40pm[121]> cat query.v1.sql
select h.name, v.type
from host h, vulnerability v, executedplugins e
where
v.executionid = e.executionid and e.sessionid = 1 and
h.hostid = e.hostid
--------------------------------------------------------------------------------
A simple query indeed. To get the vulnerabilities for a host in the e->p->v
schema, we might use something like this:
--------------------------------------------------------------------------------
jefferson8:44pm[122]> cat query.v3.sql
select h.name, v.type
from host h, vulnerability v, executedplugins e, nessusplugin p
where
p.pluginid = e.pluginid and e.sessionid = 1 and e.foundvulnerable=TRUE
and
h.hostid = e.hostid and p.vulnerabilityid = v.vulnerabilityid
--------------------------------------------------------------------------------
(nessusdb_v3 is the same as v2, but I changed the FoundVulnerable column type
from bit to boolean)
That's not too much more complex, though. So what exactly are we gaining for
all that wasted space? Okay, so we might take a small hit on performance,
but even for large result sets, I can't a see how a small query performance
save is worth the waste shown above.


> I can then link
> this to a ticket-based management system that provides me with a view
> with which vulnerabilities are still "open" (i.e. have not been fixed by
> the admins) and issue a ticket whenever I find a vulnerability.
I can understand this viewpoint entirely. I work in a massive corporation,
and this kind of thing is the bane of our existance. However, I think the
examples I've posted here show that the revisions I posted can achieve the
same thing. It's simply a matter of how one builds one's additional table
structure around the foundation, however that foundation is built. Moreover,
if the foundation is built around how the data being modeled relates to one
another, additional structure will acually work better, in the long-run.


>
> > =========================================================================
> >======= Deleted PluginCVE table, added CVE column to Vulnerability table.
> > -------------------------------------------------------------------------
> >------- A CVE names a vulnerability, not a Plugin. Plugins may reference
> > vulnerabilities through the CVE number, but CVE's are not published
> > against Nessus plugins.
> > A CVE entry only accounts for a single vulnerability. As such, each
> > vulnerability listed in the Vulnerability table should only need one
> > entry.
>
> Not correct.
Really? The CVE naming process documentation at
http://cve.mitre.org/docs/docs2000/naming_process.html references the terms
vulnerability and exposure in the singular term.

Also, this quote seems to suggest vulnerabilities and exposures are expressed
in the singular form (from http://cve.mitre.org/about/faq.html#C1):
------------------------------------------------------------------------------------------
C1. What information is included in a CVE entry?

CVE names include the name (also referred to as the CVE "number"), a brief
description of the security vulnerability or exposure, and any pertinent
references. The CVE number, for example, CVE-2000-0067, is an encoding of the
year and a unique number N for the Nth candidate proposed that year.
------------------------------------------------------------------------------------------
I have yet to see a CVE that refers to more than one vuln...could you please
give an example where a single CVE references more than one discrete
vulnerability? Even if that is the case, then simply breaking out the CVE
into its own table as it was originally done is a simple solution.


> > =========================================================================
> >======= Deleted BID, added BugtraqID column to Vulnerability table.
> > -------------------------------------------------------------------------
> >------- Same reasoning as CVE
>
> Ditto. There are three wrong assumptions here:
>
> - a vulnerability is a "theoric" one. Which is not, it's one that has
> been detected
Again, a theoretical vulnerability is one which has no *known* exploit against
it. I understand the want to link a host with it's vulnerabilities (that's
the whole point of Nessus, of course!) but that doesn't change the fact that
a vulnerability is a discrete concept, or entity, and should be properly
represented in the database design.

> - there is always one CVE entry for each Bugtraq entry
> - there is always one CVE/Bugtraq entry for each plugin.
>
> As a matter of fact there are plugins which test more than a given
> vulnerability. NASL won't allow this to be placed in the reports just
> yet, but should do in the future.
Here again, could you please provide an example? I admit I could be
completely wrong here (as with the CVE matter) but I have yet to find an
example. I did check the plugin list on the web, but was unable to find
anything.

> > =========================================================================
> >======= Deleted IsFalsePositive column from Vulnerability table.
> > Added IsFalsePositive column to ExecutedPlugins table.
> > -------------------------------------------------------------------------
> >------- In keeping with the model that differentiates a vulnerability from
> > the execution iof a plugin n a session, a false positive is an aspect of
> > a scan, not the vulnerability.
>
> Since this assumption of vulnerability not associated with plugin
> execution is false (or at least not properly understood), I'm afraid
> this shouldn't be done either.
See my comments above.

>
> > =========================================================================
> >======= Deleted DetectedService_NessusPlugin_PluginID fk relationship.
> > Deleted Services_ExecutedPlugins_ServiceID fk relationship.
> > Reversed Services_DetectedService_ServiceID fk relationship.
> > Deleted ServiceID column from ExecutedPlugins table.
> > Deleted PluginID column from DetecteService table.
> > Created ServiceID column to NessusPlugin table.
> > Created NessusPlugin_Services_ServiceID fk relationship.
> > -------------------------------------------------------------------------
> >------- A plugin will only probe a vulnerability in a single service. As
> > such, linking each NessusPlugin row will have an associated row in the
> > Services table, regardless of any scan run with the plugin
> > (ExecutedPlugins).
>
> That's not correct. There might be plugins which test more than one
> service. Simple example: a port scanner or the hydra brute force
> scanner. You cannot have a 1:1 relationship between plugins and
> services, that's just not correct.
Quite right, I see that there are plugins which do scan multiple ports. A
simple many-to-many table structure can solve that.

>
> > =========================================================================
> >======= Created NessusVersion column in Session table.
> > -------------------------------------------------------------------------
> >------- It might be useful to know what version of Nessus was used in a
> > given scan
>
> Yes. This one might be useful.
Glad we agree somewhere...hopefully through this debate we can find more to
agree on. ;-)

> > =========================================================================
> >======= Added FoundVulnerable column to ExecutedPlugins table.
> > Deleted PluginID column from Vulnerability table.
> > Added VulnerabilityID column to NessusPlugin table.
> > Added Description column to Vulnerability table.
> > Deleted Vulnerability_NessusPlugin_PluginID fk reference.
> > Created NessusPlugin_Vulnerability_VulnerabilityID fk reference.
> > -------------------------------------------------------------------------
> >------- Furthering the seperation of the Vulnerability, Plugin, and scan
> > sessions concepts.
>
> Since vulnerabilities are not "generic" ones but specific ones. There
> is no way you can do these changes. Note that you could have this schema
> and add it whatever additional information you want to (for example
> CERT's/CVE's/Bugtraq's database) which would provide the detailed
> description information you are talking about.
It's not a matter of "generic" versus "specific". I've already pretty well
beaten this topic to death, but I'll just respond to this last one by again
stressing that a vulnerability is a discrete entity that should be
appropriately represented in both table and surrounding structure (correct
foriegn key relationships, etc). The association of a host with a
vulnerability is properly achieved through the
ExecutedPlugins->Plugins->Vulnerability structure.

It is good to note that the Executed->Plugin->Vuln structure parallels the
DetectedService->Services->Protocol layout in the original design. The two
sets of tables show very similar hierarchical relationships. (A host has a
service listening on a given port over a given protocol, and a host has a
plugin result from the an execution of a plugin which was written to address
a vulnerability).

>
> > -------------------------------------------------------------------------
> >------- Other thoughts:
> >
> > There may be an issue with the NessusPlugin table. Due to the nature of
> > all the columns specified there, each one demands a large varchar()
> > datatype. However, having too large of a max row size can be problematic.
> > However, the plugin is a discrete conceptual unit, so the columns all
> > make sense to be in that table.
>
> I'm not sure this is an issue. I have the whole plugin information in a
> table with this schema and I'm not seeing problems with this.
This will be DBMS specific, and may depend on each database supported in
turn...


> > Should ExecutedPlugins have timestamps as it does now? That is, does
> > nessus record when each plugin is stopped & started? If not, then the
> > StartTime & EndTime should probably be removed from ExecutedPlugins.
>
> Nessusd should (check Michael's code) introduce this information in the
> database:
>
> - right after calling a plugin -> make an SQL insert
> - right after finishing a plugin call -> make an SQL update
D'oh! Where was my brain on that one....?!?


> If the nessus server fails you can still see which plugins were not
> finished by checking which ones do not have an end time. This
> information is also useful to make estimates of how much a scan will
> take place, given the same condition. I.e. determine roughly how much on
> average a plugin against a given host will run.
>
> However, it might make sense to add a column for the nessus server to
> add to the database when a given plugin was killed or did not end
> correctly (maybe a boolean?)
A good idea, indeed. Boolean would work, I see in the nessus code that there
is a return value specifying "killed plugin" (or some such thing, it was a
few nights ago I looked...)


> How about adding the .dia and .mysql, .pgsql files in the Nessus CVS
> source so we can keep track of what changes have been done to the schema?
Has someone set up an independent CVS server for this database project, or is
there a module in the main Nessus CVS? If the first, I know know where it
is, if the second, I don't have write access... How does one get access?

Just as a note, I plan to write some PostgreSQL code, similar in nature to
what William has written, though after looking at his code I have some
additional ideas for additional functions that should be implemented. Of
course, C design shouldn't be taken too far until a database design is
finalized.


--
Eric I. Arnoth CISSP (http://www.isc2.org)
earnoth@comcast.net
http://mywebpages.comcast.net/earnoth
¤ø,¸¸,ø¤º°*°º¤ø,¸¸,ø¤ø,¸¸,ø¤º°*°º¤ø,¸¸,ø¤ø,¸¸,ø¤º°*°º¤ø,¸¸,ø¤ø,¸¸,ø¤º°*°º¤ø,¸¸,ø
Re: Proposed schema for the backend database for Nessus [ In reply to ]
On Wed, Feb 12, 2003 at 10:15:10PM -0500, Eric Arnoth wrote:
> > How about adding the .dia and .mysql, .pgsql files in the Nessus CVS
> > source so we can keep track of what changes have been done to the schema?
> Has someone set up an independent CVS server for this database project, or is
> there a module in the main Nessus CVS? If the first, I know know where it
> is, if the second, I don't have write access... How does one get access?

Javier will set up a branch called "NESSUS_SQL" on cvs.nessus.org.


>
> Just as a note, I plan to write some PostgreSQL code, similar in nature to
> what William has written, though after looking at his code I have some
> additional ideas for additional functions that should be implemented. Of
> course, C design shouldn't be taken too far until a database design is
> finalized.

At this time, Javier Fernandez is the benevolent project manager for the
SQL integration, and he now has write access to the CVS repository. Send
him your code and he'll be in charge of commiting it after an intensive
review. When he's familiar with your code, he may ask me to give you CVS
access which I'll happily do.



-- Renaud
Re: Proposed schema for the backend database for Nessus [ In reply to ]
Eric Arnoth wrote:
> On Tuesday 11 February 2003 05:04, Javier Fernandez-Sanguino wrote:
>>
>>The fact is, you've gotten this wrong IMHO.
>
> Okay, your opinion is noted...care for a little debate? :-)

Sure, let's go.

Let me first say that, reviewing my schema, I believe that the
"Vulnerability" table is basicly misnamed. It should be
"detectedvulnerability". The fact here is that I wanted to separate
plugins that have been executed in a given run (which is quite high
usually) and plugins return that a given system is vulnerable.

Also, note that I wouldn't put both information in the same place (i.e.
table). There are two reasons for this:

1.- some plugins test more than one vulnerability. From a brief look:
http_w98_devname_dos.nasl (10930)
mediahouse_statistics_web_server.nasl (10748)
openssh_301.nasl (10802)
smb_nt_ms02-005.nasl (10861)
smb_nt_ms01-025.nasl (10668)

2.- Some other plugins give more than one security warning or note:
find_service2.nasl (11153)
find_service
http_methods.nasl (10498)
iis_nat.nasl (10759)
iplanet_dir_serv.nasl (10589)
mediahouse_statistics_web_server.nasl (10748)
ncl_items_2.nasl (10665)
novell_groupwise_webacc_information_disclosure.nasl (10789)
oracle_tnslsnr_version.nasl (10658)
php_nuke_admin_cp.nasl (10772)
phprocketaddin_traversal.nasl (10831)
showmount.nasl (10437)
web_traversal.nasl (10297)

This is even "worse" for plugins like find_services and hydra, they
might output none, 1 or many different security warnings, notes or holes.

So the point here is the call to security_{hole|warning|hole} in the
plugins. Is this information that I believe needs to be hold in a single
table.

Noticed that this is not related to the "theoretic" vulnerabilities that
Eric pointed out, these are joined to the schema through external
references (CVE or Bugtraq). These are vulnerabilities _specific_ to the
hosts tested.

>>Why are ExecutedPlugins and Vulnerabilities separated then? Because you
>>can execute a plugin against a host but don't detect any vulnerability
>>associated with it.
>
> That's why a boolean column value called "FoundVulnerable" or some such thing
> should be in the ExecutedPlugins table...because it's an attribute (the
> result) of the action of running the plugin (which is what the
> ExecutedPlugins table represents).
>

The result is not only this attribute, it's also the information
retrieved from it (take a look at security_notes or warnings). This
information has to be stored in the database and is host-specific.


>>The "AdditionalInformation" stuff is a placeholder for information that
>>a Plugin might have retrieved from a host. Sample: banners from a telnet
>>server, open shares from a Netbios host.
>
> If you want to store data gathered during a plugin, just make it a column of
> the ExecutedPlugins table. It's a much more logical place for it, since that
> table is the record of a moment in time - each row representing some given
> state of the system we're scanning.
>
Can't do, some plugins add more than one. The point is, all are need to
address separately independently of which plugins executed them. I want
to "fix" real vulnerabilities, and that's why they are separated.

>
>>That's the main reasoning of having an "executedplugin -> vulnerability"
>
> Unfortunately, this is putting the cart before the horse. What we have here
> is a hierarchical relationship between two entities and one state. A
> vulnerability is discovered. Renaurd et al write a plugin against it. You
> and I run our Nessus scanners against our respective networks, executing the
> plugin, where we get a postive or negative. That's the hierarchical order of
> these three things...to express it any other way is incorrect.

Following your analogy:

- A vulnerability is detected (CVE, Bugtraq... is updated)
- The plugin writers create a plugin, this plugin migh detect more than
one of these vulnerabilities
- A plugin is run against a given host and returns security information.
This is not just saying "you are vulnerable" but also saying "this is
the information I found about you". And notice that he a given plugin
can say "you are vulnerable to X" _and_ say "you are vulnerable to Y" or
say "I found information on X" _and_ "I found information on Y"

Even if there is a single theoretic vulnerability there are multiple
"detected" vulnerabilities. Take a given router host, if the
snmp_communities plugin finds that I can access it through "cisco",
"read" _and_ "write" these are 3 distinct issues in that router
discovered by a single plugin.


>>Maybe I should have named it "Detected_Vulnerability" and not just
>>"Vulnerability". However, the point is: I want an easy way to determine
>>the exact # of vulnerabilties in my infraestructure.
>
> To have a table that gets rows for every vulnerability on every host is
> wasteful. Let's make up an example (which you can find at
> http://mywebpages.comcast.net/earnoth/example.tar! ;) where there are three
> hosts who all have the same two plugins executed against them (let's just
> arbitrarily pick "WS FTP overflows" (CAN-2001-1021) and "Canna Overflow"
> (CVE-2000-0584). Let's now pretend that all three are vulnerable to both.

Incorrect. The "generic" information of the theoretic vulnerability is
stored in the plugin database. The specific information to a host is
detected in the table I called "vulnerability" (which should have been
"detectedvulnerability").

> Now the Vulnerability table is going to be populated with no less than four
> duplicate rows. Now lets imagine this for a scan against 200 hosts where
> there are common vulnerabilities between hosts (let's pick an average of 40
> per host). That scales out to about 7,960 (200*40 - 40) duplicate rows that
> store redunant data. This a terrible waste of space.

Let's take a look at the real space of those rows:

- Vulnerability_ID and ExecutionID: an integer
- IsFalsepositive: a bit
- AdditionalInformation: a varchar(255), in your example is empty. There
is no additional information, the proper information is in the
Nessusplugin table.

So, against having all this in one table (as you proposed, in
ExecutedPlugins) you only have an increase of one integer per
vulnerability. That's 8kbytes. (being generous)

>
>>I can then link
>>this to a ticket-based management system that provides me with a view
>>with which vulnerabilities are still "open" (i.e. have not been fixed by
>>the admins) and issue a ticket whenever I find a vulnerability.
>
> I can understand this viewpoint entirely. I work in a massive corporation,
> and this kind of thing is the bane of our existance. However, I think the
> examples I've posted here show that the revisions I posted can achieve the
> same thing. It's simply a matter of how one builds one's additional table
> structure around the foundation, however that foundation is built. Moreover,
> if the foundation is built around how the data being modeled relates to one
> another, additional structure will acually work better, in the long-run.


Please rethink my proposal, you will find it more convenient. Note that
the ExecutedPlugins space grows larger than the (Detected)Vulnerability
table space. That's because _every_time_ you execute a plugin regardless
if it's successful or not, it's stored there. Whileas the
(Detected)Vulnerability only increases when you find a vulnerability.
There are ~1200 plugins. Hopefully, you will not get 1200 security
notes/warnings/holes for each host (if you do, you are in trouble).


>>>=========================================================================
>>>======= Deleted PluginCVE table, added CVE column to Vulnerability table.
>>>-------------------------------------------------------------------------
>>>------- A CVE names a vulnerability, not a Plugin. Plugins may reference
>>>vulnerabilities through the CVE number, but CVE's are not published
>>>against Nessus plugins.
>>>A CVE entry only accounts for a single vulnerability. As such, each
>>>vulnerability listed in the Vulnerability table should only need one
>>>entry.>>
>>Not correct.
>
> Really? The CVE naming process documentation at

Yes, really. The plugins might test more than one vulnerability. That's
why this table is necessary.


> I have yet to see a CVE that refers to more than one vuln...could you please
> give an example where a single CVE references more than one discrete
> vulnerability? Even if that is the case, then simply breaking out the CVE
> into its own table as it was originally done is a simple solution.

I'm not talking about wether or not CVE refers to more than one
vulnerability. I'm saying that _Plugins_ test more than one.


> Again, a theoretical vulnerability is one which has no *known* exploit against
> it. I understand the want to link a host with it's vulnerabilities (that's
> the whole point of Nessus, of course!) but that doesn't change the fact that
> a vulnerability is a discrete concept, or entity, and should be properly
> represented in the database design.

However theoretical "vulnerabilities" is not what Nessus is about.
That's what you would have if you loaded CVE/Bugtraq/CERT alongside your
Nessus schema, not something that Nessus should provide.


>>As a matter of fact there are plugins which test more than a given
>>vulnerability. NASL won't allow this to be placed in the reports just
>>yet, but should do in the future.
>
> Here again, could you please provide an example? I admit I could be
> completely wrong here (as with the CVE matter) but I have yet to find an
> example. I did check the plugin list on the web, but was unable to find
> anything.


See above, multiple examples. The most notorious are: find_service and
hydra. There can be more than one security note for a given host. In
find_service's cases it's not really a vulnerability, it's more like
information exposure. In hydra's case there is not really an specific
vulnerability tied to a given product/service it's a generic one
(default passwords). You want to store each and every one of these in
separate rows.


>
> It is good to note that the Executed->Plugin->Vuln structure parallels the
> DetectedService->Services->Protocol layout in the original design. The two
> sets of tables show very similar hierarchical relationships. (A host has a
> service listening on a given port over a given protocol, and a host has a
> plugin result from the an execution of a plugin which was written to address
> a vulnerability).

The relationship I'm trying to mimic is:

Host (X) -> Plugin (Y) -> DetectedVulnerability (Z)

i.e.: we have found host X vulnerable using Y and this is the additional
information : Z


Have I made my point? Are you convinced now? :-)

Javi
Re: Proposed schema for the backend database for Nessus [ In reply to ]
On Tuesday 18 February 2003 13:36, Javier Fernandez-Sanguino wrote:
<Lots of stuff in response to lots of stuff>
> Have I made my point? Are you convinced now? :-)
>
> Javi
Convinced indeed. Hope I didn't burn too many of peoples' cycles on this
debate.

I've taken your original proposal and added most of the elements from the
TODO.txt in CVS NESSUS_SQL. I've also added a lot of NOT NULL statements
where they seem appropriate (to me at least). It should hopefully be
segfault-safe for everyone: I know some people had problems opening it up on
their systems due to wierd fonts. I've changed all the fonts to Courier, so
hopefully that fixes that.

The dia diagram, pgsql and mysql output from dia2sqlpy and change notes are
all here:
http://mywebpages.comcast.net/earnoth/proposed_nessus_db_schema.v4.tgz
***Please note that if you generate the mysql output with dia2sqlpy yourself,
this will FAIL. I used boolean datatypes, and as yet, dia2sqlpy does not yet
handle the datatype nuances between the two DBMSes. I hope to add such
support in this weekend (it'll be easy but tedious) but until then, the MySQL
output from my script won't work until you substutited BOOL where BOOLEAN is
(vi command - :%s/BOOLEAN/BOOL/ ;-) After doing that, it will work.

One question I want to put up for public deba^H^H^H^Hdiscussion ;-) is the
question of ACID compliance: foreign key relationships, transactions, etc.
Being a postgresql fanatic, I feel very strongly that these concepts should
be implemented in the Nessus code. Indeed, the database design that's being
hammered out is very ACIDlike

For MySQL, however, there are some issues. With InnoDB, MySQL can have all of
this (according to the website [1]). However, I expect that most people have
not installed thier production databases with InnoDB compiled in. As well,
the MySQL philosophy seems to speak against foriegn keys (and thus
transactions)[2]

While it would be possible for the C code that supports PostgreSQL to support
ACID while keeping the MySQL nonACID, it might make this development effort
rather complicated. Not to mention the other vendor databases which Javier
eluded to (Oracle, Sybase) with his email about ./configure flags, all of
which are very ACID.

Please note that I am *NOT* trying to start a flame war about database
religion or any such thing. I have complete respect for MySQL's way of doing
things and the reasons for their choices. However, this does not change the
engineering issues presented by supporting two differing philosophies (ACID &
nonACID compliance). My intention is only to head off a conundrum which, I
expect, will be easier to solve at this early stage, while the C code is
still very nascent and the SQL schema is not yet bronzed.


[1]http://www.mysql.com/documentation/mysql/bychapter/manual_Table_types.html#InnoDB
[2]http://www.mysql.com/documentation/mysql/bychapter/manual_Tutorial.html#example-Foreign_keys

--
Eric I. Arnoth CISSP (http://www.isc2.org)
earnoth@comcast.net
http://mywebpages.comcast.net/earnoth
¤ø,¸¸,ø¤º°*°º¤ø,¸¸,ø¤ø,¸¸,ø¤º°*°º¤ø,¸¸,ø¤ø,¸¸,ø¤º°*°º¤ø,¸¸,ø¤ø,¸¸,ø¤º°*°º¤ø,¸¸,ø