hacktricks/ios-pentesting/ios-uipasteboard.md
2021-05-21 16:38:18 +00:00

81 lines
6.4 KiB
Markdown

# iOS UIPasteboard
The [`UIPasteboard`](https://developer.apple.com/documentation/uikit/uipasteboard) enables sharing data within an app, and from an app to other apps. There are two kinds of pasteboards:
* **systemwide general pasteboard**: for sharing data with **any app**. Persistent by default across device restarts and app uninstalls \(since iOS 10\).
* **custom / named pasteboards**: for sharing data **with another app** \(having the same team ID as the app to share from\) or with the **app itself** \(they are only available in the process that creates them\). Non-persistent by default \(since iOS 10\), that is, they exist only until the owning \(creating\) app quits.
Some security considerations:
* Users **cannot grant or deny permission** for apps to read the **pasteboard**.
* Since iOS 9, apps [cannot access the pasteboard while in background](https://forums.developer.apple.com/thread/13760), this mitigates background pasteboard monitoring.
* [Apple warns about persistent named pasteboards](https://developer.apple.com/documentation/uikit/uipasteboard?language=objc) and **discourages their use**. Instead, shared containers should be used.
* Starting in iOS 10 there is a new Handoff feature called **Universal Clipboard** that is enabled by default. It allows the **general pasteboard contents to automatically transfer between devices**. This feature can be disabled if the developer chooses to do so and it is also possible to set an expiration time and date for copied data.
Then, it's important to **check that sensitive information isn't being saved inside the global pasteboard**.
It's also important to check that an **application isn't using the global pasteboard data to perform actions**, as malicious application could tamper this data.
An **application can also prevent its users to copy sensitive data to the clipboard** \(which is recommended\).
### Static Analysis
The **systemwide general pasteboard** can be obtained by using [`generalPasteboard`](https://developer.apple.com/documentation/uikit/uipasteboard/1622106-generalpasteboard?language=objc), search the source code or the compiled binary for this method. Using the systemwide general pasteboard should be avoided when dealing with sensitive data.
**Custom pasteboards** can be created with [`pasteboardWithName:create:`](https://developer.apple.com/documentation/uikit/uipasteboard/1622074-pasteboardwithname?language=objc) or [`pasteboardWithUniqueName`](https://developer.apple.com/documentation/uikit/uipasteboard/1622087-pasteboardwithuniquename?language=objc). Verify if custom pasteboards are set to be persistent as this is deprecated since iOS 10. A shared container should be used instead.
### Dynamic analysis
Hook or trace the following:
* `generalPasteboard` for the system-wide general pasteboard.
* `pasteboardWithName:create:` and `pasteboardWithUniqueName` for custom pasteboards.
You can also Hook or trace the deprecated [`setPersistent:`](https://developer.apple.com/documentation/uikit/uipasteboard/1622096-setpersistent?language=objc) method and verify if it's being called.
When **monitoring** the **pasteboards**, there is several **details** that may be dynamically **retrieved**:
* Obtain **pasteboard name** by hooking `pasteboardWithName:create:` and inspecting its input parameters or `pasteboardWithUniqueName` and inspecting its return value.
* Get the **first available pasteboard item**: e.g. for strings use `string` method. Or use any of the other methods for the [standard data types](https://developer.apple.com/documentation/uikit/uipasteboard?language=objc#1654275).
* Get the **number of items** with `numberOfItems`.
* Check for **existence of standard data types** with the [convenience methods](https://developer.apple.com/documentation/uikit/uipasteboard?language=objc#2107142), e.g. `hasImages`, `hasStrings`, `hasURLs` \(starting in iOS 10\).
* Check for **other data types** \(typically UTIs\) with [`containsPasteboardTypes:inItemSet:`](https://developer.apple.com/documentation/uikit/uipasteboard/1622100-containspasteboardtypes?language=objc). You may inspect for more concrete data types like, for example an picture as public.png and public.tiff \([UTIs](http://web.archive.org/web/20190616231857/https://developer.apple.com/documentation/mobilecoreservices/uttype)\) or for custom data such as com.mycompany.myapp.mytype. Remember that, in this case, only those apps that _declare knowledge_ of the type are able to understand the data written to the pasteboard. Retrieve them using [`itemSetWithPasteboardTypes:`](https://developer.apple.com/documentation/uikit/uipasteboard/1622071-itemsetwithpasteboardtypes?language=objc) and setting the corresponding UTIs.
* Check for excluded or expiring items by hooking `setItems:options:` and inspecting its options for `UIPasteboardOptionLocalOnly` or `UIPasteboardOptionExpirationDate`.
If only looking for strings you may want to use **objection's** command `ios pasteboard monitor`:
> Hooks into the iOS UIPasteboard class and polls the generalPasteboard every 5 seconds for data. If new data is found, different from the previous poll, that data will be dumped to screen.
You may also build your own pasteboard monitor that monitors specific information as seen above.
For example, this script \(inspired from the script behind [objection's pasteboard monitor](https://github.com/sensepost/objection/blob/b39ee53b5ba2e9a271797d2f3931d79c46dccfdb/agent/src/ios/pasteboard.ts)\) reads the pasteboard items every 5 seconds, if there's something new it will print it:
```javascript
const UIPasteboard = ObjC.classes.UIPasteboard;
const Pasteboard = UIPasteboard.generalPasteboard();
var items = "";
var count = Pasteboard.changeCount().toString();
setInterval(function () {
const currentCount = Pasteboard.changeCount().toString();
const currentItems = Pasteboard.items().toString();
if (currentCount === count) { return; }
items = currentItems;
count = currentCount;
console.log('[* Pasteboard changed] count: ' + count +
' hasStrings: ' + Pasteboard.hasStrings().toString() +
' hasURLs: ' + Pasteboard.hasURLs().toString() +
' hasImages: ' + Pasteboard.hasImages().toString());
console.log(items);
}, 1000 * 5);
```
## References
{% embed url="https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06h-testing-platform-interaction\#testing-object-persistence-mstg-platform-8" %}