Author Topic: 31C3 CTF: rilettura labirinto  (Read 285 times)

0 Members and 1 Guest are viewing this topic.

Offline Flavio58

31C3 CTF: rilettura labirinto
« Reply #1 on: May 21, 2018, 01:36:45 PM »
Advertisement








Questo è il mio articolo per la sfida del labirinto nel CTC 31C3, che ho giocato con il team di Hacking For Soju. Abbiamo "solo" ottenuto il 10 ° posto (su 286 squadre che hanno segnato punti), ma considerando che solo io, capl e avlidienbrunn abbiamo avuto il tempo di spendere del tempo (e sono riuscito a segnare 170 delle 340 punti, che mi avrebbero dato il posto # 33 se avessi giocato da solo), non era troppo malandato! :) Se non fossi stato così assonnato / spento durante grandi parti del CTF, probabilmente sarei stato in grado di guadagnare un po 'di più. Saluta per il brainstorming sui potenziali scenari ROP btw!

http://www.clevcode.org/31c3-ctf-maze-write-up/

Per rendere questo articolo più utile per le persone che vogliono imparare, ho cercato di renderlo abbastanza dettagliato.

Le informazioni per la sfida erano:

Le informazioni per la sfida erano:


Where do you want to go (today)?

nc 188.40.18.71 1234

maze_6a865c7769f331be0666c5c7dccbba9b.tar.gz

Where do you want to go (today)?
 
nc 188.40.18.71 1234
 
maze_6a865c7769f331be0666c5c7dccbba9b.tar.gz
Il file tar.gz fornito conteneva il binario per la sfida: labirinto

Per eseguirlo come processo del server sul proprio sistema, è possibile utilizzare il seguente comando:


socat tcp-listen:1234,reuseaddr,fork exec:./maze
1
socat tcp-listen:1234,reuseaddr,fork exec:./maze
Quando ci si collega alla destinazione, viene visualizzato il seguente messaggio:


You wake up and have a big headache.
You are in a dead end, you can only go east. Where do you want to go (today)?
1
2
You wake up and have a big headache.
You are in a dead end, you can only go east. Where do you want to go (today)?
Dal momento che il nome della sfida è "labirinto" e ci viene presentato un messaggio che afferma che possiamo andare solo verso est, gli input validi sono presumibilmente est, ovest, nord e sud, e dovremmo navigare attraverso un labirinto in per raggiungere infine una sorta di obiettivo. Per capire esattamente cosa sta succedendo e per vedere se ci sono delle vulnerabilità che possiamo sfruttare lungo il percorso, il nostro prossimo passo è caricare il binario in IDA Pro e analizzare il codice. Ma prima, vediamo che tipo di protezioni sono abilitate per il binario in questione, usando checksec.sh .


Quote
je@tiny:~/31c3/pwn/maze/je$ checksec.sh --file maze
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
Partial RELRO   No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   maze

je@tiny:~/31c3/pwn/maze/je$ checksec.sh --file maze
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
Partial RELRO   No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   maze
Ti suggerisco di prendere l'abitudine di verificare quali mitigazioni degli exploit sono state abilitate per il tuo target prima di iniziare a controllarlo. Per gli obiettivi del mondo reale, questo ti darà un'idea delle precondizioni che probabilmente dovrai soddisfare per ottenere uno sfruttamento affidabile del bersaglio (cioè se sono necessarie fughe di informazioni e così via). Per le sfide CTF, può anche fornire suggerimenti su quale tipo di vulnerabilità cercare.

In questo caso, NX è abilitato, quindi probabilmente dovremo utilizzare un payload basato su ROP. PIE (Eseguibile indipendente dalla posizione) non è abilitato, quindi saremo in grado di utilizzare i gadget ROP dall'eseguibile stesso anche se ASLR è abilitato sul sistema di destinazione. Tuttavia, il file binario è piuttosto piccolo, quindi c'è probabilmente solo un numero limitato di gadget ROP adatti disponibili. I canarini di stack non sono abilitati, il che indica chiaramente che la vulnerabilità a cui prestare attenzione in questo caso è probabilmente un overflow del buffer basato su stack.

Non affidarti completamente alle informazioni che determini in questo modo. In alcuni casi (ad esempio, un CTF scarsamente organizzato), il binario in esecuzione sul target effettivo è leggermente diverso da quello fornito, oppure alcune protezioni sono state esplicitamente disabilitate / abilitate sul sistema di destinazione.

Also note that the binary is a 64-bit Linux executable. Analyzing 64-bit (x86_64, to be specific) code has recently become a lot less time consuming, due to the release of Hex-Rays x64. Hex-Rays is an excellent decompiler plugin for IDA Pro, that lets you interactively work with the decompiled code in order to make sense of it. Note that there are still corner-cases that Hex-Rays is not able to handle, especially when dealing with obfuscated code and code that has been explicitly designed in order to make static analysis difficult. If you find something strange in the decompiled code, always perform manual analysis of the assembly code in question.

Dopo il passaggio iniziale attraverso il decompilatore Hex-Rays, viene prodotto il codice mostrato di seguito (si noti che il codice irrilevante, ovvero lo stub inserito automaticamente che sta chiamando __libc_start_main () e l'inizializzazione e la pulizia del codice, è stato rimosso manualmente dal codice sorgente elenco). Durante la lettura, prova a vedere se riesci a individuare la vulnerabilità:


Code: [Select]
//-------------------------------------------------------------------------
// Function declarations

__int64 __fastcall main(__int64 a1, char **a2, char **a3);
int __fastcall sub_400CE0(unsigned int a1);
int __fastcall sub_400DD0(unsigned int a1);

//-------------------------------------------------------------------------
// Data declarations

_UNKNOWN unk_4013E0; // weak
_UNKNOWN unk_40575C; // weak
char *off_6060C0 = "You are trapped."; // weak
char *s1 = "west"; // idb
char *off_606148 = "north"; // idb
char *off_606150 = "east"; // idb
char *off_606158 = "south"; // idb
__int16 word_606171; // weak

//----- (00000000004008E0) ----------------------------------------------------
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  __int16 v3; // di@2
  _WORD *v4; // rsi@2
  unsigned int v5; // er14@2
  int v6; // ecx@2
  _UNKNOWN *v7; // rax@3
  char *v8; // rdx@7
  int v9; // er12@7
  int v10; // er13@7
  int v11; // er15@7
  int v12; // er14@7
  char *v13; // rbx@8
  char *v14; // rbx@10
  signed int v16; // eax@21
  signed int v17; // er12@23
  unsigned int v18; // [sp+Ch] [bp-64h]@1
  __int16 v19[8]; // [sp+10h] [bp-60h]@2
  char *s; // [sp+20h] [bp-50h]@8
  size_t n; // [sp+30h] [bp-40h]@19

  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  word_606171 = 257;
  puts("You wake up and have a big headache.");
  v18 = 0;
LABEL_2:
  v3 = word_606171;
  v4 = v19;
  v5 = 0;
  v6 = 0;
LABEL_3:
  while ( 2 )
  {
    *v4 = v3;
    *((_BYTE *)v4 + (v6 & 1)) += (v6 & 2) - 1;
    ++v4;
    v7 = &unk_4013E0;
    do
    {
      if ( *(v4 - 1) == *(_WORD *)v7 )
      {
        if ( ++v6 != 4 )
          goto LABEL_3;
        goto LABEL_7;
      }
      v7 = (_UNKNOWN *)((char *)v7 + 2);
    }
    while ( v7 != &unk_40575C );
    v16 = 1 << v6++;
    v5 |= v16;
    if ( v6 != 4 )
      continue;
    break;
  }
LABEL_7:
  v8 = (&off_6060C0)[8 * v5];
  v9 = v5 & 1;
  v10 = v5 & 2;
  v11 = v5 & 4;
  v12 = v5 & 8;
  __printf_chk(1LL, "%s Where do you want to go (today)? ");
  while ( 1 )
  {
    s = 0LL;
    n = 0LL;
    if ( getline(&s, &n, stdin) <= 0 )
      return 0LL;
    v13 = s;
    if ( !s || !*s )
      return 0LL;
    v13[strlen(s) - 1] = 0;
    v14 = s;
    if ( !strcasecmp(s1, s) && v9 )
    {
      v17 = 0;
LABEL_24:
      __printf_chk(1LL, "You go %s.\n");
      free(s);
      ++v18;
      word_606171 = v19[(unsigned __int64)(unsigned int)v17];
      if ( 23986 != word_606171 )
        goto LABEL_2;
      sub_400DD0(v18);
      return 0LL;
    }
    if ( !strcasecmp(off_606148, v14) && v10 )
    {
      v17 = 1;
      goto LABEL_24;
    }
    if ( !strcasecmp(off_606150, v14) && v11 )
    {
      v17 = 2;
      goto LABEL_24;
    }
    if ( !strcasecmp(off_606158, v14) && v12 )
    {
      v17 = 3;
      goto LABEL_24;
    }
    __printf_chk(1LL, "You can not go %s. Where do you want to go (today)? ");
    free(s);
  }
}

//----- (0000000000400CE0) ----------------------------------------------------
int __fastcall sub_400CE0(unsigned int a1)
{
  ssize_t v1; // rax@1
  ssize_t v2; // rbx@1
  FILE *v3; // r13@2
  char ptr; // [sp+0h] [bp-420h]@1
  _BYTE v6[7]; // [sp+1h] [bp-41Fh]@1
  char v7; // [sp+3F8h] [bp-28h]@1

  __printf_chk(1LL, "If you want, you can also add your name: ");
  memset(&ptr, 0, 0x3F8uLL);
  ptr = 10;
  v7 = 0;
  v1 = read(0, v6, 0x420uLL);
  v2 = v1;
  if ( v1 > 0 )
  {
    v1 = (ssize_t)fopen("highscore.txt", "a");
    v3 = (FILE *)v1;
    if ( v1 )
    {
      fwrite(&ptr, 1uLL, v2 + 1, (FILE *)v1);
      LODWORD(v1) = __sprintf_chk(&ptr, 1LL, 1017LL, " (%d)", a1);
      if ( (signed int)v1 > 0 )
      {
        fwrite(&ptr, 1uLL, (signed int)v1, v3);
        LODWORD(v1) = fclose(v3);
      }
    }
  }
  return v1;
}

//----- (0000000000400DD0) ----------------------------------------------------
int __fastcall sub_400DD0(unsigned int a1)
{
  FILE *v1; // r12@1
  __int64 v2; // rbx@2
  int i; // er13@2
  int v4; // er14@8
  void *v6; // rsp@13
  char ptr; // [sp+0h] [bp-40h]@3
  char v8; // [sp+Fh] [bp-31h]@13

  puts("You can see the sun!\nFinally, you are free!");
  v1 = fopen("highscore.txt", "r");
  if ( v1 )
  {
    v2 = -1LL;
    for ( i = 0; ; ++i )
    {
      v4 = i + 1;
      if ( fseek(v1, v2, 2) )
        break;
      if ( fread(&ptr, 1uLL, 1uLL, v1) != 1 )
        break;
      if ( !ptr )
        break;
      if ( ptr == 10 )
        break;
      --v2;
      if ( ptr == 13 )
        break;
    }
    if ( !fseek(v1, -i, 2) )
    {
      v6 = alloca(v4 + 15LL);
      memset((void *)((unsigned __int64)&v8 & 0xFFFFFFFFFFFFFFF0LL), 0, v4);
      if ( fread((void *)((unsigned __int64)&v8 & 0xFFFFFFFFFFFFFFF0LL), 1uLL, i, v1) )
      {
        __printf_chk(1LL, "On the wall behind you, you see a long list of names, the last one is: %s\n");
        fclose(v1);
        return sub_400CE0(a1);
      }
    }
    fclose(v1);
  }
  puts("On the wall behind you, you see a list of something, probably names.");
  return sub_400CE0(a1);
}
Code: [Select]
//-------------------------------------------------------------------------
// Function declarations
 
__int64 __fastcall main(__int64 a1, char **a2, char **a3);
int __fastcall sub_400CE0(unsigned int a1);
int __fastcall sub_400DD0(unsigned int a1);
 
//-------------------------------------------------------------------------
// Data declarations
 
_UNKNOWN unk_4013E0; // weak
_UNKNOWN unk_40575C; // weak
char *off_6060C0 = "You are trapped."; // weak
char *s1 = "west"; // idb
char *off_606148 = "north"; // idb
char *off_606150 = "east"; // idb
char *off_606158 = "south"; // idb
__int16 word_606171; // weak
 
//----- (00000000004008E0) ----------------------------------------------------
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  __int16 v3; // di@2
  _WORD *v4; // rsi@2
  unsigned int v5; // er14@2
  int v6; // ecx@2
  _UNKNOWN *v7; // rax@3
  char *v8; // rdx@7
  int v9; // er12@7
  int v10; // er13@7
  int v11; // er15@7
  int v12; // er14@7
  char *v13; // rbx@8
  char *v14; // rbx@10
  signed int v16; // eax@21
  signed int v17; // er12@23
  unsigned int v18; // [sp+Ch] [bp-64h]@1
  __int16 v19[8]; // [sp+10h] [bp-60h]@2
  char *s; // [sp+20h] [bp-50h]@8
  size_t n; // [sp+30h] [bp-40h]@19
 
  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  word_606171 = 257;
  puts("You wake up and have a big headache.");
  v18 = 0;
LABEL_2:
  v3 = word_606171;
  v4 = v19;
  v5 = 0;
  v6 = 0;
LABEL_3:
  while ( 2 )
  {
    *v4 = v3;
    *((_BYTE *)v4 + (v6 & 1)) += (v6 & 2) - 1;
    ++v4;
    v7 = &unk_4013E0;
    do
    {
      if ( *(v4 - 1) == *(_WORD *)v7 )
      {
        if ( ++v6 != 4 )
          goto LABEL_3;
        goto LABEL_7;
      }
      v7 = (_UNKNOWN *)((char *)v7 + 2);
    }
    while ( v7 != &unk_40575C );
    v16 = 1 << v6++;
    v5 |= v16;
    if ( v6 != 4 )
      continue;
    break;
  }
LABEL_7:
  v8 = (&off_6060C0)[8 * v5];
  v9 = v5 & 1;
  v10 = v5 & 2;
  v11 = v5 & 4;
  v12 = v5 & 8;
  __printf_chk(1LL, "%s Where do you want to go (today)? ");
  while ( 1 )
  {
    s = 0LL;
    n = 0LL;
    if ( getline(&s, &n, stdin) <= 0 )
      return 0LL;
    v13 = s;
    if ( !s || !*s )
      return 0LL;
    v13[strlen(s) - 1] = 0;
    v14 = s;
    if ( !strcasecmp(s1, s) && v9 )
    {
      v17 = 0;
LABEL_24:
      __printf_chk(1LL, "You go %s.\n");
      free(s);
      ++v18;
      word_606171 = v19[(unsigned __int64)(unsigned int)v17];
      if ( 23986 != word_606171 )
        goto LABEL_2;
      sub_400DD0(v18);
      return 0LL;
    }
    if ( !strcasecmp(off_606148, v14) && v10 )
    {
      v17 = 1;
      goto LABEL_24;
    }
    if ( !strcasecmp(off_606150, v14) && v11 )
    {
      v17 = 2;
      goto LABEL_24;
    }
    if ( !strcasecmp(off_606158, v14) && v12 )
    {
      v17 = 3;
      goto LABEL_24;
    }
    __printf_chk(1LL, "You can not go %s. Where do you want to go (today)? ");
    free(s);
  }
}
 
