暗泉杯Writeup

Re

Signin

flag{REVERSE_1s_Very_3asy!}

happyCTF

s = 'rxusoCqxw{yqK`{KZqag{r`i'
for i in s:
print(chr(ord(i)^0x14),end='')
#flag{Welcome_to_Neusoft}

Remember Crypt 4

RC4加密

# cryto
key = [0x7f, 0x64, 0x99, 0xd0, 0x9, 0x57, 0x81, 0xd2, 0x78, 0x2c, 0xfc, 0xde, 0xdc, 0x89, 0x4c, 0x3b, 0xb4, 0xf5, 0x90, 0x2b, 0x70, 0x11, 0x10, 0xf, 0xe, 0x3e, 0xc, 0x67, 0x6d, 0x91, 0xb2, 0x18, 0x0, 0xdf, 0x75, 0xf9, 0x27, 0x96, 0xe1, 0x15, 0xf0, 0x45, 0xc2, 0x2d, 0x97, 0x38, 0x55, 0xb1, 0x69, 0x87, 0x61, 0xef, 0x50, 0xa6, 0x43, 0x25, 0x93, 0xe0, 0x47, 0xac, 0x98, 0x19, 0xed, 0x4d, 0x60, 0x4a, 0xbd, 0xdb, 0xe8, 0x1a, 0x86, 0x5, 0xe5, 0x92, 0x46, 0x24, 0xd3, 0xf3, 0xf6, 0xc3, 0xfa, 0x3f, 0xb0, 0x1e, 0x17, 0x30, 0x9e, 0x1b, 0x54, 0x1c, 0xfd, 0xa1, 0x13, 0x85, 0x76, 0x29, 0xd6, 0xc9, 0xca, 0x6e, 0x2a, 0xe3, 0x7b, 0x5d, 0x8e, 0x9f, 0x6f, 0x26, 0x20, 0x8b, 0x3, 0x8d, 0x12, 0xaa, 0x37, 0x71, 0x4f, 0xee, 0x84, 0xaf, 0x52, 0x2, 0xcf, 0x6, 0x33, 0x14, 0x5e, 0x31,
0x6c, 0xd7, 0xa5, 0x51, 0xf1, 0x44, 0x34, 0xb6, 0x8, 0x74, 0x7, 0xa7, 0x5f, 0x9d, 0xda, 0xfe, 0xd5, 0xdd, 0x35, 0x65, 0x7e, 0xba, 0xe9, 0xa2, 0xc7, 0xce, 0xe2, 0xa3, 0x9b, 0x22, 0xff, 0xc8, 0x77, 0xa4, 0x8f, 0xcc, 0xe7, 0xb, 0xe6, 0xbf, 0x5a, 0x39, 0xb9, 0x63, 0x4, 0xe4, 0xbe, 0xb8, 0x80, 0xa, 0x88, 0x49, 0x5b, 0x7a, 0x5c, 0xa8, 0xcb, 0xeb, 0xad, 0x16, 0xd4, 0x21, 0xc6, 0x95, 0xc4, 0x28, 0x56, 0xb7, 0x68, 0x6a, 0xd1, 0x9c, 0x4b, 0x58, 0x9a, 0xb5, 0xae, 0x1f, 0x94, 0x7d, 0xec, 0x62, 0xc1, 0x8a, 0x32, 0x53, 0x3c, 0x7c, 0x4e, 0xbb, 0x40, 0xf7, 0x2e, 0x59, 0x6b, 0x79, 0xd9, 0xa9, 0x82, 0xc5, 0xfb, 0x23, 0xb3, 0xf2, 0x72, 0x83, 0xea, 0xab, 0x1, 0xd, 0xa0, 0x73, 0xc0, 0x41, 0xf4, 0x3d, 0x42, 0x2f, 0x3a, 0x8c, 0xf8, 0xcd, 0x1d, 0x36, 0x66, 0x48, 0xd8, 0xbc]
# s盒打乱后
key2 = [188, 197, 18, 125, 133, 35, 132, 113, 123, 57, 40,
2, 211, 81, 243, 44, 137, 43, 166, 44, 175, 9, 34, 34] # 异或后的
key3 = []
v3 = 0
v4 = 0
v6 = 0
s = ""
for v3 in range(len(key2)):
v3 += 1
v6 = key[v3]
v4 = (v6+v4) % 256
key[v3] = key[v4]
key[v4] = v6
key3.append(key[(key[v3]+v6) % 256])
for i in range(len(key2)):
key2[i] ^= key3[i]
for i in key2:
s += chr(i)
print(s)

