emmm,就出了一道简单的背包密码,Misc那道图片差第三部分的flag

官方wphttps://www.yuque.com/yuqueyonghu30d1fk/gd2y5h/yleeg03c0ucdoac6

Crypto

complex_enc

超递增背包问题

c = 287687761937146187597379915545639385740275457170939564210821293233370716878150576
key = [...]
flag = ''
for i in key[::-1]:
if i <= c:
flag += '1'
c -= i
else:
flag += '0'
flag = flag[::-1]
for i in range(0, len(flag), 8):
print(chr(int(flag[i:i+8], 2)), end='')
# DASCTF{you_kn0w_b@ckpack_Crypt0?}

1z_RSA

放个题目先

from Crypto.Util.number import *
from sympy import *
import os
from secrets import flag

nbit =130
e = 3
l = getPrime(505)
m = bytes_to_long(flag + os.urandom(64))

assert len(flag) == 29

while True:
p, q = getPrime(nbit), getPrime(nbit)
PQ = int(str(p<<120)+str(q))
QP = int(str(q<<120)+str(p))
if isPrime(PQ) and isPrime(QP):
break

n = PQ * QP
PP = nextprime((PQ >> 190) * (QP & (2 ** 190 - 1)))
QQ = nextprime((QP >> 190) * (PQ & (2 ** 190 - 1)))
N = PP * QQ
M = pow(m,1,l)
c = pow(m,e,N)

print('n =', n)
print('M =', M)
print('l =', l)
print('c =', c)

'''
n = 18339446336492672809908730785358232636383625709800392830207979464962269419140428722248172110017576390002616004691759163126532392634394976712779777822451878822759056304050545622761060245812934467784888422790178920804822224673755691
M = 36208281423355218604990190624029584747447986456188203264389519699277658026754156377638444926063784368328407938562964768329134840563331354924365667733322
l = 56911058350450672322326236658556745353275014753768458552003425206272938093282425278193278997347671093622024933189270932102361261551908054703317369295189
c = 720286366572443009268610917990845759123049408295363966717060100862857351750759651979922104897091176824666482923148635058966589592286465060161271579501861264957611980854954664798904862706450723639237791023808177615189976108231923
'''

注意

PQ = int(str(p<<120)+str(q))
QP = int(str(q<<120)+str(p))

两个字符串相加,是拼接的,所以需要获取后面的p、q的十进制的长度,测试到大概为一个39,另一个40
写成这样的表达
PQ=p21201039+qPQ=p*2^{120}*10^{39}+q
QP=q21201040+pQP=q*2^{120}*10^{40}+p
n=PQQP=pq(22401079+1)+(p2+10q2)21201039n=PQ*QP=p*q*(2^{240}*10^{79}+1)+(p^{2}+10*q^{2})*2^{120}*10^{39}

观察,可以把p*q弄出来

n//(22401079+1)=pq+xn//(2^{240}*10^{79}+1)=p*q+x
n%(21201039)pq mod(21201039)n \% (2^{120}*10^{39}) \equiv p*q\ mod(2^{120}*10^{39})
注意的是
n%(21201039)pq,而是pq mod(21201039)n \% (2^{120}*10^{39})\not ={p*q},而是p*q\ mod(2^{120}*10^{39})
所以
pq=k21201039+n%(21201039)p*q=k*2^{120}*10^{39}+n \% (2^{120}*10^{39})

(话说官方那个高低位处理,我还真看不懂,emmmmm,不是太懂这个大数乘法)

然后p*q无法直接分解,可以通过解方程分解
又发现eϕ不互素e与\phi 不互素
可以转换为模QQ下的m
最后通过CRT求解

from Crypto.Util.number import *
from sympy import *
from functools import reduce
n = 18339446336492672809908730785358232636383625709800392830207979464962269419140428722248172110017576390002616004691759163126532392634394976712779777822451878822759056304050545622761060245812934467784888422790178920804822224673755691
M = 36208281423355218604990190624029584747447986456188203264389519699277658026754156377638444926063784368328407938562964768329134840563331354924365667733322
l = 56911058350450672322326236658556745353275014753768458552003425206272938093282425278193278997347671093622024933189270932102361261551908054703317369295189
c = 720286366572443009268610917990845759123049408295363966717060100862857351750759651979922104897091176824666482923148635058966589592286465060161271579501861264957611980854954664798904862706450723639237791023808177615189976108231923
e = 3
a = n % (2**120*10**39)
b = n//(2**240*10**79+1)
for i in range(1000):
for j in range(1000):
if b-i == j*2**120*10**39+a:
pq = b-i
break
print(pq)
p, q = symbols('p q')
res = solve([p*q-pq, (p*2**120*10**39+q)*(q*2**120*10**40+p)-n], [p, q])
p, q = res[1]
PQ = int(str(p << 120)+str(q))
QP = int(str(q << 120)+str(p))
PP = nextprime((PQ >> 190) * (QP & (2 ** 190 - 1)))
QQ = nextprime((QP >> 190) * (PQ & (2 ** 190 - 1)))
N = PP*QQ
def chinese_remainder(n, a):
sum = 0
prod = reduce(lambda a, b: a * b, n)

for n_i, a_i in zip(n, a):
p = prod // n_i
sum += a_i * inverse(p, n_i) * p
return int(sum % prod)
print(GCD(e, PP-1))
m_QQ = pow(c, inverse(e, QQ-1), QQ)
print(long_to_bytes(m_QQ))
print(long_to_bytes(chinese_remainder([l, QQ], [M, m_QQ])))

DASCTF{Ar3_Y0u_Su93_Abt139??}

