MJHD

エモさ駆動開発

PHPのcryptに対する総当り攻撃

よく「そのぐらいの桁数だと総当りで一瞬だよ」みたいなことを聞くので,PHPのcrypt関数が生成するハッシュ値がどれほどの時間で解けるのか,試しに書いてみた.

ちなみに,このままの状態では8桁英数字(小文字のみ)となっている.
ちなみにちなみに,自分の環境では時間がかかりすぎて途中でキャンセルしたため,本当にこのスクリプトで解けるのかは謎
それと,現在は39の8乗通り試してるので,工夫すればもっと減らせる.

Brute-force attack for php's crypt


<?php

$hash = "encrypted hash";
$salt = "salt";
$digits = 8;
$thread_n = 4;

$threads = [];
for ($i = 0; $i < $thread_n; $i++) {
    $threads[$i] = new AttackThread($i, $thread_n, $hash, $salt, $digits);
    $threads[$i]->start();
}

$finished = false;
while (!$finished) {

    sleep(1);

    $finished = true;
    for ($i = 0; $i < $thread_n; $i++) {
        $finished &= !$threads[$i]->isRunning();
    }
}

echo "done\n";


class AttackThread extends Thread {
    public $id;
    public $from;
    public $to;

    private $table = ['', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'm', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
    private $char_qty;

    private $pows = [];
    private $hash;
    private $salt;
    private $digits;

    public function __construct($id, $thread_n, $hash, $salt, $digits) {
        $this->id   = $id;
        $this->hash = $hash;
        $this->salt = $salt;
        $this->digits = $digits;

        $this->char_qty = count($this->table);

        // WORK AROUND
        $pows = [];

        for ($i = 0; $i <= $this->digits; $i++) {
            $pows[] = pow($this->char_qty, $i);
        }

        $this->pows = $pows;

        $per = intval($this->pows[$this->digits]/$thread_n);
        $this->from = $per*$this->id;
        $this->to   = $per*($this->id+1);
    }

    public function run() {
        $attempt = [];

        $count = 0;
        $per   = ($this->to - $this->from) / 100;

        echo "Thread#$this->id started From:$this->from To:$this->to\n";

        for ($i = $this->from; $i < $this->to; $i++) {
        
            if (($i - $this->from) % $per == 0) {
                echo "Thread#$this->id -- $count %\n";
                $count++;
            }
        
            for ($j = 0; $j < $this->digits; $j++) {
                $attempt[$j] = $this->table[($i / $this->pows[$j]) % $this->char_qty];
            }
        
            if (crypt(implode($attempt), $this->salt) == $this->hash) {
                echo "Thread#$this->id -- Solved: ".implode($attempt)."\n";
                exit(1);
            }
        }

        echo "Thread#$this->id finished\n";

    }
}