# flag{nice_to_meet_you}nm

EasyRe

信号量的题目之前没见过,

相关信号量的函数

一、sigqueue函数

功能:新的发送信号系统调用,主要是针对实时信号提出的支持信号带有参数,与函数sigaction()配合使用。
原型:int sigqueue(pid_t pid, int sig, const union sigval value);
参数:
sigqueue的第一个参数是指定接收信号的进程id,第二个参数确定即将发送的信号,第三个参数是一个联合数据结构union sigval,指定了信号传递的参数,即通常所说的4字节值。
返回值:成功返回0,失败返回-1

二、__sighandler_t signal(int signum, __sighandler_t handler);
参数
signal是一个带signum和handler两个参数的函数,准备捕捉或屏蔽的信号由参数signum给出,接收到指定信号时将要调用的函数由handler给出,handler这个函数必须有一个int类型的参数(即接收到的信号代码),它本身的类型是void
handler也可以是两个特殊值:SIG_IGN 忽略该信号;SIG_DFL 恢复默认行为

sigaction 结构体定义如下

struct sigaction {
void (*sa_handler) (int);
sigset_t sa_mask;
int sa_flags; // 用来设置信号处理的相关操作
void (*sa_restorer) (void);
}

分析题目

题目中使用的是 SA_SIGINFO,对信号处理程序提供了附加信息:一个指向 siginfo 结构的指针以及一个指向上下文标识符的指针

主程序中,为 2 信号注册了一个处理函数,这个函数是用于对最终加密结果进行判断的,随后进行了一个初始化,接下来进入一个死循环,等待子程序发送 2 信号

根据return sub_400A0D(&unk_4019C0, s1);第一个参数是vm的指令码,s1是输入的 flag

这个函数是由 while 循环和 switch 语句实现的

大致分为三类

第一类

case 0:
v3 = getppid();
sigqueue(v3, 34, (const union sigval)v42);
break;
通过上面的可知
v42 = s1 + 79; // v42为全局变量传参

第二类

case 1:
val = qword_6030C8 + 16;
v4 = getppid();
sigqueue(v4, 34, (const union sigval)val);
break;
case 2:
vala = qword_6030C8 + 17;
v5 = getppid();
sigqueue(v5, 34, (const union sigval)vala);
break;
case 3:
valb = qword_6030C8 + 18;
v6 = getppid();
sigqueue(v6, 34, (const union sigval)valb);
break;

猜测 qword_6030C8 +16 ,qword_6030C8+17,qword_6030C8+18 为不同的寄存器

第三类

case 21:
v24 = getppid();
kill(v24, 46);
break;

只有kill,该类只传递了全局变量

