hitcon-quals-2017 void
最近被布置了这道题,2017年hitcon资格赛的家徒四壁~Everlasting Imaginative Void~
题目: https://github.com/david942j/ctf-writeups/tree/master/hitcon-quals-2017/void
参考:
http://h3ysatan.blogspot.com/2018/02/quick-notes-hitcon-ctf-2017-qual-elf.html
https://azure.kdays.cn/2017/11/08/HITCON2017-writeup/
http://pzhxbz.cn/?p=103
程序是动态链接的,根据.rela.dyn
的内容可以看到,0x200DD8
处内容被重定向到了0x935h
处的代码。 注:0x200DD8
可能会被IDA认为是LOAD
段的内容,这是因为IDA会把自己不认识的段都认为是LOAD
。
Elf64_Rela <200DD8h, 8, 935h> ; R_X86_64_RELATIVE +935h
而0x200DD8
恰好是_fini_array[1]
,在退出时会被执行。
使用gdb调试可以让程序流程更加清楚:
先进行初始化,在elf_dynamic_do_Rela
里会将0x200DD8
处的值修改为0x935h
再注:sub_935
处可能会被IDA认为是数据,按C
可看到代码,为call sub_284
,即调用sub_284
函数。
按G
然后0x284
,enter
,追踪至sub_284
函数,经调试,可以看到它先判断输入内容的第16个字符是否!
,
(因为在进行函数调用的时候,会将返回地址,即sub_935
的下一条指令地址0x93A
压栈,而0x284
的第一条指令是pop rdi
,此时rdi寄存器的值即为0x93A
,此后将[rdi+200715h]
,即0x20104f
处的值与!
进行对比,而保存之前通过scanf传入的字符串的buf位于0x201040
,所以是和输入的第16个字符进行对比)
如果不是则直接返回至_dl_fini
,而后执行_fini_array[1]
,即0x200DD0
,即sub_6B0
。
如果输入内容的第16个字符为!
,会依次执行0x93A
处的代码,将0x0000555555554000至0x0000555555555000处地址的权限修改为可读可写可执行,然后继续接着执行, 从0x55555555486e
开始,令 将输入保存至xmm1 寄存器,然后在与初始向量异或后,使用aesenc
指令和aesenclast
指令进行AES加密。其初始向量iv为0x798
处的16byetes,而秘钥为从0x7a8
开始的十个16byete。
若加密后的结果与0x2846fb67171be9b047cf6d49120447e7
匹配,则在0x55555555489f
跳至0x5555555548a2
,然后显示Good
最终被我翻了几页谷歌找到了脚本:
https://github.com/5unKn0wn/ctfs/blob/master/2017/hitcon/void.py
脚本中的oneRoundDecrypt
函数其实对应aesenc
指令,而finalRoundDecrypt
则对应aesenclast
指令。