Simens Crypto CTF Tasks
Simens Crypto CTF Tasks
June 2020
© Copyright Simen Karlsen Lone
The material in this publication is protected by copyright law.
First and foremost I wish to thank my supervisors Håvard Raddum and Chris Dale, for the
opportunity to do this fun thesis. Your knowledge, guidance and patience has been invaluable.
Also thank you for helpful comments on the text.
Secondly i want to thank family and friends and my girlfriend Hege for support and
encouragement.
-Simen Lone
iv Acknowledgements
Abstract
Security has become an increasingly important aspect of computer science as our lives be-
come more interconnected with the internet. In modern times it has become near impossible
to live a disconnected life. Most of us use multiple services like banking, welfare services
(NAV) and social networks on a daily basis. As all these services are always online they face
a constant threat of being attacked. Creating software is hard and a tiny bug can have severe
results leading to a data breach. This has resulted in an increased need for personnel with
knowledge of security and how to write secure code.
This thesis aims to look at some common implementation flaws with the theme of cryp-
tography and teach how to prevent them. This was achieved by creating gamified versions of
the cryptographic flaws , where the intent is to learn how to exploit the flaws. This was done
by crating the challenges in a form suited for CTF competitions. Through the understanding
gained by performing an attack one should also learn how to prevent the flaw in future.
The thesis is written in four parts. The first part gives a summary of the cryptographic
primitives and tools needed to understand the flaws. The second describes the cryptographic
flaws, and how they occurred and can be abused. A solution or fix is suggested if appropriate.
The third describes the implementation process of the CTF challenges with the flaws and
provides the intended solution to them (here meaning how to exploit them). The final part is
a summery of the process of making the scenarios, implementing them and lessons learned.
vi Abstract
Contents
Acknowledgements iii
Abstract v
1 Introduction 1
1.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 NetSecurity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.1 Collaboration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.2 About . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2 Cryptographic primitives 5
2.1 Symmetric cryptography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1.1 The Advanced Encryption Standard . . . . . . . . . . . . . . . . . . 5
2.2 Asymmetric cryptography . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.2.1 RSA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.3 Diffie–Hellman key exchange . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.4 Hashing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.4.1 Bcrypt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
3 Applied Cryptography 11
3.1 Examples of crypto in software . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.1.1 An IoT device example . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.2 Identity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.2.1 Certificates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.2.2 Certificate Authority . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.2.3 Authentication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.2.4 Multi factor Authentication . . . . . . . . . . . . . . . . . . . . . . . 16
3.3 Attacks on identity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.3.1 Man in the middle . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.3.2 SSL Stripping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.3.3 HTTP Strict Transport Security . . . . . . . . . . . . . . . . . . . . . 18
3.4 Reverse engineering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.4.1 Client Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.4.2 Android . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.4.3 Rooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.4.4 Reverse Engineering Tools . . . . . . . . . . . . . . . . . . . . . . . 20
viii CONTENTS
5 Implementation of tasks 35
5.1 Technologies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
5.1.1 Languages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
5.2 Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
5.2.1 Docker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
5.2.2 Docker Compose . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
5.2.3 Android Studio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
5.2.4 OpenSSL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
5.3 Implementation of the CTF challenges . . . . . . . . . . . . . . . . . . . . . 38
5.3.1 Certificate pinning . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
5.3.2 Validation and enumeration . . . . . . . . . . . . . . . . . . . . . . . 40
5.3.3 Padding oracle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
5.3.4 Replay attack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
5.3.5 Bad random number generator . . . . . . . . . . . . . . . . . . . . . 46
5.4 Deployments of tasks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
5.4.1 Metadata files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
5.4.2 Building and Running the Challenges . . . . . . . . . . . . . . . . . 47
6 Summary 49
6.1 Lessons learned in designing CTF tasks . . . . . . . . . . . . . . . . . . . . 49
A Source code 51
A.1 Certificate Pinning source . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
A.1.1 Android App . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
A.1.2 Backend . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
A.2 Padding oracle source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
A.2.1 Backend . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
A.2.2 Client . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
A.3 Repeatable game source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
A.3.1 Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
A.3.2 Backend . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
A.4 Bad random number generator source . . . . . . . . . . . . . . . . . . . . . 60
Bibliography 63
Chapter 1
Introduction
1.1 Motivation
Internet and the ever growing online presences has come to stay. Most of us do many forms of
online activity on a daily basis. It can be a personal chat with a partner or friend. A checkup on
personal finance. Consuming news from an online tabloid or other news source or interacting
in other online communities. This in turn has resulted in vast amounts of information about us
that are stored on different servers owned by the service providers, that needs to be protected.
Personal finance probably being one of the most important.
Despite companies today starting to focus on solving security issues, this has not always
been the case. In the early stages of the Internet people were naive and traffic was sent as
plaintext. One could simply climb up a lamp post and read what was sent over the wire with
the help of a computer. The early lack of verification made it easy to set up lookalikes of web
pages and harvest user credentials from victims landing on the page and then redirecting to
the real site without the them knowing. Another problem is/was passwords stored in plaintext
on the server. If a data breach were to happen the passwords gained by the attacker could be
tried on other pages if the same password was used in multiple places.
Luckily we have learned form our mistakes and there are solutions for a few of these
problems. When chatting with a partner or friend, cryptography can be used to establish
secure communications between the two of you. The messages will only be readable by the
sender and receiver and no one in between, not even the maker of the app. Cryptography
allows us to validate identity. We can check if the website we visit actually is the site we
tried to visit and not someone serving a fake version of it. We have invented better ways of
authenticating ourselves with using more than a simple password, by introducing a second
factor like a code generator or using sim card technology. The server does not need to know
your password any more. It only knows a hashed version that can not be used to find the
actual password, thus stopping the attacker from trying your password other places. Even in
the case of a leak the data can be encrypted such that it is useless without a key. But alas,
cryptography is hard. Mistakes have been made and will be made.
The motivation for this thesis is to showcase common mistakes done by developers when
implementing cryptography in applications, hopefully in a fun and engaging way. The pur-
pose is that the showcased mistakes will not be repeated. This will be done by creating ap-
plications with the flaws built in to them in the form of capture the flag challenges. Capture
the flag, often abbreviated to CTF, has its name from the child game with the same name.
2 1. Introduction
The objective of a CTF competition is the same as in the child game: Capture the flag. In a
CTF competition the flag is usually a string on the format ”flag{some text}”. The flag can be
turned in and the player(s) receives points. CTFs come in many shapes. There are big online
events like Google’s CTF. There are smaller local CTFs where the contestants physically
meet up and there are always online challenges where one can play at ones own pace.
Now to the fun and engaging part. In this thesis i will create a number of applications
with common flaws that can be found in real life. Each of the applications contain a hidden
flag which can be turned in to the game server for points. The flag is hidden in such a way
that it can (hopefully) only be found by exploiting the intended flaw in the application. To
be able to exploit the flaw the player needs to have an understanding on how the flaw came
to be and how to leverage it to do something malicious.
An example of such a flaw could be a bug that causes the server application to crash if
malformed data is sent. A crash is bad, but the client and server code are both written by
the same developer, therefore the developer assumes that malformed data will never be sent
from the client. This however does not hinder a malicious attacker from sending malformed
data to the server and making the services provided by the server unavailable to all users,
commonly called a denial of service (DoS) attack.
By exploiting these vulnerabilities oneself, one learns how they work, and how something
that seems innocent can be exploited to cause big trouble. With the attacker’s perspective it
is easier to understand how one will be attacked, and I believe this knowledge makes it is
easier to figure out how to defend against attacks.
If you know the enemy and know yourself, you need not fear the result of a
hundred battles. If you know yourself but not the enemy, for every victory gained
you will also suffer a defeat. If you know neither the enemy nor yourself, you will
succumb in every battle. ― Sun Tzu, The Art of War
1.2 NetSecurity
1.2.1 Collaboration
This thesis is done in collaboration with Netsecurity. The company holds multiple CTF com-
petitions a year with the purpose of training people in security and raise awareness around
the topic. The intent with this collaboration is to make more CTF challenges for the plat-
form, making it more complete. A special focus was put on challenges with cryptography
as a theme, as Netsecurity wants more challenges of that type. Hopefully this thesis and
challenges it contains can provide insight to a few common common attack vectors of crypto
systems, and how to prevent them. The goals of this collaboration was met and the challenges
in this thesis have been added to Netsecurity’s CTF platform.
1.2.2 About
Netsecurity AS is a Norwegian company established in 2009. They are located in Oslo,
Bergen, Kristiansand, Grimstad and Stavanger. They deliver services and solutions that al-
lows businesses and organisations to conduct their online work in safety, allowing cyber
1.2 NetSecurity 3
attacks to be detected and stopped in an early phase, preventing severe consequences for
their customers.
Their employees are the customers’ most important resource. They especially empha-
size competence, integrity and customer proximity. They employ the best and motivate their
employees for continuous learning and improvement.
They claim to live by their reputation. They strive to be close and accessible to their
customers. They want customers where they can actively support and assist their customers’
business. They claim that if one choose Netsecurity, one should know that one can trust them
and that one will have access to the best expertise, services and solutions on the market.
They have customers throughout the country within the public and private sectors. The
common denominator for their customers is that their network and security are important to
their business.
While most companies and consultants in the industry provide a wide range of services,
Netsecurity works exclusively with network and security solutions, and provides solutions
and services like:
• Firewall Audit
• Penetration testing
• Security assessment
• Incident Response
• Backup
• Disaster Recovery
• Managed IT-services
4 1. Introduction
Chapter 2
Cryptographic primitives
all the rows are left-shifted by a number of steps equal to their zero-indexed row index. The
third step is the mixing of columns. Each column is multiplied by a predefined matrix in
GF (28 ) using x8 + x4 + x3 + x + 1 as the irreducible polynomial. The resulting vector is used
as the new column. Lastly, the next round key is xor’ed with state. For the last round only
the byte substitution, row shifting and round key xor’ing is preformed on the state, and the
mix columns is left out.
2.2.1 RSA
RSA is an acronym made of the initial letters of the surnames of Ron Rivest, Adi Shamir,
and Leonard Adleman. They first publicly described the algorithm in 1977. Clifford Cocks,
an English mathematician working for the British intelligence agency Government Commu-
nications Headquarters (GCHQ), had developed an equivalent system in 1973, but this was
not declassified until 1997.
RSA is one of the first asymmetric crypto systems, also called public key crypto system.
RSA is based on the problem of factoring a number into primes. The problem can be framed
as follows: given a big random number n find all the prime factors of the number. There is
no known algorithm efficient enough to break today’s key sizes [23] of at least 2048 bits. The
hardness of this problem is the foundation of the security of RSA.
RSA can be described with the three steps of key generation, encryption and decryption.
Key generation: For key generation, two random primes p and q are chosen. They have
to be sufficiently big such that the task of factoring the product is not feasible in reasonable
time on today’s hardware.
• n is computed as p × q
• λ(n) is computed. This can be computed as lcm(p − 1, q − 1)
• e is chosen, it needs to be 1 < e < λ(n) and gcd(e, λ(n)) = 1. One wants e to be as
small as possible as it yields faster computation. The number 3 is the smallest possible
candidate but it is not used as it has been shown that small public exponents are insecure
[21]. The standard public exponent used today is 65537. This is because it is big enough
to be safe from attacks working on smaller primes and gives a good trade off between
security and computational speed as it is a 2n +1 prime making exponentiation efficient
to compute.
• d is the last thing computed and is the inverse of e mod λ(n). This can be computed
using the extended euclidean algorithm.
• e and n are exposed as the public key. The values of p, q, d and λ(n) are the private key,
and are to be kept secret.
2.3 Diffie–Hellman key exchange 7
Encryption: The message m is encrypted into the cipher text c as follows c ≡ me mod n
2.4 Hashing
A hash function is a function taking an input of arbitrary length and returning a value of fixed
length. The value returned is called a hash or digest. A hashing function is a deterministic
function and that means that for a given input a the resulting value b will always be the same.
From the definition of hashing given above one can observe that the domain of the function
is infinite but the co-domain is finite. This means that for each value a there will exist a value
a′ such that H(a) = H(a′ ). This is called a collision.
Hash functions are used in a common programming structure called a hashmap. This is
a list structure where fetching an element given a key can be done in constant time. It is
implemented where the key is hashed and the resulting hash is used as the index in to a list
where the data is stored. This allows for arbitrary length keys and not needing to know a
specific index to retrieve an item. In this scenario a collision would be bad as it results in
two items being mapped to the same spot in the list. Therefore one wants hashing functions
where collisions do not happen in practical use.
Hashing is a primitive often used in cryptography, but for a hash function to be crypto-
graphically secure it needs to have a few extra properties namely :
8 2. Cryptographic primitives
A one way function is a function where one can easily compute the output of the function
given the input a, but if given the output b it is computationally infeasible to compute a.
A categorically safe hash function has a strict requirement to collisions. For a hashmap,
as long as collisions rarely happens, there is a speed vs collision rate trade-off that is not
acceptable for cryptographic uses. If a hash is used as message check sum collisions can be
fatal. Let us assume a scenario where a hash is used to provide a checksum. If a collision
were to be found an attacker could change the message to the colliding input and thus altering
the entire message sent to the receiver without the receiver noticing.
2.4.1 Bcrypt
In the case of a hashmap one wants a fast hashing function to minimize the time it takes to
retrieve an element in the list. There are many fast hashing algorithms, like SHA-256. These
algorithms should not be used to store password.
The average human does not like to remember long and complicated things, like pass-
words. This often results in short and common passwords. So when password hashes are
leaked, instead of trying to reverse the hashing function with is be design hard to do, the
attacker tries many variants of short passwords. The attacker is able to test a given amount of
passwords per second. So the faster the hashing algorithm is to compute, the more passwords
the attacker gets to test per second.
Bcrypt is a hashing algorithm specialized for hashing passwords. The algorithm allows a
second argument to be passed to it, determining the hardness of the hash computation. When
a user logs on the server has to compute a single hash to validate the users login request. The
attacker on the other hand has to try to guess the user’s password and try a lot of possible
passwords. So a half second wait on the login page would not pose a big annoyance to the
user, but would cripple the attacker, as for Ethash hashes with a high end graphics card like
AMD Radeon VII 16 GB one can compute 95.3M h/s, compared to only a few bcrypt hashes
per second [6].
Bcrypt also comes with a third parameter which is the salt. A salt is just a random number.
The idea behind a salt is that users tends to use easy passwords and this often results in
multiple users having the same password. This is bad as this results in two users having
the same password hash, when the attacker finds the password of one user the attacker gets
the second user for free. This can be prevented by giving each user a unique salt. This is
simply appended to the password and the combined string is hashed. In the case of Bcrypt
it is passed as the third argument. Since each user has a unique salt, this makes the string
passed for hashing unique pr user even if the password part of the string is the same. This
results in unique hashes, thus eliminating the attacker’s one for free opportunities.
10 2. Cryptographic primitives
Chapter 3
Applied Cryptography
unwrapped from the WiFi wrappings and sent as plain text by default. So a new layer of
encryption is deployed to ensure that the traffic gets safely to the mediator. This is typically
http traffic combined with TLS (sent over a TLS connection). The phone then connects to
the mediator over TLS as the fridge did.
A new problem arises as there are thousands or millions of fridges and owners with apps
on their phones. Who should be connected to witch fridge? A new crypto concept needs to be
introduced: the identity. We need a way to identify a fridge, a user, and validate a user’s claim
to ownership over said fridge. The fridge is usually identified by sending a serial number over
the secure channel in such a way that the identifying packet cannot be replayed or spoofed.
Timestamps and Message Authentication Codes (MACs) can be employed to ensure this.
The user typically creates an account and enters the serial number of the fridge, found in a
manual or on the device itself. So when the fridge and the user claim the same serial number
the mediator knows how to pair them up.
In this scenario the user also needs to be identified and this is usually done with a password
and hopefully a second factor like a verification code on SMS or another second factor. The
mediator stores the user’s password so it can compare it with the user’s entered password.
Here hashing is used so that the user’s actual password is not stored on the server in case
of a breach of the server. The code used as the second factor must not be guessable and this
introduces the need for a pseudo random number generator.
As we can see from this small example, there is a lot of crypto all around us at all times.
In this small example we have seen use of AES in multiple block modes, MAC algorithms,
the SHA-1 hashing algorithm and the use public key cryptography used both for integrity
and authenticity. Cellular networks were also briefly named and that also bring with it a few
extra primitives.
3.2 Identity
3.2.1 Certificates
A digital certificate functions much like its real-life counter part in that it is a document
proving something about the owner of the document. It is issued by an authority and singed
by this authority. This signing of the backing authority is what gives the certificates their
trust and validity.
In the case of a public key certificate it proves the public key on the certificate belongs to
the owner. By being able to verify the owner’s public key one can establish a secure connec-
tion with the owner as only the owner has the corresponding private key, thus rendering man
in the middle attacks impossible. This is the main point of digital certificates: being able to
identify and establish secure connections between two parties.
Identity
As mentioned, certificates online can be used to establish the identity of the owner. The most
common standard for certificates is the X.509, described in RFC 5280 [18]. X.509 certificates
contain three parts. A tbsCertificate, signatureAlgorithm and signatureValue. The identity is
provided by the tbsCertifcate as this is the part of the certificate that gets signed. This part
3.2 Identity 13
contains the fields version, serialNumber, signature, issuer, validity, subject, subjectPublicK-
eyInfo. If the version of the certificate is greater than one, issuerUniqueID, subjectUniqueID
and extensions may be included. The first two extra fields requires version two and exten-
sions require version three.
Version
The version field gives the version of the certificate and allowed values are v1, v2, v3. Version
3 is what is commonly used.
serialNumber
is the certificate’s serial number and is an integer chosen by the certificate authority and must
be unique for all certificates issued by that certificate authority. The integer must be in the
range 0 to 2160 .
signature
The signature field contains the signing algorithm of the certificate and must have the same
value as the signatureAlgorithm field. As to why there is a duplicate field there is no good
explanation, according to Peter Gutmann’s X.509 style guide [20]:
There doesn’t seem to be much use for this field, although you should check that
the algorithm identifier matches the one of the signature on the cert.
The signature is of the type AlgorithmIdentifier containing the fields algorithm and param-
eters. The algorithm field being a string identifying the algorithm used for signing and pa-
rameter being an optional field used to specify any parameters to be used with the algorithm.
Issuer
Issuer is a field detailing the certificate issuer, also known as the certificate authority. This
field contains a distinguished name, DN for short. The issuer field is defined in X.501 as
Name. A Name is defined as a RelativeDistinguishedName. The name contains the follow-
ing fields: Country, State/Province, Locality, Organization, Organizational Unit, Common
Name. Example string C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc.,
OU=http://certs.godaddy.com/repository/, CN=Go Daddy Secure Certificate Authority - G2
Validity.
Validity
Validity contains two subfields, Not Before and Not After. These fields contain dates and
give the validity period of the certificate.
Subject
The subject field is of type Name and is the same as described for the issuer. This details the
identity of the owner of the certificate. For web certificates the common name would be the
domain.
14 3. Applied Cryptography
subjectPublicKeyInfo
The field subjectPublicKeyInfo has two subfields, namely algorithm and subjectPublicKey.
Algorithm is of the same type as signature and has an algorithm string and parameters. This
provides information on which public key algorithm is to be used with the public key and
corresponding parameters. SubjectPublicKey is a byte array representation of the public key.
Extentions
This field is a list of optional extentions. Extensions require version three and allows users to
define private extensions to carry user defined information in the certificate. In the extension
list they are listed with the following properties. extnID, critical, extnValue. ExtnID is the id
of the extension. Critical is a boolean that determines if the field is critical to the certificate.
If a validator does not support the extension type used in the certificate and it is marked as
critical, the certificate must be treated as invalid. The last field is a value and contains the
actual data of the extension type.
Subject Alternative Name is a an example of a commonly used extension. This allows a
certificate to specify multiple subject names. This can for example be used to add multiple
domains to a certificate, which is a common practise. Examples of this can be adding the
www sub domain to the certificate. Other subjects that can be added to the alternative name
is IP addresses, mail addresses, or a Uniform Resource Identifier (URI)
signatureAlgorithm should be the same as signature, and signatureValue is the digital
signature computed using the signature algorithm.
In both of theses examples a certificate was signed by a certificate authority. The signing
process works by sending a signing request to the certificate server, a common format that is
used for this is PKCS #10. This request closely resembles the subject part in the tbsCertifcate
section of a certificate, with the addition of the public key and its corresponding algorithm,
and signing algorithm. The certificate authority takes the request and generates the tbsCer-
tifcate part of the final certificate and hashes it using the algorithm specified in the signing
request. The hash is then encrypted using the certificate authority’s private key. The resulting
value is the signatureValue. The signing algorithm is the signatureAlgorithm. tbsCertificate,
signatureAlgorithm and signatureValue is appended to a file in that order which becomes the
complete certificate.
Validation
Validating a certificate is done by checking if the current date is in the interval set by the
validity section of the certificate. Then one checks if the algorithms that are used by the cer-
tificate is supported. Certificates with old schemes will be refused. If the certificate is version
three all critical extensions if present are checked for support. One checks if the certificate
has been revoked by checking the revocation list provided by the certificate authority. Cer-
tificates can be revoked if the cryptographic algorithms used are shown to be weak or if a
private key is reported leaked by the certificate owner. When all these checks are passed one
takes the tbsCertificate and hashes it using the algorithm specified. Then one decrypts the
signatureValue and compares the newly generated hash with the decrypted one. If they match
the certificate is valid.
Trust Chain
From the description given above, the certificate authority’s public key was simply trusted
and it was never explained where the trust came from. The answer is that the certificate
authority has its own certificate. This certificate was used to get the server’s public key. This
creates a recursion as the certificate authority’s certificate must be signed by some entity as
well. This chain of recursive lookups and validations of certificates is called the trust chain
and ends in a root certificate authority. The root certificates are simply self signed. One does
not usually expect self-signed certificates as anyone can make one. In the case of the root
certificate authorities their certificates are pre-installed, either in the OS or in a browser. So
when the chain reaches a root certificate authority if it matches the one on the machine, it is
just trusted.
Certificates in nature have expiry dates and so do those of the root certificates. The prob-
lem of getting new certificates from them is solved with updates to the OS or browser.
3.2.3 Authentication
Authentication is the process of validating an identity claim. When a user logs on to a web
page the user provides an identity, like the username or email, and a proof of the identity
claim, for example a password. There are three classes of proofs the user can give: knowl-
edge, ownership, inheritance.
Knowledge is the typical proof used, usually in the form of a password. An example
where knowledge is not a password is when the user answers a CAPTCHA. Knowledge
16 3. Applied Cryptography
is demonstrated in the form of being able to transform an image to text. This proves that
whoever is using the site is not a bot/script but a human based on the assumption the bot
would not be capable of doing the same. The main problem with passwords are that they are
easy to forget, resulting in short or guessable passwords as they are easier to remember.
Ownership is a proof factor that is possessed by the user. This can be a mobile phone,
yubikey, code generator like the BankID device, or a smart card. These are typically validated
by either getting a code from said device and getting it validated on the server end or, in the
case of a locked door, directly on the identifying interface. The weakness of this factor is that
you need to have something on your person to gain access and as it is a physical item, it can
be lost or stolen.
Inheritance is the last type of proof and is something the user does or is. The most com-
mon examples of this are fingerprint or face scan, which are the standard on phones besides
the 4 digit pins. There are other inheritance proofs like iris scan, voice recognition and DNA
scans. The problem with inheritance is that fingerprint sensors and the like are often inac-
curate. The sensor often fails to read on first attempt and physical factors like a dirty wet
thumb or a wet sensor may increase the sensors inaccuracy. This is called a false negative.
Fingerprint sensors have also been shown to be prone to false positives if attacked by a so
called masterprint [30]. A masterprint a artificially fingerprint created to be the average of
common fingerprint features.
Multi factor authentication is slowly becoming the norm for sing-in’s and is the standard on
web pages granting access to vital services like banking and other government systems like
tax. It has also become quite common for email services. This is good as one can typically
reset the password of other services through the mail and a forgot-my-password button.
So what is multi factor? In a typical login one provides either a user name or email address
together with a password. Password is the single proof, or factor, for the claimed identity.
The user’s username or email is looked up in the database and a corresponding password
hash is found. The user’s entered password is hashed and matched with that in the database.
If they match (are equal) the user is granted accesses to the resource.
In the case of a multi factor the user is asked for a second, or more proofs/factors, pass-
word being the first proof, for the authentication. This can be a time based code generated
from a known seed on a small handheld device, an ownership based proof. In this case the
server has all the users’ seeds and can generate the matching codes. Other examples can be
pre-printed sheets with numbers on them and the server requests one at random. SMS is also
commonly used, one receives a code on a text message and uses it as the second factor. There
are also versions of this where a simple yes or no dialog pops up on the user’s cell phone.
The idea behind multi factor is to make sure that even if a password is guessed or leaked, one
still needs the second factor to gain access, and this is not stored with the password. One note
is that inheritance factors are for some reason rarely used as a second factor, only as primary
factor as an alternative to the password. This could be because inheritance proof often has a
high false negative rate.
3.3 Attacks on identity 17
one simply patches the ”did the bullet hit” function to always return false, it will result in the
game client never sending a hit to the server.
3.4.2 Android
Mobile platforms are a common place to find client security flaws as the apps are isolated
from each other with limited communication between them, and the user is considerably
more restricted as the user does not have the same privileges as one typically has on ones
own computer. This has fooled developers into a false sense of security, but as we shall see
this is not the case. Android apps are typically written in Java or Kotlin, with both languages
compiling to java byte code and run on a Android device. Due to the nature of the runtime
environment there exist decompilers for dex files back to java. These decompilers typically
produce a more accurate representation of the original source code than assembly decom-
pilers, as less information is removed in the translation from java to dex than from C to
assembly. If a binary is not stripped, function names and variable names are also kept. This
makes it easier to reverse engineer Android apps than their assembly counterparts. Hard-
coded strings can be found with a simple regex expression. So it becomes very hard to hide
client side secrets.
3.4.3 Rooting
As a user, the interactions with the phone is done through its UI and apps. The apps have
restricted access to the phone. This leaves the user only able to perform certain actions, but
as the Android operating system is built on Linux there always exists a root/superuser which
has full access to the phone. This superuser is hidden from the user and is not accessible from
the UI. The process of obtaining the root user is called rooting. This is done by first unlocking
the android phone’s bootloader. The bootloader on android phones act as both the bios and
a traditional bootloader like GRUB. It is placed as the first partition on the phones internal
flash memory and is where the devices code execution starts. The bootloader under normal
use is responsible for booting the Android OS but it also manages other things like installing
updates to the android system partitions and allow one to boot in the recovery partition of
the device. This partition is a small ”os” that allows to restore the android system partition if
it where to be damaged.
By unlocking the bootloader on can use it to write to the partitions of the internal flash.
This is used to install a custom recovery to the recovery partition. By booting to recovery on
can now use the newly installed custom recovery to modify the android system partition. This
can be done directly form the recovery but the custom recovery is a convenience. This can
be done by downloading zip files to the phones sdcard. These can then be read and installed
by the phones custom recovery.
To root the phone one installs a zip file with a root patch from the custom recovery. This
will modify the android system partition in such a way that apps can request to execute as
the root/superuser of the system. This allows apps to circumvent all restrictions placed by
the android system and lows for expanding the original functionality of the Android OS. An
example of this is one can use this to disable vibration for certain apps like the finger print
sensor.
20 3. Applied Cryptography
Frida
With root access to the phone, tools like Frida [7] can be used. Frida allows dynamic analysis
of Android apps. What this means is that one can run the app and examine its behavior instead
of simply studying the source code. Frida comes with two components: A server installed on
the phone and run as root, and a client run on a computer.
Frida lets one hook into the application’s functions. One can overwrite functions, get
custom functions called before the actual function is called and do a custom function after
a function is done, but before it returns it value to the caller. One can also interact with
functions already present in the app. All this is done from a simple JavaScript api. It also has
supports for python scripting.
Wireshark
Wireshark [14] is an open-source network capture and analysis program with a graphical user
interface. Wireshark allows the user to capture a copy of all network traffic going to and from
a network interface. It will even allow one to capture traffic not intended for your interface
if the interface itself supports promiscuous mode. Promiscuous mode is best explained with
an example. In the case of WiFi there is nothing stopping a third party from picking up the
signal sent between two devices. A WiFi card used in none-promiscuous mode will sort the
traffic it receives and only forward traffic which matches its mac address, in other words
traffic that was intended for it. In promiscuous all traffic is forwarded.
Wireshark also lets one analyze the traffic captured. It provides support for hundreds of
protocols. It comes with many filters allowing one to filter on protocols, network layers,
ports, ip, mac addresses, sender, receiver to name a few. It also has support for following
specific streams between two parties.
Burp suite
Burp suite [12] is collection of tools created by PortSwigger. The main part of the Burp suite
is its web proxy used for MITM’ing. This allows the user to inspect and edit http traffic going
through it. It has support for analysing https by setting up its own certificate authority. Then
by installing its certificate on the client the burp proxy will generate a certificate for every
3.4 Reverse engineering 21
requested site by the client, decrypt the requests from the client and establish its own connec-
tion to the server, forwarding the clients request. As Burp generated the client’s certificate it
can inspect and edit all traffic coming from the client and since it was Burp that established
the connection with the server all traffic coming from the server can also be inspected and
edited by Burp.
22 3. Applied Cryptography
Chapter 4
Capure The Flag
CTF, short for ’capture the flag’ and sometimes also referred to as a war game is a broad term
encompassing many forms for security challenges and competitions. The core concept is that
there is some form for vulnerability in hardware or software which that must be exploited
to retrieve a flag, this is where the name capture the flag comes form. The flag is usually a
token, often a string, which only can be retrieved by exploiting the vulnerability. The token
is often in the form flag{something} or in another known format so that the player easily
can confirm that the challenge is completed. The flag can be turned in to prove that one
completed the challenge. In some CTFs this results in points on a scoreboard and in other
CTFs this is grants access to the next level.
CTF challenges are often separated into different categories. Common categories are re-
versing, pwn, steno, web, forensics, crypto and ”boxes”.
Reversing refers to challenges tied to reverse engineering. In these challenges one usually
gets a binary or executable and the goal is to figure out how the binary works so that the flag
can be extracted from it. A common example of this is a binary that wants a password and
the flag itself is the password.
Pwn is all about binary exploitation and how to get remote code execution. The player
usually gets a binary with a flaw in it and a copy is running on a server containing the flag.
This can be a binary that has a format string vulnerability, or a buffer or heap overflow. This
can be as simple as overwriting a return pointer on the stack by performing a buffer overflow
on a binary hosted on the server or something more convoluted as performing a ROP chain
attack as the stack is not executable.
Steno is short for steganography and is the art of hiding messages in plain sight. A com-
mon example of this can be hiding the flag message in an image by appending the message
as bytes trailing the image data, or hiding morse code in a sound clip as high frequency pitch
outside of the human hearing range.
Web is short for web application and revolves around exploiting web applications. This
can be exploiting a plugin on a wordpress site, SQL injections, enumerating a domain for
unprotected sites, exploiting JWT tokens not done properly and any other web related vul-
nerability.
Forensics revolves around finding information. The player gets a log, a network traffic
dump, a USB dump or some other big collection of data. Then the challenge typically is to
sort the information and extract the valuable information from the noise. One example could
be to get a USB dump where the users at some point entered a password on a USB keyboard.
Crypto challenges typically revolves around getting a file decrypted or to exploit an im-
24 4. Capure The Flag
plementation flaw in a crypto system. Examples can be as simple as brute forcing a password
from an encrypted file to exploiting a padding oracle flaw in a web server.
Boxes is usually a multi-stage challenge. A box is a server with one or more services
running on it. If only one service is running this can be exploited, with a known or a custom
vulnerability to gain some form of remote code execution on the server. In the case of multiple
services one often has to use one weakness in a service to gain information like a username
or password to another service and from there exploit a service as a logged in user. Once
remote code execution is established, one wants to spawn a reverse shell on a server so
that the system of the server can be traversed. It is a common practice to leave the flag as
a text file in the user’s home directory on linux and freeBSD, or on the user’s desktop on
hosts running Windows. Once a user is done there is a way to gain admin or root on the
machine. This is done by exploiting some flaw in the machine only accessible by the user
like a program running with elevated privileges or a kernel exploit. The flag on linux resides
in the /root folder which requires root user access to be read. On Windows it can be found in
the administrator’s desktop.
There are multiple forms of CTFs. There are always the online challenges like hackthe-
box, overthewire, bandit, hack this site and a lot more. Then there are the annual competitions
like Google’s CTF, pico CTF, DEF CON, TG Hack and so on.
These CTFs come in different formats. There is the most common, the ’Jeopardy style’,
but there are also ’attack/defence’ and ’king of the hill’. The jeopardy style has its name from
the American TV show because of the way the challenges are chosen. They are hosted on
a web page and divided into categories, typically the ones listed above. The player(s) can
freely pick which challenge to start with. Some competitions operate with challenges being
locked so that one has to complete one of the easy challenges in a category to unlock the next.
The challenges reward points and are usually weighted on difficulty. So challenges gives less
points when the number of solves increases, sometimes this decrease in value is applied to
all players scores other times the players who have already solved it keep their points.
Attack/defence is a CTF style where each team gets their own server which has a number
of vulnerable services on them. Both run the same services. The goal is twofold. Exploit the
opposition’s services and protect your own. The protection is done by setting up firewall rules
to stop certain types of incoming traffic. It is of course not allowed to block all traffic as the
services are expected to work normally. This can be tested by a third party bot that uses the
services and reports back if they do not work as intended. One does also want to monitor the
opposition attempts as their exploits can potentially be used against them or other teams that
has not patched that exploit yet. The attacking is done in much the same fashion as attacking
a box with the added complexity of a security team activity fighting you back every step of
the way.
King of the hill is a version of attack/defence but instead of one server per team, there
are many neutral servers. They have different vulnerabilities. The goal is to get access to as
many servers as possible and then holding them by protecting them in the same fashion as
in attack/defence. The team holding a server gets point for each time unit they hold a server
multiplied by the number of servers they hold.
4.1 CTF crypto tasks 25
Most crypto challenges fall into two categories, namely breaking a cipher or breaking the
implementation of a cipher. In the first case one executes an attack directly against the
chiper/cryptographic primitive. Examples of this can be cracking an MD5 hash or break-
ing a rotor machine like Enigma. The common theme her is an older cryptographic primitive
with a known flaw. One can of course also make a weak primitive with an intended flaw.
These challenges are valuable tools for learning about mistakes done in the past but will
probably not be seen in modern software.
The other case is when the cryptographic primitives are unbreakable but the implemen-
tation is flawed. A good example of this is using AES for encrypting an image. AES with a
128-bit key is not breakable by today’s computing power, but if AES is directly applied block
for block to the image, then the same plaintext values get the same chiphertext values every
time. This results in patterns in the ciphertext emerging as one can see in Figure 4.1. One can
not find the key used to encrypt the image but it is not needed either. Another example of
this which we will get back to is the padding oracle where one can decrypt entire messages
in a linear fashion without knowing the key.
When analysing an app, one good way to get a lot of information without reading through all
the code, or even worse, the compiled code, is to look at the network traffic. A common thing
to do when analysing an app is to set up some form of network traffic capture. Wireshark
is often used for this purpose as it lets one capture all incoming and outgoing traffic on a
network interface.
The problem with the Wireshark approach is that if the traffic is encrypted and one does
not have the decryption key, little information can be extracted.This is because most traffic
is http with tls encryption. Creating a TLS connection means fetching the server’s certificate
and validating it. If the certificate is valid one uses the server’s public key to negotiate a
session key and use it to encrypt the session. Since this is done with asymmetric cryptography
one can not retrieve the key with Wireshark and thereby not read the content of the encrypted
26 4. Capure The Flag
traffic.
Burp solves this problem by acting as a man in the middle. When the client asks for a
certificate, Burp generates one that Burp itself signed and knows the private key of. This
allows Burp to unmask the encryption. Burp then establishes a legit connection to the server
and forwards the unmasked traffic over its connection to the server. The server responses are
in the same way forwarded to the client.
However, this does not explain why the client would validate the certificate issued by
Burp as a valid one. Simply explained, all certificate are issued by a Certificate Authority
and these are trusted with blind faith. The public keys of these CA’s are shipped with the
operating system itself, and stored in some form of certificate storage, for example in the
case of a Mac OS it is in the keychain application. One can add more CA’s to this cache.
So Burp simply adds itself to the blind trust list and all certificates signed with Burps root
certificate are now treated as if they came from any other CA.
As mentioned above OS’es comes prebundeled with certificates this in turn forces an
application to trust the certificates the os trust. The problem then aeries that with a proxy
like burp all traffic encrypted using a certificate can be decrypted by burp. This is done by
burps web proxy, when an application tries to establish a connection and fetches the servers
certificate burp exchanges it with one it has signed with its root certificate. Knowing the
private key of the newly forged certificate burp can decrypt the traffic and the application
can not detect this as the root certificate used by burp is trusted by the OS.
To prevent this applications instead comes bundled with the expected certificate. Thus
the application first checks if the certificate sent by the server is the same as the one it came
bundled with. If the certificates matches it precedes as normal and if they don not match the
application assumes fowl play. This bundling and checking of certificates is referred to as
certificate pinning.
The attack
Certificate pinning as stated above is done by implementing a custom way to validate cer-
tificates provided by the server. This entails that each attack will be different, so I will give
some common examples on how to unpin apps.
In the case of no certificate pinning one simply needs to add the certificate of one’s own
CA to the Android system certificate cache, as user trusted certificates are not trusted by an
app by default.
4.1 CTF crypto tasks 27
Another common way to do certificate pinning is simply shipping the certificate with the
application. This can be done by by adding the file asset folder and loading it to the trust
manager during run time. To bypass this method simply decompile the app with apk-tool
and then change the certificate with one with a known private key and recompile with the
apk-tool, resign the app and zip-align it.
The last case is when the certificate or a hash of the certificate is hard coded into the
app. In that case one has to decompile the app and find the hard coded check and patch it or
change the app’s byte code in such a way that it will accept a different certificate.
Frida can be combined with some static code analysis to ease the patching of the code by
letting one overwrite the functions performing evaluations dynamically. Also worth noting
is the ”Universal Android SSL Pinning Bypass with Frida project. This is a prebuilt Frida
hook for removing common forms of certificate pinning.
tickets, visas, family photos, contracts and e-mails. This is a good example of why enumer-
ation flaw is often paired with some form of broken authentication.
Broken authentication [28] is listed as #2 in the OWASP top 10 vulnerabilities, and is
described as follows
Application functions related to authentication and session management are often
implemented incorrectly, allowing attackers to compromise passwords, keys, or
session tokens, or to exploit other implementation flaws to assume other users’
identities temporarily or permanently.
The JWT token libraries with the None flaw is an example of this. A JWT token consists
of tree parts: a header, payload and a signature. The header contains two properties the ”alg”,
short for algorithm, and the type, which is JWT in this case. When a JWT token is validated
the algorithm is collected from the header and a signature is computed using this algorithm.
This signature is matched against the tokens own signature part. If they match the token is
considered valid. Note that signature algorithms requires some key. Either a private key if an
asymmetric algorithm is used or a pre-shared key if a symmetric one is used. The problem
is that there is a third category of signing algorithm, the None algorithm.
Tokes with the None algorithm were supposed to be used on already trusted tokens. For
example, if the token is validated by the public facing part of the server and is to be sent
further in to backend to other services, the singing part of the token is not needed as there
is no point to re-validating it every step of the way. Thus the public facing part of the front
end could validate the token, set the alg type to None and strip away the signing part of the
token. The problem with this is how the libraries validating the token were implemented.
They would have a function to validate taking an argument of a key and a token. The key
would be optional so when it was called it would check the header, find the None algorithm,
and validate it as valid as a None token has no signature to be checked and is therefore always
valid. This would allow the attacker to forge a token with any values desired in the payload,
opening for impersonation attacks.
Definitions
Throughout this section the following definitions will be used
• b is the number of bytes in a block
• N = b ∗ number of blocks
4.1 CTF crypto tasks 29
Padding
There are many implementations of padding. For the purpose of explaining the attack we
will here introduce a simple padding scheme. Given a block length of b bytes and a chunk of
message of length m where b > m, padding is used to extend the length such that m + p = b
where p is the number of padded bytes. In the case of m = b one adds a block of only padding.
The padding also needs to be distinguishable from the rest of the message. To solve this
the last byte of the cleartext is simply the number of padding bytes, and the other bytes of
the padding hold the same value. This makes the padding easy to remove. Simply read the
last byte and remove this many bytes from the message. The padding can be checked, testing
that all the padding bytes have the same value.
The attack
This attack can be described in 3 steps
1. recover a single byte of the plaintext
2. recover one block of the plaintext
3. recover the full plaintext
30 4. Capure The Flag
Figure 4.2: left the original scenario, right the attacker scenario
To start, one chooses a random block of length b and sends it as the second to last block.
Then one chooses the block one wants to decrypt and sends it as the last block (the padded
block).
One byte From the definition of the padding one can observe that any message ending in
the byte 0x01 has a valid padding. Looking at Figure 4.2 the decrypted ciphertext gets xor’ed
with the previous ciphertext to get the plaintext. The expression for the last byte then is
One block The method above describes how to get one byte, but this can be generalised.
From above, all values in (4.1) are known. This makes it such that by changing ACb the
resulting value of CLb can be any chosen value. Choose ACb such that CLb gets the value
0x02. Then if CLb−1 also is 0x2 one gets a valid padding. For CLb−1 the equation from the
byte can be modified and applied as CLb−1 = Db−1 ⊕ ACb−1 . Since ACb−1 is also controlled
by the attacker the strategy from the single byte case applies. Brute forcing ACb−1 until a
valid padding is found gives us the value of Db−1 and from it we can retrieve P Lb−1 . This
strategy can then be repeated for CLb−2 by choosing ACb−1 and ACb such that CLb−1 and
4.1 CTF crypto tasks 31
CLb are both 0x03 and one can brute force CLb−2 . This can be repeated for 0x04, 0x05 and
so on until the entire block is decrypted.
One Message To decode the entire message one simply decodes block by block as de-
scribed above by letting every block play the role of the last padded block in the message.
Complexity
The run time of this attack is linear in the number of bytes in the plaintext. N bytes takes at
most N ∗ 256 tries, giving a O(N ) algorithm.
still does not entirely resolve the problem as some transfer delay has to be factored in. If the
attacker is closer to the servers than the user, than the attacker my still be able to abuse the
small time frame and resend the message. To completely prevent such attacks, both the client
and server will need some associated information, as suggested in the paper [16].
By always appending previously sent messages to the current message body, a replay
attack becomes impossible as the replayed packet does not contain the previously sent pack-
ets. Replayed messages would have to include all the previous versions of themselves in the
chain of previously sent messages. Sending a complete history of all previous messages will
cause increasingly bigger messages conveying the same information, making it impractical.
However, this problem can be solved by hashing the previous messages, ensuring that the
history is mostly preserved in a more space effective manner, as well as maintaining the in-
tegrity of the history. As the hashing functionally is a one-way compression with minuscule
probability of collisions, the integrity of the history is not perfect compared to sending the
actual history in its entirety. But it is much more space efficient and a good trade off.
The method described over can be a bit simplified if one uses a MAC on the message. Us-
ing HMAC and then including a counter in the message makes it impossible for the attacker
to change the sequence as the HMAC provides message integrity by a shared key between
the server and client which the attacker does not have. This can be exchanged in a secure
way between the client and server by for example using the Diffie–Hellman key exchange
algorithm.
Other methods that are commonly used for https is to use a one time token. When a user
sends a get request to a site with a form in it, the get request contains a one time valid token.
This token is sent in an invisible field with the rest of the form data in the following post
request. When the server gets the post request it checks if it contains the same token it sent
with the get request and if they match the request is processed and the token is devalidated.
This makes replays impossible as replaying the post request the sent token would not be valid
and resending both get and post request will not work as a new token is generated and it will
not match the token in the replayed post request. This method can also be implemented on
other channels then http. The only drawback is the extra round trip to get the one time token.
Random numbers are a very important aspect of modern cryptography. They are used to
create session keys, used as initial vectors and as nonces in key establishment protocols
like the Diffie–Hellman key exchange. If a number becomes predictable this can be used
to break the crypto system. The most obvious example of this is if the session key can be
guessed/recreated. The problem with making random number generators is that a computer
by itself can not generate random numbers. There are mathematical functions that given an
initial input, often called a seed, will produce a random sequence of numbers. The property
the sequence should have is that given the first n numbers, the n + 1’th number can not be
derived using the previous n numbers in a computationally feasible way, without knowing
the seed value used.
The seed still needs to be random as a given seed will always produce the same sequence.
So to produce a random seed, one has to have a source of randomness. Computers can not
4.1 CTF crypto tasks 33
produce this, so external factors are used. Examples of this is current system time in nano
seconds, number of running processes on the system, the spin on disk based storage mediums
(hard drives), key stroke timings from the user and mouse movements. In the case where the
seed is poorly chosen or the mathematical function that is used has a flaw, the attacker might
be able to break the the crypto system as we shall see in the case of RSA and not so random
primes.
Common primes
The public key part of an RSA key contains a public modulus which is the product of the two
secret primes p and q . Let us assume we have two public keys, one with n1 as its modulus
and one with n2 as its modulus. If n1 = p × q and n2 = p × r then n1 and n2 would have a
common factor p. This factor could easily be found using the Euclidean algorithm for finding
greatest common divisors on n2 and n1 .
If p is found, some simple division would yield both q and r as well. From the primes p
and q , the number λ(n1 ) can be computed as lcm(q−1, p−1). The exponent d which is used to
decrypt the RSA messages can be retrieved by computing d = e−1 mod λ(n). Since λ(n1 ) is
now known we can run the extended euclidean algorithm on e and λ(n1 ). This gives the result
a×e+b×λ(n1 ) = gcd(e, λ(n1 )). From the definition of RSA we know that gcd(e, λ(n1 )) = 1
and b × λ(n1 ) mod λ(n1 ) = 0. This leaves us with the expression a × e = 1, thus a is the
inverse of e meaning that a = d1 . Now that all the parts of the private key are recovered, d1
can be used to decrypt any message. This has actually occurred. Quote from [24]:
More worrisome is that among the 4.7 million distinct 1024-bit RSA moduli that
we had originally collected, 12720 have a single large prime factor in common.
34 4. Capure The Flag
Chapter 5
Implementation of tasks
This chapter describes tools, languages and technologies used to make the different chal-
lenges and the reasoning for choosing them.
5.1 Technologies
5.1.1 Languages
Two languages were primarily used for programming: Rust and C. Rust was primarily used
as the backend language and for creating the certificates from prime numbers tool. The rea-
soning behind using Rust was twofold. The first is that it is a language I am comfortable
using. The second is that it is an efficient language requiring no runtime environment. There
are alternatives like C++ that meet the same criteria, but Rust provides a unique memory
management model that provides memory safety during compilation. This means Rust is not
susceptible to uninitialized memory accesses, buffer overflows, null dereferences, dangling
pointers and other memory related errors [19]. This is with the exception of the so called
”unsafe” code as segments declared unsafe relaxes the compile time guarantees but gaining
some flexibility like the ability to call C library functions.
C was used for the padding oracle challenge. This was done because the challenge re-
quires the source code for the server to be viewed by the contestant. C being a common lan-
guage used for code snippets in CTF’s is the main reason for choosing it for this challenge. It
is also a typical language for implementing crypto systems and other high performance pieces
of code. It is also a reasonable language to expect someone to understand as languages are
often classified as ”C-like” or not. This makes C a good common denominator. Lastly C is
relatively speaking a small language and the syntax is simple and common for most C-like
languages.
There were to front ends that were made: One Android application and a web game.
For the web game plain JavaScript was chosen as it was the simplest alternative yielding
fast results. The Android app was created using Java. The only other choice for making the
Android app is Kotlin. Java was chosen because I am familiar with the language and not
Kotlin. Kotlin is in many ways a modern version of Java with Java backwards compatibility,
and it would probably be used if not for the time constraint.
36 5. Implementation of tasks
5.2 Tools
5.2.1 Docker
Docker is a platform allowing one to create and deploy/run containers. It uses OS-virtualisation
to achieve this. In a traditional setup one would usually run a hypervisor service on the bare
metal. Examples of this is Microsoft’s hyper-v, VMwares EXSI, or KVM. The hypervisor in
turn runs a virtual machine image containing a complete OS. The application is then installed
to that virtual machine, or is part of the image.
When a virtual machine is created resources needs to be statically allocated, like disk
space and memory, as the each virtual machines needs its own OS. Docker on the other hand
is an OS-level-virtualisation. This means that the segregation of its services is done on OS
level. Instead of running a full virtual machine docker uses the Linux kernel and its names-
pace technology to separate the applications. This allows docker to create an isolated user
space for the application while having the benefit of not needing to allocate static amounts
of memory for the application. All the container share that same kernel thus removing the
need for multiple OS duplicates and an hypervisor.
Docker uses Dockerfiles to build images. A Dockerfile specifies files to copy from the
host in to the image. Images can inherit from other images. An image is usually based on a
small linux distro like apline. The apline image contains the bare bones to get an application
running. A sh shell and a packet manger to install packages with. The Dockerfile file allows
to specify command to be ran inside the image and using the packet manger it is easy to make
an enviorment for ons’s application to run inn.
When an image is built with all needed dependencies and the application to be run is
copied into the image, a container can be started. Docker makes use of kernel namespaces to
run an isolated process with its own file system called the container. Each aspect of a con-
tainer is run in its own namespace and access to resources outside its namepaces is prohibited
[15].
other containers. In this network all the containers get their own DNS. The container name as
declared in the Docker Compose file serves as a domain, so the other containers can connect
to each other using names.
The virtual network that is created is set up such that all outgoing traffic is allowed and
is forwarded to the host’s interface, but traffic from the world to the host interface is not
forwarded to the virtual network. It works in the same manner as a traditional NAT’ed home
network, where the router in this scenario is the host’s network interface and the clients
of the NAT are the container services. The router Docker Compose file also supports port
forwarding. Ports of containers can be directly exposed on the host interface if specified by
the Docker Compose file. The file specifies the port of the container and which port it is to
be mapped to on the host.
This works well for the API example as it becomes trivial to set it up in such a manner
that the web proxy is exposed to the world, while the API backend and database is shielded
from traffic originating from the outside world. The containers also maintain the ability for
cross communication between themselves.
Android studio [4] is a tools suite built upon the popular IDE from Intelij used for creating
Android apps. This was used as it contains the necessary tooling for compiling and installing
Android apps to a virtual machine or a phone. It also provides templates for creating Android
apps and some management tools for downloading the correct version of the SDK.
5.2.4 OpenSSL
OpenSSL [11] is an open-source library implementing the SSL and the later TLS protocols.
TLS and SSL are protocols that allow for secure communication between two parties. This
includes a validation of the identity of the communication parties using asymmetric cryptog-
raphy. This validation is also used to establish a secret session key.
The communication is a symmetrically encrypted connection using the session key. Mes-
sages that are sent are also reliable as they include a message authentication code. This fills
the two of criteria for information security, confidentiality and integrity. The OpenSSL li-
brary is used by both the app and the server for the certificate pinning challenge.
The OpenSSL library also comes with a command line tool. This tool provides access
to many of the library features. In two of the challenges it was used to generate public and
private keys and generating self-signed certificates from config files. It was also used to
generate a public private key pair from a config specifying the primes, exponent and key
size to be used.
38 5. Implementation of tasks
The certificate pinning challenge was implemented as an Android banking app, called the
Bit-bank, with a corresponding API backend. The player gets the app’s apk file and a test
username and password for the app. When the player installs and loads the app the player is
met with a simple login screen. The credentials that were provided will log the player into
the app, where the player can interact with the app’s main screen. The main screen contains a
simple button for fetching the name and balance of the logged in user’s account. The objective
for the player is to read all the traffic between the server and app and not just what the app
shows to the user.
The server is implemented in Rust because of the good compile-time guaranties the lan-
guage provides, such as memory safety. The http-library used is called Rouille [3]. It is a
small library and provides the minimum needed for creating the banking API. In front of the
API is an Nginx [9] server used as a reverse http-proxy to provide TLS connections. This is
done so that players cannot sniff the server’s traffic directly.
The server (code in Appendix A.1.2) provides the banking API for the app. The banking API
consists of two API endpoints, one for login and one for fetching the user’s balance.
The login endpoint takes a POST request with two arguments, namely the username and
password. When the server receives the POST request, the username is used as a key to
retrieve the corresponding password and this password is matched against the one provided
in the login request. If they do not match a 404 error code is returned, otherwise a JWT token
is generated and sent as the response. The token contains the user’s id and it is signed using
a secret server side key and the HS256 algorithm.
The endpoint for fetching the balance, called getWallet, is a get request taking a token as
its argument. When the endpoint is called it first validates the token using the secret key. If
the token is invalid, a 404 response is sent. In the case of a valid token the user id is extracted
from the token and used to fetch the user’s name and balance. The balance and the user’s
name is sent back to the client as a json object. This json object also contains the flag the
player wants to obtain.
The client app (code in Appendix A.1.1) contains two screens, the login screen and the bal-
ance screen, see Figure 5.1. The login screen has two input fields, one for username and one
for the password. Below the input field is a login button. When the login button is pressed the
client loads a certificate field from file and adds it to a trust store. A hash of this certificate is
also generated. The hash and the trust store containing the certificate is passed to the okhttp
client’s certificate pinning builder and a http client is created. This client will only accept the
cert in the store and will also check that the hash matches. This is so that even if an attacker
5.3 Implementation of the CTF challenges 39
(a) The login screen of bit- (b) The users dashboard be- (c) The user dashboard after
Bank fore interaction interaction
controlled CA is added to the system store and a valid cert is provided, the hash will still not
match and the connection will be refused.
With the new client a https POST request is made with the username and password form
values populated by the user input. If the app receives a 404 it will close itself and a login
failed popup is presented on the screen. If the login was successful the app spawns the balance
screen and passes the token received during the login to it.
The balance screen starts out empty with a single get balance button. When this button
is clicked a new client with the pinned certificate is spawned in the same fashion as with
the login screen. With the http client a getWallet request is sent with the token as the only
parameter. If the request fails, an error message is displayed to the user on the screen and the
user can retry by clicking the getBalance button a second time. In the case of a valid request
a json object is returned. This json object contains the user’s first and last name, the balance
and the flag. The fist name, last name and the balance is displayed in the app, while the flag
is ignored.
The challenge
The player is given the banking app and a test user for the app and is tasked with discovering
how this app communicates. The goal is to be able to read the encrypted traffic sent between
the server and client. This will lead to the discovery of the flag hidden in one of the messages.
Intended solution
To accomplish finding the flag the player needs to decrypt the traffic between the server and
the app. The app has the certificate used for communication built in to it. The player has to
first decompile the apk file to get the byte code and resources of the app. The decompiled app
contains a resources folder with the certificate in it. By replacing the certificate with one the
player has crafted, and recompiling the app the player can set up a MITM proxy like Burp.
Burp will act as a proxy between the app and the server using the crafted certificate to com-
40 5. Implementation of tasks
municate with the app, decrypting it and forwarding it to the server on the TLS connection
it has established. As both the session key to the app and the server is known by Burp all
traffic can be read as plaintext by Burp, and in turn, the player.
The Challenge
The challenge here is to be able to impersonate another user of the bitbank to gain access
to the their profile, which contains the flag. To achieve this one first has to complete the
previous step of this challenge as the ability to decrypt traffic between the app and server is
needed. Inspecting traffic one can observe that jwt tokens are used for authentication. The
jwt none flaw can be exploited to forge valide tokens. This must be combined with user id
enumeration to gain access as another user.
Intended Solution
From the previous challenge the contestant can view the plaintext version of the traffic going
between the server and the application. By creating a None algorithm token and changing
the user id of said token the contestant is able to call the getWallet endpoint for several user
ids. As the None-token is valid the endpoint will accept each of the requests, and only failing
because of invalid user ids. The solution is to simply try user ids until an actual user is found.
As a hint, the user id of the test user is close to 1337 in value. So the observant participant
might try that value first, and succeed. Regardless a exhaustive search in both directions will
quickly yield a result.
to attack the first block instead of the last. This will hopefully make existing tools on the
internet solving the task obsolete or at least needing to be customized.
The server (code in Appendix A.2) code starts by setting up a socket at port 1337 and lis-
tens for connections. If a connection is established. It will try read the IV and the encrypted
message sent from the client. It tests if the padding is valid and if it is not the server will
respond with the taunt ”You know nothing, skid”. If the padding is correct it will check if
the message itself is valid. In this case the message has to be the flag of the challenge to be
considered valid. The user will get another taunt namely, ”You know nothing, hacker boy”,
if the message does not match the flag file on the server. If the message and the flag matches
the server will respond with ”You know the path , bro”.
This code (code in Appendix A.2.2) simply establishes a connection to the server and sends
the flag as an encrypted message. So this program is an emulation of an actual user of the
server with the correct password and the flag. This program is simply an aid to the CTF
challenge as the traffic the program generates is to be captured as a pcap file and handed to
the constant with the server code.
The challenge
The participant is given a valid package capture of a client connection to the server sending
the flag and receiving the positive confirmation. The participant also receives the code for
the server so the participant can understand the meaning and context of the error messages
sent from the server and spot the oracle flaw within the server.
Intended solution
Every time the server sends the response ”You know nothing, skid”, the padding of a message
is wrong. On the other hand, if ”You know nothing, hacker boy” is sent the padding test
passed but the message sent was not the correct flag (with padding). These messages/taunts
from the server can be used as an oracle as it leaks one byte of information about the plaintext.
This can be used perform the padding oracle attack. If the first byte of the message is 0x1
then the padding is considered valid. Since the contestant controls the IV that is xored with
the cleartext (cipher text decrypted by AES) before the padding is checked, the value of the
last byte of the IV can be iterated through all the combinations until hitting a valid padding.
Knowing the padding lets the player infer the last byte of the plaintext as we know the IV.
Then (s)he can do the same for the second byte by setting the first byte to 0x2 and flipping
the second byte until getting a valid padding. This can be repeated for the entire block and
for multiple blocks until the entire flag/plaintext is recovered.
42 5. Implementation of tasks
Implementation choices
This replay attack was implemented in the shape of a game. The player loads the game in
their browser and is asked for a license key to play. Then a tile game is loaded. The player’s
mission is simply find the tile with the flag and receive the flag string. If the player enters an
invalid license key the game loads, but the player’s character is not able to move. The server
only sends the visible part (from the players perspective) of the map to the player. More parts
of the map are only sent from the server when the player’s position changes. The API only
allows the player to move if a correct license key is used to encrypt the packages.
The server is implemented in Rust because of the good compile-time guaranties the lan-
guage provides such as memory safety. The http-library is called Rouille [3]. It is a small
library and provides the minimum needed for this web game’s API. In front of the game an
nginx [9] server that is used as a reverse http-proxy to provide a https connection. This is
done so that players cannot sniff each others traffic. If a player gets his hands on another
player’s token, the player can potentially move the other player’s character.
The game server (code in Appendix A.3.2) provides a simple web API, as well as serving
the game resources and the game itself. For the remainder of this text, a ”hacker” refers to
the CTF-contestant and ”player” refers to the in-game player character.
When the game is served from the game server the game client fetches all the tiles (im-
ages) and makes an initial call to the move API. Since the hacker has no token, a player state
is initialized to the starting position and a token is created. The game sets the hacker’s cookie
to the token value and returns a JSON-object containing an 11 × 11 grid with the tiles the
player can observe from its position. The token is simply a long uid-string in the player’s
browser used to identify the player and find his player charterer’s coordinates on the map.
When playing the game, the hacker sends ”move”-requests to the API. The get-request
to move the player takes two parameters. The direction, which is a URL and base64 encoded
encrypted text of the direction the player wants to move, and the initial value (IV) used to
encrypt the direction.
The server fetches the current player position form its database based on the uid in the
token in the cookie. It then tries to decrypt the player’s direction. If the direction is not one
of the predefined ”up”, ”down”, ”left”, ”right”, or if it can not be the decrypted, the game
returns the player’s current position. If the direction is valid, a second check is performed to
see if the move is valid. A white list is used to check if the new position’s tile is of a type
that the player is allowed to stand on, eg. grass is allowed but water is not. If the tile type is
invalid, the player’s position remains unchanged. If both checks are valid, the new position
is returned in the form of an 11 × 11 grid with the new tiles that are visible to the player. One
additional check is performed where the game will check if the new position is the position
of the flag. If so, a ”flag”-property is appended to the returned JSON-object, with a string
containing the flag.
5.3 Implementation of the CTF challenges 43
The client (code in Appendix A.3.1) code starts by loading all the tile images and asks the
player to enter a license key. When the license key is entered the game sends a move request
to the server. The license key and a random IV is used to encrypt the plain text string of the
direction and sends the encrypted text together with the IV (in plain text). The server will
always respond with an 11× 11 tile grid with the player in the middle. The client then renders
that tile map, see Figures 5.2, 5.3 and 5.4 for screenshots of the game.
The movement keys are bound to functions sending the direction pressed over the ”move”
API, and are also encrypted with the license key. The server either returns the same state as
before or moves the player to a new position, depending on if the move was legal and if the
the license key was correct.
The challenge
The hackers are given the URL to the repeatable game and a packet dump of an earlier
playthrough of the game, with the context that the packet dump was created before the de-
veloper installed a certificate. The challenge is simply to play the game and get to the flag
tile in the game.
44 5. Implementation of tasks
Intended solution
This is a ”repeatable” game and intended as a replay attack challenge. If one studies the
code of the client it is possible to see that the sent messages are one of four strings: ”up”,
”down”, ”left” or ”right”. The packages in the packet dump are unique, only because of
the randomness of the IVs. The IV is also sent as plaintext. n After decryption, the only
information left for the server is one of the strings describing the direction. As the server does
not implement any rules regarding the iv, it is impossible to tell if the packet was original or
retransmitted. Another observation is that the token itself is not part of the encrypted packet.
This means that the token can be changed, but the http-request will still be valid. This is all
a hacker needs to move their character.
To perform the attack and solve the challenge the hacker must first find four packets
that correspond to moving in each of the directions in the game. By sending an empty to-
ken on each request the game server always creates a new player character at the starting
point, resulting in the same output for the same move command each time. This makes the
attack possible to script. Simply use the response as a key in a hashmap and the value as the
encrypted direction, then try all the move-requests from the packet capture and update the
value each time. When this is done, the hacker only have to iterate over the four entries in
the hashmap and figure out which responses correspond to which encrypted direction. In the
web-browser, open the console and simply overwrite the functions ”up”, ”down”, ”left” and
”right” to send the corresponding encrypted direction. Then it is just to play the game as if
one had the license key, and navigate to the flag-tile.
Sample overwrite of the ”left” function:
l e f t = ( ) =>{ l e t H t t p = new XMLHttpRequest ( ) ;
let url =
‘ / move ? d i r e c t i o n =18 YxlQFWlTkJIldjBN %2‘
+ ‘BeEA%3D%3D&i v =bMxkTUrLQWjPZRLxQodf4Q%3D%3D ‘ ;
H t t p . open ( ”GET” , u r l ) ;
Http . send ( ) ;
H t t p . o n r e a d y s t a t e c h a n g e = ( e ) => {
5.3 Implementation of the CTF challenges 45
};
}
46 5. Implementation of tasks
This challenge uses the OpenSSL command line tool to generate keys and certificates. It is
also used to encrypt and decrypt the flag using the generated private keys on the flag file.
Certificate generation
A script called getCert.sh is executed in the docker container. This start out by using the
OpenSSL tool to create nine public and private key pairs.
Then the first primes in keys 4 and 7 are extracted and passed to certs, a Rust program
(code in Appendix A.4) that takes two primes as an argument and prints an ASN1 file. This
file is used to produce a new public private key pair with the OppenSSL tool. The newly
created pair overwrites the seventh of the originally crated key pairs. Since this key is based
on the first prime of the fourth key and the first prime of the original seventh key, it results
in the new key having one prime in common with the fourth key.
All the nine key pairs are used to create nine self-signed certificates. For each certificate
to be created their exist a prebuilt configuration file specifying required values like subject,
organisation and so on. Then each of the private keys are used to encrypt the flag file, pro-
ducing nine encrypted versions of the flag. Finally the script copies the encrypted flags and
the certificates to the out-folder for use on the CTF platform.
The challenge
Find a way to decrypt one of the encrypted flag files. The contestant will get all of the public
keys used to do the encryption. There is a mistake in two of the public keys that will allow
the player to regenerate the private key. The exercise name hints at what the mistake in the
private keys is, namely ”Who stole/copied my prime?!”
Intended solution
The constant must realize that one of the RSA keys share a prime with one of the others. This
common factor can be found by running the gcd algorithm of the modulus on all the public
keys against each other. One combination will yield a gcd not equal to one and this will give
one of the primes uses to get the modulus, which is n = p ∗ q . Since p is now found n/p gives
q . From this one can produce a valid Ans1 file. The Ans1 file can be used with the help of
the OpenSSL utility to produce a valid private key. This private key can be used to decrypt
one of the encrypted flag files.
Docker.json
This file contains the metadata for the Docker container. The metadata file includes the fol-
lowing fields: the docker repo to be used for the image and the tag of the image, and the
name of the challenge. The IP address of the container and its ports are also listed. Lastly, it
contains the domain where the challenge can be found during a competition.
Key.txt
This file contains the key that are used for AES 128-bit encryption in the challenges. The
key is a 128-bit key and therefore must always contain 16 bytes. The key can be changed
freely but should be hard to brute force as the challenges are not intended to be solved using
or finding this key. Also note that changing the key will affect the generated packet capture.
Flag(#).txt
The flag file contains the flag of the challenge. The flag is a string that is passed to the CTF
game server as proof that the challenge was completed. This file is also customizable with
no restrictions to file length.
Readme.md
The readme file contains a short listing of metadata like the name of the flag/challenge, the
name of the container, the flag type, the points the flag is worth, and the flag string itself. Note
that the flag string must match the one in the flag file. This is followed by a description of the
challenge that is presented to the contestant. The two last sections are not presented to the
contestant and contains a short hint summary for the challenge and a longer text describing
a complete solution.
Docker file
Each of the source folders are accompanied by a docker file. This docker file is used to build
the source code and produce a container with the built binary.
DevBuildStart.sh
This file does the actual building and running of the tasks. It start by reading the values
from the Docker.json file and uses the values to first assign a port on the host system for the
challenge. Then it builds the images described in the docker file and runs them as containers.
There is one notable exception to this and that is the certificate pinning challenge where
the port is dictated by the docker compose file and the script invokes the docker compose
build and run command instead of docker’s command.
Out folder
During the initialization of the container an out folder will be mounted into the container of
a few challenges. This folder will be populated with files that are required for solving the
challenge and should be copied to a place where the contestant has access.
Chapter 6
Summary
reason is that in my personal opinion, rabbit holes are at best an annoying way to stall one
from completing a challenge and it can be argued that being stuck in a rabbit hole does not
necessarily imply lack of skill. In an ideal competition lack of skill should be the only thing
keeping one from completing a challenge!
Some of the attacks were at the beginning only something I knew by name, and thus
researching and figuring out how they worked was sometimes difficult. The padding ora-
cle was one of the harder ones to understand as there are many variables. The challenge
also required me to build a working implementation with the flaw and the solution abusing
the flaw, making small room for errors in either of the implementations. The RSA prime
challenge required some mathematical understanding paired with an understating of how the
OpenSSL library works and a partial recreation of the RSA key generation algorithm. The
other challenges offered mainly programming difficulties.
Further development
The Certificate pinning challenge could have had more flags. As the code is, it generates
the certificate’s signature at run time. This allows for decompiling the app and replacing the
certificate file with one with a known private key and recompile the app. A simpler entry flag
could be built in where if the contestant manages to recompile the app with the debugging
flag set the app prints a flag to the debug console. A common mistake done by developers is
leaving debug code in the released product. Simply by putting the application in debug mode
one gains vast amounts of information with minimal effort.
A fourth challenge that could be made is an attack as a logged in user. JWT token li-
braries introduced a new problem in addition to the problem of setting the algorithm to
None. This is due to the fact that it is the JWT token that dictates the algorithm used to
validate it. A few JWT libraries implement the verification method with a signature like this:
”verify(clientToken, Key)”. The verify function checks the token algorithm and assuming it
finds an asymmetric algorithm the function will assumes that it is handed a public key and
attempts to decrypt the token using it. In the scenario of a symmetric algorithm it will assume
the key is a normal secret key [25].
The problem arises when legit tokens are signed with a private key. The server is then
programmed to expect asymmetric tokens and therefore hands the verify method the public
key, but the verify method on the other hand reads the token first and then decides how to use
the key. If an attacker were to change the algorithm to a symmetric one the byte sequence of
the public key would simply be interpreted as a symmetric secret key. The problem with this
is that the byte sequence making up the public key also is known by the attacker. Thus he
simply signs his token using the public key, in the role as the key to a symmetric algorithm.
As the need for security grows larger hopefully the challenges that were created can con-
tribute by learning both developers and security experts about some crypto flaws and give
an understanding on how they can be fixed or prevented in the future.
Appendix A
Source code
61 i f ( r e s p o n s e . c o d e ( ) == 4 0 1 ) {
62 throw new I O E x c e p t i o n ( ) ;
63 }
64 r e t u r n r e s p o n s e . body ( ) . s t r i n g ( ) ;
65 }
66 }
67
68 p u b l i c R e s u l t < L o g g e d I n U s e r > l o g i n ( S t r i n g username , S t r i n g p a s s w o r d ) {
69 try {
70 S t r i n g r e s p o n s e = p o s t ( hostname , username , p a s s w o r d ) ;
71 Log . d ( ” h e i ” , r e s p o n s e ) ;
72 r e t u r n new R e s u l t . S u c c e s s < >(new L o g g e d I n U s e r ( r e s p o n s e ) ) ;
73 } catch ( Exception e ) {
74 r e t u r n new R e s u l t . E r r o r ( new I O E x c e p t i o n ( ” E r r o r l o g g i n g i n ” , e ) ) ;
75 }
76 }
A.1.2 Backend
1 # [ macro_use ]
2 extern c r a t e r o u i l l e ;
3 extern c r a t e frank_jwt ;
4 # [ macro_use ]
5 extern c r a t e serde_json ;
6
7 use s e r d e _ j s o n : : Value as JsonValue ;
8 use serde : : D e s e r i a l i z e ;
9 use serde : : S e r i a l i z e ;
10
11 u s e f r a n k _ j w t : : { A l g o r i t h m , encode , decode , V a l i d a t i o n O p t i o n s , d e c o d e _ h e a d e r _ a n d _ p a y l o a d } ;
12
13
14 use s t d : : c o l l e c t i o n s : : HashMap ;
15 use std : : io ;
16 use s t d : : s y n c : : Mutex ;
17 use r o u i l l e : : Request ;
18 use r o u i l l e : : Response ;
19 use s t d : : c o n v e r t : : From ;
20 use std : : fs : : File ;
21 use s t d : : i o : : { Read , BufReader , BufRead } ;
22
23 # [ d e r i v e ( Debug , Clone , S e r i a l i z e , D e s e r i a l i z e ) ]
24 s t r u c t Token {
25 id : usize ,
26 }
27
28 i m p l From< User > f o r Token {
29 f n from ( u s e r : U s e r ) −> S e l f {
30 Token { i d : u s e r . i d }
31 }
32 }
33
34 # [ d e r i v e ( Debug , Clone , D e f a u l t ) ]
35 s t r u c t User {
36 id : usize ,
37 user : String ,
38 password : String ,
39 wallet : usize ,
40 flag : String ,
41 }
42
43 # [ d e r i v e ( Debug , Clone , D e f a u l t , S e r i a l i z e , D e s e r i a l i z e ) ]
44 struct GetWalletResponse {
45 first_name : String ,
46 last_name : String ,
47 wallet : usize ,
48 flag : String ,
49 }
50
51 # [ d e r i v e ( Debug ) ]
52 s t r u c t T o k e n V a l i d a t i o n E r r o r {}
53
54
55 i m p l From< f r a n k _ j w t : : E r r o r > f o r T o k e n V a l i d a t i o n E r r o r {
56 f n from ( _ : f r a n k _ j w t : : E r r o r ) −> S e l f {
57 T o k e n V a l i d a t i o n E r r o r {}
58 }
59 }
60
61 i m p l From< s e r d e _ j s o n : : E r r o r > f o r T o k e n V a l i d a t i o n E r r o r {
62 f n from ( _ : s e r d e _ j s o n : : E r r o r ) −> S e l f {
63 T o k e n V a l i d a t i o n E r r o r {}
64 }
65 }
66
67
68 f n v a l i d a t e _ t o k e n ( r e q u e s t : &R e q u e s t , key : &S t r i n g ) −> R e s u l t <Token , T o k e n V a l i d a t i o n E r r o r > {
69 i f l e t Some ( t o k e n ) = r e q u e s t . h e a d e r ( ” A u t h o r i z a t i o n ” ) {
70 l e t r a w _ s e g m e n t s : Vec<& s t r > = t o k e n . s p l i t ( ” . ” ) . c o l l e c t ( ) ;
71 i f raw_segments . len () < 2 {
72 return Err ( TokenValidationError { } ) ;
73 }
A.1 Certificate Pinning source 53
168 _ => ( )
169 );
170
171 l e t v a l i d a t i o n _ r e s u l t = v a l i d a t e _ t o k e n (& r e q u e s t , &key ) ;
172 i f v a l i d a t i o n _ r e s u l t . i s _ e r r ( ) { r e t u r n R e s p o n s e : : empty_404 ( ) ; }
173 h a n d l e _ b a n k i n g _ r e q u e s t (& r e q u e s t , v a l i d a t i o n _ r e s u l t . unwrap ( ) , &u s e r s )
174 })
175 // });
176 }
76
77 FILE * f l a g F i l e = f o p e n ( ” f l a g . t x t ” , ” r ” ) ;
78 f r e a d ( flag , 1 , 36 , f l a g F i l e ) ;
79
80 s e r v e r _ f d = s o c k e t ( AF_INET , SOCK_STREAM, 0 ) ;
81 s e t s o c k o p t ( s e r v e r _ f d , SOL_SOCKET , SO_REUSEADDR
82 | SO_REUSEPORT , &o p t , s i z e o f ( o p t ) ) ;
83 a d d r e s s . s i n _ f a m i l y = AF_INET ;
84 a d d r e s s . s i n _ a d d r . s _ a d d r = INADDR_ANY ;
85 a d d r e s s . s i n _ p o r t = h t o n s ( PORT ) ;
86
87 b i n d ( s e r v e r _ f d , ( s t r u c t s o c k a d d r * ) &a d d r e s s , s i z e o f ( a d d r e s s ) ) ;
88 l i s t e n ( server_fd , 3);
89 while ( t r u e ) {
90 i f ( ( new_socket = accept ( server_fd ,
91 ( s t r u c t s o c k a d d r * ) &a d d r e s s ,
92 ( s o c k l e n _ t * ) &a d d r l e n ) ) < 0 ) {
93 continue ;
94 }
95 v a l r e a d = read ( new_socket , iv , 1 6 ) ;
96 v a l r e a d = read ( new_socket , b u f f e r , 1 0 2 4 ) ;
97 p r i n t f ( ” Resived : ” ) ;
98 display ( buffer , valread ) ;
99 d e c r y p t ( b u f f e r , v a l r e a d , i v , key , 1 6 ) ;
100 p r i n t f ( ” Decrypted : ” ) ;
101 display ( buffer , valread ) ;
102 if ( testPadding ( buffer )) {
103 i f ( t e s t F l a g (& b u f f e r [ b u f f e r [ 0 ] ] , f l a g , 3 6 ) ) {
104 send ( new_socket , g r e a t i n g , s t r l e n ( g r e a t i n g ) , 0 ) ;
105 } else {
106 send ( new_socket ,
107 &”You know n o t h i n g , h a c k e r boy \ n ” , 2 9 , 0 ) ;
108 c l o s e ( new_socket ) ;
109 continue ;
110 }
111 } else {
112 s e n d ( n e w _ s o c k e t , &”You know n o t h i n g , s k i d \ n ” , 2 9 , 0 ) ;
113 c l o s e ( new_socket ) ;
114 continue ;
115 }
116 }
117 }
A.2.2 Client
1 # include < u n i s t d . h>
2 # include < s t d i o . h>
3 # include < s y s / s o c k e t . h>
4 # include < s t d l i b . h>
5 # include < n e t i n e t / i n . h>
6 # include < s t r i n g . h>
7 # include <math . h>
8 # include < s t d b o o l . h>
9 # include < m c r y p t . h>
10
11 # d e f i n e PORT 1337
12
13 v o i d d i s p l a y ( char * c i p h e r t e x t , i n t l e n ) {
14 int v ;
15 f o r ( v = 0 ; v < l e n ; v ++) {
16 p r i n t f ( ”%d ” , c i p h e r t e x t [ v ] ) ;
17 }
18 p r i n t f ( ” \ n” ) ;
19 }
20
21 b o o l t e s t P a d d i n g ( char b u f f e r [ 1 0 2 4 ] ) {
22
23 char p a d d i n g S i z e = b u f f e r [ 0 ] ;
24 f o r ( i n t i = 0 ; i < p a d d i n g S i z e ; ++ i ) {
25 i f ( p a d d i n g S i z e != b u f f e r [ i ] ) {
26 return f a l s e ;
27 }
28 }
29 return b u f f e r [ 0 ] ;
30 }
31
32 b o o l t e s t F l a g ( char * b u f f e r , char * f l a g , i n t l e n ) {
33 f o r ( i n t i = 0 ; i < l e n ; ++ i ) {
34 i f ( b u f f e r [ i ] != f l a g [ i ] ) {
35 return f a l s e ;
36 }
37 }
38 return t r u e ;
39 }
40
41 int decrypt (
42 void * buffer ,
43 int buffer_len ,
44 char *IV ,
45 char * key ,
46 int key_len
47 ) {
56 Appendix A. Source code
19 }
20
21 / * Modal C o n t e n t * /
22 . modal−c o n t e n t {
23 b a c k g r o u n d −c o l o r : # f e f e f e ;
24 margin : auto ;
25 p a d d i n g : 20 px ;
26 b o r d e r : 1 px s o l i d # 8 8 8 ;
27 w i d t h : 80%;
28 }
29
30 </ s t y l e >
31 < c a n v a s i d =” game ” h e i g h t =” 770 ” w i d t h =” 770 ” > </ c a n v a s >
32 < d i v i d =” myModal ” c l a s s =” modal ” >
33 < d i v c l a s s =” modal−c o n t e n t ” >
34 <p i d =” t e x t F i e l d ” > E n t e r l i c e n s e key < / p>
35 < i n p u t i d =” l i c e n s e _ k e y _ f i e l d ” >
36 < b u t t o n i d =” l i c e n s e _ b t n ” > E n t e r < / b u t t o n >
37 </ d i v >
38 </ d i v >
39 < b u t t o n o n c l i c k =” up ( ) ” >Up < / b u t t o n >
40 < b u t t o n o n c l i c k =” down ( ) ” >Down < / b u t t o n >
41 < b u t t o n o n c l i c k =” r i g h t ( ) ” > R i g h t < / b u t t o n >
42 < b u t t o n o n c l i c k =” l e f t ( ) ” > L e f t < / b u t t o n >
43 < s c r i p t s r c = h t t p s : / / c d n j s . c l o u d f l a r e . com / a j a x / l i b s / c r y p t o −j s / 3 . 1 . 9 − 1 / c r y p t o −j s . j s > </ s c r i p t >
44 <script >
45
46 let images = [ ] ;
47 let player = [ ] ;
48 let modal = document . g e t E l e m e n t B y I d ( ” myModal ” ) ;
49 let l i c e n s e _ b u t t o n = document . g e t E l e m e n t B y I d ( ” l i c e n s e _ b t n ” ) ;
50 let l i c e n s e _ k e y _ f i e l d = document . g e t E l e m e n t B y I d ( ” l i c e n s e _ k e y _ f i e l d ” ) ;
51 let license_key = ”” ;
52 let t e x t F i e l d = document . g e t E l e m e n t B y I d ( ” t e x t F i e l d ” ) ;
53
54 l i c e n s e _ b u t t o n . a d d E v e n t L i s t e n e r ( ” c l i c k ” , ( ) => {
55 modal . s t y l e . d i s p l a y = ” none ” ;
56 add_game_controls ( ) ;
57 l i c e n s e _ k e y = document . g e t E l e m e n t B y I d ( ” l i c e n s e _ k e y _ f i e l d ” ) . v a l u e ;
58 up ( ) ;
59 });
60
61 function add_game_controls (){
62 window . a d d E v e n t L i s t e n e r ( ” keydown ” , f u n c t i o n ( e v e n t ) {
63 i f ( event . defaultPrevented ) {
64 r e t u r n ; / / Do n o t h i n g i f t h e e v e n t was a l r e a d y p r o c e s s e d
65 }
66
67 s w i t c h ( e v e n t . key ) {
68 c a s e ”Down” : / / IE / Edge s p e c i f i c v a l u e
69 c a s e ” ArrowDown ” :
70 case ” s ” :
71 c a s e ” S” :
72 down ( ) ;
73 break ;
74 c a s e ”Up” : / / IE / Edge s p e c i f i c v a l u e
75 c a s e ” ArrowUp ” :
76 c a s e ”w” :
77 c a s e ”W” :
78 up ( ) ;
79 break ;
80 c a s e ” L e f t ” : / / IE / Edge s p e c i f i c v a l u e
81 case ” ArrowLeft ” :
82 case ”a” :
83 c a s e ”A” :
84 left ();
85 / / Do s o m e t h i n g f o r ” l e f t a r r o w ” key p r e s s .
86 break ;
87 c a s e ” R i g h t ” : / / IE / Edge s p e c i f i c v a l u e
88 case ” ArrowRight ” :
89 case ”d” :
90 c a s e ”D” :
91 right ();
92 default :
93 r e t u r n ; / / Q u i t when t h i s d o e s n ’ t h a n d l e t h e key e v e n t .
94 }
95
96 / / Cancel the d e f a u l t a c t i o n to avoid i t being handled twice
97 event . preventDefault ( ) ;
98 } , true );
99 }
100
101 window . o n l o a d = f u n c t i o n ( ) {
102 f o r ( l e t i = 0 ; i <= 4 ; i ++) {
103 l e t image = new Image ( ) ;
104 image . s r c = ‘ / t i l e / C h a r a c t e r $ { i } . png ‘ ;
105 image . o n l o a d = ( ) = > { } ;
106 p l a y e r . p u s h ( image ) ;
107 }
108
109 f o r ( l e t i = 0 ; i <= 7 8 ; i ++) {
110 l e t image = new Image ( ) ;
111 image . s r c = ‘ / t i l e / O u t d o o r s _ $ { i } . png ‘ ;
112 image . o n l o a d = ( ) = > { } ;
58 Appendix A. Source code
113 i m a g e s . p u s h ( image ) ;
114 }
115 };
116
117 f u n c t i o n drawPlayer ( pos ) {
118 i f ( p o s == ” up ” ) {
119 pos = 0 ;
120 } e l s e i f ( p o s == ” down ” ) {
121 pos = 3 ;
122 } e l s e i f ( p o s == ” l e f t ” ) {
123 pos = 2 ;
124 } else {
125 pos = 1 ;
126 }
127 l e t c = document . g e t E l e m e n t B y I d ( ” game ” ) ;
128 l e t ctx = c . getContext (”2 d ” ) ;
129 c t x . drawImage ( p l a y e r [ p o s ] , 70 * 5 , 5 * 7 0 , 7 0 , 7 0 ) ;
130 }
131
132 function clear () {
133 l e t c = document . g e t E l e m e n t B y I d ( ” game ” ) ;
134 l e t ctx = c . getContext (”2 d ” ) ;
135 c t x . f i l l S t y l e = ”#70 BB23 ” ;
136 c t x . f i l l R e c t ( 0 , 0 , c . width , c . h e i g h t ) ;
137 }
138
139 f u n c t i o n drawLayer ( l a y e r ) {
140 l e t c = document . g e t E l e m e n t B y I d ( ” game ” ) ;
141 l e t ctx = c . getContext (”2 d ” ) ;
142 l a y e r . f o r E a c h ( ( row , j ) => {
143 row . f o r E a c h ( ( e l e m e n t , i ) => {
144 i f ( e l e m e n t === −1) r e t u r n ;
145 c t x . drawImage ( i m a g e s [ e l e m e n t ] , i * 7 0 , j * 7 0 , 7 0 , 7 0 ) ;
146 });
147 });
148 }
149
150
151 f u n c t i o n sendMove ( d i r e c t i o n ) {
152 l e t key = C r y p t o J S . e n c . U t f 8 . p a r s e ( l i c e n s e _ k e y ) ;
153
154 l e t e n c r y p t e d = C r y p t o J S . AES . e n c r y p t ( d i r e c t i o n , key , {
155 mode : C r y p t o J S . mode . CBC,
156 i v : C r y p t o J S . l i b . WordArray . random ( 1 6 ) ,
157 p a d d i n g : C r y p t o J S . pad . P k c s 7
158 });
159
160 c o n s t H t t p = new XMLHttpRequest ( ) ;
161 c o n s t u r l = ‘ / move ? d i r e c t i o n =$ { encodeURIComponent ( e n c r y p t e d )}& i v =$ { encodeURIComponent ( C r y p t o J S . e n c . Base64 . s t r i n g i f y ( e n c r y p t e d . i v ) ) } ‘
162 H t t p . open ( ” GET” , u r l ) ;
163 Http . send ( ) ;
164
165 H t t p . o n r e a d y s t a t e c h a n g e = ( e ) => {
166 i f ( H t t p . r e a d y S t a t e === 4 && H t t p . s t a t u s === 2 0 0 ) {
167 l e t map = JSON . p a r s e ( H t t p . r e s p o n s e T e x t ) ;
168 i f ( map . f l a g ) {
169 modal . s t y l e . d i s p l a y = ” b l o c k ” ;
170 l i c e n s e _ b u t t o n . s t y l e . d i s p l a y = ” none ” ;
171 l i c e n s e _ k e y _ f i e l d . s t y l e . d i s p l a y = ” none ” ;
172 t e x t F i e l d . i n n e r T e x t = map . f l a g ;
173 }
174 clear ();
175 d r a w L a y e r ( map . l a y e r 1 ) ;
176 d r a w L a y e r ( map . l a y e r 2 ) ;
177 drawPlayer ( d i r e c t i o n ) ;
178 }
179
180 };
181
182 }
183
184 f u n c t i o n up ( ) {
185 sendMove ( ” up ” ) ;
186 }
187
188 f u n c t i o n down ( ) {
189 sendMove ( ” down ” ) ;
190 }
191
192 function l e f t () {
193 sendMove ( ” l e f t ” ) ;
194 }
195
196 function right () {
197 sendMove ( ” r i g h t ” ) ;
198 }
199
200 </ s c r i p t >
A.3.2 Backend
1 extern c r a t e serde ;
A.3 Repeatable game source 59
2 # [ macro_use ]
3 extern c r a t e r o u i l l e ;
4 # [ macro_use ]
5 extern c r a t e serde_derive ;
6
7 use s t d : : c o l l e c t i o n s : : HashMap ;
8 use std : : io ;
9 use std : : str : : Split ;
10 use std : : str ;
11 use s t d : : s t r : : FromStr ;
12 use s t d : : s y n c : : Mutex ;
13 use std : : thread ;
14 use std : : fs : : File ;
15 use s t d : : i o : : { Read , BufReader , BufRead } ;
16 use r o u i l l e : : Request ;
17 use r o u i l l e : : Response ;
18 use base64 : : decode ;
19 use hex ;
20 use a e s : : Aes128 ;
21 use b l o c k _ m o d e s : : Cbc ;
22 use b l o c k _ m o d e s : : BlockMode ;
23 use block_modes : : b l o c k _ p a d d i n g : : Pkcs7 ;
24
25 t y p e Aes128Cbc = Cbc<Aes128 , Pkcs7 > ;
26
27 s t a t i c WALKABLE_TILE_VALUES : [ i 8 ; 4 3 ] = [ − 1 , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 1 0 , 1 1 , 1 2 , 1 3 , 1 4 , 1 8 ,
28 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 ,
29 54 , 58 , 59 , 60 , 61 , 62 , 63 , 64 , 65 , 66 , 67 , 6 8 ] ;
30
31 # [ d e r i v e ( Debug , Clone , Copy ) ]
32 struct SessionData { x : usize , y : usize }
33
34 #[ derive ( Serialize )]
35 s t r u c t MapView { l a y e r 1 : [ [ i 8 ; 1 1 ] ; 1 1 ] , l a y e r 2 : [ [ i 8 ; 1 1 ] ; 1 1 ] }
36
37 #[ derive ( Serialize )]
38 struct Flag { f l a g : S t r i n g }
39
40 f n make_map_view ( p l a y e r : &S e s s i o n D a t a , l a y e r 1 : &Vec<Vec< i 8 > > , l a y e r 2 : &Vec<Vec< i 8 > >) −> MapView {
41 l e t mut map_view = MapView { l a y e r 1 : [ [ 0 ; 1 1 ] ; 1 1 ] , l a y e r 2 : [ [ 0 ; 1 1 ] ; 11] };
42 f o r y i n 0 . . map_view . l a y e r 1 . l e n ( ) {
43 f o r x i n 0 . . map_view . l a y e r 1 . l e n ( ) {
44 l e t map_x = ( p l a y e r . x + x ) a s i 3 2 − 5 ;
45 l e t map_y = ( p l a y e r . y + y ) a s i 3 2 − 5 ;
46 map_view . l a y e r 1 [ y ] [ x ] = l a y e r 1 [ map_y a s u s i z e ] [ map_x a s usize ];
47 map_view . l a y e r 2 [ y ] [ x ] = l a y e r 2 [ map_y a s u s i z e ] [ map_x a s usize ];
48 }
49 }
50 map_view
51 }
52
53 f n w a l k a b l e _ t i l e ( p o s i t i o n : &S e s s i o n D a t a , l a y e r 1 : &Vec<Vec< i 8 > > , l a y e r 2 : &Vec<Vec< i 8 > >) −> b o o l {
54 r e t u r n WALKABLE_TILE_VALUES . c o n t a i n s (& l a y e r 1 [ p o s i t i o n . y ] [ p o s i t i o n . x ] ) ;
55 }
56
57 f n l o a d _ t i l e _ l a y e r _ f r o m _ f i l e ( f i l e n a m e : & s t r ) −> Vec<Vec< i 8 >> {
58 l e t mut l a y e r = Vec : : < Vec< i 8 > > : : new ( ) ;
59 f o r l i n e i n B u f R e a d e r : : new ( F i l e : : open ( f i l e n a m e ) . unwrap ( ) ) . l i n e s ( ) {
60 l a y e r . p u s h ( l i n e . unwrap ( ) . s p l i t ( ” , ” ) . map ( | s t r | {
61 i 8 : : f r o m _ s t r ( s t r ) . unwrap ( )
62 }). collect ());
63 }
64 layer
65 }
66
67 f n h a n d l e _ m o v e ( s e s s i o n _ d a t a : &S e s s i o n D a t a , m o v e _ d a t a : &s t r , i v : &s t r , key : &Vec<u8 > ) −> S e s s i o n D a t a {
68 l e t d e c o d e d _ d a t a = d e c o d e ( m o v e _ d a t a ) . unwrap ( ) ;
69 l e t i v = d e c o d e ( i v ) . unwrap ( ) ;
70
71
72 l e t c i p h e r = Aes128Cbc : : new_var ( key , &i v ) . unwrap ( ) ;
73 l e t d e c r y p t e d _ c i p h e r t e x t = c i p h e r . d e c r y p t _ v e c (& d e c o d e d _ d a t a ) . u n w r a p _ o r ( v e c ! [ 6 5 ] ) ;
74 l e t d i r e c t i o n = s t r : : f r o m _ u t f 8 (& d e c r y p t e d _ c i p h e r t e x t ) . u n w r a p _ o r ( ” f a i l e d ” ) ;
75
76 match d i r e c t i o n {
77 ” down ” => S e s s i o n D a t a { y : s e s s i o n _ d a t a . y + 1 , x : s e s s i o n _ d a t a . x } ,
78 ” up ” => S e s s i o n D a t a { y : s e s s i o n _ d a t a . y − 1 , x : s e s s i o n _ d a t a . x } ,
79 ” l e f t ” => S e s s i o n D a t a { y : s e s s i o n _ d a t a . y , x : s e s s i o n _ d a t a . x − 1 } ,
80 ” r i g h t ” => S e s s i o n D a t a { y : s e s s i o n _ d a t a . y , x : s e s s i o n _ d a t a . x + 1 } ,
81 _ => S e s s i o n D a t a { y : s e s s i o n _ d a t a . y , x : s e s s i o n _ d a t a . x }
82 }
83 }
84
85 f n main ( ) {
86 l e t s e s s i o n s _ s t o r a g e : Mutex <HashMap< S t r i n g , S e s s i o n D a t a >> = Mutex : : new ( HashMap : : new ( ) ) ;
87 l e t mut game_view = S t r i n g : : new ( ) ;
88 l e t mut f l a g = S t r i n g : : new ( ) ;
89 l e t mut key : Vec<u8 > = v e c ! [ ] ;
90 F i l e : : open ( ” game_view . h t m l ” ) . unwrap ( ) . r e a d _ t o _ s t r i n g (&mut game_view ) . unwrap ( ) ;
91 F i l e : : open ( ” f l a g . t x t ” ) . unwrap ( ) . r e a d _ t o _ s t r i n g (&mut f l a g ) . unwrap ( ) ;
92 F i l e : : open ( ” key . t x t ” ) . unwrap ( ) . r e a d _ t o _ e n d (&mut key ) . unwrap ( ) ;
93 l e t l a y e r 1 = l o a d _ t i l e _ l a y e r _ f r o m _ f i l e ( ” t i l e s / t e s t _ T i l e Layer 1 . csv ” ) ;
94 l e t l a y e r 2 = l o a d _ t i l e _ l a y e r _ f r o m _ f i l e ( ” t i l e s / t e s t _ T i l e Layer 2 . csv ” ) ;
95 l e t u r l = envmnt : : g e t _ o r ( ”URL” , ” 0 . 0 . 0 . 0 ” ) ;
60 Appendix A. Source code
50 */
51
52 println ! ( ” a s n 1 =SEQUENCE : r s a _ k e y ” ) ;
53 println !( ”” );
54 println ! ( ” \ t [ rsa_key ] ” ) ;
55 println ! ( ” v e r s i o n =INTEGER : 0 ” ) ;
56 println ! ( ” modulus =INTEGER : { } ” , &modulus ) ;
57 println ! ( ” pubExp=INTEGER : { } ” , &pub_exp ) ;
58 println ! ( ” p r i v E x p =INTEGER : { } ” , &p r i v _ e x p ) ;
59 println ! ( ” p=INTEGER : { } ” , &p ) ;
60 println ! ( ” q=INTEGER : { } ” , &q ) ;
61 println ! ( ” e1 =INTEGER : { } ” , &e1 ) ;
62 println ! ( ” e2 =INTEGER : { } ” , &e2 ) ;
63 println ! ( ” c o e f f =INTEGER : { } ” , &c o e f f ) ;
64
65
66 }
62 Appendix A. Source code
Bibliography
[16] T. Aura. Strategies against replay attacks. In Proceedings of the 10th IEEE Workshop
on Computer Security Foundations, CSFW ’97, pages 59–59. IEEE Computer Society,
1997. 32
[18] D. Cooper, S. Santesson, S. Farrell, S. Boeyen, R. Housley, and W. Polk. RFC 5280.
https://tools.ietf.org/html/rfc5280f, 2008. [Online; accessed 29.05.20]. 12
[21] J. Håstad. Solving simultaneous modular equations of low degree. SIAM J. Comput.,
17:336–341, 1988. 6
[22] S. Kamkar. phpwn: Attacking sessions and pseudo-random numbers in PHP. https://
samy.pl/phpwn/BlackHat-USA-2010-Kamkar-How-I-Met-Your-Girlfriend-wp.
pdf, 2010. [Online; accessed 12.02.20]. 33
[30] A. Roy, N. Memon, and A. Ross. Masterprint: Exploring the vulnerability of partial
fingerprint-based authentication systems. IEEE Transactions on Information Forensics
and Security, 12(9):2013–2025, 2017. 16
[33] S. Vaudenay. Security flaws induced by cbc padding — applications to ssl, ipsec, wtls...
In L. R. Knudsen, editor, Advances in Cryptology — EUROCRYPT 2002, pages 534–
545, Berlin, Heidelberg, 2002. Springer Berlin Heidelberg. 28