int sub_40144B()
{
struct sigaction v1; // [rsp+0h] [rbp-140h] BYREF
struct sigaction v2; // [rsp+A0h] [rbp-A0h] BYREF

sigemptyset(&v2.sa_mask);
v2.sa_handler = (__sighandler_t)sub_400E1D;
v2.sa_flags = 4;
sigaction(34, &v2, &v1);
sigemptyset(&v2.sa_mask);
v2.sa_handler = (__sighandler_t)sub_400E78;
v2.sa_flags = 4;
sigaction(35, &v2, &v1);
v2.sa_handler = (__sighandler_t)sub_400ED7;
v2.sa_flags = 0;
sigaction(36, &v2, &v1);
sigemptyset(&v2.sa_mask);
v2.sa_handler = (__sighandler_t)sub_400F16;
v2.sa_flags = 4;
sigaction(37, &v2, &v1);
v2.sa_handler = (__sighandler_t)sub_400F67;
v2.sa_flags = 0;
sigaction(38, &v2, &v1);
sigemptyset(&v2.sa_mask);
v2.sa_handler = (__sighandler_t)sub_400FA8;
v2.sa_flags = 4;
sigaction(39, &v2, &v1);
v2.sa_handler = (__sighandler_t)sub_400FFB;
v2.sa_flags = 0;
sigaction(40, &v2, &v1);
v2.sa_handler = (__sighandler_t)sub_40103A;
v2.sa_flags = 0;
sigaction(41, &v2, &v1);
sigemptyset(&v2.sa_mask);
v2.sa_handler = (__sighandler_t)sub_401089;
v2.sa_flags = 4;
sigaction(42, &v2, &v1);
v2.sa_handler = (__sighandler_t)sub_4010EA;
v2.sa_flags = 0;
sigaction(43, &v2, &v1);
sigemptyset(&v2.sa_mask);
v2.sa_handler = (__sighandler_t)sub_40113A;
v2.sa_flags = 4;
sigaction(44, &v2, &v1);
sigemptyset(&v2.sa_mask);
v2.sa_handler = (__sighandler_t)sub_40116C;
v2.sa_flags = 4;
sigaction(45, &v2, &v1);
v2.sa_handler = (__sighandler_t)sub_4011AD;
v2.sa_flags = 0;
sigaction(46, &v2, &v1);
v2.sa_handler = (__sighandler_t)sub_40120D;
v2.sa_flags = 0;
return sigaction(47, &v2, &v1);
}

解题

看大佬解的Wp

经过对每条指令的分析,以及动调查看内存,确定 qword_6030C8[19]esp*(_QWORD *)qword_6030C8 模拟了栈,*((_QWORD *)qword_6030C8 + 1) 是输入的开始地址,qword_6030C8[16, 17, 18] 是三个寄存器,qword_6030C8[21] 是跳转用的 ZF 标志位

先反汇编

code = [
17, 52, 0, 42, 5, 16, 20, 9, 23, 0, 36, 5, 3, 17, 29, 6, 0,
0, 5, 3, 17, 64, 6, 0, 72, 5, 17, 29, 23, 14, 1, 21, 4, 15,
1, 22, 2, 0, 0, 4, 3, 5, 16, 20, 50, 5, 9, 2, 19, 29, 5, 18,
21, 4, 16, 20, 61, 10, 1, 19, 52, 3, 4, 18, 14, 1, 21, 4, 7,
1, 22, 2, 0, 0, 4, 3, 5, 16, 20, 85, 5, 9, 1, 19, 64, 5, 18
]

sub_400E1D = "push({});"
sub_400E78 = "pop({});"
sub_400F16 = "{} += {};"
sub_400FA8 = "{} -= {};"

