看雪.纽盾 KCTF 2019 Q2 | 第一题点评及解题思路

2019-06-26  本文已影响0人  看雪学院

2019看雪纽盾KCTF晋级赛Q2经过十四天的激烈比拼,于昨日正午12点整正式宣告结束。

攻破难题时战士们豪情万丈,意气风发,未能攻破也不要灰心,我们一起来看下第一题的题目解析,积蓄力量,再接再厉!

本次比赛我们特意为大家设置了一个故事背景:

时间快进到100年后的地球,一束耀眼的白光划破长空,天空随即被撕开一个犹如黑洞般深不见底的黑洞,一艘巨大的宇宙飞船从这黑洞中冲出来,悬浮在高空中,随即来自外星球的宇宙大军也开始源源不断的涌入地球。

各个国家纷纷开启防御模式,拿出最强武器,对着来犯的外星人发起进攻。但显然,人类的武器撑不了多久,人类最后一片净土--新西兰,已经一片荒芜,正在缓慢沉入海底。

留给人类的时间不多了。最好的方法是逃离地球。你需要借助时间之轮,开启进入另一个平行时空的入口,拯救人类于水火之中。

而启动时间之轮,需要集齐9个能量宝石,方能开启。快点行动起来吧!

题目简介

北京地球上的人们还在沉睡,此时的地球早已没有了996,每人每天只需要工作2~3小时,其余都交给人工智能,世界一片祥和。人们在这样和平安逸的生活中逐渐放松警惕。以至于面对突如其来的外来入侵,毫无防备。

你作为海军陆战队的一员,刚刚从与外星人对抗的一线撤离下来。手机信箱中突然出现了一封神秘来信,称里面含有时间之轮的秘密。但是必须成功解出这封信的密码才能看到......

本题围观人数高达5282人,人气颇高,攻破人数也达到了197人,为本次比赛开了个好彩头!

攻破此题的战队排名一览:

看雪CTF 评委 点评

这道题难度较低,作为一道签到题被放在了第一题。其考察的内容是“异常(Exception)”的产生。

原理是:正确的flag可以触发除0异常。程序逻辑本身并不复杂。也有队伍采用穷举的办法完成此题。

解题思路

本题解题思路是将两位小伙伴的解题思路整合而成的。

第一部分由 jackandkx 提供:

签到题,F5一下。

输入长度为6,最后3位为353,前3位的和为149。

int __cdecl main(int argc, const char **argv, const char **envp)

{

int val; // esi

unsigned int v4; // kr00_4

unsigned int i; // ecx

unsigned __int8 input[6]; // [esp+10h] [ebp-3Ch]

CPPEH_RECORD ms_exc; // [esp+34h] [ebp-18h]

val = 0;

printf((int)"请输入序列号:\n");

scanf("%s", input);

v4 = strlen((const char *)input);

if ( v4 < 7 && input[5] == '3' && input[4] == '5' && input[3] == '3' && input[2] + input[1] + input[0] == 149 )

{

i = 0;

if ( v4 )

{

do

val = input[i++] + 16 * val - 48;

while ( i < v4 );

}

ms_exc.registration.TryLevel = 0;

printf((int)"error!\n");

while ( 1 )

;

}

printf((int)"error\n");

return 0;

}

F5的代码不完整,直接看汇编。函数开头设置异常处理函数:

.text:00401260 push ebp

.text:00401261 mov ebp, esp

.text:00401263 push 0FFFFFFFEh

.text:00401265 push offset stru_41CC98

.text:0040126A push offset __except_handler4

.text:0040126F mov eax, large fs:0

.text:00401275 push eax

处理函数显示"success",所以需要产生异常。

.rdata:0041CC98 stru_41CC98 dd 0FFFFFFE4h ; GSCookieOffset

.rdata:0041CC98 ; DATA XREF: _main+5↑o

.rdata:0041CC98 dd 0 ; GSCookieXOROffset ; SEH scope table for function 401260

.rdata:0041CC98 dd 0FFFFFFB4h ; EHCookieOffset

.rdata:0041CC98 dd 0 ; EHCookieXOROffset

.rdata:0041CC98 dd 0FFFFFFFEh ; ScopeRecord.EnclosingLevel

.rdata:0041CC98 dd offset loc_401373 ; ScopeRecord.FilterFunc

.rdata:0041CC98 dd offset sucesss ; ScopeRecord.HandlerFunc

6位数字转化为16进制数:

.text:00401330 movzx eax, [ebp+ecx+input]

.text:00401335 shl esi, 4

.text:00401338 add esi, 0FFFFFFD0h

.text:0040133B add esi, eax

.text:0040133D inc ecx

.text:0040133E cmp ec

16进制数与地址0x401353相减,作为除数,让除数等于0就能产生异常。

