- vừa được xem lúc

[Write-up] Hackthebox: Clicker. Nếu Server mở dịch vụ NFS thì có cách nào để khai thác không?

0 0 12

Người đăng: Phạm Hiếu

Theo Viblo Asia

OS Difficulty
Linux Medium

Giới thiệu

Clicker là 1 machine trên Hackthebox có độ khó ở mức Medium. Bài cho chúng ta biết cách thực hiện pentest như nào khi mà trên server có mở cổng 2049(NFS).

1. Recon

Sử dụng Nmap để kiểm tra dịch vụ chạy trên Server

┌──(kali㉿kali)-[~]
└─$ sudo nmap -sC -sV 10.10.11.232
[sudo] password for kali: Starting Nmap 7.92 ( https://nmap.org ) at 2024-01-03 03:51 EST
Nmap scan report for clicker.htb (10.10.11.232)
Host is up (0.091s latency).
Not shown: 996 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: | 256 89:d7:39:34:58:a0:ea:a1:db:c1:3d:14:ec:5d:5a:92 (ECDSA)
|_ 256 b4:da:8d:af:65:9c:bb:f0:71:d5:13:50:ed:d8:11:30 (ED25519)
80/tcp open http Apache httpd 2.4.52 ((Ubuntu))
|_http-title: Clicker - The Game
| http-cookie-flags: | /: | PHPSESSID: |_ httponly flag not set
|_http-server-header: Apache/2.4.52 (Ubuntu)
111/tcp open rpcbind 2-4 (RPC #100000)
| rpcinfo: | program version port/proto service
| 100000 2,3,4 111/tcp rpcbind
| 100000 2,3,4 111/udp rpcbind
| 100000 3,4 111/tcp6 rpcbind
| 100000 3,4 111/udp6 rpcbind
| 100003 3,4 2049/tcp nfs
| 100003 3,4 2049/tcp6 nfs
| 100005 1,2,3 41995/tcp6 mountd
| 100005 1,2,3 49388/udp mountd
| 100005 1,2,3 57925/udp6 mountd
| 100005 1,2,3 60761/tcp mountd
| 100021 1,3,4 35949/udp6 nlockmgr
| 100021 1,3,4 40341/tcp6 nlockmgr
| 100021 1,3,4 40645/tcp nlockmgr
| 100021 1,3,4 44662/udp nlockmgr
| 100024 1 32806/udp6 status
| 100024 1 48193/tcp6 status
| 100024 1 49263/udp status
| 100024 1 59853/tcp status
| 100227 3 2049/tcp nfs_acl
|_ 100227 3 2049/tcp6 nfs_acl
2049/tcp open nfs_acl 3 (RPC #100227)
|_http-title: Directory listing for /
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 19.31 seconds

Chúng ta được 4 cổng 22: SSH, 80: HTTP, 111: rcpbind, 2049: NFS

Thực hiện thêm dòng sau vào /etc/hosts

10.10.11.232 clicker.htb

2. Enum

Thực hiện kiểm tra ứng dụng Web

image.png

Thì nó là 1 game với số điểm bằng lượng click của người chơi

image.png

Sau khi kiểm tra thì chưa phát hiện được chỗ nào có thể khai thác được

Tiếp theo kiểm tra đến cổng 2049 thì nó là dịch vụ NFS giúp chia sẻ file lên các network

Sau khi google thì ta được kết quả tại đây. Nó có hướng dẫn cách pentest 1 ứng dụng chạy NFS

Mình sẽ thực hiện như sau:

Đầu tiên kiểm tra thư mục trên server có public để chúng ta mount được không

┌──(kali㉿kali)-[~]
└─$ showmount -e 10.10.11.232 Export list for 10.10.11.232:
/mnt/backups *

Chúng ta có thư mục /mnt/backups ở trên server có thể mount được

Mình tạo 1 thự mục ở đây là clicker

Thực hiện mount thư mục /mnt/backups lên thư mục ở trên máy mình là clicker

sudo mount -t nfs 10.10.11.232:/mnt/backups clicker/

Thực hiện xem trong thư mục t vừa mount thì có 1 file zip tên là clicker.htb_backup.zip .Thực hiện giải nén ta được Source Code của ứng dụng web của game clicker ở trên mình truy cập, các chức năng được thực hiện như sau:

  • admin.php: trang quản trị của admin(cần quyền admin)
  • authenticate.php: trang thực hiện xác thực hiện quá trình đăng nhập
  • db_utils.php: trang thực hiện các bước liên quan đến database
  • diagnostic.php: nó cần token nên mình không quan tâm đến nó
  • export.php: xuất ra file (cần quyền admin)
  • info.php: hiển thị thông tin về ứng dụng
  • login.php: trang đăng nhập
  • logout.php: trang đăng xuất
  • play.php: trang chơi game
  • profile.php: hiển thị thông tin của mình
  • register.php: trang đăng ký
  • save_game.php: lưu game

3. Exploit

Phân tích chức năng

Sau khi thực hiện đọc code cũng như là tìm hiểu các chức năng của ứng dụng thì mình thấy các file có thể khai thác như sau:

# save_game.php
<?php
session_start();
include_once("db_utils.php"); if (isset($_SESSION['PLAYER']) && $_SESSION['PLAYER'] != "") { $args = []; foreach($_GET as $key=>$value) { if (strtolower($key) === 'role') { // prevent malicious users to modify role header('Location: /index.php?err=Malicious activity detected!'); die; } $args[$key] = $value; } save_profile($_SESSION['PLAYER'], $_GET); // update session info $_SESSION['CLICKS'] = $_GET['clicks']; $_SESSION['LEVEL'] = $_GET['level']; header('Location: /index.php?msg=Game has been saved!'); }
?>

Chức năng của file này sẽ thực hiện nhận input của người dùng tương đương với 1 mảng, nếu trong mảng đó có từ role thì sẽ bị chặn và hiển thi thông báo Malicious activity detected!. Nếu thoả mãn điều kiện if (nghĩa là không có từ role), nó sẽ set giá trị vào trong mảng $arg

Sau đó sẽ thực hiện save_profile() và hiển thị thông báo Game has been saved

#db_utils.php
<?php .... function save_profile($player, $args) { global $pdo; $params = ["player"=>$player]; $setStr = ""; foreach ($args as $key => $value) { $setStr .= $key . "=" . $pdo->quote($value) . ","; } $setStr = rtrim($setStr, ","); $stmt = $pdo->prepare("UPDATE players SET $setStr WHERE username = :player"); $stmt -> execute($params);
} ..... ?>

Chức năng save_profile.php sẽ nhận đầu vào của người dùng với mảng ở trên file save_game.php

Sau đó nó sẽ nối vào biến $setStr ví dụ mảng nó có giá trị như sau [”clicks”⇒15, “level”⇒14] thì biến $setStr sẽ như sau: clicks = “15”, level = “14” và nó sẽ đi vào câu truy vấn để update dữ liệu của player:

UPDATE players SET clicks =15, level =14WHERE username = :player

Sau khi mình biết các chức năng thì mình sẽ đi vào khai thác:

Sau khi thực hiện chức năng save_game ở trên ứng dụng mình bắt request

image.png

Sẽ ra sao nếu mình có thể thêm được biến role có value là “Admin” . Nhưng role bị chặn. Thực ra để bypass được cách kiểm tra trên ta chỉ cần thay biến role thành role/**/

image.png

Như vậy có thể bypass được câu lệnh if cũng như có thể thực hiện truy vấn để thay đổi role của mình. Sau khi update xong logout rồi login lại thì nhận có thể truy cập được vào trang admin

image.png

Thực hiện truy cập vào trang admin, ở đây có 1 nút export dẫn tới chức năng export.php

#export.php
<?php
session_start();
include_once("db_utils.php"); if ($_SESSION["ROLE"] != "Admin") { header('Location: /index.php'); die;
} function random_string($length) { $key = ''; $keys = array_merge(range(0, 9), range('a', 'z')); for ($i = 0; $i < $length; $i++) { $key .= $keys[array_rand($keys)]; } return $key;
} $threshold = 1000000;
if (isset($_POST["threshold"]) && is_numeric($_POST["threshold"])) { $threshold = $_POST["threshold"];
}
$data = get_top_players($threshold);
$currentplayer = get_current_player($_SESSION["PLAYER"]);
$s = "";
if ($_POST["extension"] == "txt") { $s .= "Nickname: ". $currentplayer["nickname"] . " Clicks: " . $currentplayer["clicks"] . " Level: " . $currentplayer["level"] . "\n"; foreach ($data as $player) { $s .= "Nickname: ". $player["nickname"] . " Clicks: " . $player["clicks"] . " Level: " . $player["level"] . "\n"; }
} elseif ($_POST["extension"] == "json") { $s .= json_encode($currentplayer); $s .= json_encode($data);
} else { $s .= '<table>'; $s .= '<thead>'; $s .= ' <tr>'; $s .= ' <th scope="col">Nickname</th>'; $s .= ' <th scope="col">Clicks</th>'; $s .= ' <th scope="col">Level</th>'; $s .= ' </tr>'; $s .= '</thead>'; $s .= '<tbody>'; $s .= ' <tr>'; $s .= ' <th scope="row">' . $currentplayer["nickname"] . '</th>'; $s .= ' <td>' . $currentplayer["clicks"] . '</td>'; $s .= ' <td>' . $currentplayer["level"] . '</td>'; $s .= ' </tr>'; foreach ($data as $player) { $s .= ' <tr>'; $s .= ' <th scope="row">' . $player["nickname"] . '</th>'; $s .= ' <td>' . $player["clicks"] . '</td>'; $s .= ' <td>' . $player["level"] . '</td>'; $s .= ' </tr>'; } $s .= '</tbody>'; $s .= '</table>';
} $filename = "exports/top_players_" . random_string(8) . "." . $_POST["extension"];
file_put_contents($filename, $s);
header('Location: /admin.php?msg=Data has been saved in ' . $filename);
?>

Ở trang này có chức năng cho phép xuất ra đuôi file .txt, .json, .html lên đường dẫn exports/top_players_randomStr những người có số điểm clicks lớn hơn $threshhold = 1000000

image.png

Nhưng thực ra mình có thể xuất ra đuôi file nào tuỳ thích và ở đây mình sẽ để đuôi .php

image.png

Sẽ thế nào khi mình có thể thay đổi cái bảng đó thành code php để RCE

Trước hết mình phải cần điểm trên 1000000 thì mình sẽ vào top_player. Ở đây mình chỉ cần sửa biến clicks của mình thành 9999999 thì sẽ được lọt vào top player

image.png

Mình đã lọt vào top player

image.png

Xuất ra file .php

image.png

Mình chỉ cần thay đổi giá trị biến nickname như cách mình làm với Role thành php code là sẽ RCE được

Đầu tiên mình sẽ thay đổi giá trị nickname của mình

image.png

Sau đó thực hiện xuất file php và truy cập vào file php đó

image.png

Như vậy có thể RCE được hệ thống, bây giờ thực hiện reverse shell

image.png

image.png

RCE thành công vào hệ thống

4. Recommendation

  • Không nên cho phép đặt nhiều biến vào 1 array như chức năng save_game
  • Ở chức năng export nên đặt whitelist các tên đuôi file được phép xuất

Bình luận

Bài viết tương tự

- vừa được xem lúc

[Hackthebox] Tabby and Doctors Writeups

Tiếp tục là series về các bài writeups hackthebox mà mình làm được. Vì 2 bài này thuộc loại dễ và ngắn nên mình quyết định sẽ gộp chung vào 1 bài luôn. I. Thông tin chung về box.

0 0 41

- vừa được xem lúc

[Write up] HTB: BountyHunter - Khai thác lỗ hổng XXE

Giới thiệu. BountyHunter là một machine về leo quyền trên Linux.

0 0 31

- vừa được xem lúc

[Write-up] Romhack CTF 2022 - [Forensics] Chiếc email nguy hiểm...

Giới thiệu. .

0 0 26

- vừa được xem lúc

[Write up] HTB Cyber Apocalypse 2023: Perfect Synchronization

Đề bài:. .

0 0 20

- vừa được xem lúc

[Write-up] Hackthebox: Keeper. Một việc rất đơn giản nhưng thường bị bỏ quên

Tổng quan. Việc thay đổi mật khẩu mặc định là việc rất quan trọng, nó là việc tối thiểu để người dùng bảo vệ thông tin của mình, nhưng lại bị bỏ quên dẫn đến việc có thể rò rỉ thông tin cũng như bị xâ

0 0 14

- vừa được xem lúc

[Write-up] Hackthebox: Analytics. Chỉ thiếu 1 dòng code cũng trở nên nguy hiểm

Giới thiệu. Tưởng chừng như việc nâng cấp code sẽ mang lại cho ứng dụng web thêm tiện ích hay bảo mật.

0 0 10