eip = 0 # 20
eax = 0 # 16
ebx = 0 # 17
ecx = 0 # 18
edx = 0 # 19
memory = [2] * 0x1000
memory2 = [1] * 50
while eip < len(code):
cur_op = code[eip]
if cur_op == 0:
cur_arg = code[eip + 1]
print ("_%02X:" % (eip), sub_400E1D.format(cur_arg))
edx += 1
memory[edx] = cur_arg
eip += 1
elif cur_op == 1:
cur_arg = "eax"
print ("_%02X:" % (eip), sub_400E1D.format(cur_arg))
edx += 1
memory[edx] = eax
elif cur_op == 2:
cur_arg = "ebx"
print ("_%02X:" % (eip), sub_400E1D.format(cur_arg))
edx += 1
memory[edx] = ebx
elif cur_op == 3:
cur_arg = "ecx"
print ("_%02X:" % (eip), sub_400E1D.format(cur_arg))
edx += 1
memory[edx] = ecx
elif cur_op == 4:
cur_arg = "eax"
edx -= 1
print ("_%02X:" % eip, sub_400E78.format(cur_arg))
eax = memory[edx]
elif cur_op == 5:
cur_arg = "ebx"
edx -= 1
print ("_%02X:" % eip, sub_400E78.format(cur_arg))
ebx = memory[edx]
elif cur_op == 6:
cur_arg = "ecx"
edx -= 1
print ("_%02X:" % eip, sub_400E78.format(cur_arg))
ecx = memory[edx]
elif cur_op == 7:
eax += ebx
print ("_%02X:" % eip, "eax += ebx;")
elif cur_op == 8:
cur_arg = code[eip + 1]
print ("_%02X:" % eip, sub_400F16.format("eax", cur_arg))
eax += cur_arg
eip += 1
elif cur_op == 9:
cur_arg = code[eip + 1]
print ("_%02X:" % eip, sub_400F16.format("ebx", cur_arg))
ebx += cur_arg
eip += 1
elif cur_op == 10:
cur_arg = code[eip + 1]
print ("_%02X:" % eip, sub_400F16.format("ecx", cur_arg))
ecx += cur_arg
eip += 1
elif cur_op == 11:
eax -= ebx
print ("_%02X:" % eip, "eax -= ebx;")
elif cur_op == 12:
cur_arg = code[eip + 1]
print ("_%02X:" % eip, sub_400FA8.format("eax", cur_arg))
eax -= cur_arg
eip += 1
elif cur_op == 13:
cur_arg = code[eip + 1]
print ("_%02X:" % eip, sub_400FA8.format("ebx", cur_arg))
ebx -= cur_arg
eip += 1
elif cur_op == 14:
cur_arg = code[eip + 1]
print ("_%02X:" % eip, sub_400FA8.format("ecx", cur_arg))
eip += 1
elif cur_op == 15:
eax ^= ebx
print ("_%02X:" % eip, f"eax ^= ebx;")
elif cur_op == 16:
zf = (eax == ebx)
print ("_%02X:" % eip, f"zf = (eax == ebx);")
elif cur_op == 17:
cur_arg = code[eip + 1]
print ("_%02X:" % eip, f"push(eip+2); eip = {hex(cur_arg)};")
memory[edx] = eip
edx += 1
eip += 1
elif cur_op == 18:
edx -= 1
print ("_%02X:" % eip, f"pop(eip);")
elif cur_op == 19:
cur_arg = code[eip + 1]
print ("_%02X:" % eip, f"eip = {hex(cur_arg)};")
eip += 1
elif cur_op == 20:
cur_arg = code[eip + 1]
print ("_%02X:" % eip, f"if zf: eip = {hex(cur_arg)};")
eip += 1
elif cur_op == 21:
memory[edx] = memory2[ecx]
print ("_%02X:" % eip, f"push(memory2[ecx]);")
edx += 1
elif cur_op == 22:
edx -= 1
memory2[ecx] = memory[edx]
print ("_%02X:" % eip, f"pop(memory2[ecx]);")
elif cur_op == 23:
print ("_%02X:" % eip, "break;")
eip += 1

结果

