-
-
[原创]看雪CTF.TSRC 2018 团队赛 第二题 半加器 write up
-
2018-12-3 19:46 2648
-
环境配置
系统 : Windows 7
程序 : 半加器
要求 : 输入口令
使用工具 :od
开始分析
我们运行程序,发现弹出提示字符串Please Input:
,od中搜索字符串,发现具体信息如下:
中文搜索引擎, 条目 35 地址=004319D8 反汇编=push Exam.005425BC 文本字符串=Please Input:
定位到相关代码段:
004319B0 /> \55 push ebp 004319B1 |. 8BEC mov ebp,esp 004319B3 |. 81EC CC000000 sub esp,0xCC 004319B9 |. 53 push ebx 004319BA |. 56 push esi 004319BB |. 57 push edi 004319BC |. 8DBD 34FFFFFF lea edi,[local.51] 004319C2 |. B9 33000000 mov ecx,0x33 004319C7 |. B8 CCCCCCCC mov eax,0xCCCCCCCC 004319CC |. F3:AB rep stos dword ptr es:[edi] 004319CE |. B9 07605800 mov ecx,Exam.00586007 004319D3 |. E8 DCBDFEFF call Exam.0041D7B4 004319D8 |. 68 BC255400 push Exam.005425BC ; Please Input: 004319DD |. 68 E0315800 push Exam.005831E0 004319E2 |. E8 5FB3FEFF call Exam.0041CD46 004319E7 |. 83C4 08 add esp,0x8 004319EA |. 6A 1E push 0x1E 004319EC |. 68 68305800 push Exam.00583068 ; 1234567A90 004319F1 |. 68 9C225400 push Exam.0054229C ; %s 004319F6 |. E8 F3A6FEFF call Exam.0041C0EE 004319FB |. 83C4 0C add esp,0xC 004319FE |. 68 68305800 push Exam.00583068 ; 1234567A90 00431A03 |. E8 9E8FFEFF call Exam.0041A9A6 ; get_len 00431A08 |. 83C4 04 add esp,0x4 00431A0B |. 8945 F8 mov [local.2],eax 00431A0E |. 837D F8 1E cmp [local.2],0x1E ; > 30 00431A12 |. 7F 06 jg XExam.00431A1A 00431A14 |. 837D F8 0A cmp [local.2],0xA ; >= 10 00431A18 |. 7D 16 jge XExam.00431A30 00431A1A |> 68 CC255400 push Exam.005425CC ; 输入错误; 00431A1F |. E8 B78CFEFF call Exam.0041A6DB 00431A24 |. 83C4 04 add esp,0x4 00431A27 |. 6A 00 push 0x0 00431A29 |. E8 46A8FEFF call Exam.0041C274 00431A2E |. EB 4E jmp XExam.00431A7E 00431A30 |> 68 68305800 push Exam.00583068 ; 1234567A90 00431A35 |. 6A 1E push 0x1E 00431A37 |. A1 88305800 mov eax,dword ptr ds:[0x583088] 00431A3C |. 50 push eax 00431A3D |. E8 7DCBFEFF call Exam.0041E5BF ; ready to inti 00431A42 |. 83C4 0C add esp,0xC 00431A45 |. B8 01000000 mov eax,0x1 00431A4A |. 6BC8 07 imul ecx,eax,0x7 00431A4D |. 8B15 88305800 mov edx,dword ptr ds:[0x583088] 00431A53 |. 0FBE040A movsx eax,byte ptr ds:[edx+ecx] 00431A57 |. 83F8 41 cmp eax,0x41 ; position 8 is 'A'? 00431A5A |. 74 14 je XExam.00431A70 00431A5C |. 68 CC255400 push Exam.005425CC ; 输入错误; 00431A61 |. E8 758CFEFF call Exam.0041A6DB 00431A66 |. 83C4 04 add esp,0x4 00431A69 |. 6A 00 push 0x0 00431A6B |. E8 04A8FEFF call Exam.0041C274 00431A70 |> A1 88305800 mov eax,dword ptr ds:[0x583088] 00431A75 |. 50 push eax 00431A76 |. E8 29B9FEFF call Exam.0041D3A4 ; process my_str 00431A7B |. 83C4 04 add esp,0x4 00431A7E |> 33C0 xor eax,eax 00431A80 |. 5F pop edi 00431A81 |. 5E pop esi 00431A82 |. 5B pop ebx 00431A83 |. 81C4 CC000000 add esp,0xCC 00431A89 |. 3BEC cmp ebp,esp 00431A8B |. E8 A5BEFEFF call Exam.0041D935 00431A90 |. 8BE5 mov esp,ebp 00431A92 |. 5D pop ebp 00431A93 \. C3 retn
在输入字符串后的返回地址下断:004319FB |. 83C4 0C add esp,0xC
然后按F8
单步走,简单的就能猜出call Exam.0041A9A6
是在计算字符串长度,接着对字符串长度进行控制:
00431A0E |. 837D F8 1E cmp [local.2],0x1E ; > 30 00431A12 |. 7F 06 jg XExam.00431A1A 00431A14 |. 837D F8 0A cmp [local.2],0xA ; >= 10 00431A18 |. 7D 16 jge XExam.00431A30
这代表输入一个长度10的字符串就可以,我们用1234567A90
代替输入,因为有以下检测代码:
00431A45 |. B8 01000000 mov eax,0x1 00431A4A |. 6BC8 07 imul ecx,eax,0x7 00431A4D |. 8B15 88305800 mov edx,dword ptr ds:[0x583088] 00431A53 |. 0FBE040A movsx eax,byte ptr ds:[edx+ecx] 00431A57 |. 83F8 41 cmp eax,0x41 ; position 8 is 'A'? 00431A5A |. 74 14 je XExam.00431A70
F8
执行到这一步,发现我们的字符串有了明显的变化:
00431A70 |> \A1 88305800 mov eax,dword ptr ds:[0x583088] 00431A75 |. 50 push eax 00431A76 |. E8 29B9FEFF call Exam.0041D3A4 ; process my_str
我们查看调用子函数后的字符串:
00799710 2E 2D 2C 2B 2A 29 28 3C 26 2F 00 FE FE FE FE FE .-,+*)(<&/.? 00799720 FE FE FE FE FE FE FE FE FE FE FE FE FE FE FD FD
我们在内存窗口中选择前四个字节,右击->断点
->内存访问
。完成后F9
让程序继续执行,看看是什么代码访问了操作后的字符串:
01147DF2 3A01 cmp al,byte ptr ds:[ecx] 01147DF4 75 32 jnz XExam.01147E28 01147DF6 84C0 test al,al 01147DF8 74 26 je XExam.01147E20 01147DFA 3A61 01 cmp ah,byte ptr ds:[ecx+0x1] 01147DFD 75 29 jnz XExam.01147E28 01147DFF 84E4 test ah,ah 01147E01 74 1D je XExam.01147E20 01147E03 C1E8 10 shr eax,0x10 01147E06 3A41 02 cmp al,byte ptr ds:[ecx+0x2] 01147E09 75 1D jnz XExam.01147E28 01147E0B 84C0 test al,al 01147E0D 74 11 je XExam.01147E20 01147E0F 3A61 03 cmp ah,byte ptr ds:[ecx+0x3]
发现是一段比较字符串是否相等的汇编代码,我们查看程序内的用于比对的固定数据:
011F1000 75 72 6A 7D 70 75 78 3C 7D 6E 7B 69 71 79 72 68 urj}pux<}n{iqyrh 011F1010 00
做到这里,有经验的朋友都知道。程序对输入的字符串做操作,作比较之后,就会输出成功与否的提示了。我们不妨直接将内存断点先删除,将以上数据的值直接复制给我们的字符串,看看输出如何。
验证可行性
我们直接在内存窗口中定位我们的字符串,双击第一个字节,出现编辑窗口。此时,取消掉保持大小
的单选框,然后将以上数据的hex值直接黏贴(包括00结束值)。完成后,直接F9运行程序:Please Input:1234567A90
ok
发现程序提示成功,如果程序一闪而过,可以在od里按Alt
+k
查看调用栈,在退出之前对相关代码段下断。
分析操作字符的函数
此时,我们再回头定位分析操作字符的函数,按Ctrl
+F2
重新调试:
00221A75 |. 50 push eax 00221A76 |. E8 29B9FEFF call Exam.0020D3A4 ; process my_str
进行函数前,用之前的方式对我们的字符串下内存访问断点,然后直接F9
运行程序,第二断下时到达关键算法:
0089DBD0 /> \55 push ebp 0089DBD1 |. 8BEC mov ebp,esp 0089DBD3 |. 81EC CC000000 sub esp,0xCC 0089DBD9 |. 53 push ebx 0089DBDA |. 56 push esi 0089DBDB |. 57 push edi 0089DBDC |. 8DBD 34FFFFFF lea edi,[local.51] 0089DBE2 |. B9 33000000 mov ecx,0x33 0089DBE7 |. B8 CCCCCCCC mov eax,0xCCCCCCCC 0089DBEC |. F3:AB rep stos dword ptr es:[edi] 0089DBEE |. B9 07609F00 mov ecx,Exam.009F6007 0089DBF3 |. E8 BCFBFEFF call Exam.0088D7B4 0089DBF8 |. B8 01000000 mov eax,0x1 0089DBFD |. 6BC8 07 imul ecx,eax,0x7 0089DC00 |. 8B55 08 mov edx,[arg.1] 0089DC03 |. C6040A 23 mov byte ptr ds:[edx+ecx],0x23 ; mystr[7] = '#' 0089DC07 |. C745 F8 00000>mov [local.2],0x0 0089DC0E |. EB 09 jmp XExam.0089DC19 0089DC10 |> 8B45 F8 /mov eax,[local.2] 0089DC13 |. 83C0 01 |add eax,0x1 0089DC16 |. 8945 F8 |mov [local.2],eax 0089DC19 |> 8B45 08 mov eax,[arg.1] 0089DC1C |. 50 |push eax 0089DC1D |. E8 84CDFEFF |call Exam.0088A9A6 0089DC22 |. 83C4 04 |add esp,0x4 0089DC25 |. 3945 F8 |cmp [local.2],eax 0089DC28 |. 73 16 |jnb XExam.0089DC40 0089DC2A |. 8B45 08 |mov eax,[arg.1] 0089DC2D |. 0345 F8 |add eax,[local.2] 0089DC30 |. 0FBE08 |movsx ecx,byte ptr ds:[eax] 0089DC33 |. 83F1 1F |xor ecx,0x1F 0089DC36 |. 8B55 08 |mov edx,[arg.1] 0089DC39 |. 0355 F8 |add edx,[local.2] 0089DC3C |. 880A |mov byte ptr ds:[edx],cl 0089DC3E |.^ EB D0 \jmp XExam.0089DC10 0089DC40 |> 8B45 08 mov eax,[arg.1]
这是把字符串的第八位置赋值#
,然后整个字符串和0x1F
异或。
逻辑推理
程序首先对字符串进行格式检查,然后检查第八位是否为A
,接着,在异或操作之前对第八位赋值#
,字符串整体与0x1F
异或。最后,与字符串urj}pux<}n{iqyrh
对比,相同则成功。
我们不妨用urj}pux<}n{iqyrh
作为输入,当然,第八位要改为#
,也就是urj}pux#}n{iqyrh
直接传入xor循环,然后让其帮我们输出password。最后,因为输入要求的关系,将结果的第八位改成A
,就ok了。
夺旗成功
将xor函数的输入改成:
00639710 75 72 6A 7D 70 75 78 23 7D 6E 7B 69 71 79 72 68 urj}pux#}n{iqyrh 00639720 00 FE FE FE FE FE FE FE FE FE FE FE FE FE FD FD .?
然后在循环的结束位置0x00BADC40下断点:
00BADC3C |. 880A |mov byte ptr ds:[edx],cl 00BADC3E |.^ EB D0 \jmp XExam.00BADC10 00BADC40 |> 8B45 08 mov eax,[arg.1]
结果为:
00639710 6A 6D 75 62 6F 6A 67 3C 62 71 64 76 6E 66 6D 77 jmubojg<bqdvnfmw
将字符串第八位改成A
:jmubojgAbqdvnfmw
。单独运行程序,输入flag提示成功:
Please Input:jmubojgAbqdvnfmw ok
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课