$ Capture The Flag $

zer0pts CTF 2020 write up

ws1004 2020. 3. 12. 23:50

Forensics

 

Locked KitKat

 

 

첨부파일은 안드로이드 디바이스의 내부 디스크 이미지 파일이고, 잠금해제 패턴을 찾아서 패턴입력을 하면 Clear가 되는 문제입니다.

 

해당 문제를 풀기 위해서 잠금해제 패턴과 관련되어 있는 파일을 찾아야 하는데 경로는 아래와 같습니다.

해당 파일 경로 : /system/gesture.key

 

해당 경로에 가서 해당 파일을 확인해보면 존재합니다.

 

이번에는 gesture.key 파일에서 패턴을 추출해주는 툴을 찾아보겠습니다.

↑ 경로 :  https://github.com/sch3m4/androidpatternlock

 

아래의 방법을 따라 진행을 해보면 패턴을 발견 할 수 있습니다.

 

 

http://13.230.161.88:10001/ 사이트에서 패턴을 입력해 보면 아래와 같이 Flag를 획득 할 수 있습니다.

 

 

Flag는 아래와 같습니다.

 

 

Flag : zer0pts{n0th1ng_1s_m0r3_pr4ct1c4l_th4n_brut3_f0rc1ng}

 

 

Web

 

Can you guess it?

 

 

해당 사이트에 들어가 보면 아래와 같이 값을 제출하는 화면을 확인 할 수 있고, Source를 확인 해 볼 수 있습니다.

 

Source 코드를 확인해보면 해당 문제에 있었던 첨부파일과 일치 합니다.

Source Code는 첨부된 파일로 다뤄보겠습니다.

 

먼저 해당 코드를 보면 config.php 에 flag가 있다는 것을 이야기 하는것 같습니다.

그리고 $_SERVER['PHP_SELF'] 를 확인 할 수 있습니다.

해당 코드를 이용해서 PHP_SELF 를 우회 할 수 있습니다.

아래와 같은 예시를 확인해 볼 수 있습니다.

 

basename 함수는 Path의 맨마지막 파일 이름을 추출하는 함수입니다.

이를 이용해서 index.php -> config.php 로 인식을 하도록 하면 될거 같습니다.

 

하지만 아래의 코드에서 preg_match 를 이용해서 정규표현식으로 $_SERVER['PHP_SELF'] 를 필터링 합니다.

 

정규 표현식에 의해서 config.php 이후에 /특정값을 추가로 적어줘야 합니다.

하지만 basename 함수 뒤에 붙는 \x80~\xff 인 아스키코드 값 부분이 아닌 영역의 문자열은 무시하게 됩니다.

 

그렇기 때문에 아래와 같이 입력을 하면 Flag를 확인 할 수 있습니다.

 

Flag : zer0pts{gu3ss1ng_r4nd0m_by73s_1s_un1n73nd3d_s0lu710n}

 

 

notepad

 

 

해당 문제는 Flask 로 만들어진 게시판 형식을 띄고 있습니다.

 

주어진 첨부 파일에 들어 있는 코드인 app.py를 확인해 보면 flask.render_tamplate_string(html) 이 눈에 먼저 보입니다.

 

해당 함수는 Flask SSTI(Server Side Template Injection) 를 발생 시키는 함수로 해당 함수를 가지고 SECRET_KEY를 뽑아 낼 수 있습니다.

flask.render_tamplate_string 함수의 매개변수는 referer로 받기 때문에 아래와 같이 예를 들어서 입력을 하면 다음과 같은 결과를 확인 할 수 있습니다.

또한 404 페이지에 접근할 때 해당 값이 확인 할 수 있습니다.

 

실제로 curl 를 이용해서 Header 값을 조작 해 보면 아래와 같습니다.

 

그렇기 때문에 SECRET_KEY를 얻기 위해서 {{config}}를 입력하면 KEY 값을 확인 할 수 있습니다.

 

이것도 curl을 이용해서 Header를 조작해 보면 아래와 같습니다.

 

위의 값을 가지고 이제 SESSION 값을 자유롭게 조작이 가능합니다.

 

첨부 파일 인 app.py를 보면 load함수에서 RCE가 가능한것을 확인할 수 있습니다.

 

flask.session을 이용해서 savedata를 얻어서 해당 값을 base64 디코드 후에 loads함수로 데이터를 읽어오는 것을 확인 할 수 있습니다.

이 과정에서 session 값을 조작하여 데이터를 삽입하면 RCE가 가능합니다.

 

위의 과정이 pickle unserialize 되는 곳이기 때문에 flask.sessions.SecureCookieSessionInterface 하위에 있는 함수인 get_signing_serializer 함수를 이용해서 데이터를 넘겨 줘야 합니다.

 

그렇기 때문에 해당 문제는 Flask SSTI 취약점pickle unserialize 취약점이 있는 것 을 알 수 있습니다.

 

pickle serialize 를 할때 넘겨 주는 데이터는 전부 pickle byte 형식으로 넘어가게 됩니다.

이점을 유의 해서 Flag를 획득 하는 RCE 코드를 작성해 보면 아래와 같습니다.

 

주요 코드는 12번 줄에 선언 되어 있는 serializer 함수 입니다.

secret_key에 값을 넣은뒤 get_signing_serializer 를 진행 하는 코드입니다.

 

20~23번 줄은 그냥 secret_key를 가져오는 코드!

 

25번 줄에 들어가 있는 값은 아마도 위의 코드중 가장 중요한 서버에 flag파일을 열어서 읽어오는 코드 입니다.

앞서 이야기 한것 처럼 pickle byte 형식으로 데이터를 넘겨야 하기 때문에 b"c__builtin__\neval\n(S'open('flag').read()'\ntR" 이렇게 코드를 넣어야 합니다.

 

위의 코드를 이해하기 위해서 아래의 사진을 확인하면 될것 같습니다.

 

코드 중에서 __builtin__은 내장함수를 읽어오는 모듈입니다.

 

26번 줄에 savedata로 넣은 바이트화 된 문자열은 [{"date":0, "text":"", "title":주요코드}] 를 의미 합니다.

[{"date":0, "text":"", "title":주요코드}] 를 위와 같이 변환을 하려면 다음과 같은 코드를 입력하면 됩니다.

 

g3\n 부분에 주요 코드를 넣은 코드가 전체 코드입니다.

text, data, title의 순서가 다른 부분은 data 변수에 넣은 데이터의 순서 차이로 발생한 것입니다.

 

중요한 데이터에 대한 설명은 이정도로 하고 위의 코드를 실행해 보면 flag를 찾을 수 있는 것을 알 수 있습니다.

 

Flag : zer0pts{fl4sk_s3ss10n_4nd_pyth0n_RCE}

 

 

urlapp

 

 

먼저 첨부된 파일을 확인해 보면 ruby로 작성된 파일이 눈에 가장 많이 띄는 것같습니다.

 

핵심 소스코드로 보이는 파일인 app.rb 파일을 확인해 보면 아래와 같습니다.

 

먼저 눈에 띄는 것은 sock = TCPSocket.open("redis", 6379) 코드 입니다. redis 문자열이 눈에 잘 띄어서 관련된 취약점을 찾아보았습니다.

 

redis ssrf 라는 취약점이 있는것을 알았습니다.

 

SSRF 란?

Server-Side Request Forgery 의 약자로 Request를 변조 해서 공격자가 의도한 대로 요청을 가게 하거나 요청 자체를 변경하는 공격입니다.

 

또한 redis 관련 함수가 있다는 것을 알게 되었고 eval를 이용해서 해당 함수를 사용할수 있다는 것을 알게되었습니다.

그래서 eval 와 같이 사용할 수 있는 redis.call() 을 사용해 보려고 합니다.

[위의 사진에서 eval 함수 부분은 줄바꿈을 한것이 아닙니다.]

 

위와 같이 redis.call 을 이용해서 0d7348897a00b310 이라는 키값에 이어서 오는 redis.call('get','flag')로 인해서 flag값을 담게 됩니다.

 

그리고 GET 방식 으로 /?q=0d7348897a00b310 를 진행해 보면 아래와 같이 Response 가 날라오게 됩니다.

 

위의 Response 데이터에서 Flag를 확인 할 수 있습니다.

 

Flag : zer0pts{sh0rt_t0_10ng_10ng_t0_sh0rt}