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

Useradd #18194

Merged
merged 56 commits into from
Oct 25, 2023
Merged

Useradd #18194

merged 56 commits into from
Oct 25, 2023

Conversation

rad10
Copy link
Contributor

@rad10 rad10 commented Jul 17, 2023

Vulnerable Application

This module creates a new user using the standard (or non-standard) means of
creating a new user on the victim OS. This module requires root privileges
in order to run as it needs access to /etc/shadow.

Tested Versions

  • Debian 11.7
  • Alpine 3.17
  • Fedora 37

Verification Steps

  1. Start msfconsole
  2. Get a Meterpreter session
  3. use post/linux/manage/adduser
  4. set session <id>
  5. attempt to log in with account

Options

USERNAME

Provide the username that can be used. Linux has a standardization that means
that password have to follow this regex to be able to be used as a username
^[a-z][a-z0-9_-]{0,31}$

PASSWORD

Provides a password for your new user.

SHELL

Define the shell that is to be used. Defaults to /bin/sh but can be changed
to a shell that exists.

HOME

Speficy the home directory of the new user. An empty value specifies that the
home directory does not exist.

GROUPS

Specify what groups the new user should be under. Takes one or multiple values
to provide what groups the new user will have.

Advanced Options

SudoMethod

Sets the method that the new user will get root access. This can be done
through multiple methods provided below:

  • GROUP - Put the new user in the sudo group (is added automatically to
    the groups option)
  • SUDO_FILE - Adds user directly to /etc/sudoers file in order to
    prevent being removed from sudoers group
  • NONE - No sudo methods are provided. New user is a unprivileged user

UseraddBinary

Set the binary used to add the user. The two main binaries concerned with are
useradd and adduser. If you want to overwrite which binary is used or give
an absolute path rather than a relative path, you can override it here. Or you
can set it to MANUAL to make the module skip using a binary entirely and edit
/etc/passwd directly.

MissingGroups

This option decides how to manage groups requested that are missing on the victim.
The possible options are provided as such:

  • ERROR - If a group is missing, fail the module with a given error
  • IGNORE - If the group doesnt exist, continue to add the user, but dont add
    them to the missing groups
  • CREATE - If the group doesnt exist, then make them first then add the user
    to them

Scenarios

msf6 > use post/linux/manage/adduser
msf6 post(linux/manage/adduser) > set session 6 
session => 6
msf6 post(linux/manage/adduser) > set sudomethod GROUP 
sudomethod => GROUP
msf6 post(linux/manage/adduser) > set groups wheel docker wireshark
groups => wheel docker wireshark
msf6 post(linux/manage/adduser) > set username metasploit
username => metasploit
msf6 post(linux/manage/adduser) > set password abcd1234
password => abcd1234
msf6 post(linux/manage/adduser) > set shell /bin/bash
shell => /bin/bash
msf6 post(linux/manage/adduser) > set home /home/metasploit
home => /home/metasploit
msf6 post(linux/manage/adduser) > set missinggroups CREATE 
missinggroups => CREATE
msf6 post(linux/manage/adduser) > set verbose true 
verbose => true
msf6 post(linux/manage/adduser) > run

[-] Groups [docker] do not exist on system
[*] Running on Debian 11.7 (Linux 5.10.0-23-amd64)
[*] Useradd exists. Using that
[*] groupadd docker
[*] 
[+] Added docker group
[*] useradd --password $1$WDX5Sg4N$Hcfx4HSigx/KbvtSzhsXD/ --home-dir /home/metasploit --groups wheel,docker,wireshark,sudo --shell /bin/bash --no-log-init metasploit
[*] 
[*] Post module execution completed
msf6 post(linux/manage/adduser) > run

[*] Running on Debian 11.7 (Linux 5.10.0-23-amd64)
[*] Useradd exists. Using that
[*] useradd --password $1$EVUDKEc3$Sip80MAZmLv.2vOhzW/4k0 --home-dir /home/metasploit --groups wheel,docker,wireshark,sudo --shell /bin/bash --no-log-init metasploit
[*] useradd: user 'metasploit' already exists
[*] Post module execution completed

