thedigicraft / Atom.CMS

Atom.CMS
56 stars 52 forks source link

Sql Injection in /admin/login.php #255

Closed jsjbcyber closed 1 year ago

jsjbcyber commented 2 years ago

In /admin/login.php:

<?php ..... if($_POST) { $q = "SELECT * FROM users WHERE email = '$_POST[email]' AND password = SHA1('$_POST[password]')"; $r = mysqli_query($dbc, $q); ..... ?>

When logging in at the background, you can log in at the background with the wrong password and account by the method of post. post: /admin/login.php email=alan@alan.com'or '1'='1&password=123。 then, I can log in to the system with the wrong password

creptor commented 2 years ago

This project is just to get started and learn how to create web pages with php. I do not recommend an exact copy of this site to be used in production due to the many error the site has, like the one you have mentioned.

That said, to mitigate SQL injections you could replace the connection to the database and use PDO. It involves changes on many things but it should work for avoiding these injection issues with ease. Link to manual.

I'll try to post an example of some code I found, but give me some time.

jsjbcyber commented 2 years ago

OK

creptor commented 2 years ago

I didn't find the exact page where it was very well explained, but you should be able to find multiple sources with more information on how to implement PDO.

To get you started you could look to this implementation that I used a while back... Maybe you could search with some of this code how to do certain stuff.

For a working login example, you need to use the following code:

  1. Database conection
// database configuration
Config::write_db('db.system','mysql');
Config::write_db('db.host','127.0.0.1');
Config::write_db('db.port','3306');
Config::write_db('db.basename','xxxx');
Config::write_db('db.user','xxxx');
Config::write_db('db.password','xxxx');
  1. Class for storing site configuration:
// Config class for Core
class Config {
    private static $database_conf;

    protected static function read_db($name) {
        return self::$database_conf[$name];
    }

    public static function write_db($name, $value) {
        self::$database_conf[$name] = $value;
    }

    //private function __construct() { }

}// Config class END
  1. Class for creating and using the PDO connection:

    // Core class, will be called for database connection and user data
    class Core extends Config {
    public $db,$user;
    private static $instance;
    
    private function __construct() {
        // building data source name from config
    $dsn = Config::read_db("db.system").":host=".Config::read_db("db.host").";dbname=".Config::read_db("db.basename").";port=".Config::read_db("db.port").";connect_timeout=15";
        // getting DB user from config                
        $user = Config::read_db("db.user");
        // getting DB password from config                
        $password = Config::read_db("db.password");
    
    //Check connection to database
    try{
            $this->db = new PDO($dsn, $user, $password);
    } catch (PDOException $e) {
            echo $e->getMessage();
        die;
    } catch (Exception $e) {
            echo $e->getMessage();
        die;
        }
    }
    
    public static function getInstance() {
    //Checks if the new class exists or creates it
        if(!isset(self::$instance)) {
            $object = __CLASS__;
            self::$instance = new $object;
        }
        return self::$instance;
    }
    }
  2. Function of login implementation:

    //user_handler
    function login ($email=null, $password=null) {
    if($_POST['email'] == null || $_POST['password'] == null) {
    return(alert('warning', 'No se ingresaron todos los datos.', true));
    }
    
    $email = filter_var($_POST['email'], FILTER_SANITIZE_EMAIL);
    
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        return(alert('warning', 'Correo invalido.', true));
    } else {
        $conn = Core::getInstance()->db->prepare('SELECT password, id FROM users WHERE email = ?');
        $conn->bindParam(1, $email,PDO::PARAM_STR);
        $conn->execute();
        if($conn->rowCount() == 1) {
            $data = $conn->fetch(PDO::FETCH_ASSOC);
            if(password_verify($password, $data['password'])) {
                $_SESSION['user_id'] = $data['id'];
            } else {
                return(alert('warning', 'Los datos son incorrectos.', true));
            }
    } else {
            return(alert('warning', 'Los datos son incorrectos.', true));
        }
    }
    }
  3. Complementary functions:

    function alert($type, $msg, $close = false){
    if($close == true) {
        return '<div class="alert alert-'.$type.' alert-dismissible fade show" role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>'.$msg.'</div>';
    } else {
        return '<div class="alert alert-'.$type.'">'.$msg.'</div>';
    }
    }
jsjbcyber commented 2 years ago

OK. I'll try it.

creptor commented 2 years ago

I just noted that the example provided was not complete.

I edited the comment above to include the missing pieces of code.

v-dumitrescu commented 1 year ago

The branch "AtomCMS-2.1" contains security fixes.