HackTheBox - Medium - Linux - Format

Format

Format 是一种中等难度的 Linux 机器,它突出显示了由解决方案的结构方式引起的安全问题。立足点涉及PHP源代码审查,发现和利用本地文件读/写漏洞,并利用Nginx中的错误配置在Redis Unix套接字上执行命令。横向移动包括浏览 Redis 数据库以发现用户密码,而权限提升则围绕以 root 权限运行的 Python 脚本展开,该脚本容易受到代码注入的影响。


外部信息收集

端口扫描

循例nmap

HackTheBox - Medium - Linux - Format_第1张图片

Web枚举

80端口 - app.microblog.htb

HackTheBox - Medium - Linux - Format_第2张图片

3000端口 - microblog.htb

HackTheBox - Medium - Linux - Format_第3张图片

Foldhold

和我预想的一样,gitea包含了app子域的源码,毕竟遇到这种情况的次数也不少了

HackTheBox - Medium - Linux - Format_第4张图片

我们首先在app子域创建一个账号并登录

HackTheBox - Medium - Linux - Format_第5张图片

这里有一个最显眼的功能也是唯一一个功能就是创建新博客,我们可以指定子域域名,我们在源码里面定位到那个功能的代码

一开始我把目光放到了addsite函数上

addSite($_POST['new-blog-name']);


function addSite($site_name) {
    if(isset($_SESSION['username'])) {
        ...
        $tmp_dir = "/tmp/" . generateRandomString(7);
        system("mkdir -m 0700 " . $tmp_dir);
        system("cp -r /var/www/microblog-template/* " . $tmp_dir);
        system("chmod 500 " . $tmp_dir);
        system("chmod +w /var/www/microblog");
        system("cp -rp " . $tmp_dir . " /var/www/microblog/" . $site_name);
		...

我们应该可以尝试控制$_POST[‘new-blog-name’]来尝试执行系统命令,但是我发现后端对new-blog-name进行了严格的过滤,只允许26个字母,所以使我打消了这个念头

if (isset($_SESSION['username']) && isset($_POST['new-blog-name'])) {
    if(!preg_match('/^[a-z]+$/', $_POST['new-blog-name']) || strlen($_POST['new-blog-name']) > 50) {
        print_r("Invalid blog name");

我创建了一个test子域

在gitea中我看到一个sunny子域,我猜那个应该是由app子域创建的,所以我刚刚创建的test子域应该与sunny子域有同样的代码结构

HackTheBox - Medium - Linux - Format_第6张图片

在edit/index.php中,我发现了任意文件读写

//add header
if (isset($_POST['header']) && isset($_POST['id'])) {
    chdir(getcwd() . "/../content");
    $html = "
{$_POST['header']}
"
; $post_file = fopen("{$_POST['id']}", "w"); fwrite($post_file, $html); fclose($post_file); $order_file = fopen("order.txt", "a"); fwrite($order_file, $_POST['id'] . "\n"); fclose($order_file); header("Location: /edit?message=Section added!&status=success"); } //add text if (isset($_POST['txt']) && isset($_POST['id'])) { chdir(getcwd() . "/../content"); $txt_nl = nl2br($_POST['txt']); $html = "
{$txt_nl}
"
; $post_file = fopen("{$_POST['id']}", "w"); fwrite($post_file, $html); fclose($post_file); $order_file = fopen("order.txt", "a"); fwrite($order_file, $_POST['id'] . "\n"); fclose($order_file); header("Location: /edit?message=Section added!&status=success"); }

尝试读取passwd

HackTheBox - Medium - Linux - Format_第7张图片

我尝试着在web目录下写入webshell,但很不幸的是应该是没有权限和解析php

Nginx配置错误

读/etc/nginx/sites-available/default

...
location ~ /static/(.*)/(.*) {
	resolver 127.0.0.1;
	proxy_pass http://$1.microbucket.htb/$2;
...

这篇文章讲述了nginx的proxy_pass支持将请求代理到本地unix套接字

现在我们可以控制$1,我们看到register.php设置的字段

HackTheBox - Medium - Linux - Format_第8张图片

通过nginx的proxy_pass来对redis进行操作

将自己的账户的pro字段设置为true

HackTheBox - Medium - Linux - Format_第9张图片

刷新一下

HackTheBox - Medium - Linux - Format_第10张图片

function provisionProUser() {
    if(isPro() === "true") {
        $blogName = trim(urldecode(getBlogName()));
        system("chmod +w /var/www/microblog/" . $blogName);
        system("chmod +w /var/www/microblog/" . $blogName . "/edit");
        system("cp /var/www/pro-files/bulletproof.php /var/www/microblog/" . $blogName . "/edit/");
        system("mkdir /var/www/microblog/" . $blogName . "/uploads && chmod 700 /var/www/microblog/" . $blogName . "/uploads");
        system("chmod -w /var/www/microblog/" . $blogName . "/edit && chmod -w /var/www/microblog/" . $blogName);
    }
    return;
}

现在我们是pro,上面这些命令会使我们能够对uploads/目录写入文件,借此来getshell

HackTheBox - Medium - Linux - Format_第11张图片

然后通过rce来使用祖传python3 payload

file

本地横向移动 -> cooper

在redis发现了一个系统用户名的key

HackTheBox - Medium - Linux - Format_第12张图片

读一下发现了他的密码

hgetall cooper.dooper

HackTheBox - Medium - Linux - Format_第13张图片

直接登ssh

本地权限提升

sudo -l

HackTheBox - Medium - Linux - Format_第14张图片

这是一个python脚本

我们主要关注脆弱点

    username = r.hget(args.provision, "username").decode()
    firstlast = r.hget(args.provision, "first-name").decode() + r.hget(args.provision, "last-name").decode()
    license_key = (prefix + username + "{license.license}" + firstlast).format(license=l)

这里的license_key由几个变量拼接进来然后format,应该存在模板注入,而username这些都是在redis读取的,我们可以控制redis来触发模板注入

secret = [line.strip() for line in open("/root/license/secret")][0]
secret_encoded = secret.encode()
salt = b'microblogsalt123'
kdf = PBKDF2HMAC(algorithm=hashes.SHA256(),length=32,salt=salt,iterations=100000,backend=default_backend())

通过模板注入来获取secret,设置username

HackTheBox - Medium - Linux - Format_第15张图片

再次运行

HackTheBox - Medium - Linux - Format_第16张图片

root flag还在老地方

HackTheBox - Medium - Linux - Format_第17张图片

你可能感兴趣的:(HackTheBox,HackTheBox,网络安全,Linux渗透测试,配置错误,Nginx,Web漏洞,php代码审计)