@Op3n4M3
Copy link

Op3n4M3 commented Jul 17, 2023

This functionality seems interesting.

Probably more of a future enhancement idea thinking about what is does and what already exist in Framework, I wonder if it would be helpful to have a generic payload launch post module that support reuse of #18002 in some way? Or does that seem like it would to hard to discover and use? It seems like shell_to_meterpreter's PAYLOAD_OVERRIDE option may be the closest thing to the idea that already exists, however the name for that modules does not intuitively suggest executing a non-meterpreter payload and post modules do not have access to set payload options at this time.

@rad10
Copy link
Contributor Author

rad10 commented Jul 18, 2023

This functionality seems interesting.

Probably more of a future enhancement idea thinking about what is does and what already exist in Framework, I wonder if it would be helpful to have a generic payload launch post module that support reuse of #18002 in some way? Or does that seem like it would to hard to discover and use? It seems like shell_to_meterpreter's PAYLOAD_OVERRIDE option may be the closest thing to the idea that already exists, however the name for that modules does not intuitively suggest executing a non-meterpreter payload and post modules do not have access to set payload options at this time.

I whole heartedly agree that a means to launch a payload onto an already existing session should exits rather than a somewhat nonintuitive generate -> exploit -z -> session -i ? -c and that needs to happen. Thinking that the payload is enough however is not good enough. I made that payload, and it was designed to complete the task in the smallest form possible. This means that its dirty and obvious. That payload puts the new users password in /etc/passwd which to any administrator checking on files once in a while is going to see a very obvious intrusion. The payload is perfect for quick and dirty means of entry, but for adding in backdoors and hiding them, this module is far better suited for it as users added use the standard means of adding users meaning a far less suspicious insertion.

modules/post/linux/manage/adduser.rb Outdated Show resolved Hide resolved
modules/post/linux/manage/adduser.rb Outdated Show resolved Hide resolved
modules/post/linux/manage/adduser.rb Outdated Show resolved Hide resolved
modules/post/linux/manage/adduser.rb Outdated Show resolved Hide resolved
@rad10 rad10 requested a review from adfoster-r7 July 24, 2023 15:31
@rad10
Copy link
Contributor Author

rad10 commented Jul 29, 2023

All suggestions should be finished, Anything else before we are clear to land?

@cdelafuente-r7 cdelafuente-r7 self-assigned this Jul 31, 2023
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 for adding this module @rad10. I left some comments and suggestions for you to review when you get a chance.

Would it be possible to break down the run method in smaller methods with descriptive names? This would make the code easier to read and help any future maintenance.

modules/post/linux/manage/adduser.rb Outdated Show resolved Hide resolved
modules/post/linux/manage/adduser.rb Outdated Show resolved Hide resolved
modules/post/linux/manage/adduser.rb Outdated Show resolved Hide resolved
modules/post/linux/manage/adduser.rb Outdated Show resolved Hide resolved
modules/post/linux/manage/adduser.rb Show resolved Hide resolved
modules/post/linux/manage/adduser.rb Outdated Show resolved Hide resolved
modules/post/linux/manage/adduser.rb Outdated Show resolved Hide resolved
modules/post/linux/manage/adduser.rb Outdated Show resolved Hide resolved
modules/post/linux/manage/adduser.rb Outdated Show resolved Hide resolved
modules/post/linux/manage/adduser.rb Outdated Show resolved Hide resolved
@cdelafuente-r7
Copy link
Contributor

Hi @rad10, thanks for these updates. I'm just checking in, do you plan to push more changes? I noticed there are still a few pending comments.

@rad10
Copy link
Contributor Author

rad10 commented Sep 23, 2023

Hi @rad10, thanks for these updates. I'm just checking in, do you plan to push more changes? I noticed there are still a few pending comments.

