Sovrascrivere un indirizzo di memoria

Difatti disassemblando un qualsiasi sketch per Atmega328P si trovano tra le prime operazioni compiute le seguenti:

  6c:	cf ef       	ldi	r28, 0xFF	; 255
  6e:	d8 e0       	ldi	r29, 0x08	; 8

Questo codice carica i registri r29:r28 con i valori $08:$FF
$08FF è l'indirizzo dell'ultimo byte di SRAM del microcontrollore: $08FF = 231010
(La SRAM ricordo che contiene 256 byte extra usati per mappare i suoi registri. Difatti 2047 (2 kB) + 256 dà proprio 2303)

Quindi R29:R28 formano l'SP.

non capita tutti igiorni di avere discussioni di questa corposità :slight_smile:

compliemnti lock, per me spieghi molto bene, e come al solito complimenti a leo che non perde un colpo!

NOTA: perche' l'istruzione successiva alla call addr e' PC+2 ? Perche' le istruzioni sono a 16bit, nel corpetto hardcoded ci sono 6 bit in quei primi 16, e seguono altri 16 bit di LSB addr, per un totale di 6+16=22bit di hardcoded addr, quindi in totale la call si compone di 2 parole da 16bit!

intendevi +3 o sono io che non ho capito qualcosa?

In order to access stack locations, avr-gcc will set up a 16-bit frame pointer in R29:R28 (Y) because the stack pointer (SP) cannot be used to access stack slots.

cosa vuol dire? non capisco a che serva SP a qusto punto

ahhh ok, capito! molto chiaro l'esempino, uso un sistema simile per inviare più in fretta le letture ADC (10bit) via seriale, concetenandone più di una senza sprecare i 6 bit che avanzerebbero.

Sì, è vero.
Anche l'inizializzazione iniziale completa è questa:

  6c:	cf ef       	ldi	r28, 0xFF	; 255
  6e:	d8 e0       	ldi	r29, 0x08	; 8
  70:	de bf       	out	0x3e, r29	; 62
  72:	cd bf       	out	0x3d, r28	; 61

In questi due giorni non sono stata molto bene, quindi ho perso un po' il filo. Domani credo che ritornerò ad avere la giusta concentrazione.

Una domanda al volo per vedere se ho capito bene.
Siccome l'obiettivo è fare l'exploit della memoria in modo tale che quando finisce la funzione possa puntare ad un altro punto della memoria, questa nuova locazione deve per forza far parte della flash, giusto?
Da quanto c'è scritto qui [0901.3482] Code injection attacks on harvard-architecture devices nel capitolo "The memories" potrei anche puntare ad una locazione nella program memory.
Mi sfugge qualcosa :~

La Flash è divisa in 2 aree, l'Application Flash Section e la Boot Flash Section.
Si tratta sempre di Flash, perché un micro può eseguire del codice solo se questo risiede nella Flash.

Poi c'è distinzione fra area Application e area Boot in quanto un codice eseguito nell'area Boot può scrivere in quella Application a runtime ma un codice che gira in Application non può scrivere su sé stesso.

però lo stack è sull'altra memoria, giusto?

Questo è per l'atmega128, che dovrebbe essere uguale alla 1280

memory.jpeg

Lo stack sta sempre in RAM, come tutto il resto dei dati creati a runtime (tipo heap e variabili)

Aspetta un secondo, cerco di mettere ordine.

Questa è la figura che è a pagina tre nel reply #42, giusto?

Che quindi sarebbe la Data Address Space che però è divisa dalla flash. Guarda nell'allegato.
Mi sbaglio?

Memories.jpeg

Sì, è la RAM. Che è fisicamente divisa dalla Flash.
Ora, io non conosco bene l'Atmega128 (non potendolo programmare tramite Arduino non ne ho mai studiato il datasheet) però so che può avere RAM esterna, come l'Atmega1280/2560. Non so se può avere Flash esterna, ma dal disegno che metti pare di sì. Ma non credo che possa eseguire da questa Flash esterna un programma perché vedo dallo schema che la Program Address Space è sempre quella interna.

Ma tutto questo per giungere a cosa? Cos'è che stai pensando? :wink:

Una volta fatto l'exploit volevo puntare ad una locazione di memoria dove risiede un pezzo di programma (quindi nell'applicazion code) per poterlo fare eseguire. Sempre facendo tutto passo passo.
Il passo successivo ancora è di completare l'esperimento facendo usare un pezzo di programma, ma che finisce con il ret, così l'attacco non va in crash, ma esegue il codice che desidero.
L'attacco è l'ROP (return-oriented programming).

