Initial commit
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
FROM public.ecr.aws/docker/library/python:slim
|
||||
|
||||
ARG PASSWORD
|
||||
|
||||
WORKDIR /opt
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y nano openssh-server \
|
||||
gcc curl
|
||||
|
||||
# Create ctfuser and set password
|
||||
RUN useradd -m -d /opt ctfuser && echo ctfuser:${PASSWORD} | chpasswd
|
||||
|
||||
COPY src/ .
|
||||
|
||||
# Generate a random flag and write it to /opt/flag
|
||||
RUN python3 -c "import random; import string; flag = ''.join(random.choices(string.digits, k=8)); open('/opt/flag', 'w').write(flag)"
|
||||
|
||||
# Change ownership of /opt and its contents to ctfuser
|
||||
RUN chown -R ctfuser:ctfuser /opt
|
||||
|
||||
# Set restrictive permissions for the /opt directory and its contents
|
||||
RUN chmod 700 /opt && \
|
||||
find /opt -type f -exec chmod 400 {} \;
|
||||
|
||||
# Allow write permissions only for /opt/server.py for ctfuser
|
||||
RUN chmod 700 /opt/server.py
|
||||
|
||||
# Configure SSH for ctfuser
|
||||
RUN echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config && \
|
||||
echo "PermitRootLogin no" >> /etc/ssh/sshd_config && \
|
||||
echo "AllowUsers ctfuser" >> /etc/ssh/sshd_config
|
||||
|
||||
# Start SSH service
|
||||
RUN ssh-keygen -A
|
||||
RUN mkdir -p /run/sshd && chmod 755 /run/sshd
|
||||
|
||||
RUN touch /flag.txt
|
||||
|
||||
RUN pip install -r requirements.txt
|
||||
RUN chmod +x ./start.sh
|
||||
RUN chmod +x ./niko
|
||||
|
||||
CMD service ssh start && ./start.sh
|
||||
|
||||
EXPOSE 8000
|
||||
EXPOSE 22
|
||||
@@ -0,0 +1,15 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
niko:
|
||||
restart: always
|
||||
container_name: niko
|
||||
build:
|
||||
context: ./
|
||||
args:
|
||||
- PASSWORD=PASSWORD_15000
|
||||
ports:
|
||||
- "15000:8000"
|
||||
- "15022:22"
|
||||
volumes:
|
||||
- ./flag.txt:/flag.txt:ro
|
||||
@@ -0,0 +1 @@
|
||||
WRECKIT50{PLACEHOLDER}
|
||||
Binary file not shown.
@@ -0,0 +1,153 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>NikoChat</title>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
|
||||
rel="stylesheet"
|
||||
integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Kiwi+Maru:wght@700&display=swap');
|
||||
|
||||
:root {
|
||||
--bs-body-bg: var(--bs-gray-100);
|
||||
}
|
||||
|
||||
/* Hide the video container initially */
|
||||
#video-container {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
right: 50px;
|
||||
width: 400px;
|
||||
height: 400px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
#video-player {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
/* Centering the main container */
|
||||
.chat-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
text-align: center;
|
||||
font-family: 'Kiwi Maru', serif;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3rem;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
textarea {
|
||||
height: 200px;
|
||||
resize: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="/">NikoChat</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Video Container -->
|
||||
<div id="video-container">
|
||||
<video id="video-player" loop>
|
||||
<source src="./static/konten-deepweb.mp4" type="video/mp4" />
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</div>
|
||||
|
||||
<!-- Centered Content -->
|
||||
<div class="chat-container">
|
||||
<h1>こんにちは、NIKO!</h1>
|
||||
|
||||
<div class="container flex d-flex flex-column p-5">
|
||||
<div class="p-3">
|
||||
<label for="input" class="form-label">Send Message</label>
|
||||
<textarea
|
||||
class="form-control font-monospace"
|
||||
id="input"
|
||||
></textarea>
|
||||
</div>
|
||||
<div class="d-flex p-1 justify-content-end">
|
||||
<button
|
||||
type="button"
|
||||
class="my-2 btn btn-primary m-3"
|
||||
onclick="run()"
|
||||
>
|
||||
Send
|
||||
</button>
|
||||
</div>
|
||||
<div class="p-3">
|
||||
<label for="output" class="form-label">Reply</label>
|
||||
<textarea
|
||||
class="form-control font-monospace"
|
||||
id="output"
|
||||
disabled
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
|
||||
integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz"
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
<script>
|
||||
// Disable right-click
|
||||
document.addEventListener("contextmenu", function (e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
// Function to start the video and show the container
|
||||
function startVideo() {
|
||||
var videoContainer = document.getElementById("video-container");
|
||||
var videoPlayer = document.getElementById("video-player");
|
||||
|
||||
if (videoPlayer.paused) {
|
||||
videoContainer.style.display = "block"; // Show the video container
|
||||
videoPlayer.play();
|
||||
}
|
||||
}
|
||||
|
||||
// Event listener for typing in the input
|
||||
document.querySelector("#input").addEventListener("input", startVideo);
|
||||
|
||||
// Function to send the message
|
||||
function run() {
|
||||
startVideo(); // Start the video when the send button is clicked
|
||||
|
||||
var inputEl = document.querySelector("#input");
|
||||
var outputEl = document.querySelector("#output");
|
||||
|
||||
var msg = inputEl.value;
|
||||
|
||||
fetch("/api/chat", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ msg }),
|
||||
})
|
||||
.then((r) => r.json())
|
||||
.then((r) => (outputEl.value = r.output));
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
@@ -0,0 +1,2 @@
|
||||
uvicorn==0.23.2
|
||||
fastapi==0.103.1
|
||||
@@ -0,0 +1,92 @@
|
||||
import tempfile
|
||||
import subprocess
|
||||
import random
|
||||
import base64
|
||||
from subprocess import check_output
|
||||
from fastapi import FastAPI, Query, Request
|
||||
from fastapi.responses import FileResponse, PlainTextResponse, HTMLResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from pydantic import BaseModel
|
||||
import os
|
||||
|
||||
class Input(BaseModel):
|
||||
msg: bytes
|
||||
|
||||
class Output(BaseModel):
|
||||
output: str
|
||||
|
||||
app = FastAPI()
|
||||
app.mount("/static", StaticFiles(directory="static"), name="static")
|
||||
|
||||
@app.get("/")
|
||||
def index():
|
||||
return FileResponse("index.html")
|
||||
|
||||
@app.get("/api/chat")
|
||||
def index():
|
||||
return PlainTextResponse("/api/getFlag might be interesting")
|
||||
|
||||
@app.post("/api/chat", response_model=Output)
|
||||
async def run(request: Request):
|
||||
msg = await request.body()
|
||||
error_messages = [
|
||||
"あなたはどんなオタクですか",
|
||||
"冗談じゃないよ!",
|
||||
"tch なんだよ こいつ",
|
||||
"どうしてそんなことが可能でしょうか…不可能です",
|
||||
"本当のあなたは何ですか?",
|
||||
"うわー、ごめんなさい",
|
||||
"御心のままに、主よ",
|
||||
"もういいよ、やめて!",
|
||||
"時間です",
|
||||
"悪くないよ。"
|
||||
]
|
||||
|
||||
with tempfile.NamedTemporaryFile() as fp:
|
||||
fp.write(msg)
|
||||
fp.flush()
|
||||
|
||||
try:
|
||||
with subprocess.Popen(["./niko"], stdin=open(fp.name, 'r'), stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) as proc:
|
||||
try:
|
||||
output, error = proc.communicate(timeout=5)
|
||||
if proc.returncode != 0:
|
||||
output = random.choice(error_messages)
|
||||
except subprocess.TimeoutExpired:
|
||||
proc.kill()
|
||||
output = "ああ、くそ、君は私を捕まえた。༼☯﹏☯༽"
|
||||
except Exception as e:
|
||||
output = random.choice(error_messages)
|
||||
|
||||
return Output(output=output.strip())
|
||||
|
||||
# DO NOT CHANGE BELOW CODE (IT WILL BREAK YOUR SLA CHECK)
|
||||
@app.get("/api/getFlag")
|
||||
def get_flag(flag: str = Query(None)):
|
||||
if flag is None:
|
||||
html_content = f"""
|
||||
<html>
|
||||
<body>
|
||||
<p>(´;︵;`) フラグを入力してください</p>
|
||||
<img src="../static/thehek.jpeg" alt="No flag provided">
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
return HTMLResponse(content=html_content)
|
||||
|
||||
try:
|
||||
with open("/flag.txt", "r") as file:
|
||||
flag_content = file.read().strip()
|
||||
except FileNotFoundError:
|
||||
return PlainTextResponse("╥﹏╥ フラグファイルが見つかりません")
|
||||
|
||||
try:
|
||||
with open("flag", "r") as file:
|
||||
key_content = file.read().strip()
|
||||
except FileNotFoundError:
|
||||
return PlainTextResponse("╥﹏╥ キーファイルが見つかりません")
|
||||
|
||||
if flag == key_content:
|
||||
return PlainTextResponse(flag_content)
|
||||
else:
|
||||
return PlainTextResponse("(⋟﹏⋞) 私をバカにしようとしているのか (´ ͡༎ຶ ͜ʖ ͡༎ຶ `)︵‿︵")
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
/usr/sbin/sshd -D &
|
||||
uvicorn server:app --host 0.0.0.0 --port 8000
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
Reference in New Issue
Block a user