Skip to main content

学校ctf训练赛的wp

前言

一次为期十天的训练赛,检验了前段时间所学,也认识了很多不足~~~有2题好像好简单但没啥头绪,到后面心态也没前几天那么好了,有、、浮躁,基本都没怎么做题,还要努力呀

MISC

Checkin

linux下命令行strings 文件名 即得flag

图片中的密码

隐写,binwalk得加密的压缩包,密码在注释中,解压 即得flag

Lsb

Lsb低位隐写,stegsolve看一下图片的低位通道

确定为红绿蓝0通道;data extract得到504b开头的一堆东西,猜测为压缩包

另存为、解压即得flag

Fakenews

1.伪加密,修改即可,得到docx文件

2.binwalk将docx文件分离

打开文件document即得flag(为了避免直接搜索flag还去掉了f~~~)

Hackmeok

下载得一个虚拟盘,打开有一txt文件内容如上,提示删掉了视频,flag是中文和标点符号

winhex修复视频文件

得到这个视频

截图一下

-..----.--...../--..--...-.----/-..----.--.-...-/-..---.....--.-/-..---.-....--./--...-....-...-/---.--.-....-../--------....--../-.-.-..--..-.../-.-.-..--..-.../-.-.-..--..-.../-.-.-..--..-.../-.-.-..--..-.../--------.......-

找个中文摩斯网站解密一下得到flag:

生命是有光的

得到压缩包,提示解压密码为6位小写字母

爆破太久,看一下文件名,结合题目名猜测为:iloveu

解压即得图片

binwalk分析不出隐藏文件,hxd看一下发现是存在zip压缩包的,但出题人将504b后的两个十六进制数调换了位置,我们换回来就可以了

得到的压缩包中其实有两个文件,但另一个password.txt只有504b0102开头的串,也就是说在压缩包中是看不到他的名字的

当时我打算foremost看能不能爆一下内容,不行再手动改压缩包

foremost结果:

显然password.txt没用,只是提示咱们这个压缩包是伪加密,0900改成0000即得flag文件!

这个格式是MP3,改一下后缀名即可

得到了一个夹杂着英语听力和嗨歌的mp3文件,使劲听qaq,不过最后还是求助了学长才得flag,听的人麻了,还把高中班长拉来一起折磨~~~

