-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathTotalCommanderPasswordDecoder.php
More file actions
123 lines (93 loc) · 2.66 KB
/
TotalCommanderPasswordDecoder.php
File metadata and controls
123 lines (93 loc) · 2.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
<?php
////////////////////////////////////////////////////////////////////////////////
//
// Total Commander FTP Password Recovery Algorithm
//
// Bartosz Wójcik
// https://www.pelock.com
//
////////////////////////////////////////////////////////////////////////////////
class TotalCommanderPasswordDecoder
{
private int $random_seed = 0;
public static function hexstr2bytearray($str)
{
if (!is_string($str)) return false;
$result = [];
$len = strlen($str);
if ($len == 0 || ($len & 1) != 0)
{
return false;
}
for ($i = 0; $i < $len; $i += 2)
{
$result[] = ( hexdec($str[$i]) << 4 ) | hexdec($str[$i + 1]);
}
return $result;
}
// initialize random generator with specified seed
public function srand($seed)
{
$this->random_seed = $seed;
}
// generate pseudo-random number from the specified seed
public function rand_max($nMax)
{
// cut numbers to 32 bit values (important)
$this->random_seed = (( ($this->random_seed * 0x8088405) & 0xFFFFFFFF) + 1) & 0xFFFFFFFF;
return ($this->random_seed * $nMax) >> 32;
}
// rotate bits left
public static function rol8($var, $counter)
{
return (($var << $counter) | ($var >> (8 - $counter))) & 0xFF;
}
// decrypt Total Commander FTP password
public function decryptPassword($password)
{
// convert hex string to array of integers
$password_hex = static::hexstr2bytearray($password);
// if the conversion failed - exit
if (!$password_hex) return false;
// number of converted bytes
$password_length = count($password_hex);
// length includes checksum at the end
if ($password_length <= 4)
{
return false;
}
// minus checksum
$password_length -= 4;
$this->srand(849521);
for ($i = 0; $i < $password_length; $i++)
{
$password_hex[ $i ] = static::rol8($password_hex[ $i ], $this->rand_max(8));
}
$this->srand(12345);
for ($i = 0; $i < 256; $i++)
{
$x = $this->rand_max($password_length);
$y = $this->rand_max($password_length);
$c = $password_hex[ $x ];
$password_hex[ $x ] = $password_hex[ $y ];
$password_hex[ $y ] = $c;
}
$this->srand(42340);
for($i = 0; $i < $password_length; $i++)
{
$password_hex[ $i ] ^= $this->rand_max(256);
}
$this->srand(54321);
for ($i = 0; $i < $password_length; $i++)
{
$password_hex[ $i ] = ($password_hex[ $i ] - $this->rand_max(256)) & 0xFF;
}
// build final password
$decoded_password = "";
for($i = 0; $i < $password_length; $i++)
{
$decoded_password .= chr($password_hex[ $i ]);
}
return $decoded_password;
}
}