Pages: 1 ... 6 7 [8]   Go Down
Author Topic: Sovrascrivere un indirizzo di memoria  (Read 4376 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Jr. Member
**
Karma: 2
Posts: 71
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Grazie, già ce l'avevo smiley-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...
« Last Edit: August 27, 2013, 07:06:01 pm by DarkCoffee » Logged

The creatures outside looked from pig to man, and from man to pig, and from pig to man again: but already it was impossible to say which was which.

Offline Offline
Jr. Member
**
Karma: 2
Posts: 71
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Ok, questo codice funziona:

Code:
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().

Code:
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
Code:
ciao\xa0\x00\x00\x00
ed in output ho avuto
Code:
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
Code:
Hello World
Address of printHacked is A0

-

ciaocia
è%
e si è bloccato con è%
Mentre con "ciaociao"
Code:
Hello World
Address of printHacked is A0

-

-
ciaHello World
Address of printHacked is A0

-

« Last Edit: August 31, 2013, 08:32:34 am by DarkCoffee » Logged

The creatures outside looked from pig to man, and from man to pig, and from pig to man again: but already it was impossible to say which was which.

Offline Offline
Edison Member
*
Karma: 11
Posts: 1489
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

possibilissimo, ti consiglio una cosa molto + bovina

char_t msg[]={'c','i', 'a', 'o', 0xca,0xfe,'\0'};

almeno escludi eventuali rogne della console.in
Logged

Offline Offline
Jr. Member
**
Karma: 2
Posts: 71
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

The creatures outside looked from pig to man, and from man to pig, and from pig to man again: but already it was impossible to say which was which.

Offline Offline
Edison Member
*
Karma: 11
Posts: 1489
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

yeppa, pero' con un po' di malizia te la giochi un attimo comoda e lontana dai casini della console.input, giusto per provare a sfondare lo stack in modo furbo per sovrascrivere la ret-addr.

Puoi definire un buffer2 locale all'interno della function di size n, e fuori dalla function un buffer1 di size (n+m), e poi copiare 1 su 2, andando a sfondare lo stack di m byte. Questo simula + o - quello che succede invocando una get(buffer).

char_t buffer1[n+m]={...};

void function()
{
char_t local_buffer2[n]={...};

copy(buffer1, local_buffer2, sizeof(buffer1)); /* m byte overflowed */

quanto poi trovi un buffer1 soddisfacente, e tutto ti torna, allora poi si pensa a come sfondare lo stack usando qualcosa che entro function() acquisca byte da una qualche sorgente
- console seriale
- scheda di rete
- etc ...

Se function() chiama copy() passandogli il buffer per indirizzo, copy fa buffer overflow in modo mirato sullo stack del chiamante che si trovera' un goloso uovo di pasqua sul suo stack nella posizione giusta per il proprio return.


UNIX: nello scenario di un login, copy simula quanto fa la gets, l'utente inserisce caratteri per la passwd che gets accomoda in un buffer di size n, se l'utente digita n+m caratteri ecco che ci sara' un overflow di m caratteri sullo stack. Nota che proprio per questo la gets e' stata riscritta in forma safe, introducendo fra gli argomenti la dimensione del buffer: safe_gets(char_t buffer[], uint32_t buffer_size)

Quote

       gets()  reads a line from stdin into the buffer pointed to by s until either a terminating newline or EOF, which it replaces with a null byte ('\0').  No
       check for buffer overrun is performed (see BUGS below).

       fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s.  Reading stops after an EOF or a new-
       line.  If a newline is read, it is stored into the buffer.  A terminating null byte ('\0') is stored after the last character in the buffer.

Quote

       char *gets(char *s);
       char *fgets(char *s, int size, FILE *stream);

Code:
BUGS
       Never use gets().  Because it is impossible to tell without knowing the data in advance how many characters gets() will read,  and  because  gets()  will
       continue  to  store  characters  past the end of the buffer, it is extremely dangerous to use.  It has been used to break computer security.  Use fgets()
       instead.
Logged

Offline Offline
Jr. Member
**
Karma: 2
Posts: 71
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.  smiley

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.
Quote
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);

Il mio codice:

Code:
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:
Code:
ciao56§

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

Code:
   
     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.
« Last Edit: September 03, 2013, 07:39:02 pm by DarkCoffee » Logged

The creatures outside looked from pig to man, and from man to pig, and from pig to man again: but already it was impossible to say which was which.

Offline Offline
Jr. Member
**
Karma: 2
Posts: 71
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


Code:
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:
Code:
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:
Code:
314
168
A8
« Last Edit: September 03, 2013, 08:59:01 pm by DarkCoffee » Logged

The creatures outside looked from pig to man, and from man to pig, and from pig to man again: but already it was impossible to say which was which.

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 313
Posts: 21624
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged


0
Offline Offline
Shannon Member
****
Karma: 117
Posts: 10106
:(){:|:&};: TOX id: fcb8e918bef08581e23f6ddf9d4dba77697c25b217bf372736ed959a95fde36df5b8c5b90fbb
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Code:
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:
Code:
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:
Code:
314
168
A8


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

my Arduino code: https://github.com/lestofante/arduinoSketch
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Offline Offline
Edison Member
*
Karma: 11
Posts: 1489
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Lo stream unsafe di una puts(char msg[]) e' fatto circa cosi'

Code:
i=0;
while (msg[i]!='\0'}
{
    putchar(msg[i]);
    i++;
}

'\0' solitamente e' tradotto con 0x00, significa EndOfString

Giocandosela bovina con la seriale potresti scriverti una uart_putchar sbolognandoti da quella roba strana che c'e' in liberia arduino. Ti basta gestire la uart tx ready, anche con un loop attivo di attesa, e poi infilare il byte msg [ i ] nel registro uart_tx, e ualla, il byte viene trasmesso!

Questo se avessimo davvero dubbi su cosa fa di strano la lib-serial, pero' probabilmente non e' colpa sua, probabilmente ci sfugge qualcosa riguardo lo stack

Abbiamo ipotizzato, sulla base del reversing di semplici function, che sfondando lo stack per sovrascrivere la ret-addr non sovrascriva anche il push di SP, esattamente come abbiamo ipotizzato che avr8 non faccia uso di stack frame, bisogna vedere se e' davvero così sempre e comunque.

Vedi quei push di r27 ed r28 prima che in quei registri venga copiato (per vie traverse, attraverso le istruzioni IN) il valore di SP ? Ecco, tu sfondando lo stack cmq li infastidisci nel momento in cui viene fatta la pop, bisogna capire di quanto, e nel caso come porvi rimedio.


Fai tre cose
1) non usare objdump, usa direttamente gcc, fai cosi', "gcc -S foo.c -o foo.s", produce un listato asm + pulito del reversing fatto da objdump
2) stampa a run time il contenuto dello stack, anche con una roba bovina come ho fatto io negli esempi per i bestio RISC a 32bit, tanto ti basta definire un array locale di size anche 1 tanto poi ne abusi per puntare i vari byte o word o longword sullo stack. Ti consiglio di definirlo uint8_t, io ho usato uint32_t perche' ho registri a 32bit, tu li hai ad 8
3) indaga un attimo quella rcall . che non mi piace nemmeno un po'

Dopo la guardo anche io, ora sono alle prese con una dannatissima flash che non vuole saperne ne di farsi riconoscere ne di farsi cancellare e riprogrammare. Purtroppo non ho alcun sistema Avr8 per indagare.
Logged

Offline Offline
Edison Member
*
Karma: 11
Posts: 1489
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Andrebbe assolutamente verificato, mi e' capitato con gcc-mips di vedere porcate simili e questa cosa mi perplime parecchio, in un modello ideale, pulito ed ordinato di function call, una function dovrebbe provvedere da se a smantellare tutto quanto infila sullo stack, eccetto il suo valore ret_value (sempre che la function non sia void -> no_ret_value) che e' a carico del chiamante.

Va chiarito!
Logged

Pages: 1 ... 6 7 [8]   Go Up
Jump to: