deardaniel/secdata-raw huggingface dataset:
Cryptopals Attack Solution — S1C03:

# http://www.data-compression.com/english.html
CHARACTER_FREQ = {
    'a': 0.0651738, 'b': 0.0124248, 'c': 0.0217339, 'd': 0.0349835, 'e': 0.1041442, 'f': 0.0197881, 'g': 0.0158610,
    'h': 0.0492888, 'i': 0.0558094, 'j': 0.0009033, 'k': 0.0050529, 'l': 0.0331490, 'm': 0.0202124, 'n': 0.0564513,
    'o': 0.0596302, 'p': 0.0137645, 'q': 0.0008606, 'r': 0.0497563, 's': 0.0515760, 't': 0.0729357, 'u': 0.0225134,
    'v': 0.0082903, 'w': 0.0171272, 'x': 0.0013692, 'y': 0.0145984, 'z': 0.0007836, ' ': 0.1918182
}


def get_english_score(input_bytes):
    """Returns a score which is the sum of the probabilities in how each letter of the input data
    appears in the English language. Uses the above probabilities.
    """
    score = 0

    for byte in input_bytes:
        score += CHARACTER_FREQ.get(chr(byte).lower(), 0)

    return score


def singlechar_xor(input_bytes, key_value):
    """XORs every byte of the input with the given key_value and returns the result."""
    output = b''

    for char in input_bytes:
        output += bytes([char ^ key_value])

    return output


def singlechar_xor_brute_force(ciphertext):
    """Tries every possible byte for the single-char key, decrypts the ciphertext with that byte
    and computes the english score for each plaintext. The plaintext with the highest score
    is likely to be the one decrypted with the correct value of key.
    """
    candidates = []

    for key_candidate in range(256):
        plaintext_candidate = singlechar_xor(ciphertext, key_candidate)
        candidate_score = get_english_score(plaintext_candidate)

        result = {
            'key': key_candidate,
            'score': candidate_score,
            'plaintext': plaintext_candidate
        }

        candidates.append(result)

    # Return the candidate with the highest English score
    return sorted(candidates, key=lambda c: c['score'], reverse=True)[0]


def pretty_print_result(result):
    """Prints the given resulting candidate in a pretty format."""
    print(result['plaintext'].decode().rstrip(), "\tScore:", "{0:.2f}".format(result['score']),
          "\tKey:", chr(result['key']))


def main():
    ciphertext = bytes.fromhex("1b[PII_REDACTED]3f78151b7f2b783431333d[PII_REDACTED]2d363c78373e783a393b3736")
    most_likely_plaintext = singlechar_xor_brute_force(ciphertext)
    pretty_print_result(most_likely_plaintext)

    # Check that the attack works properly
    assert most_likely_plaintext['plaintext'].rstrip() == b"Cooking MC's like a pound of bacon"


if __name__ == "__main__":
    main()
Cryptopals Attack Solution — S4C32:

from S4C31 import discover_mac_with_timing_attack


def main():
    """Solved the same way as challenge 31.
    To play between the two challenge, you can try to change the rounds value in the discover_mac function call
    and the delay value in the server module.

    NOTE: Make sure that the web server S4C31_server is running.
    """

    # Correct HMAC for foo: 8c80a95a8e72b3e822a[PII_REDACTED]a433e267d8
    discover_mac_with_timing_attack("foo", 10)


if __name__ == '__main__':
    main()
Cryptopals Attack Solution — S3C22:

from S3C21 import MT19937
from random import randint
from time import time

# This is to fake the current time and avoid waiting with a sleep()
current_time = int(time())


def routine_rng():
    """Performs the operations specified in the challenge and returns the first result of the
    newly created MT19937 rng.
    """
    global current_time
    current_time += randint(40, 1000)

    seed = current_time
    rng = MT19937(seed)

    current_time += randint(40, 1000)
    return seed, rng.extract_number()


def crack_mt19937_seed(rng_output):
    """Finds the seed that was used to get rng_output as the first output of an MT19937 rng.
    The approach used is to try the most recent timestamps as seeds until the
    first output of the newly created MT19937 matches rng_output.
    """
    global current_time

    # Start from the current timestamp plus one second, so that we can still find the seed even when the
    # timestamp was not increased (or the program ran fast enough to get the answer in the same timestamp)
    guessed_seed = current_time + 1
    rng = MT19937(guessed_seed)

    # Decrease the Unix timestamp by 1 second every time until we find the same output
    while rng.extract_number() != rng_output:
        guessed_seed -= 1
        rng = MT19937(guessed_seed)

    # If the output of a MT19937 with our guessed seed was the same as rng_output, then
    # it means that the seed we guessed was really equal to the original one.
    return guessed_seed


def main():
    real_seed, rng_output = routine_rng()
    assert real_seed == crack_mt19937_seed(rng_output)


if __name__ == '__main__':
    main()
Cryptopals Attack Solution — S2C11:

from S1C08 import count_aes_ecb_repetitions
from S2C10 import aes_ecb_encrypt, aes_cbc_encrypt
from random import randint
from Crypto.Cipher.AES import block_size
from Crypto import Random


class AesEncryptionOracle:
    """Oracle which encrypts the given data using every time a random AES method (chosen between ECB and CBC),
    a random key, a random iv (in case of CBC) and also adds a random padding before and after the plaintext.
    """

    @staticmethod
    def encrypt(plaintext):
        # Add a random padding before and after the plaintext
        padded_plaintext = AesEncryptionOracle._pad_with_bytes(plaintext)

        # Generate a random key
        key = Random.new().read(block_size)

        # Encrypt randomly with ECB or CBC
        if randint(0, 1) == 0:
            return "ECB", aes_ecb_encrypt(padded_plaintext, key)
        else:
            return "CBC", aes_cbc_encrypt(padded_plaintext, key, Random.new().read(block_size))

    @staticmethod
    def _pad_with_bytes(binary_data):
        """Returns the given binary_data with a padded with a short random prefix and suffix."""
        return Random.new().read(randint(5, 10)) + binary_data + Random.new().read(randint(5, 10))


def detect_cipher(ciphertext):
    """Detects if the given ciphertext was encrypted with ECB or CBC mode."""

    # When there are some repeated chunks in the ciphertext, it is most likely becaues
    # it wes encrypted with ECB
    if count_aes_ecb_repetitions(ciphertext) > 0:
        return "ECB"
    else:
        return "CBC"


def main():
    oracle = AesEncryptionOracle()

    # We choose a repeating input data so that we will be able to detect
    # repetitions in the ciphertext (if it's encrypted with ECB) later.
    input_data = bytes([0]*64)

    # Check that the detection method works correctly
    for _ in range(1000):
        encryption_used, ciphertext = oracle.encrypt(input_data)
        encryption_detected = detect_cipher(ciphertext)
        assert encryption_used == encryption_detected


if __name__ == '__main__':
    main()
Cryptopals Attack Solution — S6C46:

from base64 import b64decode
from S5C39 import int_to_bytes, RSA
from math import ceil, log
from decimal import *


class RSAParityOracle(RSA):
    """Extends the RSA class by adding a method to verify the parity of data."""

    def is_parity_odd(self, encrypted_int_data):
        """Decrypts the input data and returns whether the resulting number is odd."""
        return pow(encrypted_int_data, self._d, self.n) & 1


def parity_oracle_attack(ciphertext, rsa_parity_oracle, holliwood=False):
    """Decrypts the given ciphertext using just the parity method of the oracle. Here a detailed explanation:
    http://secgroup.dais.unive.it/wp-content/uploads/2012/11/Practical-Padding-Oracle-Attacks-on-RSA.html
    """

    # Compute the encryption of 2, which will be our ciphertext multiplier
    multiplier = pow(2, rsa_parity_oracle.e, rsa_parity_oracle.n)

    # Initialize lower and upper bound.
    # I need to use Decimal because it allows me to set the precision for the floating point
    # numbers, which we will need when doing the binary search divisions.
    lower_bound = Decimal(0)
    upper_bound = Decimal(rsa_parity_oracle.n)

    # Compute the number of iterations that we have to do
    k = int(ceil(log(rsa_parity_oracle.n, 2)))

    # Set the precision of the floating point number to be enough
    getcontext().prec = k

    # Binary search for the correct plaintext
    for _ in range(k):
        ciphertext = (ciphertext * multiplier) % rsa_parity_oracle.n

        if rsa_parity_oracle.is_parity_odd(ciphertext):
            lower_bound = (lower_bound + upper_bound) / 2
        else:
            upper_bound = (lower_bound + upper_bound) / 2

        # If the user wants to see the message being decrypted at every iteration, print the current upper_bound
        if holliwood is True:
            print(int_to_bytes(int(upper_bound)))

    # Return the binary version of the upper_bound (converted from Decimal to int)
    return int_to_bytes(int(upper_bound))