_00: push(eip+2); eip = 0x34;
_02: push(42);
_04: pop(ebx);
_05: zf = (eax == ebx);
_06: if zf: eip = 0x9;
_08: break;
_09: push(36);
_0B: pop(ebx);
_0C: push(ecx);
_0D: push(eip+2); eip = 0x1d;
_0F: pop(ecx);
_10: push(0);
_12: pop(ebx);
_13: push(ecx);
_14: push(eip+2); eip = 0x40;
_16: pop(ecx);
_17: push(72);
_19: pop(ebx);
_1A: push(eip+2); eip = 0x1d;
_1C: break;
_1D: ecx -= 1;
_1F: push(memory2[ecx]);
_20: pop(eax);
_21: eax ^= ebx;
_22: push(eax);
_23: pop(memory2[ecx]);
_24: push(ebx);
_25: push(0);
_27: pop(eax);
_28: push(ecx);
_29: pop(ebx);
_2A: zf = (eax == ebx);
_2B: if zf: eip = 0x32;
_2D: pop(ebx);
_2E: ebx += 2;
_30: eip = 0x1d;
_32: pop(ebx);
_33: pop(eip);
_34: push(memory2[ecx]);
_35: pop(eax);
_36: zf = (eax == ebx);
_37: if zf: eip = 0x3d;
_39: ecx += 1;
_3B: eip = 0x34;
_3D: push(ecx);
_3E: pop(eax);
_3F: pop(eip);
_40: ecx -= 1;
_42: push(memory2[ecx]);
_43: pop(eax);
_44: eax += ebx;
_45: push(eax);
_46: pop(memory2[ecx]);
_47: push(ebx);
_48: push(0);
_4A: pop(eax);
_4B: push(ecx);
_4C: pop(ebx);
_4D: zf = (eax == ebx);
_4E: if zf: eip = 0x55;
_50: pop(ebx);
_51: ebx += 1;
_53: eip = 0x40;
_55: pop(ebx);
_56: pop(eip);

发现其实是调用了几个函数,分别在0x34、0x40、0x1D

0x34处的函数判断了长度,0x1D处的函数从后往前异或数字,每次加2,0x40处的函数从后往前进行加法,数字每次加1

所以最后的加密算法为:首先从后往前 ^36, ^38, ^40,随后从后往前+0, +1, +2…,最后从后往前 ^72, ^74, ^76…

反向解密即可

s2 = [
0xA3, 0xD8, 0xAC, 0xA9, 0xA8, 0xD6, 0xA6, 0xCD, 0xD0, 0xD5,
0xF7, 0xB7, 0x9C, 0xB3, 0x31, 0x2D, 0x40, 0x5B, 0x4B, 0x3A,
0xFD, 0x57, 0x42, 0x5F, 0x58, 0x52, 0x54, 0x1B, 0x0C, 0x78,
0x39, 0x2D, 0xD9, 0x3D, 0x35, 0x1F, 0x09, 0x41, 0x40, 0x47,
0x42, 0x11
]

flag = ''
x = 36
y = 0
z = 72

for i in s2[::-1]:
flag += chr(((i ^ z) - y) ^ x)
x += 2
y += 1
z += 2

print (flag[::-1])
# 'flag{Now_Y0u_Know_th4_Signa1_0f_Linux!!!!}'

Crypto

素数

使用gmpy2生成10个大素数,然后依次提交即可

键盘侠

将密文放入键盘的对应位置后,发现一组密文在键盘上构成一个图案,这个图案是一个字母

Pwn

[签到]NssShop

输个负数就能出flag

flag{Pwn_Is_Vary_Ez}

Misc

[签到]签到

题目描述,直接提交

[萌新]在哪儿呢

PDF里面有很多不可见字符,直接复制粘贴到就可以看到flag

flag{hey_there_is_no_thing}

只是个PNG,别想太多了.png

压缩包压缩包压缩包压缩包

import zipfile
import os

for i in range(0,1000):
name = os.listdir("./")[0]
zfile = zipfile.ZipFile(name,'r')
in_file = zfile.namelist()[0]
passwd = in_file[0:-4]
zfile.extract(in_file, './',bytes(passwd,encoding ="ascii"))
zfile.close()
os.remove(name)

Copy

解出23333.zip

密码根据规律猜测是3-6位,爆破得到756698是密码

010editor搜索flag得到flag

flag{Unz1p_i5_So_C00l##}