Log in / Register
Home arrow Computer Science arrow Understanding Network Hacks
< Prev   CONTENTS   Next >

7.9 SQL Injection

Until recently the author of this book thought SQL injection exploits were only to be found in tiny web pages developed by no-name companies, because this kind of weakness is so simple to understand and avoid (at least most of the time), but he got schooled!

Attacks from groups like Anonymous and Lulz Sec clearly revealed that SQL injection is still a hot topic. Intrusions into various Sony sites, government institutions, the Playstation network and so on and so on were not the only ones that were successful only by using SQL injection!

Therefore it's time to write a scanner that will sporadically search your own web sites for those attack vectors. To avoid misunderstandings, this automatic scanners' aim is not to find all weaknesses. This is simply not possible for such a simple script, but it should show the most obvious gaps and make you aware of the problem.

How do SQL injection attack really work? To clarify that we must first of all have a look at a typical construction of a modern web application. Today nearly all web pages are dynamic, that means they do not always deliver the same HTML page for the same request, but react on user input and properties and generate content related to that. Those inputs are either sent over the URL in form of (GET request) or with the help of forms that most of the time transmit its data with the POST method and therefore invisibly to an ordinary user. All dynamic elements can be reduced to GET and POST request regardless of whether they got invoked by direct user interaction, AJAX functions, SOAP, REST, Flash, Java or whatever Plugin calls. To be really complete we must extend the list by cookies, PUT and other HTTP headers such as Language or Referer. Most dynamic web applications achieve their dynamism with the help of a SQL database. Exceptions exist such as server side includes, scripts that execute shell commands (command injection is the topic of the next section) or more exotic ones like NoSQL or XML database or even more outlandish that they are not listed here at all.

After the web server received an user input via GET or POST it will trigger a CGI or PHP, ASP, Python, Ruby or whatever other program on it, that uses the data to make an inquiry to a SQL database. On a login attempt this could for example generate the following SQL code:

SELECT COUNT(*) FROM auth WHERE username="hans" AND


Let's assume the username and password were inserted completely unfiltered into the SQL command that a malicious attacker could inject strange authentication data. As username he could send " OR ""=" and as password also " OR ""=". The database now gets the following command:

SELECT COUNT(*) FROM auth WHERE username="" OR ""="" AND

password="" OR ""=""

Empty equals empty is always true which leads to the result that the whole statement returns always true. If the calling code only checks if the result is true or greater null than the attacker has successfully logged in without even knowing any username or password at all! This is the famous “Open sesame” trick of SQL injection!

Wrongly, some developers think SQL injection is only possible with string based input. This misconception is common for e.g. a PHP developer who think they only have to activate their Magic-Quotes setting and are safe. Magic-Quotes take care of quoting characters like ' and " with a backslash to prevent them being interpreted as special character by a subsystem. In the best case such an automatic function even quotes the backslash itself otherwise an attack could simply quote the quote and make it useless for example by entering " OR ""=", which gives

\" OR \"\"=\" after quoting. A trick that can be applied to circumvent various security mechanisms. Check your code and don't trust magic security

mechanisms blindly!

But what happens when the parameter that is used for injection is not a string but an integer? Here some quote functions do not do anything at all. In the worst case you are dealing with an untyped programming language that even doesn't use an object relational mapper and as such does not guarantee type safety. Then an attacker can append ; DROP DATABASE to an ID parameter and ruin your whole weekend! No limits exists for the attacker, because he can freely add any SQL code and depending on the construction of the web page he can even see the results right away. Then he can not only dump the whole database, but also manipulate data, insert new user accounts, delete anything and so on. He cannot only use a colon to append extra SQL commands but also the keyword UNION to extend a select statement.

The developer should always distrust the user and eliminate or quote all special characters for each subsystem he or she uses. They should also avoid being specific with error messages and never supply a detailed SQL failure or stack trace.