def main():
    input_bytes = b64decode("VGhhdCdzIHdoeSBJIGZvdW5kIHlvdSBkb24ndCBwbGF5IG"
                            "Fyb3VuZCB3aXRoIHRoZSBGdW5reSBDb2xkIE1lZGluYQ==")

    rsa_parity_oracle = RSAParityOracle(1024)

    ciphertext = rsa_parity_oracle.encrypt(input_bytes)
    rsa_parity_oracle.decrypt(ciphertext)

    # Check if the attack works
    plaintext = parity_oracle_attack(ciphertext, rsa_parity_oracle)
    assert plaintext == input_bytes


if __name__ == '__main__':
    main()
Cryptopals Attack Solution — S4C26:

from S3C18 import aes_ctr
from random import randint
from Crypto import Random
from Crypto.Cipher import AES
from S2C10 import xor_data


class Oracle:

    def __init__(self):
        self._key = Random.new().read(AES.key_size[0])
        self._nonce = randint(0, 2 ** 32 - 1)
        self._prefix = "comment1=cooking%20MCs;userdata="
        self._suffix = ";comment2=%20like%20a%20pound%20of%20bacon"

    def encrypt(self, data):
        """Adds the prefix and the suffix specified in the challenge and encrypts the data with AES-CTR"""
        data = data.decode().replace(';', '').replace('=', '')  # Remove special characters to avoid injection
        plaintext = (self._prefix + data + self._suffix).encode()
        return aes_ctr(plaintext, self._key, self._nonce)

    def decrypt_and_check_admin(self, ciphertext):
        """Decrypts the string and returns whether the characters ";admin=true;" are in the string"""
        data = aes_ctr(ciphertext, self._key, self._nonce)
        return b';admin=true;' in data


def get_prefix_length(oracle):
    """Finds the length of the prefix that mysterious_encrypt adds to the plaintext before encrypting."""
    # Encrypt two different ciphertexts
    ciphertext_a = oracle.encrypt(b'A')
    ciphertext_b = oracle.encrypt(b'B')

    # Since the stream ciphers encrypts bit by bit, the prefix length will be equal to
    # the number of bytes that are equal in the two ciphertext.
    prefix_length = 0
    while ciphertext_a[prefix_length] == ciphertext_b[prefix_length]:
        prefix_length += 1

    return prefix_length


def ctr_bit_flip(oracle):
    """Performs a stream cipher bit flipping attack to accomplish admin privileges in the decrypted data."""
    plaintext = b'?admin?true'
    ciphertext = oracle.encrypt(plaintext)

    # Prepare the data with which we want to XOR our goal ciphertext substring
    goal_text = b';admin=true'
    insert = xor_data(plaintext, goal_text)

    # Find the position where our goal ciphertext substring starts
    prefix_length = get_prefix_length(oracle)

    # Force our goal ciphertext block to be the encryption of our goal text
    forced_ciphertext = ciphertext[:prefix_length] + \
                        xor_data(ciphertext[prefix_length:prefix_length + len(plaintext)], insert) + \
                        ciphertext[prefix_length + len(plaintext):]

    return forced_ciphertext


def main():
    oracle = Oracle()
    forced_ciphertext = ctr_bit_flip(oracle)

    # Check if the ciphertext was forced properly
    assert oracle.decrypt_and_check_admin(forced_ciphertext)


if __name__ == "__main__":
    main()
Cryptopals Attack Solution — S1C07:

from base64 import b64decode
from Crypto.Cipher import AES
from S2C09 import pkcs7_unpad


def aes_ecb_decrypt(data, key):
    """Decrypts the given AES-ECB encrypted data with the given key.
    The un-padding part has been added to support the use that I will make of this
    method on future challenges (for the sake of this challenge it's not needed).
    """
    cipher = AES.new(key, AES.MODE_ECB)
    return pkcs7_unpad(cipher.decrypt(data))


