-
[Clear] LIT CTF 2021 web/LIT BUGS WriteupCTF/LIT CTF 2021 2021. 7. 20. 18:46
주어진 페이지에 가보면 대회 페이지와 유사한 페이지가 나타난다. 다른 기능들은 막혀있고, 회원 가입 및 로그인 기능만 살아있다. 문제에서 언급되어있듯이, 가입되어있는 팀 이름이 플래그라고 한다.
주어진 소스의 일부이다. 핵심 기능인 로그인 부분을 분석해보자. 특이한점은 소켓 통신을 하고 있다는 점이다.
io.on('connection',(socket) => { socket.on('login',(tn,pwd) => { if(accounts[tn] == undefined || accounts[tn]["password"] != md5(pwd)) { socket.emit("loginRes",false,-3); ##### ............................. (1) return; } socket.emit("loginRes",true,accounts[tn]["rand_id"]); ##### ................. (2) return; }); socket.on('reqName',(rand_id) => { name = id2Name[parseInt(rand_id)]; socket.emit("reqNameRes",name); ##### ....................................... (3) }); ... 중략(register) });
우선, 계정 정보를 맞추어 로그인 시도를 하여 (1)의 조건을 만족하면 (2) 로직이 수행된다.
정상적인 통신 시 (1)~(3) 까지의 로그인 과정이 실제로 어떻게 수행되는지 프록시 툴을 사용하여 확인하면 아래와 같다.
(1) 로그인 시도 (1) 조건 만족 시 (2) 통신 수행 (2) 로직 수행 후 (3) 로직 실행 최종적으로는 (3)의 요청에 대해 아래와 같은 응답이 옴으로써 팀 이름을 확인 할 수 있다.
(1), (2), (3) 각각의 과정이 socket.io / socket.emit 으로 각각 수행되기 때문에, 아무 계정으로 로그인을 시도하여 (1)의 조건을 만족시키고, (1)과 (2) 사이 혹은 (2)와 (3) 사이에 rand_id 를 변조하면 타 계정으로 로그인이 될 것이라고 생각했고, 실제로 두 개의 계정을 통해서 테스트 한 결과 실제로 타 계정으로 로그인하는데 성공했다.
플래그인 기생성되어있는 계정은 아래 로직으로 생성되기 때문에, rand_id가 0~1000 범위안의 임의의 값임을 확인 할 수 있다.
const flag = fs.readFileSync("flag.txt",{encoding:'utf8', flag:'r'}); var accounts = {}; // Special account for LIT Organizers var admin_id = Math.floor(Math.random() * 1000) accounts[flag] = { "password": md5(flag), "rand_id": admin_id };
소켓 통신이기 때문에 패킷 재사용이 불가하기 때문에 brute force를 자동화하기엔 번거롭다고 생각했고,
버프 스위트의 Match and Replace 기능을 통해 아래와 같이 수동으로 brute force 공격을 수행함으로써 플래그를 획득 할 수 있었다.
FLAG = flag{if_y0u_d1d_not_brut3force_ids_plea5e_c0ntact_codetiger}
반응형'CTF > LIT CTF 2021' 카테고리의 다른 글
[Clear] LIT CTF 2021 web/A Flask of Pickles Writeup (0) 2021.07.21