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

Use execl instead of popen in RADIUS NSS code to fix vulnerability. #15512

Merged
merged 9 commits into from
Aug 7, 2023

Conversation

shdasari
Copy link
Contributor

Why I did it

#15284 fixes a case of shell escape exploit for TACACS+. This applies to RADIUS as well. RADIUS creates an unconfirmed user locally on the switch while attempting authentication. popen() is used to execute useradd,usermod and userdel commands. This exposes a vulnerability where a tactically designed username (which could contain explicit linux commands) can lead to getting executed as root.

An example of such a username could be "asd";echo>remoteRCE2;#". This leads to remoteRCE2 getting created in "/".

Work item tracking
  • Microsoft ADO (number only):

How I did it

All calls to popen() used to execute useradd, usermod and userdel are replaced with fork()/execl().

How to verify it

Prior to the fix, following is the behavior:

[s@i vm] ssh "asd";echo>remoteRCE2;#"@1.1.1.1
asd";echo>remoteRCE2;#@1.1.1.1's password:
Permission denied, please try again.

On the SONiC switch,

root@sonic:/# ls
accton_as7816_monitor.log home lib64 remoteRCE2 sys
bin host libx32 root tmp
boot initrd.img media run usr
cache.tgz initrd.img.old mnt sbin var
dev lib opt sonic vmlinuz
etc lib32 proc srv vmlinuz.old
root@sonic:/# ls -l

With the fix:

[s@i vm] ssh "asd";echo>remoteRCE2;#"@1.1.1.1
asd";echo>remoteRCE2;#@1.1.1.1's password:
Permission denied, please try again.

root@sonic:/# ls
accton_as7816_monitor.log etc lib mnt sbin usr
bin home lib32 opt sonic var
boot host lib64 proc srv vmlinuz
cache.tgz initrd.img libx32 root sys vmlinuz.old
dev initrd.img.old media run tmp

Verified that RADIUS authentication works as expected for valid users as well.

@a-barboza
Copy link
Contributor

Why I did it

#15284 fixes a case of shell escape exploit for TACACS+. This applies to RADIUS as well. RADIUS creates an unconfirmed user locally on the switch while attempting authentication. popen() is used to execute useradd,usermod and userdel commands. This exposes a vulnerability where a tactically designed username (which could contain explicit linux commands) can lead to getting executed as root.

An example of such a username could be "asd";echo>remoteRCE2;#". This leads to remoteRCE2 getting created in "/".

Work item tracking
  • Microsoft ADO (number only):

How I did it

All calls to popen() used to execute useradd, usermod and userdel are replaced with fork()/execl().

How to verify it

Prior to the fix, following is the behavior:

[s@i vm] ssh "asd";echo>remoteRCE2;#"@1.1.1.1 asd";echo>remoteRCE2;#@1.1.1.1's password: Permission denied, please try again.

On the SONiC switch,

root@sonic:/# ls accton_as7816_monitor.log home lib64 remoteRCE2 sys bin host libx32 root tmp boot initrd.img media run usr cache.tgz initrd.img.old mnt sbin var dev lib opt sonic vmlinuz etc lib32 proc srv vmlinuz.old root@sonic:/# ls -l

With the fix:

[s@i vm] ssh "asd";echo>remoteRCE2;#"@1.1.1.1 asd";echo>remoteRCE2;#@1.1.1.1's password: Permission denied, please try again.

root@sonic:/# ls accton_as7816_monitor.log etc lib mnt sbin usr bin home lib32 opt sonic var boot host lib64 proc srv vmlinuz cache.tgz initrd.img libx32 root sys vmlinuz.old dev initrd.img.old media run tmp

Verified that RADIUS authentication works as expected for valid users as well.

@adyeung @seiferteric @shdasari

The semgrep flagged failure appears to be a false +ve. The compiler cannot optimize that particular memset, since the target of the memset is modified inside the function, and returned from the function, and used else where.

I recommend merging this patch. There are some minor enhancements (replace integer constants with macros which could be done). But, I recommend merging this patch. Please let me know if anything else needs to be done from my side. thank you

@lguohan
Copy link
Collaborator

lguohan commented Jun 23, 2023

can you check the semgrep failure?

"%s -U -G %s -c \"%s\" -d \"/home/%s\" -m -s %s \"%s\"",
USERADD, rnm->groups, unconfirmed ? buf : user, user,
rnm->shell, user);
memset(buf, 0, sizeof(buf));
Copy link
Contributor

Choose a reason for hiding this comment

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

This memset seems redundant? snprintf() Man Page: "The functions snprintf() and vsnprintf() write at most size bytes (including the terminating null byte ('\0')) to str." semgrep appears to complain about it.

