11.7 Source Code Review & Encoded/Cryptographic Value Analysis
Key Takeaways
- Source code review traces untrusted input from its entry point (source) to a dangerous operation (sink), and is the most reliable way to find injection and logic flaws.
- Grep-driven review targets dangerous sinks: query concatenation, eval, system, deserialization, and hardcoded secrets.
- Base64 is encoding, not encryption: it is reversible with no key, so identifying and decoding it is trivial and it protects nothing.
- A 32-hex-character value is very likely an MD5 hash; length and character set identify the algorithm, and unsalted hashes fall to rainbow tables.
- Distinguishing encoding from encryption from hashing tells the assessor whether a captured value can be decoded, decrypted or only cracked.
11.7 Source Code Review & Encoded/Cryptographic Value Analysis
Two final web-testing skills round out the syllabus. H13 (Source Code Review) requires common techniques for identifying and reviewing deficiencies in the areas of security. H12 (Encryption) requires identifying and exploiting encoded values (e.g. Base64) and cryptographic values (e.g. MD5 hashes), and identifying common SSL vulnerabilities. They belong together because both are about reading what an application reveals of its own internals — one from the code, one from the data it hands the client.
1. Source Code Review (H13)
Source code review (SAST when automated) is white-box testing: with the source in hand, you can find flaws that black-box testing would never reach, and you can confirm suspected flaws definitively. It complements dynamic testing rather than replacing it.
The Source-to-Sink Method
The core technique is data-flow (taint) analysis: trace untrusted data from where it enters the application to where it is used dangerously.
SOURCE (untrusted input) SINK (dangerous operation)
-------------------------- ---------------------------
request.getParameter() Statement.execute(sql) -> SQLi
$_GET / $_POST / $_REQUEST eval(), system(), exec() -> code/cmd injection
request body / headers / cookies ...> Runtime.exec() -> command injection
file upload / filename new File(path), include() -> traversal / LFI
deserialized object readObject() -> deserialization RCE
database / external API (2nd order) innerHTML / response write -> XSS
If tainted data reaches a sink without adequate validation, encoding or parameterisation in between, that is a vulnerability. A "second-order" flaw is one where the input is stored first and reaches a sink later — invisible to naive black-box testing but obvious in the code.
Grep-Driven Review
Even without a full SAST tool, a targeted search for dangerous sinks and secrets is highly productive:
# Injection sinks
grep -RInE "execute\(|executeQuery\(|Statement|createQuery|\.raw\(" .
grep -RInE "eval\(|exec\(|system\(|passthru\(|popen\(|Runtime\.exec|subprocess" .
grep -RInE "readObject|ObjectInputStream|pickle\.loads|unserialize|BinaryFormatter" .
# XSS sinks
grep -RInE "innerHTML|document\.write|dangerouslySetInnerHTML|\|safe" .
# Secrets and crypto misuse
grep -RInE "password|passwd|secret|api[_-]?key|AKIA|BEGIN (RSA|OPENSSH) PRIVATE KEY" .
grep -RInE "MD5|SHA1|DES|ECB|Math\.random|new Random\(" .
What to Look For Beyond Injection
- Authentication and session logic — how credentials are checked, how tokens are generated (predictable? properly random?), how sessions expire.
- Access-control checks — are they present on every sensitive operation, or only on the UI path (the recurring API-authorisation failure)?
- Cryptographic choices — MD5/SHA-1 for passwords, hardcoded keys, ECB mode,
Math.random()for tokens, disabled certificate validation. - Hardcoded secrets — credentials, keys and connection strings committed to source (and to version-control history).
- Configuration — debug flags, default credentials, permissive CORS, verbose errors.
Automated SAST tools (Semgrep, SonarQube, CodeQL, Fortify) scale this up, but they generate false positives; the reviewer's judgement in confirming that a source genuinely reaches a sink without mitigation is what turns a tool finding into a real one.
2. Encoded Values: Base64 and Friends (H12)
During testing you constantly encounter opaque-looking strings in cookies, tokens, hidden fields and parameters. The first task is to recognise encoding, which is trivially reversible.
Encoding is a reversible representation change with no key. It exists for transport safety and interoperability, not secrecy. Common encodings and their tells:
| Encoding | Recognisable by | Reverse |
|---|---|---|
| Base64 | A-Z a-z 0-9 + /, length a multiple of 4, =/== padding | base64 -d; URL-safe variant uses - and _ |
| Hex | only 0-9 a-f, even length | xxd -r -p |
| URL / percent | %2F, %20 | URL-decode |
| HTML entities | < ' | HTML-decode |
The security point is stated plainly in the syllabus example: Base64 is not encryption. A session cookie, "encrypted" price field, or "secret" token that is merely Base64 offers no protection — decode it, read it, modify it, re-encode it. A very common finding is a role or user ID Base64-encoded in a cookie (eyJyb2xlIjoidXNlciJ9 decodes to {"role":"user"}), which the attacker simply changes to admin. Layered encodings (Base64 of hex of JSON) are still just encodings; peel each layer.
3. Cryptographic Values: Hashes and Encryption (H12)
When a value is not plain encoding, decide whether it is a hash or ciphertext, because that determines what you can do with it.
Identifying Hashes
Hashes are one-way: you cannot reverse them, only guess the input and compare. Identify by length and character set:
| Length (hex) | Bits | Likely algorithm |
|---|---|---|
| 32 | 128 | MD5 (or NTLM, which is MD4 of UTF-16LE) |
| 40 | 160 | SHA-1 |
| 64 | 256 | SHA-256 |
| 128 | 512 | SHA-512 |
A 32-character hex string is the syllabus's own example: very likely MD5. Tools like hashid/hash-identifier automate the guess, and the modular-crypt prefixes ($1$, $5$, $6$, $2y$) identify salted Unix hashes (see 9.6).
Exploiting hashes:
- Unsalted hashes fall instantly to rainbow tables and to online lookup databases — a huge fraction of leaked MD5/SHA-1 hashes are simply searchable.
- Salted hashes require per-hash cracking with
hashcat/john, but weak passwords still fall. - Fast algorithms (MD5, SHA-1, SHA-256) are wrong for passwords precisely because they crack quickly; finding them used for password storage is itself a finding, and the fix is bcrypt/scrypt/Argon2.
- Hash length extension attacks apply to
H(secret || data)MAC constructions built on Merkle–Damgård hashes (MD5, SHA-1, SHA-256), which is why HMAC (3.2) exists.
Recognising Encryption
Ciphertext is reversible with the key. Tells: high entropy, no readable structure, often Base64-wrapped, and a length that is a multiple of the block size (8 bytes for DES/3DES, 16 for AES) for block ciphers. Client-side testing rarely recovers the key, but you can still find:
- ECB mode, betrayed by identical plaintext blocks producing identical ciphertext blocks (the "ECB penguin"), which leaks structure and allows block cut-and-paste;
- static IVs and encoded-not-encrypted values that only looked encrypted;
- keys recovered by decompiling a thick client (10.6).
Common SSL/TLS Vulnerabilities (H12)
The syllabus explicitly folds SSL vulnerability identification into this item; section 3.3 covers these in depth, so here they are the checklist an assessor applies to any HTTPS endpoint:
- Protocol: SSLv2/SSLv3 and TLS 1.0/1.1 enabled (POODLE, and deprecated).
- Ciphers: RC4 (Bar Mitzvah), export-grade (FREAK/Logjam), 64-bit block ciphers in CBC (Sweet32 on 3DES).
- Implementation: Heartbleed (CVE-2014-0160), BEAST, CRIME/BREACH (compression).
- Certificate: expired, self-signed, weak signature (MD5/SHA-1), wrong hostname, weak key.
- Config: no HSTS, no forward secrecy, insecure renegotiation.
testssl.sh, sslscan and sslyze automate the whole checklist and are the standard tools.
4. Bringing It Together
Captured opaque value
|
Decodable with no key? --yes--> ENCODING (Base64/hex/URL): decode, tamper, re-encode
| no
Fixed length, hex, one-way? --yes--> HASH: identify by length; rainbow/crack; flag if used for passwords
| no
High entropy, block-multiple length? --> CIPHERTEXT: identify mode (ECB?), seek key (client decompile)
The discipline this section teaches is diagnostic: correctly classifying a value as encoded, hashed or encrypted tells you immediately whether it can be decoded (trivial), cracked (feasible for weak hashes/passwords), or decrypted (needs the key) — and that classification, together with a source-code review that shows how the value was produced, is what turns a mysterious blob into a finding.
A source code reviewer wants to find SQL injection efficiently. Which technique is the foundation of the review?
An assessor finds the cookie value eyJyb2xlIjoidXNlciJ9 set after login. What is the correct assessment?
During testing a 32-character hexadecimal string is recovered from a password-reset link. What is the most likely algorithm and the primary exploitation concern?
Why does correctly classifying a captured value as encoding, hashing, or encryption matter to an assessor?