Heap Overflow Vulnerability in Citrix NetScaler Gateway (CVE-2017-7219)

After presenting my findings on the Swisscom router at the CybSecConference last year, I started looking for a new product to analyze. I quickly found that it’s possible to download virtual “demo” appliances of Citrix products, so I went on to download a Netscaler VPX, which at the time was at version 11.10 (b50.10). The goal as always was to discover a way to compromise the device remotely, which is what led me to discover a heap overflow vulnerability which allows an authenticated user to compromise the device with root privileges. During the research, I (un)fortunately wasn’t able to find a way to exploit the flaw without credentials.


A heap overflow in the “ping” functionality allows an authenticated VPN user to trigger a use-after-free condition in order to execute arbitrary commands on the appliance. (CVE-2017-7219)

The following Metasploit module can be used to exploit the vulnerability (use at your own risk…), though it will probably only function against the version that was analyzed.


As mentioned above, I began by downloading the virtual appliance and started it up on my machine. Since I’ve never used or configured a Netscaler appliance in the past, it took a while to get things going and configuring it in some kind of standard mode.

Once the appliance is started, it is possible to log into the console with the standard nsroot account. This gives access to a “limited” shell, but Citrix were nice enough to add a shell command which gives root access to the box, so I used this to extract the filesystem and analyze what was going on.

Going through the various files on the system, I found one that seemed promising which was named /netscaler/nsvpnd. As it’s name hints at, it is used to handle requests sent to the VPN web interface. Though only authenticated requests seem to get here, as authentication itself is performed by another binary on the system.

One of the requests that is performed by the nsvpnd binary is the ping request.

This results in the following HTTP request:

POST /cvpn/aHR0cDovLzEyNy4wLjAuMQ/fs/ping HTTP/1.1
Cookie: NSC_AAAC=b2f85f0b72ef21c82eac5ac4d314a4170af182cd945525d5f4f58455e445a4a42; NSC_FSSO=0
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 41


Apparently the /cvpn/aHR0cDovLzEyNy4wLjAuMQ part of the URL is not actually required, so it can safely be removed. In any case, this request is eventually handled by one of two vulnerable functions that contain an unbounded strcpy with our host parameter, as shown below.

This is where the overflow happens, though we are not overwriting a stack variable, but one of the members of a struct, which is expected to be at most 256 bytes long. Our parameter on the other hand can go up to 512 bytes, which is what allows us to overflow this buffer.

So it is possible to write up to 256 bytes after the host member of the structure, therefore overwriting any other members of the structure after the host, which is where things get interesting. One of the following members is actually a pointer to another structure (a parameter list) on the heap which was previously allocated and eventually gets free‘d by the application when the request has completely been processed.  This means we can essentially free an arbitrary memory location.

Before going any further, a quick analysis of the system and binary show that FreeBSD uses jemalloc instead of dlmalloc, the heap is not executable, but the stack is, and ASLR is not enabled (this was 2016 after all). Another thing that was helpful in exploiting this particular issue is that all requests to the web interface are handled by one single process, which means we can actually interact many times with the process by sending multiple HTTP requests if required.

At this point, my idea to gain code execution was the following:

  1. Find a function pointer somewhere in the application, as well as the size that was used to allocate that memory
  2. Free the memory address of this function pointer
  3. On the next malloc of the appropriate size, the same address should be returned
  4. Overwrite the function pointer with user-controlled data (a pointer to my shellcode) when it is copied to this memory address
  5. Trigger the function pointer to call my shellcode

The only remaining problem is getting a shellcode to some predictable location. Thankfully, as mentioned earlier, ASLR is disabled, the stack is executable and the value we send in our host parameter is actually stored on the stack! All we need is to get this address and plug it into the function pointer to get the shellcode to execute. Obviously, despite ASLR being disabled, the stack will not always be exactly at the same place, so I used a super-l33t technique consisting of pre-pending my shellcode with lots of NOPs (because 2016).

So we can now break down each step and look at how we can achieve them:

  1. With some reverse engineering and debugging, I found one function pointer that was always allocated at address 0x2840a0c0. This function seems to be used to decode parameters sent in the HTTP requests. The memory address is initially allocated at 0x08097fb9 with a call to malloc(32).
  2. Use the overflow to overwrite the pointer to the parameter list with 0x2840a0c0. The address is then free‘d when the request has finished being processed. Here, we also need to take a note of where our host parameter is located on the stack, as this is where we will store our shellcode.
  3. While searching through the binary’s code, I found one place where a malloc is called with a length which can be specified by the VPN user directly. This is when providing the username and password to log into a SMB server. There may be other parts of the code that could be exploited in a more reliable manner, but this is the first I found and decided to go with it. The only problem is that it means we need to initiate a SMB login to a server that is accessible to the Netscaler appliance.
  4. As long as our password is between 16 and 32 characters, the previously free‘d address is returned and we can therefore overwrite the function pointer with the value of our password. It must therefore be the address of our shellcode, which we discovered was placed on the stack when performing the ping.
  5. The function pointer is actually called at regular intervals by the application while processing data, so we can just wait until it is called to get our code executed.

As you’ve probably deduced by now, in order to exploit the vulnerability, we are going to use two separate HTTP requests. The first one is used to put the shellcode on the stack and trigger the overflow, while the second is used to overwrite the function pointer with the address of our shellcode and actually execute our payload. This is summarised here:

Request 1 (ping host)

→ Start of host value contains shellcode which is conveniently placed on the stack

→ Use overflow to overwrite pointer to parameter list with 0x2840a0c0

→ When the request has been entirely processed, the program frees the address 0x2840a0c0

Request 2 (smb login)

→ Specify a password parameter of length between 16 and 32, this forces malloc to return the address that was previously freed.

→ Password value (shellcode location) overwrites function pointer that was previously located there

→ While processing the request, the overwritten function pointer is called, executing the shellcode

So that’s pretty much it. The following MSF module, should be able to exploit the flaw, but use it at your own risk. I’ve only tested it on a controlled lab environment.

For those of you who participated in our Insomni’hack teaser this year, you’ll notice many similarities with “The Great Escape – part 2” challenge, as it was very much inspired by this flaw.


  • 08.12.2016: Initial report sent to Citrix
  • 09.12.2016: Case opened by Citrix to investigate the issue
  • 14.12.2016: Vulnerability acknowledged and reproduced by Citrix team
  • February-March 2017: Rollout of fixed Netscaler versions
  • 12.04.2017: Release of security bulletin: https://support.citrix.com/article/CTX222657


Joomla! Admin user creation (3.4.4 → 3.6.3)

On October 25th, Joomla! was updated to version 3.6.4 to address two vulnerabilities :

CVE-2016-8869 concerning registration with elevated privileges.
CVE-2016-8870 concerning account creation while registration is disabled.

In this post, we wanted to quickly discuss the vulnerability and its impact on vulnerable installations.

Upon patch-diffing the two versions, we noticed that an entire method had been removed from the components/com_users/controllers/user.php file : the register method from the UsersControllerUser class.


Normally, the register method used by Joomla! is the one from the UsersControllerRegistration class, in components/com_users/controllers/registration.php.

The deleted one is most likely a leftover from old patches, and doesn’t enforce a check on whether or not user registration is enabled (as opposed to the UsersControllerRegistration.register method).

Moreover, the $data array is supposed to be sanitized in the first line below, but the unsanitized value is then used in the register function at the end of this snippet, allowing us to submit custom data such as group and uid values.


We can call this method by posting our registration values on the index.php?option=com_users&task=User.register URL.

