1.
소스코드 올려주면 로컬에서 돌려보면서 라이트업을 쓰려고 했는데 운영진들이 약속된 시간이 지나도 올려주지 않길래 그냥 기억을 되살려 가면서 쓰기로 했다. 항상 대회할 때는 스크린샷을 저장할 정신이 없는데 남들은 그럴 시간이 있는 건지 모르겠다. 2주 전에 한 CTF기도 하고, 그냥 기록하는 용도로 쓰는 라이트업이 될 것 같다. CTF 자체는 초보자에게 매우 적합한 난이도였다. 한 90%쯤 풀고 팀원들이랑 같이 해서 푼 문제가 많았던 것 같다. 그만큼 아쉽게 플래그를 못 딴 문제가 많기도 했다…
2. THE CHALLS
- hypermaze - web
- swapping heads - web
- that one rsa - crypto
hypermaze - web
시작하고 바로 퍼블냈다.
스크린샷은 없지만, 들어가면 어지러울 정도로 난잡한 페이지가 나온다. 페이지 소스 들어가서 내리다보면 두번째 페이지로 이어진다. 한 다섯번 누르다보면 이 짓을 100페이지까지 하면 플래그가 나오겠구나 생각이 든다. 그러면 페이지 소스에서 다음 페이지로 이어지는 부분을 가져와서 컴퓨터가 대신 접속하게 하면 된다.
import requests
addr = 'https://hyper-maze.tuctf.com/pages/page_sheepfacedly94.html'
r = requests.get(addr)
for i in range(93):
addr = 'https://hyper-maze.tuctf.com/pages/'
next = "page_"+ r.text.split("page_")[1].split("\">")[0]
r = requests.get(addr+next)
print(next)
print(r)
swapping heads - web
웹사이트에는 특정 조건이 걸려있다.
- date를 정오와 자정 중 사이로 세팅해야 한다. “Date” 헤더를 조정하면 된다.
- 2009 3월 기준의 브라우저가 필요한데, 그건 IE 8이다.
- 문제에 나와있는 도메인과 똑같은 오리진의 이메일이 필요하다.
이 조건에 맞게끔 curl request를 작성해주면 다음과 같다.
curl -H "Date: Sat, 07 Mar 2009 20:22:21 GMT" -H "user-agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)" -H "From: user@swapping-heads.tuctf.com" https://swapping-heads.tuctf.com
That one rsa - crypto
이것도 퍼블이었던 걸로 기억한다. 기본적인 rsa 문제가 주어진다. n, e, c가 주어지고, e는 5이다. e가 작은 숫자이므로, Low Exponent Attack을 할 수 있다. picoCTF에서 비슷한 문제를 4달 전에 풀었기 때문에 푼 문제다. 그니까 경험에서 유래한 직감으로 푼 문제고, RSA에서 Low Exponent Attack에 대한 in-depth 이해를 쌓지는 않았다. gmpy.iroot 함수가 다 해준다.
t를 브루트포싱할 수 있고, 그렇기 때문에 M도 찾을 수 있다.
import gmpy2
n = 5298438288332178426768877317375400490227544340282664384289229779109493175252168113756709952888154006528729202728248982466140436254725968162207657962148952523086968640945348022966610395393965128483656442403510410041943367052376194992737466903957956931660236261552831008315227449477655663694875215019298592169200418810276784144383015495556951112436257147066711001463
e = 5
c = 734276875829282616322751997649418630245638671226703184601977056004438931141828631476968512345058534354899333924237859187064958807399796961910211805995351688832296480125056457430992509192050007013547895209643129634137270364389724403495545598124146218685414217638191115020362097919741254624849060416592305152438528539596745151532302276997019695236094644399512192261
t = 1
while True:
M, is_true_root = gmpy2.iroot(t*n + c, e)
if is_true_root:
print(f"Found t = {t}")
print(f"M = {M}")
break
t += 1
#Found t = 13862328
#M = 149003617072514967705362966617328574884671140357033588603732115961358085245
print(bytes.fromhex(hex(M)[2:]).decode('utf-8'))