# Code security 101
@silur
<aside class="notes">
emphasize it's not a complete course and may have errors
</aside>
---
## Agenda
- Peptalk :face_with_rolling_eyes:
- Current Stats
- General attack types and approaches
- The SDLC
- OWASP top10 deep-dive
- Mitigation workshop
- Secure architecture patterns
- DecSecOps
- Threat Modelling
---
## Web security
- Low-hangig fruits, OWASP top 10
- Server-side is not the only asset
- Vuln bots and the cloud
- Composite attacks
---
## Secure web coding:
- Kerckhoff's principle
- Properly handling secrets
- Sanitazation
- CSRF tokens
- Iframe Sandboxing
- Cookies and JWT
- Service isolation
- Service authorization
- Supply chain considerations
---
## Native security primer:
- X86 and ARM
- Android
- Old but gold, refresh on buffer overflows
- Canaries & ASLR
- GOT
- Android Zygote isolation
---
## Native secure coding:
- Properly handling secrets
- hardening your C
- NASA's way of secure C
- AndroidManifests
- To obfuscate or not?
- (Crypto) API misuse on mobile
- ARM trustzone
- OP-TEE
---
## Why bother at all?

---
## Supply chain is indeed risky

---
## ... And you can't react in time anymore

---

---
## Your web services are the most likely target

---

---
- The most common attack vector in organizations is improper access control
- This is usually a logical, not a supply-chain bug
- Root cause is sometimes not software, these access controls might ACTUALLY be missing
---

<small>source: OWASP WSTG</small>
---
## Attacker personas
---
## Vijender Kumar

- Low attention span
- Only uses rapid7 and shellstorm
- Mass-scans the whole IP4 range for low-hanging fruit
- Easily defeated by WAFs and basic measures
---
## Business competitors

