I tried the link in my browser and it wasn't loading, so I decided
to statically analyze the webserver in Ghidra.
From the static analysis, I noticed that if "GET / HTTP/1.1" was sent
to the server, that it had a predetermined response. I then pulled up
netcat, connected to the server, and sent "GET / HTTP/1.1" and got this
response (Note that, from here on out, I used netcat to communicate with
the server, since the HTTP requests weren't complicated).
I then noticed that it mentioned to try "GET /echo?message HTTP/1.1",
so I tried that (thanks for making my dynamic analysis easier), and
I did get the string "message" back. Naturally, I was very curious about
how they did that, so I looked more in Ghidra and saw that, if the
header is of the form
"GET /<command>?<arguments> HTTP/1.1"
Then it would do a popen in the code with '<command> <arguments>' as
the string to pass to the function and write the first "few" bytes
from the process output to the HTTP response body.
I tested this with "GET /ls?. HTTP/1.1" to confirm this, and it did
actually list out things in the directory. However, the command acts
kind of funny for some strange reason which I wasn't sure about.
After a bit of toying around, I realized that I could encode spaces in
the command by typing '$' in arguments, since it actually puts a space
whenever it sees '$'
For example, if I write "GET /echo?hello$world$how$are$you HTTP/1.1", the popen
string becomes 'echo hello world how are you'.
I also notice that backticks (`) aren't converted to spaces. That gives me a certain
idea. If I send to the server
GET /echo?`ls$-la` HTTP/1.1
The server should blissfully run "echo `ls -la`" (which it should've done before,
but it never hurts to try different things). Sure enough, running that gives me.
total 104 drwxr-xr-x 1 root root 4096 Mar 27 19:17 . drwxr-xr-x 1 root root 4096 Mar 27 19:17 .. -rw-r--r-- 1 root root 220 Feb 25 2020 .bash_logout -rw-r--r-- 1 root root 3771 Feb 25 2020 .bashrc -rw-r--r-- 1 root root 807 Feb 25 2020 .profile -rwxr-xr-x 1 root root 17704 Mar 27 19:14 a.out -rwxr-xr-x 1 root root 39256 Mar 27 19:14 echo -rw-r--r-- 1 root root 16 Mar 27 19:14 flag.txt -rwxr-xr-x 1 root root 18744 Mar 27 19:14 ynetd
Optionally, you could also do
GET /echo?`ls` HTTP/1.1
to get the simpler output
a.out echo flag.txt ynetd
After that, simply entering
GET /echo?`cat$flag.txt` HTTP/1.1
Gives you the flag