L'idea è quella di mandare un messaggio, e qui si ricollega anche al mio codice iniziale, che possa sovrascrivere lo stack in un modo da andare ad inserire indirizzi di parti di codice che finiscano con il ret, cosicchè una volta che vorrà fare il return troverà gli indirizzi, come in questa situazione (ovviamente non con la libc):

Le slides del paper principale che parla di questo attacco sono qui: http://www.docstoc.com/docs/39341604/Return-oriented-Programming-Exploitation-without-Code-Injection

Grazie, già ce l'avevo :wink:
Anzi se sei interessato, qui (clicca) c'è proprio il paper completo

già è molto furbo e raffinato, ma anche molto complicato, soprattutto per l'atmega con l'arduino...
però sul paper che avevo linkato prima ( http://arxiv.org/abs/0901.3482 ) qualcuno l'ha fatto su un atmega128, non credo con arduino...

Riprendo questo topic perchè non ancora riesco a capire alcune cose.

Ok, questo codice funziona:

void setup ()
  {
  Serial.begin (115200);
  }  // end of setup

void bar ()
  {
  Serial.println ("hacked!");
  while (true);  
  }
  
void foo ()
  {
  Serial.println ("in foo.");
  // corrupt return address
  unsigned int * stack = (unsigned int *) SP;
  stack [1] = (unsigned int) bar;
  }
  
void loop ()
  {
  foo ();
  }  // end of loop

Ma non è quello il modo in cui volevo raggiungere printHacked().

Sto provando a mandare una stringa come input e cercare di fare il buffer overflow con quella stringa scrivendoci anche l'indirizzo di printHacked().

int  indexB  = 0;
int sb;

void setup();
void loop();
void readSerialString ();
void printHacked();


void setup(){
    unsigned long val;
    Serial.begin(115200);
    Serial.println("Hello World");
    val = (unsigned long) printHacked;
    Serial.print("Address of printHacked is "); 
    Serial.println(val,HEX); //I use it to print the address of the function
        
}

void loop(){
	readSerialString();
	Serial.println ("-");
	delay(1500);
}

void readSerialString () {
	char buffer[4];
	if(Serial.available()) {
		while (Serial.available()){
			sb = Serial.read();
			buffer[indexB] = sb;
			indexB++;
		}
	  }
        Serial.println(buffer);
        
}

void printHacked(){
	Serial.println("Hacked!");
}

Ho messo in input

ciao\xa0\x00\x00\x00

ed in output ho avuto

Hello World
Address of printHacked is A0
-

-
ciao\xa0\x00\x00CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCÿ
Hello World
Address of printHacked is A0

-

(ho cancellato tante C per accorciare il post)

E' possibile che non riesce a riconoscere \xa0\x00\x00\x00 ?
Come posso fare secondo voi per farlo riconoscere come esadecimale?

Ho provato anche a mettere "ciaocia" ed ecco l'output

Hello World
Address of printHacked is A0

-

ciaocia
è%

e si è bloccato con è%
Mentre con "ciaociao"

Hello World
Address of printHacked is A0

-

-
ciaHello World
Address of printHacked is A0

-

Però così non lo inserisco con il messaggio, giusto?

Grazie per l'aiuto!

Già inizialmente avevo provato questo metodo "bovino" (eheheh, mi piace l'espressione), ma avevo cambiato strada non avendo avuto buoni risultati.
Ora che posso condividerli con voi è tutta un'altra cosa. :slight_smile:

Il discorso che hai fatto con get() è simile al strcpy e strncpy, dove il primo non ha nessun controllo, mentre il secondo copia gli n byte passati come parametro.

char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);

Il mio codice:

char buff1[13]={'c','i','a','o','5','6',0xA7,0x00,0x00,0x00,'\0'}; //il 5 e il 6 sono per i due pop finali 

void setup(){
    unsigned long val;
    Serial.begin(115200);
    Serial.println("Hello World");
    val = (unsigned long) printHacked;
    Serial.print("Address of printHacked is "); 
    Serial.println(val,HEX); //I use it to print the address of the function
        
}

void loop(){
	readSerialString();
	Serial.println ("-");
	delay(1500);
}

void readSerialString () {
	char buff2[4];
	strcpy(buff2,buff1);
        Serial.println(buff2);
}

void printHacked(){
	Serial.println("Hacked!");
}

Ma stampa:

ciao56§

Ho fatto l'avr-objdump, questa volta mi aspettavo 6 pop, ma... ce ne sono 8!

     15c:	0f 93       	push	r16
     15e:	1f 93       	push	r17
     160:	df 93       	push	r29
     162:	cf 93       	push	r28
     164:	00 d0       	rcall	.+0      	; 0x166 <_Z16readSerialStringv+0xa>
     166:	00 d0       	rcall	.+0      	; 0x168 <_Z16readSerialStringv+0xc>
     168:	cd b7       	in	r28, 0x3d	; 61
     16a:	de b7       	in	r29, 0x3e	; 62
     16c:	8e 01       	movw	r16, r28
     16e:	0f 5f       	subi	r16, 0xFF	; 255
     170:	1f 4f       	sbci	r17, 0xFF	; 255
     172:	c8 01       	movw	r24, r16
     174:	61 e3       	ldi	r22, 0x31	; 49
     176:	72 e0       	ldi	r23, 0x02	; 2
     178:	0e 94 a0 00 	call	0x140	; 0x140 <strcpy>
     17c:	83 e7       	ldi	r24, 0x73	; 115
     17e:	94 e0       	ldi	r25, 0x04	; 4
     180:	b8 01       	movw	r22, r16
     182:	0e 94 bb 07 	call	0xf76	; 0xf76 <_ZN5Print7printlnEPKc>
     186:	0f 90       	pop	r0
     188:	0f 90       	pop	r0
     18a:	0f 90       	pop	r0
     18c:	0f 90       	pop	r0
     18e:	cf 91       	pop	r28
     190:	df 91       	pop	r29
     192:	1f 91       	pop	r17
     194:	0f 91       	pop	r16
     196:	08 95       	ret

Allora ho cambiato il buff1 in:
char buff1[13]={'c','i','a','o','5','6','7','8',0xA7,0x00,0x00,0x00,'\0'};
e sono usciti 5 caratteri stranissimi con una serie di HelloWorld consecutivi che hanno bloccato tutto fino alla chiusura forzata...

Piano piano sono andata ad aggiungere carattere per carattere e fino a
char buff1[13]={'c','i','a','o','5','6','7','8','\0'};
stampava ciao con i relativi numeri

mentre con
char buff1[13]={'c','i','a','o','5','6','7','8','9','\0'};
ha scritto qualcosa e poi ciao56789 in continuazione. Quindi effettivamente dopo gli 8 pop ha iniziato a "sclerare"

Quindi ho riprovato con
char buff1[13]={'c','i','a','o','5','6','7','8',0xA7,0x00,'\0'};
ma niente come prima...

Inizio ad avere paura che non c'è modo per uscirne...

Edit: Ho capito perchè sono 8 pop! Per colpa della print.
Fatto sta, che con print o non print ha sempre lo stesso comportamento, ossia calcolando con 6 o 8 pop.
Edit:
Ho provato anche con unsigned char* e memcpy.

DarkCoffee:

ciao56§

Cosa interessante.
Se si mette nel convertitore ASCII/Hex il valore "§" si ottiene "c2 a7"
dove a7 è proprio quello che ho inserito! Ma c2 cos'è?

Edit:
Credo proprio che ci sia un problema di lettura. Non riesce a capire il valore giusto quando è nell'array.
Ho provato una cosa simile:

int value=0xa8;
int buff[1]={'0xa8'}; //anche con int buff[1]={0xa8}
Serial.println(buff[1],HEX);
Serial.println(value,DEC);
Serial.println(value,HEX);

Output:

314
168
A8

DarkCoffee:
Ho fatto l'avr-objdump, questa volta mi aspettavo 6 pop, ma... ce ne sono 8!

Andrebbero seguiti i vari jmp e call e vedere se vengono eseguite altre push

DarkCoffee:

DarkCoffee:

ciao56§

Cosa interessante.
Se si mette nel convertitore ASCII/Hex il valore "§" si ottiene "c2 a7"
dove a7 è proprio quello che ho inserito! Ma c2 cos'è?

Edit:
Credo proprio che ci sia un problema di lettura. Non riesce a capire il valore giusto quando è nell'array.
Ho provato una cosa simile:

int value=0xa8;

int buff[1]={'0xa8'}; //anche con int buff[1]={0xa8}
Serial.println(buff[1],HEX);
Serial.println(value,DEC);
Serial.println(value,HEX);



Output:


314
168
A8

secondo me succede qualcosa di strano all'interno dell'array circolare che usa la classe Serial