Exploiting RCE vulnerability in Bassmaster

Tram Ho

Want to learn something new is really not difficult but just too hard. And it also depends on the investigator himself, the difficulty of the problem to be investigated and many other objective factors. So the only way is to go into it, find out until you understand the problem

Bassmaster too, at first I don’t understand anything at first, but just read, study and practice then finally understand. Actually, at first I didn’t know what bassmaster was, if I didn’t study and do OSWE lab, I wouldn’t touch it. When searching on bassmaster on google, I can’t find it anywhere, but I have to search with bassmaster github keyword to see. In the article, we will analyze why the bassmaster has an RCE error and practice exploitation after understanding the problem.

When learning new technology, what is the first thing? And for what?

Bassmaster makes it easy to combine requests into a single one. It also supports pipelining, allowing you to take the result of one query in the batch request and use it in a subsequent one. The batch endpoint only responds to POST requests.

Above is the bassmaster’s self-introduction. In short, the bassmaster allows us to make multiple requests in one request. I just imagine that instead of giving chopsticks one by one, I give the whole bunch of chopsticks to others.

Find the RCE error

Bassmaster code is in nodejs and in version 1.5.1 there exists a RCE vulnerability that allows attackers to execute arbitrary code on the server. Since the source is available, we will go into the code analysis to find the vulnerability. As mentioned above, the bassmaster code is using nodejs so we’ll be looking for the functions we can use to execute the code on the server as eval . The simplest way to find dangerous functions is to use grep to search.

As the results above, we see some suspicious results but we see the first result is the most suspicious. Hence, we will go into the ./lib/batch.js file section and will start on line 152 .

The eval function is in the TRUE branch of the if..else statement, so if you want to execute this function, you need to know when the program goes into the TRUE branch. Notice that internals.batch is assigned by the eval command, so we trace the code back to see if there is any place calling internals.batch . When going back up, we immediately see the call to internals.batch in the following code

The place to call internals.batch is internals.process , we continue to trace to find out where to call internals.process . After going up a bit, we can see the call to internals.process in module.exports.config.

We notice that in order to be able to call internals.process , the errorMessage must be null . The errorMessage variable is assigned in the loop when the error is detected and in the parseRequest function when the URL is invalid. In the for loop that calls the replace function with 2 parameters, the first parameter is pattern, the second parameter is the function to process after matching the string with pattern.

The replace function

To better understand the program’s execution flow, we need to better analyze the behavior of the replace function. Especially the case that the 1st parameter is a regex string and the 2nd parameter is a function. After reading the documentation on this function on the MDN ( link ), immediately realize that the passed function will be called after the initial match with the regex string and the result will be passed to the parameter through the function’s parameters. .

You can specify a function as the second parameter. In this case, the function will be invoked after the match has been performed. The function’s result (return value) will be used as the replacement string.

Note that the function will be invoked multiple times for each full match to be replaced if the regular expression in the first parameter is global.

The parameters passed to the function are described in the following table

The bassmaster’s code

Compare with the above table we can understand the meaning of the parameters: $ 0 , $ 1 , $ 2

  • $ 0 : The entire string matches regex
  • $ 1 : string group 1
  • $ 2 : string group 2

Notice the parseRequest function, this is the last function that assigns the value type: ‘ref’ to the result and is a condition that evaluates the eval function.

To be able to add type: ‘ref’ then $ 1 must be non- null , where $ 1 is group 1 of regex. When we pass the data below, $ 1 will be non- null

After adding the type: ‘ref’ and parts, we can now execute the eval function.

value is assigned $ 2 (which is group 2 of regex) above. When we pass /item/$1.id , the value here is id

Regex use is not tight

Bassmaster used regex to filter out valid paths. But this Regex is not tight enough, allowing the user to bypass from there to be able to execute arbitrary code on the server. Hence we will go into analyzing the pattern that the bassmaster used.

The purpose of the regex above is clearly stated in the source code

/project/$1.project/tasks, does not allow using array

The data is sent to the server in the json format and looks like this (sample from the file example / batch.js )

As mentioned above, if we pass, the eval function will take the string id as the argument.

The problem is that if we insert other values, we can execute arbitrary code. In javascript, the separator holds the statements we use semicolon ( ; ) so we will use it to bypass regex from which we can execute the javascript code.

With the above javascript code you can bypass regex and perform the reverse shell.

Using the exploit code above successfully created the reverse shell.

Share the news now

Source : Viblo