Authentication Bypass Using an Alternate Path or Channel in star7th/showdoc

Valid

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 which md5sum 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
  • 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不正确");
  ...

Occurences

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不正确");

We have contacted a member of the star7th/showdoc team and are waiting to hear back 2 months ago
hi-unc1e
2 months ago

Researcher


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)
star7th
2 months ago

Maintainer


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不正确"); }

star7th validated this vulnerability 2 months ago
hi-unc1e has been awarded the disclosure bounty
The fix bounty is now up for grabs
hi-unc1e
2 months ago

Researcher


Yes, using strict comparison ===is able to fix the vuln.

star7th confirmed that a fix has been merged on 7e6b54 2 months ago
star7th has been awarded the fix bounty