//----- (0000000000400CE0) ----------------------------------------------------
int __fastcall sub_400CE0(unsigned int a1)
{
  ssize_t v1; // rax@1
  ssize_t v2; // rbx@1
  FILE *v3; // r13@2
  char ptr; // [sp+0h] [bp-420h]@1
  _BYTE v6[7]; // [sp+1h] [bp-41Fh]@1
  char v7; // [sp+3F8h] [bp-28h]@1
 
  __printf_chk(1LL, "If you want, you can also add your name: ");
  memset(&ptr, 0, 0x3F8uLL);
  ptr = 10;
  v7 = 0;
  v1 = read(0, v6, 0x420uLL);
  v2 = v1;
  if ( v1 > 0 )
  {
    v1 = (ssize_t)fopen("highscore.txt", "a");
    v3 = (FILE *)v1;
    if ( v1 )
    {
      fwrite(&ptr, 1uLL, v2 + 1, (FILE *)v1);
      LODWORD(v1) = __sprintf_chk(&ptr, 1LL, 1017LL, " (%d)", a1);
      if ( (signed int)v1 > 0 )
      {
        fwrite(&ptr, 1uLL, (signed int)v1, v3);
        LODWORD(v1) = fclose(v3);
      }
    }
  }
  return v1;
}
 
