Initial commit
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
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
|
||||
@@ -0,0 +1,34 @@
|
||||
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': 'ctfuser',
|
||||
'password': getattr(self.settings, f'PASSWORD_{self.port}'),
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
from .Challenge import Challenge
|
||||
|
||||
import io
|
||||
import requests
|
||||
import random
|
||||
import subprocess
|
||||
import requests
|
||||
import re
|
||||
|
||||
class Naraka(Challenge):
|
||||
flag_location = 'flags/naraka.txt'
|
||||
history_location = 'history/naraka.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):
|
||||
random_name = [
|
||||
"nael", "mufat", "rayhan", "wicak", "Kingggg",
|
||||
"osdie", "udin", "memet", "entong", "krabby",
|
||||
"mew", "charizard", "pidgey", "rattata", "vulpix",
|
||||
"eevee", "snorlax", "magikarp", "growlithe", "abra"
|
||||
]
|
||||
|
||||
math_expression = "+-*"
|
||||
|
||||
python_programs = [
|
||||
"a = 10;b = 5;print(a+b)", "a = 'add'; b='string';print(a+b)","x = [1,2,3,4,5,6,7,8];print(max(x))"
|
||||
]
|
||||
|
||||
programs_result = ["b'15","b'addstring","b'8"]
|
||||
try:
|
||||
# Step 1: Chekc Greetings return name
|
||||
name = random.choice(random_name)
|
||||
url = f'http://localhost:{self.port}/render?name={name}'
|
||||
r = requests.get(url, timeout=5)
|
||||
assert name in r.text, 'Greetings is not greetings my name :('
|
||||
|
||||
# Step 2: Check eval calculator using random math expression
|
||||
math = f'{random.randint(1,100)}{random.choice(math_expression)}{random.randint(1,100)}'
|
||||
math_result = eval(math)
|
||||
data = {'chall': '2','input':math}
|
||||
url = f'http://localhost:{self.port}/chall'
|
||||
r = requests.post(url, data=data, timeout=5)
|
||||
assert str(math_result) in r.text, 'Eval calculator is not working :('
|
||||
|
||||
# Step 3: Check exec that execute python program
|
||||
ind = random.randint(0,2)
|
||||
pythononeline = python_programs[ind]
|
||||
pythonresult = programs_result[ind]
|
||||
data = {'chall': '1','input':pythononeline}
|
||||
url = f'http://localhost:{self.port}/chall'
|
||||
r = requests.post(url, data=data, timeout=5)
|
||||
assert pythonresult in r.text, 'My code line is not execute :('
|
||||
|
||||
# Step 4: Check execute FLAG declaration execute
|
||||
url = f'http://localhost:{self.port}/sourcecode/1'
|
||||
r = requests.get(url, timeout=5)
|
||||
flag_assignments = re.findall(r'^\s*FLAG\s*=\s*sys\.argv\[2\]\s*$', r.text, re.MULTILINE)
|
||||
flag_assignments_num = flag_assignments = re.findall(r'^\s*FLAG\s*=\s*.+$', r.text, re.MULTILINE)
|
||||
assert flag_assignments != 1 or flag_assignments_num != 1, "execute FLAG declared incorrectly"
|
||||
|
||||
# Step 5: Check evaluate FLAG declaration execute
|
||||
url = f'http://localhost:{self.port}/sourcecode/1'
|
||||
r = requests.get(url, timeout=5)
|
||||
flag_assignments = re.findall(r'^\s*FLAG\s*=\s*sys\.argv\[2\]\s*$', r.text, re.MULTILINE)
|
||||
flag_assignments_num = flag_assignments = re.findall(r'^\s*FLAG\s*=\s*.+$', r.text, re.MULTILINE)
|
||||
assert flag_assignments != 1 or flag_assignments_num != 1, "evaluate FLAG declared incorrectly"
|
||||
|
||||
# Step 6: Check flag
|
||||
with open(self.flag_location, 'r') as f:
|
||||
host_flag = f.read().strip()
|
||||
|
||||
container_flag = subprocess.run(
|
||||
["docker", "exec", "naraka_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('Check passed for naraka')
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not check naraka: {e}')
|
||||
return False
|
||||
@@ -0,0 +1,93 @@
|
||||
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
|
||||
@@ -0,0 +1,65 @@
|
||||
from .Challenge import Challenge
|
||||
|
||||
import io
|
||||
import requests
|
||||
import random
|
||||
import subprocess
|
||||
|
||||
class Poke(Challenge):
|
||||
flag_location = 'flags/poke.txt'
|
||||
history_location = 'history/poke.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):
|
||||
pokemon_names = [
|
||||
"pikachu", "bulbasaur", "charmander", "squirtle", "jigglypuff",
|
||||
"meowth", "psyduck", "machop", "gastly", "krabby",
|
||||
"mew", "charizard", "pidgey", "rattata", "vulpix",
|
||||
"eevee", "snorlax", "magikarp", "growlithe", "abra"
|
||||
]
|
||||
|
||||
try:
|
||||
# Step 1: Randomize the Pokémon name
|
||||
pokemon_name = random.choice(pokemon_names)
|
||||
url = f'http://localhost:{self.port}/'
|
||||
data = {'pokemon_name': pokemon_name}
|
||||
r = requests.post(url, data=data, timeout=5)
|
||||
assert pokemon_name.lower() in r.text.lower(), 'Pokémon data not available'
|
||||
|
||||
# Step 2: Check if the image is available
|
||||
image_url = f'http://localhost:{self.port}/?image={pokemon_name.lower()}.png'
|
||||
r = requests.get(image_url, timeout=5)
|
||||
assert r.status_code == 200 and 'image/png' in r.headers['Content-Type'], 'Pokémon image not available or incorrect content type'
|
||||
|
||||
# Step 3: 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", "poke_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('Check passed for poke')
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not check poke: {e}')
|
||||
return False
|
||||
@@ -0,0 +1,88 @@
|
||||
from .Challenge import Challenge
|
||||
|
||||
import io
|
||||
import requests
|
||||
import random
|
||||
import subprocess
|
||||
import requests
|
||||
import re
|
||||
|
||||
class Wanderer(Challenge):
|
||||
flag_location = 'flags/wanderer.txt'
|
||||
history_location = 'history/wanderer.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:
|
||||
session = requests.Session()
|
||||
# Step 1: Check Register
|
||||
register_url = f'http://localhost:{self.port}/index.php?module=user&action=register'
|
||||
registration_data = {'username': 'adminwreckitchecker','password': 'adminwreckitchecker'}
|
||||
response = session.post(register_url, data=registration_data)
|
||||
assert "username already exists" in response.text or "Registration Success" in response.text or response.status_code == 200 , 'Function Register Failed'
|
||||
|
||||
# Step 2: Check Login
|
||||
login_url = f'http://localhost:{self.port}/index.php?module=user&action=login'
|
||||
login_data = {'username': 'adminwreckitchecker', 'password': 'adminwreckitchecker'}
|
||||
response = session.post(login_url, data=login_data)
|
||||
assert "Login Success" in response.text or response.status_code == 200, 'Login function failed'
|
||||
|
||||
# Step 3: Check UUID Not hidden
|
||||
view_page_url = f'http://localhost:{self.port}/index.php?module=page&action=viewPage'
|
||||
response = session.get(view_page_url)
|
||||
uuid_pattern = re.compile(r'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}')
|
||||
found_uuids = uuid_pattern.findall(response.text)
|
||||
assert found_uuids, 'UUID not found'
|
||||
|
||||
# Step 4: Check create sample page
|
||||
sample_page_url = f'http://localhost:{self.port}/index.php?module=page&action=samplePage'
|
||||
response = session.get(sample_page_url)
|
||||
assert "Create Success" in response.text or response.status_code == 200, 'Create Sample Failed'
|
||||
|
||||
# Step 5: Check Edit HTML Functionality
|
||||
edit_url_html = f'http://localhost:{self.port}/index.php?module=user&action=edit&type=html'
|
||||
response = session.get(edit_url_html)
|
||||
assert response.status_code == 200, 'Edit html page not accessible'
|
||||
|
||||
# Step 6: Check Edit JS Functionality
|
||||
edit_url_js = f'http://localhost:{self.port}/index.php?module=user&action=edit&type=js'
|
||||
response = session.get(edit_url_js)
|
||||
assert response.status_code == 200, 'Edit js page not accessible'
|
||||
|
||||
# Step 7: Check Edit CSS Functionality
|
||||
edit_url_css = f'http://localhost:{self.port}/index.php?module=user&action=edit&type=css'
|
||||
response = session.get(edit_url_css)
|
||||
assert response.status_code == 200, 'Edit css page not accessible'
|
||||
|
||||
# Step 8: Check flag
|
||||
with open(self.flag_location, 'r') as f:
|
||||
host_flag = f.read().strip()
|
||||
|
||||
container_flag = subprocess.run(
|
||||
["docker", "exec", "wanderer_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('Check passed for wanderer')
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'Could not check wanderer: {e}')
|
||||
return False
|
||||
Reference in New Issue
Block a user