首页
论坛
课程
招聘
[原创][2020][KCTF]第九题 歧路亡羊wp
2020-5-4 22:05 4256

[原创][2020][KCTF]第九题 歧路亡羊wp

ccfer 活跃值
15
2020-5-4 22:05
4256
一 从歧路开始
__int64 sub_140001000()
{
  unsigned int v0; // edi
  const char *v1; // rcx
  int v2; // edx
  char v4; // [rsp+20h] [rbp-F8h]

  sub_140038630("Please input your flag: ");
  if ( (signed int)sub_140038680("%16s", &v4) >= 0 )
  {
    sub_140038630("Checking... ");
    v0 = 0;
    sub_140001130();
    v1 = "Wow, you've got the correct flag!!!!!";
    if ( !v2 )
      v1 = "Sorry, maybe you should try harder.";
  }
  else
  {
    v0 = 1;
    v1 = "Error read input";
  }
  puts(v1);
  return v0;
}
读取16个字符的输入,调用sub_140001130检查结果
通过memcmp可以看到输入检查,要求前5个字符是"KCTF{",末尾字符是"}"
000000014001D1DB  | 4 | lea rdx,qword ptr ds:[14003A356]                |"KCTF{"
000000014001D1E2  | E | call <JMP.&memcmp>                              |
000000014002471E  | 4 | lea rdx,qword ptr ds:[14003A35C]                |“}”
0000000140024725  | E | call <JMP.&memcmp>                              |
所以先是断定输入格式:KCTF{1234567890}

调试发现sub_140001130被很很多地方调用,是个复用函数入口,有4个参数:r13,r11,r15,r10,返回rdx
r13是操作码id,r11和r15是操作数
0x1C7FA2AB    :    rdx = r11 >> r15
0x36E9DD2F    :    rdx = r11 - r15
0x51B457D2    :    rdx = r11 ^ r15
0x788A4576    :    rdx = r11 | r15
0x811608C6    :    rdx = r11 << r15
0xCB5F003D    :    rdx = r11 >> r15
0xD28BBC22    :    rdx = r11 & r15
0xF63646BD    :    rdx = r11 + r15
0x07DDDD59    :    是主检查入口
0xDE06D135    :    一个解密函数,后来发现是个假算法陷阱
0x32652A7E    :    真正的检查从这里才算开始
0x8052C248    :    没发现什么用途,忽略
0xFB9FC71E    :    用r10d做循环次数,对r11处16字节xor,偶数次次循环内容不变,后来知道是控制延时的
把sub_140001130入口hook以后,就基本能把所有运算逻辑log出来,分析算法了

这里是检查结果的地方,如果16字节匹配,就会ok了:
000000014000346C  | | lea rcx,qword ptr ds:[14003C000]                |解密结果
0000000140003473  | | lea rdx,qword ptr ds:[14003A2C0]                |16字节常数
000000014000347A  | | call <JMP.&memcmp>                              |

根据log出来的算法流程,整理出算法,运行结果也和上面解密结果完全匹配
只是怎么也无法写出逆算法,明显感觉功力不够,也怀疑可能是不可逆,只好找找其他路子,比如是否有多解漏洞
果然发现输入超过16个字符,也只读取出16字符,末尾任意附加不就是多解吗?
于是在群里告诉半神,存在多解可能,半神信誓旦旦且人品担保不会多解,多亏有这个提示,我相信了半神的人品
如果没有多解,那这里一定有机关了

二 大侠重新来过
队友KevinsBobo首先发现了问题,对qword_14003C0D8这个全局变量下了硬件断点,后来有访问:
0000000140038735  | | mov qword ptr ds:[14003C0D8],rcx                |这个地方
000000014003873C  | | call yanso.140038770                            |
0000000140038741  | | mov rcx,qword ptr ds:[rax]                      |
0000000140038744  | | mov qword ptr ss:[rsp+20],rsi                   |
0000000140038749  | | mov rdx,rdi                                     |
000000014003874C  | | mov r8,rbx                                      |
000000014003874F  | | mov r9,r14                                      |
0000000140038752  | | call <JMP.&__stdio_common_vfscanf>              |
看了一下这个是__acrt_iob_func返回的结构,通过它可以获取输入缓冲区中16字符以后未读取部分数据
通过断点定位到这里:
0000000140028C9C  | | mov eax,dword ptr ss:[rsp+DB0]                  |
0000000140028CA3  | | movzx eax,word ptr ds:[rax+15]                  |0x15位置
0000000140028CA7  | | cmp eax,A7D                                     |是"}\n"

现在修正输入格式:KCTF{1234567890}abcde}
有了这个输入格式可以更进一步走到这里了:
0000000140012940  | | mov rax,qword ptr ss:[rsp+DB0]                  |
0000000140012948  | | mov rcx,qword ptr ds:[rax+D]                    |x1 = 读取输入第14~21的8个字符
000000014001294C  | | mov r15,rcx                                     |
000000014001294F  | | mov rax,DAE79EBC6E26E62B                        |
0000000140012959  | | imul r15,rax                                    |
000000014001295D  | | mov rax,qword ptr ss:[rsp+DB0]                  |
0000000140012965  | | mov r11,qword ptr ds:[rax+5]                    |x0 = 读取输入第6~13的8个字符
0000000140012969  | | mov rax,49BA1EEFBCFA13FF                        |
0000000140012973  | | imul r11,rax                                    |
0000000140012977  | | mov r13d,32652A7E                               |貌似是个正确的验证入口了
000000014001297D  | | xor r10d,r10d                                   |
0000000140012980  | | call yanso.140001130                            |真正的check流程要开始了
(x0 * 49BA1EEFBCFA13FF)和(x1 * DAE79EBC6E26E62B)作为参数去验证
运行到下面这个断点完成一段2个64轮的异或,根据输入每一位0或1分别从两个表里取值异或
0000000140005EAF  | | mov r13d,8052C248                               |
0000000140005EB5  | | xor r10d,r10d                                   |
0000000140005EB8  | | xor r11d,r11d                                   |
0000000140005EBB  | | xor r15d,r15d                                   |
0000000140005EBE  | | call yanso.140001130                            |
这部分算法相当于GF(2)的矩阵乘以输入向量,把整个完整的表抓出来就可以得到矩阵
接着有一轮加密,不长没循环,没什么好写的,就是对数据下硬件读取断点,一行一行把追踪到的算法记录下来
然后从下面开始是很长的过程:
000000014001BF9E  | | movzx ebx,byte ptr ss:[rsp+20D]                 |
000000014001BFA6  | | lea r10,qword ptr ss:[rsp+258]                  |
000000014001BFAE  | | lea r15,qword ptr ss:[rsp+48]                   |
000000014001BFB3  | | lea r12,qword ptr ss:[rsp+30]                   |
000000014001BFB8  | | call yanso.140037110                            |
直到这里结束:
0000000140032AA4  | | lea r13,qword ptr ss:[rsp+2F8]                  |
0000000140032AAC  | | lea r15,qword ptr ss:[rsp+128]                  |
0000000140032AB4  | | lea rdx,qword ptr ss:[rsp+58]                   |
0000000140032AB9  | | lea r11,qword ptr ss:[rsp+30]                   |
0000000140032ABE  | | call yanso.140036CE0                            |
上面这段循环算法对128位的输入数据,重新排列次序,把位置关系记录下来即可逆推
这段虽然没什难度,但是需要格外小心,这里利用了rdtsc时间检测,是不能patch的:
000000014002B3A3  | | rdtsc                                           |
000000014002B3A5  | | mov rdi,rax                                     |
000000014002B3A8  | | shl rdx,20                                      |
000000014002B3AC  | | or rdx,rax                                      |
000000014002B3AF  | | mov r15,qword ptr ss:[rsp+E10]                  |
000000014002B3B7  | | mov r13d,hook09.36E9DD2F                        |
000000014002B3BD  | | xor r10d,r10d                                   |
000000014002B3C0  | | mov r11,rdx                                     |
000000014002B3C3  | | call yanso.140001130                            |减法
000000014002B3C8  | | cmp rdx,73375                                   |时间差判断
因为这个时间差是用前面128位的0或1来控制的,该超时的要超时,不该超时的不能超时,才能得到正确结果
bit是1的时候会执行到这里:
00000001400095A1  | | movsxd rdi,dword ptr ss:[rsp+128]               |
00000001400095A9  | | movzx ecx,byte ptr ss:[rsp+rdi+38]              |
00000001400095AE  | | mov dword ptr ss:[rsp+B98],ecx                  |
00000001400095B5  | | mov eax,dword ptr ss:[rsp+B98]                  |
00000001400095BC  | | xor ebp,ebp                                     |
00000001400095BE  | | cmp eax,7F                                      |
00000001400095C1  | | setg bpl                                        |
00000001400095C5  | | mov r10d,84                                     |
00000001400095CB  | | mov eax,7E                                      |
00000001400095D0  | | cmovg r10d,eax                                  |
00000001400095D4  | | mov r13d,FB9FC71E                               |循环0x7E次或0x84次的16字节异或
00000001400095DA  | | lea r11,qword ptr ss:[rsp+58]                   |故意产生延时超过0x73375
00000001400095DF  | | xor r15d,r15d                                   |
00000001400095E2  | | call yanso.140001130                            |
所以这个0x73375阈值的时间差判断是由输入数据控制的,调试的时间干扰会影响运算结果