//----- (0000000000400DD0) ----------------------------------------------------
int __fastcall sub_400DD0(unsigned int a1)
{
  FILE *v1; // r12@1
  __int64 v2; // rbx@2
  int i; // er13@2
  int v4; // er14@8
  void *v6; // rsp@13
  char ptr; // [sp+0h] [bp-40h]@3
  char v8; // [sp+Fh] [bp-31h]@13
 
  puts("You can see the sun!\nFinally, you are free!");
  v1 = fopen("highscore.txt", "r");
  if ( v1 )
  {
    v2 = -1LL;
    for ( i = 0; ; ++i )
    {
      v4 = i + 1;
      if ( fseek(v1, v2, 2) )
        break;
      if ( fread(&ptr, 1uLL, 1uLL, v1) != 1 )
        break;
      if ( !ptr )
        break;
      if ( ptr == 10 )
        break;
      --v2;
      if ( ptr == 13 )
        break;
    }
    if ( !fseek(v1, -i, 2) )
    {
      v6 = alloca(v4 + 15LL);
      memset((void *)((unsigned __int64)&v8 & 0xFFFFFFFFFFFFFFF0LL), 0, v4);
      if ( fread((void *)((unsigned __int64)&v8 & 0xFFFFFFFFFFFFFFF0LL), 1uLL, i, v1) )
      {
        __printf_chk(1LL, "On the wall behind you, you see a long list of names, the last one is: %s\n");
        fclose(v1);
        return sub_400CE0(a1);
      }
    }
    fclose(v1);
  }
  puts("On the wall behind you, you see a list of something, probably names.");
  return sub_400CE0(a1);
}
Come puoi vedere, questo è un programma veramente piccolo e semplice, e l'uscita Hex-Rays è abbastanza leggibile così com'è. Quando lavoro con il codice in IDA, posso comunque pulire ulteriormente. Rinominare funzioni e variabili, modificare tipi e definizioni di funzioni, aggiungere commenti e correggere manualmente gli errori che sono stati fatti dall'analisi automatica del codice IDA, può rendere il codice molto più facile da capire e rendere più facile individuare vulnerabilità nel codice .

