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 '🤔'
url = r.headers.get('location')
if valid_ip(urlparse(url).netloc) == False:
return '🤔'
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 '🥺'
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))
코드를 주고 있는데 필터링 로직이 위의 코드로 변경되었다.
달라진 점은 도메인을 받은 뒤 socket 모듈을 이용하여 dns resolves를 수행하기 때문에 위에서 사용한 방식으로는 공격하기가 힘들다.
따라서 DNS rebinding을 이용하여 공격을 진행하면 된다.
이런 식으로 도메인에다가 DNS 연결을 내 서버로 한다.
그 다음에 바로 내서버에서 127.0.0.1로 DNS 연결을 바꾼 다음에 어느 정도 DNS 캐시가 남아있기 때문에 계속 url을 넘겨주다보면
어느 순간 플래그를 얻을 수 있다.
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 |
PHP object injection (0) | 2020.08.13 |
Python Pickle Deserialization Vulnerability (Python pickle 취약점) (0) | 2020.04.22 |
디미고 benedu 취약점 (0) | 2020.03.06 |