def main():
    with open("S1C07_input.txt") as input_file:
        binary_data = b64decode(input_file.read())

    # Compute and print the decrypted plaintext
    print(aes_ecb_decrypt(binary_data, b'YELLOW SUBMARINE').decode().rstrip())


if __name__ == "__main__":
    main()
Cryptopals Attack Solution — S6C41:

from S5C39 import RSA, mod_inv, int_to_bytes
from random import randint


def unpadded_message_recovery(ciphertext, rsa_server):
    """Performs the unpadded message recovery attack on the rsa_server which does not use padding."""

    # Let N and E be the public modulus and exponent respectively
    e, n = rsa_server.get_public_key()

    # Let S be a random number > 1 mod N
    while True:
        s = randint(2, n - 1)
        if s % n > 1:
            break

    # Create a new forged ciphertext
    new_ciphertext = (pow(s, e, n) * ciphertext) % n

    # Decipher it and convert the deciphered string to an int
    new_plaintext = rsa_server.decrypt(new_ciphertext)
    int_plaintext = int.from_bytes(new_plaintext, byteorder='big')

    # Recover the original plaintext as int, remembering to be careful about division in cyclic groups
    r = (int_plaintext * mod_inv(s, n)) % n

    # Convert it back to bytes and return it
    return int_to_bytes(r)


class RSAServer:
    """This server allows to submit an arbitrary RSA blob and will return the corresponding plaintext
    decrypted with the private key stored on the server. However, it keeps hashes of the messages that
    have been decrypted and rejects the decryption when a ciphertext is submitted more than once.
    NOTE: the messages are supposed to have an embedded timestamp, so they are unique.
    """

    def __init__(self, rsa):
        self._rsa = rsa
        self._decrypted = set()

    def get_public_key(self):
        return self._rsa.e, self._rsa.n

    def decrypt(self, data):
        """If the data has not be decrypted before, it decrypts it, otherwise it raises an exception."""
        if data in self._decrypted:
            raise Exception("This ciphertext has already been decrypted")
        self._decrypted.add(data)
        return self._rsa.decrypt(data)


def main():
    plaintext = b"Hello, I'm another Javascript programmer."
    rsa = RSA(1024)
    ciphertext = rsa.encrypt(plaintext)
    rsa_server = RSAServer(rsa)

    # Test if the attack works
    recovered_plaintext = unpadded_message_recovery(ciphertext, rsa_server)
    assert recovered_plaintext == plaintext


if __name__ == '__main__':
    main()
44

msg: Listen for me, you better listen for me now. 
s:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]615804316
r:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]10474875
m: a4db3de27e2db3e5ef085ced2bced91b82e0df19
msg: Listen for me, you better listen for me now. 
s:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]9516683
r:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]4169532
m: a4db3de27e2db3e5ef085ced2bced91b82e0df19
msg: When me rockin' the microphone me rock on steady, 
s:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]13405915
r:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]45721541
m: 21194f72fe39a80c9c20689b8cf6ce9b0e7e52d4
msg: Yes a Daddy me Snow me are de article dan. 
s:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]122277350
r:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]857446485
m: 1d7aaaa05d2dee2f7dabdc6fa70b6ddab9c051c5
msg: But in a in an' a out de dance em 
s:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]95279549
r:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]5133736
m: 6bc188db6e9e6c7d796f7fdd7fa411776d7a9ff
msg: Aye say where you come from a, 
s:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]5114553
r:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]9264007
m: 5ff4d4e8be2f8aae8a5bfaabf7408bd7628f43c9
msg: People em say ya come from Jamaica, 
s:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]059955513
r:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]40220795
m: 7d9abd18bbecdaa93650ecc4da1b9fcae911412
msg: But me born an' raised in the ghetto that I want yas to know, 
s:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]14568162
r:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]75316699
m: 88b9e184393408b133efef59fcef85576d69e249
msg: Pure black people mon is all I mon know. 
s:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]552714967
r:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]10474875
m: d22804c4899b522b23eda34d2137cd8cc22b9ce8
msg: Yeah me shoes a an tear up an' now me toes is a show a 
s:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]62367256
r:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]4169532
m: bc7ec371d951977cba10381da08fe934dea80314
msg: Where me a born in are de one Toronto, so 
s:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]82138703
r:[PII_REDACTED][PII_REDACTED][PII_REDACTED][PII_REDACTED]45721541
m: d6340bfcda59b6b75b59ca634813d572de800e8f
flaws2.cloud AWS Security Challenge