- Regurarly keeps updated with your operations
- Does not invest much on offense (mostly recon)
- Expertise in your industry, including your supply chain :warning:
- Likely even shared coworkers with you
---
[tsc code theft case](https://www.theregister.com/2023/11/24/tata_210m_code_theft/)
[nvidia code theft case](https://www.theverge.com/2023/11/23/23973673/valeo-nvidia-autonomous-driving-software-ip-theft-lawsuit)
---
## Lone wolf blackhats

- High attention span and focus on you
- Invests time and money into an attack that has no economic value beyond fame on IRC chats
- Ahead of the industry, usually only on technical terms
- The easier type of APT
---
## Organized APT

- High attention span and focus
- Considerable budget and organization
- Sometimes even state-sponsored
- Highly advanced TTPs involving human factors and on-site ops
---
## Web security
- 98% of attackers go against websites and webapps
- They swarm with low-hanging fruit (thanks npm :slightly_smiling_face: )
---
## Webapps are the best kind of software
<small>... from a user and business perspecitve `\(סּںסּَ )/ۜ`</small>
- Browsers are on every platform and kindof standardized
- No installation
- UX/UI flexibility (independent of device vendors)
- Engineering team is (kindof) unified
- Fast time to market :)
---
## Webapps are the worst kind of softare
<small>... from a security perspective `(╯°□°)╯`</small>
- JS was never meant for large-scale logic
- New framework every 2nd week, engineers always in the dark
- Processes large amounts of user-supplied (aka untrusted) data
- Interfaces with protected parts of the network (paid API, user DB etc)
- Supply chain is unnecessarly large and fragmented, lots of abandonware
- Fast time to market :(
---
## Low-hanging fruit
### OWASP TOP10
- Broken Access Control
- Cryptographic Failures
- Injection
- Insecure Design
- Security Misconfiguration
- Legacy software
- ID and Auth failures
- Software and data integrity failure
- Logging and monitoring failure
- SSR
---
## Example 1 - Broken access control part 1
- View another user's basket
- How would you store which user's data we render on the DOM?
- What means the user can tamper with that?
<aside class="notes">
edit `bid` in sessionStorage
</aside>
---
## Example 2 - Broken access control part 2
- We can't only mess up read access with BAC
- Let's send a service feedback but from someone else's account!
<aside class="notes">
intercept http://localhost:3000/api/Feedbacks
</aside>
---
## Cryptographic erros
- Never brew your own
- There's _always_ a security geek in your team, consult them if in doubt
- There's _always_ a better security geek oustide the team, consult with them too
- Follow well-reputed standards from tech leaders and institutions such as NIST, OWASP, FIPS, Google
---
## Insecure hash
```
|
d131dd02c5e6eec4693d9a0698aff95c2fcab58712467eab4004583eb8fb7f89
55ad340609f4b30283e488832571415a085125e8f7cdc99fd91dbdf280373c5b
d8823e3156348f5bae6dacd436c919c6dd53e2b487da03fd02396306d248cda0
e99f33420f577ee8ce54b67080a80d1ec69821bcb6a8839396f9652b6ff72a70
```
```
|
d131dd02c5e6eec4693d9a0698aff95c2fcab50712467eab4004583eb8fb7f89
55ad340609f4b30283e4888325f1415a085125e8f7cdc99fd91dbd7280373c5b
d8823e3156348f5bae6dacd436c919c6dd53e23487da03fd02396306d248cda0
e99f33420f577ee8ce54b67080280d1ec69821bcb6a8839396f965ab6ff72a70
```
Each of these blocks has MD5 hash `79054025255fb1a26e4bc422aef54eb4`
---
## Symmetric encryption
Insecure (or reused) IV
```c
EVP_CIPHER_CTX ctx;
char key[EVP_MAX_KEY_LENGTH];
char iv[EVP_MAX_IV_LENGTH];
RAND_bytes(key, b);
memset(iv,0,EVP_MAX_IV_LENGTH); // insecure
getrandom(iv, EVP_MAX_IV_LENGTH, 0) // secure
EVP_EncryptInit(&ctx,EVP_bf_cbc(), key,iv);
```
---
```js
// we use xsalsa20poly1305
msg1 = "This is a secret message!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
msg2 = "***************************More secret stuff here***"
secret_key = [252, 225, 194, 245, 50, 74, 200, 62, 171, 0, 232, 145, 225, 127, 41, 81, 81, 251, 42, 168, 34, 184, 60, 137, 168, 122, 88, 68, 189, 219, 123, 112]
nonce = [147, 3, 123, 195, 76, 217, 196, 102, 214, 10, 144, 88, 23, 135, 163, 60, 46, 86, 20, 249, 39, 70, 110, 205]
ciphertext1 = encrypt(msg1, nonce, secret_key)
ciphertext2 = encrypt(msg2, nonce, secret_key)
```
---
```js
xor_cipher = []
for i in range(len(ciphertext1)):
xor_cipher.append(operator.xor(ciphertext1[i], ciphertext2[i]))
for d in range(32,127):
xor_temp = []
for i in range(len(xor_cipher)):
xor_temp.append(operator.xor(xor_cipher[i], d))
xor_str = ''
for i in range(len(xor_temp)):
if xor_temp[i] == 0:
xor_str += ' '
else:
xor_str += chr(xor_temp[i])
print(xor_str)
```
---

---
## Asymmetric encryption
Never sign messages just blindly
```python
p, q , e = rsa_gen_key()
n, d = rsa_pubkey(p, q, e)
```
---
Let's imagine your hash is weak as in the following example, or that your implementation accepts unhashed inputs:
```python
intercepted_ciphertext = 0xdeadbeef
def sign(msg)
return (msg^e) % n // insecure!
def attack():
decrypt(intercepted_ciphertext + 0xcafebabe)
// c2 = (intercepted_ciphertext + 0xcafebabe) ^ n
// c2 = intercepted_ciphertext^e + 0xcafebabe^e
// factor out 0xcafebabe and you have the original plaintext
```
---
NAAAH but who ever uses RSA without hashes and padding?
If your padding system leaks validity checks, it basically becomes a tool to decrypt any ciphertext: https://github.com/flast101/padding-oracle-attack-explained
---
- Nesting Asymmetric and Symmetric crypto is okay
- but not if you place the keys next to the ciphertext
---
## Injection
The vulnerability that dominated the internet untill 2016.... and still dominates all of PHP :shrug:
---
:angel:
```js
async function loginUser(req, res) {
const hashedPasswordQuery = `SELECT password FROM
users WHERE email = '${req.email}'`; // insecure
}
```
:smiling_imp:
```
curl 'http://example.com/loginUser'
--data 'email=\' OR 1=1; --'
```
query becomes `SELECT password FROM
users WHERE email = '' OR 1=1; --'`;
---
:angel:
```html
<html>
<body>
<?php
print "Not found: " . urldecode($_SERVER["REQUEST_URI"]);
?>
</body>
</html>
```
:smiling_imp:
```
curl 'http://example.com/<script>alert("pwned");</script>'
```
What happens if you try to print the path? You get JS executed :)
---
## Insecure design
- A cinema chain allows group booking discounts and has a maximum of fifteen attendees before requiring a deposit.
- A retail chain’s e-commerce website does not have protection against bots run by scalpers buying high-end video cards to resell auction websites.
---
## Security misconfiguration
:angel:
```xml=
<Directory />
Require all granted
</Directory>
```
:smiling_imp:
```bash=
curl 'http://example.com/cgi-bin/.%2e/.%2e/.%2e/.%2e/etc/passwd'
```
---
```java
public BankAccount getUserBankAccount(String username, String accountNumber) {
BankAccount userAccount = null;
String query = null;
try {
if (isAuthorizedUser(username)) {
query = "SELECT * FROM accounts WHERE owner = "
+ username + " AND accountID = " + accountNumber;
DatabaseManager dbManager = new DatabaseManager();
Connection conn = dbManager.getConnection();
Statement stmt = conn.createStatement();
ResultSet queryResult = stmt.executeQuery(query);
userAccount = (BankAccount)queryResult.getObject(accountNumber);
}
} catch (SQLException ex) {
String logMessage = "Unable to retrieve account information from database,\nquery: " + query;
Logger.getLogger(BankManager.class.getName()).log(Level.SEVERE,
logMessage, ex);
}
return userAccount;
}
```
---
## Supply chain issues


---
## Identification and Authentication Failures
:smiling_imp:
```bash
ffuf -u 'http://example.com/login' \
--data "email=alice@example.com&pass=FUZZ" \
-w /usr/share/seclists/Passwords/2020-200_most_used_passwords.txt
```
---
## Software and Data Integrity Failures

---

---
## Logging and monitoring failure

---
## SSRF
:angel:
```ascii=
POST /meteorology/forecasts HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 113
weatherApi=http://data.weatherapp.com:8080/meterology/forecasts/check%3FcurrentDateTime%3D6%26cityId%3D1
```
:smiling_imp:
```
POST /meteorology/forecasts HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 33
weatherApi=http://localhost/admin
```
---
## Composite attacks
- It's not enough to only protect each case separately
- Maybe an internal user can make an SSRF with a magic cookie from tech support
- The external (blackbox) pentest might miss this as it needs knowledge about this credential
- .... But the cookie might leak during a phising attack
<aside class="notes">
composite attacks usually start with highly sophisticated phising
</aside>
---
## But my business just started, they don't even know my shop is there!
- All cloud providers are mass-scanned 24/7
- It takes approx 16 SECONDS from renting a VPS to having an automated vuln scanner bombing it
- By the time you even start configuring apache, you might get locked out by the VPS due to spam
---
# Web defenses
__"one ought to design systems under the assumption that the enemy will immediately gain full familiarity with them".__ ~ Kerckhoffs
---
- Moving your SSH port from port 22 to 922 is <u>Obscurity</u>. This is like hiding an open safe under Metro line 3.
- Disabling password auth and X11 forwarding is <u>Security</u>. It takes more than just network knowledge and maths to factor ECDSA.
---
## Golden trick 1
Never echo back or even process RAW data from users.
Every user with every user interaction is malicious. Period.
<small>for real it'll make your job way easier :)</small>
---
## Access control
For startups who don't have time for this:
- Supabase
- Oauth
---
For architects who don't trust thirdparties with security (as you should):
- Never let the user alter the control flow of auth. She is the very subject of it!
---
For serious security geeks:
- Google zanzibar
- Ory.sh
---
But overall:
- Identities and credentials for authorized users, services, and hardware are managed by the organization
- Identities are proofed and bound to credentials based on the context of interactions
- Users, services, and hardware are authenticated
- Physical access to assets is managed, monitored, and enforced commensurate with risk
- Every auth/access event is attributable, accountable and asserted to credentials!
---
## Cryptographic failures
- Only use highly reputed frameworks
- Don't ever try to be smart with them
- Check up on your libs CVEs and reports regularly
- Always consult and audit with a specialized entity when in doubt, a GDPR violation costs much more.
---
## Recommendation
If you are unsure and want the basics:
https://github.com/openpgpjs/openpgpjs
- IETF standardized format
- Easy to use
- Used by protonmail
- Independently verified by a reputable group :warning:
---
If you wanna dirt your hands with lower-level stuff:
- https://www.w3.org/TR/WebCryptoAPI/
- W3C standardized
- Easy to misuse :warning:
- More performant and builtin in most browsers
---
## Injection
- Sanitize, Sanitize, Sanitize!
- Better if you reduce user-controlled input overall!
---
## SQL
Your framework is guaranteed to have a high-level parametrized call that already sanitizes every param:
```nodejs=
const text = 'INSERT INTO users(name, email) VALUES($1, $2) RETURNING *'
const values = ['brianc', 'brian.m.carlson@gmail.com']
const res = await client.query(text, values)
```
If you can't find one, make an SQL prepared statement manually.
**Never try to come up with an escape rule on your own. It's an NP-complete problem**
---
## XSS
use https://github.com/cure53/DOMPurify
```js
import * as DOMPurify from 'dompurify';
const clean = DOMPurify.sanitize('<b>hello there</b>');
```
---
## Insecure design
Follow https://arc42.org/
Re-evaluate the stakeholders and the business requirements again...
When it comes to money, everyone becomes a security expert suddenly!
Especially when communicating the design is easier!
---
## Security misconfiguration
Do automated security in your DevOps pipeline!

---
Use [Semgrep](https://semgrep.dev)
```bash=
python3 -m pip install semgrep
cd myapp
python -m semgrep .
```
---
Use the free [ZAProxy full scan CI job](https://github.com/marketplace/actions/zap-full-scan)
... or one of the paid actions from security companies
... or heck write your own shell scripts based on this talk!
---
Use [Bunkerweb](https://www.bunkerity.com/en)
- Nginx Proxy
- Owasp core rule set
- Rate limiting
- Auto SSL
- Automatically bans Tor and VPNs
- Bruteforce protection
- Injection protection
- Dynamic config
- Much more!
---
## Identificaion and Auth
Auth0 for the lazy (and the managers)
```bash
npm install @auth0/auth0-react
```
```javascript
import { useAuth0 } from "@auth0/auth0-react";
import React from "react";
const LoginButton = () => {
const { loginWithRedirect } = useAuth0();
return <button
onClick={() => loginWithRedirect()}>
Log In
</button>;
};
```
---
## Supabase for the GDPR concious
```javascript
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'
const supabase = createClient('https://xyzcompany.supabase.co', 'public-anon-key')
async function signUpNewUser() {
const { data, error } = await supabase.auth.signUp({
email: 'example@email.com',
password: 'example-password',
options: {
emailRedirectTo: 'https//example.com/welcome'
}
})
}
async function signInWithEmail() {
const { data, error } = await supabase.auth.signInWithPassword({
email: 'example@email.com',
password: 'example-password'
})
}
```
---
## Recommendations for the manual laborer
- JWTs are OK as long as you encrypt them properly.
- Encrypt your cookies too
- Enforce SameSite (done by default on bunkerweb)
- Implement Passkeys (WebAuthN) ASAP
- If you REALLY need to still do legacy passwords, use Argon2
- Keep sessions short in redis at serverside
---
## Ory.sh for the chads
- Bunch of FOSS, state-of-the art products for Auth, SAML etc
- Some (google zanzibar) designed by tech titans such as google
- Hard to grasp and integrate but scales very well and reusable across all your products
---
## Software integrity
- Your production software (and preferably all data provided by your org) has to be signed
- I'd personally ECDSA sign even official tweets with threshold keys from PR
---
## For windows
```bash
New-SelfSignedCertificate
-Type Custom
-Subject "CN=Contoso Software, O=Contoso Corporation, C=US"
-KeyUsage DigitalSignature
-FriendlyName "Your friendly name goes here"
-CertStoreLocation "Cert:\CurrentUser\My"
-TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.3", "2.5.29.19={text}")
SignTool sign
/fd sha256
/n mycert
myapp.msix
```
---
## For java/android
```bash!
keytool -genkey -v -keystore my-release-key.keystore
-alias alias_name
-keyalg RSA
-keysize 4096
-validity 365
jarsigner -verbose -sigalg SHA256withRSA -digestalg SHA256 -keystore my-release-key.keystore my_application.apk alias_name
# optional for android
zipalign -v 4 my_application.apk my_application-aligned.apk
```
---
## Logging and monitoring
- Use a [SIEM]
- Use an EDR/XDR
- Ship your logs to the SIEM don't just pay for it :upside_down_face:
---
## Recommendation [Wazuh](https://wazuh.com/)

- FOSS & Self-hosted
- Extremely performant
- Used by Cisco, Ebay, NASA, Salesforce
---
## SSRF
- Your infra should never face WAN
- Only the kuber cluster, docker swarm or VPN
- Quick'n'dirty way - an SSH tunnel
---
```bash!
# ssh -L localPort:remoteHost:remotePort user@remote
ssh -L 1979:localhost:3000 webapp@example.com
# manage your web admin without listening on WAN
```
---
# Misc tip from previous top10
- Use `iframe` with `sandbox` option
- If your framework doesn't do CSRF tokens ~~drop it~~ generate your own from `/dev/urandom` on serverside
- Those HTTP headers MATTER
---

---
# Native apps
## Desktop, X86 and ARM
---

---
## Windows address space

---

---

```c!
void myFunc(int a, int b, int c, int d, int e, int f);
// MOV RCX, a
// MOV RDX, b
// MOV R8, c
// MOV R9, d
// PUSH f
// PUSH e
```
---
## Old but gold
```c
char name[4];
// write past end of buffer (buffer overflow)
strcpy(name,"a string longer than 4 characters");
// read past end of buffer (also not a good idea)
printf("%s\n",name[6]);
```
---
```c!
#include <string.h>
#include <stdio.h>
void foo(char *bar)
{
float My_Float = 10.5; // Addr = 0x0023FF4C
char c[28]; // Addr = 0x0023FF30
// Will print 10.500000
printf("My Float value = %f\n", My_Float);
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Memory map:
@ : c allocated memory
# : My_Float allocated memory
*c *My_Float
0x0023FF30 0x0023FF4C
| |
@@@@@@@@@@@@@@@@@@@@@@@@@@@@#####
foo("my string is too long !!!!! XXXXX");
memcpy will put 0x1010C042 (little endian) in My_Float value.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
memcpy(c, bar, strlen(bar)); // no bounds checking...
// Will print 96.031372
printf("My Float value = %f\n", My_Float);
}
int main(int argc, char **argv)
{
foo("my string is too long !!!!! \x10\x10\xc0\x42");
return 0;
}
```
---
Let's pwn an actual overflow
```bash!
wget https://github.com/mattetti/IOLI-crackme/raw/master/bin-linux/crackme0x00
r2 crackme0x00
> aaaa
```
---
```
80486e3: e8 38 fd ff ff call 8048420 <strcmp@plt>
80486e8: 83 c4 10 add esp,0x10
80486eb: 85 c0 test eax,eax
80486ed: 75 3a jne 8048729 <start+0x8c>
80486ef: 83 ec 0c sub esp,0xc
-> 80486f2: 68 5e 88 04 08 push 0x804885e
80486f7: e8 74 fd ff ff call 8048470 <puts@plt>
...
804872c: 68 92 88 04 08 push 0x8048892
8048731: e8 3a fd ff ff call 8048470 <puts@plt>
8048736: 83 c4 10 add esp,0x10
```
---
```bash!
$ echo AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJ > input
$ ./crackme0x00 < input
$ dmesg | tail -1
[238584.915883] crackme0x00[1095]: segfault at 48484848 ip 0000000048484848 sp 00000000ffffd6a0 error 14
```
---
```python
from pwn import *
p = process("./crackme0x00")
p.sendline(cyclic(50))
#aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaama
p.interactive()
# segfault at 61616168 ip 0000000061616168
cyclic_find(0x61616168) # 28
```
---
```python!
from pwn import *
shellcode = shellcraft.sh()
from pwn import *
p = process("./crackme0x00")
shellcode = shellcraft.sh()
p.sendline("A"*28+shellcode)
p.interactive()
# \o/
```
---
# Realitiy punches in the face
DATA regions are not executable for a while...
...But you can always reuse code from .TEXT :smiling_imp:
---
## Stack canaries
They don't PREVENT overflows but detect and can enforce early abort.

<small>Usually a random value starting with `0x00` to halt all string functions</small>
---
## ASLR
- randomized address space to prevent reliable jumping
---
# How to defend (in C)
Long version:
```bash
gcc
-D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS -ftrivial-auto-var-init=pattern
-fPIE -pie -Wl,-z,relro,-z,now -fstack-protector-strong
-fstack-clash-protection -fcf-protection=full
myprogram.c
```
Short version (after GCC 14.0):
```bash
gcc -fhardened myprogram.c
```
<small>... or just use a memory-safe lingo `¯\_(ツ)_/¯`</small>
---
## NASA's 10 rules fore safety-critical code
- Restrict all code to very simple control flow constructs—do not use goto statements, setjmp or longjmp constructs, or direct or indirect recursion.
- Give all loops a fixed upper bound.
- Do not use dynamic memory allocation after initialization.
- No function should be longer than what can be printed on a single sheet of paper
---
- The code's assertion density should average to minimally two assertions per function.
- Declare all data objects at the smallest possible level of scope.
- Each calling function must check the return value of nonvoid functions, and each called function must check the validity of all parameters provided by the caller.
---
- The use of the preprocessor must be limited to the inclusion of header files and simple macro definitions.
- Limit pointer use to a single dereference, and do not use function pointers.
- Compile with all possible warnings active; all warnings should then be addressed before the release of the software.
---
## Anti-reverse & Anti-debug
### PEB (process environment block)
- BeingDebugged / isDebuggerPresent()
- NtGlobalFlag
- StartupInfo
---
- set THREADINFOCLASS flag to ThreadHideFromDebugger to start hidden threads
- alternatively use NtCreateThreadEx with `THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER`
- NtSetInformationProcess - detect tracing
- NtQuerySystemInformation - bunch of debug symbols here
- NtUserBlockInput - yes this works
---
## Virtual machines?
- some advanced DRM solutions build their own proprietary bytecode VM
- ... which also proves ineffective against teenagers
- And sometimes symbolic executors
---
## Fuzzers
- A type of automatic tester that injects "structure junk"
- Can work with every type of input, CLI, files even networks
- In most cases it needs instrumentation but can work in blackbox
- Not just for C/C++
- https://github.com/google/AFL
---
## Esil, Capstone, Angr
```python!
p = angr.Project('sender', auto_load_libs=False)
# Start with a blank state at the EIP after "key.txt" is read
state = p.factory.blank_state(addr=0x401198)
# Initialize global variables
ADDR_PW_ORI = state.regs.ebp - 0x80004
ADDR_PW_ENC = ADDR_PW_ORI + 0x10000
ADDR_HASH = state.regs.ebp - 0x40000
# Setup stack to simulate the state after which the "key.txt" is read
state.regs.esi = LEN_PW
for i in range(LEN_PW):
state.mem[ADDR_PW_ORI+i:].byte = state.solver.BVS('pw', 8)
# Hook instructions to use a separate buffer for the XOR-ing function
p.hook(0x401259, hook_duplicate_pw_buf, length=0)
p.hook(0x4011E7, hook_use_dup_pw_buf, length=0)
# To avoid calling imports (HeapAlloc), retrofit part of the stack as
# temporary buffer to hold symbolic copy of the password
p.hook(0x4011D6, hook_heapalloc, length=5)
# Explore the states until after the hash is computed
sm = p.factory.simulation_manager(state)
sm.explore(find=0x4011EC)
```
---
# Mobile
---
Android code runs on top of the ART VM, which is forked after boot by the Zygote process using a socket comm
ART (and it's predecessor Dalvik) may be or may not (Oracle and Google is still sueing each other) a JVM
---
On top of ART, each app has it's own isolated, sandboxed environment which can be even tightened with SELinux.
Also the VM follows a permission-first system, Android was the first widely-adopted system with this idea
---

---
- Apps are packaged into `.apk` files which are basically ZIPs
- They contain a `MANIFEST` which is XML with a bunch of descriptors
- and a DEX file that has the actual bytecode
---
```bash
wget 'https://dl.androidcontents.com/com.king.candycrushsaga/download?ecp=edb6fa9a664d82bfabe7089b706cd2e9&fn=com_king_candycrushsaga_v1.266.0.4.apk' -O candycrush.apk
#jadx-gui candycrush.apk
# or apktool d candycrush.apk
---

---
- Java by nature is almost trivially reversible
- You can protect with Proguard somewhat...
- ... but there is ALWAYS a russian teenager with more time than you
- Remember Kerckhoffs. You protect your app with cryptography, authorization and logic isolation NOT OBFUSCATION
---
# Use the KeyChain API
```kotlin
//Generate a key and store it in the KeyStore
val keyGenerator: KeyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
val keyGenParameterSpec: KeyGenParameterSpec = new KeyGenParameterSpec.Builder("MyKeyAlias",
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setUserAuthenticationRequired(true)
setUserAuthenticationValidityDurationSeconds(-1) // require fingerprint ever time
.setRandomizedEncryptionRequired(true) //different ciphertext for same plaintext on each call
.build();
keyGenerator.init(keyGenParameterSpec);
keyGenerator.generateKey();
val key: SecretKey = keygen.generateKey();
```
---
<small>did you find the vulnerability in the above code? :)</small>
- The keystore API uses ARM Trustzone under the hood
- It's a CC EAL5+ Secure element on most flagship phones
- Almost the same security as a smartcard
- The keys inside are EXTREMELY hard to read as they never actually reach the main CPU memory
- Use this to encrypt your SharedPreferences and sensitive DB data
---
## What happens under the hood
```c!
#define TA_HELLO_WORLD_CMD_INC_VALUE 0
TEEC_Result res;
TEEC_Context ctx;
TEEC_Session sess;
TEEC_Operation op;
TEEC_UUID uuid = TA_HELLO_WORLD_UUID;
uint32_t err_origin;
res = TEEC_InitializeContext(NULL, &ctx);
if (res != TEEC_SUCCESS)
errx(1, "TEEC_InitializeContext failed with code 0x%x", res);
res = TEEC_OpenSession(&ctx, &sess, &uuid,
TEEC_LOGIN_PUBLIC, NULL, NULL, &err_origin);
if (res != TEEC_SUCCESS)
errx(1, "TEEC_Opensession failed with code 0x%x origin 0x%x",
res, err_origin);
/*
* Execute a function in the TA by invoking it, in this case
* we're incrementing a number.
*
* The value of command ID part and how the parameters are
* interpreted is part of the interface provided by the TA.
*/
/* Clear the TEEC_Operation struct */
memset(&op, 0, sizeof(op));
/*
* Prepare the argument. Pass a value in the first parameter,
* the remaining three parameters are unused.
*/
op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_NONE,
TEEC_NONE, TEEC_NONE);
op.params[0].value.a = 42;
/*
* TA_HELLO_WORLD_CMD_INC_VALUE is the actual function in the TA to be
* called.
*/
printf("Invoking TA to increment %d\n", op.params[0].value.a);
res = TEEC_InvokeCommand(&sess, TA_HELLO_WORLD_CMD_INC_VALUE, &op,
&err_origin);
if (res != TEEC_SUCCESS)
errx(1, "TEEC_InvokeCommand failed with code 0x%x origin 0x%x",
res, err_origin);
printf("TA incremented value to %d\n", op.params[0].value.a);
TEEC_CloseSession(&sess);
TEEC_FinalizeContext(&ctx);
return 0;
```
---
```kotlin
val cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING")
cipher.init(Cipher.ENCRYPT_MODE, key)
val ciphertext: ByteArray = cipher.doFinal(plaintext)
val iv: ByteArray = cipher.iv
var sharedPref = getSharedPreferences("key", Context.MODE_WORLD_READABLE)
var editor = sharedPref.edit()
editor.putString("username", "administrator")
editor.putString("password", iv + ciphertext)
editor.commit()
```
---
More on ARM Trustzone and OP-TEE at https://optee.readthedocs.io/en/latest/index.html
It's amazing stuff try it!
---
## Use [SQLCipher](https://www.zetetic.net/sqlcipher/sqlcipher-for-android/) to encrypt your whole app DB
```gradle
implementation 'net.zetetic:sqlcipher-android:4.5.5@aar'
implementation 'androidx.sqlite:sqlite:2.2.0'
```
```kotlin
System.loadLibrary("sqlcipher")
val databaseFile = getDatabasePath("test.db")
databaseFile.mkdirs()
val database = SQLiteDatabase.openOrCreateDatabase(databaseFile, password, null, null, null)
if (database != null) {
database.execSQL("create table t1(a,b);")
database.execSQL(
"insert into t1(a,b) values(?, ?);",
arrayOf("one for the money", "two for the show")
)
}
}
```
---
# Cert pinning
put this into `res/xml/network_security_config.xml`
```
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
<domain includeSubdomains="true">example.com</domain>
<pin-set expiration="2024-01-01">
<pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin>
<!-- backup pin -->
<pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=</pin>
</pin-set>
</domain-config>
</network-security-config>
```
... even when you ARE signed by a trusted CA
---
## Rely on https://developer.android.com/jetpack/androidx/releases/biometric for critical operations
---
## Anti-reverse? (meh)
- Proguard
- ApplicationInfo.FLAG_DEBUGGABLE
- Debug.isDebuggerConnected()
- Timer checks
- /proc/pid/status
---
## Detect root (meh)
- Yes, sandboxing is worthless on a rooted device
- You can detect a rooted device with [rootbeer](https://github.com/scottyab/rootbeer)
- But sensitive data should never be plaintext, even in isolated apps
- Encrypt with the keystore and use X.509
- Authenticate both client and Server
- Only use native android cryptography
---
## Wrapping up
- 30% of security happens at code level
- You don't have to be specifically targeted
- DevSecOps is important, bunch of free tools for it
- Half of your attacker personas fall out with a well-configured WAF
- Don't obfuscate, encrypt and authorize!
- TEE is okay if treated correctly
- Get into passkeys asap!
---
Spare a minute for a password policy questionary?

https://tinyurl.com/2th7wtjd
---
## Thanks for your attention!
Questions?
https://silur.dev
https://www.linkedin.com/in/silur/
@silur@infosec.exchange
{"title":"Code security 101","description":"type: slide","contributors":"[{\"id\":\"f4d4af67-750e-4c99-b33e-c04b6d99a6c6\",\"add\":39378,\"del\":5931}]"}