{"id":359,"date":"2012-11-05T20:35:27","date_gmt":"2012-11-06T04:35:27","guid":{"rendered":"http:\/\/seanmurphree.com\/blog\/?p=359"},"modified":"2012-11-20T16:21:59","modified_gmt":"2012-11-21T00:21:59","slug":"natas-level-15-blind-injection","status":"publish","type":"post","link":"https:\/\/seanmurphree.com\/blog\/?p=359","title":{"rendered":"Natas Level 15 &#8211; Blind Injection"},"content":{"rendered":"<p>In this post, we&#8217;re going to be looking at Level 15 of the Natas wargame, hosted by Over The Wire.<\/p>\n<h2>What&#8217;s Going On?<\/h2>\n<p>Upon logging in, we are presented with another form. \u00a0This one prompts us for a username, and provides a &#8220;check existence&#8221; button. \u00a0A quick test of the form with a random username, such as &#8220;asdf&#8221;, and an assumed valid one, such as &#8220;natas16&#8221;, gives us a page which tells us the first user doesn&#8217;t exist and that the second one does. \u00a0To get a better understanding from here, let&#8217;s follow the link to the source code, and take a look at the PHP.<\/p>\n<p>We can see that the PHP source starts out with a comment about the creation of a table in a database. \u00a0This table is called &#8220;users&#8221; and has two columns, &#8220;username&#8221; and &#8220;password&#8221;. Below this comment we see the main PHP section of the page. \u00a0This code checks that the &#8220;username&#8221; field of the HTTP request is set before continuing on. \u00a0If it is set, there is a connection established to the level15 database, and a query is constructed to look up entries which match the value submitted through the username field of the HTTP request. \u00a0Looking at how the query is constructed, we can see that it&#8217;s vulnerable to injection. \u00a0However, if we look through the rest of the code, we notice it&#8217;s slightly different than the previous level in that there is no line printing the password, nor printing the results of the query. So, how will we get the password to the next level?<\/p>\n<h2>Exploit<\/h2>\n<p>As we can see in the PHP code, there is no direct way to get the results of the query, or get the password. \u00a0Thus, we&#8217;re going to have to take an indirect approach. \u00a0So, how can we indirectly get information from the database?<\/p>\n<p>Well, if we were able to compare the password field of the user natas16 to various values, and do something different when the values match, we could somehow get information out. \u00a0Since we know we cannot print information, how about doing something like making the process sleep? \u00a0Unfortunately, MySQL doesn&#8217;t have a sleep function we can embed in a query, but let&#8217;s look at what it does have.<\/p>\n<ul>\n<li>Union &#8211; Combines sets, allows additional select statements to be run.<\/li>\n<li>If &#8211; We can make conditional logic!<\/li>\n<li>Substring &#8211; We can look at only one part of a string, say 1 character at a time.<\/li>\n<li>Benchmark &#8211; Allows repeated execution of code, say, to delay the return of the query results (sounds similar to sleep!)<\/li>\n<\/ul>\n<p>Now let&#8217;s think about how to combine those things to figure out the length of the password. As we can see from the PHP code, the query is as follows:<\/p>\n<blockquote><p>SELECT\u00a0*\u00a0from\u00a0users\u00a0where\u00a0username=&#8221;username&#8221;<\/p><\/blockquote>\n<p>So, let&#8217;s choose the natas16 user, then join on another select query for the password which, if the length of the password is 32, will run a long benchmark before returning:<\/p>\n<blockquote><p>natas16&#8243; UNION SELECT password, IF(LENGTH(password)=32,BENCHMARK(500000000,ENCODE(&#8216;The Message&#8217;,&#8217;The Key&#8217;)),null) FROM users WHERE username=&#8221;natas16<\/p><\/blockquote>\n<p>When submitted, we can see that it takes a long time for the page to load (if it ever does). \u00a0If we change to length 31, the page loads immediately. \u00a0Thus, we have used this indirect path to gain information about what was in the table by using time as a pathway to transfer information. \u00a0Now that we know the password is 32 characters (like the previous passwords), let&#8217;s attempt to make another construction to test the values of the password.<\/p>\n<p>As stated above, we can use MySQL&#8217;s substring function to return part of a string. \u00a0So, let&#8217;s use this to select one character in the string and compare it&#8217;s value to a character we specify. \u00a0If they are equal, we&#8217;ll force a benchmark, otherwise we&#8217;ll see the resultant page immediate.<\/p>\n<blockquote><p>natas16&#8243; UNION SELECT password, IF(SUBSTRING(password,1,1) = BINARY(CHAR(50)),BENCHMARK(600000000,ENCODE(&#8216;The Message&#8217;,&#8217;The Key&#8217;)),null) FROM users WHERE username=&#8221;natas16<\/p><\/blockquote>\n<p>One thing to specify about the above code is the use of binary(char(50)). \u00a0Char(50) specifies the character with ascii decimal code 50. \u00a0However, when MySQL compares strings (or characters), it does so without regard to case. \u00a0Thus, not including the binary() call, this query would run the benchmark for both char(97) and char(65) (a or A). \u00a0The use of binary(char()) forces case-sensitivity.<\/p>\n<p>Now that we know how the above code works, we can submit it for every ASCII value we&#8217;d expect could be in the password as the input into the char() function, until we reach a value which forces the page to not return quickly (aka forces the benchmark to run). \u00a0Once this happens, we know we&#8217;ve found the ASCII value of the 1st character of the password. \u00a0For example, if we increase 50 to 51 and submit the query, we find out the page doesn&#8217;t load and thus, the first character of the password is ASCII 51, also known as the number 3.<\/p>\n<p>Once we&#8217;ve found the 1st character, we can change the substring call from\u00a0SUBSTRING(password,1,1) to\u00a0SUBSTRING(password,2,1) and start all over again brute forcing char values at 48. \u00a0Once the 2nd character is found, restart with the 3rd, repeat until finished.<\/p>\n<p>Now I hear you saying, &#8220;But that sounds boring and like it will take a long time!&#8221; \u00a0Yeah, well, write a script to do it. \u00a0Computers are great at\u00a0repetitive tasks. \u00a0In fact, a PHP script to figure out the entire password isn&#8217;t too hard to write and is what I used for this challenge. \u00a0Expect a script post here in the future.<\/p>\n<h2>So What?<\/h2>\n<p>Even when results of a query are not displayed on the page, or directly used to display sensitive information, results are still transferred to users. \u00a0Results are a relative term, and with injection a result can be the delayed processing of a page, such as in this example. \u00a0More strenuous actions need to be taken to prevent injection in the first place, because as this level shows, even blind injection can be used to get the exact values in a database, such as a 32 character long password in under an hour (or faster in production web environments which will allow more connections at a time and thus, less throttling for a script).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this post, we&#8217;re going to be looking at Level 15 of the Natas wargame, hosted by Over The Wire. What&#8217;s Going On? Upon logging in, we are presented with another form. \u00a0This one prompts us for a username, and &hellip; <a href=\"https:\/\/seanmurphree.com\/blog\/?p=359\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[36,35,4],"tags":[37,13,40,38],"_links":{"self":[{"href":"https:\/\/seanmurphree.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/359"}],"collection":[{"href":"https:\/\/seanmurphree.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/seanmurphree.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/seanmurphree.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/seanmurphree.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=359"}],"version-history":[{"count":5,"href":"https:\/\/seanmurphree.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/359\/revisions"}],"predecessor-version":[{"id":374,"href":"https:\/\/seanmurphree.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/359\/revisions\/374"}],"wp:attachment":[{"href":"https:\/\/seanmurphree.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=359"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/seanmurphree.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=359"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/seanmurphree.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=359"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}