2015-07-29 01:14 PM
Currently using Security Analytics 10.4
I'm running a daily report on password changes by non-owner, i.e., user changes a different user's password.
The predicate clause is:
alert.id = 'account:modified' && category = 'user account management' && device.type = 'winevent_nic' && user.src != user.dst
However, the last predicate doesn't do anything to remove accounts where user.src & user.dst are identical. There are still a large number of rows (almost all of them) where the user is changing their own password.
Anyone have any insight here? I've got a decent background in SQL and query syntax, but using the reporting engine makes me want to scream most days.
Message was edited by: nolsen311 -- trying to use code snippet markup --
2015-08-14 01:42 PM
To compare a meta value against a variable - essentially comparing against another meta value - you'd have to write a parser (on the Decoder / LogDecoder) then look for the resulting meta.
The below will accomplish your predicate clause. I haven't tested the functionality, but it is syntactically correct and the logic is simple. It will register alert meta "password change by non-owner". Save it as "*.lua" and put it in /etc/netwitness/ng/parsers then reload parsers (or upload it via the UI).
local pwchange = nw.createParser("password_change", "password change by non-owner")
pwchange:setKeys({
nwlanguagekey.create("alert"),
})
function pwchange:sessionBegin()
metaTable = {
["alertID"] = {},
["category"] = {},
["device"] = {},
["userSrc"] = {},
["userDst"] = {},
}
end
function pwchange:checkMeta()
if metaTable.alertID["account:modified"] and
metaTable.category["user account management"] and
metaTable.device["winevent_nic"] then
for changee in pairs(metaTable.userDst) do
for changeBy in pairs(metaTable.userSrc) do
if changee ~= changeBy then
nw.createMeta(self.keys.alert, "password change by non-owner")
return
end
end
end
end
end
function pwchange:alertID(idx, vlu)
metaTable.alertID[vlu] = true
self:checkMeta()
end
function pwchange:category(idx, vlu)
metaTable.category[vlu] = true
self:checkMeta()
end
function pwchange:device(idx, vlu)
metaTable.device[vlu] = true
self:checkMeta()
end
function pwchange:userSrc(idx, vlu
)
metaTable.userSrc[vlu] = true
self:checkMeta()
end
function pwchange:userDst(idx, vlu)
metaTable.userDst[vlu] = true
self:checkMeta()
end
pwchange:setCallbacks({
[nwevents.OnSessionBegin] = pwchange.sessionBegin,
[nwlanguagekey.create("alert.id", nwtypes.Text)] = pwchange.alertID,
[nwlanguagekey.create("category", nwtypes.Text)] = pwchange.category,
[nwlanguagekey.create("device.type", nwtypes.Text)] = pwchange.device,
[nwlanguagekey.create("user.src", nwtypes.Text)] = pwchange.userSrc,
[nwlanguagekey.create("user.dst", nwtypes.Text)] = pwchange.userDst,
})
2015-08-03 12:43 PM
As of now SA Core services (Concentrator, Broker, etc) does not support comparing meta with other meta with relational operators. i.e user.src != user.dst (both are metas)is not supported, only user.src != ‘user1, user2..’ is supported.
2015-08-14 01:42 PM
To compare a meta value against a variable - essentially comparing against another meta value - you'd have to write a parser (on the Decoder / LogDecoder) then look for the resulting meta.
The below will accomplish your predicate clause. I haven't tested the functionality, but it is syntactically correct and the logic is simple. It will register alert meta "password change by non-owner". Save it as "*.lua" and put it in /etc/netwitness/ng/parsers then reload parsers (or upload it via the UI).
local pwchange = nw.createParser("password_change", "password change by non-owner")
pwchange:setKeys({
nwlanguagekey.create("alert"),
})
function pwchange:sessionBegin()
metaTable = {
["alertID"] = {},
["category"] = {},
["device"] = {},
["userSrc"] = {},
["userDst"] = {},
}
end
function pwchange:checkMeta()
if metaTable.alertID["account:modified"] and
metaTable.category["user account management"] and
metaTable.device["winevent_nic"] then
for changee in pairs(metaTable.userDst) do
for changeBy in pairs(metaTable.userSrc) do
if changee ~= changeBy then
nw.createMeta(self.keys.alert, "password change by non-owner")
return
end
end
end
end
end
function pwchange:alertID(idx, vlu)
metaTable.alertID[vlu] = true
self:checkMeta()
end
function pwchange:category(idx, vlu)
metaTable.category[vlu] = true
self:checkMeta()
end
function pwchange:device(idx, vlu)
metaTable.device[vlu] = true
self:checkMeta()
end
function pwchange:userSrc(idx, vlu
)
metaTable.userSrc[vlu] = true
self:checkMeta()
end
function pwchange:userDst(idx, vlu)
metaTable.userDst[vlu] = true
self:checkMeta()
end
pwchange:setCallbacks({
[nwevents.OnSessionBegin] = pwchange.sessionBegin,
[nwlanguagekey.create("alert.id", nwtypes.Text)] = pwchange.alertID,
[nwlanguagekey.create("category", nwtypes.Text)] = pwchange.category,
[nwlanguagekey.create("device.type", nwtypes.Text)] = pwchange.device,
[nwlanguagekey.create("user.src", nwtypes.Text)] = pwchange.userSrc,
[nwlanguagekey.create("user.dst", nwtypes.Text)] = pwchange.userDst,
})
2015-08-18 12:47 PM
After installing this parser yesterday, I was a bit surprised that it didn't trip even once yesterday. Presumably, there was at least one password change yesterday, right?! (rhetorical)
Looking at the predicate, I noticed a teensy-tiny error on the alertID: account.modified -> account:modified
Is there some place to get a reference for what the lua objects are named vs their associated meta names?
2015-08-18 04:59 PM
Sorry about the typo. Does it work with that corrected?
There's no object name magic involved. The parser:
a) Does meta-callbacks for the keys that it is interested in. Any time any piece of content registered a value with one of those keys, the associated function will be called. E.g.,
[nwlanguagekey.create("category", nwtypes.Text)] = pwchange.category,
translation: Whenever meta is registered with the key "category", run the function in this parser named "category".
The function name is arbitrary - it could be "foo", so long as there is a function defined in the parser named "foo".
b) Stores the meta values in a lua table as they come in. The indices of the table are themselves tables, each named after the key with which the value was registered:
metaTable = {
["alertID"] = {},
["category"] = {},
["device"] = {},
["userSrc"] = {},
["userDst"] = {}
}
Again, the table names are arbitrary. You could name them anything you like, so long as you can keep track of which is which.
As meta comes in an index is added to a subtable. The index name is the meta value, and the value of the index is just set to 'true' (boolean).
e.g., Some log parser registers meta key "user.src" value "bob". The table now looks like:
metaTable = {
["alertID"] = {},
["category"] = {},
["device"] = {},
["userSrc"] = {
["bob"] = true
},
["userDst"] = {}
}
c) The table is examined to see if the meta values meet the conditions. Since booleans are used as the values of the indexes, that part is easy, e.g.,
-- did we see user.src meta with a value of "bob"?
if metaTable["userSrc"]["bob"] then ...
d) One bit of subtlety is checking metaTable every time meta comes in. This is because the parser doesn't know in what order it may see the meta. And the nested 'for' loops don't assume user.dst meta comes in after user.src meta since they are looking for 'values are different' rather than 'value doesn't exist'.
2015-08-19 10:32 AM
Hi,
Agree with the LUA, but maybe alert.id = account:password-change maybe better focused on windows eventid 4723 about password change.
I'm wrong?
Regards
2015-08-19 12:22 PM
It doesn't work that I can tell. I'm not seeing any "Alert" meta appearing, even though there are numerous password changes this morning already.
Probably not related, but:
We don't have a packet decoder with our equipment; we're set up as a "shared service" and the packet decoder is only available to our management agency.
I haven't implemented any custom lua parsers before this, maybe there's something I'm forgetting from the training about custom parsers.
Steps:
Still doesn't seem to be any Alert meta being populated.
2015-08-19 12:24 PM
@MaxSoc Using Investigation to narrow down the events, not all of the password changes are being tagged with reference.id = 4723, so I'm not sure that this would help out much. Thanks, though!
2015-08-20 09:12 AM
So I finally actually tested the parser with dummy data
The fault was a silly error on my part. I've edited the post above to correct it, as well as "account.modified" -> "account:modified".
2015-08-20 09:14 AM
Forgot to add:
For a parser like this which is only looking at meta generated by other content rather than looking directly at packets or logs itself - packet vs. log decoder doesn't matter. It will work on either.
Your steps for deploying it are exactly correct.