이 문제의 파일을 열어보면 각각 ‘index.php’, ‘flag.php’, check.php’ 이렇게 세 개의 php파일이 있는데, 해결하기 위해서는 ‘check.php’ 파일만 보면 된다.
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<title>Type c-j</title>
</head>
<body>
<!-- Fixed navbar -->
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="/">Type c-j</a>
</div>
<div id="navbar">
<ul class="nav navbar-nav">
<li><a href="/">Index page</a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</nav><br/><br/><br/>
<div class="container">
<?php
function getRandStr($length = 10) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[mt_rand(0, $charactersLength - 1)];
}
return $randomString;
}
require_once('flag.php');
error_reporting(0);
$id = getRandStr();
$pw = sha1("1");
// POST request
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$input_id = $_POST["input1"] ? $_POST["input1"] : "";
$input_pw = $_POST["input2"] ? $_POST["input2"] : "";
sleep(1);
if((int)$0e123456 == $id && strlen($input_id) === 10){
echo '<h4>ID pass.</h4><br>';
if((int)$356a192b7913b00000000 == $pw && strlen($input_pw) === 8){
echo "<pre>FLAG\n";
echo $flag;
echo "</pre>";
}
} else{
echo '<h4>Try again.</h4><br>';
}
}else {
echo '<h3>Fail...</h3>';
}
?>
</div>
</body>
</html>
위 코드는 ‘check.php’의 코드이다.
위 사진은 사이트의 모습이다
id와 password에 문자열을 넣고 제출을 누르면
require_once('flag.php');
error_reporting(0);
$id = getRandStr();
$pw = sha1("1");
// POST request
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$input_id = $_POST["input1"] ? $_POST["input1"] : "";
$input_pw = $_POST["input2"] ? $_POST["input2"] : "";
sleep(1);
if((int)$input_id == $id && strlen($input_id) === 10){
echo '<h4>ID pass.</h4><br>';
if((int)$input_pw == $pw && strlen($input_pw) === 8){
echo "<pre>FLAG\n";
echo $flag;
echo "</pre>";
}
} else{
echo '<h4>Try again.</h4><br>';
}
}else {
echo '<h3>Fail...</h3>';
}
이 코드에 의해 문자열이 검증을 거치게 되는데, 우리가 입력한 아이디와 비밀번호는 각각 $input_id와 $input_pw에 삽입되어 $id와 $pw에 각각 일치하는지 검사하고
만약 둘다 일치한다면 ‘$flag’를 출력
만약 아이디만 일치한다면 ‘ID pass.’
만약 비밀번호만 일치한다면 ‘Try agin.’ 이렇게 출력하게끔 되어있다.
그렇다면 $id와 $pw이 무엇인지 알아야 우리가 어떤 문자열을 삽입 할 것인지 결정할 수 있을 것이다.
$id = getRandStr();
$pw = sha1("1");
위 코드는 $id와 $pw가 어떻게 정의 되었는지 보여주는 코드인데, $id → getRandStr(), $pw → sha(”1”)를 통해서 정의된다.
getRandStr()
function getRandStr($length = 10) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[mt_rand(0, $charactersLength - 1)];
}
return $randomString;
}
위 코드는 getRandStr()의 내용이다.
대충 $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';이 문자열 중 무작위로 골라서 문자열을 만드는 함수인 것 같다.
for문을 이용해서 문자열 길이를 줄여가며 무작위로 문자열을 만들어주는 함수인 것 같다.
sha("1")
이것은 ‘sha-1’ 해시로 바꾸는 방식을 이용하여 ‘1’을 ‘sha-1’해시로 바꾸는 함수이다.
그렇다면 이제 아이디와 비밀번호를 찾아보자.
이 문제서 아이디는 복잡해보이니 비밀번호부터 찾아보면
if((int)$input_pw == $pw && strlen($input_pw) === 8)
여기서 $pw는 sha(1)이므로 즉 1을 ‘sha-1’ 해시로 바꾼 값에서 앞 8자리인 것을 알 수 있다.
그렇다면 비밀번호는
import hashlib
# 문자열 "1"을 바이트로 변환하여 SHA-1 해시를 계산합니다.
text = "1"
hashed_text = hashlib.sha1(text.encode()).hexdigest()
# 결과를 출력합니다.
print("SHA-1 Hash of '1':", hashed_text)
위 파이썬 코드를 이용해 해시로 바꿔서 보면
SHA-1 Hash of '1': 356a192b7913b04c54574d18c28d46e6395428ab 이렇게 나오게 되고
즉 비밀번호는 356a192b 이다.
이제 아이디를 찾아보자.
if((int)$input_id == $id && strlen($input_id) === 10)
입력한 데이터가 int형으로 바뀌고, $id와 문자열을 대조해서 같고, 길이가 10개라면 pass되는 구조인 것 같다.
그런데 php의 취약점이 여기서 드러난다. 위 코드처럼 input받은 문자열을 int형으로 바꾸고 다른 문자열과 대조를 할 경우에, 매직 해시 취약점에 의해 이 문제 처럼 문제가 될 수 있는 것이다.
매직 해시 취약점이란?
- == 와 같이 비교적 약한 비교를 사용하거나 아이디를 먼저 불러오고, 그 후에 비밀번호 비교하도록 짜여져 있는 php 코드에 있는 취약점이다.
위 조건에 맞는 코드라는 전제에서 문자열을 int형으로 형변환을 할 경우, 앞자리에 숫자가 없으면 모두 0으로 바뀌기 때문에 ==로 비교하는 결과값이 ‘0’으로 문자열 크기만 맞추어도 참이 나오는 것이다.
그러면 다시 위의 코드로 돌아가 입력받은 문자열을 int형으로 형변환 하여 ==을 사용하여 $id와 비교하기 때문에 매직 해시 취약점으로 id에 ‘0’을 10개만 채워서 입력해도 참 값을 출력하게 하여 pass되게 된다.
이렇게 제출하게 되면………
플래그가 출력된다!!!!!!!!!
'DreamHack > Web hacking' 카테고리의 다른 글
[LEVEL-1] simple_sqli_chatgpt (1) | 2023.11.27 |
---|---|
[LEVEL-1] session-basic (0) | 2023.11.20 |
[LEVEL-1] [wargame.kr] strcmp (0) | 2023.11.09 |
[LEVEL-Beginner] session (2) | 2023.11.09 |
[LEVEL-1] baby-union (0) | 2023.11.09 |