본문 바로가기

웹/CTF study & write up

ctf sutdy #2

ctf 웹 문제를 분석하거나 풀어보면서 공부하는 스터디 글입니다.

 

1. ctf 문제

2021년 tetctf의 Super calc를 분석했습니다. 

라업은 아래의 두 라업을 참고했습니다.

ando.gq/tetctf-super-calc-1a0dd8dc7a5b48af9c657698d1698935

 

tetctf: super calc

Super Calc was a Web challenge featured in TetCTF, a 2 day CTF run from the 1st to the 3rd of January, 2021. The challenge description was as follows:

ando.gq

github.com/hrca-writeups/CTF-Writeups/blob/master/2021/TetCTF%202021/Super%20Calc.md

 

hrca-writeups/CTF-Writeups

CTF-Writeups. Contribute to hrca-writeups/CTF-Writeups development by creating an account on GitHub.

github.com

2. 문제에 사용된 취약점 목록

 이 문제의 취약점은 preg_match 함수로 필터링된 문자들을 어떻게 우회하는 방법입니다. 즉 LOS에서 푼 문제들처럼 필터링에 의해 단순한 공격이 막혀있고, 이 부분을 우회하여 푸는 문제입니다. 그리고 eval 함수의 취약점도 이용합니다.

 

eval 함수의 취약점은 아래의 링크에 eval 함수의 설명과 함께 아주 자세히 설명되어 있습니다.

velog.io/@modolee/javascript-eval-is-evil

 

JavaScript - eval 함수란 무엇이고, 왜 사용하지 말라고 하는가? (eval() is evil)

JavaScript의 eval 함수가 무엇이고, 왜 사용하지 말라고 하는지에 대한 정리해 보았습니다.

velog.io

3. 분석

<!-- Enjoy Tsu's Super Calculator <3, Not Only + - * / but also many other operators <3 <3 <3 -->

<?php

ini_set("display_errors", 0);

if(!isset($_GET["calc"])) 
{
    show_source(__FILE__);
}
else
{
    $wl = preg_match('/^[0-9\+\-\*\/\(\)\'\.\~\^\|\&]+$/i', $_GET["calc"]);
    if($wl === 0 || strlen($_GET["calc"]) > 70) {
        die("Tired of calculating? Lets <a href='https://www.youtube.com/watch?v=wDe_aCyf4aE' target=_blank >relax</a> <3");
    }
    echo 'Result: ';
    eval("echo ".eval("return ".$_GET["calc"].";").";");
}

라업에 나와있는 소스코드의 일부분입니다. wl의 값을 get방식으로 전달된 calc의 값에서 필터링된 값을 저장하는 구조입니다. 이 부분은 웹을 어느 정도 공부를 했다면 쉽게 이해가 가능할 것이라고 생각합니다. 그리고 특징은 calc의 길이가 70이하여야 한다는 점입니다.

 

먼저 눈에 띄는 부분은 eval함수를 사용했다는 것입니다. 이 함수는 간단히 말해서 인자로 받은 문자열을 코드로 인식해서 해당 코드를 실행시킨 결과를 출력해주는 함수입니다. 예를 들어 eval('2+2'); 일 경우 단순 출력함수 라면 화면에 2+2를 출력해야 합니다. 하지만 eval함수로 화면에 출력할 경우 2+2의 연산 결과값인 4가 화면에 출력되게 됩니다. 즉 calc에 어떤 정보를 보내는지에 따라서 결과가 달라지고 즉 이 부분이 취약점이 되어 공격에 사용될 확률이 높다는 점입니다. 다른 말로는 우리가 원하는 코드를 서버 단에서 실행할 수 있다는 말과 같기 때문에 실제로 코딩에서는 사용하면 매우 심각한 취약점을 발생하는 함수입니다.

 

그리고 라업을 보면서 이 문제의 핵심은 단순히 eval 함수의 취약점을 이용하는 것이 아니라 필터링된 문자들을 어떻게 우회할 것인지 였습니다. 필터링되는 문자들을 보면 싱글쿼터('), &, ^, 0~9, 사칙연산 등의 문자가 있는지 확인하고, wl의 값이 0일 경우, 즉 이 문자들이 포함되지 않는다면 바로 die를 통해 죽게 되어 있습니다. 그렇기 때문에 소스코드에 보이는 문자만 사용이 가능한 것으로 이해하면 됩니다.

 

분석 내용을 정리하면

 

1. 길이는 70자 이하여야 한다.

2. calc는 0~9, +, -, *. /, (, ), ', ., ~, ^, |, &로만 이루어져야 한다.

 

그리고 제가 이 문제를 직접 풀어본 것은 아니기 때문에 이 부분은 라업에 의한 내용 입니다.

3. 이 문제의 플래그는 소스 코드와 같은 디렉토리인  fl4g1sH3re.php이다. 그렇기 때문에 1=system('cat fl4g1sH3re.php'); 라는 코드를 실행하여 서버에 있는 플래그 파일을 읽어와야 한다.

 

3번 문제같은 경우에는 저 파일 이전에 1=system(ls); 를 통하여 쉘을 따고 현재 디렉토리에 존재하는 파일을 확인한 것 같습니다.

 

이렇게 분석을 마친 뒤 이제부터 해야할 점은 어떻게 허용 가능한 문자들로 system함수와 그 인자를 가지는 페이로드를 작성할 것인가 입니다.

 

두 라업 모두 xor연산을 이용했습니다.

예를 들어

더보기

'G' ^ '0' = 'w' (not whitelisted)

'G' ^ '1' = 'v' (not whitelisted) ...

'G' ^ '8' = 127 (not valid ASCII character)

'G' ^ '9' = '~' (whitelisted, success!)

이런 식의 연산을 통해 두 문자의 xor 연산을 통해 새로운 문자를 만들어내는 방식입니다. 

여기서 a ^ b = c의 연산을 b ^ c = a의 연산으로 변환이 가능하기 때문에 위에서 만들어낸 연산인 필터링 되지 않는 ~, 9의 문자로 알파벳 G를 만들어 낼 수 있는 것입니다. 이 문제에서는 이 연산이 핵심으로 사용되었습니다.

 

4. 전체 익스코드 분석

chars = '0123456789+-*/().~^|&'
search = ")"
print("character ", search)

for c in chars:
	x = chr(ord(c)^ord(search))
	print(c, "=>" x)

익스 코든는 두 번째 라업의 익스코드가 조금 더 간단하다고 생각하여 가져왔습니다. 분석에서 설명한 내용으로 필요한 페이로드인 1=system('cat fl4g1sH3re.php'); 를 허용된 문자들로 만드는 코드입니다. 여기서 만약 70글자가 넘어갈 경우에 대해서는 첫 번째 라업에서 설명이 잘 되어 있습니다.

 

만약 단순히 $_GET[]을 허용 가능한 문자로 만들면 ('&'^('('^'*')).('8'^('9'^'^')).('9'^'~').('9'^'|').('~'^'*').(('('^'-')^'^').('^'^('('^'+')) 으로 90글자가 되어 70자가 넘어가버립니다. 이때, xor연산의 결합법칙을 이용해서 연산 길이를 줄인 것 같습니다. 그렇게 해서 코드를 줄이면

'(9222(('^'*^^^^-+'^'&8+)8^^'로 감소합니다. 이 방식을 이용해서 페이로드의 길이를 줄여서 사용했습니다. 

 

이러한 방법으로 필요한 페이로드인 1=system('cat fl4g1sH3re.php'); 를 제작하여 calc의 값으로 전달하게 되면 서버 단에 저장되어 있는 플래그 파일을 읽어 올 수 있습니다.

 

5. 리뷰

이 문제는 어떻게 보면 그냥 필터링을 우회해서 시스템 단의 쉘을 획득하여 플래그를 읽어오는 간단한 구조의 문제처럼 보일지 모릅니다. 하지만 사용가능한 문제가 굉장히 극단적으로 제한되어 있으며, 이 문자들을 이용해 페이로드를 작성해야 하는 부분이 굉장히 흥미로웠습니다.  그리고 이 문제에서 사용한 xor 연산을 이용하여 새로운 문자를 만드는 방법도 처음 알게 되어 새로운 공격 방법을 공부할 수 있었습니다.(물론 이 부분은 eval 함수의 특징 때문에 가능한 것 같긴합니다.) 그래서 문제 구조는 단순할지 모르지만 페이로드를 만드는 과정에서 꽤나 어려움을 겪을 수 있고, 만약 저처럼 xor연산을 통해 새로운 문자를 만드는 방법을 모르고 있던 사람이 이 문제를 처음 접하게 되면 페이로드 작성 방법에 대하여 생각하다가 막힐 것이라고 생각합니다. 하지만 이 부분은 xor 연산의 활용에 대해서 알고 있는 사람이라면 쉽게 풀릴 수도 있는 문제이기 때문에 꽤 극단적인 문제라고 생각합니다. 그래서 저는 이 문제의 점수를 5.5점으로 주고 싶습니다. 왜냐하면 이 문제는 이 문제와 비슷한 문제를 풀어보지 못한 사람에게는 페이로드 작성 과정과 문제 분석 과정이 꽤나 어려운 과정이라고 생각하지만, 알고 있던 사람들에게는 굉장히 접근이 쉬운 문제라고 생각하기 때문입니다.

' > CTF study & write up' 카테고리의 다른 글

ctf study #6  (0) 2021.02.24
ctf study #5  (0) 2021.02.17
ctf study #4  (0) 2021.02.15
ctf study #3  (0) 2021.02.11
ctf sutdy #1  (0) 2021.02.03