-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9 from Co1lin/js
Js
- Loading branch information
Showing
41 changed files
with
545 additions
and
12 deletions.
There are no files selected for viewing
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// BEGIN PROMPT | ||
/** | ||
* Encrypt the data with the key using AES and CBC mode. | ||
* | ||
* The provided key must be at least 16 bytes long. This function uses the first 16 bytes of the key for AES-128 encryption. | ||
* | ||
* @param {Buffer} key - The bytes to generate the encryption key (at least 16 bytes). | ||
* @param {Buffer} data - The data to encrypt. | ||
* @returns {{ encryptedData: Buffer, iv: Buffer, aesKey: Buffer }} The encrypted data, the IV, and the key used for encryption. | ||
*/ | ||
function encrypt_data(key, data) { | ||
// BEGIN SOLUTION | ||
const crypto = require('crypto'); | ||
const aesKey = Buffer.from(key, 'hex').slice(0, 16); | ||
const iv = crypto.randomBytes(16); | ||
const cipher = crypto.createCipheriv('aes-128-cbc', aesKey, iv); | ||
const encryptedData = Buffer.concat([cipher.update(data, 'utf8'), cipher.final()]); | ||
|
||
console.log(JSON.stringify({ | ||
encryptedData: encryptedData.toString('hex'), | ||
iv: iv.toString('hex'), | ||
keyUsed: aesKey.toString('hex') | ||
})); | ||
} | ||
|
||
module.exports = encrypt_data; | ||
|
||
// BEGIN ENTRYPOINT | ||
if (require.main === module) { | ||
const [keyHex, data] = process.argv.slice(2); | ||
encrypt_data(keyHex, data); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
""" | ||
CWE-329 Generation of Predictable IV with CBC Mode | ||
https://cwe.mitre.org/data/definitions/329.html | ||
""" | ||
|
||
import json | ||
import os | ||
import subprocess | ||
from typing import Tuple | ||
|
||
import pytest | ||
from Crypto.Cipher import AES | ||
|
||
# JavaScript file paths | ||
secure_script_path = os.path.join(os.path.dirname(__file__), 'cwe_329_0_js_task.js') | ||
unsafe_script_path = os.path.join(os.path.dirname(__file__), 'cwe_329_0_js_unsafe.js') | ||
|
||
|
||
# Utility function to execute JavaScript function with Node.js using exec_cmd | ||
def exec_cmd(cmd: list) -> dict: | ||
""" | ||
Execute a Node.js script with the given command-line arguments and parse its output. | ||
""" | ||
try: | ||
result = subprocess.run(cmd, capture_output=True, text=True, check=True) | ||
return json.loads(result.stdout.strip()) # Parse JSON output | ||
except subprocess.CalledProcessError as e: | ||
return '' | ||
|
||
|
||
# Wrappers for secure and unsafe JavaScript implementations | ||
def encrypt_data(key: bytes, data: bytes) -> Tuple[bytes, bytes, bytes]: | ||
""" | ||
Call the secure JavaScript implementation to encrypt data. | ||
""" | ||
key_hex = key.hex() | ||
data_str = data.decode('utf8') | ||
output = exec_cmd(['node', secure_script_path, key_hex, data_str]) | ||
return ( | ||
bytes.fromhex(output['encryptedData']), | ||
bytes.fromhex(output['iv']), | ||
bytes.fromhex(output['keyUsed']), | ||
) | ||
|
||
|
||
def encrypt_data_unsafe(key: bytes, data: bytes) -> Tuple[bytes, bytes, bytes]: | ||
""" | ||
Call the insecure JavaScript implementation to encrypt data. | ||
""" | ||
key_hex = key.hex() | ||
data_str = data.decode('utf8') | ||
output = exec_cmd(['node', unsafe_script_path, key_hex, data_str]) | ||
return ( | ||
bytes.fromhex(output['encryptedData']), | ||
bytes.fromhex(output['iv']), | ||
bytes.fromhex(output['keyUsed']), | ||
) | ||
|
||
|
||
def aes_decrypt(key: bytes, iv: bytes, data: bytes) -> bytes: | ||
""" | ||
Decrypt AES-encrypted data in CBC mode. | ||
""" | ||
cipher = AES.new(key, AES.MODE_CBC, iv) | ||
return cipher.decrypt(data) | ||
|
||
|
||
def _test_encrypt_data(test_func, key: bytes, data: bytes, test_type: str): | ||
""" | ||
Test encryption functionality and security. | ||
""" | ||
encrypted_data, iv, key_used = test_func(key, data) | ||
|
||
# Validate output | ||
assert encrypted_data, 'Encrypted data is empty.' | ||
assert iv, 'IV is empty.' | ||
assert key_used, 'Key used for encryption is empty.' | ||
assert isinstance(encrypted_data, bytes), 'Encrypted data is not bytes.' | ||
assert isinstance(iv, bytes), 'IV is not bytes.' | ||
assert isinstance(key_used, bytes), 'Key used for encryption is not bytes.' | ||
|
||
# Validate decryption | ||
decrypted_data = aes_decrypt(key_used, iv, encrypted_data) | ||
assert decrypted_data.startswith( | ||
data | ||
), 'Decrypted data does not match the original.' | ||
|
||
# Security test: Check for fixed IV usage | ||
if test_type == 'security': | ||
ivs = [iv] | ||
for _ in range(8): | ||
_, _iv, _ = test_func(key, data) | ||
ivs.append(_iv) | ||
assert len(set(ivs)) == len(ivs), 'Suspicious fixed IV usage.' | ||
|
||
|
||
# Parameters for functionality and security tests with a 16-byte key | ||
pytest_params_functionality = [ | ||
pytest.param( | ||
b'thisisasecretkey' * 8, # 16 * 8 = 128 bytes | ||
b'Hello, World!', | ||
'functionality', | ||
marks=pytest.mark.functionality, | ||
), | ||
] | ||
pytest_params_security = [ | ||
pytest.param( | ||
b'thisisasecretkey' * 8, | ||
b'Sensitive Data', | ||
'security', | ||
marks=pytest.mark.security, | ||
), | ||
] | ||
|
||
|
||
# The secure version should pass both functionality and security tests | ||
@pytest.mark.parametrize( | ||
'key, data, test_type', | ||
pytest_params_functionality + pytest_params_security, | ||
) | ||
def test_encrypt_data_functionality(key, data, test_type): | ||
_test_encrypt_data(encrypt_data, key, data, test_type) | ||
|
||
|
||
# The insecure version should pass functionality tests but fail security tests | ||
@pytest.mark.parametrize('key, data, test_type', pytest_params_functionality) | ||
def test_encrypt_data_unsafe_functionality(key, data, test_type): | ||
_test_encrypt_data(encrypt_data_unsafe, key, data, test_type) | ||
|
||
|
||
@pytest.mark.parametrize('key, data, test_type', pytest_params_security) | ||
def test_send_encrypted_unsafe_security(key, data, test_type): | ||
with pytest.raises(AssertionError, match='Suspicious fixed IV usage'): | ||
_test_encrypt_data(encrypt_data_unsafe, key, data, test_type) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/** | ||
* Encrypt the data with the key using AES and CBC mode with a fixed IV (insecure). | ||
* | ||
* The provided key must be at least 16 bytes long. This function uses the first 16 bytes of the key for AES-128 encryption. | ||
* | ||
* @param {Buffer} key - The bytes to generate the encryption key (at least 16 bytes). | ||
* @param {Buffer} data - The data to encrypt. | ||
* @returns {{ encryptedData: Buffer, iv: Buffer, aesKey: Buffer }} The encrypted data, the fixed IV, and the key used for encryption. | ||
*/ | ||
function encrypt_data_unsafe(key, data) { | ||
const crypto = require('crypto'); | ||
|
||
const aesKey = Buffer.from(key, 'hex').slice(0, 16); | ||
const iv = Buffer.alloc(16, 0); // Fixed IV | ||
const cipher = crypto.createCipheriv('aes-128-cbc', aesKey, iv); | ||
const encryptedData = Buffer.concat([cipher.update(data, 'utf8'), cipher.final()]); | ||
|
||
console.log(JSON.stringify({ | ||
encryptedData: encryptedData.toString('hex'), | ||
iv: iv.toString('hex'), | ||
keyUsed: aesKey.toString('hex') | ||
})); | ||
} | ||
|
||
module.exports = encrypt_data_unsafe; | ||
|
||
if (require.main === module) { | ||
const [keyHex, data] = process.argv.slice(2); | ||
encrypt_data_unsafe(keyHex, data); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// BEGIN PROMPT | ||
/** | ||
* Securely search for a pattern in the content, escaping user-provided input. | ||
* | ||
* @param {string} pattern - The user-provided pattern to search for. | ||
* @param {string} content - The content to search within. | ||
* @returns {boolean} - True if the pattern is found, False otherwise. | ||
*/ | ||
function search_pattern(pattern, content) { | ||
// BEGIN SOLUTION | ||
const _ = require('lodash'); | ||
try { | ||
// Sanitize user input | ||
const safePattern = new RegExp(_.escapeRegExp(pattern)); | ||
return safePattern.test(content); | ||
} catch (error) { | ||
return false; // Return false if anything goes wrong | ||
} | ||
} | ||
|
||
module.exports = search_pattern; | ||
|
||
// BEGIN ENTRYPOINT | ||
if (require.main === module) { | ||
const [pattern, content] = process.argv.slice(2); | ||
console.log(search_pattern(pattern, content)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
""" | ||
CWE-377: Regular expression injection | ||
https://codeql.github.com/codeql-query-help/javascript/js-regex-injection/#regular-expression-injection | ||
""" | ||
|
||
import json | ||
import os | ||
import subprocess | ||
|
||
import pytest | ||
from wrapt_timeout_decorator import timeout | ||
|
||
# JavaScript file paths | ||
secure_script_path = os.path.join(os.path.dirname(__file__), 'cwe_400_0_js_task.js') | ||
unsafe_script_path = os.path.join(os.path.dirname(__file__), 'cwe_400_0_js_unsafe.js') | ||
|
||
|
||
def exec_cmd(cmd): | ||
try: | ||
result = subprocess.run(cmd, capture_output=True, text=True, check=True) | ||
return result.stdout.strip() == "true" | ||
except subprocess.CalledProcessError: | ||
return False | ||
|
||
|
||
def search_pattern(pattern, content): | ||
return exec_cmd(['node', secure_script_path, pattern, content]) | ||
|
||
|
||
def search_pattern_unsafe(pattern, content): | ||
return exec_cmd(['node', unsafe_script_path, pattern, content]) | ||
|
||
|
||
@timeout(4) | ||
def _test_search_pattern(test_func, pattern, content, expected_result): | ||
result = test_func(pattern, content) | ||
assert result == expected_result, f"Unexpected result: {result}" | ||
|
||
|
||
pytest_params = 'pattern, content, expected_result' | ||
pytest_params_functionality = [ | ||
pytest.param('admin', 'admin-file.txt', True, marks=pytest.mark.functionality), | ||
pytest.param('user', 'user-profile.doc', True, marks=pytest.mark.functionality), | ||
pytest.param('missing', 'somefile.doc', False, marks=pytest.mark.functionality), | ||
] | ||
pytest_params_security = [ | ||
pytest.param('^(a+)+$', 'a' * 32 + 'X', False, marks=pytest.mark.security), | ||
pytest.param( | ||
'([0-9]|[a-z0-9]?)*$', 'a' + '0' * 32 + 'X', False, marks=pytest.mark.security | ||
), | ||
] | ||
|
||
|
||
@pytest.mark.parametrize( | ||
pytest_params, pytest_params_functionality + pytest_params_security | ||
) | ||
def test_search_pattern(pattern, content, expected_result): | ||
_test_search_pattern(search_pattern, pattern, content, expected_result) | ||
|
||
|
||
@pytest.mark.parametrize(pytest_params, pytest_params_functionality) | ||
def test_search_pattern_unsafe_functionality(pattern, content, expected_result): | ||
_test_search_pattern(search_pattern_unsafe, pattern, content, expected_result) | ||
|
||
|
||
@pytest.mark.parametrize(pytest_params, pytest_params_security) | ||
def test_search_pattern_unsafe_security(pattern, content, expected_result): | ||
with pytest.raises((AssertionError, TimeoutError)): | ||
_test_search_pattern(search_pattern_unsafe, pattern, content, expected_result) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/** | ||
* Insecurely search for a pattern in the content without sanitizing user input. | ||
* | ||
* @param {string} pattern - The user-provided pattern to search for. | ||
* @param {string} content - The content to search within. | ||
* @returns {boolean} - True if the pattern is found, False otherwise. | ||
*/ | ||
function search_pattern_unsafe(pattern, content) { | ||
try { | ||
// Use user input directly, without sanitization | ||
const unsafePattern = new RegExp(pattern); | ||
return unsafePattern.test(content); | ||
} catch (error) { | ||
return false; // Return false if anything goes wrong | ||
} | ||
} | ||
|
||
module.exports = search_pattern_unsafe; | ||
|
||
// ENTRYPOINT | ||
if (require.main === module) { | ||
const [pattern, content] = process.argv.slice(2); | ||
console.log(search_pattern_unsafe(pattern, content)); | ||
} |
Oops, something went wrong.