You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Describe the bug
If a fact defined in a Fact Source is updated, operations created using this Fact Source will be able to access the old fact value as well, thus creating multiple links (since several values "exist" for this fact).
I will include a detailed example for clarity after the simple To Reproduce part.
To Reproduce
Steps to reproduce the behavior:
Create a Fact Source, say "Test source".
Set a Fact, say "host.network.ip" with the value "192.168.1.1".
Create an operation using that Fact Source, with an Adversary that uses the fact you defined, e.g. with an Ability "Ping IP" whose only action is ping #{host.network.ip}
Everything's fine!
Update the Fact defined in the Fact Source, e.g. "10.0.0.1" instead of "192.168.1.1".
Create a new operation with the same Fact Source and same Adversary.
The Ability using that Fact is now duplicated, with both the new value and the old value for host.network.ip (2 links are created).
Expected behavior
From the documentation: Fact source: You can attach a source of facts to an operation. This means the operation will start with “pre-knowledge” of the facts, which it can use to fill in variables inside the abilities. A fact source is a collection of facts that you have grouped together. A fact source can be applied to an operation when you start it, which gives the operation facts to fill in variables with.
In the light of these lines, I expect that Caldera:
DOES use the provided Fact Source to fill in facts in links.
DOES NOT fill in facts in links when I have not provided a Fact Source, or that are not set in the Fact Source.
This means in that case, that the old Fact value(s) should not exist within the context of the operation created with the updated Fact Source (or anywhere else really). Therefore, there should only be one link generated, using the new Fact value, and we shouldn't see the previous Facts values or Facts being used at all.
Detailed example
(Bug in step 6)
Create a Fact Source, set a Fact host.network.ip with value 192.168.1.1
Create an Adversary with an Ability that uses the fact host.network.ip
Create an Operation using that Adversary and Fact Source. As expected, it uses the Fact defined in the Fact Source.
Update and save the value of the Fact in the Fact Source.
Create an Operation with the same Adversary and Fact Source. As expected, a Fact host.network.ip with the new value is added to the Operation (random print in Operation._init_source in c_operation.py)
Despite what is expected or visible in step 5, 2 values exist for the Fact host.network.ip thus 2 links are created.
The Fact Source generated by the Operation does show these 2 Facts.
Stop the server, inspect object_store. There is only one value for the Fact, and the correct one.
Boot the server, create the same Operation again. The same issue happens.
Bonus tests
If the Fact value is updated one more time, we now have 3 different values, with 1 "real" and 2 "ghosts".
If a second Fact value is added (same Fact source), we now have 4 values.
If the newly added value is deleted, we still have 4 values.
With the host.network.value removed entirely from the Fact Source, there are no Facts added in _init_source, but the 4 values still exist (even before _init_source is called).
Just to make sure, with all the parameters equal and a new empty fact source, there is no abnormal behavior, i.e. no link is generated because no Fact exists.
Conclusion
The old value for the Fact remains in memory somewhere, even though I have been unable to locate where.
It's not in the object_store (checked in Step 8).
It's not seeded in Operation._init_source (checked in Step 5).
It remains after a server reboot (checked in Step 8-9).
From the bonus tests, I assume there isn't really any way to get rid of old facts / old fact values, save for deleting the Fact Source and creating a new one, because the Facts remain somehow bound to the specific Fact Source they were created in (tested in Bonus).
I did notice that updating the Fact value in the Fact Source triggers a write operation to a yaml file in data/sources, but this file does not seem to be read in later operations (at least I didn't see it), so I'm not sure what to think of it. However, this seems to be the most promising lead at the moment.
Desktop
OS: Windows 10
Browser: Firefox 124.0.1
Server
Caldera: V5
Unbuntu Server 22.04
Additional context
This may or may not have its importance, but it looks like facts are taken (with the atomic planner) in the reverse order they were created: if the Fact had value 1, then updated to 2, then updated to 3, the links are generated with the current value first, then the old ones: 3 -> 2 -> 1
The "ghost" Facts are added with their origin_type as SEEDED, and the source being the correct yaml file in data/sources, which looks ok when reading it (i.e. only 1 Fact, or none at the end of my tests).
The text was updated successfully, but these errors were encountered:
Guil33
changed the title
Updating fact sources' facts generates duplicated facts during operations
Updating fact sources' facts generates ghost facts during operations
Mar 26, 2024
Describe the bug
If a fact defined in a Fact Source is updated, operations created using this Fact Source will be able to access the old fact value as well, thus creating multiple links (since several values "exist" for this fact).
I will include a detailed example for clarity after the simple
To Reproduce
part.To Reproduce
Steps to reproduce the behavior:
ping #{host.network.ip}
host.network.ip
(2 links are created).Expected behavior
From the documentation:
Fact source: You can attach a source of facts to an operation. This means the operation will start with “pre-knowledge” of the facts, which it can use to fill in variables inside the abilities.
A fact source is a collection of facts that you have grouped together. A fact source can be applied to an operation when you start it, which gives the operation facts to fill in variables with.
In the light of these lines, I expect that Caldera:
This means in that case, that the old Fact value(s) should not exist within the context of the operation created with the updated Fact Source (or anywhere else really). Therefore, there should only be one link generated, using the new Fact value, and we shouldn't see the previous Facts values or Facts being used at all.
Detailed example
(Bug in step 6)
host.network.ip
with value192.168.1.1
host.network.ip
host.network.ip
with the new value is added to the Operation (random print inOperation._init_source
inc_operation.py)
host.network.ip
thus 2 links are created.object_store
. There is only one value for the Fact, and the correct one.Bonus tests
host.network.value
removed entirely from the Fact Source, there are no Facts added in_init_source
, but the 4 values still exist (even before_init_source
is called).Conclusion
The old value for the Fact remains in memory somewhere, even though I have been unable to locate where.
object_store
(checked in Step 8).From the bonus tests, I assume there isn't really any way to get rid of old facts / old fact values, save for deleting the Fact Source and creating a new one, because the Facts remain somehow bound to the specific Fact Source they were created in (tested in Bonus).
I did notice that updating the Fact value in the Fact Source triggers a write operation to a yaml file in
data/sources
, but this file does not seem to be read in later operations (at least I didn't see it), so I'm not sure what to think of it. However, this seems to be the most promising lead at the moment.Desktop
Server
Additional context
atomic
planner) in the reverse order they were created: if the Fact had value1
, then updated to2
, then updated to3
, the links are generated with the current value first, then the old ones:3
->2
->1
origin_type
asSEEDED
, and thesource
being the correct yaml file indata/sources
, which looks ok when reading it (i.e. only 1 Fact, or none at the end of my tests).The text was updated successfully, but these errors were encountered: