n00bzCTF 2024

Yolololololo發表於2024-09-07

n00bzCTF 2024

Crypto

Vinegar

題目:

Encrypted flag: nmivrxbiaatjvvbcjsf
Key: secretkey

exp:

維吉尼亞密碼

image-20240803213429-3gxhu0y

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 列印出來

image-20240805235532-qzmqkzx

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)

思路:

看路由  **/&lt;uid&gt;**  ,當 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)

image-20240805234610-o4a24xu

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

image-20240806004346-55ar9na

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

我們開啟時發現現在被損壞了

image-20240806004937-62ujmug

010 檢視一下 16進位制,不難發現,標誌位都被換成了 00

image-20240806161816-n8zfbva

修改後,然後播放可以明顯聽到是摩斯電碼,使用線上網站解即可

image-20240806162436-5ec1aj5

image-20240806163319-2og40bd

flag: n00bz{beepbopmorsecode}

Disk Golf

題目:

Let's play some disk golf!

思路:本來想使用 volatility2.6 ,但是無用,想到 fls 工具,就搜尋到 flag

fls disk.img | grep "flag"

-r:遞迴地列出所有檔案和目錄。

-p:顯示檔案的路徑。

image-20240807023220-f9uz68x

在使用 icat 命令讀取資料

image-20240807023612-uodhfgu

image-20240807024431-k2n9sjh

flag: n00bz{7h3_l0ng_4w41t3d_d15k_f0r3ns1c5}