Search K
Appearance
Appearance
ruid
: The real user ID denotes the user who initiated the process.euid
: Known as the effective user ID, it represents the user identity utilized by the system to ascertain process privileges. Generally, euid
mirrors ruid
, barring instances like a SetUID binary execution, where euid
assumes the file owner's identity, thus granting specific operational permissions.suid
: This saved user ID is pivotal when a high-privilege process (typically running as root) needs to temporarily relinquish its privileges to perform certain tasks, only to later reclaim its initial elevated status.A process not operating under root can only modify its euid
to match the current ruid
, euid
, or suid
.
setuid
: Contrary to initial assumptions, setuid
primarily modifies euid
rather than ruid
. Specifically, for privileged processes, it aligns ruid
, euid
, and suid
with the specified user, often root, effectively solidifying these IDs due to the overriding suid
. Detailed insights can be found in the setuid man page.setreuid
and setresuid
: These functions allow for the nuanced adjustment of ruid
, euid
, and suid
. However, their capabilities are contingent on the process's privilege level. For non-root processes, modifications are restricted to the current values of ruid
, euid
, and suid
. In contrast, root processes or those with CAP_SETUID
capability can assign arbitrary values to these IDs. More information can be gleaned from the setresuid man page and the setreuid man page.These functionalities are designed not as a security mechanism but to facilitate the intended operational flow, such as when a program adopts another user's identity by altering its effective user ID.
Notably, while setuid
might be a common go-to for privilege elevation to root (since it aligns all IDs to root), differentiating between these functions is crucial for understanding and manipulating user ID behaviors in varying scenarios.
execve
System Call โexecve
initiates a program, determined by the first argument. It takes two array arguments, argv
for arguments and envp
for the environment.ruid
, euid
, and supplementary group IDs remain unaltered.euid
might have nuanced changes if the new program has the SetUID bit set.suid
gets updated from euid
post-execution.execve
man page.system
Function โexecve
, system
creates a child process using fork
and executes a command within that child process using execl
.sh
with execl("/bin/sh", "sh", "-c", command, (char *) NULL);
.execl
is a form of execve
, it operates similarly but in the context of a new child process.system
man page.bash
and sh
with SUID โbash
: -p
option influencing how euid
and ruid
are treated.-p
, bash
sets euid
to ruid
if they initially differ.-p
, the initial euid
is preserved.bash
man page.sh
: -p
in bash
.-i
option, emphasizing the preservation of euid
and ruid
equality.sh
man page.These mechanisms, distinct in their operation, offer a versatile range of options for executing and transitioning between programs, with specific nuances in how user IDs are managed and preserved.
Examples taken from https://0xdf.gitlab.io/2022/05/31/setuid-rabbithole.html#testing-on-jail, check it for further information
setuid
with system
โObjective: Understanding the effect of setuid
in combination with system
and bash
as sh
.
C Code:
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
int main(void) {
setuid(1000);
system("id");
return 0;
}
Compilation and Permissions:
oxdf@hacky$ gcc a.c -o /mnt/nfsshare/a;
oxdf@hacky$ chmod 4755 /mnt/nfsshare/a
bash-4.2$ $ ./a
uid=99(nobody) gid=99(nobody) groups=99(nobody) context=system_u:system_r:unconfined_service_t:s0
Analysis:
ruid
and euid
start as 99 (nobody) and 1000 (frank) respectively.setuid
aligns both to 1000.system
executes /bin/bash -c id
due to the symlink from sh to bash.bash
, without -p
, adjusts euid
to match ruid
, resulting in both being 99 (nobody).C Code:
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
int main(void) {
setreuid(1000, 1000);
system("id");
return 0;
}
Compilation and Permissions:
oxdf@hacky$ gcc b.c -o /mnt/nfsshare/b; chmod 4755 /mnt/nfsshare/b
Execution and Result:
bash-4.2$ $ ./b
uid=1000(frank) gid=99(nobody) groups=99(nobody) context=system_u:system_r:unconfined_service_t:s0
Analysis:
setreuid
sets both ruid and euid to 1000.system
invokes bash, which maintains the user IDs due to their equality, effectively operating as frank.Objective: Exploring the interaction between setuid and execve.
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
int main(void) {
setuid(1000);
execve("/usr/bin/id", NULL, NULL);
return 0;
}
Execution and Result:
bash-4.2$ $ ./c
uid=99(nobody) gid=99(nobody) euid=1000(frank) groups=99(nobody) context=system_u:system_r:unconfined_service_t:s0
Analysis:
ruid
remains 99, but euid is set to 1000, in line with setuid's effect.C Code Example 2 (Calling Bash):
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
int main(void) {
setuid(1000);
execve("/bin/bash", NULL, NULL);
return 0;
}
Execution and Result:
bash-4.2$ $ ./d
bash-4.2$ $ id
uid=99(nobody) gid=99(nobody) groups=99(nobody) context=system_u:system_r:unconfined_service_t:s0
Analysis:
euid
is set to 1000 by setuid
, bash
resets euid to ruid
(99) due to the absence of -p
.C Code Example 3 (Using bash -p):
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
int main(void) {
char *const paramList[10] = {"/bin/bash", "-p", NULL};
setuid(1000);
execve(paramList[0], paramList, NULL);
return 0;
}
Execution and Result:
bash-4.2$ $ ./e
bash-4.2$ $ id
uid=99(nobody) gid=99(nobody) euid=100