题目

看雪.TSRC 2017CTF秋季赛

地址:https://ctf.pediy.com/game-fight-47.htm

入坑

初始程序

打开国际惯例,查看字符串,找到引用,

#main函数

.text:00401000 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:00401000 _main           proc near               ; CODE XREF: start+AF↓p
.text:00401000
.text:00401000 argc            = dword ptr  4
.text:00401000 argv            = dword ptr  8
.text:00401000 envp            = dword ptr  0Ch
.text:00401000
.text:00401000                 push    offset aCrackmeForCtf2 ; "\n Crackme for CTF2017 @Pediy.\n"
.text:00401005                 call    printf
.text:0040100A                 add     esp, 4
.text:0040100D                 mov     dword ptr unk_41B034, 2
.text:00401017                 call    sub_401050
.text:0040101C                 call    sub_401090
.text:00401021                 call    sub_4010E0
.text:00401026                 mov     eax, dword ptr unk_41B034
.text:0040102B                 test    eax, eax
.text:0040102D                 jnz     short loc_40103F
.text:0040102F                 push    offset aYouGetIt ; "You get it!\n"
.text:00401034                 call    printf
.text:00401039                 add     esp, 4
.text:0040103C                 xor     eax, eax
.text:0040103E                 retn  

main函数,很简单,不过不能F5,看来是作者自己汇编,(因为三连call),很简单的流程在text:00401017里面进行输入

#sub_401050函数

.text:00401050 var_C           = dword ptr -0Ch #注意这个地方
.text:00401050
.text:00401050                 sub     esp, 0Ch
.text:00401053                 push    offset aCodedByFpc ; " Coded by Fpc.\n\n"
.text:00401058                 call    printf
.text:0040105D                 add     esp, 4
.text:00401060                 push    offset aPleaseInputYou ; " Please input your code: "
.text:00401065                 call    printf
.text:0040106A                 add     esp, 4
.text:0040106D                 lea     eax, [esp+0Ch+var_C]
.text:00401071                 push    eax
.text:00401072                 push    offset aS       ; "%s" #这里没有确定输入大小,可以导致溢出
.text:00401077                 call    _scanf
.text:0040107C                 lea     eax, [esp+14h+var_C]
.text:00401080                 add     esp, 14h
.text:00401083                 retn
.text:00401083 sub_401050      endp

经过测试,输入9位没有问题,输入12位会跳转到401000地址处,但是不能输入10位或11位,会导致地址错误,堆栈不平衡。可以自己试验下。

直接跳转到You get it

因为有溢出,我们直接覆盖ret地址,也就是这种aaaabbbbcccc+目标地址十六进制
input:aaaabbbbcccc/@
溢出返回地址
但是不符合解题要求,这个值输入不了,只能复制粘贴上

看看下面两个call

#sub_401090()
if ( v1 && v0 && v1 != v0 && 5 * (v1 - v0) + v1 == 2404399682 && 13 * (v1 - v0) + v0 == 4015012418 )
    --unk_41B034;
#sub_4010E0()
if ( v1 && v0 && v1 != v0 && 17 * (v1 - v0) + v1 == -207009661 && 7 * (v1 - v0) + v0 == 866732163 )
    --unk_41B034;

可能ida翻译有问题,根据汇编把他两化简出来

401090:
ecx=5678 x
edx=1234 y
eax=eax-edx = x-y
l.3 = eax = x-y
eax = eax*5 = (x-y)*5
ecx = eax+ecx = (x-y)*5+x
(x-y)*5+x = 0x8f503a42

4010e0:
ecx=5678 x
edx=1234 y
eax=ecx=x
eax=eax-edx=x-y
l.3=eax=x-y
eax=eax*0x11=(x-y)*0x11
ecx=ecx+eax=(x-y)*0x11+x
(x-y)*0x11+x = 0xf3a94883

z3 check一下,发现无解 无解
而且看了一下,只能通过这两个地址减少unk_41B034的值所以这个地址是不行的

别人的write up

https://bbs.pediy.com/thread-222372.htm
这个人写的很好,很接地气,让我学会了不少。
我自己再来记录一下

找到一块可输入地址

因为我们可以输入flag是数字和字母,而0x40是@,说一不行,我们排除0x40xxxx地址,然后开始从0x410000开始找,发先0x413131有个很奇怪的不能识别的,管他那么多,跳转到这试试。

跳转到0x413131

根据前面的溢出
我们前面12位随意填,因为 我们输入值在内存是以十六进制反向保存 所以我们输入11A 保存到内存就是413131
所以我们输入aaaabbbbcccc11A 就可以跳转到这里了。然后发现全都是跳转,可以看出好像是故意留的花指令。

od run 跟踪去花指令

这题也是让我学会了od的跟踪,确实好用啊。

下断413131

这里是花指令开始的地方,我们先在40102D地址下短,打开od->查看->run跟踪,然后打开调试->跟踪步入,然后od会记录下从413131运行到40102D这之间的地址,方便我们查看。跟踪结果

更改花指令

因为我们输入的肯定是错误的flag 所以花指令肯定是不全的,而且肯定是不全的。我们查看花指令的413420 ,将jnz改为jz,让他跳转,继续验证,后面的也是同理,在 413420 0x41362e 都下断,修改指令,最后可以把有用指令清理出来

ecx=41414141 x
ebx=42424242 y
edx=43434343 z

eax=ecx-ebx=x-y
eax=eax<<2 = (x-y)*4
eax=eax+ecx = (x-y)*4+x
eax=eax+edx = (x-y)*4+x+z 

(x-y)*4+x+z = 0xeaf917e2

eax=0+ecx=x
eax=eax-ebx = x-y
ebx=eax=x-y
eax=eax*2=(x-y)*2
eax=eax+ebx=(x-y)*3
eax=eax+ecx=(x-y)*3+x
ecx=eax=(x-y)*3+x
eax=eax+edx=(x-y)*3+x+z

(x-y)*3+x+z =0xe8f508c8

eax=ecx=(x-y)*3+x
eax=eax-edx=(x-y)*3+x-z

(x-y)*3+x-z = 0xc0a3c68

总结出来就是三个方程

(x-y)*4+x+z = 0xeaf917e2
(x-y)*3+x+z = 0xe8f508c8
(x-y)*3+x-z = 0xc0a3c68

Z3启动

三个未知数,三个方程,应该是能有解

from z3 import *
import binascii

s = Solver()
x = Int('x')
y = Int('y')
z = Int('z')

s.add((x-y)*4+x+z == 0xeaf917e2)
s.add((x-y)*3+x+z == 0xe8f508c8)
s.add((x-y)*3+x-z == 0xc0a3c68)
print(s.check())
res = s.model()
a2 = '' + binascii.a2b_hex(hex(int(('%s'%res[x]))).replace('0x','')).decode('utf-8')[::-1]
a2 += binascii.a2b_hex(hex(int(('%s'%res[y]))).replace('0x','')).decode('utf-8')[::-1]
a2 += binascii.a2b_hex(hex(int(('%s'%res[z]))).replace('0x','')).decode('utf-8')[::-1]
print(a2)

总的来说还是很有收获,很喜欢这种题。



CTF  

z3 花指令 OD

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!