三 见到曙光
这里后面就是比较最终结果的时候了:
000000014002080F  | | call yanso.1400374E0                                     |p[15] ^ [9]
000000014002BF50  | | call yanso.1400379B0                                     |== 0x08

000000014001234A  | | movzx r11d,byte ptr ss:[rsp+61]                          |[9]
0000000140012350  | | movzx ecx,byte ptr ss:[rsp+64]                           |[12]
0000000140012355  | | mov r13d,51B457D2                                        |
000000014001235B  | | xor r10d,r10d                                            |
000000014001235E  | | mov r15,rcx                                              |
0000000140012361  | | call yanso.140001130                                     |
0000000140012366  | | xor eax,eax                                              |
0000000140012368  | | cmp edx,83                                               |xor == 0x83
000000014001236E  | | sete al                                                  |

000000014000D9C0  | | mov al,byte ptr ss:[rsp+64]                              |[12]
000000014000D9C4  | | mov byte ptr ss:[rsp+A1],al                              |
000000014000D9CB  | | movzx eax,byte ptr ss:[rsp+A1]                           |
000000014000D9D3  | | mov dword ptr ss:[rsp+7A8],eax                           |
000000014000D9DA  | | movzx r15d,byte ptr ss:[rsp+63]                          |[11]
000000014000D9E0  | | mov ecx,dword ptr ss:[rsp+7A8]                           |
000000014000D9E7  | | mov r13d,51B457D2                                        |
000000014000D9ED  | | xor r10d,r10d                                            |
000000014000D9F0  | | mov r11,rcx                                              |
000000014000D9F3  | | call yanso.140001130                                     |
000000014000D9F8  | | xor eax,eax                                              |
000000014000D9FA  | | cmp edx,9B                                               |xor == 0x9B
000000014000DA00  | | sete al                                                  |

00000001400238DF  | | mov al,byte ptr ss:[rsp+63]                              |[11]
00000001400238E3  | | mov byte ptr ss:[rsp+B5],al                              |
00000001400238EA  | | movzx ecx,byte ptr ss:[rsp+B5]                           |
00000001400238F2  | | movzx edi,byte ptr ss:[rsp+5A]                           |[2]
00000001400238F7  | | mov byte ptr ss:[rsp+B6],dil                             |
00000001400238FF  | | movzx r15d,byte ptr ss:[rsp+B6]                          |
0000000140023908  | | mov r13d,51B457D2                                        |
000000014002390E  | | xor r10d,r10d                                            |
0000000140023911  | | mov r11,rcx                                              |
0000000140023914  | | call yanso.140001130                                     |
0000000140023919  | | xor eax,eax                                              |
000000014002391B  | | cmp edx,73                                               |xor == 0x73

0000000140007BA5  | | movzx ecx,byte ptr ss:[rsp+5A]                           |[2]
0000000140007BAA  | | movzx r15d,byte ptr ss:[rsp+62]                          |[10]
0000000140007BB0  | | mov r13d,51B457D2                                        |
0000000140007BB6  | | xor r10d,r10d                                            |
0000000140007BB9  | | mov r11,rcx                                              |
0000000140007BBC  | | call yanso.140001130                                     |
0000000140007BC1  | | cmp edx,92                                               |xor == 0x92

0000000140017D4A  | | movzx ecx,byte ptr ss:[rsp+62]                           |[10]
0000000140017D4F  | | movzx ebp,byte ptr ss:[rsp+5D]                           |[5]
0000000140017D54  | | mov byte ptr ss:[rsp+A9],bpl                             |
0000000140017D5C  | | movzx edi,byte ptr ss:[rsp+A9]                           |
0000000140017D64  | | mov r13d,51B457D2                                        |
0000000140017D6A  | | xor r10d,r10d                                            |
0000000140017D6D  | | mov r11,rcx                                              |
0000000140017D70  | | mov r15,rdi                                              |
0000000140017D73  | | call yanso.140001130                                     |
0000000140017D78  | | mov dword ptr ss:[rsp+86C],edx                           |
0000000140017D7F  | | mov eax,dword ptr ss:[rsp+86C]                           |
0000000140017D86  | | cmp eax,93                                               |xor == 0x93

