<!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.21">
 <META NAME="LFCATEGORY" CONTENT="Software Development">
<!-- this is used by 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 ao desenvolver uma aplica&ccedil;&atilde;o - Parte 6: 6: scripts CGI
 =LF=NUMBER: 203
 =LF=ANAME_: article203.shtml
 -->
 <TITLE>lf203, Software Development: Evitando falhas de Seguran&ccedil;a ao desenvolver uma aplica&ccedil;&atilde;o - Parte 6: 6: scripts CGI</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.code { width:80%; alignment:center; background-color:#aedbe8; border-style:none; border-width:medium; border-color:#aedbe8; padding:0.1cm ;  text-align:left }
 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" size="-1">In&iacute;cio</FONT></A> &nbsp;|&nbsp; <A class=
                 "nodec" href="../map.html"><FONT color=
                 "#DDDDDD" size="-1">Mapa</FONT></A> &nbsp;|&nbsp; <A class=
                 "nodec" href="../indice.html"><FONT color=
                 "#DDDDDD" size="-1">&Iacute;ndice</FONT></A> &nbsp;|&nbsp; <A class="nodec" href="../Search/index.shtml"><FONT color=
                 "#DDDDDD" size="-1">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 WIDTH="20%"><A class="nodec" href="../News/index.shtml"><FONT color=
           "#FFFFFF">Novidades</FONT></A> </TD>
           <TD WIDTH="5%"><FONT color="#FFFFFF">|</FONT> </TD>
           <TD WIDTH="20%"><A class="nodec" href="../Archives/index.html"><FONT color=
           "#FFFFFF">Arquivos</FONT></A> </TD>
           <TD WIDTH="5%"><FONT color="#FFFFFF">|</FONT> </TD>
           <TD WIDTH="20%"><A class="nodec" href="../Links/index.shtml"><FONT color=
           "#FFFFFF">Links</FONT></A> </TD>
           <TD WIDTH="5%"><FONT color="#FFFFFF">|</FONT> </TD>
           <TD WIDTH="20%"><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.1 --><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/November2001/article203.shtml">English</a> &nbsp;<A href="../../Castellano/November2001/article203.shtml">Castellano</a> &nbsp;<A href="../../Deutsch/November2001/article203.shtml">Deutsch</a> &nbsp;<A href="../../Francais/November2001/article203.shtml">Francais</a> &nbsp;<A href="../../Nederlands/November2001/article203.shtml">Nederlands</a> &nbsp;<A href="../../Portugues/November2001/article203.shtml">Portugues</a> &nbsp;<A href="../../Russian/November2001/article203.shtml">Russian</a> &nbsp;<A href="../../Turkce/November2001/article203.shtml">Turkce</a> &nbsp;</FONT></TD></TR></TABLE><br>
 


<!-- SSI_INFO STOP -->
<!-- 2pdaIgnoreStop -->

<!-- SHORT BIO ABOUT THE AUTHOR -->
<TABLE ALIGN=LEFT BORDER=0  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   Fr&eacute;d&eacute;ric Raynal, Christophe Blaess, Christophe Grenier <br> <small>&lt;pappy(at)users.sourceforge.net, ccb(at)club-internet.fr, grenier(at)nef.esiea.fr&gt;</small>
<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>
<!-- TRANSLATED TO pt -->
<BR><BR><I>Traduzido para Portugu&ecirc;s por:</I><BR>
Bruno Sousa <small>&lt;bruno(at)linuxfocus.org&gt;</small>
<br>
<!-- TRANSLATED TO STOP -->
<BR><i>Conte&uacute;do</i>:
<UL>
  <LI><A HREF="#203lfindex0">Servidor Web, URL e problemas de configura&ccedil;&atilde;o</A></LI>
  <LI><A HREF="#203lfindex1">Introdu&ccedil;&atilde;o (breve) como um servidor web funciona e como construir
		um URL</A></LI>
  <LI><A HREF="#203lfindex2">Configura&ccedil;&atilde;o do Apache com "SSI Server Side
    Include"</A></LI>
  <LI><A HREF="#203lfindex3">Scripts em Perl</A></LI>
  <LI><A HREF="#203lfindex4">O byte Nulo</A></LI>
  <LI><A HREF="#203lfindex5">Utilizando pipes</A></LI>
  <LI><A HREF="#203lfindex6">Avan&ccedil;o de Linha</A></LI>
  <LI><A HREF="#203lfindex7">A Backslash e a semicoluna</A></LI>
  <LI><A HREF="#203lfindex8">Utilizando um caracter " desprotegido </A></LI>
  <LI><A HREF="#203lfindex9">Escrevendo em Perl</A></LI>
  <LI><A HREF="#203lfindex10">Avisos e op&ccedil;�es defeituosas</A></LI>
  <LI><A HREF="#203lfindex11">Chamada ao open()</A></LI>
  <LI><A HREF="#203lfindex12">Filtra&ccedil;&atilde;o e protec&ccedil;&atilde;o dos dados de entrada</A></LI>
  <LI><A HREF="#203lfindex13">Scripts PHP </A></LI>
  <LI><A HREF="#203lfindex14">Conclus&atilde;o</A></LI>
  <LI><A HREF="#203lfindex15">Alguns caracteres URL codificados </A></LI>
  <LI><A HREF="#203lfindex16">Liga&ccedil;�es (Links)</A></LI>
  <LI><A HREF="#203lfindex17">O programa guestbook.cgi defeituoso</A></LI>
  <LI><A HREF="http://cgi.linuxfocus.org/cgi-bin/lftalkback?anum=203&amp;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 ao desenvolver uma aplica&ccedil;&atilde;o - Parte 6: 6: scripts CGI</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>

	Obter um ficheiro, correndo um programa a partir de uma scripts mal
	programada ... " H&aacute; mais do que uma maneira de o fazer ! "<BR><BR>
    Artigos Anteriores, desta s&eacute;rie:

    <UL><LI><A href="../January2001/article182.shtml">Evitando falhas de
			seguran&ccedil;a ao desenvolver uma aplica&ccedil;&atilde;o - Parte 1</A></LI><LI><A href="../March2001/article183.shtml">Evitando falhas de
			seguran&ccedil;a ao desenvolver uma aplica&ccedil;&atilde;o - Parte 2 : mem&oacute;ria,
			fun&ccedil;�es e a stack, e o c&oacute;digo da shell</A></LI><LI><A href="../May2001/article190.shtml">Evitando falhas de
			seguran&ccedil;a ao desenvolver uma aplica&ccedil;&atilde;o - Parte 3 : buffer
			overflows</A></LI><LI><A href="../July2001/article191.shtml">Evitando falhas de
		  seguran&ccedil;a ao desenvolver uma aplica&ccedil;&atilde;o - Parte 4 : formata&ccedil;&atilde;o de
		  strings</A></LI><LI><A href="../September2001/article198.shtml">Evitando falhas de
		  seguran&ccedil;a ao desenvolver uma aplica&ccedil;&atilde;o - Parte 5 : race
		  conditions</A></LI></UL></P>
<HR size="2" noshade align="right"><BR>
<!-- BODY OF THE ARTICLE -->


    <A NAME="203lfindex0">&nbsp;</A>
<H2>Servidor Web, URL e problemas de configura&ccedil;&atilde;o</H2>


    <A NAME="203lfindex1">&nbsp;</A>
<H3>Introdu&ccedil;&atilde;o (breve) como um servidor web funciona e como construir
		um URL</H3>


	<P>Quando um cliente pede um ficheiro HTML, o servidor envia o ficheiro
	pedido (ou uma mensagem de erro). O browser interpreta o c&oacute;digo HTML
	para formatar e apresentar o ficheiro. Por exemplo digitando o URL
	(Uniform Request Location):
<!-- we need a space in the next line otherwise it gets too long
and causes problems with printing -->
    <CODE>http://www.linuxdoc.org/HOWTO/ HOWTO-INDEX/howtos.html</CODE>
	o cliente liga-se ao servidor <CODE>www.linuxdoc.org</CODE> e pede a
	p&aacute;gina <CODE>/HOWTO/HOWTO-INDEX/howtos.html</CODE>, utilizando o
	protocolo HTTP. Se a p&aacute;gina existe o servidor envia o ficheiro pedido.
	Com este modelo <EM>est&aacute;tico</EM>, se o ficheiro est&aacute; presente no
	servidor, &eacute; enviado "tal e qual" para o cliente, caso contr&aacute;rio &eacute;
	enviada uma mensagem de erro (o bastante conhecido 404 - Not Found).<P>

    <P>Infelizmente, isto n&atilde;o permite interactividade com o utilizador,
	fazendo com que inova&ccedil;�es como o e-business, o e-reservation para
	f&eacute;rias ou o e-qualquer coisa seja imposs&iacute;vel.</P>

	<P>Felizmente, existem solu&ccedil;�es para gerar p&aacute;ginas HTML dinamicamente.
	As Scripts CGI (Common Gateway Interface) s&atilde;o uma delas. Neste caso, O
	URL para aceder &agrave;s p&aacute;ginas web &eacute; constru&iacute;do de uma maneira um pouco
	diferente :</P>
<PRE>
http://&lt;server&gt;&lt;pathToScript&gt;[?[param_1=val_1][...][&amp;param_n=val_n]]
</PRE>
A lista de argumentos &eacute; guardada na vari&aacute;vel de ambiente
<CODE>QUERY_STRING</CODE>. Neste contexto, uma script CGI n&atilde;o &eacute; mais do que
um ficheiro execut&aacute;vel. Utiliza a <CODE>stdin</CODE> (entrada de dados
padr&atilde;o - standard input) ou a vari&aacute;vel de ambiente
<CODE>QUERY_STRING</CODE> para obter os argumentos passados. Ap&oacute;s executar
o c&oacute;digo o resultado &eacute; apresentado na <CODE>stdout</CODE> (sa&iacute;da de dados
padr&atilde;o - standard output) e depois, redireccionada para o cliente web.
Praticamente todas as linguagens de programa&ccedil;&atilde;o podem ser usadas para
escrever um script CGI (programas C compilados, Perl, scripts da
shell...).<BR>
    <BR>

    <P>Por exemplo, procuremos o que os HOWTOs em
    <CODE>www.linuxdoc.org</CODE> sabem acerca do ssh&nbsp;:</P>
<PRE>
http://www.linuxdoc.org/cgi-bin/ldpsrch.cgi?
  svr=http%3A%2F%2Fwww.linuxdoc.org&amp;srch=ssh&amp;db=1&amp;scope=0&amp;rpt=20
</PRE>
    De facto, &eacute; muito mais simples do que parece. Analisemos este URL.
    :

    <UL>
		<LI>o servidor ainda &eacute; o mesmo
      <CODE>www.linuxdoc.org</CODE>&nbsp;;</LI>

	  <LI>o ficheiro pedido, a script CGI, chama-se
      <CODE>/cgi-bin/ldpsrch.cgi</CODE>&nbsp;;</LI>

      <LI>
	  o <CODE>?</CODE> &eacute; o principio de uma longa lista de argumentos
        :

        <OL>
			<LI><CODE>srv=http%3A%2F%2Fwww.linuxdoc.org</CODE> &eacute; o servidor
			de onde o pedido vem;</LI>

			<LI><CODE>srch=ssh</CODE> representa o pedido em si;</LI>

			<LI><CODE>db=1</CODE> significa que o pedido s&oacute; diz respeito
			aos HOWTOs;</LI>

			<LI><CODE>scope=0</CODE> significa que o pedido diz respeito ao
			conte&uacute;do dos documentos e n&atilde;o somente ao t&iacute;tulo;</LI>

          <LI><CODE>rpt=20</CODE> limita a 20 o n&uacute;mero de respostas
		  apresentadas.</LI>
        </OL>
      </LI>
    </UL>
    <BR>
    <BR>

	<P>Muitas vezes, os nomes dos argumentos s&atilde;o bastante expl&iacute;citos para
	se compreender o seu significado. E acrescente-se que o conte&uacute;do da
	p&aacute;gina a apresentar a resposta &eacute; mais significativo.</P>

	<P>Agora sabem que o lado bom das scripts CGI &eacute; a habilidade do
	utilizador em passar argumentos... mas o lado negro &eacute; que uma script
	mal escrita abre um buraco na seguran&ccedil;a.</P>

	<P>Provavelmente, reparou nos caracteres estranhos utilizados pelo seu
	browser preferido no pedido acima. Estes caracteres est&atilde;o no formato
	<EM>URL codificado</EM> (n&atilde;o confunda isto com unicode). A <A href=
		"#tab_url">tabela 1</A> fornece o significado de tais c&oacute;digos.
	Mencionemos que os servidores IIS4.0 e IIS5.0 t&ecirc;m vulnerabilidades
	baseadas nestes caracteres.</P>

    <A NAME="203lfindex2">&nbsp;</A>
<H3>Configura&ccedil;&atilde;o do Apache com "<CODE>SSI Server Side
    Include</CODE>"</H3>


    <P>O <CODE><EM>Server Side Include</EM></CODE> faz parte da
	funcionalidade de um servidor web. Permite a integra&ccedil;&atilde;o de instru&ccedil;�es
	nas p&aacute;ginas web, ou incluir um ficheiro "as is", ou executar um comando
	(shell ou script CGI).</P>

	<P>No ficheiro de configura&ccedil;&atilde;o do Apache <CODE>httpd.conf</CODE>, a
	instru&ccedil;&atilde;o "<CODE>AddHandler server-parsed .shtml</CODE>" activa este
	mecanismo. Por vezes para evitar a distin&ccedil;&atilde;o entre <CODE>.html</CODE> e
	<CODE>.shtml</CODE>, adiciona-se &agrave; &uacute;ltima a extens&atilde;o
	<CODE>.html</CODE>. Claro que isto atrasa o servidor... Isto pode ser
	controlado ao n&iacute;vel dos direct&oacute;rios com as instru&ccedil;�es :</P>

    <UL>
      <LI><CODE>Options Includes</CODE> activa qualquer SSI&nbsp;;</LI>

      <LI><CODE>OptionsIncludesNoExec</CODE> pro&iacute;be <CODE>exec
      cmd</CODE> e <CODE>exec cgi</CODE>.</LI>
    </UL>
    <BR>
    <BR>

    <P>Na script <CODE><A href=
    "#guestbook">guestbook.cgi</A></CODE> em anexo, o texto fornecido por
	um utilizador est&aacute; inclu&iacute;do num ficheiro HTML, sem a convers&atilde;o dos
	caracteres '&lt;' e ' &gt;' para &amp;lt; e &amp;gt; no c&oacute;digo HTML.
	Uma pessoa curiosa podia submeter uma das instru&ccedil;�es:</P>

    <UL>
		<LI><CODE>&lt;!--#printenv --&gt;</CODE> (ignore o espa&ccedil;o a seguir
		ao <CODE>printenv&nbsp;</CODE> )</LI>

      <LI><CODE>&lt;!--#exec cmd="cat /etc/passwd"--&gt;</CODE></LI>
    </UL>
	Com o primeiro, <BR>
    <CODE>guestbook.cgi?email=pappy&amp;texte=%3c%21--%23printenv%20--%3e</CODE>
    <BR>
    obt&eacute;m algumas linhas contendo informa&ccedil;&atilde;o acerca do sistema :
<PRE>
<SMALL>DOCUMENT_ROOT=/home/web/sites/www8080
HTTP_ACCEPT=image/gif, image/jpeg, image/pjpeg, image/png, */*
HTTP_ACCEPT_CHARSET=iso-8859-1,*,utf-8
HTTP_ACCEPT_ENCODING=gzip
HTTP_ACCEPT_LANGUAGE=en, fr
HTTP_CONNECTION=Keep-Alive
HTTP_HOST=www.esiea.fr:8080
HTTP_PRAGMA=no-cache
HTTP_REFERER=http://www.esiea.fr:8080/~grenier/cgi/guestbook.cgi?
 email=&amp;texte=%3C%21--%23include+file%3D%22guestbook.cgi%22--%3E
HTTP_USER_AGENT=Mozilla/4.76 [fr] (X11; U; Linux 2.2.16 i686)
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/X11R6/bin
REMOTE_ADDR=194.57.201.103
REMOTE_HOST=nef.esiea.fr
REMOTE_PORT=3672
SCRIPT_FILENAME=/mnt/c/nef/grenier/public_html/cgi/guestbook.html
SERVER_ADDR=194.57.201.103
SERVER_ADMIN=master8080@nef.esiea.fr
SERVER_NAME=www.esiea.fr
SERVER_PORT=8080
SERVER_SIGNATURE=&lt;ADDRESS&gt;Apache/1.3.14 Server www.esiea.fr Port 8080&lt;/ADDRESS&gt;

SERVER_SOFTWARE=Apache/1.3.14 (Unix)  (Red-Hat/Linux) PHP/3.0.18
GATEWAY_INTERFACE=CGI/1.1
SERVER_PROTOCOL=HTTP/1.0
REQUEST_METHOD=GET
QUERY_STRING=
REQUEST_URI=/~grenier/cgi/guestbook.html
SCRIPT_NAME=/~grenier/cgi/guestbook.html
DATE_LOCAL=Tuesday, 27-Feb-2001 15:33:56 CET
DATE_GMT=Tuesday, 27-Feb-2001 14:33:56 GMT
LAST_MODIFIED=Tuesday, 27-Feb-2001 15:28:05 CET
DOCUMENT_URI=/~grenier/cgi/guestbook.shtml
DOCUMENT_PATH_INFO=
USER_NAME=grenier
DOCUMENT_NAME=guestbook.shtml
</SMALL>
</PRE>
    <BR>
    <BR>

	<P>A instru&ccedil;&atilde;o <CODE>exec</CODE> &eacute; como que um equivalente da shell :</P>
<PRE>
<small>

guestbook.cgi?email=ppy&amp;texte=%3c%21--%23exec%20cmd="cat%20/etc/passwd"%20--%3e
</small>
</PRE>

    <P>N&atilde;o tente "<CODE>&lt;!--#include file="/etc/passwd"--&gt;</CODE>", o
	caminho &eacute; relativo ao direct&oacute;rio onde pode encontrar o ficheiro HTML e
	n&atilde;o pode conter "<CODE>..</CODE>". O ficheiro do Apache
	<CODE>error_log</CODE> cont&eacute;m depois uma mensagem indicando uma
	tentativa de acesso a um ficheiro proibido. O utilizador pode ver a
	mensagem <CODE>[an error occurred while processing this
		directive]</CODE> na p&aacute;gina HTML.</P>

	<P>O SSI, na generalidade, n&atilde;o &eacute; preciso por isso &eacute; melhor desactiv&aacute;-lo
	no servidor. Contudo a causa do problema &eacute; a combina&ccedil;&atilde;o de uma m&aacute;
	aplica&ccedil;&atilde;o do guestbook com o SSI.</P>

    <A NAME="203lfindex3">&nbsp;</A>
<H2>Scripts em Perl</H2>


	<P>Nesta sec&ccedil;&atilde;o, apresentamos buracos de seguran&ccedil;a relacionados com as
	scripts CGI escritas em Perl. Para manter as coisas claras, n&atilde;o
	fornecemos todo o c&oacute;digo mas somente as partes necess&aacute;rias para
	entender onde se encontra o problema.</P>

    <P>Cada uma das nossas scripts &eacute; constru&iacute;da segundo o modelo seguinte
	:</P>
<PRE>
#!/usr/bin/perl -wT
BEGIN { $ENV{PATH} = '/usr/bin:/bin' }
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};   # Make %ENV safer =:-)
print "Content-type: text/html\n\n";
print "&lt;HTML&gt;\n&lt;HEAD&gt;";
print "&lt;TITLE&gt;Remote Command&lt;/TITLE&gt;&lt;/HEAD&gt;\n";
&amp;ReadParse(\%input);
# now use $input e.g like this:
# print "&lt;p&gt;$input{filename}&lt;/p&gt;\n";
# #################################### #
# Start of problem description         #
# #################################### #



# ################################## #
# End of problem description         #
# ################################## #

form:
print "&lt;form action=\"$ENV{'SCRIPT_NAME'}\"&gt;\n";
print "&lt;input type=texte name=filename&gt;\n &lt;/form&gt;\n";
print "&lt;/BODY&gt;\n";
print "&lt;/HTML&gt;\n";
exit(0);

# first arg must be a reference to a hash.
# The hash will be filled with data.
sub ReadParse($) {
  my $in=shift;
  my ($i, $key, $val);
  my $in_first;
  my @in_second;

  # Read in text
  if ($ENV{'REQUEST_METHOD'} eq "GET") {
    $in_first = $ENV{'QUERY_STRING'};
  } elsif ($ENV{'REQUEST_METHOD'} eq "POST") {
    read(STDIN,$in_first,$ENV{'CONTENT_LENGTH'});
  }else{
    die "ERROR: unknown request method\n";
  }

  @in_second = split(/&amp;/,$in_first);

  foreach $i (0 .. $#in_second) {
    # Convert plus's to spaces
    $in_second[$i] =~ s/\+/ /g;

    # Split into key and value.
    ($key, $val) = split(/=/,$in_second[$i],2);

    # Convert %XX from hex numbers to alphanumeric
    $key =~ s/%(..)/pack("c",hex($1))/ge;
    $val =~ s/%(..)/pack("c",hex($1))/ge;

    # Associate key and value
    # \0 is the multiple separator
    $$in{$key} .= "\0" if (defined($$in{$key}));
    $$in{$key} .= $val;

  }
  return length($#in_second);
}

</PRE>

    <P>Mais acerca dos argumentos passados ao Perl (<CODE>-wT</CODE>) mais
	tarde. Come&ccedil;amos por limpar as vari&aacute;veis de ambiente <CODE>$ENV</CODE>
	e <CODE>$PATH</CODE> e enviamos o cabe&ccedil;alho de HTML (isto &eacute; algo que
	faz parte do protocolo entre o browser e o servidor. N&atilde;o o consegue ver
	do lado do cliente). A fun&ccedil;&atilde;o <CODE>ReadParse()</CODE> l&ecirc; os argumentos
	passados &agrave; script. Isto podia ser feito mais facilmente com m&oacute;dulos,
	mas deste modo pode ver todo o c&oacute;digo. De seguida apresentamos
	exemplos. Por &uacute;ltimo acabamos o ficheiro HTML.</P>

	<A NAME="203lfindex4">&nbsp;</A>
<H3>O byte Nulo</H3>


	<P>O Perl considera cada caracter do mesmo modo, o que difere das
	fun&ccedil;�es C, por exemplo. Para o perl o caracter nulo para terminar uma
	string &eacute; como outro qualquer. E ent&atilde;o ?</P>

    <P>Adicionemos o seguinte c&oacute;digo &agrave; nossa script para criar o
	<CODE>showhtml.cgi</CODE>&nbsp; :</P>
<PRE>
  # showhtml.cgi
  my $filename= $input{filename}.".html";
  print "&lt;BODY&gt;File : $filename&lt;BR&gt;";
  if (-e $filename) {
      open(FILE,"$filename") || goto form;
      print &lt;FILE&gt;;
  }
</PRE>
    <BR>
    <BR>

	<P>A fun&ccedil;&atilde;o <CODE>ReadParse()</CODE> obt&eacute;m o &uacute;nico argumento : O nome
	do ficheiro a apresentar. Para prevenir alguns "convidados rudes" de
	ler para al&eacute;m dos ficheiros HTML, adicionamos a extens&atilde;o
	"<CODE>.html</CODE>" no fim do ficheiro. Mas lembre-se que o byte nulo
	&eacute; um caracter como outro qualquer...</P>

	<P>Assim, se o nosso pedido &eacute;
	<CODE>showhtml.cgi?filename=%2Fetc%2Fpasswd%00</CODE> o ficheiro
	chama-se <CODE>my $filename = "/etc/passwd\0.html"</CODE> e os nossos
	olhos ficam pasmados com algo que n&atilde;o &eacute; HTML.</P>

    <P>O que acontece ? O comando <CODE>strace</CODE> mostra como o Perl
	abre um ficheiro:</P>
<PRE>
  /tmp &gt;&gt;cat &gt;open.pl &lt;&lt; EOF
  &gt; #!/usr/bin/perl
  &gt; open(FILE, "/etc/passwd\0.html");
  &gt; EOF
  /tmp &gt;&gt;chmod 0700 open.pl
  /tmp &gt;&gt;strace ./open.pl 2&gt;&amp;1 | grep open
  execve("./open.pl", ["./open.pl"], [/* 24 vars */]) = 0
  ...
  open("./open.pl", O_RDONLY)             = 3
  read(3, "#!/usr/bin/perl\n\nopen(FILE, \"/et"..., 4096) = 51
  open("/etc/passwd", O_RDONLY)           = 3
</PRE>
    <BR>
    <BR>

    <P>O &uacute;ltimo <CODE>open()</CODE> apresentado pelo <CODE>strace</CODE>
	corresponde a uma chamada de sistema escrita em C. Podemos ver que a
	extens&atilde;o <CODE>.html</CODE> desapareceu e isto permitiu-nos abrir o
	ficheiro /etc/passwd.</P>

    <P>Este problema resolve-se com uma simples express&atilde;o regular que
	remove os bytes nulos:</P>
<PRE>
s/\0//g;
</PRE>
    <BR>
    <BR>


    <A NAME="203lfindex5">&nbsp;</A>
<H3>Utilizando pipes</H3>


	<P>Eis aqui uma script sem qualquer protec&ccedil;&atilde;o. Apresenta um dado
	ficheiro na &aacute;rvore da directoria /home/httpd/ :</P>
<PRE>
#pipe1.cgi

my $filename= "/home/httpd/".$input{filename};
print "&lt;BODY&gt;File : $filename&lt;BR&gt;";
open(FILE,"$filename") || goto form;
print &lt;FILE&gt;;
</PRE>
    <BR>
    <BR>

	<P>N&atilde;o se ria com este exemplo ! Eu vi scripts assim.</P>

	<P>A primeira explora&ccedil;&atilde;o &eacute; &oacute;bvia :</P>
<PRE>
pipe1.cgi?filename=..%2F..%2F..%2Fetc%2Fpasswd
</PRE>
S&oacute; precisa de subir na &aacute;rvore de directoria para aceder a qualquer
ficheiro. Mas existe ainda uma possibilidade mais interessante : a execu&ccedil;&atilde;o
de um comando &agrave; sua escolha. Em Perl, o comando <CODE>open(FILE,
	"/bin/ls")</CODE> abre o ficheiro bin&aacute;rio "<CODE>/bin/ls</CODE>"... mas
o <CODE>open(FILE,&nbsp;"/bin/ls&nbsp;|")</CODE> executa o comando
especificado. O facto de se adicionar um simples pipe <CODE>|</CODE> altera
o comportamento do <CODE>open()</CODE>. <BR>
    <BR>

    <P>Outro problema vem do facto da exist&ecirc;ncia do ficheiro n&atilde;o ser testado, o que nos permite executar qualquer comando mas tamb&eacute;m passar os argumentos :
    <CODE>pipe1.cgi?filename=..%2F..%2F..%2Fbin%2Fcat%20%2fetc%2fpasswd%20|</CODE>
    o que apresenta o conte&uacute;do do ficheiro password.</P>

    <P>Testar a exist&ecirc;ncia da abertura de um ficheiro d&aacute; menos liberdade :</P>
<PRE>
#pipe2.cgi

my $filename= "/home/httpd/".$input{filename};
print "&lt;BODY&gt;File : $filename&lt;BR&gt;";
if (-e $filename) {
  open(FILE,"$filename") || goto form;
  print &lt;FILE&gt;
} else {
  print "-e failed: no file\n";
}
</PRE>
O exemplo anterior j&aacute; n&atilde;o trabalha mais. O teste "<CODE>-e</CODE>" falha se
n&atilde;o encontra o ficheiro "<CODE>../../../bin/cat /etc/passwd |</CODE>".
<BR>
    <BR>

    <P>Tentemos, agora o comando <CODE>/bin/ls</CODE>. O comportamento ser&aacute;
	como antes. Ou seja, se por exemplo, tentarmos listar o conte&uacute;do do
	direct&oacute;rio <CODE>/etc</CODE>, o teste "<CODE>-e</CODE>" verifica a
	exist&ecirc;ncia do ficheiro "<CODE>../../../bin/ls /etc |</CODE> mas tamb&eacute;m
	n&atilde;o existe. A n&atilde;o ser que demos o nome de um ficheiro "fantasma" n&atilde;o
	conseguiremos nada interessante :(</P>

	<P>Contudo, existe ainda um modo de "contornar" a situa&ccedil;&atilde;o, mesmo que o
	resultado n&atilde;o seja t&atilde;o bom. O ficheiro <CODE>/bin/ls</CODE> existe
	(bem, na maioria dos sistemas), mas se o <CODE>open()</CODE> &eacute; chamado
	com o nome do ficheiro o comando n&atilde;o &eacute; executado, mas &eacute; apresentado o
	ficheiro em bin&aacute;rio. Temos ent&atilde;o de encontrar um modo de p&ocirc;r um pipe
	'<CODE>|</CODE>' no fim do nome, sem que seja usado na verifica&ccedil;&atilde;o
	feita por "<CODE>-e</CODE>". J&aacute; sabemos a solu&ccedil;&atilde;o : o byte nulo. Se
	enviarmos "<CODE>../../../bin/ls\0|</CODE>" como nome, o teste da
	exist&ecirc;ncia tem sucesso visto que s&oacute; considera
	"<CODE>../../../bin/ls</CODE>", mas o <CODE>open()</CODE> consegue ver
	o pipe e executar o comando. Ent&atilde;o o URL fornecendo o conte&uacute;do do
	direct&oacute;rio corrente &eacute;: </P>
<PRE>
pipe2.cgi?filename=../../../bin/ls%00|
</PRE>

    <A NAME="203lfindex6">&nbsp;</A>
<H3>Avan&ccedil;o de Linha</H3>


	<P>A script finger.cgi executa a instru&ccedil;&atilde;o <CODE>finger</CODE> na sua
	m&aacute;quina :</P>
<PRE>
#finger.cgi

print "&lt;BODY&gt;";
$login = $input{'login'};
$login =~ s/([;&lt;&gt;\*\|`&amp;\$!#\(\)\[\]\{\}:'"])/\\$1/g;
print "Login $login&lt;BR&gt;\n";
print "Finger&lt;BR&gt;\n";
$CMD= "/usr/bin/finger $login|";
open(FILE,"$CMD") || goto form;
print &lt;FILE&gt;
</PRE>
    <BR>
    <BR>

	<P>Esta script, (pelo menos) toma uma precau&ccedil;&atilde;o &uacute;til : toma cuidado com
	caracteres estranhos para prevenir que estes sejam interpretados pela
	shell colocando uma '<CODE>\</CODE>' &agrave; frente dos caracteres. Assim, a
	semicoluna &eacute; alterada para "<CODE>\;</CODE>" por uma express&atilde;o regular.
	Mas a lista n&atilde;o cont&eacute;m todos os caracteres importantes. Entre outros o
	avan&ccedil;o de linha '<CODE>\n</CODE>' est&aacute; em falta.</P>

    <P>Se preferir a linha de comandos da shell, voc&ecirc; valida uma instru&ccedil;&atilde;o
carregando <CODE>RETURN</CODE> ou <CODE>ENTER</CODE> que envia o caracter
'<CODE>\n</CODE>'. Em Perl, pode fazer o mesmo. J&aacute; vimos a instru&ccedil;&atilde;o
<CODE>open()</CODE> que nos permitia executar um comando logo que a linha
terminasse com um pipe '<CODE>|</CODE>'.</P>

    <P>Para simular este comportamento adicionamos um carriage-return e uma
instru&ccedil;&atilde;o ap&oacute;s o login enviado ao comando finger :</P>

    <CENTER>
<PRE>
finger.cgi?login=kmaster%0Acat%20/etc/passwd
</PRE>
    </CENTER>
    <BR>
    <BR>

    <P>Outros caracteres s&atilde;o bastante interessantes para executar v&aacute;rias
instru&ccedil;�es numa c&eacute;lula : </P>

    <UL>
      <LI><CODE>;</CODE>&nbsp; :termina a instru&ccedil;&atilde;o e salta para a pr&oacute;xima;</LI>

      <LI><CODE>&amp;&amp;</CODE>&nbsp; : se a primeira instru&ccedil;&atilde;o tiver
sucesso (<EM>i.e.</EM> retorna 0 na shell), ent&atilde;o a pr&oacute;xima &eacute;
executada;</LI>

      <LI><CODE>||</CODE>&nbsp; : se a primeira instru&ccedil;&atilde;o falhar
(<EM>i.e.</EM> retorna um valor n&atilde;o nulo na shell), ent&atilde;o a pr&oacute;xima &eacute;
executada.</LI>
    </UL>
    <BR>
    <BR>
     Elas n&atilde;o trabalham aqui, visto que est&atilde;o protegidas pela express&atilde;o
regular. Mas vamos encontrar um modo de p&ocirc;r isto a funcionar.

    <A NAME="203lfindex7">&nbsp;</A>
<H3>A Backslash e a semicoluna</H3>


    <P>A script anterior, <CODE>finger.cgi</CODE> evita problemas com
caracteres estranhos. Ent&atilde;o o URL
<CODE>&lt;finger.cgi?login=kmaster;cat%20/etc/passwd</CODE> n&atilde;o trabalha
quando a semicoluna est&aacute; protegida. Contudo, existe um caracter que n&atilde;o
est&aacute; protegido : a backslash '<CODE>\</CODE>'.</P>

    <P>Tomemos, por exemplo, uma script que nos previne de subir na &aacute;rvore
utilizando express�es regulares <CODE>s/\.\.//g</CODE> para nos livrarmos
de "<CODE>..</CODE>". N&atilde;o importa ! As shells conseguem lidar com v&aacute;rios
n&uacute;meros de '<CODE>/</CODE>' uma s&oacute; vez (tente <CODE>cat
    ///etc//////passwd</CODE> para ficar convencido).</P>

    <P>Por exemplo, na script acima <CODE>pipe2.cgi</CODE>, a vari&aacute;vel
<CODE>$filename</CODE> &eacute; inicializada a partir do prefixo
"<CODE>/home/httpd/</CODE>". Utilizando a express&atilde;o regular anterior podia
parecer eficiente a preven&ccedil;&atilde;o de subir nos direct&oacute;rios. Claro que esta
express&atilde;o protege-o de "<CODE>..</CODE>", mas o que &eacute; que acontece se
protegermos o caracter '<CODE>.</CODE>'? Ou seja, a express&atilde;o n&atilde;o condiz se
o nome do ficheiro &eacute; : <CODE>.\./.\./etc/passwd</CODE>.
    Mencionemos, que isto trabalha bem com <CODE>system()</CODE> (ou
    <CODE>` ... `</CODE>), mas o <CODE>open()</CODE> ou o "<CODE>-e</CODE>"
    falham.</P>

    <P>Voltemos &agrave; script <CODE>finger.cgi</CODE>. Utilizando a semicoluna,
o URL <CODE>finger.cgi?login=kmaster;cat%20/etc/passwd</CODE> n&atilde;o d&aacute; o
resultado esperado visto que a semicoluna est&aacute; protegida
pela express&atilde;o regular. Ou seja, a shell recebe a instru&ccedil;&atilde;o:</P>
<PRE>
/usr/bin/finger kmaster\;cat /etc/passwd
</PRE>
    S&atilde;o encontrados os seguintes erros no servidor web :
<PRE>
finger: kmaster;cat: no such user.
finger: /etc/passwd: no such user.
</PRE>
    As mensagens s&atilde;o id&ecirc;nticas aquelas que obt&eacute;m quando digita esta linha
na shell. O problema vem do facto do protegido caracter '<CODE>;</CODE>'
ser considerado como pertencente &agrave; string "<CODE>kmaster;cat</CODE>" . <BR>
    <BR>

    <P>Queremos separar ambas as instru&ccedil;�es, uma da script e aquela que
queremos utilizar. Devemos, ent&atilde;o proteger '<CODE>;</CODE>'&nbsp;: <CODE>&lt;A
    HREF="finger.cgi?login=kmaster\;cat%20/etc/passwd"&gt;
    finger.cgi?login=kmaster\;cat%20/etc/passwd&lt;/A&gt;</CODE>. A string
"<CODE>\;</CODE>, &eacute; ent&atilde;o alterada pela script para "<CODE>\\;</CODE>", e
depois, enviada &agrave; shell que l&ecirc; :
    :</P>
<PRE>
/usr/bin/finger kmaster\\;cat /etc/passwd
</PRE>
    A shell divide isto em duas instru&ccedil;�es diferentes :

    <OL>
      <LI><CODE>/usr/bin/finger kmaster\</CODE> que provavelmente falhar&aacute;
... mas n&atilde;o nos importamos ;-)</LI>

      <LI><CODE>cat /etc/passwd</CODE> a que apresenta o ficheiro
passwd.</LI>
    </OL>
    A solu&ccedil;&atilde;o &eacute; simples : a backslash '<CODE>\</CODE>' deve tamb&eacute;m estar protegida. <BR>
    <BR>


    <A NAME="203lfindex8">&nbsp;</A>
<H3>Utilizando um caracter " desprotegido </H3>


    <P>Por vezes o par&acirc;metro, est&aacute; "protegido" utilizando aspas. Alter&aacute;mos
a script anterior <CODE>finger.cgi</CODE> para proteger a vari&aacute;vel
<CODE>$login</CODE> deste modo.</P>

    <P>Contudo, se as aspas n&atilde;o est&atilde;o protegidas &eacute; in&uacute;til. Mesmo que seja
adicionada o pedido falhar&aacute;. Isto acontece porque a primeira aspa enviada
fecha com a que abre a script. De seguida escreve o comando, e a segunda
aspa fecha a &uacute;ltima (a do fecho) aspa da script.</P>

    <P>A script finger2.cgi ilustra isto : </P>
<PRE>
#finger2.cgi

print "&lt;BODY&gt;";
$login = $input{'login'};
$login =~ s/\0//g;
$login =~ s/([&lt;&gt;\*\|`&amp;\$!#\(\)\[\]\{\}:'\n])/\\$1/g;
print "Login $login&lt;BR&gt;\n";
print "Finger&lt;BR&gt;\n";
#New (in)efficient super protection :
$CMD= "/usr/bin/finger \"$login\"|";
open(FILE,"$CMD") || goto form;
while(&lt;FILE&gt;) {
  print;
}
</PRE>
    <BR>
    <BR>

    <P>O URL ent&atilde;o, a executar vem de seguida :</P>
<PRE>
finger2.cgi?login=kmaster%22%3Bcat%20%2Fetc%2Fpasswd%3B%22
</PRE>
    A shell recebe o comando <CODE>/usr/bin/finger "$login";cat
    /etc/passwd""</CODE> e as aspas j&aacute; n&atilde;o constituem nenhum problema. <BR>
    <BR>

    <P>Assim, &eacute; importante, se desejar proteger os par&acirc;metros com aspas,
deve proteg&ecirc;-los bem como &aacute; semicoluna e &agrave; backslash, como anteriormente
referido. </P>

    <A NAME="203lfindex9">&nbsp;</A>
<H3>Escrevendo em Perl</H3>


    <A NAME="203lfindex10">&nbsp;</A>
<H3>Avisos e op&ccedil;�es defeituosas</H3>


    <P>Ao programar em Perl, utilize a op&ccedil;&atilde;o <CODE>w</CODE> ou "<CODE>use
warnings;</CODE>" (no Perl 5.6.0 e posteriores), informando-lhe acerca de
poss&iacute;veis problemas como vari&aacute;veis n&atilde;o inicializadas ou express�es/fun&ccedil;�es
obsoletas. </P>

    <P>A op&ccedil;&atilde;o <CODE>T</CODE> ( <EM>modo defeituoso</EM>) fornece ainda
mais seguran&ccedil;a. Este modo activa v&aacute;rios testes. O mais importante diz
respeito a poss&iacute;veis vari&aacute;veis <EM>"defeituosas"</EM>. As vari&aacute;veis ou s&atilde;o limpas ou
defeituosas. A informa&ccedil;&atilde;o que vem de fora do programa &eacute; considerada
defeituosa at&eacute; que seja limpa. Uma vari&aacute;vel defeituosa n&atilde;o &eacute; capaz de
atribuir valores a coisas que s&atilde;o utilizadas fora do programa (chamadas a
outros comandos da shell).</P>

    <P>No modo <EM>defeituoso</EM> os argumentos da linha de comando, as
vari&aacute;veis de ambiente, alguns resultados das chamadas de sistema (<CODE>readdir()</CODE>,
    <CODE>readlink()</CODE>, <CODE>readdir()</CODE>, ...) e os
dados provindos de ficheiros, s&atilde;o considerados suspeitos, logo
defeituosos.</P>

    <P>Para limpar uma vari&aacute;vel, deve filtr&aacute;-la atrav&eacute;s de uma express&atilde;o
regular. Obviamente que a utiliza&ccedil;&atilde;o de <CODE>.*</CODE> &eacute; in&uacute;til. O
objectivo &eacute; for&ccedil;a-lo a verificar os argumentos fornecidos. Utilize sempre
uma express&atilde;o regular que deve ser especifica.</P>

    <P>Contudo, este modo n&atilde;o o protege de tudo : O defeito dos argumentos
passados ao <CODE>system()</CODE> ou <CODE>exec()</CODE> como uma lista de
vari&aacute;veis n&atilde;o &eacute; verificada. Deve ter bastante cuidado se uma das suas
scripts utiliza estas fun&ccedil;�es. A instru&ccedil;&atilde;o
<CODE>exec&nbsp;"sh",&nbsp;'-c',&nbsp;$arg;</CODE> &eacute; considerada segura,
segundo o <CODE>$arg</CODE> &eacute; ou n&atilde;o defeituoso :(</P>

    <P>&Eacute; tamb&eacute;m recomend&aacute;vel adicionar "use strict;"  no inicio dos seus
programas. Isto obriga-o a declarar as vari&aacute;veis; algumas pessoas podem
achar isto aborrecido mas &eacute; obrigat&oacute;rio se utilizar <CODE>mod-perl</CODE>.</P>

    <P>Assim, se utilizar Perl CGI nas suas scripts :</P>
<PRE>
#!/usr/bin/perl -wT
use strict;
use CGI;
</PRE>
    ou com o Perl 5.6.0 :
<PRE>
#!/usr/bin/perl -T
use warnings;
use strict;
use CGI;
</PRE>
    <BR>
    <BR>


    <A NAME="203lfindex11">&nbsp;</A>
<H3>Chamada ao <CODE>open()</CODE></H3>


    <P>Muitos programadores abrem um ficheiro utilizando
<CODE>open(FILE,"$filename") || ...</CODE>. J&aacute; vimos os riscos de tal
c&oacute;digo. Para reduzir o risco especifique o modo de abertura :</P>

    <UL>
      <LI><CODE>open(FILE,"&lt;$filename") || ...</CODE> para leitura
somente;</LI>

      <LI><CODE>open(FILE,"&gt;$filename") || ...</CODE> para escrita
somente</LI>
    </UL>
    N&atilde;o abra os seus ficheiros num modo n&atilde;o especificado.<BR>
    <BR>


    <P>Antes de aceder a um ficheiro &eacute; recomend&aacute;vel verificar se o ficheiro
existe. Isto n&atilde;o previne os tipos de problemas das race conditions,
apresentadas no artigo anterior. Mas evita armadilhas com os comandos que
t&ecirc;m argumentos.</P>
<PRE>
if ( -e $filename ) { ... }
</PRE>

    <P>A come&ccedil;ar pelo Perl 5.6, existe uma nova sintaxe para o
<CODE>open()</CODE> : <CODE>open(FILEHANDLE,MODE,LIST)</CODE>. Como modo
'&lt;', o ficheiro &eacute; aberto para leitura; como modo '&gt;' o ficheiro &eacute;
truncado ou criado se necess&aacute;rio e aberto para escrita. Isto torna-se
interessante para os modos de comunicar com outros processos. Se o modo for
'|-' or '-|', A LISTA de argumentos &eacute; interpretada como um comando e
encontra-se, respectivamente, antes do pipe.</P>

    <P>Antes do Perl 5.6 e do <CODE>open()</CODE> com os tr&ecirc;s argumentos,
algumas pessoas preferiam utilizar o comando <CODE>sysopen()</CODE>.</P>

    <A NAME="203lfindex12">&nbsp;</A>
<H3>Filtra&ccedil;&atilde;o e protec&ccedil;&atilde;o dos dados de entrada</H3>


    <P>Existem dois m&eacute;todos : especificar os caracteres proibidos ou
definir explicitamente os caracteres permitidos, utilizando express�es
regulares. Os programas de dos exemplos devem t&ecirc;-lo convencido como &eacute; f&aacute;cil
esquecer de filtrar os potenciais caracteres perigosos, e &eacute; por isto que o
segundo m&eacute;todo &eacute; recomendado.</P>

    <P>Eis aqui, o que, praticamente deve fazer : primeiro verifique que o
pedido s&oacute; cont&eacute;m caracteres permitidos. De seguida "remova" os caracteres
considerados como perigosos de entres todos os caracteres.</P>
<PRE>
#!/usr/bin/perl -wT

# filtre.pl

#  The $safe and $danger variables respectively define
#  the characters without risk and the risky ones.
#  Add or remove some to change the filter.
#  Only $input containing characters included in the
#  definitions are valid.

use strict;

my $input = shift;

my $safe = '\w\d';
my $danger = '&amp;`\'\\|"*?~&lt;&gt;^(){}\$\n\r\[\]';
#Note:
#  '/', space and tab are not part of the definitions on purpose


if ($input =~ m/^[$safe$danger]+$/g) {
    $input =~ s/([$danger]+)/\\$1/g;
} else {
    die "Bad input chars in $input\n";
}
print "input = [$input]\n";
</PRE>
    <BR>
    <BR>

    <P>Esta script define duas defini&ccedil;�es de caracteres :</P>

    <UL>
      <LI><CODE>$safe</CODE> cont&eacute;m os caracteres considerados seguros
(aqui, n&uacute;meros e letras somente);</LI>

      <LI><CODE>$danger</CODE> cont&eacute;m os caracteres a serem removidos,
visto que s&atilde;o permitidos mas potencialmente perigosos.</LI>
    </UL>
    Qualquer pedido contendo caracteres n&atilde;o definidos nestas defini&ccedil;�es &eacute;
imediatamente rejeitado. <BR>
    <BR>


    <A NAME="203lfindex13">&nbsp;</A>
<H2>Scripts PHP </H2>


    <P>N&atilde;o quero ser controverso, mas penso que &eacute; melhor escrever scripts
em PHP do que em Perl. Mais, exactamente, como administrador de sistema,
prefiro que os meus utilizadores escrevem scripts em PHP do que em Perl.
Algu&eacute;m programando de um modo inseguro em PHP &eacute; t&atilde;o perigoso como em Perl,
mas porque &eacute; que prefiro o PHP ? Se tiver problemas de programa&ccedil;&atilde;o com o
PHP pode activar o modo de seguran&ccedil;a (<CODE>safe_mode=on</CODE>) ou
desactivar fun&ccedil;�es (<CODE>disable_functions=...</CODE>). Este modo previne
o acesso a ficheiros que n&atilde;o pertencem ao utilizador, alterar vari&aacute;veis de
ambiente a n&atilde;o ser que seja explicitamente permitido executar comandos,
etc.</P>

    <P>Por omiss&atilde;o, o banner do Apache informa-o acerca do PHP que est&aacute; a
ser utilizado.</P>
<PRE>
$ telnet localhost 80
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.
HEAD / HTTP/1.0

HTTP/1.1 200 OK
Date: Tue, 03 Apr 2001 11:22:41 GMT
Server: Apache/1.3.14 (Unix)  (Red-Hat/Linux) mod_ssl/2.7.1
        OpenSSL/0.9.5a PHP/4.0.4pl1 mod_perl/1.24
Connection: close
Content-Type: text/html

Connection closed by foreign host.
</PRE>
    Escreva <CODE>expose_PHP = Off</CODE> no ficheiro
<CODE>/etc/php.ini</CODE> para esconder a informa&ccedil;&atilde;o :
<PRE>
Server: Apache/1.3.14 (Unix)  (Red-Hat/Linux) mod_ssl/2.7.1
OpenSSL/0.9.5a mod_perl/1.24
</PRE>
    <BR>
    <BR>


    <P>O ficheiro <CODE>/etc/php.ini</CODE> (no PHP4) e
<CODE>/etc/httpd/php3.ini</CODE> t&ecirc;m muitos par&acirc;metros que o podem ajudar a
dificultar/proteger o sistema. Por exemplo a op&ccedil;&atilde;o
"<CODE>magic_quotes_gpc</CODE>" adiciona aspas aos argumentos recebidos
pelos m&eacute;todos <CODE>GET</CODE>, <CODE>POST</CODE> e atrav&eacute;s de cookies;
isto evita um variado n&uacute;mero de problemas encontrados nos nossos exemplos
em Perl.</P>

    <A NAME="203lfindex14">&nbsp;</A>
<H2>Conclus&atilde;o</H2>


    <P> Este artigo &eacute; provavelmente, o mais f&aacute;cil de entender entre os
artigos  desta s&eacute;rie. Mostra-lhe vulnerabilidades exploradas todos os dias
na web. Existem muitas outras relacionadas com a m&aacute; programa&ccedil;&atilde;o (por
exemplo uma script enviando um mail, tendo como argumento o campo
<CODE>From:</CODE>, fornece um bom spam para um site). Os exemplos s&atilde;o
numerosos. Logo que uma script esteja num site pode apostar que pelo menos
uma pessoa tentar&aacute; us&aacute;-la de um modo pervertido.</P>

    <P>Este artigo termina a s&eacute;rie acerca da programa&ccedil;&atilde;o segura. Esperamos
que tenhamos ajudado a descobrir os principais buracos de seguran&ccedil;a em
muitas aplica&ccedil;�es. e que levar&aacute; mais em conta o par&acirc;metro de "seguran&ccedil;a"
quando estiver a desenvolver/programar as suas aplica&ccedil;�es. Os problemas de
seguran&ccedil;a s&atilde;o, por vezes, negligenciados devido &agrave; limitada abrang&ecirc;ncia do
desenvolvimento (uso interno, ... uso de redes privadas, modelos
tempor&aacute;rios, etc) Contudo um modelo, originalmente desenhado para um uso
muito restrito pode vir a ser a base de um aplica&ccedil;&atilde;o muito maior, tendo-se
depois de alterar o que se torna mais dispendioso.</P>
    <HR>
<A NAME="203lfindex15">&nbsp;</A>
<H2>Alguns caracteres URL codificados </H2>

    <CENTER>
      <A name="tab_url"></A>

      <TABLE border width="45%" nosave="">
        <TR>
          <TD>Codifica&ccedil;&atilde;o URL </TD>

          <TD>Caracter</TD>
        </TR>

        <TR>
          <TD>%00</TD>

          <TD>\0 (fim de string)</TD>
        </TR>

        <TR>
          <TD>%0a</TD>

          <TD>\n (carriage return)</TD>
        </TR>

        <TR>
          <TD>%20</TD>

          <TD><EM>espa&ccedil;o</EM></TD>
        </TR>

        <TR>
          <TD>%21</TD>

          <TD>!</TD>
        </TR>

        <TR>
          <TD>%22</TD>

          <TD>"</TD>
        </TR>

        <TR>
          <TD>%23</TD>

          <TD>#</TD>
        </TR>

        <TR>
          <TD>%26</TD>

          <TD>&amp; (o i comercial)</TD>
        </TR>

        <TR>
          <TD>%2f</TD>

          <TD>/</TD>
        </TR>

        <TR>
          <TD>%3b</TD>

          <TD>;</TD>
        </TR>

        <TR>
          <TD>%3c</TD>

          <TD>&lt;</TD>
        </TR>

        <TR>
          <TD>%3e</TD>

          <TD>&gt;</TD>
        </TR>

        <TR>
          <TD>
          </TD>

          <TD>
          </TD>
        </TR>

        <CAPTION align="BOTTOM">
          Tab 1 : Correspond&ecirc;ncia entre Unicode e caracter
        </CAPTION>
      </TABLE>
    </CENTER>
    <HR>

    <A NAME="203lfindex16">&nbsp;</A>
<H2>Liga&ccedil;�es (Links)</H2>


    <UL>
      <LI><CODE>man perlsec</CODE>&nbsp;: P&aacute;gina do manual (man) de Perl
acerca de seguran&ccedil;a;</LI>

      <LI><A href=
      "http://www.php.net/manual/fr/security.php">www.php.net/manual/fr/security.php</A>&nbsp;:
      seguran&ccedil;a com o php;</LI>

      <LI><A href=
      "http://phrack.infonexus.com/">phrack.infonexus.com/</A>&nbsp;:
      outra refer&ecirc;ncia, de uma vista de olhos no artigo de Rain Forest
      Puppy (rfp) no Phrack 55.</LI>

      <LI><A href="http://www.unicode.org">www.unicode.org</A></LI>

      <LI>P&aacute;gina pessoal de Christophe Blaess : <A href=
      "http://perso.club-internet.fr/ccb/">perso.club-internet.fr/ccb/</A></LI>

      <LI>P&aacute;gina pessoal de Christophe Grenier : <A href=
      "http://www.esiea.fr/public_html/Christophe.GRENIER/">www.esiea.fr/public_html/Christophe.GRENIER/</A></LI>

      <LI>P&aacute;gina pessoal de Fr&eacute;d&eacute;ric Raynal : <A href=
      "http://www-rocq.inria.fr/~raynal/">www-rocq.inria.fr/~raynal/</A></LI>
    </UL>

    <P></P>
    <HR>
<a name="guestbook"> </a>
    <A NAME="203lfindex17">&nbsp;</A>
<H2>O programa guestbook.cgi defeituoso</H2>

<PRE>
#!/usr/bin/perl -w

# guestbook.cgi

BEGIN { $ENV{PATH} = '/usr/bin:/bin' }
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};   # Make %ENV safer =:-)
print "Content-type: text/html\n\n";
print "&lt;HTML&gt;\n&lt;HEAD&gt;&lt;TITLE&gt;Buggy Guestbook&lt;/TITLE&gt;&lt;/HEAD&gt;\n";
&amp;ReadParse(\%input);
my $email= $input{email};
my $texte= $input{texte};
$texte =~ s/\n/&lt;BR&gt;/g;

print "&lt;BODY&gt;&lt;A HREF=\"guestbook.html\"&gt;
       GuestBook &lt;/A&gt;&lt;BR&gt;&lt;form action=\"$ENV{'SCRIPT_NAME'}\"&gt;\n
      Email: &lt;input type=texte name=email&gt;&lt;BR&gt;\n
      Texte:&lt;BR&gt;\n&lt;textarea name=\"texte\" rows=15 cols=70&gt;
      &lt;/textarea&gt;&lt;BR&gt;&lt;input type=submit value=\"Go!\"&gt;
      &lt;/form&gt;\n";
print "&lt;/BODY&gt;\n";
print "&lt;/HTML&gt;";
open (FILE,"&gt;&gt;guestbook.html") || die ("Cannot write\n");
print FILE "Email: $email&lt;BR&gt;\n";
print FILE "Texte: $texte&lt;BR&gt;\n";
print FILE "&lt;HR&gt;\n";
close(FILE);
exit(0);

sub ReadParse {
  my $in =shift;
  my ($i, $key, $val);
  my $in_first;
  my @in_second;

  # Read in text
  if ($ENV{'REQUEST_METHOD'} eq "GET") {
    $in_first = $ENV{'QUERY_STRING'};
  } elsif ($ENV{'REQUEST_METHOD'} eq "POST") {
    read(STDIN,$in_first,$ENV{'CONTENT_LENGTH'});
  }else{
    die "ERROR: unknown request method\n";
  }

  @in_second = split(/&amp;/,$in_first);

  foreach $i (0 .. $#in_second) {
    # Convert plus's to spaces
    $in_second[$i] =~ s/\+/ /g;

    # Split into key and value.
    ($key, $val) = split(/=/,$in_second[$i],2);

    # Convert %XX from hex numbers to alphanumeric
    $key =~ s/%(..)/pack("c",hex($1))/ge;
    $val =~ s/%(..)/pack("c",hex($1))/ge;

    # Associate key and value
    $$in{$key} .= "\0" if (defined($$in{$key}));
    $$in{$key} .= $val;

  }

  return length($#in_second);
}

</PRE>
    <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=203&amp;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="98%">
<TR><TD ALIGN=CENTER BGCOLOR="#9999AA" WIDTH="50%">
<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&amp;article=article203.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 --&gt; -- :  Fr&eacute;d&eacute;ric Raynal, Christophe Blaess, Christophe Grenier <small>&lt;pappy(at)users.sourceforge.net, ccb(at)club-internet.fr, grenier(at)nef.esiea.fr&gt;</small></font></td></tr>
  <tr><td><font size="2">fr --&gt; en: Georges Tarbouriech &lt;georges.t(at)linuxfocus.org&gt;</font></td></tr>
  <tr><td><font size="2">en --&gt; en: Lorne Bailey &lt;sherm_pbody(at)yahoo.com&gt;</font></td></tr>
  <tr><td><font size="2">en --&gt; pt: Bruno Sousa &lt;bruno(at)linuxfocus.org&gt;</font></td></tr>
</TABLE>
</TD>
</TR></TABLE></CENTER>
<p><font size=1>2001-12-19, generated by lfparser version 2.21</font></p>
<!-- 2pdaIgnoreStop -->
</BODY>
</HTML>