Hacking

Fail-Open Authentication in IT Security

Jaideep Jha
January 11, 2012 by
Jaideep Jha

Authentication: Fail-Open

FREE role-guided training plans

FREE role-guided training plans

Get 12 cybersecurity training plans — one for each of the most common roles requested by employers.

FREE role-guided training plans

FREE role-guided training plans

Get 12 cybersecurity training plans — one for each of the most common roles requested by employers.

What do you mean by Fail-Open authentication?

Fail-open authentication is the situation when the user authentication fails but results in providing open access to authenticated and secure sections of the web application to the end user.

What is the impact when authentication does not fail securely?

Users can bypass authentication and gain access to authenticated section of the web application.

  • Failure modes should not result in successful authentication
  • All unauthenticated decision must result in LOGOUT

What are the conditions that trigger Fail-Open authentication?

The following conditions need to be met:

  1. A server side variable value is set. This authentication decision for the rest of the pages in the web application is made on the basis of the value of this variable.
  2. The provided user input (username/password) triggers an exception. Since the control directly passes to the exception handler and bypasses the code that handles failed authentication, users are able to access the unauthenticated section, as the server variable had already been set.

 

Case Study – Demo

1. Submit login request by filling arbitrary username and password:

2. Intercept the request in the proxy and remove the parameter value =dsf of parameter Text1

 

3. This results in an exception and a message – "Something went wrong" – is displayed.

4. Immediately after this, try accessing any of the internal pages – say PageA.aspx

You will notice that the user is able to access a protected page even though the user was not successfully authenticated.

Code Analysis


protected

void Button1_Click(object sender, EventArgs e)

{

try

{

SqlCommand scmd1;

SqlConnection scon1;

SqlDataReader dr1;

string constr1;

//bool login = true;

constr1 = ConfigurationManager.ConnectionStrings["mydbconn"].ConnectionString;

scon1 = new
SqlConnection(constr1);

scmd1 = new
SqlCommand("select * from Users where userid = '" + Text1.Text + "' and password='" + TextBox1.Text + "'", scon1);

scon1.Open();

dr1 = scmd1.ExecuteReader();

Session["login"] = true;

string x = Request.QueryString["Text1"];

ViewState.Add("user", x);

ViewState.Add("userlen", x.Length);

if (dr1.Read())

{

FormsAuthentication.RedirectFromLoginPage(Text1.Text, false);

}

else

{

Session["login"] = false;

FormsAuthentication.SignOut();
}

dr1.Close();

scon1.Close();

}

catch (Exception ne)

{

L4.Text = "Something went Wrong !";

}

}

The above listed lines of code represent the authentication logic. The lines shaded in yellow:

  1. Create SQL connection and execute SQL command. SQL command gets the request parameters and constructs SQL query to fetch record from the database.
  2. Since we had removed the value from Text1 parameter, the SQL query would look like:

    Select * from Users where userid='' and password='asfasf'

This query would not fetch any record from the database

  1. The line shaded in green:

    sets the session variable "login" to true. This is important, as this session variable is set before the check for valid database record fetch is made.

  2. The lines shaded in turquoise:

    Gets the username parameter in the query string, and add the string and string length to the viewstate. In our case, the line

string x = Request.QueryString["Text1"];

     ViewState.Add("user", x);

    ViewState.Add("userlen", x.Length);

results in Null Exception, since we had removed the parameter value from the Text1 request parameter in the query string. The control now passes directly to the exception handler in the catch block, which prints the "Something went wrong!" message.

  1. The lines shaded in blue:

    Here, if there is any record present in the user table with matching username and password as provided in the request, would lead to successful authentication, and a Form Authentication Ticket cookie will be set and the user would be redirected to the homepage.

  2. The lines shaded in grey:

    If there are no records in the user table with matching username and password as provided in the request, this means that the authentication has failed and the a Form Authentication Ticket cookie is removed and the "login" session variable is set to false.

I would like to elaborate a bit on point 3: the importance of the location of the "login" session variable. In the normal course of things, this is not very significant. Valid username/password conditions will result in successful authentication and the code shaded in blue will be executed as explained in point 5. In the case of invalid credentials, the code shaded in grey will be executed and the "login" session variable will be removed. The location of

Session["login"] = true;

becomes important only when an exception condition occurs. The code relevant to unsuccessful authentication is not executed and control directly lands in the catch block. So, when an exception happens (which gets triggered on execution of lines shaded in turquoise), the login session variable is already set.

The login session variable is used on the internal pages to enforce authentication. As the login session variable is already set to true value, when the exception is raised (and not reset back to false value in the exception handler catch block), the authentication check on all the protected internal pages will succeed.

Mitigation

All sections of the codebase, wherever authentication or access control related decisions are made, ensure that the exception handler in those sections of code nullify all artifacts based on which authentication or access control related decisions are made. In case of our example scenario, the line of code that deals with failed authentication should be included in the catch block, like this:


protected

void Button1_Click(object sender, EventArgs e)

{

try

{

SqlCommand scmd1;

SqlConnection scon1;

SqlDataReader dr1;

string constr1;


//bool login = true;

constr1 = ConfigurationManager.ConnectionStrings["mydbconn"].ConnectionString;

scon1 = new
SqlConnection(constr1);

scmd1 = new SqlCommand("select * from Users where userid = @uid and password= @pwd", scon1);

scon1.Open();

scmd1.Parameters.AddWithValue("@uid", Text1.Text);

scmd1.Parameters.AddWithValue("@pwd", TextBox1.Text);

Session["login"] = true;

string x = Request.QueryString["Text1"];

ViewState.Add("user", x);

ViewState.Add("userlen", x.Length);

if (dr1.Read())

{

FormsAuthentication.RedirectFromLoginPage(Text1.Text,false);
}

else

{

Session["login"] = false;

FormsAuthentication.SignOut();

}

dr1.Close();

scon1.Close();

}

catch (Exception ne)

{

Session["login"] = false;

FormsAuthentication.SignOut();

L4.Text = "Something went Wrong !";
}

FREE role-guided training plans

FREE role-guided training plans

Get 12 cybersecurity training plans — one for each of the most common roles requested by employers.

FREE role-guided training plans

FREE role-guided training plans

Get 12 cybersecurity training plans — one for each of the most common roles requested by employers.

}

Jaideep Jha
Jaideep Jha

Jaideep is a researcher for InfoSec Institute, as well as an Information Security Professional, with 6 years of experience doing application source code reviews and web application penetration testing. The best part of his day job is that it provides him with opportunities to understand the working and interactions of complex information systems.

He likes creating tools in Python and Perl.