0000000140016E54  | | movzx edi,byte ptr ss:[rsp+5D]                           |[5]
0000000140016E59  | | movzx ecx,byte ptr ss:[rsp+5B]                           |[3]
0000000140016E5E  | | mov r13d,51B457D2                                        |
0000000140016E64  | | xor r10d,r10d                                            |
0000000140016E67  | | mov r11,rdi                                              |
0000000140016E6A  | | mov r15,rcx                                              |
0000000140016E6D  | | call yanso.140001130                                     |
0000000140016E72  | | cmp edx,5F                                               |xor == 0x5F

000000014001E7B7  | | movzx r11d,byte ptr ss:[rsp+5B]                          |[3]
000000014001E7BD  | | mov al,byte ptr ss:[rsp+5E]                              |[6]
000000014001E7C1  | | mov byte ptr ss:[rsp+B1],al                              |
000000014001E7C8  | | movzx eax,byte ptr ss:[rsp+B1]                           |
000000014001E7D0  | | mov dword ptr ss:[rsp+CC0],eax                           |
000000014001E7D7  | | mov ecx,dword ptr ss:[rsp+CC0]                           |
000000014001E7DE  | | mov r13d,51B457D2                                        |
000000014001E7E4  | | xor r10d,r10d                                            |
000000014001E7E7  | | mov r15,rcx                                              |
000000014001E7EA  | | call yanso.140001130                                     |
000000014001E7EF  | | mov rbp,rdx                                              |
000000014001E7F2  | | xor eax,eax                                              |
000000014001E7F4  | | cmp ebp,BA                                               |xor == 0xBA

000000014001CE0F  | | movzx r11d,byte ptr ss:[rsp+5E]                          |[6]
000000014001CE15  | | mov al,byte ptr ss:[rsp+5C]                              |[4]
000000014001CE19  | | mov byte ptr ss:[rsp+AF],al                              |
000000014001CE20  | | movzx ecx,byte ptr ss:[rsp+AF]                           |
000000014001CE28  | | mov dword ptr ss:[rsp+104],ecx                           |
000000014001CE2F  | | mov r15d,dword ptr ss:[rsp+104]                          |
000000014001CE37  | | mov r13d,51B457D2                                        |
000000014001CE3D  | | xor r10d,r10d                                            |
000000014001CE40  | | call yanso.140001130                                     |
000000014001CE45  | | cmp edx,37                                               |xor  == 0x37

00000001400133B4  | | movzx eax,byte ptr ss:[rsp+5C]                           |[4]
00000001400133B9  | | mov dword ptr ss:[rsp+800],eax                           |
00000001400133C0  | | movzx ecx,byte ptr ss:[rsp+66]                           |[14]
00000001400133C5  | | mov dword ptr ss:[rsp+804],ecx                           |
00000001400133CC  | | mov edi,dword ptr ss:[rsp+800]                           |
00000001400133D3  | | mov r12d,dword ptr ss:[rsp+804]                          |
00000001400133DB  | | mov r13d,51B457D2                                        |
00000001400133E1  | | xor r10d,r10d                                            |
00000001400133E4  | | mov r11,rdi                                              |
00000001400133E7  | | mov r15,r12                                              |
00000001400133EA  | | call yanso.140001130                                     |
00000001400133EF  | | cmp edx,A1                                               |xor == 0xA1

00000001400367DA  | | movzx eax,byte ptr ss:[rsp+66]                           |[14]
00000001400367DF  | | mov dword ptr ss:[rsp+D9C],eax                           |
00000001400367E6  | | movzx r12d,byte ptr ss:[rsp+5F]                          |[7]
00000001400367EC  | | mov r11d,dword ptr ss:[rsp+D9C]                          |
00000001400367F4  | | mov r13d,51B457D2                                        |
00000001400367FA  | | xor r10d,r10d                                            |
00000001400367FD  | | mov r15,r12                                              |
0000000140036800  | | call yanso.140001130                                     |
0000000140036805  | | mov qword ptr ss:[rsp+1F68],rdx                          |
000000014003680D  | | mov rax,qword ptr ss:[rsp+1F68]                          |
0000000140036815  | | cmp eax,9B                                               |xor == 0x9B