POST /index.php?option=com_users&task=User.register HTTP/1.1
 Host: localhost
 Connection: keep-alive
 Accept-Encoding: gzip, deflate
 Accept: */*
 User-Agent: python-requests/2.11.1
 Cookie: 96b8cb33d84fb0aa459957bcad81cf90=go86e62fsve2a3jaqdmk6h6oq4
 Content-Length: 284
 Content-Type: application/x-www-form-urlencoded

user[password1]=exploit&user[username]=exploit&user[email2][email protected]&user[password2]=exploit&user[name]=exploit&user[email1][email protected]&user[groups][]=7&7c48521fa302676bada83d0e344011f2=1

The newly created user is then found on the server  :


For a valid request, we need to retrieve a CSRF Token and post it with a value = 1.

We are able to specify a custom user[id] value. If that id pre-exists in the database, the corresponding user will be overwritten during the registration.

Additionally, we can get high privileges by posting an array of user[groups][] values that will be assigned to the account. The default group id for Administrators is 7.

However, the only way to get the SuperAdmin group (8 by default) is to overwrite a pre-existing SuperAdmin user by specifying his user id.

Note that if user registration is disabled, the new/overwritten user will be blocked from logging in resulting in a denial of service for the SuperAdmin account.

In order to find and compromise a SuperAdmin account, it is possible to bruteforce all user ids and try to create a user with all possible groups. This will ensure that only the existing SuperAdmin accounts are overwritten (only the SuperAdmin ids can be overwritten to have SuperAdmin rights).

To create an admin account when the Administrator group id isn’t 7, it is possible to assign all the group ids from 1-99 (but leave the SuperAdmin group id out).

Download the PoC

Metasploit psexec resurrect

What a joy !

I just received tonight this nice email from github :

Meatballs1 merged commit 1a3b319 into  from 

My 2 years old pull request to metasploit was just accepted !

Long story short

Annoyed to have to chain msfencode and msfencode and msfencode to bypass anti-virus during penetration testing, we wanted to create some packers that do the job. Better than that, we wanted to integrate it in metasploit to use it with all the framework features and improve our performances :D.

I firstly figured it out that most of AVs detect ‘exe’ loader creation technique (from msfpayload) even if you put a “foobar” payload : echo -n “foobar” | msfencode -t exe -e generic/none => HIGH SCORE on virustotal.

I proposed “exe-only” technique. Shortly, it write the payload at the original entry-point of your exe template and put the section RWX so it reduces the loader signature to one RWX section only.

So next we could focus on the payload encoding.

For information, I scanned every native windows exe and find that ntkrnlpa.exe and ntoskrnl.exe contains RWX section (if AVs shoots files for having RWX sections, it would shoot Windows native exe too).

After some debate this exe-only technique was added to metasploit.

Next part was to use it with the famous psexec module that nobody use anymore because every AVs trigger it.

It’s simply because service executable created by psexec module use subsitution method, replacing “PAYLOAD:” with the payload in a template. Again, AVs trigger template regardless of the payload and to create a working template it was such a pain that we prefered use a “normal” executable and send it using psexec custom_exe feature…

So I wanted to use the previously merged “exe-only” technique to create a register service payload prepended to the user encoded payload.

That’s that stuff that took two years to land in Metasploit, mostly because I’m a noob in ruby and git (booo) and a little bit of scepticism from some metasploit guys.

Anyway, I’m proud it’s finally merged, you could just track it for fun :

07/09/2012 – https://dev.metasploit.com/redmine/issues/7231

14/10/2012 – https://github.com/rapid7/metasploit-framework/pull/903

19/05/2013 – https://github.com/rapid7/metasploit-framework/pull/1850

20/11/2013 – https://github.com/rapid7/metasploit-framework/pull/2657

07/06/2014 – Merged !

I hope you will re-use psexec now and I’m sure it bypass a lot of BIG AV at this moment because their sandbox executes the service PE that actually register itself to the SVC manager and exit. SVC manager then re run the PE beginning at the registered service entry-point.

It was very cool to speak with Metasploit guys and I know I would have to persevere for my next pull request !

NeDi Remote Code Execution

During a recent intrusion test, we discovered that NeDi was used in our target infrastructure. Since this application’s source code is freely available on the developer’s website (www.nedi.ch) I thought I’d have a look and see whether it would be possible to take control of a server through it.

It didn’t take too long to discover a call to PHP’s eval function in file inc/graph.php:

function drawFunction($function, $dx = 0.1) {
$xold = $x = $this->x0;
for ($x += $dx; $x <= $this->x1; $x += $dx) {
eval("$y = ".$function.";");
imageLine($this->img, $this->posX0+$xold*$this->scale,
$this->posY0-$y*$this->scale, $this->grn);
$xold = $x;
$yold = $y;

We see that parameter $function is used directly in the eval(). Where does this particular parameter come from? Well drawFunction is called from page OtherPlot.php:

$cmd = isset($_GET['cmd']) ? $_GET['cmd'] : '';
$res = isset($_GET['res']) ? $_GET['res'] : 'vga';
$xf = isset($_GET['xf']) ? $_GET['xf'] : 4;
$yf = isset($_GET['yf']) ? $_GET['yf'] : 4;
$xt = isset($_GET['xt']) ? $_GET['xt'] : 4;
$yt = isset($_GET['yt']) ? $_GET['yt'] : 4;
$f = isset($_GET['function']) ? $_GET['function'] : 'sin(30 * $x) * 1 / cos($x) / $x';
# $f='tan($x - $x * cos(pi() * $x))';

if ($cmd=="img"){
include_once ("inc/graph.php");
$graph = new FunctionGraph($xf,$yf);
$graph->drawFunction($f, 0.01);

As you can see, the parameter which is sent to the vulnerable function is taken directly from the function GET parameter.

Moreover, this particular piece of code can be called by an unauthenticated user, meaning that it is possible to execute arbitrary code (unless there is some sort of PHP hardening going on) on the web server without needing any credentials.

After discussing the issue with Remo Rickli, who wrote the application, it turns out this is a piece of legacy code which is not used any more and will be removed in future versions. For the time being, the recommendation is to remove the Other-Plot.php and inc/graph.php files from your servers (http://www.nedi.ch/nedi-news/).

Remote Command Execution in HP TippingPoint Security Management System

During a recent security audit, SCRT discovered a TippingPoint SMS server that exposed a famously exploitable JBoss invoker to any unauthenticated user. By using this invoker, it is possible to upload new applications on the server that are then run with the permissions of the JBoss application server (which happens to be running as root in this case).  The server can then be compromised entirely by uploading new files into the SMS application’s folder and then accessing them through a Web browser. This  could be done with the help of a very practical tool called jimmix which makes it possible to invoke commands on a JBoss server from the command line.

This flaw was not discovered on the latest SMS firmware at the time, as the tested version was An initial analysis of the latest version ( seemed to show that the vulnerability had been patched. But after a little digging, we discovered that this was not the case. The vulnerable invoker had only been moved to a restricted folder that now required authentication. However, the authentication mechanism was flawed (as it is in most JBoss 4 servers) and it was possible to bypass it by tampering with the HTTP verbs that are sent to the server. For example, we could access the invoker by using the HEAD method instead of GET. The vulnerability was therefore confirmed on the latest version of the SMS firmware on branches 3.5 and 3.6!

Exploitation still leads to complete root compromise of the appliance or virtual machine, making it possible to view or modify IPS protection profiles and retrieve encrypted user passwords.

The vulnerability was reported to HP who have now issued a patch for both versions 3.5 and 3.6 of their SMS firmware. The patch simply removes the handlers for the JMX invokers which can no longer be interacted with.

CVE-2013-6201 was attributed to the vulnerability and HP published a bulletin on the 4th of March about the issue : HPSBHF02965. Make sure you update your SMS servers as soon as possible.