Travel这台靶机真的是做hackthebox以来遇到的最佳靶机了。相比之前因为pwn的知识而根本没法下手的一些hard靶机。Travel属于纯渗透WEB知识,而且非常接近实战。难度甚至完全可以担当insane了。其起手式相比其他靶机相当困难。但我也因此学到了ssrf利用的新姿势,并且在之后的提权部分也基本上是面对完全未知的系统操作。所以最后完成的瞬间真的非常高兴。毕竟这是自己第一次做出不到四位数solved的靶机。整个过程中也遇到了很多困难。感谢anoNym1ty与traut的帮助。在他们给我的提示下我才能找到下手点并逐步完成渗透的过程。
Let's get it started.
由于Travel还是active状态,所以我会给文章上锁直到靶机退役。
9.14:靶机已退役
- 靶机ip:10.10.10.189
- 攻击机ip: 10.10.14.6
initial foothold
Starting Nmap 7.80 ( https://nmap.org ) at 2020-06-20 21:07 CST
Nmap scan report for 10.10.10.189
Host is up (0.44s latency).
Not shown: 997 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
80/tcp open http nginx 1.17.6
|_http-server-header: nginx/1.17.6
|_http-title: Travel.HTB
443/tcp open ssl/http nginx 1.17.6
|_http-server-header: nginx/1.17.6
|_http-title: Travel.HTB - SSL coming soon.
| ssl-cert: Subject: commonName=www.travel.htb/organizationName=Travel.HTB/countryName=UK
| Subject Alternative Name: DNS:www.travel.htb, DNS:blog.travel.htb, DNS:blog-dev.travel.htb
| Not valid before: 2020-04-23T19:24:29
|_Not valid after: 2030-04-21T19:24:29
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
nmap扫描显示了22,80与443端口。值得注意的是这次我们的nmap直接爆出了除www外的两个子域名blog.travel.htb
与blog-dev.travel.htb
。这实际上节省了我们后续的很多时间。
然后老规矩一个个来了。
- travel.htb。只是单纯的一个静态网页。中间提到blog字眼。看来是暗示了
blog.travel.htb
。 - blog.travel.htb 这个很有可能是重头戏。因为访问之后发现是一个wordpress搭建的网站。有着很明显的wordpress特征。且首页源码内有一段注释提到了
-dev
to-prod
。似乎是blog-dev
的提示。 - blog-dev.travel.htb 访问直接是403。且跟前两者一样都是nginx服务。
- https://www.travel.htb 直接访问会显示证书错误。网页提醒说要去
non-https
站看。因此没有过多信息。
因为没有过多有用的点。所以我们必须得用wfuzz来收集更多目录信息了。这一步基本上就两种选择:目录爆破或者子域名爆破。其中子域名我们应该已经齐全了,接下来就是一个不漏的进行目录爆破。(这点非常重要,因为我第一次忘记对blog-dev进行信息收集,所以导致错失关键信息)
对blog.travel.htb可以使用wpsscan 收集下wordpress的信息
wpscan --url https://xxxxx --enumerate vtp
并没有什么收获。之后用wfuzz对网站直接fuzzdir。也只是得到一些普通的wordpress路径。
ps: 这里因为自己第一次下手wordpress之类的站。导致对一些常规的php文件与路由会过分关注。比如一般robots.txt中会出现的allow: /wp-admin/admin-ajax.php
.以及xmlrpc.php
。后者确实存在一些ping的命令调用,但是并没有什么用。而这个站还有wp-json
的res api。但是除了博文信息一无所获。
之后转向blog-dev.travel.htb
。开始使用的字典什么都没爆出来,但是之后换了/usr/share/wordlists/dirb/common.txt
后得到了一个.git/HEAD
的存在。原来是存在.git
泄露。(再吐槽下,kali自带的几个字典有时真的拉胯,如果是平时打CTF用的扫描器肯定不会出这种没爆出来.git的问题)
那就常规githack源码恢复。得到三个文件
README.md
# Rss Template Extension
Allows rss-feeds to be shown on a custom wordpress page.
## Setup
* `git clone https://github.com/WordPress/WordPress.git`
* copy rss_template.php & template.php to `wp-content/themes/twentytwenty`
* create logs directory in `wp-content/themes/twentytwenty`
* create page in backend and choose rss_template.php as theme
## Changelog
- temporarily disabled cache compression
- added additional security checks
- added caching
- added rss template
## ToDo
- finish logging implementation
rss_template.php
set_cache_location('memcache://127.0.0.1:11211/?timeout=60&prefix=xct_');
//$simplepie->set_raw_data($data);
$simplepie->set_feed_url($url);
$simplepie->init();
$simplepie->handle_content_type();
if ($simplepie->error) {
error_log($simplepie->error);
$simplepie = null;
$failed = True;
}
} else {
$failed = True;
}
return $simplepie;
}
$url = $_SERVER['QUERY_STRING'];
if(strpos($url, "custom_feed_url") !== false){
$tmp = (explode("=", $url));
$url = end($tmp);
} else {
$url = "http://www.travel.htb/newsfeed/customfeed.xml";
}
$feed = get_feed($url);
if ($feed->error())
{
echo '' . "\r\n";
echo '' . htmlspecialchars($feed->error()) . "
\r\n";
echo '' . "\r\n";
}
else {
?>
get_link();
$title = $feed->get_title();
if ($link)
{
$title = "$title";
}
echo $title;
?>
get_description(); ?>
get_items() as $item): ?>
get_permalink()) echo ''; echo $item->get_title(); if ($item->get_permalink()) echo ''; ?> get_date('j M Y, g:i a'); ?>
get_content(); ?>
get_enclosure(0))
{
echo '';
echo '' . $enclosure->embed(array(
'audio' => './for_the_demo/place_audio.png',
'video' => './for_the_demo/place_video.png',
'mediaplayer' => './for_the_demo/mediaplayer.swf',
'altclass' => 'download'
)) . '
';
if ($enclosure->get_link() && $enclosure->get_type())
{
echo '(' . $enclosure->get_type();
if ($enclosure->get_size())
{
echo '; ' . $enclosure->get_size() . ' MB';
}
echo ')
';
}
if ($enclosure->get_thumbnail())
{
echo '
';
}
echo '';
}
?>
template.php
Hacking attempt prevented (LFI). Event has been logged.");
}
if(strpos($tmpUrl, "-o") !== false or strpos($tmpUrl, "-F") !== false)
{
die("Hacking attempt prevented (Command Injection). Event has been logged.
");
}
$tmp = parse_url($url, PHP_URL_HOST);
// preventing all localhost access
if($tmp == "localhost" or $tmp == "127.0.0.1")
{
die("Hacking attempt prevented (Internal SSRF). Event has been logged.
");
}
return $url;
}
function url_get_contents ($url) {
$url = safe($url);
$url = escapeshellarg($url);
$pl = "curl ".$url;
$output = shell_exec($pl);
return $output;
}
class TemplateHelper
{
private $file;
private $data;
public function __construct(string $file, string $data)
{
$this->init($file, $data);
}
public function __wakeup()
{
$this->init($this->file, $this->data);
}
private function init(string $file, string $data)
{
$this->file = $file;
$this->data = $data;
file_put_contents(__DIR__.'/logs/'.$this->file, $this->data);
}
}
到这一步一下子得到了很多关键信息。我首先注意到的是template.php中存在的针对ssrf的waf以及一个可以写文件的反序列化利用。看来我们的最终目的肯定是反序列化写webshell了。
回过头看readme.提到它将这两个php文件放在twentytwenty的文件夹下。并且似乎使用了rss_template.php作为模板文件。
这点从我们访问网址提供的blog主页也可以看出。
然后注意rss_template.php.其中有很多关键语句。大致流程是。如果我们传了custom_feed_url
变量。其值将被送去过一层waf.然后调用curl+escapeshellarg(url)的系统命令。之后是与memcache
进行连接,进行了一系列操作。
同时,注意php中还有提到debug.php的存在。如果带上参数debug就会include debug.php.
这里大致的脉络肯定有了。反序列化存在一个写文件的利用。curl存在一个ssrf的利用.并且waf很好绕。关键在于如何通过ssrf 反序列化。我想大部分应该都只接触过ssrf打redis触发python 的pickle数据反序列化。但是这里是php,真的有办法让curl执行的ssrf触发反序列化吗?答案是肯定的。
首先我去了解了下Memcache。发现这是一个及其类似redis的键值存储数据库。只不过常用于缓存服务器。其大致操作与redis非常相近
#set 命令
set key flags exptime bytes [noreply]
value
#get 命令
get key
那么这里我们必须找到memcache与序列化数据的相互关联。不过在此之前我们可以先在页面尝试下这个ssrf.并且通过debug参数看看debug.php会返回什么