WordPress – block xml-rpc

How to disable or block XML-RPC in wordpress served by apache server.

Per the official documentation –
XML-RPC on WordPress is actually an API or “application program interface“. It gives developers who make mobile apps, desktop apps and other services the ability to talk to your WordPress site. The XML-RPC API that WordPress provides gives developers a way to write applications (for you) that can do many of the things that you can do when logged into WordPress via the web interface

Unfortunately XML-RPC has drawbacks too, to mention some –

  • DDoS via XML-RPC pingbacks
  • Brute force attacks via XML-RPC

While looking at the access logs of my web servers, there were so many xmlrpc.php calls that looked suspicious.

121.42.52.27 - - [18/Sep/2019:22:53:32 -0400] "POST /xmlrpc.php HTTP/1.1" 200 3831 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  808526
121.42.52.27 - - [18/Sep/2019:22:53:34 -0400] "POST /xmlrpc.php HTTP/1.1" 200 816 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  868119
121.42.52.27 - - [18/Sep/2019:22:53:35 -0400] "POST /xmlrpc.php HTTP/1.1" 200 816 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  866812
121.42.52.27 - - [18/Sep/2019:22:53:37 -0400] "POST /xmlrpc.php HTTP/1.1" 200 816 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  708040
121.42.52.27 - - [18/Sep/2019:22:53:46 -0400] "POST /xmlrpc.php HTTP/1.1" 200 816 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  715609
121.42.52.27 - - [18/Sep/2019:22:53:48 -0400] "POST /xmlrpc.php HTTP/1.1" 200 816 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  768145
121.42.52.27 - - [18/Sep/2019:22:53:49 -0400] "POST /xmlrpc.php HTTP/1.1" 200 816 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  862514
121.42.52.27 - - [18/Sep/2019:22:53:56 -0400] "POST /xmlrpc.php HTTP/1.1" 200 816 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  847106
121.42.52.27 - - [18/Sep/2019:22:53:58 -0400] "POST /xmlrpc.php HTTP/1.1" 200 816 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  891537
121.42.52.27 - - [18/Sep/2019:22:54:02 -0400] "POST /xmlrpc.php HTTP/1.1" 200 816 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  983415
121.42.52.27 - - [18/Sep/2019:22:54:04 -0400] "POST /xmlrpc.php HTTP/1.1" 200 816 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  879661

Searching the abuse IP database –
https://www.abuseipdb.com/check/121.42.52.27 – the remote client hitting my server has been reported several times. Time to block this IP. After some googling, I came across a way to block it with .htaccess. We can either completely block the xmlrpc.php for all external IPs or for a specific blacklisted IPs.

In my .htaccess file, I added below line to block all IPs –

<Files xmlrpc.php>
order deny,allow
deny from all
allow from 127.0.0.1
</Files>

We can also block a specific IP address which is showing suspicious activity from our access logs –

<Files xmlrpc.php>
Order Deny,Allow
Allow from all
Deny from 121.42.52.27
</Files>

Post reloading apache, we can see that the remote client is getting 403s

121.42.52.27 - - [18/Sep/2019:22:55:02 -0400] "POST /xmlrpc.php HTTP/1.1" 403 634 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  1310
 121.42.52.27 - - [18/Sep/2019:22:55:03 -0400] "POST /xmlrpc.php HTTP/1.1" 403 634 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  1645
 121.42.52.27 - - [18/Sep/2019:22:55:05 -0400] "POST /xmlrpc.php HTTP/1.1" 403 634 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  1352
 121.42.52.27 - - [18/Sep/2019:22:55:05 -0400] "POST /xmlrpc.php HTTP/1.1" 403 634 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  1208
 121.42.52.27 - - [18/Sep/2019:22:55:06 -0400] "POST /xmlrpc.php HTTP/1.1" 403 634 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  1177
 121.42.52.27 - - [18/Sep/2019:22:55:06 -0400] "POST /xmlrpc.php HTTP/1.1" 403 634 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  1633
 121.42.52.27 - - [18/Sep/2019:22:55:06 -0400] "POST /xmlrpc.php HTTP/1.1" 403 634 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  1568
 121.42.52.27 - - [18/Sep/2019:22:55:06 -0400] "POST /xmlrpc.php HTTP/1.1" 403 634 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  1398
 121.42.52.27 - - [18/Sep/2019:22:55:07 -0400] "POST /xmlrpc.php HTTP/1.1" 403 634 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  1262
 121.42.52.27 - - [18/Sep/2019:22:55:07 -0400] "POST /xmlrpc.php HTTP/1.1" 403 634 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  1917
 121.42.52.27 - - [18/Sep/2019:22:55:08 -0400] "POST /xmlrpc.php HTTP/1.1" 403 634 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  2074
 121.42.52.27 - - [18/Sep/2019:22:55:08 -0400] "POST /xmlrpc.php HTTP/1.1" 403 634 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  1286
 121.42.52.27 - - [18/Sep/2019:22:55:08 -0400] "POST /xmlrpc.php HTTP/1.1" 403 634 "-" "Apache-HttpClient/4.5.2 (Java/1.8.0_151)"  847

References –

Make http request with telnet

How to make an HTTP request with telnet


One of the most frequent interview question for tech professionals, especially system administrators and developers is – “tell us what happens when you type a URL in a browser?”. Skipping the DNS resolution part, we can understand the client to server HTTP communication with telnet. The simplest case is a GET request to a path with a HOST header.As an example, let us make an http request to an AWS service which responds back with our public IP address –

$ telnet checkip.amazonaws.com 80
....
GET / HTTP/1.1
Host: checkip.amazonaws.com
....

Here is the full transaction –


daniel@hidmo:~$ telnet checkip.amazonaws.com 80
Trying 18.214.132.216...
Connected to checkip.us-east-1.prod.check-ip.aws.a2z.com.
Escape character is '^]'.
GET / HTTP/1.1
Host: checkip.amazonaws.com

HTTP/1.1 200 OK
Date: Sat, 14 Sep 2019 12:51:55 GMT
Server: lighttpd/1.4.41
Content-Length: 14
Connection: keep-alive

162.247.79.245
Connection closed by foreign host.

Notice how the server closes the connection after waiting for a few seconds, that is because the keep-alive is enabled on the server side as shown from the server response – “Connection: keep-alive“. With keep-alive we can make additional http calls with out going through the whole 3-way TCP handshake.

Disable keep-alive on client side

If for some reason, we want to close the connection on the client side immediately we can pass “Connection: Close” as part of the http header in the request.


References –

Telnet manpage

https://stackoverflow.com/questions/15772355/how-to-send-an-http-request-using-telnet

https://www.ntu.edu.sg/home/ehchua/programming/webprogramming/HTTP_Basics.html

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Keep-Alive


In Linux, the find command is most commonly used to search files using different criteria such as file name, size and modified time. Did you know that you can search files using inode number as well? Here is how to do it?

With “ls” we can find the inode number –

$ ls -li /etc/hosts
1576843 -rw-r--r-- 1 root root 311 Jan 21  2017 /etc/hosts

Using “-inum” option of find command, we can locate the filename and its path by its inode number.

$ find /etc -type f -inum 1576843 2>/dev/null 
/etc/hosts

$ cat $(find /etc -type f -inum 1576843 2>/dev/null)
127.0.0.1	localhost
127.0.1.1	ubuntu

References

http://man7.org/linux/man-pages/man7/inode.7.html

http://man7.org/linux/man-pages/man1/find.1.html

Linux – show file system type

How to print the file system type of a mount


Linux supports several file systems, including VFAT, ext2, ext3, ext4 and Reiser. The ext* family of file systems are probably the most popular ones.

The quickest way to view the file system on which each FILE resides, or all file systems is the “df” command.

