Skip to content

Commit a005c28

Browse files
committed
release 2019 quals and beginners quest
1 parent fe23bcd commit a005c28

File tree

399 files changed

+57867
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

399 files changed

+57867
-0
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# name: "Crypto Caulingo"
2+
3+
description: "Well you've done it, you're now an admin of the Cookie World Order. The clandestine organisation that seeks to control the world through a series of artfully placed tasty treats, bringing folks back in to their idea of what a utopian society would look like. Strangely enough, the webcam data is being fed to understand the properties of the entities you had originally seen. They seem to be speaking back into the camera (an unadvertised microphone) but it's hard to understand what they want. You must- if nothing else ever was important in your life, you must make contact with these beautiful creatures! Also, what exactly is a \"cauliflower\"?"
4+
5+
# flag: "CTF{017d72f0b513e89830bccf5a36306ad944085a47}"
51.8 KB
Binary file not shown.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Hints
2+
3+
4+
### Where to start
5+
6+
* Bruteforce
7+
* Fermat's Factorization Method
8+
9+
10+
### Search return nothing
11+
12+
* Check the precision of the result of your `sqrt`
13+
* Do not use python's own `sqrt`
14+
* Do not use python's `Decimal.sqrt()`
15+
* Try using `gmpy2` or `sagemath`
16+
17+
### License
18+
19+
Copyright 2019 Google LLC
20+
21+
Licensed under the Apache License, Version 2.0 (the "License");
22+
you may not use this file except in compliance with the License.
23+
You may obtain a copy of the License at
24+
25+
https://www.apache.org/licenses/LICENSE-2.0
26+
27+
Unless required by applicable law or agreed to in writing, software
28+
distributed under the License is distributed on an "AS IS" BASIS,
29+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30+
See the License for the specific language governing permissions and
31+
limitations under the License.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Solution
2+
3+
```text
4+
a * p ≈ b * q
5+
-> a / b * p ≈ q
6+
-> a / b * p * q ≈ q * q
7+
-> a / b * N ≈ q^2
8+
-> q^2 ≈ N / b * a
9+
-> q ≈ sqrt(N / b * a)
10+
```
11+
12+
If we know `a` and `b`, we know the estimate of `q`, then we can search around
13+
`q` (i.e. the range `[est_q - delta, est_q + delta]`) and find one that divides `N`.
14+
15+
Since `a` and `b` are small, we could bruteforce all possible `(a, b)` pairs,
16+
then search around the corresponding estimate of `q`.
17+
18+
Since `abs(a * p - b * q) < 10000`, we expect that the estimate of `q` won't be
19+
too far away from the actual `q`. We could start searching from `est_q ± 10`,
20+
then `est_q ± 100`, then `est_q ± 1000` and so on until we are able to find the
21+
answer. In this challenge, `est_q ± 10` would be enough.
22+
23+
After we've found the `q` that divides `N`, we basically factorized `N`. We can
24+
then obtain `p = N / q`, `phi = (p - 1) * (q - 1)`, and the decryption key
25+
`d = invert(e, phi)`. Obtain the plaintext by `pow(c, d, n)`.
26+
27+
Note that native python doesn't handle `sqrt` of huge numbers properly. So one
28+
should use libraries like `gmpy2` or `sagemath` to compute the square root. I
29+
guess python try to convert your integer to float before performaing square
30+
root, and the precision of the float is not enough for such huge numbers.
31+
32+
See `solution.py` for a sample solution script.
33+
34+
35+
# License
36+
37+
Copyright 2019 Google LLC
38+
39+
Licensed under the Apache License, Version 2.0 (the "License");
40+
you may not use this file except in compliance with the License.
41+
You may obtain a copy of the License at
42+
43+
https://www.apache.org/licenses/LICENSE-2.0
44+
45+
Unless required by applicable law or agreed to in writing, software
46+
distributed under the License is distributed on an "AS IS" BASIS,
47+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
48+
See the License for the specific language governing permissions and
49+
limitations under the License.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/usr/bin/env python3
2+
3+
# Copyright 2019 Google LLC
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# https://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
from Crypto.Util.number import long_to_bytes, bytes_to_long
18+
from gmpy2 import mpz, isqrt, invert, powmod
19+
20+
n = mpz(17450892350509567071590987572582143158927907441748820483575144211411640241849663641180283816984167447652133133054833591585389505754635416604577584488321462013117163124742030681698693455489404696371546386866372290759608301392572928615767980244699473803730080008332364994345680261823712464595329369719516212105135055607592676087287980208987076052877442747436020751549591608244950255761481664468992126299001817410516694015560044888704699389291971764957871922598761298482950811618390145762835363357354812871474680543182075024126064364949000115542650091904557502192704672930197172086048687333172564520657739528469975770627)
21+
e = 65537
22+
23+
c = bytes_to_long(bytes.fromhex('50fb0b3f17315f7dfa25378fa0b06c8d955fad0493365669bbaa524688128ee9099ab713a3369a5844bdd99a5db98f333ef55159d3025630c869216889be03120e3a4bd6553d7111c089220086092bcffc5e42f1004f9888f25892a7ca007e8ac6de9463da46f71af4c8a8f806bee92bf79a8121a7a34c3d564ac7f11b224dc090d97fdb427c10867ad177ec35525b513e40bef3b2ba3e6c97cb31d4fe3a6231fdb15643b84a1ce704838d8b99e5b0737e1fd30a9cc51786dcac07dcb9c0161fc754cda5380fdf3147eb4fbe49bc9821a0bcad98d6df9fbdf63cf7d7a5e4f6cbea4b683dfa965d0bd51f792047e393ddd7b7d99931c3ed1d033cebc91968d43f'))
24+
25+
def solve_pq(n):
26+
for a in range(1, 1001):
27+
for b in range(a, 1001):
28+
est_q = isqrt(n // b * a)
29+
for q in range(est_q - 100, est_q + 100):
30+
if n % q == 0:
31+
return n // q, q
32+
33+
p, q = solve_pq(n)
34+
phi = (p - 1) * (q - 1)
35+
d = invert(e, phi)
36+
37+
msg = long_to_bytes(powmod(c, d, n))
38+
print(msg.decode('utf-8'))
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Google CTF 2019 Beginner's quest - Drive to the target
2+
3+
## Installation
4+
5+
```
6+
$ pip install -r requirements.txt
7+
```
8+
9+
## Intended solution
10+
11+
The goal is to drive from the starting point to the final point, by inputting
12+
coordinates. See the exploit.py script for a possible implementation.
13+
14+
## Hints
15+
16+
- What is the point of the challenge?
17+
- How can you maximize your speed?
18+
- How can you know where you're supposed to go?
19+
20+
## License
21+
22+
Copyright 2019 Google LLC
23+
24+
Licensed under the Apache License, Version 2.0 (the "License");
25+
you may not use this file except in compliance with the License.
26+
You may obtain a copy of the License at
27+
28+
https://www.apache.org/licenses/LICENSE-2.0
29+
30+
Unless required by applicable law or agreed to in writing, software
31+
distributed under the License is distributed on an "AS IS" BASIS,
32+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
33+
See the License for the specific language governing permissions and
34+
limitations under the License.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#
2+
# Copyright 2019 Google LLC
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# https://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
17+
service: drivetothetarget-19a22ab12qofd
18+
runtime: python37
19+
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Copyright 2019 Google LLC
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.import requests
16+
#
17+
18+
from datetime import datetime, timedelta
19+
from cryptography.fernet import Fernet
20+
from geopy.distance import geodesic
21+
from flask import Flask, render_template, request
22+
23+
app = Flask(__name__)
24+
25+
STARTING_POINT = (51.6498, 0.0982)
26+
DESTINATION_POINT = (51.4921, -0.1929)
27+
MAX_STEP_DISTANCE = 300 # no more than 300 meters per step
28+
MAX_SPEED_KMPH = 50 # 50 km/h. It will take under an hour to drive from start to destination.
29+
FINISH_RADIUS = 10 # If the point is within 10m from DESTINATION_POINT then FLAG is shown
30+
FLAG = ' CTF{Who_is_Tardis_Ormandy}'
31+
32+
f = Fernet(b'l4ydYP_3aH8n7uQR2EIHgt-jfhhL7U6-yurXBeE89Do=')
33+
34+
def parse_state(state):
35+
lat, lon, time = tuple(map(float, state.split(',')))
36+
return (lat, lon), datetime.fromtimestamp(time)
37+
38+
@app.route('/')
39+
def process():
40+
try:
41+
time = datetime.now()
42+
if 'token' not in request.args:
43+
token = f.encrypt(('%f,%f,%f' % (STARTING_POINT[0], STARTING_POINT[1],time.timestamp())).encode()).decode()
44+
return render_template('ui.html', lat=STARTING_POINT[0], lon=STARTING_POINT[1], token=token)
45+
46+
old_token = request.args.get('token')
47+
pos = float(request.args.get('lat')), float(request.args.get('lon'))
48+
49+
old_pos, old_time = parse_state(f.decrypt(old_token.encode()).decode())
50+
distance = geodesic(old_pos, pos)
51+
hours = (time - old_time) / timedelta(hours=1)
52+
speed_kmph = distance.kilometers / hours if hours > 0 else 10 * MAX_SPEED_KMPH # if time == old_time, e.g. hours == 0, then we say that player has moved infinitely fast, e.g. 10 max speeds.
53+
next_pos, next_token = old_pos, old_token
54+
55+
msg = ''
56+
if old_pos == pos:
57+
msg = 'If you want to meet your friends, you should move.'
58+
elif speed_kmph > MAX_SPEED_KMPH:
59+
msg = 'Woa, were about to move at %dkm/h, this is too fast!' % speed_kmph
60+
elif distance.meters > MAX_STEP_DISTANCE:
61+
msg = 'You tried to travel %dm, which too far at once from your current position.' % distance.meters
62+
else:
63+
if geodesic(pos, DESTINATION_POINT).meters < FINISH_RADIUS:
64+
msg = 'Congratulations, you made it, here is the flag: %s' % FLAG
65+
elif geodesic(pos, DESTINATION_POINT) < geodesic(old_pos, DESTINATION_POINT):
66+
msg = 'You went %dm at a speed of %dkm/h. You are getting closer…' % (distance.meters, speed_kmph)
67+
else:
68+
msg = 'You went %dm at a speed of %dkm/h. You are getting away…' % (distance.meters, speed_kmph)
69+
next_token = f.encrypt(('%f,%f,%f' % (pos[0], pos[1],time.timestamp())).encode()).decode()
70+
next_pos = pos
71+
return render_template('ui.html', lat=next_pos[0], lon=next_pos[1], token=next_token, message=msg)
72+
except Exception as e:
73+
print(e)
74+
return 'Please use roads.'
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
Copyright 2019 Google LLC
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.import requests
15+
*/
16+
17+
body {
18+
line-height: 1.6;
19+
color: #4a4a4a;
20+
background: #f9f9f9;
21+
max-width: 40rem;
22+
padding: 2rem;
23+
margin: auto;
24+
font-family: Verdana, Geneva, sans-serif;
25+
}
26+
img {
27+
max-width: 100%;
28+
}
29+
a {
30+
color: #2ECC40;
31+
}
32+
33+
.grey {
34+
padding: 1em;
35+
background-color: #f1f1f1;
36+
}
37+
38+
textarea, select, input[type] {
39+
color: #4a4a4a;
40+
padding: 6px 10px;
41+
margin-bottom: 10px;
42+
background-color: #f1f1f1;
43+
border: 1px solid #f1f1f1;
44+
border-radius: 4px;
45+
box-shadow: none;
46+
box-sizing: border-box;
47+
}
48+
49+
fieldset {
50+
border: 1px solid #c0c0c0;
51+
margin: 0 2px;
52+
padding: 0.35em 0.625em 0.75em;
53+
}
54+
55+
label, legend, fieldset {
56+
display: block;
57+
margin-bottom: .5rem;
58+
font-weight: 600;
59+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<!--
2+
Copyright 2019 Google LLC
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
https://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
-->
13+
14+
<!doctype html>
15+
<html>
16+
<head>
17+
<link href="{{ url_for('static', filename='style.css') }}" type="text/css" rel="stylesheet"/>
18+
<title>Driving to the target</title>
19+
</head>
20+
<h1>Driving to the target</h1>
21+
<body>
22+
<p>Hurry up, don't be late for you rendez-vous!
23+
<form method="get" action="/">
24+
<fieldset>
25+
<legend>Pick your direction</legend>
26+
<input type="number" name="lat" value="{{ lat }}" min="-90" max="90" step="0.0001">
27+
<input type="number" name="lon" value="{{ lon }}" min="-180" max="180" step="0.0001">
28+
<input style="display: none" name="token" value="{{ token }}">
29+
<button type="submit">go</button>
30+
</fieldset>
31+
</form>
32+
<p>{{ message }}</p>
33+
</body>
34+
</html>

0 commit comments

Comments
 (0)