Other possibilities to inject SQL code are to comment out the succeeding code with the help of -or /*, until such fascinating attacks that use database internal functions like char(0x27) (0x27 is the hex value of ') to generate code on the fly.

As if this was not enough, modern database systems offer a lot more functionality today than just structure, save, update, delete and query data. They offer the possibility of programming triggers and stored procedures up to such bizarre properties such as executing shell commands (in MySQL via system, in MS-SQL via xp_cmdshell) or even manipulate the Windows registry. An attacker that can inject SQL code can use all the functionality of the database and may even get a root shell if the database runs as root or under the Admin account! In this way, a simple SQL injection that a developer maybe wipes away with the comment “Who cares? The data is all public.” can lead to the whole system being compromised.

Reason enough to dig a little deeper. If you want to learn more about SQL injection attacks the author suggest reading the book “The Web Application Hacker's Handbook” from Dafydd Stuttard and Marcus Pinto, the authors of the Burp-Proxies.

Let's write a Python program that will at least find the biggest holes.

1 #!/usr/bin/python


3 ###[ Loading modules


5 import sys

6 import httplib2

7 from urlparse import urlparse

8 from BeautifulSoup import BeautifulSoup



11 ###[ Global vars


13 max_urls = 999

14 inject_chars = ["'",

15 "--",

16 "/*",

17 '"']

18 error_msgs = [

19 "syntax error",

20 "sql error",

21 "failure",

22 ]


24 known_url = {}

25 already_attacked = {}

26 attack_urls = []



29 ###[ Subroutines


31 def get_abs_url(link):

32 """

33 check if the link is relative and prepend the protocol

34 and host. filter unwanted links like mailto and links

35 that do not go to our base host

36 """

37 if link:

38 if "://" not in link:

39 if link[0] != "/":

40 link = "/" + link


42 link = protocol + "://" + base_host + link


44 if "mailto:" in link or base_host not in link:

45 return None

46 else:

47 return link



50 def spider(url):

51 """

52 check if we dont know the url

53 spider to url

54 extract new links

55 spider all new links recursively

56 """

57 if len(known_url) >= max_urls:

58 return None


60 if url:

61 (n_proto, n_host, n_path,

62 n_params, n_query, n_frag) = urlparse(url)


64 if not known_url.get(url) and n_host == base_host:

65 try:

66 sys.stdout.write(".")

67 sys.stdout.flush()


69 known_url[url] = True

70 response, content = browser.request(url)


72 if response.status == 200:

73 if "?" in url:

74 attack_urls.append(url)


76 soup = BeautifulSoup(content)


78 for tag in soup('a'):

79 spider(get_abs_url(tag.get('href')))

80 except httplib2.ServerNotFoundError:

81 print "Got error for " + url +

82 ": Server not found"

83 except httplib2.RedirectLimit:

84 pass



87 def found_error(content):

88 """

89 try to find error msg in html

90 """

91 got_error = False


93 for msg in error_msgs:

94 if msg in content.lower():

95 got_error = True


97 return got_error



100 def attack(url):

101 """

102 parse an urls parameter

103 inject special chars

104 try to guess if attack was successfull

105 """

106 (a_proto, a_host, a_path,

107 a_params, a_query, a_frag) = urlparse(url)


109 if not a_query in already_attacked.get(a_path, []):

110 already_attacked.setdefault(a_path, []).append(a_query)


112 try:

113 sys.stdout.write(" Attack " + url)

114 sys.stdout.flush()

115 response, content = browser.request(url)


117 for param_value in a_query.split("&"):

118 param, value = param_value.split("=")


120 for inject in inject_chars:

121 a_url = a_proto + "://" +

122 a_host + a_path +

123 "?" + param + "=" + inject

124 sys.stdout.write(".")

125 sys.stdout.flush()

126 a_res, a_content = browser.request(a_url)


128 if content != a_content:

129 print " Got different content " +

130 "for " + a_url

131 print "Checking for exception output"

132 if found_error(a_content):

133 print "Attack was successful!"

134 except (httplib2.ServerNotFoundError,

135 httplib2.RedirectLimit):

136 pass



139 ###[ MAIN PART


141 if len(sys.argv) < 2:

142 print sys.argv[0] + ": <url>"

143 sys.exit(1)


145 start_url = sys.argv[1]

146 (protocol, base_host,

147 path, params, query, frag) = urlparse(start_url)

148 browser = httplib2.Http()


150 sys.stdout.write("Spidering")

151 spider(start_url)

152 sys.stdout.write(" Done. ")


154 for url in attack_urls:

155 attack(url)

The heart of the tool is a web spider or crawler, so a program code that reads a HTML page from a web server, parses it by using the module BeautifulSoup and extracts all links. This task is implemented in the function spider(). First of all it checks if the URL got called before. If this is not the case it fetches the HTML code and extracts all links. If a link includes a question mark and therefore receives additional parameters it is added to the list attack_urls. The spider algorithm of this script is only rudimentary. It should explain the principle and not confuse the reader through complexity. It just extracts links of a-tags and overlooks a lot. Nowadays web spidering is a tedious task. Think of links in AJAX calls, Javascript code, Flash classes, ActiveX objects, Java applets and so on. The script can be extended on demand by updating the parser code in the spider() function. The list of possible attackable links that is filled by the spider() function get iterated link by link and the function attack() is applied to each link. It parses the URL into its components like protocol, host, path and query-string. The path includes the path of the called web page or web application, the query string all parameters. With the combination of path and query string the attack() function checks if this URL was already attacked. If not, it remembers it in the already_attacked dictionary. Now we add common SQL injection characters to each parameter and send the manipulated URL to the server. Depending on its reaction the script tries to guess if the attack was a success. Therefore it calls the normal URL and compares its result with the result of the manipulated URL. If it is

not the same it scans the HTML source for common patterns of error messages.

Found a mistake? Please highlight the word and press Shift + Enter  
< Prev   CONTENTS   Next >
Business & Finance
Computer Science
Language & Literature
Political science