Dopo aver lavorato con il codice manualmente in IDA per un po ', finiamo con il seguente codice. Se non hai ancora trovato la vulnerabilità, cercala ancora una volta durante la lettura dell'elenco aggiornato del codice:


Code: [Select]
typedef struct
{
  unsigned char x;
  unsigned char y;
} position;

//-------------------------------------------------------------------------
// Function declarations

void __fastcall append_highscore(unsigned int num_moves);
void __fastcall reached_goal(unsigned int num_moves);

//-------------------------------------------------------------------------
// Data declarations

position winning_position = { 178u, 93u };
position maze_map[8638] = {
  ... // large array removed to make this more convenient to read
};
const char *info_text[16] =
{
  "You are trapped.",
  "You are in a dead end, you can only go west.",
  "You are in a dead end, you can only go north.",
  "You can feel a wall in the east and south.",
  "You are in a dead end, you can only go east.",
  "North and south are blocked.",
  "You can go north, oh east is also free.",
  "In the south, something is in your way.",
  "You are in a dead end, you can only go south.",
  "From somewhere comes light, you can see a wall in north and east directions.",
  "In the south is no wall, you can also go north.",
  "In the east is a wall.",
  "South and East are not blocked.",
  "Better not go north.",
  "West is blocked.",
  "You can feel no wall around you."
};
const char *west_str_ptr = "west";
const char *north_str_ptr = "north";
const char *east_str_ptr = "east";
const char *south_str_ptr = "south";
position current_position;