提示flag为六个单词:flag{it's_really_fun_to_compress_data}

REVERSE

Easyreverse

如图~~

Easyc

提供了一个exe文件和pass

Pass:也就是flag加密后的结果103107097096122048104048113086048116095109053116116094066086119052114126094116049108114056050088067088109102110056119104056098095119115055103115099100124

程序是用c写的,IDAf5看一下伪代码

主函数:

加密函数:

分析可知: 1.输入学长的学号:1707170129,才能进行下一步的加密操作 2.输入要加密的字符串,程序就会输出加密后的字符串 所以我们的目的是利用给出的加密字段和加密函数,求得加密前的flag

对程序和pass分析可知: 1.三位数字代表一个字符,则flag{xxxx}(包含flag{}共51个字符) 2.a1=v6也就是flag;a2=str1也就是学号1707170129 3.加密函数中: v7=flag,str=学号1707170129,v6=10(学号的长度)

For循环(i--flag长度): v5=学号[i%10] - 48;

Sprintf:将格式化的字符串写入v4最后输出,将原本一个字符转换为3个数字输入的v4中。 格式化方法:v5^v7[i];由此可知还原方法:每三位数与V5亦或 求各个字符的v5

即得v5

再写个小脚本跑跑即得flag

a = [103,107,97,96,122,48,104,48,113,86,48,116,95,109,53,116,116,94,66,86,119,52,114,126,94,116,49,108,114,56,50,88,67,88,109,102,110,56,119,104,56,98,95,119,115,55,103,115,99,100,124]
b = [1,7,0,7,1,7,0,1,2,9,1,7,0,7,1,7,0,1,2,9,1,7,0,7,1,7,0,1,2,9,1,7,0,7,1,7,0,1,2,9,1,7,0,7,1,7,0,1,2,9,1]
l = 0
for i in a:
x = chr(i^b[l])
l+=1
print(x,end='')

CRYPTO

Case64?

给出Case64的加密py源码(我在后面加了注释)

C64_TABLE = [
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '_', '?'
]

def encrypt(s: str):
bits = "".join(bin(byte)[2:].zfill(8) for byte in bytes(s.encode('utf8')))[::-1]#逆序输出s的二进制形式
length = len(bits)#求输入的长度

for count in range(length - 1):#n个字符执行8*n次
bits = bits[:count] + str(int(bits[count]) ^ int(bits[count+1])) + bits[count + 1:]#将每个二进制与其后的一个字符异或再拼接
for i in range(11):
bits = (bits[-1]+bits[:-1])[::-1]#将最末端的bit提到最前端,再逆序

left = ""
right = ""
for i in range(length):#偶数位包括0 进入left 奇数位进入right
if(not i % 2):
left += bits[i]
else:
right += bits[i]

data = right[:len(right)//2] + "".join(str(int(byte1) ^ int(byte2)) for byte1, byte2 in zip(left, right)) + right[len(right)//2:]
#//向前取整,data=right左半+left与right异或+right右半

data = data + "".join(str(byte % 2) for byte in range(6-len(data) % 6))
#data = data + byte%2(即取二进制)(byte=range(6-data长度%6))

return "".join(C64_TABLE[int(data[i*6:(i+1)*6], 2)] for i in range(len(data)//6))
#将data以6位二进制为一组,转为十进制即为在C64中的下标

if __name__ == '__main__':
flag="flag{???}"
print(encrypt(flag))

# result -> _b1QZYJ5GGEjL?ghMbY6GzV3mCuPABc7t_m3S_tTm532vQleV

#111110011011110101010000011001011000001001111001000110000110000100100011001011111111100000100001001100011011011000111010000110110011010101110111100110000010101110001111000000000001011100111011101101111110100110110111010010111110101101010011100110111001110111110110101111010000100101011110

由此即可知解密方法:

1.将data以6位二进制为一组,转为十进制即为在C64中的下标 转为数组下标 62,27,53,16,25,24,9,57,6,6,4,35,11,63,32,33,12,27,24,58,6,51,21,55,38,2,46,15,0,1,28,59,45,62,38,55,18,62,45,19,38,57,55,54,47,16,37,30,21

再转为二进制 111110011011110101010000011001011000001001111001000110000110000100100011001011111111100000100001001100011011011000111010000110110011010101110111100110000010101110001111000000000001011100111011101101111110100110110111010010111110101101010011100110111001110111110110101111010000100101011110 010101

2.range(6-原长度%6) 减去多出的长度:6-data长度%6 设原长度为x;则现长度 294=x+(6-x%6)

6-x%6=6/5/4/3/2/1

294=x+6/5/4/3/2/1

x=288/289/290/291/292/293 x=288√、289X、290√、291x、292√、293x

故x=288/290/292(这里从288开始试,直接能得到flag)

right= left=bin(int('',2)^int('',2))

288=>144=>72 111110011011110101010000011001011000001001111001000110000110000100100011 001011111111100000100001001100011011011000111010000110110011010101110111100110000010101110001111000000000001011100111011101101111110100110110111 010010111110101101010011100110111001110111110110101111010000100101011110

right=111110011011110101010000011001011000001001111001000110000110000100100011010010111110101101010011100110111001110111110110101111010000100101011110 left =bin(int('111110011011110101010000011001011000001001111001000110000110000100100011010010111110101101010011100110111001110111110110101111010000100101011110',2)^int('001011111111100000100001001100011011011000111010000110110011010101110111100110000010101110001111000000000001011100111011101101111110100110110111',2)) =110101100100010101110001010101000011010001000011000000110101010001010100110100111100000011011100100110111000101011001101000010101110000011101001

3.向前取整,data=right左半+left与right异或+right右半 =>求得left 288 right=111110011011110101010000011001011000001001111001000110000110000100100011010010111110101101010011100110111001110111110110101111010000100101011110 left =110101100100010101110001010101000011010001000011000000110101010001010100110100111100000011011100100110111000101011001101000010101110000011101001

4.偶数位包括0 进入left 奇数位进入right

bits=""
left = ""
right = ""
l=0
r=0
for i in range(len(left)+len(right)): # 偶数位包括0 进入left 奇数位进入right
if(not i % 2):
bits += left[l]
l+=1
else:
bits += right[r]
r+=1
print(bits)

288 111101110110100101100101011100110011101100000010001101100011000101001010001001000011010101001011000000010100101000110110001000010010011000100101101100100100111111110100010001011011001110100101110000111100111111000001110110011111010110110110010001011101100110101000010000011011100111010110

5.原:将最末端的bit提到最前端,再逆序,(bits[-1] + bits[:-1])[::-1]

现:先逆序,再将最前端放到最后端 逆序:bits = bits[::-1] 将最前端放到最后端:bits = bits[2:len(bits)] + bits[0]

for i in range(11):
bits = bits[::-1]
bits = bits[1:len(bits)] + bits[0]
  1. 原:由前面开始,将每个二进制与其后的一个字符异或再拼接

现:由后面开始,将每个二进制与其后一个字符异或再拼接

for count in range(len(bits)-1, 0, -1):
bits = bits[:count-1] + str(int(bits[count-1]) ^ int(bits[count])) + bits[count:]

综合5、6即得

for count in range(len(bits)-1, 0, -1):
for i in range(11):
bits = bits[::-1]
bits = bits[1:len(bits)] + bits[0]
bits = bits[:count-1] + str(int(bits[count-1]) ^ int(bits[count])) + bits[count:]
print(bits[::-1], "\n")

最终: 011001100110110001100001011001110111101101000011001101100011010001011111001100010011010101011111010000000101111100110110001100000111001000110001011011100011100101011111001100110110111001100011011100100111100101110000011101000101111101101101001100110111010001101000001100000110010001111101

转换ascii得flag{C6415@_60r1n9_3ncrypt_m3th0d}

Decode

0x253444253534253431253739253439253434253435253737253446253433253431253335253445253739253431253738253444253434253444253637253444253534253439253741253439253434253435253737253445253639253431253738253444253534253633253637253444253534253435253331253439253434253435253738253445253639253431253738253444253434253431253637253444253534253431253738253439253434253642253335253439253434253435253738253444253533253431253738253444253434253431253637253444253534253431253738253439253434253435253739253445253531253344253344(16进制)

%4D%54%41%79%49%44%45%77%4F%43%41%35%4E%79%41%78%4D%44%4D%67%4D%54%49%7A%49%44%45%77%4E%69%41%78%4D%54%63%67%4D%54%45%31%49%44%45%78%4E%69%41%78%4D%44%41%67%4D%54%41%78%49%44%6B%35%49%44%45%78%4D%53%41%78%4D%44%41%67%4D%54%41%78%49%44%45%79%4E%51%3D%3D(url)

MTAyIDEwOCA5NyAxMDMgMTIzIDEwNiAxMTcgMTE1IDExNiAxMDAgMTAxIDk5IDExMSAxMDAgMTAxIDEyNQ==(base64)

102 108 97 103 123 106 117 115 116 100 101 99 111 100 101 125(ascii)

flag{justdecode}

Ilovebacon

-- --- .-. ... . ..--.- .. ... ..--.- -.-. --- --- .-.. ..--.- -... ..- - ..--.- -... .- -.-. --- -. ..--.- .. ... ..--.- -.-. --- --- .-.. . .-. ..--.- .- .- -... .- -... .- .- .- .- .- .- .- -... -... -... -... .- -... .- -... .- .- .- .- .- .- -... -... -... .- .- .- .- -... -... .- .- .- .- .- .- -... .- -... -... .- .- -... -... .- .- .- .- .- .- .- .- -... .- .- .- .- -... -... .- .- -... -... -... .- .- .- .- -... -... -... -... .- .- .-(摩斯)

morse_is_cool_but_bacon_is_cooler_aababaaaaaaabbbbababaaaaaabbbaaaabbaaaaaababbaabbaaaaaaaabaaaabbaabbbaaaabbbbaaa

Aababaaaaaaabbbbababaaaaaabbbaaaabbaaaaaababbaabbaaaaaaaabaaaabbaabbbaaaabbbbaaa =》 fahvaodalgaegody(培根) =》 flaghaveagoodday(栅栏) flag{haveagoodday}

RSA

得到n 解出p、q 利用脚本:(f=x,x取值为三段密文的十进制)

import gmpy2
p = 325045504186436346209877301320131277983
q = 302825536744096741518546212761194311477
e = 65537
f = x
n = p * q
fn = (p - 1) * (q - 1)
d = gmpy2.invert(e, fn)
h = hex(gmpy2.powmod(f, d, n))[2:]
if len(h) % 2 == 1:
h = '0' + h
print (d)
print (h)

(m1)5077560311513279671817430508125151837396585328082180175253360345086848717946 (m2)70099856477856647119324475779448956753505959373194081911451122574748717928011 (m3)6793000449683458761243147198477390385097096925500467689087326832717298959098

最后拼接解出的可打印字符即得flag{3b6d3806-4b2b-11e7-95a0-000c29d7e93d}

WEB

PHP1

重置了__wakeup()函数 #反序列化时触发,传入参数应为序列化 $this->password = $nobodyknow; #password始终等于nobodyknow,password值无意义 Private #private属性序列化的时候格式是%00类名%00成员名; #protected属性序列化的时候格式是 %00*%00成员名 === Hint:引用& #这两个对象变量一定要指向某个类的同一个实例(即同一个对象)

在php中,引用a=&b;实际是同一个内容有a和b两个别名;而不是像c语言一样的指针

也就是说利用引用&将nobodyknow的值传递给varify 类属性赋值:php中类的属性声明时赋值一定是一个直接的值,不能是函数返回值,表达式,以及通过"."连接起来的字符串,如果偏要用这些赋值,可以通过构造函数__construct(); ——也就是说如varify=&password或者&nobodyknow的语法是错误的

如果在 foreach 语句中给一个具有引用的变量赋值,被引用的对象也被改变。

  • 1.类属性仅允许使用以下类型的数据进行初始化
  • 标量和数组字面量:字符串,数值,常量,数组,原型文档(php5.3+)
  • 2.不允许使用:变量,表达式,对象
  • 3.类常量使用关键字const声明,不允许设置访问限制符,强制为public,不能更改
  • 4.类常量是属性类的,不属性它的某个实例对象,必须使用类才可以访问
  • 5.访问类常量要使用范围解析符::,双冒号
  • 在类中使用关键字self表示当前类,在外部可直接使用类名

serialize() 可处理除了 resource 之外的任何类型。甚至可以 serialize() 那些包含了指向其自身引用的数组。serialize() 的数组/对象中的引用也将被存储。

O:5:"funny":2:{s:15:"%00funny%00password";s:1:"2";s:6:"verify";r:1;} ”you die” QAQ R为指针引用,将两个属性指向同一指针地址 Poc:O:5:"funny":2:{s:15:"%00funny%00password";R:1;s:6:"verify";R:1;} 即得:GXUCTF{thr33_eq4@15_5i9n_i5_s0_e@sy}

PHP2

调用pyflag()即可 @unserialize($_GET['try'])(); @表示无回显,因此有了开头的报错定义需要我们反序列化 目标:通过传入序列化参数使@unserialize($_GET['try'])();反序列化成为funny::pyflag(); 原有();固需要传入的参数为:funny::pyflag;序列化后得到

poc:s:13:"funny::pyflag";

Easynodejs

考点是 nodejs的原型链污染

题目如下:

通过传参row、key、value赋值morouu[row][key]=value

使得判断条件yhck[‘money’] === 100000000000为真;输出flag

Poc:?row=__proto__&key=money&value=100000000000

即得flag:GXU-CTF{Wow_No1dejs_is_s0_interesting}