Write-up CTFZone Quals 2019: Chicken

Despite postponing the conference OFFZONE 2020competition finale CTFZone to be! This year it will be held for the first time online and will be actively broadcast on social networks.

We will announce the details later, but for now we propose to study the website web-tasking from the qualifying stage. Analysis sent to us Devand maclean from Canada. Especially for “Habr” we translated text of the wright and we invite you to find out which chain of vulnerabilities the participants encountered and what does the chicken have to do with it.


general information

Author Task: Pavel Sorokin
Points: 470
Number of teams that solved the task: 2

Useful links:

Description of task

At first glance, the web application contained:

  • home page (/ Home / Index);
  • page about hens (/ Home / Hens);
  • contact page (/ Home / Contact);
  • login page (/ Auth / Login).

Later, during the analysis, the following were also discovered:

  • page for changing user password;
  • a second interface with an API for entering, recovering and changing a password.

Task Solution

The / Home / Hens page contains links to download chicken “passports”.

After decoding Base64, we find the parameter filename: 1.txt. Using CyberChef we encode / etc / passwd in Base64 and follow the link:

http://web-chicken.ctfz.one/File/Download?filename=L2V0Yy9wYXNzd2Q=

The contents of the file are opened in the browser / etc / passwd on the server, which means we get the right to read arbitrary files in the system.

When you try to find other files in the system, you may notice an error that appears every time you request a nonexistent file (or a file that cannot be read with the application user rights):

Seeing that the error refers to an environment variable ASPNETCORE_ENVIRONMENT, we are starting to learn ASP.NET Core web application layouts. And we see the following:

To convert the necessary paths and file names and extract them to Base64, we write a small Python script (fetch.py):

Using this knowledge about the structure of the MVC web application created in ASP.NET Core, using fetch.py ​​we get the source code for the following files:

  • ../Views/Shared/_Layout.cshtml
  • ../Views/Home/Index.cshtml
  • ../Views/Home/Contact.cshtml
  • ../Views/Home/Hens.cshtml
  • ../Views/Auth/Login.cshtml

Having done this and having studied the source code of each page, we find an interesting detail in Hens.cshtml

Line 1 contains the inclusion statement @ using StackHenneryMVCAppProject, which in ASP.NET means a link to a DLL file.

We open ../StackHenneryMVCAppProject.dll – but not through the Python utility in Kali Linux, but in the browser on Windows, because we are going to decompile this file in Windows. We use the following URL for this:

http://web-chicken.ctfz.one/File/Download?filename=Li4vU3RhY2tIZW5uZXJ5TVZDQXBwUHJvamVjdC5kbGw=

Opening the DLL file in dnSpy (.NET decompiler), we immediately see that in the method Initialize () class Config.Configurationthat runs when the web application starts, the contents of the file are read chicken_domains_internal.txt. Using a Python script, we extract the contents of this file:

web-chicken-flag
web-chicken-auth

Method Initialize () connects to web-chicken-flag through port 4321 and receives several parameters: secret_token, RSA_key and flag.

Unfortunately, it is not possible to initiate a connection to web-chicken-flag. But, when we set the local DNS hosts record to translate web-chicken-auth to the server’s external IP address (34.89.232.240), we manage to open http: // web-chicken-auth / with interface Swagger ui, which is used to describe and execute commands through the REST API.

After delving into the decompiled DLL file, you will notice that the controller Authcontroller was not only a method Login ()but also a method Change_Password_Test ():

When going to / Auth / Change_Password_Test we see this form:

In the study of the method Change_Password_Test () we understand that it processes four parameters of type String through an HTTP POST request:

  • username;
  • new_password;
  • old_password;
  • base_url.

A little lower in the method Change_Password_Test () see: not getting a value for base_urlmethod takes value conf.auth_server, i.e web-chicken-authand then adds / auth / login at the end of the value base_urlassigning the resulting string to a variable requestUri:

The next important part of the code is string parameter values username and old_password from the HTTP POST request, and with them secret_token from the configuration are inserted into the JSON string. Then a JSON object is created from this data. StringContentthat is sent as HTTP POST data to a variable requestURIcreated in the previous step.

Now the server is waiting for the HTTP POST request to requestUri returned a JSON object with parameter codeequal to 0. If this does not happen, we get into the code branch that starts on line 6 and returns a view / Views / Auth / Login with an error Invalid login / password.

If the HTTP POST request is still returns JSON object with parameter codeequal to 0, we go to the code branch from line 11. Then the variable requestUri2 gets value http: // web-chicken-auth, another JSON object is created StringContent with parameters from the original HTTP POST request, as in the previous part, and this data is sent to the address requestUri2 in the HTTP PUT request. Finally, a message is returned to the client Password changed.

In a nutshell: the whole process starts with an HTTP POST request to / Auth / Change_Password_Testthat expects a certain number of parameters. It takes these values ​​and creates a JSON object to send it to / auth / login via HTTP POST. If in response it receives JSON with parameter codeequal to 0 then creates another JSON object and sends an HTTP PUT request to http: // web-chicken-auth / auth / change_password.

When learning the REST API in Swagger UI, we see that in the decompiled DLL file there were more than just routes / auth / login and / auth / change_passwordbut also the route for / auth / password_recovery.

This API route expected a JSON object with two parameters: email and secret_token. If he received it, then returned a JSON object with the property codeequal to 0 and lines message and token.

It turns out that if we somehow force the method Check_Password_Test () immediately request a route / auth / password_recovery instead / auth / login, then to enter the password change branch it will be enough to enter a valid email address.

We again study the part of the code in which the method Check_Password_Test () assigns a value requestUri in the original HTTP POST request, and we understand that we need to send the value http: // web-chicken-auth / auth / password_recovery # as the base_url parameter, and requestUri will eventually get the value http: // web-chicken-auth / auth / password_recovery # / auth / login.

The # character in the HTTP URL indicates that part of the request address has ended. Therefore, the server that receives the request will simply ignore the part / auth / login.

This, of course, is good, but we just have to figure out how the REST endpoint, where we now redirect the request, will get the value email. Without this value, the request will fail, and we will not go any further.

We carefully look at how the method Check_Password_Test () creates JSON data, and we see that the input data is not cleared at all, which means that you can easily implement your parameters. It is enough to send the following parameters in the HTTP POST request:

username = admin

old_password = pwned “,” email “:” admin@chicken.ctf.zone “,” lol “:”

new_password = p0tat0

base_url = http: // web-chicken-auth / auth / password_recovery #

The resulting JSON object is sent to / auth / password_recovery:

With this JSON data, we met the requirements that / auth / password_recovery should return a response, after which the server will go into the password change branch (the JSON object contains the property email) Now value old_password we don’t need it anymore. In this code branch, we provided all the values ​​necessary to change the password (property username has the meaning admin, and the property passwordp0tat0) The request is completed, and we get Password changed in reply.

It remains only to enter a new username and password on the login page!

And here is our flag:

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *