Profile

i love cat

as3617

TokyoWesterns CTF 2020 Web Writeup

오늘 TokyoWesterns CTF 2020이 끝났다.
1인팀으로 참여해서 웹만 풀었는데 많이 못 풀었다.

urlcheck1 - 98 points

app.re_ip = re.compile('\A(\d+)\.(\d+)\.(\d+)\.(\d+)\Z')

def valid_ip(ip):
    matches = app.re_ip.match(ip)
    if matches == None:
        return False

    ip = list(map(int, matches.groups()))
    if any(i > 255 for i in ip) == True:
        return False
    # Stay out of my private!
    if ip[0] in [0, 10, 127] \
        or (ip[0] == 172 and (ip[1] > 15 or ip[1] < 32)) \
        or (ip[0] == 169 and ip[1] == 254) \
        or (ip[0] == 192 and ip[1] == 168):
        return False
    return True

def get(url, recursive_count=0):
    r = requests.get(url, allow_redirects=False)
    if 'location' in r.headers:
        if recursive_count > 2:
            return '&#x1f914;'
        url = r.headers.get('location')
        if valid_ip(urlparse(url).netloc) == False:
            return '&#x1f914;'
        return get(url, recursive_count + 1) 
    return r.text

@app.route('/admin-status')
def admin_status():
    if flask.request.remote_addr != '127.0.0.1':
        return '&#x1f97a;'
    return app.flag

코드를 주고 있는데 중요한 부분은 위와 같다.
간단하게 로직을 우회하여 /admin-status에 접근하는 것이 가능하다.
exploit : http://0177.0.0.1/admin-status

FLAG: TWCTF{4r3_y0u_r34dy?n3x7_57463_15_r34l_55rf!}

Urlcheck v2 - 128 points

Urlcheck v2 문제다.

def valid_ip(ip):
    try:
        result = ipaddress.ip_address(ip)
        # Stay out of my private!
        return result.is_global
    except:
        return False

def valid_fqdn(fqdn):
    return valid_ip(socket.gethostbyname(fqdn))

코드를 주고 있는데 필터링 로직이 위의 코드로 변경되었다.
달라진 점은 도메인을 받은 뒤 ipaddress 모듈을 이용하여 dns resolves를 수행하기 때문에 위에서 사용한 방식으로는 공격하기가 힘들다.

따라서 DNS rebinding을 이용하여 공격을 진행하면 된다.

이런 식으로 도메인에다가 DNS 연결을 내 서버로 한다.

그 다음에 바로 내서버에서 127.0.0.1로 DNS 연결을 바꾼 다음에 어느 정도 DNS 캐시가 남아있기 때문에 계속 url을 넘겨주다보면
어느 순간 플래그를 얻을 수 있다.

내 생각에는 이 방식이 한 도메인에 DNS 연결을 2개 하는 것보다 더 빠르고 확실하게 플래그를 얻을 수 있는 것 같다.

FLAG : TWCTF{17_15_h4rd_70_55rf_m17164710n_47_4pp_l4y3r:(}

Angular of the Universe - (139,149) points

이 문제도 소스코드를 주고 있는데 한 문제 안에 2개의 플래그가 있다고 한다.

맨 처음에는 서버에다가 환경을 세팅한 뒤에 풀이를 진행하려고 했지만 빌드 도중에 계속 오류가 발생해서
그냥 코드 분석만 하고 그것을 토대로 풀이를 진행했다.

  location /debug {
    # IP address restriction.
    # TODO: add allowed IP addresses here
    allow 127.0.0.1;
    deny all;
  }

nginx 설정은 위와 같다. 내부에서만 /debug/* 에 접근할 수 있고 그외의 /debug/*로의 요청은 서버에서 차단한다.

    if (process.env.FLAG && req.path.includes('debug')) {
      return res.status(500).send('debug page is disabled in production env')
    }

메인 코드를 확인해보면 request path에 debug라는 문자열이 들어있으면 500을 출력한다고 한다.

이것은 간단하게 우회하는 것이 가능한데
http://~~~/\debug 와 같이 요청하게 되면 nginx는 /\debug라는 디렉토리로 요청했다고 인식한 뒤
http://app 뒤에 path를 붙여서 서버로 넘겨주게 된다.

그러면 http://app/\debug 로 서버로 넘겨주고 angular.js는 \를 /로 인식하기 때문에
최종적으로는 http://app//debug로 요청하게 된다.
이를 이용하여 http://app/\debug/answer로 요청하면 플래그를 얻을 수 있을 것이다.
하지만 요청 path에 debug라는 문자열이 있기 때문에 500 page가 뜨는 것을 확인할 수 있다.
이것도 간단하게 urlencoding을 이용하여 e를 %65로 바꿔서 요청을 날리면 된다.

FLAG1 :TWCTF{ky0-wa-dare-n0-donna-yume-ni?kurukuru-mewkledreamy!}

2번째 플래그를 얻으려면
/api/true-answer로 요청을 보내야한다.

우리가 봐야할 부분은

location / {
    proxy_pass http://app;
    proxy_set_header Host $host;
  }

이 부분이다. 여기서 보면 우리가 요청할 때 보낸 Host를 그대로 백엔드로 넘겨줄 때 사용하는 것을 알 수 있다.

 getAnswer() {
    return this.http.get('/api/answer')
  }

angular.js에서 이런식으로 http 요청을 보내고 있는데 이때 angular.js는 host를 사용하여 요청을 보낸다.
그럼 우리가 host를 조작하여 외부로의 요청을 만들고 redirection을 이용하여 내부서버로 접근하게 한다면 플래그를 얻을 수 있을 것이다.

옛날에 이 글을 읽었던 기억이 나서 문제푸는 것에 사용했다. -> https://www.hahwul.com/2019/02/22/bypass-ssrf-protection-using-http-redirect/

 

FLAG2 : TWCTF{you-have-to-eat-tomato-yume-chan!}

Angular of another Universe - 239 points (not solve....)

이 문제는 대회 중에는 못 풀었고 대회가 끝난 뒤에 풀었다.

https://github.com/angular/angular/blob/1801d0c6500ea5e677e753fbcfb73dbd3675f054/packages/router/src/url_tree.ts#L586
이 부분을 보면 풀 수 있었다고 한다.

http://aaa/(outlet_name:c/d) 이런식으로 요청을 보낼 수 있다고 한다.
여기서 outlet_name은 angular 문서에 따르면 설정이 따로 되있지 않는다면 기본값은 primary로 설정되있다고 한다.

따라서 http://another-universe.chal.ctf.westerns.tokyo/(primary:debug/answer)로 요청을 하면
내부에선 /debug/answer로 요청한 것으로 해석하고 FLAG를 얻을 수 있다고 한다.

FLAG : TWCTF{theremightbeanotheranotheranotherissuesinuniverse}

'web hacking' 카테고리의 다른 글

DarkCON CTF web Writeup - DarkCON Challs  (0) 2021.02.21
SQL Injection 정리  (0) 2020.11.08
TokyoWesterns CTF 2020 Web Writeup  (0) 2020.09.21
Python Pickle Deserialization Vulnerability (Python pickle 취약점)  (0) 2020.04.22
los rubiya allclear  (0) 2020.02.29
los rubiya 1일차  (0) 2019.12.17