mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-20 10:03:51 +00:00
79 lines
6.3 KiB
Markdown
79 lines
6.3 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" %}
|
|
|