flaws2.cloud
flAWS 2
Brought to you by
Scott Piper
.
Welcome to the flAWS 2 challenge! Similar to the original
flAWS.cloud
(also created by Summit Route), this game/tutorial teaches you AWS (Amazon Web Services) security concepts. The challenges are focused on AWS specific issues, so no buffer overflows, XSS, etc. You can play by getting hands-on-keyboard or just click through the hints to learn the concepts and go from one level to the next without playing.
flAWS 2 has two paths this time: Attacker and Defender!  In the Attacker path, you'll exploit your way through misconfigurations in serverless (Lambda) and containers (ECS Fargate). In the Defender path, that target is now viewed as the victim and you'll work as an incident responder for that same app, understanding how an attack happened.  You'll get access to logs of a previous successful attack.  As a Defender you'll learn the power of jq in analyzing logs, and instructions on how to set up Athena in your own environment.
I recommend first playing the Attacker Side and then going back and playing the Defender side.
Choose your destiny:
Attacker!
Defender!
README

This terraform code will deploy an EC2 instance in a VPC, with the VPC endpoints that are necessary to complete this scenario. Only a few AWS services are needed to be used at this stage in the scenario, so only the associated endpoints (and those required for SSM to function) are deployed.

In order to use this terraform code to finish the scenario you need to:
* Identify the IP of the ec2 instance you want to spoof (CloudTrails does not distinguish between public and private IPs in the "sourceIPAddress" field).
* run `terraform init`
* run `terraform apply -var profile="__aws_profile_name__" -var target_ip="__ec2.instance.ip.addr__"`
  * This assumes the instance IP is in the `3.84.104.*` range. If it's not, you'll need to set `-var target_cidr_block="__cidr.ip.block__/24"
* Ensure the SSM awscli plugin is installed ([SSM plugin install docs](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html)).
* log into the console and get a shell on the instance with ssm.

    ```bash
    # The following command will return a shell from the target instance. If you getting a (TargetNotConnected) error and you just deployed the resources, wait 10 min and try again. There can be a lag time before SSM works properly.
    aws --profile cg4 --region us-east-1 ssm start-session --target [INSTANCE_ID]
    ```
README


# Scenario: lambda_privesc

**Size:** Small

**Difficulty:** Easy

**Command:** `$ ./cloudgoat.py create lambda_privesc`

## Scenario Resources

- 1 IAM User  
- 2 IAM Roles  

## Scenario Start(s)

1. IAM User Chris

## Scenario Goal(s)

Acquire full admin privileges.

## Summary

Starting as the IAM user Chris, the attacker discovers that they can assume a role that has full Lambda access and pass role permissions. The attacker can then perform privilege escalation to obtain full admin access.

Note: This scenario may require you to create some AWS resources, and because CloudGoat can only manage resources it creates, you should remove them manually before running `./cloudgoat destroy`.

## Exploitation Route(s)

![Scenario Route(s)](https://app.lucidchart.com/publicSegments/view/f1b7a749-dee0-4645-b305-add2a025b9cc/image.png)


## Walkthrough - IAM User "Chris"

1. Starting as the IAM user "Chris",  the attacker analyses their privileges.
2. The attacker realizes they are able to list and assume IAM roles. There are two interesting IAM roles: lambdaManager and debug.
3. The attacker looks at the attached policies for the two IAM roles and realizes lambdaManager has full lambda access and pass role permissions and the debug role has full administrator privileges.
4. The attacker then tries to assume each role but realizes that they only have sufficient privileges to assume the lambdaManager role, and that the debug role can only be assumed by a Lambda function.
5. The attacker now leverages the lambdaManager role to perform a privilege escalation using a Lambda function.
6. First, the attacker writes a script that will attach the administrator policy to the IAM user "Chris".
7. Next, using the lambdaManager role, the attacker creates a Lambda function, specifying the code in step 6, and set the lambda execution role to the debug role.
8. Lastly, using the lambdaManager role, the attacker invokes the Lambda function, causing the administrator policy to be attached to the "Chris" user and thus gaining full admin access.

A cheat sheet for this route is available [here](./cheat_sheet_chris.md).