.text:0040134E call loc_401354

.text:0040134E ; ---------------------------------------------------------------------------

.text:00401353 db 0EBh

.text:00401354 ; ---------------------------------------------------------------------------

.text:00401354

.text:00401354 loc_401354: ; CODE XREF: _main+EE↑j

.text:00401354 pop eax

.text:00401355 sub eax, 0

.text:00401358 sub esi, eax

.text:0040135A div esi

故key为401353

第二部分由 微笑明天 提供:

简单介绍一下SEH。

参考加密与解密

1、功能

SEH实际包含两个主要功能:结束处理(termination handling)和异常处理(exception handling)。

每当你建立一个try块,它必须跟随一个finally块或一个except块。一个try块之后不能既有finally块又有except块。但可以在try-except块中嵌套try-finally块,反过来也可以。

__try,__finally关键字用来标出结束处理程序两段代码的轮廓。

不管保护体(try块)是如何退出的。不论你在保护体中使用return,还是goto,或者是longjump,结束处理程序(finally块)都将被调用。在try使用__leave关键字会引起跳转到try块的结尾。

2、TIB结构

在用户模式下,TIB(ThreadInformationBlock)位于TEB的头部。而TEB是操作系统为了保存每个线程的私有数据创建的,每个线程都有自己的TEB。

nt!_TEB

+0x000 NtTib : _NT_TIB

+0x01c EnvironmentPointer : Ptr32 Void

我们看一下TIB的结构

typedef struct _NT_TIB //sizeof 1ch

{

00h struct _EXCEPTION_REGISTRATION *ExceptionList; //SEH链入口

04h PVOID StackBase; //堆栈基址

08h PVOID StackLimit; //堆栈大小

0ch PVOID SubSystemTib;

union {

PVOID FiberData;

10h DWORD Version;

};

14h PVOID ArbitraryUserPointer;

18h struct _NT_TIB *Self; //本NT_TIB结构自身的线性地址

}NT_TIB;

我们看到,ExceptionList在TIB的头部。而在X86下,TEB总是由fs:[0]指向的。

ExceptionList是一个链表的结构。画了一个流程图便于理解:

+---------+ +----------------+ +---------------+

| 发生异常 +--->+ TIB +----->+ Next +--+

| | | fs:[0] | +---------------+ | +------------------+

+---------+ +----------------+ | Handler +-------------->+ 异常处理函数 |

+---------------+ | | ... |

| | retn |

+----------+ +------------------+

|

+-------v-------+

| Next +--+

+---------------+ | +------------------+

| Handler +-------------->+ 异常处理函数 |

+---------------+ | | ... |

| | retn |

+----------+ +------------------+

|

+-------v-------+

| FFFFFFh |

+---------------+ +------------------+

| Handler +-------------->+ 异常处理函数 |

+---------------+ | ... |

| retn |

+------------------+

next是下一个链的地址。如果next的值是FFFFFFh,表示是链表的最后一个节点,该节点的回调函数是系统设置的一个终结处理函数,所有无人值守的异常都会到达这里。

异常处理函数可以是自定义的函数,系统有一个默认的函数,但我们可以自定义一个异常处理函数,让它来处理。

但是得先安装自定义函数才能使用。

我们可以写一个异常处理的例子:

//Powered by HAPPY

#include <Windows.h>

#include <iostream>

int exception_memory_access_violation(LPEXCEPTION_POINTERS p_exinfo)

{

if (p_exinfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)

{

return EXCEPTION_EXECUTE_HANDLER; //handle this exception

}

else return EXCEPTION_CONTINUE_SEARCH; //Do not handle this exception

}

int main()

{

char* mem = 0;

std::cout << "Hello World!\n";

__try {

*mem = 0; //throw exception

}

__except (exception_memory_access_violation(GetExceptionInformation())) //handler

{

puts("Memory error in except");

}

}

我们可以将其编译后反汇编研究下except的代码以及是如何安装SEH的,限于篇幅,我们不做深入探究。

主办方

看雪学院(http://www.kanxue.com)是一个专注于PC、移动、智能设备安全研究及逆向工程的开发者社区!创建于2000年,历经19年的发展,受到业内的广泛认同,在行业中树立了令人尊敬的专业形象。平台为会员提供安全知识的在线课程教学,同时为企业提供智能设备安全相关产品和服务。

合作伙伴

上海纽盾科技股份有限公司成立于2009年,是一家以“网络安全”为主轴,以“科技源自生活,纽盾服务社会”为核心经营理念,以网络安全产品的研发、生产、销售、售后服务与相关安全服务为一体的专业安全公司,致力于为数字化时代背景下的用户提供安全产品、安全服务以及等级保护等安全解决方案。

上一篇下一篇

猜你喜欢

热点阅读