- 2101075ff6b9adc84f9.zip">某乱七八糟选拔赛 main2101075ff6b9adc84f9.zip
- NCTF-2020 re4
- WxyVM1.rar">NCTF-2019 WxyVM1WxyVM1.rar
- Test_your_math.rar">NEFUCTF-2020 Test_your_mathTest_your_math.rar
- notsudoku.zip">VNCTF-2021 notsudoku notsudoku.zip
某乱七八糟选拔赛 main2101075ff6b9adc84f9.zip
拿到文件发现有upx壳,脱壳。
静态分析发现用随机数与flag.png每一字节异或得到flag.png.enc,而随机数种子用的是生成文件的时间戳
查看flag.png.enc生成时间2020-12-18 21:14:01(北京时间)得到时间戳1608297241,然后异或得到文件flag.png
解题脚本
用linux g++编译后运行
#include <stdlib.h>
#include <iostream>
#include <fstream>
using namespace std;
void decrypt(char *a1, int a2){
long long timestamp = 1608297241; //GMT+8 2020-12-18 21:14:01
srand(timestamp);
for (int i = 0; ; ++i)
{
if ( (signed int)i >= a2)
break;
unsigned char v4 = a1[i];
a1[i] = (unsigned long long)rand()^v4;
}
}
int main(){
ifstream infile;
infile.open("flag.png.enc", ios::binary);
infile.seekg(0, ios::end);
int a2 = infile.tellg();// 0x5D9;
infile.seekg(0, ios::beg);
char *a1 = new char[a2];
infile.read(a1, a2);
decrypt(a1,a2);
ofstream outfile;
outfile.open("flag.png");
outfile.write(a1, a2);
}
Flag
flag.png文件
扫一扫得到flag
flag{sRandANd_LCg_is_No_Safty}
NCTF-2020 re4
题目文件 qiandao.rar
脱壳后文件 Dumped.rar
Exeinfo PE打开exe发现有壳,并且打开时提示decode_shell.pdb,得知exe有壳。
题目提示“运行时关闭ida od”,所以先将ida和od关闭后打开exe,再用PE Tools选择exe进程Dump,从而获得脱壳后的exe。
用IDA打开,先复现一次加密函数(代码中的encode),发现(tmp[v1] | v1) & ~(tmp[v1] & v1)为异或运算,反运算后得到flag
解题脚本
byte_B731E8 = [
0xA3, 0x4D, 0x44, 0x7F, 0x53, 0xD6, 0xE9, 0x88, 0x4D, 0x95,
0x1A, 0x72, 0x01, 0x3C, 0x71, 0x00, 0xE8, 0xCE, 0xA1, 0xF8,
0x51, 0x48, 0xF5, 0xE9, 0x6A, 0x02, 0x27, 0xD8, 0x96, 0x7F,
0x72, 0xD6, 0xF1, 0xE9, 0x9F, 0xC6, 0x5D, 0x60, 0xE4, 0x10,
0x64, 0x99, 0xA0, 0x00
]
Dst = [
0x70, 0xDA, 0x19, 0xB3, 0x76, 0x8C, 0x66, 0x69, 0x28, 0xC7,
0xD0, 0x1B, 0x11, 0x77, 0x94, 0xA2, 0x92, 0x1C, 0x51, 0xA3,
0x4A, 0xC4, 0xAB, 0xF8, 0xAA, 0x2F, 0xE9, 0x3B, 0x95, 0x84,
0xEE, 0xCD, 0x55, 0xCB, 0xC1, 0x99, 0xE4, 0xA4, 0x7A, 0x4E,
0xE1, 0x9A, 0x89, 0xC3, 0xF9, 0x41, 0x34, 0x13, 0x57, 0xE5,
0xBB, 0x05, 0x64, 0xC5, 0x5C, 0xB7, 0xBF, 0x79, 0x31, 0x26,
0x47, 0x86, 0x1F, 0xD3, 0xA1, 0xF2, 0xE2, 0x3D, 0x9D, 0xDF,
0x43, 0xE7, 0xF4, 0xA6, 0x67, 0xFD, 0xC9, 0x78, 0x00, 0x98,
0x58, 0x8E, 0xA8, 0xD2, 0xFC, 0x71, 0x6A, 0xC2, 0xF0, 0xB2,
0x0A, 0x6E, 0xBC, 0x6D, 0x48, 0xB8, 0xD8, 0x0E, 0x49, 0x1D,
0x6F, 0xAD, 0x74, 0x91, 0xC6, 0x1E, 0x59, 0x82, 0x45, 0x2B,
0x46, 0xAF, 0x0B, 0xD5, 0x5D, 0x17, 0x8D, 0x6B, 0xB4, 0xDB,
0xB9, 0x09, 0x01, 0xBD, 0xEF, 0x7E, 0x6C, 0x23, 0x65, 0x97,
0x96, 0x72, 0x02, 0x33, 0x3C, 0xB6, 0x53, 0x27, 0x32, 0x24,
0x3E, 0xF3, 0x8B, 0xEA, 0x1A, 0xA9, 0x2C, 0xED, 0xD1, 0x56,
0x18, 0x38, 0x75, 0x52, 0xF7, 0x88, 0x0F, 0xF6, 0x20, 0xE0,
0x50, 0x5F, 0xD9, 0x9C, 0x5A, 0x5E, 0xD6, 0x2D, 0x06, 0x63,
0xFE, 0xBA, 0x35, 0xCC, 0xD7, 0x9E, 0xFB, 0x2A, 0x0C, 0xB1,
0x25, 0x44, 0x87, 0xF5, 0xFA, 0x8A, 0x40, 0xCF, 0x7D, 0xB5,
0x04, 0xC8, 0x60, 0xDC, 0x4D, 0xE3, 0xB0, 0xD4, 0x3F, 0x9B,
0xE8, 0x62, 0xC0, 0xA7, 0xA0, 0x21, 0x4B, 0x4C, 0x7F, 0x2E,
0xEC, 0xCE, 0xDD, 0x03, 0xFF, 0xDE, 0xCA, 0x22, 0x5B, 0x29,
0xF1, 0x39, 0x80, 0x9F, 0x73, 0x42, 0xA5, 0x90, 0x10, 0x0D,
0x81, 0x15, 0xEB, 0x8F, 0x4F, 0x61, 0x54, 0x7C, 0x93, 0x36,
0xAC, 0x68, 0x3A, 0x85, 0x16, 0xE6, 0x7B, 0xBE, 0x30, 0x08,
0x83, 0x37, 0x14, 0x12, 0xAE, 0x07, 0xB9, 0x85, 0xEC, 0xC2,
0xC4, 0xFC, 0xA1, 0x02, 0x59, 0x63, 0x75, 0x76, 0x00, 0x00,
0x00, 0x00, 0x40, 0x63, 0x75, 0x76, 0x20, 0xFD, 0xA1, 0x02,
0x44, 0x89, 0x4F, 0x77, 0x00, 0x00, 0x00, 0x00, 0x2D, 0xE3,
0x51, 0xC6
]
def encode(text):
tmp = [data+1 for data in text];v5 = 0;v6 = 0;v7 = 0;
while True:
v5 = (v5 + 1) % 256;
v8 = Dst[v5];
v6 = (v8 + v6) % 256;
Dst[v5] = Dst[v6];
Dst[v6] = v8;
tmp[v7] ^= Dst[(v8 + Dst[v5])&0xFF];
v7 += 1;
if v7 >= 0x2B: break
v1 = 0;
while True:
v2 = (tmp[v1] | v1) & ~(tmp[v1] & v1);
tmp[v1] = v2;
v1 += 1
if v1 >= 43: break
return tmp
def decode(text):
encode_dict = []; v5 = 0;v6 = 0;v7 = 0;
while True:
v5 = (v5 + 1) % 256;
v8 = Dst[v5];
v6 = (v8 + v6) % 256;
Dst[v5] = Dst[v6];
Dst[v6] = v8;
encode_dict.append(Dst[(v8 + Dst[v5])&0xFF]);
v7 += 1;
if v7 >= 0x2B: break
tmp = [text[i]^i for i in range(len(text))]
v7 = 0x2B-1;
while True:
tmp[v7] ^= encode_dict[v7];
v7 -= 1;
if v7 == 0: break
return tmp
print("".join([chr(data) for data in decode(byte_B731E8)]))
得到flag:flag{Process_Hollowing_with_multithreading}
加壳源码
NCTF-2019 WxyVM1WxyVM1.rar
虚拟机题目,不过当时做题的时候不觉得是虚拟机…很久之前做的题目了,分析过程早忘了,附上个脚本给有需要的人学习一下
WxyVM.py
NEFUCTF-2020 Test_your_mathTest_your_math.rar
静态分析发现flag是一个方程组的解,用sympy解出
解题脚本
from sympy import *
for i in range(11):
if i+1 == 4: continue
exec('v{} = Symbol(\'v{}\')'.format(str(i+1),str(i+1)))
answer = solve([
98 * v3 + 73 * v10 + 86 * (v8 + v5) + 79 * (v2 - v1) - 22 * (v11 + 2 * v9) - 23 * v6 - 81 * v7 -20413,
37 * v9 + 86 * v1 + 31 * v7 + 9 * v10 + 7 * (4 * v3 - v11) + 8 * v6 - 89 * v8 - 11 * v5 + 10 * v2 -2513,
48 * v2 + -70 * v10 - 46 * (v5 + v9) - 88 * v7 - 28 * v3 - 95 * v8 - 81 * v1 - (v11 * 2**6) - 52 * v6 +43184,
56 * v6 + 15 * v11 + 79 * v7 - 91 * v10 + 62 * v3 - 73 * v8 - 34 * v5 + 18 * v2 - 12 * v1 - 32 * v9 +5076,
21 * v11 + 80 * v2 + 51 * v3 + 97 * v10 + -83 * v6 - 14 * (v5 + 7 * v7) - 68 * v8 - 82 * v1 - 32 * v9 +9282,
33 * v2 + 51 * v8 + 14 * (v3 - 7 * v6) - 36 * v10 - 92 * v7 - 60 * v5 - 55 * v1 - 90 * v11 - 94 * v9 +30200,
99 * v3 + 67 * v10 + 97 * v6 - 59 * v7 + 24 * v5 - 22 * v2 - 53 * v1 - 37 * v11 - 15 * v9 - v8 -8225,
77 * v1 + 5 * v8 + 96 * v3 + -72 * v7 - (v10 * 2**6) - 47 * v5 - 97 * v2 + 56 * v6 + 49 * v11 + 78 * v9 +4117,
52 * v6 + 35 * v2 + 43 * v3 + 20 * (v11 - 2 * v8) - 75 * v10 - 8 * v7 - 39 * v5 - 38 * v1 + 53 * v9 +2782,
42 * v9 + 44 * v5 + 39 * v10 + 94 * v6 + 12 * (v3 + 2 * v8) + 10 * (v1 - 3 * v11) - 49 * v7 - 32 * v2 -12417,
],
[v1,v2,v3,v5,v6,v7,v8,v9,v10,v11])
# {v1: 55, v2: 110, v3: 57, v5: 77, v6: 85, v7: 95, v8: 121, v9: 70, v10: 104, v11: 64}
flag = []; index = [9,6,3,2,8,7,5,11,1,10]
for i in range(10):
flag.append(eval("chr(answer[v{}])".format(str(index[i]))))
print("flag{"+"".join(flag)+"}")
得到flag:flag{FU9ny_M@7h}
VNCTF-2021 notsudoku notsudoku.zip
这题看了下官方wp前面步骤都不难(wp在这里可以找到),我接手的时候拿到了个用日文混淆的pynotsudoku_obfu.py
我用编辑器替换一下后,如下
import time, sys, hashlib
class Class:
def __init__(self):
self.a_dict = {}
self.arr1 = []
self.text = ''
self.arr2 = []
self.num = 65
def wrapper(self, key):
def fun(f):
self.a_dict[key] = f
return f
return fun
def get_data(self, key):
return self.a_dict.get(key)
def checkflag(self):
i = 0
while True:
data1 = self.arr1[i][0]
data2 = self.arr1[i][1]
data3 = self.arr1[i][2]
fun = self.get_data(data1)
fun(data2, data3)
i += 1
obj = Class()
@obj.wrapper('a')
def f(a, b):
if a == 1:
obj.arr2 += b
@obj.wrapper('b')
def f(a, b):
if a == 1:
print(obj.text)
else:
if a == 2:
print(obj.arr2)
else:
if a == 3:
print((obj.flag), end='')
else:
print(a, end='')
@obj.wrapper('c')
def f(a, b):
sys.exit()
@obj.wrapper('d')
def f(a, b):
obj.text = input()
@obj.wrapper('e')
def f(a, b):
time.sleep(a)
@obj.wrapper('f')
def f(a, b):
if len(obj.text) % 2 != 0:
sys.exit()
for i in obj.text:
if ord(i) > 52 or ord(i) < 48:
sys.exit()
x = str(hashlib.new('md5', bytes((obj.text), encoding='utf8')).hexdigest())
if x[:6] != 'e3a912':
pass#sys.exit()
obj.flag = x
@obj.wrapper('g')
def f(a, b):
j = 0
for i in range(0, len(obj.text), 2):
j += 1
a = int(obj.text[i])
b = int(obj.text[(i + 1)])
obj.arr2[a][b] = j
@obj.wrapper('h')
def f(a, b):
if obj.arr2[0][1] != 24 or obj.arr2[4][3] != 2:
sys.exit()
if obj.arr2[0][2] != 1 or obj.arr2[2][3] != 20:
sys.exit()
if obj.arr2[1][0] != 23 or obj.arr2[3][4] != 3:
sys.exit()
@obj.wrapper('k')
def f(a, b):
num = 0
if b == -1:
for i in range(5):
num += obj.arr2[a][i]
if num != obj.num:
sys.exit()
else:
for i in range(5):
num += obj.arr2[i][b]
if num != obj.num:
sys.exit()
obj.arr1 = [
[
'b', 'welcome baby~ ', 0],
[
'b', 'input your flag~:', 0],
[
'd', 0, 0],
[
'b', 'your input is:', 0],
[
'b', 1, 0],
[
'b', "let's check......", 0],
[
'e', 0.5, 0],
[
'a', 1, [[0 for i in range(5)]]],
[
'a', 1, [[0 for i in range(5)]]],
[
'a', 1, [[0 for i in range(5)]]],
[
'a', 1, [[0 for i in range(5)]]],
[
'a', 1, [[0 for i in range(5)]]],
[
'f', 0, 0],
[
'g', 0, 0],
[
'h', 0, 0],
[
'k', 0, -1],
[
'k', 1, -1],
[
'k', 2, -1],
[
'k', 3, -1],
[
'k', 4, -1],
[
'k', 0, 0],
[
'k', 0, 1],
[
'k', 0, 2],
[
'k', 0, 3],
[
'k', 0, 4],
[
'b', 'Goodjob!', 0],
[
'b', 'The flag is vnctf{', 0],
[
'b', 3, 0],
[
'b', '}', 0],
[
'c', 0, 0]]
obj.checkflag()
仔细看看就知道是用wrapper写了个虚拟机,将文字作为指令然后调用函数。程序流程是弄了个5x5的数组然后每行或者每列加起来为65,且数组里面1到25每个数字不能重复,最后弄了个md5验证。
解题脚本
直接用z3约束求解然后再每一个md5一下就找到flag,z3的脚本我参考了解数独的脚本
Python Z3约束求解器解决数独问题
from z3 import *
import hashlib
# 约束变元数组,变元名为a_行_列
arr=[[Int('a_%d_%d'%(i,j)) for i in range(5)] for j in range(5)]
# 初始条件,数字表示提示数,0表示未填入
problem=((00,24, 1,00,00),
(23,00,00,00,00),
(00,00,00,20,00),
(00,00,00,00, 3),
(00,00,00, 2,00))
# 数独规则约束
Sudoku = []
Sudoku=[And(arr[i][j]>0,arr[i][j]<=25) for i in range(5) for j in range(5)] # 数字为1~25的整数
for i in range(5):
Sudoku+=[arr[i][0]+arr[i][1]+arr[i][2]+arr[i][3]+arr[i][4]==65]
Sudoku+=[arr[0][i]+arr[1][i]+arr[2][i]+arr[3][i]+arr[4][i]==65]
for i in range(25):
for j in range(5):
for k in range(5):
if int(i/5) == j and i%5 == k: continue
Sudoku+=[arr[int(i/5)][i%5]!=arr[j][k]] # 所有元素不能相等
def SolveSudoku(board):
"""使用Z3约束求解器求解数独,若有解,返回表示可行解的5*5列表;若无解返回None"""
global Sudoku,arr
for i in range(5):
for j in range(5):
if board[i][j]!=0:
Sudoku+=[arr[i][j]==board[i][j]] # 将初始数字作为约束条件添加
s=Solver()
n = 0
s.add(Sudoku)
while(s.check()==sat): # 检查是否有解
#fp=open("log.txt","a",encoding="utf-8")
m=s.model() # 获取解的模型
res=[[m[arr[i][j]] for j in range(5)] for i in range(5)]
#for k in res:
# print(k)
text = ["" for i in range(25)]
for i in range(5):
for j in range(5):
text[m[arr[i][j]].as_long()-1] = str(i)+str(j)
t = "".join(text)
n += 1
output = str(n).zfill(4)+": "+t
print(output)
#fp.write(output+"\n")
#fp.close()
x = str(hashlib.new('md5', bytes(t, encoding='utf8')).hexdigest())
if x[:6] == 'e3a912':
print("Found!",n)
print("The flag is vnctf{%s}"%x)
sys.exit()
s.add(Or(arr[0][0]!=res[0][0],arr[0][1]!=res[0][1],arr[0][2]!=res[0][2],arr[0][3]!=res[0][3],arr[0][4]!=res[0][4],
arr[1][0]!=res[1][0],arr[1][1]!=res[1][1],arr[1][2]!=res[1][2],arr[1][3]!=res[1][3],arr[1][4]!=res[1][4],
arr[2][0]!=res[2][0],arr[2][1]!=res[2][1],arr[2][2]!=res[2][2],arr[2][3]!=res[2][3],arr[2][4]!=res[2][4],
arr[3][0]!=res[3][0],arr[3][1]!=res[3][1],arr[3][2]!=res[3][2],arr[3][3]!=res[3][3],arr[3][4]!=res[3][4],
arr[4][0]!=res[4][0],arr[4][1]!=res[4][1],arr[4][2]!=res[4][2],arr[4][3]!=res[4][3],arr[4][4]!=res[4][4]))
else:
return None # 无解返回None
SolveSudoku(problem)
'''
......
4640: 02433420112112034430403122130414004132233324100142
Found! 4640
The flag is vnctf{e3a912c1e911ad82544af0c3d753f44f}
'''
第一次做这种限制md5的题目,最后爆了一段时间(大概半小时)才爆出来