//----- (00000000004008E0) ----------------------------------------------------
__int64 __fastcall main(__int64 argc, char **argv, char **envp)
{
  position _current_position; // di@2
  position *adjacent_position; // rsi@2
  unsigned int valid_moves; // er14@2
  __int64 valid_moves_bitmap; // rcx@2
  position *map_iterator; // rax@3
  const char *info_text_ptr; // rdx@7
  int can_go_west; // er12@7
  int can_go_north; // er13@7
  int can_go_east; // er15@7
  int can_go_south; // er14@7
  char *_s; // rbx@8
  char *user_input; // rbx@10
  signed int move_currently_checked; // eax@21
  signed int direction; // er12@23
  unsigned int num_moves; // [sp+Ch] [bp-64h]@1
  position valid_move_map[8]; // [sp+10h] [bp-60h]@2
  char *s; // [sp+20h] [bp-50h]@8
  size_t n; // [sp+30h] [bp-40h]@19

  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  current_position.y = 1;
  current_position.x = 1;
  puts("You wake up and have a big headache.");
  num_moves = 0;
main_loop:
  _current_position = current_position;
  adjacent_position = valid_move_map;
  valid_moves = 0;
  LODWORD(valid_moves_bitmap) = 0;
check_valid_moves_loop:
  while ( 2 )
  {
    *adjacent_position = _current_position;
    *(&adjacent_position->x + (valid_moves_bitmap & 1)) += (valid_moves_bitmap & 2) - 1;
    ++adjacent_position;
    map_iterator = maze_map;
    do
    {
      if ( adjacent_position[-1] == *map_iterator )
      {
        valid_moves_bitmap = (unsigned int)(valid_moves_bitmap + 1);
        if ( (_DWORD)valid_moves_bitmap != 4 )
          goto check_valid_moves_loop;
        goto check_valid_moves_loop_finished;
      }
      ++map_iterator;
    }
    while ( map_iterator != &maze_map[sizeof(maze_map)/sizeof(maze_map[0])] );
    move_currently_checked = 1 << valid_moves_bitmap;
    valid_moves_bitmap = (unsigned int)(valid_moves_bitmap + 1);
    valid_moves |= move_currently_checked;
    if ( (_DWORD)valid_moves_bitmap != 4 )
      continue;
    break;
  }
check_valid_moves_loop_finished:
  info_text_ptr = info_text[(unsigned __int64)valid_moves];
  can_go_west = valid_moves & 1;
  can_go_north = valid_moves & 2;
  can_go_east = valid_moves & 4;
  can_go_south = valid_moves & 8;
  __printf_chk(1LL, "%s Where do you want to go (today)? ", info_text_ptr, valid_moves_bitmap);
  while ( 1 )
  {
    s = 0LL;
    n = 0LL;
    if ( getline(&s, &n, stdin) <= 0 )
      return 0LL;
    _s = s;
    if ( !s || !*s )
      return 0LL;
    _s[strlen(s) - 1] = 0;
    user_input = s;
    if ( !strcasecmp(west_str_ptr, s) && can_go_west )
    {
      direction = 0;
make_move:
      __printf_chk(1LL, "You go %s.\n", user_input);
      free(s);
      ++num_moves;
      current_position = valid_move_map[direction];
      if ( winning_position != current_position )
        goto main_loop;
      reached_goal(num_moves);
      return 0LL;
    }
    if ( !strcasecmp(north_str_ptr, user_input) && can_go_north )
    {
      direction = 1;
      goto make_move;
    }
    if ( !strcasecmp(east_str_ptr, user_input) && can_go_east )
    {
      direction = 2;
      goto make_move;
    }
    if ( !strcasecmp(south_str_ptr, user_input) && can_go_south )
    {
      direction = 3;
      goto make_move;
    }
    __printf_chk(1LL, "You can not go %s. Where do you want to go (today)? ", user_input);
    free(s);
  }
}