Copy link
Contributor

@a-barboza a-barboza left a comment

Choose a reason for hiding this comment

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

semgrep run passes.

@shdasari
Copy link
Contributor Author

shdasari commented Jul 7, 2023

/azpw run Azure.sonic-buildimage

@mssonicbld
Copy link
Collaborator

/AzurePipelines run Azure.sonic-buildimage

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@adyeung
Copy link
Collaborator

adyeung commented Jul 7, 2023

@lguohan pls check if you are ok with the vulnerability fix

@adyeung adyeung requested a review from seiferteric July 7, 2023 20:07
Copy link
Contributor

@seiferteric seiferteric left a comment

Choose a reason for hiding this comment

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

Added a couple minor comments, but otherwise looks good to me.

@@ -167,6 +168,109 @@ static void init_rnm(RADIUS_NSS_CONF_B * conf) {

}

static int user_add(const char* cmd, const char* name, char* gid, char* sec_grp, char* gecos,
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the purpose of accepting cmd as first argument if you have one function for each command (user_add, user_del, user_mod)?


} else if(pid == 0) {

return execl(cmd, cmd, "-G", sec_grp, "-c", name, name, NULL);
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we can add log in case of execl failure.

@lguohan
Copy link
Collaborator

lguohan commented Jul 7, 2023

@adyeung , i see some comments, as soon as eric sign off, i can get it merged.

int wstatus;
char cmd[64];

snprintf(cmd, 63, "%s", USERADD);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this needed? Or can you use USERADD etc. directly in the execl call? Secondly, looking in nss_radius_common.h (https://github.com/shdasari/sonic-buildimage/blob/radius_execl_fix/src/radius/nss/libnss-radius/nss_radius_common.h#L69) I see this:

#define USERADD "/usr/sbin/useradd"
#define USERMOD "/usr/sbin/usermod"
#define USERDEL "/usr/sbin/userdel"

...

#undef USERADD
#define USERADD "/bin/echo"
#undef USERMOD
#define USERMOD "/bin/echo"
#undef USERDEL
#define USERDEL "/bin/echo"

Why is this being done? Have you tested if it is correctly set to /usr/bin/useradd etc. instead of /bin/echo?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These changes have been tested and the user is added as expected. Note that the #define code is existing code and not added as a part of this code review. We can get rid of the defines and use the command directly however.

@lguohan lguohan enabled auto-merge (squash) August 7, 2023 16:47
@lguohan lguohan disabled auto-merge August 7, 2023 16:47
@lguohan lguohan merged commit d9393b0 into sonic-net:master Aug 7, 2023

} else {
snprintf(buf, sizeof(buf), "Unconfirmed-%ld", time(NULL));

Choose a reason for hiding this comment

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

Shouldn't we use sizeof(buf)-1 to leave a null termination place for the buf?

sonic-otn pushed a commit to sonic-otn/sonic-buildimage that referenced this pull request Sep 20, 2023
…ability. (sonic-net#15512)

Why I did it
sonic-net#15284 fixes a case of shell escape exploit for TACACS+. This applies to RADIUS as well. RADIUS creates an unconfirmed user locally on the switch while attempting authentication. popen() is used to execute useradd,usermod and userdel commands. This exposes a vulnerability where a tactically designed username (which could contain explicit linux commands) can lead to getting executed as root.

An example of such a username could be "asd";echo>remoteRCE2;#". This leads to remoteRCE2 getting created in "/".

How I did it
All calls to popen() used to execute useradd, usermod and userdel are replaced with fork()/execl().

How to verify it
Prior to the fix, following is the behavior:

[s@i vm] ssh "asd";echo>remoteRCE2;#"@1.1.1.1
asd";echo>remoteRCE2;#@1.1.1.1's password:
Permission denied, please try again.

On the SONiC switch,

root@sonic:/# ls
accton_as7816_monitor.log home lib64 remoteRCE2 sys
bin host libx32 root tmp
boot initrd.img media run usr
cache.tgz initrd.img.old mnt sbin var
dev lib opt sonic vmlinuz
etc lib32 proc srv vmlinuz.old
root@sonic:/# ls -l

With the fix:

[s@i vm] ssh "asd";echo>remoteRCE2;#"@1.1.1.1
asd";echo>remoteRCE2;#@1.1.1.1's password:
Permission denied, please try again.

root@sonic:/# ls
accton_as7816_monitor.log etc lib mnt sbin usr
bin home lib32 opt sonic var
boot host lib64 proc srv vmlinuz
cache.tgz initrd.img libx32 root sys vmlinuz.old
dev initrd.img.old media run tmp

Verified that RADIUS authentication works as expected for valid users as well.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants