GroundWork: Erro no ficheiro PHPTAL.php

Hoje aconteceu-me um erro estúpido no GroundWork:

Warning: PHPTAL::require_once(/tmp/………php) [phptal.require-once]: failed to open stream: No such file or directory in /…../guava/htdocs/guava/lib/PHPTAL/PHPTAL.php on line 265

Fatal error: PHPTAL::require_once() [function.require]: Failed opening required ‘/tmp/tpl_1_0_1152692ea3c1dbf45f6582b0a1c4f80394.php’ (include_path=’.:/……/groundwork/core/foundation/api/php:/……/groundwork/php/lib/php’) in /…../groundwork/core/guava/htdocs/guava/lib/PHPTAL/PHPTAL.php on line 265

Porque é que eu chamo erro estúpido?

Porque a solução é limpar a cache (session cookies) do browser e fazer o refresh à página!

Enfim…

Ao menos é de fácil solução :)

Tags: , ,

SQL Injection: segurança de aplicações Web

Na semana passada ao navegar por um site, lembrei-me de fazer um pequeno teste à segurança do mesmo e para minha surpresa, ou não, o site era vulnerável a ataques do tipo sql injection.

Depois de ter enviado um e-mail aos responsáveis do site a avisar e de eles terem corrigido o problema, lembrei-me de falar um pouco sobre este tema.

O que é que são ataques do tipo SQL Injection?

Basicamente são ataques que exploram o facto as instruções SQL serem criadas dinamicamente com os valores dos inputs (formulários / querystring), sem que estes sejam devidamente tratados. Estes ataques tornam possível executar código sql, tal como U_PDATE, I_NSERT, D_ROP, etc., e até executar programas no servidor web!

Mas como é que funciona?

Vou tentar mostrar como é que o SQL Injection funciona através  de um exemplo muito simples.

Para isso vou criar uma página de autenticação de utilizadores feita em PHP e MySQL.
Resumidamente vou ter:

  • uma base de dados MySQL com uma tabela “utilizadores”;
  • um ficheiro em php (login.php) onde vou ter o formulário HTML e o código PHP para validar os utilizadores na base de dados.

O aspecto da página login.php será qualquer coisa deste género:

sqlInjection-login-vazio

Formulário de Login (login.php)

Passando à parte prática

Neste exemplo, a construção da instrução SQL é feita de forma dinâmica, utilizando os valores dos formulários sem qualquer tipo de validação.
Temos então que:

$sql="S_ELECT id F_ROM utilizadores WHERE login='".$_POST["utilizador"]."' and password='".$_POST["password"]."'";

Se no formulário introduzirmos os dados:  “admin” e “1234“, a nossa instrução sql vai ficar:

S_ELECT id F_ROM utilizadores WHERE login='admin' and password='1234'

Aparentemente até aqui não existe qualquer problema. Só se adivinharmos o utilizador e a password é que vamos conseguir efectuar o login com sucesso.

O problema começa quando começamos a utilizar caracteres especiais do sql (que podem variar consoante a base de dados) nos inputs.
Por exemplo: vamos ver o que acontece se introduzirmos  no utilizador o seguinte texto:

 xpto' or 1=1#

O SQL resultante seria:

S_ELECT id F_ROM utilizadores WHERE login='xpto' or 1=1#' and password='1234'

Neste caso estou a utilizar dois caracteres especiais. a pelica “  ” e o cardinal “  # “.
O 1.º serve para delimitarmos campos do tipo “texto”.
O 2.º serve para fazer comentários.

Assim sendo, como carácter # é um carácter especial ( carácter p/ comentários), tudo o que vier depois do # vai ser ignorado pelo motor da BD. Ficamos então com:

S_ELECT id F_ROM utilizadores WHERE login='xpto' or 1=1#

Se analisarmos o sql vemos que além de termos ignorado todo o código sql que vier depois do #, estamos também a inserir a condição “ OR 1=1 “. Como esta condição é sempre verdade (1=1), o resultado da pesquisa vai devolver sempre pelo menos um id (a não ser que a tabela utilizadores esteja vazia).
Isto é, apesar de até poder não existir nenhum utilizador com o login=xpto, 1 é sempre igual a 1 :)

Outro código que podem experimentar é:

 xpto' or 1=1 limit 1#

Porquê o “limit 1″?
porque desta forma limitamos o n.º de resultados a 1.

Então mas porque é que isso é importante?
Pode ser ou não. Depende da forma como o programador está a validar o resultado da query à base de dados.
Se o programador tivesse feito qualquer coisa deste género:


// ligação à base de dados
 mysql_connect("localhost", "root", "******")or die("cannot connect");
 mysql_select_db("junkDB")or die("cannot select DB");
 // construção da instrução sql
 $sql="S_ELECT * F_ROM utilizadores WHERE login='".$_POST["utilizador"]."' and password='".$_POST["password"]."'";
 // execução da instrução sql
 $result=mysql_query($sql);
 // variável que diz o n.º de resultados obtidos
 $count=mysql_num_rows($result);

 // se o n.º de resultados for igual a 1, então é porque os dados introduzidos
 // no formulário são válidos. Isto é, existe um utilizador com o login e password
 // iguais aos introduzidos no formulário
 if($count==1) {
    echo "Dados correctos!";
 }
 else{
    echo "Dados incorrectos!";
 }

com o código:

 xpto' or 1=1#

Só iríamos conseguir “entrar” caso existisse apenas 1 registo na tabela utilizadores.
Bastava a tabela ter dois utilizadores para já não conseguirmos “entrar”.
Ao utilizarmos o “limit 1″ estamos a dizer que só queremos 1 registo. Logo a condição ($count==1) vai ser sempre verdadeira.

Código Necessário para simular este exemplo:

Criar a tabela “utilizadores”:

--
-- Table structure for table `utilizadores`
--
C_REATE TABLE IF NOT EXISTS `utilizadores` (
 `id` int(4) NOT NULL AUTO_INCREMENT,
 `login` varchar(65) NOT NULL DEFAULT '',
 `password` varchar(65) NOT NULL DEFAULT '',
 PRIMAR Y KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=8 ;
--
-- Dumping data for table `utilizadores`
--
I_NSERT INTO `utilizadores` (`id`, `login`, `password`) VALUES
(1, 'gestor', '1234'),
(2, 'admin', '1234');

O conteúdo do ficheiro login.php é:


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Login - Security test</title>
        <style type="text/css">
            /*folha de estilos básica*/
            *{font-family:verdana; font-size:12px; color:#333;}
            form{width:400px; border:2px solid #ddd;}
            form p{font-size:14px; font-weight:bold;}}
            input{ border: solid 1px #ddd; background-color:#f5f5f5;}
            label{font-weight:bold;}
            .red{color:red;}
            .green{color:green;}
            #sql{ width:400px; background-color:#336699; color:white; padding:5px; margin:10px; text-align:left;}
        </style>
    </head>
    <body>
        <center>
<!-- formulário -->
        <form name="form1" method="post" action="login.php?action=validateUser">
            <p>Acesso Reservado</p>
            <label for="username">Utilizador:</label>
            <input name="utilizador" type="text" id="username" />
            <br />
            <label for="password">Password:</label>
            <input name="password" type="password" id="password" />
            <br />
            <input type="submit" name="Submit" value="Login" />
        </form>
<!-- // formulário -->

        <?php
// "verificar" se o formulário foi submetido e validar o utilizador
            if(isset($_POST["utilizador"]) && isset($_POST["password"]) ) {

// ligação à base de dados
mysql_connect("localhost", "root", "********")or die("cannot connect");
mysql_select_db("junkDB")or die("cannot select DB");

// construção da instrução sql
// notem que estou a utilizar os inputs directamente, sem qualquer tipo de validação.
                $sql="S_ELECT * F_ROM utilizadores WHERE login='".$_POST["utilizador"]."' and password='".$_POST["password"]."'";

// execução da instrução sql
                $result=mysql_query($sql);

// variavel que diz o n.º de resultados obtidos
                $count=mysql_num_rows($result);

// se o n.º de resultados for igual a 1, então é porque os dados introduzidos
// no formulário são válidos. Isto é, existe na base de dados UM utilizador
// com o login e password iguais aos introduzidos no formulário
                if($count==1) {
                    echo "<p class=\"green\">Dados correctos!</p>";
                }
                else{
                    echo "<p class=\"red\">Dados incorrectos!</p>";
                }
                echo "<div id=\"sql\"><b>SQL:</b><br>$sql</div>";
            }
            ?>
        </center>
    </body>
</html>

Para quem quiser aprofundar os conhecimentos sobre este tema ficam aqui alguns links muito interessantes:

Notas:
  • Este exemplo é muito simples e tem como objectivo apenas mostrar o que é o sql Injection.
  • Relativamente ao site do meu teste, de referir que enviei um e-mail aos responsáveis pelo site a avisar dos problemas de segurança, tendo corrigido de imediato os problemas e agradecido o meu aviso. Gostei :)
Testing for SQL Injection (OWASP-DV-005)

Tags: , ,

U2: One

Uma das minhas músicas preferidas :)


U2 One Live

Letra:

Is it getting better?
Or do you feel the same?
Will it make it easier on you now?
You got someone to blame
You say
One love
One life
When it’s one need
In the night
One love
We get to share it
Leaves you baby if you
Don’t care for it

Did I disappoint you?
Or leave a bad taste in your mouth?
You act like you never had love
And you want me to go without
Well it’s

Too late
Tonight
To drag the past out into the light
We’re one, but we’re not the same
We get to
carry each other
carry each other
One

Have you come here for forgiveness?
Have you come to raise the dead?
Have you come here to play Jesus?
To the lepers in your head

Did I ask too much?
More than a lot.
You gave me nothing,
Now it’s all I got
We’re one
But we’re not the same
See we
Hurt each other
Then we do it again
You say
Love is a temple
Love a higher law
Love is a temple
Love is a higher law
You ask me to enter
But then you make me crawl
And I can’t keep holding on
To what you got
When all you’ve got is hurt

One love
One blood
One life
You got to do what you should
One life
With each other
Sisters and my
Brothers
One life
But we’re not the same
We get to
Carry each other
Carry each other

One…
One…

extended version

Can You hear us coming Lord
Can You hear us call
Feel us knocking
We’re knocking at Your door

Hoje deu-me para isto :-p

Windows 7 RC – Instalar impressora HP p1005

Depois de não ter conseguido instalar a impressora HP p1005 no Windows 7 através do método tradicional, correr o install dos drivers da HP, achei outra forma de o fazer:

  1. Efectuar o download do driver (pacote completo) para o windows vista;
  2. Descompactar o Ficheiro (para isto basta correr o install e ver onde é que ele guarda os ficheiros).
    No meu caso foi em “C:\hp_LJ_P1005_P1500_Full_Solution_ROW”.
  3. Ir ao Painel de Controlo >> Impressoras;
  4. Clicar com o botão direito do rato e escolher a opção “Adicionar Impressora”;
  5. Escolher a opção “Have Disk” e faça browse até à directoria do segundo ponto;
  6. Escolha o ficheiro “hpljp1005.inf”;
  7. Escolha o modelo correcto da impressora e já está!

Nota: é provável que este truque funcione com outras impressoras Wink