//----- (0000000000400CE0) ----------------------------------------------------
void __fastcall append_highscore(unsigned int num_moves)
{
  ssize_t nread; // rbx@1
  FILE *_rax; // rax@2
  FILE *fp; // r13@2
  int n; // eax@3
  char buf[1056]; // [sp+0h] [bp-420h]@1

  __printf_chk(1LL, "If you want, you can also add your name: ");
  memset(buf, 0, 1016uLL);
  buf[0] = '\n';
  buf[1016] = 0;
  nread = read(0, &buf[1], 1056uLL);
  if ( nread > 0 )
  {
    _rax = fopen("highscore.txt", "a");
    fp = _rax;
    if ( _rax )
    {
      fwrite(buf, 1uLL, nread + 1, _rax);
      n = __sprintf_chk(buf, 1LL, 1017LL, " (%d)", num_moves);
      if ( n > 0 )
      {
        fwrite(buf, 1uLL, n, fp);
        fclose(fp);
      }
    }
  }
}

//----- (0000000000400DD0) ----------------------------------------------------
void __fastcall reached_goal(unsigned int num_moves)
{
  FILE *fp; // r12@1
  __int64 offset; // rbx@2
  int i; // er13@2
  int len; // er14@8
  void *ptr; // rsp@13
  char chr; // [sp+0h] [bp-40h]@3
  unsigned __int8 last_name; // [sp+Fh] [bp-31h]@13

  puts("You can see the sun!\nFinally, you are free!");
  fp = fopen("highscore.txt", "r");
  if ( fp )
  {
    offset = -1LL;
    for ( i = 0; ; ++i )
    {
      len = i + 1;
      if ( fseek(fp, offset, 2) )
        break;
      if ( fread(&chr, 1uLL, 1uLL, fp) != 1 )
        break;
      if ( !chr )
        break;
      if ( chr == '\n' )
        break;
      --offset;
      if ( chr == '\r' )
        break;
    }
    if ( !fseek(fp, -i, 2) )
    {
      // allocating a temporary buffer on the stack
      ptr = alloca(len + 15LL);
      // hexrays is not able to show this correctly :P
      // it uses the buffer that is allocated on the stack,
      // and aligns it to a 16-byte boundary.
      memset((void *)((unsigned __int64)&last_name & 0xFFFFFFFFFFFFFFF0LL), 0, len);
      if ( fread((void *)((unsigned __int64)&last_name & 0xFFFFFFFFFFFFFFF0LL), 1uLL, i, fp) )
      {
        __printf_chk(
          1LL,
          "On the wall behind you, you see a long list of names, the last one is: %s\n",
          (unsigned __int64)&last_name & 0xFFFFFFFFFFFFFFF0LL);
        fclose(fp);
        goto do_append;
      }
    }
    fclose(fp);
  }
  puts("On the wall behind you, you see a list of something, probably names.");
do_append:
  append_highscore(num_moves);
}
Code: [Select]
typedef struct
{
  unsigned char x;
  unsigned char y;
} position;
 
//-------------------------------------------------------------------------
// Function declarations
 
void __fastcall append_highscore(unsigned int num_moves);
void __fastcall reached_goal(unsigned int num_moves);
 
//-------------------------------------------------------------------------
// Data declarations
 
position winning_position = { 178u, 93u };
position maze_map[8638] = {
  ... // large array removed to make this more convenient to read
};
const char *info_text[16] =
{
  "You are trapped.",
  "You are in a dead end, you can only go west.",
  "You are in a dead end, you can only go north.",
  "You can feel a wall in the east and south.",
  "You are in a dead end, you can only go east.",
  "North and south are blocked.",
  "You can go north, oh east is also free.",
  "In the south, something is in your way.",
  "You are in a dead end, you can only go south.",
  "From somewhere comes light, you can see a wall in north and east directions.",
  "In the south is no wall, you can also go north.",
  "In the east is a wall.",
  "South and East are not blocked.",
  "Better not go north.",
  "West is blocked.",
  "You can feel no wall around you."
};
const char *west_str_ptr = "west";
const char *north_str_ptr = "north";
const char *east_str_ptr = "east";
const char *south_str_ptr = "south";
position current_position;
 