Misc

png_master

就给了一张png图片,010打开,末尾
Q29uZ3JhdHVsYXRpb25zIG9uIGZpbmRpbmcgdGhlIGZpcnN0IHBhcmFncmFwaCBvZiBmbGFnLCBidXQgdGhlIHVuZGVyc3RhbmRpbmcgb2YgcG5nIGlzIGp1c3QgYmVnaW5uaW5nLgpmbGFnMTpEQVNDVEZ7MmZkOWU5ZmYtZTI3

Congratulations on finding the first paragraph of flag, but the understanding of png is just beginning.
flag1:DASCTF{2fd9e9ff-e27

然后正常来说,lsb应该会考察到,先看一下
观察到Alpha plane7到0都存在异常

flag2:d-5405-c5f5-

利用zsteg看看还有没有其他的信息

[?] 172 bytes of extra data after image end (IEND), offset = 0x3f2dd
[?] 3394 bytes of extra data after zlib stream
extradata:0 .. text: "Q29uZ3JhdHVsYXRpb25zIG9uIGZpbmRpbmcgdGhlIGZpcnN0IHBhcmFncmFwaCBvZiBmbGFnLCBidXQgdGhlIHVuZGVyc3RhbmRpbmcgb2YgcG5nIGlzIGp1c3QgYmVnaW5uaW5nLgpmbGFnMTpEQVNDVEZ7MmZkOWU5ZmYtZTI3"
extradata:1 .. file: zlib compressed data

zsteg -E "extradata:1" flag.png > flag.zlib得到的东西暂时没有用

应该是IDAT块隐写
使用pngcheck查看png图片的IDAT块是否异常

└─$ pngcheck -v '/home/kali/桌面/flag.png' 
File: /home/kali/桌面/flag.png (258953 bytes)
chunk IHDR at offset 0x0000c, length 13
2170 x 1080 image, 32-bit RGB+alpha, non-interlaced
chunk IDAT at offset 0x00025, length 65536
zlib: deflated, 32K window, default compression
chunk IDAT at offset 0x10031, length 65536
chunk IDAT at offset 0x2003d, length 65536
chunk IDAT at offset 0x30049, length 58674
chunk IDAT at offset 0x3e587, length 3394
chunk IEND at offset 0x3f2d5, length 0
additional data after IEND chunk
ERRORS DETECTED in /home/kali/桌面/flag.png

上一个IDAT块数据还未填满就出现下一个,可以知道这段IDAT数据块有问题

保留第五个IDAT块(因为它是人为加进来的),将其他IDAT块都删除并保存,使用到的工具是tweakpng

按道理下一步是要爆破宽高的,但是它crc校验的宽高是正确的,说明不是根据crc值来确定的,不知道怎么搞了
有个自动crc校验宽高工具https://github.com/AabyssZG/Deformed-Image-Restorer
隐写这里,参考了https://www.cnblogs.com/cierra/p/17357133.html

参考这位师傅的wp
https://mumuzi7179.github.io/docs/Blog/CTFWP/DASCTF2024暑期挑战赛#png_master

import zlib
def decompress_data(zip_file, new_file):
zip_file = open(zip_file, 'rb')
new_file = open(new_file, 'wb')
decompress = zlib.decompressobj()
data = zip_file.read(1024)
while data:
new_file.write(decompress.decompress(data))
data = zip_file.read(1024)
new_file.write(decompress.flush())
zip_file.close()
new_file.close()
a = "flag.zlib"
b = "new_flag.zlib"
decompress_data(a, b)

zlib解压,得到size: 750500

然后根据开头的01 80 80 80 00……猜测出这是RGB图像?翻了挺久的资料了,还是没搞懂,但是也知道了这个

color_type字段的值对应于以下PNG颜色类型:
0: 灰度图像
2: 真彩色图像(RGB)
3: 索引彩色图像
4: 灰度图像+α
6: 真彩色图像+α(RGBA)

宽高的计算是这样的

最后


还是存在一些不明白之处的

Web

Sanic’s revenge()

源代码

from sanic import Sanic
import os
from sanic.response import text, html
import sys
import random
import pydash
# pydash==5.1.2

# 这里的源码好像被admin删掉了一些,听他说里面藏有大秘密
class Pollute:
def __init__(self):
pass

app = Sanic(__name__)
app.static("/static/", "./static/")

@app.route("/*****secret********")
async def secret(request):
secret='**************************'
return text("can you find my route name ???"+secret)

@app.route('/', methods=['GET', 'POST'])
async def index(request):
return html(open('static/index.html').read())

@app.route("/pollute", methods=['GET', 'POST'])
async def POLLUTE(request):
key = request.json['key']
value = request.json['value']
if key and value and type(key) is str and 'parts' not in key and 'proc' not in str(value) and type(value) is not list:
pollute = Pollute()
pydash.set_(pollute, key, value)
return text("success")
else:
log_dir = create_log_dir(6)
log_dir_bak = log_dir + ".."
log_file = "/tmp/" + log_dir + "/access.log"
log_file_bak = "/tmp/" + log_dir_bak + "/access.log.bak"
log = 'key: ' + str(key) + '|' + 'value: ' + str(value);
# 生成日志文件
os.system("mkdir /tmp/" + log_dir)
with open(log_file, 'w') as f:
f.write(log)
# 备份日志文件
os.system("mkdir /tmp/" + log_dir_bak)
with open(log_file_bak, 'w') as f:
f.write(log)
return text("!!!此地禁止胡来,你的非法操作已经被记录!!!")


if __name__ == '__main__':
app.run(host='0.0.0.0')