Skip to content

Commit 5136740

Browse files
committed
Git fail fixed.
1 parent 44c30f4 commit 5136740

File tree

3 files changed

+172
-0
lines changed

3 files changed

+172
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
## Frog Fractions 2(reversing, 5 points, 65 solves)
2+
Turns out Frog Fractions 2 is not battletoads
3+
We're given a 64bit elf file, let's start by disassembling it and describing important points in the program.
4+
5+
The program uses a library called libgmp to handle big numbers, it makes the debugging less friendly.
6+
7+
After analysing the binary come we come up with a replacement script in python:
8+
9+
```python
10+
data = [] #scraped data array from binary
11+
primes = [] #init primes somewhere
12+
v11 = 1019
13+
line = "A sample line input" #our input
14+
15+
def factor_print(a1):
16+
v4 = a1
17+
for x in range(200):
18+
c = 0
19+
while(v4 % primes[x] == 0):
20+
v4 = v4/primes[x];
21+
c = c+1
22+
if(c != 0):
23+
sys.stdout.write(chr(c))
24+
print
25+
26+
for i in range(len(line)):
27+
v11 = v11* pow(primes[i], ord(line[i]))
28+
j =0
29+
while(j < len(data)/2):
30+
v6 = data[j*2]
31+
v7 = data[j*2+1]
32+
33+
v10 = v11*v6
34+
if(v10 % v7 == 0):
35+
v11 = v10/v7
36+
j = 0
37+
else:
38+
j = j+1
39+
factor_print(v11)
40+
```
41+
42+
While searching through the binary we stumble into two big, interesting integers: 62834...(6955 chars) and 50209...(8423 chars).
43+
44+
What's interesting about them is that if we run them through our `factor_print` function we get the 2 messages available:
45+
46+
`Nope! You need to practice your fractions!`
47+
48+
`Congratulations! Treat yourself to some durians!`
49+
50+
So we need to find a line that reproduces the second output message, we do that by reversing the function:
51+
52+
```python
53+
def crack(v11):
54+
j = 0
55+
while(j < len(data)/2):
56+
v7 = data[j*2]
57+
v6 = data[j*2+1]
58+
59+
v10 = v11*v6
60+
if(v10 % v7 == 0):
61+
v11 = v10/v7
62+
j = 0
63+
else:
64+
j = j+1
65+
factor_print(v11)
66+
```
67+
68+
Which gives us the desired output: `KEY{(By the way, this challenge would be much easier with a cybernetic frog brain)}`
69+
70+
The full source is available [here](https://gist.github.com/nazywam/0634494b4b1c0ffd46a3)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
## Good Morning (web, 3 points, 110 solves)
2+
http://52.86.232.163:32800/ https://s3.amazonaws.com/bostonkeyparty/2016/bffb53340f566aef7c4169d6b74bbe01be56ad18.tgz
3+
4+
In this task we were given a source of web survey. It used MySQL in backend to store our answers. The script
5+
was not using prepared statements, so we quickly came to conclusion that there has to be a SQL injection possible.
6+
Unfortunately, our input was escaped before passing to MySQL library. However, they use their home-made escaping function
7+
instead of properly tested official ones.
8+
9+
Because the site was in Japanese, they used Shift-JIS character encoding. One of the oddities conencted to this encoding
10+
is that it changes position of backslash - 0x5C, which is ASCII backslash, in SJIS means yen. The websocket and Python script
11+
itself (including escaping function) use Unicode, so we can send `[yen]" stuff`, which will be converted by escaping function
12+
to `[yen]\" stuff`, and then converted to SJIS `0x5C\" stuff`. Since 0x5C is equivalent to backslash, that means our input will
13+
be interpreted as one escaped backslash, followed by unescaped quote, enabling us to put arbitrary SQL code there.
14+
15+
Proof:
16+
```
17+
>>> print mysql_escape(json.loads('{"type":"get_answer","question":"q","answer":"\u00a5\\\""}')["answer"]).encode("sjis")
18+
\\"
19+
```
20+
Exploiting via Chrome developer console:
21+
```
22+
socket.onmessage=function(e){console.log(e.data);};
23+
socket.send('{"type":"get_answer","question":"q","answer":"\u00a5\\\" OR 1=1 -- "}')
24+
25+
VM416:2 {"type": "got_answer", "row": [1, "flag", "BKPCTF{TryYourBestOnTheOthersToo}"]}
26+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#!/usr/bin/env python
2+
3+
from flask import Flask, render_template, Response
4+
from flask_sockets import Sockets
5+
import json
6+
import MySQLdb
7+
8+
app = Flask(__name__)
9+
sockets = Sockets(app)
10+
11+
with open("config.json") as f:
12+
connect_params = json.load(f)
13+
14+
connect_params["db"] = "ganbatte"
15+
16+
# Use Shift-JIS for everything so it uses less bytes
17+
Response.charset = "shift-jis"
18+
connect_params["charset"] = "sjis"
19+
20+
questions = [
21+
"name",
22+
"quest",
23+
"favorite color",
24+
]
25+
26+
# List from http://php.net/manual/en/function.mysql-real-escape-string.php
27+
MYSQL_SPECIAL_CHARS = [
28+
("\\", "\\\\"),
29+
("\0", "\\0"),
30+
("\n", "\\n"),
31+
("\r", "\\r"),
32+
("'", "\\'"),
33+
('"', '\\"'),
34+
("\x1a", "\\Z"),
35+
]
36+
def mysql_escape(s):
37+
for find, replace in MYSQL_SPECIAL_CHARS:
38+
s = s.replace(find, replace)
39+
return s
40+
41+
@sockets.route('/ws')
42+
def process_questsions(ws):
43+
i = 0
44+
conn = MySQLdb.connect(**connect_params)
45+
with conn as cursor:
46+
ws.send(json.dumps({"type": "question", "topic": questions[i], "last": i == len(questions)-1}))
47+
while not ws.closed:
48+
message = ws.receive()
49+
if not message: continue
50+
message = json.loads(message)
51+
if message["type"] == "answer":
52+
question = mysql_escape(questions[i])
53+
answer = mysql_escape(message["answer"])
54+
cursor.execute('INSERT INTO answers (question, answer) VALUES ("%s", "%s")' % (question, answer))
55+
conn.commit()
56+
i += 1
57+
if i < len(questions):
58+
ws.send(json.dumps({"type": "question", "topic": questions[i], "last": i == len(questions)-1}))
59+
elif message["type"] == "get_answer":
60+
question = mysql_escape(message["question"])
61+
answer = mysql_escape(message["answer"])
62+
cursor.execute('SELECT * FROM answers WHERE question="%s" AND answer="%s"' % (question, answer))
63+
ws.send(json.dumps({"type": "got_answer", "row": cursor.fetchone()}))
64+
print message
65+
66+
@app.route('/')
67+
def hello():
68+
return app.send_static_file("index.html")
69+
70+
if __name__ == "__main__":
71+
from gevent import pywsgi
72+
from geventwebsocket.handler import WebSocketHandler
73+
addr = ('localhost', 5000)
74+
75+
server = pywsgi.WSGIServer(addr, app, handler_class=WebSocketHandler)
76+
server.serve_forever()

0 commit comments

Comments
 (0)