//----- (00000000004008E0) ----------------------------------------------------
__int64 __fastcall main(__int64 argc, char **argv, char **envp)
{
  position _current_position; // di@2
  position *adjacent_position; // rsi@2
  unsigned int valid_moves; // er14@2
  __int64 valid_moves_bitmap; // rcx@2
  position *map_iterator; // rax@3
  const char *info_text_ptr; // rdx@7
  int can_go_west; // er12@7
  int can_go_north; // er13@7
  int can_go_east; // er15@7
  int can_go_south; // er14@7
  char *_s; // rbx@8
  char *user_input; // rbx@10
  signed int move_currently_checked; // eax@21
  signed int direction; // er12@23
  unsigned int num_moves; // [sp+Ch] [bp-64h]@1
  position valid_move_map[8]; // [sp+10h] [bp-60h]@2
  char *s; // [sp+20h] [bp-50h]@8
  size_t n; // [sp+30h] [bp-40h]@19
 
  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  current_position.y = 1;
  current_position.x = 1;
  puts("You wake up and have a big headache.");
  num_moves = 0;
main_loop:
  _current_position = current_position;
  adjacent_position = valid_move_map;
  valid_moves = 0;
  LODWORD(valid_moves_bitmap) = 0;
check_valid_moves_loop:
  while ( 2 )
  {
    *adjacent_position = _current_position;
    *(&adjacent_position->x + (valid_moves_bitmap & 1)) += (valid_moves_bitmap & 2) - 1;
    ++adjacent_position;
    map_iterator = maze_map;
    do
    {
      if ( adjacent_position[-1] == *map_iterator )
      {
        valid_moves_bitmap = (unsigned int)(valid_moves_bitmap + 1);
        if ( (_DWORD)valid_moves_bitmap != 4 )
          goto check_valid_moves_loop;
        goto check_valid_moves_loop_finished;
      }
      ++map_iterator;
    }
    while ( map_iterator != &maze_map[sizeof(maze_map)/sizeof(maze_map[0])] );
    move_currently_checked = 1 << valid_moves_bitmap;
    valid_moves_bitmap = (unsigned int)(valid_moves_bitmap + 1);
    valid_moves |= move_currently_checked;
    if ( (_DWORD)valid_moves_bitmap != 4 )
      continue;
    break;
  }
check_valid_moves_loop_finished:
  info_text_ptr = info_text[(unsigned __int64)valid_moves];
  can_go_west = valid_moves & 1;
  can_go_north = valid_moves & 2;
  can_go_east = valid_moves & 4;
  can_go_south = valid_moves & 8;
  __printf_chk(1LL, "%s Where do you want to go (today)? ", info_text_ptr, valid_moves_bitmap);
  while ( 1 )
  {
    s = 0LL;
    n = 0LL;
    if ( getline(&s, &n, stdin) <= 0 )
      return 0LL;
    _s = s;
    if ( !s || !*s )
      return 0LL;
    _s[strlen(s) - 1] = 0;
    user_input = s;
    if ( !strcasecmp(west_str_ptr, s) && can_go_west )
    {
      direction = 0;
make_move:
      __printf_chk(1LL, "You go %s.\n", user_input);
      free(s);
      ++num_moves;
      current_position = valid_move_map[direction];
      if ( winning_position != current_position )
        goto main_loop;
      reached_goal(num_moves);
      return 0LL;
    }
    if ( !strcasecmp(north_str_ptr, user_input) && can_go_north )
    {
      direction = 1;
      goto make_move;
    }
    if ( !strcasecmp(east_str_ptr, user_input) && can_go_east )
    {
      direction = 2;
      goto make_move;
    }
    if ( !strcasecmp(south_str_ptr, user_input) && can_go_south )
    {
      direction = 3;
      goto make_move;
    }
    __printf_chk(1LL, "You can not go %s. Where do you want to go (today)? ", user_input);
    free(s);
  }
}
 
//----- (0000000000400CE0) ----------------------------------------------------
void __fastcall append_highscore(unsigned int num_moves)
{
  ssize_t nread; // rbx@1
  FILE *_rax; // rax@2
  FILE *fp; // r13@2
  int n; // eax@3
  char buf[1056]; // [sp+0h] [bp-420h]@1
 
  __printf_chk(1LL, "If you want, you can also add your name: ");
  memset(buf, 0, 1016uLL);
  buf[0] = '\n';
  buf[1016] = 0;
  nread = read(0, &buf[1], 1056uLL);
  if ( nread > 0 )
  {
    _rax = fopen("highscore.txt", "a");
    fp = _rax;
    if ( _rax )
    {
      fwrite(buf, 1uLL, nread + 1, _rax);
      n = __sprintf_chk(buf, 1LL, 1017LL, " (%d)", num_moves);
      if ( n > 0 )
      {
        fwrite(buf, 1uLL, n, fp);
        fclose(fp);
      }
    }
  }
}
 