So, I can put in more changes. I just noticed just how much is having to be done in order to have it work as I planned.

I am still working on it. In fact, I am taking a completely new approach and starting nearly from scratch. My terrifying plan is to build the post module to imitate all the actions that useradd does from a source level. I am rebuilding the module based on the source from the shadow package. I've already gotten groups and getting the correct GID finished. I just need to finish up UID and a few other aspects and create some new checks. The idea of this round is that not a single shell command should be run and it should use only the base linux files in the same manner shadow does.

If there is any advice to give, or even sympathies for having to read the shadow source code. I'll take them as soon as possible. I'm hoping to have this finished by the middle of october however at the very most

@rad10
Copy link
Contributor Author

rad10 commented Oct 16, 2023

So I have been looking at the source code for a long while now, and I now realize that... This thing will be at best a nightmare to put into a module and at worst impossible to do. This mainly stems from how many ways that a user can be added to a system. You can send it in through PAM, you can write it to /etc/passwd, you can add the change to the audit log, you can utilize tcb (Dont really know what that is at all, but its entirely separate from the users). Now labeling all of this should be easier, but migrating this over becomes impossible because these options are baked into the binary and I cannot find an external file that ensures/guarantees whether a given route is used or not. Because of this were back to the binary fiasco.

Theres no clean way of implementing this by following the source code. I could keep it as simple as possible and only interact with /etc/passwd, /etc/shadow, and /etc/group, but this module will fail on any system with strict policies on adding users and it will not follow defaults set by the system. We can keep with the jank that this modules is currently setup as which will ensure that the user is added how the system likes, or I can attempt to have it all done with the filesystem.

Which would be preferred?

@cdelafuente-r7
Copy link
Contributor

Hi @rad10 , thank you for looking into this. I understand it is getting very complex, almost impossible to cover every user cases. I believe your first idea/implementation was good enough for now. This can still be improved later, if the need to do so arises.
Please, let me know when you think it is ready and I'll have a look.

@rad10
Copy link
Contributor Author

rad10 commented Oct 24, 2023

Hi @rad10 , thank you for looking into this. I understand it is getting very complex, almost impossible to cover every user cases. I believe your first idea/implementation was good enough for now. This can still be improved later, if the need to do so arises. Please, let me know when you think it is ready and I'll have a look.

In that case, yes. This module is ready to go. It should cover all of the bases given. I tested using containers and vms.

@cdelafuente-r7
Copy link
Contributor

cdelafuente-r7 commented Oct 25, 2023

Sure! It looks good to me. I retested and it works as expected. I just added a last minute commit to fix some typos. Thank you again for your contribution!

  • Example output
msf6 post(linux/manage/adduser) > run verbose=true session=2 username=test1 groups=foo MissingGroups=CREATE

[!] Groups [foo] do not exist on system
[*] groupadd foo

[+] Added foo group
[*] Running on Linux 6.2.0-33-generic #33~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Thu Sep  7 10:33:52 UTC 2
[*] Useradd exists. Using that
[*] useradd --password '$1$8L8sccqA$xuemoWa316iD0Fz4C986y1' --no-create-home --groups foo,sudo --shell /bin/sh --no-log-init test1

[*] Post module execution completed

@cdelafuente-r7 cdelafuente-r7 added the rn-modules release notes for new or majorly enhanced modules label Oct 25, 2023
cdelafuente-r7 added a commit that referenced this pull request Oct 25, 2023
@cdelafuente-r7 cdelafuente-r7 merged commit e026791 into rapid7:master Oct 25, 2023
3 checks passed
@cdelafuente-r7
Copy link
Contributor

Release Notes

This adds a post module that creates a new user on the target OS. It tries to use standard tools already available on the system, but it's also able to directly updates the plaintext database files (/etc/passwd and `/etc/shadow). This module requires root privileges.

@rad10 rad10 deleted the useradd branch October 26, 2023 17:00
@rad10 rad10 restored the useradd branch October 26, 2023 17:00
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