n00bzCTF 2024
Crypto
Vinegar
題目:
Encrypted flag: nmivrxbiaatjvvbcjsf
Key: secretkey
exp:
維吉尼亞密碼
flag:n00bz{vigenerecipherisfun}
RSA
題目:
e = 3 n = 135112325288715136727832177735512070625083219670480717841817583343851445454356579794543601926517886432778754079508684454122465776544049537510760149616899986522216930847357907483054348419798542025184280105958211364798924985051999921354369017984140216806642244876998054533895072842602131552047667500910960834243 c = 13037717184940851534440408074902031173938827302834506159512256813794613267487160058287930781080450199371859916605839773796744179698270340378901298046506802163106509143441799583051647999737073025726173300915916758770511497524353491642840238968166849681827669150543335788616727518429916536945395813
思路:
低加密指數攻擊
exp :
from Crypto.Util.number import *
import gmpy2
e = 3
n = 135112325288715136727832177735512070625083219670480717841817583343851445454356579794543601926517886432778754079508684454122465776544049537510760149616899986522216930847357907483054348419798542025184280105958211364798924985051999921354369017984140216806642244876998054533895072842602131552047667500910960834243
c = 13037717184940851534440408074902031173938827302834506159512256813794613267487160058287930781080450199371859916605839773796744179698270340378901298046506802163106509143441799583051647999737073025726173300915916758770511497524353491642840238968166849681827669150543335788616727518429916536945395813
m = gmpy2.iroot(c, e)[0]
print(long_to_bytes(m))
Vinegar 2
題目:
-
chall.py
alphanumerical = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*(){}_?' matrix = [] for i in alphanumerical: matrix.append([i]) idx=0 for i in alphanumerical: matrix[idx][0] = (alphanumerical[idx:len(alphanumerical)]+alphanumerical[0:idx]) idx += 1 flag=open('../src/flag.txt').read().strip() key='5up3r_s3cr3t_k3y_f0r_1337h4x0rs_r1gh7?' assert len(key)==len(flag) flag_arr = [] key_arr = [] enc_arr=[] for y in flag: for i in range(len(alphanumerical)): if matrix[i][0][0]==y: flag_arr.append(i) for y in key: for i in range(len(alphanumerical)): if matrix[i][0][0]==y: key_arr.append(i) for i in range(len(flag)): enc_arr.append(matrix[flag_arr[i]][0][key_arr[i]]) encrypted=''.join(enc_arr) f = open('enc.txt','w') f.write(encrypted)
-
enc.txt
*fa4Q(}$ryHGswGPYhOC{C{1)&_vOpHpc2r0({
exp:
# 定義字符集
alphanumerical = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*(){}_?'
# 構建矩陣
matrix = []
for i in alphanumerical:
matrix.append([i])
idx = 0
for i in alphanumerical:
matrix[idx][0] = (alphanumerical[idx:len(alphanumerical)] + alphanumerical[0:idx])
idx += 1
# 讀取加密後的檔案
with open('enc.txt', 'r') as f:
encrypted = f.read().strip()
# 定義key
key = '5up3r_s3cr3t_k3y_f0r_1337h4x0rs_r1gh7?'
# 將key轉換為索引陣列
key_arr = []
for y in key:
for i in range(len(alphanumerical)):
if matrix[i][0][0] == y:
key_arr.append(i)
break
# 解密加密後的字串
decrypted_arr = []
for i in range(len(encrypted)):
enc_char = encrypted[i]
key_idx = key_arr[i]
for row in range(len(matrix)):
if matrix[row][0][key_idx] == enc_char:
decrypted_arr.append(matrix[row][0][0])
break
# 將解密後的字元陣列轉換為字串
decrypted = ''.join(decrypted_arr)
# 輸出解密後的flag
print(decrypted)
Random
題目:
I hid my password behind an impressive sorting machine. The machine is very luck based, or is it?!?!?!?
我把密碼藏在一臺令人印象深刻的分揀機後面。這臺機器非常靠運氣,或者是嗎?!?!?!?
#include<chrono>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<string>
#include<fstream>
#include<thread>
#include<map>
using namespace std;
bool amazingcustomsortingalgorithm(string s) {
int n = s.size();
for (int i = 0; i < 69; i++) {
cout << s << endl;
bool good = true;
for (int i = 0; i < n - 1; i++)
good &= s[i] <= s[i + 1];
if (good)
return true;
random_shuffle(s.begin(), s.end());
this_thread::sleep_for(chrono::milliseconds(500));
}
return false;
}
int main() {
string s;
getline(cin, s);
map<char, int> counts;
for (char c : s) {
if (counts[c]) {
cout << "no repeating letters allowed passed this machine" << endl;
return 1;
}
counts[c]++;
}
if (s.size() < 10) {
cout << "this machine will only process worthy strings" << endl;
return 1;
}
if (s.size() == 69) {
cout << "a very worthy string" << endl;
cout << "i'll give you a clue'" << endl;
cout << "just because something says it's random mean it actually is" << endl;
return 69;
}
random_shuffle(s.begin(), s.end());
if (amazingcustomsortingalgorithm(s)) {
ifstream fin("flag.txt");
string flag;
fin >> flag;
cout << flag << endl;
}
else {
cout << "UNWORTHY USER DETECTED" << endl;
}
}
Misc
Addition
題目:
import time
import random
questions = int(input("how many questions do you want to answer? "))
for i in range(questions):
a = random.randint(0, 10)
b = random.randint(0, 10)
yourans = int(input("what is " + str(a) + ' + ' + str(b) + ' = '))
print("calculating")
totaltime = pow(2, i)
print('.')
time.sleep(totaltime / 3)
print('.')
time.sleep(totaltime / 3)
print('.')
time.sleep(totaltime / 3)
if yourans != a + b:
print("You made my little brother cry")
exit(69)
f = open('/flag.txt', 'r')
flag = f.read()
print(flag[:questions])
思路: 很明顯計算對一次就會讀取一個 flag 的值,但是有個問題,延遲的時間呈指數級增長,做 8 個以上的問題很痛苦,我以開始沒注意到,寫了個指令碼一直跑,出不來,最後看了一下題目,發現輸入 -1 可以繞過這個迴圈, print(flag[:-1]) 也可以把 flag 列印出來
exp: 錯誤的
import pwn
import re
import time
p = pwn.remote('24.199.110.35', 42189)
# 接收
bytes = p.recv(1024)
print(bytes)
# 傳送
p.sendline(b'20')
bytes = p.recv(1024)
print(bytes)
# b'what is 8 + 10 = ' 寫個正規表示式匹配 8 + 10 =
# eval_result = re.findall(r'\d+', bytes.decode())
# sum = int(eval_result[0]) + int(eval_result[1])
# print(sum)
for i in range(20):
eval_result = re.findall(r'\d+', bytes.decode())
sum = int(eval_result[0]) + int(eval_result[1])
print(sum)
p.sendline(str(sum).encode())
# time.sleep(1)
bytes = p.recv(1024)
print(bytes)
web
Passwordless
題目:
#!/usr/bin/env python3
from flask import Flask, request, redirect, render_template, render_template_string
import subprocess
import urllib
import uuid
global leet
app = Flask(__name__)
flag = open('/flag.txt').read()
leet=uuid.UUID('13371337-1337-1337-1337-133713371337')
@app.route('/',methods=['GET','POST'])
def main():
global username
if request.method == 'GET':
return render_template('index.html')
elif request.method == 'POST':
username = request.values['username']
if username == 'admin123':
return 'Stop trying to act like you are the admin!'
uid = uuid.uuid5(leet,username) # super secure!
return redirect(f'/{uid}')
@app.route('/<uid>')
def user_page(uid):
if uid != str(uuid.uuid5(leet,'admin123')):
return f'Welcome! No flag for you :('
else:
return flag
if __name__ == '__main__':
app.run(host='0.0.0.0', port=1337)
思路:
看路由 **/<uid>** ,當 uid = uuid.uuid5(leet,'admin123') 時可以 return flag,
學習:
[探索 Python 中的 uuid 模組:生成唯一識別符號_python uuid-CSDN部落格](https://blog.csdn.net/Trb601012/article/details/135744410)
exp:
所以我們本地可以生成這個 uid
import uuid
leet=uuid.UUID('13371337-1337-1337-1337-133713371337')
uid = uuid.uuid5(leet,"admin123")
print(uid)
Rev
Brain
題目:
+++++++++++[<++++++++++>-]<[-]>++++++++[<++++++>-]<[-]>++++++++[<++++++>-]<[-]>++++++++++++++[<+++++++>-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<++>-]<[-]>+++++++++++++++++++++++++++++++++++++++++[<+++>-]<[-]>+++++++[<+++++++>-]<[-]>+++++++++++++++++++[<+++++>-]<[-]>+++++++++++[<+++++++++>-]<[-]>+++++++++++++[<++++>-]<[-]>+++++++++++[<++++++++++>-]<[-]>+++++++++++++++++++[<+++++>-]<[-]>+++++++++++[<+++++++++>-]<[-]>++++++++[<++++++>-]<[-]>++++++++++[<++++++++++>-]<[-]>+++++++++++++++++[<+++>-]<[-]>+++++++++++++++++++[<+++++>-]<[-]>+++++++[<+++++++>-]<[-]>+++++++++++[<++++++++++>-]<[-]>+++++++++++++++++++[<+++++>-]<[-]>++++++++++++++[<+++++++>-]<[-]>+++++++++++++++++++[<++++++>-]<[-]>+++++++++++++[<++++>-]<[-]>+++++++[<+++++++>-]<[-]>+++++++++++[<++++++++++>-]<[-]>+++++++++++++++++[<++++++>-]<[-]>+++++++[<++++++>-]<[-]>+++++++++++[<+++++++++>-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<+>-]<[-]>+++++++++++[<+++>-]<[-]>+++++++++++++++++++++++++[<+++++>-]<[-]
思路:
Brainfuck 解密,解密失敗,說明需要將給的BF轉成python程式碼,
學習:記一次brainfuck的解密思路 - 『脫殼破解區』 - 吾愛破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn
exp:
def shrinkBFCode(code):
cPos2Vars = {} #位置對應的變數
cPos2Change = {} #位置中 + 號 增加的值
varPos = 0
nCode = []
incVal = 0
lc = None
dataChangeOp = set(['+', '-'])
dataShiftOp = set(['>', '<'])
for i in range(len(code)):
c = code[i]
if c not in dataChangeOp and lc in dataChangeOp:
cPos2Change[len(nCode)] = incVal
cPos2Vars[len(nCode)] = varPos
nCode.append('+')
incVal = 0
if c == '>':
varPos += 1
elif c == '<':
varPos -= 1
else:
if c in dataChangeOp:
incVal += 1 if c == '+' else -1
else:
#if lc == '>' or lc == '<':
# cPos2Vars[len(nCode)] = varPos
cPos2Vars[len(nCode)] = varPos
nCode.append(c)
lc = c
return ''.join(nCode), cPos2Vars, cPos2Change
def generatePyCode(shellCode, pVars, pChange):
pyCodes = []
bStacks = []
whileVarCache = {}
for i, c in enumerate(shellCode):
d_pos = i if i not in pVars else pVars[i]
d_change = 1 if i not in pChange else pChange[i]
indentLevel = len(bStacks)
indentStr = ' '*(4*indentLevel)
if c == '[':
pyCodes.append('{}while data[{}] != 0:'.format(indentStr, d_pos))
bStacks.append((c, i))
whileVarCache[i] = {}
elif c == ']':
if bStacks[-1][0] != '[':
raise Exception('miss match of {}] found between {} and {}'.format(bStacks[-1][0], bStacks[-1][1], i))
cNum = i-bStacks[-1][1]
if cNum == 2:
del pyCodes[-1]
del pyCodes[-1]
d_pos_l = i-1 if i-1 not in pVars else pVars[i-1]
pyCodes.append('{}data[{}] = 0'.format(' '*(4*(indentLevel-1)), d_pos_l))
whileCode = shellCode[bStacks[-1][1]+1 : i]
if cNum>2 and '[' not in whileCode and not '%' in whileCode: # nested loop is a bit complicated, just skip
loopCondvar = bStacks[-1][1]
d_pos_l = loopCondvar if loopCondvar not in pVars else pVars[loopCondvar]
whileVars = whileVarCache[bStacks[-1][1]]
cVarChange = whileVars[d_pos_l]
# remove statement of same indent
while len(pyCodes)>0 and pyCodes[-1].startswith(indentStr) and pyCodes[-1][len(indentStr)]!=' ':
pyCodes.pop()
pyCodes.pop()
#del pyCodes[bStacks[-1][1]-i:]
for vPos, vChange in whileVars.items():
if vPos == d_pos_l:
continue
ctimes = abs(vChange / cVarChange)
ctimesStr = '' if ctimes==1 else '{}*'.format(ctimes)
cSign = '+' if vChange > 0 else '-'
pyCodes.append('{}data[{}] {}= {}data[{}]'.format(' '*(4*(indentLevel-1)),
vPos, cSign, ctimesStr, d_pos_l))
pyCodes.append('{}data[{}] = 0'.format(' '*(4*(indentLevel-1)), d_pos_l))
del whileVarCache[bStacks[-1][1]]
bStacks.pop()
elif c == '.':
pyCodes.append('{}print(data[{}])'.format(indentStr, d_pos))
elif c == ',':
pyCodes.append('{}data[{}] = ord(stdin.read(1))'.format(indentStr, d_pos))
elif c == '+':
opSign = '-=' if d_change < 0 else '+='
if pyCodes and pyCodes[-1] == '{}data[{}] = 0'.format(indentStr, d_pos):
pyCodes[-1] = '{}data[{}] = {}'.format(indentStr, d_pos, d_change)
else:
pyCodes.append('{}data[{}] {} {}'.format(indentStr, d_pos, opSign, abs(d_change)))
if bStacks:
whileVarCache[bStacks[-1][1]].setdefault(d_pos, 0)
whileVarCache[bStacks[-1][1]][d_pos] += d_change
elif c == '-':
opSign = '+=' if d_change < 0 else '-='
if pyCodes and pyCodes[-1] == '{}data[{}] = 0'.format(indentStr, d_pos):
pyCodes[-1] = '{}data[{}] = {}'.format(indentStr, d_pos, -d_change)
else:
pyCodes.append('{}data[{}] {} {}'.format(indentStr, d_pos, opSign, abs(d_change)))
if bStacks:
whileVarCache[bStacks[-1][1]].setdefault(d_pos, 0)
whileVarCache[bStacks[-1][1]][d_pos] -= d_change
elif c == '%':
pyCodes.append('{}data[{}] %= data[{}]'.format(indentStr, d_pos, d_pos+1))
return '\n'.join(pyCodes)
s = '>+++++++++++[<++++++++++>-]<[-]>++++++++[<++++++>-]<[-]>++++++++[<++++++>-]<[-]>++++++++++++++[<+++++++>-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<++>-]<[-]>+++++++++++++++++++++++++++++++++++++++++[<+++>-]<[-]>+++++++[<+++++++>-]<[-]>+++++++++++++++++++[<+++++>-]<[-]>+++++++++++[<+++++++++>-]<[-]>+++++++++++++[<++++>-]<[-]>+++++++++++[<++++++++++>-]<[-]>+++++++++++++++++++[<+++++>-]<[-]>+++++++++++[<+++++++++>-]<[-]>++++++++[<++++++>-]<[-]>++++++++++[<++++++++++>-]<[-]>+++++++++++++++++[<+++>-]<[-]>+++++++++++++++++++[<+++++>-]<[-]>+++++++[<+++++++>-]<[-]>+++++++++++[<++++++++++>-]<[-]>+++++++++++++++++++[<+++++>-]<[-]>++++++++++++++[<+++++++>-]<[-]>+++++++++++++++++++[<++++++>-]<[-]>+++++++++++++[<++++>-]<[-]>+++++++[<+++++++>-]<[-]>+++++++++++[<++++++++++>-]<[-]>+++++++++++++++++[<++++++>-]<[-]>+++++++[<++++++>-]<[-]>+++++++++++[<+++++++++>-]<[-]>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++[<+>-]<[-]>+++++++++++[<+++>-]<[-]>+++++++++++++++++++++++++[<+++++>-]<[-]'
shrinkCode, pVars, pChange = shrinkBFCode(s)
res = generatePyCode(shrinkCode, pVars, pChange)
# 將結果寫入檔案,
with open('flag.txt', 'w') as f:
f.write(res)
print(res)
將輸出結果分析一下,就是一直在計算 d[0] 的值,處理一下就好
# 初始化data列表
data = [0, 0]
# 儲存每次data[0]的值
data_values = []
data[1] = 0
data[0] = 0
data[1] += 11
data[0] += 10.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 8
data[0] += 6.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 8
data[0] += 6.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 14
data[0] += 7.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 61
data[0] += 2.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 41
data[0] += 3.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 7
data[0] += 7.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 19
data[0] += 5.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 11
data[0] += 9.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 13
data[0] += 4.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 11
data[0] += 10.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 19
data[0] += 5.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 11
data[0] += 9.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 8
data[0] += 6.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 10
data[0] += 10.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 17
data[0] += 3.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 19
data[0] += 5.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 7
data[0] += 7.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 11
data[0] += 10.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 19
data[0] += 5.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 14
data[0] += 7.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 19
data[0] += 6.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 13
data[0] += 4.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 7
data[0] += 7.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 11
data[0] += 10.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 17
data[0] += 6.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 7
data[0] += 6.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 11
data[0] += 9.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 107
data[0] += data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 11
data[0] += 3.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
data[1] += 25
data[0] += 5.0*data[1]
data_values.append(data[0])
data[1] = 0
data[0] = 0
flag = ""
for i in range(len(data_values)):
flag += chr(int(data_values[i]))
print(flag)
flag: n00bz{1_c4n_c0d3_1n_br41nf*ck!}
Forensics
Plane
題目:
So many plane-related challenges! Why not another one? The flag is the latitude, longitude of the place this picture is taken from, rounded upto two decimal places. Example: n00bz{55.51,-20.27}. Author: NoobMaster Author: NoobMaster
exp:
先下載圖片:
curl https://static.n00bzunit3d.xyz/Forensics/Plane/plane.jpg -o plane.jpg
在檢視圖片資訊
exiftool plane.jpg
Wave
題目:
The Wave is not audible, perhaps corrupted? Note: Wrap the flag in n00bz{}. There are no spaces in the flag and it is all lowercase.
學習:【音訊處理】WAV 檔案格式分析 ( 逐個位元組解析檔案頭 | 相關欄位的計算公式 )_52 49 46 46-CSDN部落格
exp:
先下載這個音訊
curl https://static.n00bzunit3d.xyz/Forensics/Wave/chall.wav -o wave.wav
我們開啟時發現現在被損壞了
010 檢視一下 16進位制,不難發現,標誌位都被換成了 00
修改後,然後播放可以明顯聽到是摩斯電碼,使用線上網站解即可
flag: n00bz{beepbopmorsecode}
Disk Golf
題目:
Let's play some disk golf!
思路:本來想使用 volatility2.6 ,但是無用,想到 fls 工具,就搜尋到 flag
fls disk.img | grep "flag"
-r:遞迴地列出所有檔案和目錄。
-p:顯示檔案的路徑。
在使用 icat 命令讀取資料
flag: n00bz{7h3_l0ng_4w41t3d_d15k_f0r3ns1c5}