Our goal in this challenge is to bypass a logging page to get the flag. Moving
the mouse over the web page, we found a link to admin.php page, the source
code of this page was provided to us.

Navigating to admin.php page, we see a login page where we are prompted to
provide the correct username, password and hmac for a valid logging.  
Looking into the source code, a flag.inc.php page is included to get the value
of the variables: `$secret`, `$password` and `$flag`, obviously cause these
variable were not defined anywere in the admin.php sorce code.

the first check, test if all the POST variables: username, password, hmac and
nonce are not empty (nonce is a random value generated each time we refresh
the page, and it is sended back once we submit our request), we can easily
validate this check.  
```  
if (!empty($_POST['username']) && !empty($_POST['password']) &&  
!empty($_POST['hmac']) && !empty($_POST['nonce']))  
{  
```

The next check, test if the username is 'admin" and password equal to
`$password` and hmac equal to `$hmac`:  
```  
if (strcmp($_POST['username'], "admin") == 0 &&  
strcmp($_POST['password'], $password) == 0 &&  
$_POST['hmac'] === $hmac)  
```

Let's decompose this into three checks and bypass each one individually (for
this purpose we can setup a web site locally with the admin.php code, and
modify it so that we can test each check individually):

\- We can simply set username to "admin" to pass the first condition.  
  
\- To validate the password, the website check if the user provided password
equal to the one defined in flah.inc.php file, this is done by using strcmp
function and check if the returned value equal to 0, strcmp return 0 if both
string match, as per [user
note](https://www.php.net/manual/en/function.strcmp.php#108563) in php Docs of
this function: strcmp returns 0 in some cases where the variables being
compared are of different types, for example a string and an array will return
0.  
So to bypass this check without knowing the `$password` value we can simply
set the user password as an array.  
  
\- The admin page override the `$secret` value with the sha256 hmac of
`$nonce` using `$secret` as key ($secret was firstly defined in flag.inc.php
page): `$secret = hash_hmac('sha256', $_POST['nonce'], $secret);`.  
Then it set `$hmac` var with the calculated value of sha256 hmac of
"admin"(username) using the new `$secret` value as key: `$hmac =
hash_hmac('sha256', $_POST['username'], $secret);`.  
And it check if the user hmac match the `$hmac` variable (here also the type
is checked): `$_POST['hmac'] === $hmac`  
As per the below test, if we try to calculate the hmac of an array we got a
warning and the variable taking the output of hmac is defined with an empty
string:  
```  
php > echo $secret;  
PHP Notice: Undefined variable: secret in php shell code on line 1  
php > $secret = hash_hmac('sha256', [], 'secret');  
PHP Warning: hash_hmac() expects parameter 2 to be string, array given in php
shell code on line 1  
php > echo $secret;  
php >  
```  
So to bypass this check without knowing the `$secret` value we can set
`$nonce` as an array, which will result in an empty string, assigned to
`$secret`, at this point we can simply calculate the hmac of "admin" with an
empty string as key which will be used as user hmac in our request:  
```  
php > echo hash_hmac('sha256', 'admin', '');  
8d5f8aeeb64e3ce20b537d04c486407eaf489646617cfcf493e76f5b794fa080  
php >  
```  
So now, let us join all the pieces together to construct out final payload:  
```  
[Pwn17@machine ~]$ curl -X POST http://challenges.uactf.com.au:30002/admin.php
-d
"username=admin&password[]=admin&hmac=8d5f8aeeb64e3ce20b537d04c486407eaf489646617cfcf493e76f5b794fa080&nonce[]=c0ab90748f754cdd53a4a2ad1e780500"  
```

With the above request, we can pass the checks and get the flag.