$ df -Th
Filesystem     Type      Size  Used Avail Use% Mounted on
udev           devtmpfs  481M  4.0K  481M   1% /dev
tmpfs          tmpfs      99M  1.2M   98M   2% /run
/dev/sda1      ext4       46G   32G   12G  73% /
none           tmpfs     4.0K     0  4.0K   0% /sys/fs/cgroup
none           tmpfs     5.0M     0  5.0M   0% /run/lock
none           tmpfs     494M   12K  494M   1% /run/shm
none           tmpfs     100M   36K  100M   1% /run/user
In the above example, with "df -Th", we can see the file system type
("-T" option) in a human readable ("-h") size format.

Reference

http://linuxcommand.org/lc3_man_pages/df1.html

There are several tools for compressing and decompressing files in Linux, you can get a summary of these tools in this link. Zip is one of the utilities used for packaging, compressing (archive) and decompressing files.

Installation

  • Ubuntu
sudo apt-get update
sudo apt-get install zip unzip
  • RedHat or CentOS
sudo yum install unzip

Compress files

Compress files in a directory named tutorial –

$ zip -r tutorial.zip tutorial/
   adding: tutorial/ (stored 0%)
   adding: tutorial/host.conf (deflated 13%)
   adding: tutorial/hostname (stored 0%)
   adding: tutorial/hosts.deny (deflated 44%)
   adding: tutorial/hosts (deflated 35%)
   adding: tutorial/hosts.allow (deflated 42%)
   adding: tutorial/auth_sa.py (deflated 52%)

View contents of zip files, without uncompressing –

$ zip -sf tutorial
 Archive contains:
   tutorial/
   tutorial/host.conf
   tutorial/hostname
   tutorial/hosts.deny
   tutorial/hosts
   tutorial/hosts.allow
   tutorial/auth_sa.py
 Total 7 entries (2487 bytes)

Unzip or decompress

To decompress a zipped file, use the unzip command –

 $ unzip tutorial.zip
Archive:  tutorial.zip
   creating: tutorial/
  inflating: tutorial/host.conf
 extracting: tutorial/hostname
  inflating: tutorial/hosts.deny
  inflating: tutorial/hosts
  inflating: tutorial/hosts.allow
  inflating: tutorial/auth_sa.py

Search and compress

You can also combine find and zip command to search for certain types of files and compress those files in one command –

 $ find . -type f -name '*.conf' -print | zip confi-files -@
  adding: host.conf (deflated 13%)
  adding: colord.conf (deflated 50%)
  adding: ntp.conf (deflated 56%)

$ zip -sf confi-files
Archive contains:
  host.conf
  colord.conf
  ntp.conf
Total 3 entries (1858 bytes)
References -
https://linux.die.net/man/1/zip

Contents of most text files change during the life of the file , and it is common to find yourself trying to search and replace certain text across multiple files. In Linux, this is a fairly easy task. Let us go through some of the commands you will need to perform this task and then finally construct a single liner to do the job.

  • grep is your best friend when it comes to finding a string in a file. In this case we are looking for the string “REPLACEME” in current directory and across multiple files –
$ grep -r REPLACEME *
host.conf:# The "REPLACEME" line is only used by old versions of the C library.
host.conf:order hosts,REPLACEME,bind
hostname:REPLACEME
hosts.deny:ALL: REPLACEME

If we are interested only in the files which contains this particular text –

$ grep -lr REPLACEME *
host.conf
hostname
hosts.deny
  • sed is a tool of choice for inline editing of files –
$ cat data 
This text will be replaced - REPLACEME
$ sed -i 's/REPLACEME/NEWTEXT/g' data 
$ cat data 
This text will be replaced - NEWTEXT

From here, there are multiple ways to skin the cat – we can loop through the files and do the replacement or we can let the commands do the replacement with a wildcard.

For loop style update -

$ for f in $(grep -lr REPLACEME *); do echo "*** File: ${f} ***" ; sed -i 's/REPLACEME/NEWTEXT/g' $f; done
*** File: host.conf ***
*** File: hostname ***
*** File: hosts.deny ***

$ grep -lr REPLACEME *

$ grep -lr NEWTEXT *
data
host.conf
hostname
hosts.deny

Actually the above for loop is redundant, sed can make changes across multiple files –

 sed -i 's/REPLACEME/NEWTEXT/g' *