0000000140024895  | | movzx ecx,byte ptr ss:[rsp+5F]                           |[7]
000000014002489A  | | mov al,byte ptr ss:[rsp+58]                              |[0]
000000014002489E  | | mov byte ptr ss:[rsp+B7],al                              |
00000001400248A5  | | movzx r15d,byte ptr ss:[rsp+B7]                          |
00000001400248AE  | | mov r13d,51B457D2                                        |
00000001400248B4  | | xor r10d,r10d                                            |
00000001400248B7  | | mov r11,rcx                                              |
00000001400248BA  | | call yanso.140001130                                     |
00000001400248BF  | | cmp edx,D8                                               |xor == 0xD8

000000014002064E  | | movzx ecx,byte ptr ss:[rsp+58]                           |[0]
0000000140020653  | | movzx edi,byte ptr ss:[rsp+60]                           |[8]
0000000140020658  | | mov r13d,51B457D2                                        |
000000014002065E  | | xor r10d,r10d                                            |
0000000140020661  | | mov r11,rcx                                              |
0000000140020664  | | mov r15,rdi                                              |
0000000140020667  | | call yanso.140001130                                     |
000000014002066C  | | mov qword ptr ss:[rsp+22F0],rdx                          |
0000000140014D9A  | | mov rax,qword ptr ss:[rsp+22F0]                          |
0000000140014DA2  | | xor edx,edx                                              |
0000000140014DA4  | | cmp eax,5F                                               |xor == 0x5F

00000001400157A7  | | movzx ebx,byte ptr ss:[rsp+60]                           |[8]
00000001400157AC  | | mov qword ptr ss:[rsp+B20],r11                           |
00000001400157B4  | | movzx r12d,byte ptr ss:[rsp+65]                          |[13]
00000001400157BA  | | mov r13d,51B457D2                                        |
00000001400157C0  | | xor r10d,r10d                                            |
00000001400157C3  | | mov r15,r12                                              |
00000001400157C6  | | call yanso.140001130                                     |
00000001400157CB  | | xor ebp,ebp                                              |
00000001400157CD  | | cmp edx,25                                               |xor == 0x25

00000001400325EE  | | movzx ecx,byte ptr ss:[rsp+65]                           |[13]
00000001400325F3  | | mov byte ptr ss:[rsp+C3],cl                              |
00000001400325FA  | | movzx r11d,byte ptr ss:[rsp+C3]                          |
0000000140032603  | | movzx edi,byte ptr ss:[rsp+59]                           |[1]
0000000140032608  | | mov dword ptr ss:[rsp+2E0],edi                           |
000000014003260F  | | mov r15d,dword ptr ss:[rsp+2E0]                          |
0000000140032617  | | mov r13d,51B457D2                                        |
000000014003261D  | | xor r10d,r10d                                            |
0000000140032620  | | call yanso.140001130                                     |
0000000140032625  | | cmp edx,7C                                               |xor == 0x7C

0000000140005D17  | | cmp byte ptr ss:[rsp+59],34                              |[1] == 0x34
0000000140005D1C  | | sete byte ptr ss:[rsp+9C]                                |
16个字节都比较通过就成功了

kg代码见附件文件
算出的flag结果:KCTF{BL4ckSH33p}WA11_}

这篇不好写,都是体力活,很多都是调试器里无数个断点反复观察出来的,实在没什么道理可讲


《0day安全 软件漏洞分析技术(第二版)》第三次再版印刷预售开始!

最后于 2020-5-5 09:49 被kanxue编辑 ,原因:
上传的附件:
收藏
点赞1
打赏
分享
最新回复 (3)
雪    币: 256
活跃值: 活跃值 (155)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ZwCopyAll 活跃值 2020-5-5 03:59
2
0
mark
雪    币: 609
活跃值: 活跃值 (19)
能力值: ( LV12,RANK:294 )
在线值:
发帖
回帖
粉丝
半盲道人 活跃值 2 2020-5-5 11:49
3
0
tql 一趟下来行云流水. 换我自己上手的时候看着 wp 估计都得做个两三天
雪    币: 19
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_tfcmlgee 活跃值 2020-5-6 06:12
4
0
mark
游客
登录 | 注册 方可回帖
返回