Skip to content
72 changes: 72 additions & 0 deletions demos/ios/MASVS-CRYPTO/MASTG-DEMO-0068/MASTG-DEMO-0068.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
platform: ios
title: Uses of Broken Encryption Modes in CommonCrypto with r2
code: [swift]
id: MASTG-DEMO-0068
test: MASTG-TEST-0304
---

### Sample

The snippet below shows sample code that uses the insecure ECB (Electronic Codebook) mode when encrypting data with CommonCrypto's `CCCrypt` function. ECB mode is vulnerable because it encrypts identical plaintext blocks to identical ciphertext blocks, revealing patterns in the data.

{{ MastgTest.swift # function.asm # decompiled-o1-review.swift }}

### Steps

1. Unzip the app package and locate the main binary file (@MASTG-TECH-0058), which in this case is `./Payload/MASTestApp.app/MASTestApp`.
2. Open the app binary with @MASTG-TOOL-0073 with the `-i` option to run this script.

{{ ccecb.r2 }}

{{ run.sh }}

### Observation

The output contains the disassembled code for the `CCCrypt` function in ECB mode.

{{ output.asm }}

### Evaluation

Inspect the disassembled code to identify the use of insecure encryption modes.

In [CommonCryptor.h](https://web.archive.org/web/20240606000307/https://opensource.apple.com/source/CommonCrypto/CommonCrypto-36064/CommonCrypto/CommonCryptor.h), you can find the definition of the `CCCrypt` function:

```c
CCCryptorStatus CCCrypt(
CCOperation op, /* kCCEncrypt, etc. */
CCAlgorithm alg, /* kCCAlgorithmAES128, etc. */
CCOptions options, /* kCCOptionPKCS7Padding, kCCOptionECBMode, etc. */
const void *key,
size_t keyLength,
const void *iv, /* optional initialization vector */
const void *dataIn, /* optional per op and alg */
size_t dataInLength,
void *dataOut, /* data RETURNED here */
size_t dataOutAvailable,
size_t *dataOutMoved);
```

There you will also find the `options` parameter, which can include `kCCOptionECBMode`:

```c
/*!
@enum CCOptions
@abstract Options flags, passed to CCCryptorCreate().

@constant kCCOptionPKCS7Padding Perform PKCS7 padding.
@constant kCCOptionECBMode Electronic Code Book Mode.
Default is CBC.
*/
enum {
kCCOptionPKCS7Padding = 0x0001,
kCCOptionECBMode = 0x0002,
};
typedef uint32_t CCOptions;
```

With this information, we can now inspect the disassembled code and, in particular, the third argument of the `CCCrypt` function (`w2`), which has a numeric value `3`. Since there is no enum value `3`, we derive that both `kCCOptionPKCS7Padding` with value `1` and ECB mode option (`kCCOptionECBMode`) with value `2` are set, as `1+2=3`.
Therefore, the `CCCrypt` function is called with the ECB mode option, AES algorithm, and a key of 16 bytes:

The test fails because ECB mode was found in the code.
Binary file added demos/ios/MASVS-CRYPTO/MASTG-DEMO-0068/MASTestApp
Binary file not shown.
37 changes: 37 additions & 0 deletions demos/ios/MASVS-CRYPTO/MASTG-DEMO-0068/MastgTest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import SwiftUI
import CommonCrypto

struct MastgTest {
static func mastgTest(completion: @escaping (String) -> Void) {
let key = "0123456789abcdef" // 16-byte key for AES-128
let data = "This is a sample text for ECB mode testing!".data(using: .utf8)!

// Create a buffer for encrypted data
var encryptedBytes = [UInt8](repeating: 0, count: data.count + kCCBlockSizeAES128)
var numBytesEncrypted: size_t = 0

let cryptStatus = data.withUnsafeBytes { dataBytes in
key.withCString { keyBytes in
CCCrypt(
CCOperation(kCCEncrypt),
CCAlgorithm(kCCAlgorithmAES), // AES Algorithm
CCOptions(kCCOptionECBMode | kCCOptionPKCS7Padding), // ECB Mode (INSECURE!)
keyBytes, kCCKeySizeAES128,
nil,
dataBytes.baseAddress, data.count,
&encryptedBytes, encryptedBytes.count,
&numBytesEncrypted
)
}
}

if cryptStatus == kCCSuccess {
let encryptedData = Data(bytes: encryptedBytes, count: numBytesEncrypted)
let encryptedHex = encryptedData.map { String(format: "%02hhx", $0) }.joined()
let value = "Original:\n\n \(String(data: data, encoding: .utf8)!)\n\nEncrypted with ECB mode (Hex):\n \(encryptedHex)"
completion(value)
} else {
completion("Encryption failed with status: \(cryptStatus)")
}
}
}
16 changes: 16 additions & 0 deletions demos/ios/MASVS-CRYPTO/MASTG-DEMO-0068/cccrypt-ecb.r2
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
e asm.bytes=false
e scr.color=false
e asm.var=false

?e Uses of the CCCrypt function:
afl~CCCrypt

?e

?e xrefs to CCCrypt:
axt @ 0x1000075ec
?e

?e Use of CCCrypt with ECB mode:
# Seek to the function where CCCrypt is called with ECB mode
pd-- 7 @ 0x100004824
142 changes: 142 additions & 0 deletions demos/ios/MASVS-CRYPTO/MASTG-DEMO-0068/function.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
; CALL XREFS from sym.func.100004888 @ 0x1000049e0(x), 0x100004aa8(x), 0x100004afc(x)
┌ 492: sym.func.10000469c (int64_t arg1, int64_t arg2, int64_t arg3, int64_t arg4, int64_t arg5, int64_t arg6, int64_t arg7, int64_t arg8, int64_t arg_20h, int64_t arg_d0h);
│ 0x10000469c sub sp, sp, 0xd0
│ 0x1000046a0 stp x27, x26, [var_80h]
│ 0x1000046a4 stp x25, x24, [var_90h]
│ 0x1000046a8 stp x23, x22, [var_a0h]
│ 0x1000046ac stp x20, x19, [arg_20h]
│ 0x1000046b0 stp x29, x30, [var_c0h]
│ 0x1000046b4 add x29, sp, 0xc0
│ 0x1000046b8 mov x19, x21
│ 0x1000046bc mov x20, x2 ; arg3
│ 0x1000046c0 mov x2, x0 ; arg1
│ 0x1000046c4 stp x20, x3, [arg_d0hx30] ; arg4
│ 0x1000046c8 stp x4, x5, [arg_d0hx40] ; arg6
│ 0x1000046cc stp x6, x7, [arg_d0hx50] ; arg8
│ ┌─< 0x1000046d0 tbnz x1, 0x3c, 0x100004848
│ │ 0x1000046d4 mov x22, x7
│ │ 0x1000046d8 mov x23, x6
│ ┌──< 0x1000046dc tbnz x1, 0x3d, 0x1000046fc
│ ┌───< 0x1000046e0 tbz x2, 0x3c, 0x100004848
│ │││ 0x1000046e4 lsr x8, x5, 0x3e
│ │││ 0x1000046e8 cmp w8, 1
│ ┌────< 0x1000046ec b.gt 0x100004734
│ ┌─────< 0x1000046f0 cbnz w8, 0x1000047a8
│ │││││ 0x1000046f4 ubfx x24, x5, 0x30, 8
│ ┌──────< 0x1000046f8 b 0x1000047c0
│ ││││││ ; CODE XREF from sym.func.10000469c @ 0x1000046dc(x)
│ ││││└──> 0x1000046fc and x8, x1, 0xffffffffffffff
│ ││││ │ 0x100004700 stp x2, x8, [x29, -0x58]
│ ││││ │ 0x100004704 lsr x8, x5, 0x3e
│ ││││ │ 0x100004708 cmp w8, 1
│ ││││┌──< 0x10000470c b.gt 0x10000471c
│ ┌───────< 0x100004710 cbnz w8, 0x10000474c
│ │││││││ 0x100004714 ubfx x24, x5, 0x30, 8
│ ────────< 0x100004718 b 0x100004764
│ │││││││ ; CODE XREF from sym.func.10000469c @ 0x10000470c(x)
│ │││││└──> 0x10000471c cmp w8, 2
│ │││││┌──< 0x100004720 b.ne 0x100004760
│ │││││││ 0x100004724 ldp x9, x8, [x4, 0x10]
│ │││││││ 0x100004728 subs x24, x8, x9
│ ────────< 0x10000472c b.vc 0x100004764
│ │││││││ 0x100004730 brk 1
│ │││││││ ; CODE XREF from sym.func.10000469c @ 0x1000046ec(x)
│ │││└────> 0x100004734 cmp w8, 2
│ │││┌────< 0x100004738 b.ne 0x1000047bc
│ │││││││ 0x10000473c ldp x9, x8, [x4, 0x10]
│ │││││││ 0x100004740 subs x24, x8, x9
│ ────────< 0x100004744 b.vc 0x1000047c0
│ │││││││ 0x100004748 brk 1
│ │││││││ ; CODE XREF from sym.func.10000469c @ 0x100004710(x)
│ └───────> 0x10000474c lsr x8, x4, 0x20
│ ││││││ 0x100004750 subs w8, w8, w4
│ ┌───────< 0x100004754 b.vs 0x100004880
│ │││││││ 0x100004758 sxtw x24, w8
│ ────────< 0x10000475c b 0x100004764
│ │││││││ ; CODE XREF from sym.func.10000469c @ 0x100004720(x)
│ │││││└──> 0x100004760 mov x24, 0
│ │││││ │ ; CODE XREFS from sym.func.10000469c @ 0x100004718(x), 0x10000472c(x), 0x10000475c(x)
│ ────────> 0x100004764 ldr x25, [x23]
│ │││││ │ 0x100004768 ldr x26, [x25, 0x10]
│ │││││ │ 0x10000476c mov x0, x25
│ │││││ │ 0x100004770 bl sym.imp.swift_isUniquelyReferenced_nonNull_native
│ │││││ │ 0x100004774 str x25, [x23]
│ │││││┌──< 0x100004778 tbnz w0, 0, 0x100004794
│ │││││││ 0x10000477c ldr x1, [x25, 0x10] ; int64_t arg2
│ │││││││ 0x100004780 mov w0, 0
│ │││││││ 0x100004784 mov w2, 0
│ │││││││ 0x100004788 mov x3, x25
│ │││││││ 0x10000478c bl sym.func.100004488
│ │││││││ 0x100004790 mov x25, x0
│ │││││││ ; CODE XREF from sym.func.10000469c @ 0x100004778(x)
│ │││││└──> 0x100004794 str x25, [x23]
│ │││││ │ 0x100004798 add x8, x25, 0x20
│ │││││ │ 0x10000479c stp x26, x22, [var_8h]
│ │││││ │ 0x1000047a0 sub x3, x29, 0x58
│ │││││┌──< 0x1000047a4 b 0x100004804
│ │││││││ ; CODE XREF from sym.func.10000469c @ 0x1000046f0(x)
│ ││└─────> 0x1000047a8 lsr x8, x4, 0x20
│ ││ ││││ 0x1000047ac subs w8, w8, w4
│ ││┌─────< 0x1000047b0 b.vs 0x100004884
│ │││││││ 0x1000047b4 sxtw x24, w8
│ ────────< 0x1000047b8 b 0x1000047c0
│ │││││││ ; CODE XREF from sym.func.10000469c @ 0x100004738(x)
│ │││└────> 0x1000047bc mov x24, 0
│ │││ │││ ; CODE XREFS from sym.func.10000469c @ 0x1000046f8(x), 0x100004744(x), 0x1000047b8(x)
│ ─└──────> 0x1000047c0 and x26, x1, 0xfffffffffffffff
│ │ │ │││ 0x1000047c4 ldr x25, [x23]
│ │ │ │││ 0x1000047c8 ldr x27, [x25, 0x10]
│ │ │ │││ 0x1000047cc mov x0, x25
│ │ │ │││ 0x1000047d0 bl sym.imp.swift_isUniquelyReferenced_nonNull_native
│ │ │ │││ 0x1000047d4 str x25, [x23]
│ │ │┌────< 0x1000047d8 tbnz w0, 0, 0x1000047f4
│ │ │││││ 0x1000047dc ldr x1, [x25, 0x10] ; int64_t arg2
│ │ │││││ 0x1000047e0 mov w0, 0
│ │ │││││ 0x1000047e4 mov w2, 0
│ │ │││││ 0x1000047e8 mov x3, x25
│ │ │││││ 0x1000047ec bl sym.func.100004488
│ │ │││││ 0x1000047f0 mov x25, x0
│ │ │││││ ; CODE XREF from sym.func.10000469c @ 0x1000047d8(x)
│ │ │└────> 0x1000047f4 str x25, [x23]
│ │ │ │││ 0x1000047f8 add x8, x25, 0x20
│ │ │ │││ 0x1000047fc stp x27, x22, [var_8h]
│ │ │ │││ 0x100004800 add x3, x26, 0x20
│ │ │ │││ ; CODE XREF from sym.func.10000469c @ 0x1000047a4(x)
│ │ │ │└──> 0x100004804 str x8, [sp]
│ │ │ │ │ 0x100004808 mov w0, 0
│ │ │ │ │ 0x10000480c mov w1, 0
│ │ │ │ │ 0x100004810 mov w2, 3
│ │ │ │ │ 0x100004814 mov w4, 0x10
│ │ │ │ │ 0x100004818 mov x5, 0
│ │ │ │ │ 0x10000481c mov x6, x20
│ │ │ │ │ 0x100004820 mov x7, x24
│ │ │ │ │ 0x100004824 bl sym.imp.CCCrypt ; CCCryptorStatus CCCrypt(CCOperation op, CCAlgorithm alg, int32_t options, const void *key, uint32_t keyLength, const void *iv, const void *dataIn, uint32_t dataInLength, void *dataOut, uint32_t dataOutAvailable, uint32_t *dataOutMoved)
│ │ │ │ │ ; CODE XREFS from sym.func.10000469c @ 0x100004874(x), 0x10000487c(x)
│ │ │┌─┌──> 0x100004828 mov x21, x19
│ │ │╎│╎│ 0x10000482c ldp x29, x30, [var_c0h]
│ │ │╎│╎│ 0x100004830 ldp x20, x19, [arg_20h]
│ │ │╎│╎│ 0x100004834 ldp x23, x22, [var_a0h]
│ │ │╎│╎│ 0x100004838 ldp x25, x24, [var_90h]
│ │ │╎│╎│ 0x10000483c ldp x27, x26, [var_80h]
│ │ │╎│╎│ 0x100004840 add sp, sp, 0xd0 ; 0x178000
│ │ │╎│╎│ 0x100004844 ret
│ │ │╎│╎│ ; CODE XREFS from sym.func.10000469c @ 0x1000046d0(x), 0x1000046e0(x)
│ │ │╎└─└─> 0x100004848 adrp x0, 0x100005000
│ │ │╎ ╎ 0x10000484c add x0, x0, 0x374
│ │ │╎ ╎ 0x100004850 adrp x4, segment.__DATA_CONST ; 0x10000c000
│ │ │╎ ╎ 0x100004854 ldr x4, [x4, 0x3f0] ; [0x10000c3f0:4]=125 ; "}"
│ │ │╎ ╎ 0x100004858 sub x8, x29, 0x44
│ │ │╎ ╎ 0x10000485c mov x3, x1 ; arg2
│ │ │╎ ╎ 0x100004860 add x1, sp, 0x20
│ │ │╎ ╎ 0x100004864 mov x21, x19
│ │ │╎ ╎ 0x100004868 bl sym.imp._StringGuts._slowWithCString.Int8...VGKXEKlF
│ │ │╎ ╎ 0x10000486c mov x19, x21
│ │ │╎ ╎┌─< 0x100004870 cbz x21, 0x100004878
│ │ │└────< 0x100004874 b 0x100004828
│ │ │ ╎│ ; CODE XREF from sym.func.10000469c @ 0x100004870(x)
│ │ │ ╎└─> 0x100004878 ldur w0, [x29, -0x44]
│ │ │ └──< 0x10000487c b 0x100004828
│ │ │ ; CODE XREF from sym.func.10000469c @ 0x100004754(x)
│ └───────> 0x100004880 brk 1
│ │ ; CODE XREF from sym.func.10000469c @ 0x1000047b0(x)
└ └─────> 0x100004884 brk 1
23 changes: 23 additions & 0 deletions demos/ios/MASVS-CRYPTO/MASTG-DEMO-0068/output.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Uses of the CCCrypt function:
0x1000075ec 1 12 sym.imp.CCCrypt

xrefs to CCCrypt:
sym.func.100004000 0x1000040e0 [CALL:--x] bl sym.imp.CCCrypt
sym.func.10000469c 0x100004824 [CALL:--x] bl sym.imp.CCCrypt

Use of CCCrypt with ECB mode:
│ 0x100004808 mov w0, 0
│ 0x10000480c mov w1, 0
│ 0x100004810 mov w2, 3
│ 0x100004814 mov w4, 0x10
│ 0x100004818 mov x5, 0
│ 0x10000481c mov x6, x20
│ 0x100004820 mov x7, x24
│ 0x100004824 bl sym.imp.CCCrypt ; CCCryptorStatus CCCrypt(CCOperation op, CCAlgorithm alg, int32_t options, const void *key, uint32_t keyLength, const void *iv, const void *dataIn, uint32_t dataInLength, void *dataOut, uint32_t dataOutAvailable, uint32_t *dataOutMoved)
│ ; CODE XREFS from sym.func.10000469c @ 0x100004874(x), 0x10000487c(x)
│ 0x100004828 mov x21, x19
│ 0x10000482c ldp x29, x30, [var_c0h]
│ 0x100004830 ldp x20, x19, [arg_20h]
│ 0x100004834 ldp x23, x22, [var_a0h]
│ 0x100004838 ldp x25, x24, [var_90h]
│ 0x10000483c ldp x27, x26, [var_80h]
2 changes: 2 additions & 0 deletions demos/ios/MASVS-CRYPTO/MASTG-DEMO-0068/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
r2 -q -i cccrypt-ecb.r2 -A MASTestApp > output.asm
69 changes: 69 additions & 0 deletions tests-beta/ios/MASVS-CRYPTO/MASTG-TEST-0304.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
title: Broken Symmetric Encryption Modes
platform: ios
id: MASTG-TEST-0304
type: [static, dynamic]
weakness: MASWE-0020
best-practices: [MASTG-BEST-0005]
profiles: [L1, L2]
---

## Overview

To test for the [use of broken encryption modes](../../../Document/0x04g-Testing-Cryptography.md#broken-block-cipher-modes) in iOS apps, we need to focus on methods from cryptographic frameworks and libraries that are used to configure and apply encryption modes.

In iOS development, the `CCCrypt` function from CommonCrypto is the primary API that allows you to specify the encryption mode through the `options` parameter. The [`CCCrypt`](https://web.archive.org/web/20240606000307/https://opensource.apple.com/source/CommonCrypto/CommonCrypto-36064/CommonCrypto/CommonCryptor.h) function accepts a `CCOptions` parameter, which controls the mode of operation:

```c
CCCryptorStatus CCCrypt(
CCOperation op, /* kCCEncrypt, etc. */
CCAlgorithm alg, /* kCCAlgorithmAES128, etc. */
CCOptions options, /* kCCOptionPKCS7Padding, kCCOptionECBMode, etc. */
const void *key,
size_t keyLength,
const void *iv, /* optional initialization vector */
const void *dataIn,
size_t dataInLength,
void *dataOut,
size_t dataOutAvailable,
size_t *dataOutMoved);
```

The `CCOptions` parameter can include `kCCOptionECBMode` (value `0x0002` or `2`) to enable ECB mode. For example:

```swift
CCCrypt(
CCOperation(kCCEncrypt),
CCAlgorithm(kCCAlgorithmAES),
CCOptions(kCCOptionECBMode), // ECB mode enabled
...
)
```

In this test, we're going to focus on symmetric encryption modes such as [ECB (Electronic Codebook)](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_(ECB)).

ECB (defined in [NIST SP 800-38A](https://csrc.nist.gov/pubs/sp/800/38/a/final)) is generally discouraged [see NIST announcement in 2023](https://csrc.nist.gov/news/2023/decision-to-revise-nist-sp-800-38a) due to its inherent security weaknesses. While not explicitly prohibited, its use is limited and advised against in most scenarios. ECB is a block cipher mode that operates deterministically, dividing plaintext into blocks and encrypting them separately, which reveals patterns in the ciphertext. This makes it vulnerable to attacks like [known-plaintext attacks](https://en.wikipedia.org/wiki/Known-plaintext_attack) and [chosen-plaintext attacks](https://en.wikipedia.org/wiki/Chosen-plaintext_attack).

When `kCCOptionECBMode` is set in the options parameter, the encryption uses ECB mode, which is considered vulnerable. The default behavior (when `kCCOptionECBMode` is not set) is to use CBC mode, which is more secure when used with a proper initialization vector (IV).

You can learn more about ECB and other modes in [NIST SP 800-38A - Recommendation for Block Cipher Modes of Operation: Methods and Techniques](https://csrc.nist.gov/pubs/sp/800/38/a/final). Also check the [Decision to Revise NIST SP 800-38A, Recommendation for Block Cipher Modes of Operation: Methods and Techniques](https://csrc.nist.gov/news/2023/decision-to-revise-nist-sp-800-38a) and [NIST IR 8459 Report on the Block Cipher Modes of Operation in the NIST SP 800-38 Series](https://nvlpubs.nist.gov/nistpubs/ir/2024/NIST.IR.8459.pdf) for the latest information.

**Note**: CryptoKit does not support ECB mode and is therefore not vulnerable to this issue. CryptoKit only supports secure encryption modes like AES-GCM and ChaCha20-Poly1305.

## Steps

1. Run a static analysis tool such as @MASTG-TOOL-0073 on the app binary, or use a dynamic analysis tool like @MASTG-TOOL-0039, and look for uses of `CCCrypt` with the `kCCOptionECBMode` option.

## Observation

The output should contain the disassembled code of the functions using `CCCrypt` with ECB mode enabled.

## Evaluation

The test case fails if you can find the use of `kCCOptionECBMode` (value `2` or `0x0002`) in the third parameter (options) of `CCCrypt` calls within the source code.

**Stay up-to-date**: Make sure to check the latest standards and recommendations from organizations such as the National Institute of Standards and Technology (NIST), the German Federal Office for Information Security (BSI), or any other relevant authority in your region.

**Context Considerations**:

To reduce false positives, make sure you understand the context in which the mode is being used before reporting the associated code as insecure. Ensure that it is being used in a security-relevant context to protect sensitive data.
Loading