//----- (0000000000400DD0) ----------------------------------------------------
void __fastcall reached_goal(unsigned int num_moves)
{
  FILE *fp; // r12@1
  __int64 offset; // rbx@2
  int i; // er13@2
  int len; // er14@8
  void *ptr; // rsp@13
  char chr; // [sp+0h] [bp-40h]@3
  unsigned __int8 last_name; // [sp+Fh] [bp-31h]@13
 
  puts("You can see the sun!\nFinally, you are free!");
  fp = fopen("highscore.txt", "r");
  if ( fp )
  {
    offset = -1LL;
    for ( i = 0; ; ++i )
    {
      len = i + 1;
      if ( fseek(fp, offset, 2) )
        break;
      if ( fread(&chr, 1uLL, 1uLL, fp) != 1 )
        break;
      if ( !chr )
        break;
      if ( chr == '\n' )
        break;
      --offset;
      if ( chr == '\r' )
        break;
    }
    if ( !fseek(fp, -i, 2) )
    {
      // allocating a temporary buffer on the stack
      ptr = alloca(len + 15LL);
      // hexrays is not able to show this correctly :P
      // it uses the buffer that is allocated on the stack,
      // and aligns it to a 16-byte boundary.
      memset((void *)((unsigned __int64)&last_name & 0xFFFFFFFFFFFFFFF0LL), 0, len);
      if ( fread((void *)((unsigned __int64)&last_name & 0xFFFFFFFFFFFFFFF0LL), 1uLL, i, fp) )
      {
        __printf_chk(
          1LL,
          "On the wall behind you, you see a long list of names, the last one is: %s\n",
          (unsigned __int64)&last_name & 0xFFFFFFFFFFFFFFF0LL);
        fclose(fp);
        goto do_append;
      }
    }
    fclose(fp);
  }
  puts("On the wall behind you, you see a list of something, probably names.");
do_append:
  append_highscore(num_moves);
}
Se anche questa volta non hai trovato la vulnerabilità, devi esercitarti di più. ;) Nel codice originale, è stato facile trascurare (anche se è ancora abbastanza visibile, quando si prendono in considerazione gli offset del puntatore stack / frame nei commenti prodotti automaticamente). Nel codice revisionato, la vulnerabilità è piuttosto ovvia. Si noti come il codice decompilato nella funzione append_highscore () (originariamente, sub_400CE0) è cambiato:

Prima:

Code: [Select]
  char ptr; // [sp+0h] [bp-420h]@1
  _BYTE v6[7]; // [sp+1h] [bp-41Fh]@1
  char v7; // [sp+3F8h] [bp-28h]@1

  __printf_chk(1LL, "If you want, you can also add your name: ");
  memset(&ptr, 0, 0x3F8uLL);
  ptr = 10;
  v7 = 0;
  v1 = read(0, v6, 0x420uLL);

  char ptr; // [sp+0h] [bp-420h]@1
  _BYTE v6[7]; // [sp+1h] [bp-41Fh]@1
  char v7; // [sp+3F8h] [bp-28h]@1
 
  __printf_chk(1LL, "If you want, you can also add your name: ");
  memset(&ptr, 0, 0x3F8uLL);
  ptr = 10;
  v7 = 0;
  v1 = read(0, v6, 0x420uLL);
Dopo:


Code: [Select]
  char buf[1056]; // [sp+0h] [bp-420h]@1

  __printf_chk(1LL, "If you want, you can also add your name: ");
  memset(buf, 0, 1016uLL);
  buf[0] = '\n';
  buf[1016] = 0;
  nread = read(0, &buf[1], 1056uLL);

  char buf[1056]; // [sp+0h] [bp-420h]@1
 
  __printf_chk(1LL, "If you want, you can also add your name: ");
  memset(buf, 0, 1016uLL);
  buf[0] = '\n';
  buf[1016] = 0;
  nread = read(0, &buf[1], 1056uLL);
Come si può vedere, 1056 byte vengono letti in un buffer di 1056 byte, ma inizia a leggere all'offset 1. Ciò significa che siamo in grado di sovrasfruttare il buffer con un byte. Mentre questo è ovviamente un esempio piuttosto forzato, le vulnerabilità off-by-one si trovano spesso anche in natura. I casi tipici includono persone che fanno cose come buf [sizeof (buf)] = X, o allocando spazio per le stringhe senza prendere in considerazione il byte NUL terminante.


Consulente in Informatica dal 1984

Software automazione, progettazione elettronica, computer vision, intelligenza artificiale, IoT, sicurezza informatica, tecnologie di sicurezza militare, SIGINT. 

Facebook:https://www.facebook.com/flaviobernardotti58
Twitter : https://www.twitter.com/Flavio58

Cell:  +39 366 3416556

f.bernardotti@deeplearningitalia.eu

#deeplearning #computervision #embeddedboard #iot #ai

 

Related Topics

  Subject / Started by Replies Last post
0 Replies
97 Views
Last post April 06, 2018, 01:59:29 PM
by Ruggero Respigo
0 Replies
141 Views
Last post June 26, 2018, 10:01:39 PM
by Ruggero Respigo
0 Replies
87 Views
Last post August 26, 2018, 04:02:48 PM
by Flavio58

Sitemap 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326