Authentication Bypass Using an Alternate Path or Channel in star7th/showdoc
Reported on
Oct 13th 2021
Firstly, I would say to the dev, your application Showdoc is good to use, and I will keep an eye on it, continuously improving the safety of it. Then, I would also thank the staff in huntr.dev, your quick response impressed me a lot.
Good to work with you enthusiastic people.
Description
Since PHP has a feature like this,
<?php
// $token == $new_token
var_dump( "0e123123" == "0e6666"); //(bool)true
- So-called
PHP Type Juggling
(弱类型,in ZH-CH) - there're lots of related
Magic Hashes
,at spaze/hashes/blob/master/md5.md,in whichmd5sum
seems to satisfy==
in PHP
Affected codes are at server/Application/Api/Controller/ExtLoginController.class.php#L22
public function bySecretKey(){
$username = I("username") ;
$key = I("key") ;
$time = I("time") ; //【1】the hardest part is to brute force a "VALID" Timestamp
$token = I("token") ; // eg: '0e1'
$redirect = I("redirect") ;
if($time < (time() - 60) ){
$this->sendError(10101,"已过期");
return ;
}
$login_secret_key = D("Options")->get("login_secret_key") ;
if(!$login_secret_key) return false ;
$new_token = md5($username.$login_secret_key.$time);
if($token != $new_token){ //【2】 unsafe comparison, should use hash_equals() instead, see https://www.php.net/manual/zh/function.hash-equals.php
$this->sendError(10101,"token不正确");
return ;
}
Mathematical Proof
- Probability:
(10÷16)^30
=7.5231638452626400509999138382224e-7
While trying to use https://3v4l.org/DBlsO , despite I found No solution til now
[989‰]
[990‰]
[991‰]
[992‰]
[993‰]
[994‰]
[995‰]
[996‰]
[997‰]
[998‰]
[999‰]
...
Also,!=
expression in Hash-Compare is vulnerable to timing attack, see https://wiki.php.net/rfc/timing_attack
Theoretical PoC
Here is a **theoretical PoC, **
Once an attacker could keep requesting,with numerous valid timestamp($time
), one day he/she will find a possible solution, i.e.0e1122334455..
like this.
a possible HTTP request
GET /server/?s=/api/extLogin/bySecretKey&username=test_user&time=1694133952&token=0e1&redirect= HTTP/1.1
Host: showdoc
HTTP Response will be like
HTTP/1.1 302 Found
Date: Wed, 13 Oct 2021 14:32:21 GMT
Server: Apache/2.4.39 (Win64) OpenSSL/1.1.1b mod_fcgid/2.3.9a mod_log_rotate/1.02
X-Powered-By: PHP/7.3.4
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Set-Cookie: cookie_token=b33e8003a0334e0ef1818c4715eccaf066a864da5fcf3926ef2284d824d62ec2; expires=Mon, 11-Apr-2022 14:32:21 GMT; Max-Age=15552000; path=/; HttpOnly
location: /
Content-Length: 0
Connection: close
Content-Type: text/html; charset=UTF-8
Impact
This vulnerability is capable of
- Login arbitrary existing account
- Limit:due to the restriction in ExtLoginController.class.php#L35, we CANNOT login the admin account, i.e.
showdoc
- Limit:due to the restriction in ExtLoginController.class.php#L35, we CANNOT login the admin account, i.e.
- Register unlimtedly, bypass CAPTCHA
- We could register unlimited account without using CAPTCHA
Suggestion
For https://github.com/star7th/showdoc/blob/master/server/Application/Api/Controller/ExtLoginController.class.php#L22, a possible patch is like:
$new_token = md5($username.$login_secret_key.$time);
if(hash_equals(string $new_token, string $token)){
$this->sendError(10101,"token不正确");
...
Occurrences
ExtLoginController.class.php L22
should use hash_equals, possible version is like
$new_token = md5($username.$login_secret_key.$time);
if(hash_equals(string $new_token, string $token)){
$this->sendError(10101,"token不正确");
I wanna add extra info, sorry for the interruption:
- CWE-288:Authentication Bypass Using an Alternate Path or Channel
- Credit:Qianxin, Network Security Department, Product-Safety Team ( Unc1e )
- CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:L/A:L / CVSS Score:6.0(medium)
Will it work if I change it to this ?Because I want to use some syntax compatible with the old version of PHP.
if( !($token === $new_token) ){ $this->sendError(10101,"token不正确"); }