0xGame 2024 re week2 wp
BabyUPX
upx壳,直接upx -d脱壳
ida反编译:
int __cdecl main(int argc, const char **argv, const char **envp)
{
char Str1[60]; // [rsp+20h] [rbp-40h] BYREF
int v5; // [rsp+5Ch] [rbp-4h]
_main(argc, argv, envp);
v5 = 0;
puts("input flag here:");
scanf("%s", Str1);
v5 = strncmp(Str1, "0xGame", 6ui64);
if ( !v5 && strlen(Str1) == 44 )
{
encode(Str1);
if ( !strcmp(Str1, &encdata) )
printf("succeed");
return 0;
}
else
{
printf("invalid");
return 0;
}
}
有一个加密函数encode,将str1传入得到encode
攻击脚本
a = [0x03, 0x87, 0x74, 0x16, 0xD6, 0x56, 0xB7, 0x63, 0x83, 0x46, 0x66, 0x66, 0x43, 0x53, 0x83, 0xD2, 0x23, 0x93, 0x56, 0x53, 0xD2, 0x43, 0x36, 0x36, 0x03, 0xD2, 0x16, 0x93, 0x36, 0x26, 0xD2, 0x93, 0x73, 0x13, 0x66, 0x56, 0x36, 0x33, 0x33, 0x83, 0x56, 0x23, 0x66, 0xD7]
for i in a:
print(chr((i<<4)&0xFF | (i>>4)),end='')
# 0xGame{68dff458-29e5-4cc0-a9cb-971fec338e2f}
需要注意加密过程把二进制的高八位和低八位互换,然而低八位左移溢出,需要限制在八位内,所以 &0xFF
FirstSight-Jar
jadx打开
public class EzJar {
static String Alphabat = "0123456789abcdef";
private static String encrypt(String str) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
int indexOf = Alphabat.indexOf(str.charAt(i));
if (indexOf < 0) {
sb.append(str.charAt(i));
} else {
sb.append(Alphabat.charAt(((indexOf * 5) + 3) % 16));
}
}
return sb.toString();
}
public static void main(String[] strArr) {
System.out.println("请以uuid的格式输入你的flag内容:");
Scanner scanner = new Scanner(System.in);
String nextLine = scanner.nextLine();
scanner.close();
if (encrypt(nextLine).equals("ab50e920-4a97-70d1-b646-cdac5c873376")) {
System.out.println(String.format("验证成功: 0xGame{%s}", nextLine));
} else {
System.out.println("验证失败");
}
}
}
定义了一个加密函数encrypt,加密后在主函数验证
遍历str元素在Alphabat的索引,加密置换str,解密时仍然根据索引还原
攻击脚本
import gmpy2
inv = gmpy2.invert(5, 16)
a = 'ab50e920-4a97-70d1-b646-cdac5c873376'
b = '0123456789abcdef'
flag = ''
for i in a:
index = i.find(b)
if index:
flag += i
else:
flag += chr(((ord(i) - 3 + 16) * inv) % 16)
print(flag)
# ab50e920-4a97-70d1-b646-cdac5c873376
套上0xGame{}即可
FisrtSight-Pyc
提示要用python3.8环境
uncompyle6反编译得到源码
import hashlib
user_input = input("请输入神秘代号:")
if user_input != "Ciallo~":
print("代号不是这个哦")
exit()
input_hash = hashlib.md5(user_input.encode()).hexdigest()
input_hash = list(input_hash)
for i in range(len(input_hash)):
if ord(input_hash[i]) in range(48, 58):
original_num = int(input_hash[i])
new_num = (original_num + 5) % 10
input_hash[i] = str(new_num)
input_hash = "".join(input_hash)
print("0xGame{{{}}}".format(input_hash))
运行一下,输入“神秘代号”Ciallo~
得到结果0xGame{2f5ef5762bf8a2c043d836b522127e54}
然而这个不是flag,猜测反编译结果不准确,在python3.8环境下运行pyc
输入Ciallo~
,得到flag
0xGame{2f0ef0217bf3a7c598d381b077672e09}
Xor::Ramdom
c++编写的PE64位程序,无壳
拖入ida反编译
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rax
char v4; // bl
bool v5; // si
bool v6; // bl
_BYTE *v7; // rdx
char v8; // al
int v9; // ebx
__int64 v10; // rax
__int64 v11; // rax
__int64 v13[4]; // [rsp+20h] [rbp-60h] BYREF
char v14[32]; // [rsp+40h] [rbp-40h] BYREF
char v15[46]; // [rsp+60h] [rbp-20h] BYREF
char v16; // [rsp+8Eh] [rbp+Eh] BYREF
char v17; // [rsp+8Fh] [rbp+Fh] BYREF
char v18[32]; // [rsp+90h] [rbp+10h] BYREF
char v19[32]; // [rsp+B0h] [rbp+30h] BYREF
char v20[39]; // [rsp+D0h] [rbp+50h] BYREF
char v21; // [rsp+F7h] [rbp+77h]
int inited; // [rsp+F8h] [rbp+78h]
int v23; // [rsp+FCh] [rbp+7Ch]
_main(argc, argv, envp);
inited = 0;
v23 = 0;
v21 = 0;
std::allocator<char>::allocator(&v16);
std::string::basic_string(v15, 40i64, 0i64, &v16);
std::allocator<char>::~allocator(&v16);
std::allocator<char>::allocator(&v17);
std::string::basic_string(v14, 32i64, 0i64, &v17);
std::allocator<char>::~allocator(&v17);
v13[0] = 0x1221164E1F104F0Ci64;
v13[1] = 0x171F240A4B10244Bi64;
v13[2] = 0x1A2C5C2108074F09i64;
v13[3] = 0x5A5916111F10i64;
v3 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Input flag here:");
std::ostream::operator<<(v3, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
std::operator>><char>(refptr__ZSt3cin, v15);
v4 = 0;
v5 = 1;
if ( std::string::size(v15) == 38 )
{
std::string::substr(v18, v15, 0i64, 7i64);
v4 = 1;
if ( !std::operator!=<char>(v18, "0xGame{") && *std::string::operator[](v15, 37i64) == '}' )
v5 = 0;
}
if ( v4 )
std::string::~string(v18);
if ( v5 )
exit(0);
std::string::substr(v19, v15, 7i64, 30i64);
std::string::operator=(v14, v19);
std::string::~string(v19);
inited = init_random();
std::string::basic_string(v20, v14);
v6 = check(v20) != 0;
std::string::~string(v20);
if ( v6 )
{
srand(0x1919810u);
inited = rand();
}
v21 = rand();
do
{
v7 = std::string::operator[](v14, v23);
if ( (v23 & 1) != 0 )
v8 = v21;
else
v8 = v21 + 3;
*v7 ^= v8;
v9 = *std::string::operator[](v14, v23);
if ( v9 != *std::array<unsigned char,32ull>::operator[](v13, v23) )
{
v10 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Wrong.Try again");
std::ostream::operator<<(v10, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
exit(0);
}
++v23;
}
while ( v23 <= 29 );
v11 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Right!");
std::ostream::operator<<(v11, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
std::string::~string(v14);
std::string::~string(v15);
return 0;
}
反编译代码看起来有点乱,只需要抓住重点看
这个v21显然是题目提示的随机数,可以爆破随机数,由于随机数种子确定,也可以动调出来
在第67行下一个断点,就可以动调出v21=0x7B
加密部分只有下面这一小部分,v7为数据也就是前面的v13,v23为循环次数
if ( (v23 & 1) != 0 )
v8 = v21;
else
v8 = v21 + 3;
*v7 ^= v8;
攻击脚本
rand = 0x7B
a = [0x0C, 0x4F, 0x10, 0x1F, 0x4E, 0x16, 0x21, 0x12, 0x4B, 0x24, 0x10, 0x4B, 0x0A, 0x24, 0x1F, 0x17, 0x09, 0x4F, 0x07, 0x08, 0x21, 0x5C, 0x2C, 0x1A, 0x10, 0x1F, 0x11, 0x16, 0x59, 0x5A]
for i in range(len(a)):
if i&1:
print(chr(a[i]^rand),end='')
else:
print(chr(a[i]^rand+3),end='')
# r4nd0m_i5_n0t_alw4ys_'Random'!
套上0xGame{}即可
ZzZ
ida反编译进入主函数
__int64 sub_140011AA0()
{
char *v0; // rdi
__int64 i; // rcx
char v3[32]; // [rsp+0h] [rbp-40h] BYREF
char v4; // [rsp+40h] [rbp+0h] BYREF
int v5[8]; // [rsp+44h] [rbp+4h] BYREF
int v6[8]; // [rsp+64h] [rbp+24h] BYREF
int v7[9]; // [rsp+84h] [rbp+44h] BYREF
char *Buffer; // [rsp+A8h] [rbp+68h]
char v9[80]; // [rsp+C8h] [rbp+88h] BYREF
__int64 v10; // [rsp+118h] [rbp+D8h]
__int64 v11; // [rsp+138h] [rbp+F8h]
__int64 v12; // [rsp+158h] [rbp+118h]
__int64 v13[4]; // [rsp+178h] [rbp+138h] BYREF
__int64 v14[26]; // [rsp+198h] [rbp+158h] BYREF
v0 = &v4;
for ( i = 94i64; i; --i )
{
*v0 = -858993460;
v0 += 4;
}
sub_140011393(&unk_140023008);
sub_1400111A9("Please enter your flag\nTip: The flag format is 'uuid'\n");
sub_1400110A0("%44s", v9);
if ( v9[43] != '}' )
goto LABEL_11;
sub_14001128F(v9, "0xGame{%8llx-%4s-%4s-%4s-%12llx}", v13, v5, v6, v7, v14);
v10 = v5[0];
v11 = v6[0];
v12 = v7[0];
if ( v14[0] == 0xD085A85201A4i64 )
{
if ( 11 * v11 + 14 * v10 - v12 == 0x48FB41DDDi64
&& 9 * v10 - 3 * v11 + 4 * v12 == 0x2BA692AD7i64
&& ((v12 - v11) >> 1) + (v10 ^ 0x87654321i64) == 0xCDBDFAAC )
{
Buffer = "Congratulations! You get the correct flag.";
if ( v13[0] == 0xE544267Di64 )
{
puts(Buffer);
goto LABEL_12;
}
}
LABEL_11:
sub_1400112BC(v9);
}
LABEL_12:
sub_14001132F(v3, &unk_14001AED0);
return 0i64;
}
中间if夹了一个连续的方程,这里显然要用z3解,然后根据格式化字符串的格式填入%4s,至于两个十六进制部分,代码直接给出了,只需要注意要小写
from z3 import *
v5,v6,v7 = BitVecs('v5 v6 v7', 64)
solve(
11 * v6 + 14 * v5 - v7 == 0x48FB41DDD,
9 * v5 - 3 * v6 + 4 * v7 == 0x2BA692AD7,
((v7 - v6) >> 1) + (v5 ^ 0x87654321) == 0xCDBDFAAC
)
# [v5 = 842086455, v7 = 1681208161, v6 = 862073908]
from libnum import n2s
v5 = 842086455
v7 = 1681208161
v6 = 862073908
print(n2s(v5)[::-1],n2s(v6)[::-1],n2s(v7)[::-1])
# b'7812' b'44b3' b'a35d'
然后手动连接一下
0xGame{e544267d-7812-44b3-a35d-d085a85201a4}
0 条评论
可输入 255 字