解题领红包之二 {Windows 初级题}
https://down.52pojie.cn/dHmjGF.7z | PassWord:vX5lHs8adoRk
运行一下:
>【2023春节】解题领红包之二.exe
Please input password:
hello
Length Error, please try again
Press any key to continue . . .
IDA看一下:
v4 = _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc((int)&dword_4433D0, "Please input password: ");
_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v4);
_ZStrsIcSt11char_traitsIcESaIcEERSt13basic_istreamIT_T0_ES7_RSbIS4_S5_T1_E(&dword_443470, v14);
if ( *(_DWORD *)(v14[0] - 12) == 29 )
{
v13 = 0;
while ( 1 )
{
if ( *(int *)(v14[0] - 12 + 8) >= 0 )
_ZNSs12_M_leak_hardEv(v14);
if ( *(_BYTE *)(v14[0] + v13) != (unsigned __int8)(dword_43F000[v13] >> 2) )
break;
if ( (unsigned int)++v13 >= *(_DWORD *)(v14[0] - 12) )
{
v7 = _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc((int)&dword_4433D0, "Success");
_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v7);
system("Pause");
也就是长度等于29,然后列表dword_43F000的每个元素右移2位和输入比较
写个脚本:
encoded_list = [408, 432, 388, 412, 492, 212, 200, 320, 444, 296, 420, 404, 200, 192, 200, 204, 288, 388, 448, 448, 484, 312, 404, 476, 356, 404, 388, 456, 500]
result = []
for a in encoded_list:
result.append(a >> 2)
result = bytes(result).decode()
print(result)
# flag{52PoJie2023HappyNewYear}
解题领红包之三 {Android 初级题}
https://down.52pojie.cn/nUvaFj.7z | PassWord:zYchSGxanOOx
jadx打开看看,关键逻辑:
key.setText(this$0.decrypt("hnci}|jwfclkczkppkcpmwckng\u007f", 2));
public final String decrypt(String encryptTxt, int i) {
Intrinsics.checkNotNullParameter(encryptTxt, "encryptTxt");
char[] charArray = encryptTxt.toCharArray();
StringBuilder sb = new StringBuilder();
for (char c : charArray) {
sb.append((char) (c - i));
}
String sb2 = sb.toString();
return sb2;
}
写脚本解密即可:
encrypted = "hnci}|jwfclkczkppkcpmwckng\u007f"
result = []
for a in encrypted:
result.append(ord(a) - 2)
result = bytes(result).decode()
print(result)
# flag{zhudajiaxinniankuaile}
解题领红包之四 {Android 初级题}
https://down.52pojie.cn/JfCdrX.7z | PassWord:5dPxREzsOa89
jadx打开,关键逻辑如下:
if (a.B(obj, StringsKt.trim((CharSequence) editText2.getText().toString()).toString())) {
Toast.makeText(this$0, "恭喜你,flag正确!", 1).show();
} else {
Toast.makeText(this$0, "flag错误哦,再想想!", 1).show();
}
// str是UID,str2是flag
public final boolean B(String str, String str2) {
Intrinsics.checkNotNullParameter(str, "str");
Intrinsics.checkNotNullParameter(str2, "str2");
if (!(str.length() == 0 && str2.length() == 0) && StringsKt.startsWith$default(str2, "flag{", false, 2, (Object) null) && StringsKt.endsWith$default(str2, "}", false, 2, (Object) null)) {
String substring = str2.substring(5, str2.length() - 1);
Intrinsics.checkNotNullExpressionValue(substring, "this as java.lang.String…ing(startIndex, endIndex)");
C c = C.INSTANCE;
MD5Utils mD5Utils = MD5Utils.INSTANCE;
Base64Utils base64Utils = Base64Utils.INSTANCE;
String encode = B.encode(str + "Wuaipojie2023");
Intrinsics.checkNotNullExpressionValue(encode, "encode(str3)");
byte[] bytes = encode.getBytes(Charsets.UTF_8);
Intrinsics.checkNotNullExpressionValue(bytes, "this as java.lang.String).getBytes(charset)");
return Intrinsics.areEqual(substring, c.cipher(mD5Utils.MD5(base64Utils.encodeToString(bytes)), 5));
}
return false;
}
public class B {
public static String encode(String str) {
int length = str.length();
char[] cArr = new char[length];
int i = length - 1;
while (i >= 0) {
int i2 = i - 1;
cArr[i] = (char) (str.charAt(i) ^ '5');
if (i2 < 0) {
break;
}
i = i2 - 1;
cArr[i2] = (char) (str.charAt(i2) ^ '2');
}
return new String(cArr);
}
}
public final class C {
public static final C INSTANCE = new C();
private C() {
}
private final char cipher(char c, int i) {
char c2 = Character.isUpperCase(c) ? 'A' : 'a';
return (char) (((char) (((((char) (c - c2)) + (i % 26)) + 26) % 26)) + c2);
}
public final String cipher(String str, int i) {
Intrinsics.checkNotNullParameter(str, "str");
StringBuilder sb = new StringBuilder();
int length = str.length();
for (int i2 = 0; i2 < length; i2++) {
if (Intrinsics.compare((int) str.charAt(i2), 65) >= 0 && Intrinsics.compare((int) str.charAt(i2), 90) <= 0) {
sb.append(cipher(str.charAt(i2), i));
} else if (Intrinsics.compare((int) str.charAt(i2), 97) < 0 || Intrinsics.compare((int) str.charAt(i2), 122) > 0) {
sb.append(str.charAt(i2));
} else {
sb.append(cipher(str.charAt(i2), i));
}
}
String sb2 = sb.toString();
Intrinsics.checkNotNullExpressionValue(sb2, "sb.toString()");
return sb2;
}
}
比较简单的方法应该是在最终比较的时候直接输出计算好的flag
也可以自己看加密逻辑,用脚本重新实现一遍
import base64
from hashlib import md5
uid = "445991"
tmp_str = uid + "Wuaipojie2023"
tmp_str_len = len(tmp_str)
tmp_list = [0] * tmp_str_len
i = tmp_str_len - 1
# 简单的异或
while i >= 0:
i2 = i - 1
tmp_list[i] = ord(tmp_str[i]) ^ ord("5")
if i2 < 0:
break
i = i2 - 1
tmp_list[i2] = ord(tmp_str[i2]) ^ ord("2")
# base64编码,md5哈希
tmp_md5 = md5(base64.b64encode(bytes(tmp_list))).hexdigest()
# 类似凯撒的移位密码,只处理大小写字母
shift_num = 5
result = []
for a in tmp_md5:
ord_a = ord(a)
if (ord_a >= 65 and ord_a <= 90) or (ord_a >= 97 and ord_a <= 122):
if ord_a >= 65 and ord_a <= 90:
the_base_num = 65
else:
the_base_num = 97
tmp = (ord_a - the_base_num + shift_num) % 26 + the_base_num
result.append(tmp)
else:
result.append(ord_a)
result = bytes(result).decode()
result = "flag{" + result + "}"
print(result)
# flag{k88ff9k49321j1i9111gkk8i57h8h56k}
解题领红包之五 {Windows 中级题}
https://down.52pojie.cn/RRxUhX.7z | PassWord:CGSZnTvK0fwB
file type: PE32+ executable (GUI) x86-64, for MS Windows
加壳了
直接调试,异常退出,所以让程序运行起来再附加
MessageBoxW
可以找到dump的地方 0x140001000,dump之后慢慢分析
445991 0x6ce27
1111111122222222333333334444444455555555666666667777777788888888 可以确定flag长度64,而且全部是16进制字符,没有"flag{..}"这种形式
最终比较结果是 "flag{!!!_HAPPY_NEW_YEAR_2023!!!}"
假的的关键逻辑:
__int64 __fastcall real_key_func(__int64 input_key, int uid)
{
unsigned __int64 v2; // kr00_8
int k; // [rsp+20h] [rbp-3A8h]
int j; // [rsp+24h] [rbp-3A4h]
int v6; // [rsp+28h] [rbp-3A0h]
int v7; // [rsp+28h] [rbp-3A0h]
int changed_uid; // [rsp+2Ch] [rbp-39Ch]
int v9; // [rsp+30h] [rbp-398h]
int v10; // [rsp+30h] [rbp-398h]
unsigned int v11; // [rsp+38h] [rbp-390h]
int v12; // [rsp+3Ch] [rbp-38Ch]
int v13; // [rsp+40h] [rbp-388h]
int v14; // [rsp+44h] [rbp-384h]
unsigned int v15; // [rsp+48h] [rbp-380h]
int v16[6]; // [rsp+58h] [rbp-370h] BYREF
int the_content[104]; // [rsp+70h] [rbp-358h] BYREF
int expect_result[104]; // [rsp+210h] [rbp-1B8h] BYREF
v12 = end_point((_WORD *)input_key);
the_copy((__int64)expect_result, 56ui64, (__int64)dword_1400168F0, 56ui64);
*(_WORD *)(input_key + 2i64 * (unsigned int)(v12 - 1)) ^= '}';// 去掉结尾的"}"
v6 = 0xFFFFFFFF;
for ( changed_uid = uid - 1; changed_uid >= 0; changed_uid = 2 * changed_uid + 9 )
;
for ( j = 0; j < 4; ++j )
{
v16[j] = j + 1 + (j + 1) * changed_uid;
*(_WORD *)(input_key + 50 + 2i64 * j) = *(_WORD *)(input_key + 50 + 2i64 * j) + j + 1 - '0';
}
the_copy((__int64)the_content, 56ui64, input_key + 10, 56ui64);// 去掉开头的"flag{"
v9 = 3;
v11 = 0;
for ( k = 0; k < 14; k += 2 )
{
v2 = (unsigned __int64)(unsigned int)the_content[k] << 16;
the_content[k] = v6 ^ (v2 | HIDWORD(v2));
sub_140001D70((unsigned int *)&expect_result[k], v16, changed_uid);
v7 = v6 + 0x11111111;
the_content[k + 1] = v7 ^ (HIWORD(the_content[k + 1]) | (the_content[k + 1] << 16));
v11 = sub_140001D70((unsigned int *)&the_content[k], v16, changed_uid);
v6 = v7 + 0x11111111;
if ( expect_result[k] == the_content[k] )
v14 = 0;
else
v14 = k + 1;
v10 = v14 + v9;
if ( expect_result[k + 1] == the_content[k + 1] )
v13 = 0;
else
v13 = k + 1;
v9 = v13 + v10;
}
if ( v9 == 3 )
v15 = 0;
else
v15 = v11;
return v15;
}
__int64 __fastcall sub_140001D70(unsigned int *a1, _DWORD *a2, int a3)
{
unsigned int v4; // [rsp+0h] [rbp-28h]
unsigned int v5; // [rsp+4h] [rbp-24h]
unsigned int v6; // [rsp+8h] [rbp-20h]
unsigned int i; // [rsp+Ch] [rbp-1Ch]
v4 = *a1;
v5 = a1[1];
v6 = 0;
for ( i = 0; i < 0x20; ++i )
{
v6 += a3;
v4 += (a2[1] + (v5 >> 4)) ^ (v6 + v5) ^ (*a2 + 32 * v5);
v5 += (a2[3] + (v4 >> 4)) ^ (v6 + v4) ^ (a2[2] + 32 * v4);
}
*a1 = v4;
a1[1] = v5;
return v6;
}
// dword_1400168F0经过简单解密是: "!!!!_HAPPY_NEW_YEAR_2023!!!!"
真的关键逻辑:
__int64 __fastcall decrypt_happy_new_year(__int64 key_hex_num, int uid, unsigned int a3)
{
int i; // [rsp+20h] [rbp-188h]
int j; // [rsp+20h] [rbp-188h]
int k; // [rsp+20h] [rbp-188h]
int l; // [rsp+20h] [rbp-188h]
int changed_uid; // [rsp+24h] [rbp-184h]
int v9; // [rsp+28h] [rbp-180h]
int v10; // [rsp+28h] [rbp-180h]
int v11; // [rsp+2Ch] [rbp-17Ch]
int v12; // [rsp+30h] [rbp-178h]
unsigned int v13; // [rsp+34h] [rbp-174h]
int v14; // [rsp+38h] [rbp-170h]
int v15; // [rsp+3Ch] [rbp-16Ch]
int expect_result; // [rsp+40h] [rbp-168h]
char v17; // [rsp+44h] [rbp-164h]
char v18; // [rsp+5Fh] [rbp-149h]
char v19; // [rsp+60h] [rbp-148h]
int v20[52]; // [rsp+B0h] [rbp-F8h]
int with_uid_list[4]; // [rsp+180h] [rbp-28h] BYREF
if ( !key_hex_num )
return 0i64;
v11 = 0x11111111;
for ( i = 0; i < 14; ++i )
{
v20[i] = v11 ^ dword_1400168F0[i];
v11 += 0x11111111;
}
LOBYTE(expect_result) = *((_BYTE *)lpMem + 200);// "flag{"
BYTE1(expect_result) = *((_BYTE *)lpMem + 202);
BYTE2(expect_result) = *((_BYTE *)lpMem + 204);
HIBYTE(expect_result) = *((_BYTE *)lpMem + 206);
v17 = *((_BYTE *)lpMem + 208);
for ( j = 1; j < 27; ++j )
*((_BYTE *)&expect_result + j + 4) = *((_BYTE *)v20 + 2 * j);
v18 = *((_BYTE *)lpMem + 212); // "}"
v19 = 0;
for ( changed_uid = v11 + uid; changed_uid >= 0; changed_uid = 2 * changed_uid + 9 )
;
for ( k = 0; k < 4; ++k )
with_uid_list[k] = (k + 1) * (changed_uid + 1);
v9 = 0;
v15 = 0;
for ( l = 0; l < 7; l += 2 )
{
v15 = sub_1400026E0((unsigned int *)(key_hex_num + 4i64 * l), with_uid_list, changed_uid, a3);
if ( *(&expect_result + l) == *(_DWORD *)(key_hex_num + 4i64 * l) )
v14 = 0;
else
v14 = l + 1;
v10 = v14 + v9;
if ( *(&expect_result + l + 1) == *(_DWORD *)(key_hex_num + 4i64 * (l + 1)) )
v12 = 0;
else
v12 = l + 1;
v9 = v12 + v10;
}
if ( v9 == v15 )
v13 = l >> 1;
else
v13 = 3;
return v13;
}
__int64 __fastcall sub_1400026E0(unsigned int *a1, _DWORD *with_uid_list, int changed_uid, unsigned int a4)
{
unsigned int v5; // [rsp+0h] [rbp-28h]
unsigned int v6; // [rsp+4h] [rbp-24h]
unsigned int i; // [rsp+8h] [rbp-20h]
v5 = *a1;
v6 = a1[1];
for ( i = 0; i < 32; ++i )
{
v6 -= (with_uid_list[3] + (v5 >> 5)) ^ (a4 + v5) ^ (with_uid_list[2] + 16 * v5);
v5 -= (with_uid_list[1] + (v6 >> 5)) ^ (a4 + v6) ^ (*with_uid_list + 16 * v6);
a4 -= changed_uid;
}
*a1 = v5;
a1[1] = v6;
return a4;
}
爆破太慢了,尝试用angr,但缺少dll
所以看看反推,照着样子写个程序:
#include <stdio.h>
#include <Windows.h>
__int64 __fastcall reverse_sub_1400026E0(unsigned int* a1, DWORD* with_uid_list, int changed_uid)
{
unsigned int v5; // [rsp+0h] [rbp-28h]
unsigned int v6; // [rsp+4h] [rbp-24h]
unsigned int i; // [rsp+8h] [rbp-20h]
unsigned int a4 = 0;
v5 = *a1;
v6 = a1[1];
for (i = 0; i < 32; ++i)
{
a4 += changed_uid;
v5 += (with_uid_list[1] + (v6 >> 5)) ^ (a4 + v6) ^ (*with_uid_list + 16 * v6);
v6 += (with_uid_list[3] + (v5 >> 5)) ^ (a4 + v5) ^ (with_uid_list[2] + 16 * v5);
}
*a1 = v5;
a1[1] = v6;
printf("%08x", a1[0]);
printf("%08x", a1[1]);
return a4;
}
int main() {
int uid = 445991;
int changed_uid;
int j;
int k;
int v16[6];
// flag{!!!_HAPPY_NEW_YEAR_2023!!!}
unsigned int expect_result[14] =
{
0x67616c66, 0x2121217b, 0x5041485f, 0x4e5f5950, 0x595f5745, 0x5f524145, 0x33323032, 0x7d212121
};
int the_content[104] = { 0 };
for (changed_uid = uid - 1; changed_uid >= 0; changed_uid = 2 * changed_uid + 9)
;
for (j = 0; j < 4; ++j)
{
v16[j] = (j + 1) * (changed_uid + 1);
}
int tmp;
for (k = 0; k < 7; k += 2)
{
reverse_sub_1400026E0((unsigned int*)&expect_result[k], (DWORD*)v16, changed_uid);
}
getchar();
return 0;
}
结果: ae604f7d36b62afdade349c2abf51409ed32e7c83ce3c70beacbd6dda3bd44e8
解题领红包Web题
xuqi(UID: 445991)
题目共包含 12 个静态 flag: flag1~flag12,另外还需要寻找到 3 个动态 flag: flagA~flagC。
本题总共有 3 个难度,每个难度提交 4 个静态 flag 和 1 个动态 flag 就算通过(如果答对人数较少,我们会在未来二天逐步降低难度,依次减少静态 flag提交的数量,奖励也会依次减少)。
初级难度为 flag1~flag4 与 flagA(当前需要提交所有5个答案,明天可以重新查看本题要求)
提交时,请将 flag 使用空格分隔,提交到对应任务中。
不要被吓到,当做猜灯谜就好了~
提醒:UID 在这里查看:https://www.52pojie.cn/home.php?mod=space&do=profile
仔细查看视频和视频下方的介绍链接获得信息:https://www.bilibili.com/video/BV123411R7K6/
flag1
flag1{52pojiehappynewyear} 直接在视频里
flag2
扫描视频里的二维码得到: https://2023challenge.52pojie.cn/?flag=flag2{878a48f2}
flag5
有电报声音,对应摩斯电码,得到 FLAG5EAIT,整理形式应该是 flag5{eait}
对应关系参考: https://baike.baidu.com/item/摩尔斯电码/1527853
flag6
flag6{**} 是打电话按键声音
看这里 https://www.cnblogs.com/Jlay/p/unctf_2020.html 说可以用dtmf2num直接解出来
我用Audition导出的wav,dtmf2num报错: "Error: only the classical PCM WAVE files are supported"
后来手机录了按键声音,在Audition里对比了一下,得到了6个数字 590124,所以flag: flag6{590124}
flag7
01字符串
"01 1 001 1 001 1 01 1 0001 1 00001 01 1 001 1 1 001 1 0111 011 1 101100 1 1 0 10 1 011 0 01 0000 1 10000 001 1 01 1 0 011 0 00 10 011 0 010 100 1 1011 000 1 1 0 0 11 01111101"
用脚本转换得到flag
import re
one_zero_str = "011001100110110001100001011001110011011101111011001101010110010000110000001101100110001001100101001101100011001101111101"
one_zero_list = re.findall(r".{8}", one_zero_str)
result = ""
for one_zero_item in one_zero_list:
result += chr(int(one_zero_item, 2))
print(result)
# flag7{5d06be63}
flag8
Audition查看频谱图得到flag: flag8{c394d7}
flag11
brainfuck
++++++++++[>++++++++++>++++++++++>+++++>++++++++++++<<<<-]>++.++++++.>---.<-----.>>-..>+++.<+++++.---.+.---.+++++++.<+++.+.>-.>++.
在这里 https://tool.bugku.com/brainfuck/ 解码得到: flag11{63418de7}
flagB
https://2023challenge.52pojie.cn/
在hosts文件里把这个域名解析到主站ip就可以访问了,所以上面的不用手动识别,,
主页源码有注释: "<!-- 提示:你可以去 DNS 中寻找一些信息 -->"
在这里查询 https://uutool.cn/nslookup/ 域名写"2023challenge.52pojie.cn",TXT记录是:
"_52pojie_2023_happy_new_year=flagB{substr(md5(uid+\"_happy_newyear\"+floor(timestamp/600)),0,8)}"
用dig也可以"dig 2023challenge.52pojie.cn TXT"
计算得到flag: flagB{6907f0b7}
flagC
登录提示不是admin,查看cookie
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiI0NDU5OTEiLCJyb2xlIjoidXNlciJ9.itha4Kxj8nxKQ1-GAjdJMLQOLIQOQpGFSWbFYw5b2Tg
中间一段解码是{"uid":"445991","role":"user"},把"user"改成"admin"
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiI0NDU5OTEiLCJyb2xlIjoiYWRtaW4ifQ.itha4Kxj8nxKQ1-GAjdJMLQOLIQOQpGFSWbFYw5b2Tg
替换后刷新得到flag: flagC{b0a37804}
其它的没找到,赛后看了wp,整理一下
flag3
视频的第25秒右下角出了"iodj3{06i95dig}", 凯撒密码,数字不变,字母向前移3位,得到flag: flag3{06f95afd}
flag4
视频制作者GanlvTech的签名"快猜猜这个是什么 ZmxhZzR7OWNiOTExMTd9", base64解码得到flag: flag4{9cb91117}
flag9
视频最后的声音反向可以听出flag: flag9{21c5f8} (我只觉得奇怪,但听不出来)
flag10
首页有01字符串的部分转换过程,加一点脑洞,得到flag: flag10{4a752b}
"""
const FLAG_LINE_A = '|01 1 001 1 001 1 01 1 0001 1 00001 01 1 001 1 1 001 1 0111 011 1 101100 1 1 0 10 1 011 0 01 0000 1 10000 001 1 01 1 0 011 0 00 10 011 0 010 100 1 1011 000 1 1 0 0 11 01111101==========|';
// 这里面藏着两个 flag 哦~
const FLAG_LINE_B = '|++++++++++[>++++++++++>++++++++++>+++++>++++++++++++<<<<-]>++.++++++.>---.<-----.>>-..>+++.<+++++.---.+.---.+++++++.<+++.+.>-.>++.|';
const FLAG_LINE_A2 = FLAG_LINE_A.replaceAll(' ', '');
const FLAG_LINE_A_PARTS = Array.from(FLAG_LINE_A.matchAll(/. ?/g));
"""
import re
FLAG_LINE_A = "01 1 001 1 001 1 01 1 0001 1 00001 01 1 001 1 1 001 1 0111 011 1 101100 1 1 0 10 1 011 0 01 0000 1 10000 001 1 01 1 0 011 0 00 10 011 0 010 100 1 1011 000 1 1 0 0 11 01111101"
FLAG_LINE_A_PARTS = re.findall(". ?", FLAG_LINE_A)
print(FLAG_LINE_A_PARTS)
the_str = ""
for a in FLAG_LINE_A_PARTS:
the_str += str(len(a)-1)
aa = re.findall(r'.{8}', the_str)
result = ''
for a in aa:
result += chr(int(a, 2))
print(result)
# flag10{4a752b}
flag12
视频背景有盲水印,在线工具: http://bigwww.epfl.ch/demo/ip/demos/FFT/
解出flag: flag12{3ac97e24}
flagA
https://2023challenge.52pojie.cn/ 的响应头有:
X-Dynamic-Flag: flagA{Header X-52PoJie-Uid Not Found}
在请求头添加"X-52PoJie-Uid: 445991", 发送后响应头有"X-Dynamic-Flag: flagA{acb3572e} ExpiredAt: 2023-02-06T22:40:00+08:00"