-
-
[翻译]使用WinAppDbg解决Flareon第3题
-
发表于: 2017-12-24 15:58 4641
-
文章作者: Parsia's Den
博客地址: https://parsiya.net/
原文链接: WinAppDbg - Part 4 - Bruteforcing FlareOn 2017 - Challenge 3
翻译前言: 这是解决Flareon4第3题的第4种方法, 也是这个系列翻译的完结篇. 作者用的WinAppDbg跟ODScript有类似的感觉, 虽然不及之前2篇让人耳目一新, 但这是作者对于WinAppDbg写的简易教程的第4篇, 如果感兴趣可以点击原文链接从其它3篇WinAppDbg的教程开始阅读.
ps: 程序可以从附件下载, 程序可能会报毒但是安全的, 建议在虚拟机下操作, 解压密码: www.pediy.com
如果朋友想看我之前翻译的用其他3种全新的方法解决该题的文章, 可以点击以下链接:
首先我们要运行strings
程序分析文件. 在Windows我喜欢从以下两种方式获取strings
什么都没有显示. 故程序是在进行本地监听.
运行程序并以管理员身份运行命令行, 输入netstat -anb
.
程序正在监听本地端口2222
程序监听端口2222, 当接收到数据, 它使用了我们输入的第1个字节(也就只用了第1个字节). 如下所示:
现在dl指向着我们发送给socket的第1个字节
它抓取了一些数据(准确说是0x79
或121字节), 使用我们的第1个字节跟其异或随后加上0x22
. 取出的数据则是位于loc40107C
偏移处的十六进制块.
随后修改的数据块(在异或和加法操作后)传递给sub_4011E6
并继续处理:
sub_4011E6
的返回值跟0xFB5E
进行比较, 如果不匹配, jz
跳转将不会实现并继续执行, 程序也会传回来Nope, that's not it.
.
现在就变得越发有趣了. 如果结果匹配, 它就会跳转到我们刚刚修改过的数据块并试图将其作为代码执行. 如果程序没有崩溃且运行到结尾, 那么它就会发送回来Congratulations!
.
换句话说, 我们输入的第1个字节就是用来将那数据块转换成正确的汇编操作码.
现在我们应该用另外一种方式来解决该题. 我想所有人都会用打开套接字, 发送256个可能字节并查看结果的方法来解决它. 这确实可以解决这个问题.
我使用另外一种方法解决. 复现这个方法我们需要了解一点点WinAppDbg的知识.
WinAppDng允许我们在任意地址设置断点:
当断点触发, action_callback
函数就会被调用
更多信息请看:
WinAppDbg运行我们存储/恢复内存和上下文
上下文包含寄存器和各种标志值, 是逐线程(而非逐进程的)
注意: 在设置完上下文后, 我们需要手动修改指令指针指向一个开始执行的具体位置. 比如说如果我们获取了上下文, 改变Eip
指向一个地址, 实际的指令指针并不会变化. 我们在设置完上下文后, 需要使用thread.set_pc(address)
手动将指令指针改成你需要的地址.
在进行内存和上下文的操作时, 请确保事先暂停了程序/线程, 在操作完成后再恢复.
现在我们有了建筑模块, 我们需要制定一个作战计划. 非常简单明了.
改变buf
中第1个字节会比edx
中更简单些, 而且能够避免途中标签2对应的跳转.
我们使用的脚本是19-GreekToMe.py
, 你需要将greek_to_me.exe
放在脚本的同一目录下, 该程序可以在附件里下载.
脚本运行非常快,因为我们的穷举空间仅仅只有1字节(0x00到0xFF)
重新在调试器中运行程序, 在"Congratulations!"处设下断点然后重新发送0xA2
, 数据块正确解密, 我们也获得了flag
flag: et_tu_brute_force@flare-on.com
PS > .\SysinternalsSuite\strings.exe -o -nobanner .\3-GreektoMe\greek_to_me.exe 0077:!This program cannot be run in DOS mode. 0176:Rich 0432:.text 0472:.rdata ... 1584:Nope, that's not it. 1608:Congratulations! But wait, where's my flag? 1652:127.0.0.1 1752:WS2_32.dll
TCP 127.0.0.1:2222 0.0.0.0:0 LISTENING 5816 [greek_to_me.exe]
.text:00401029 loc_401029: ; CODE XREF: sub_401008+1A .text:00401029 mov ecx, offset loc_40107C .text:0040102E add ecx, 79h .text:00401031 mov eax, offset loc_40107C .text:00401036 mov dl, [ebp+buf] ; first byte of input moved to dl
.text:00401039 loc_401039: ; CODE XREF: sub_401008+3D .text:00401039 mov bl, [eax] ; bl = grab a byte from blob .text:0040103B xor bl, dl ; bl = blob_byte xor our_first_byte .text:0040103D add bl, 22h ; bl += 0x22 .text:00401040 mov [eax], bl ; *eax = bl .text:00401042 inc eax ; eax++ (next char) .text:00401043 cmp eax, ecx ; ecx is the address of the second section .text:00401045 jl short loc_401039 ; check if we have reached the next section
33 E1 C4 99 11 06 81 16 F0 32 9F C4 91 17 06 81 14 F0 06 81 15 F1 C4 91 1A 06 81 1B E2 06 81 18 F2 06 81 19 F1 06 81 1E F0 C4 99 1F C4 91 1C 06 81 1D E6 06 81 62 EF 06 81 63 F2 06 81 60 E3 C4 99 61 06 81 66 BC 06 81 67 E6 06 81 64 E8 06 81 65 9D 06 81 6A F2 C4 99 6B 06 81 68 A9 06 81 69 EF 06 81 6E EE 06 81 6F AE 06 81 6C E3 06 81 6D EF 06 81 72 E9 06 81 73 7C
.text:00401047 mov eax, offset loc_40107C ; eax = *modified_blob .text:0040104C mov [ebp+var_C], eax ; varC = eax .text:0040104F push 79h ; length of modified_blob .text:00401051 push [ebp+var_C] .text:00401054 call sub_4011E6 ; sub_4011E6(*modified_blob, 0x79) .text:00401059 pop ecx .text:0040105A pop ecx .text:0040105B movzx eax, ax .text:0040105E cmp eax, 0FB5Eh ; compare return value with 0xFB5E .text:00401063 jz short loc_40107C .text:00401065 push 0 ; flags .text:00401067 push 14h ; len .text:00401069 push offset buf ; "Nope, that's not it." .text:0040106E push [ebp+s] ; s .text:00401071 call ds:send .text:00401077 jmp loc_401107
debug.break_at(pid, address, action_callback) def action_callback(event): # do something
$ python 19-GreekToMe.py [21:23:48.0743] Starting simple_debugger [21:23:48.0753] Started simple_debugger. Sleeping for 2 seconds. [21:23:50.0756] Starting send_me. [21:23:50.0875] Socket connected [21:23:50.0875] Sent 0 [21:23:53.0490] ------------------------------------------------------------------------------- Key: 0xa2 Eax: 0000FB5E [21:23:54.0901] Reached 0x100
- 从Cygwin的binutils包获取strings
- 从微软Sysinternals套件获取strings
运行strings
我们获得下图: -
-nobanner
: 不要显示启动时的标语和版权信息 -
-o
: 打印字符串偏移(如果想要找寻字符串地址这会很有帮助)PS > .\SysinternalsSuite\strings.exe -o -nobanner .\3-GreektoMe\greek_to_me.exe 0077:!This program cannot be run in DOS mode. 0176:Rich 0432:.text 0472:.rdata ... 1584:Nope, that's not it. 1608:Congratulations! But wait, where's my flag? 1652:127.0.0.1 1752:WS2_32.dll
ws2_32.dll
是Windows套接字库, 故程序中有着网络活动.
说个有趣的题外话, 当我在搜索这个DLL时我发现以下这个链接: -
Is Your Windows “ws2_32.dll” File Safe?
回归正题,127.0.0.1
表明程序有网络活动, 表明它尝试连接或监听本地端口.
为了进一步探明, 我们运行procmon
或wireshark
- Procmon过滤条件:
- 进程名是
greek_to_me.exe
- 操作是
TCP/UDP
连接
- 进程名是
- Wireshark:
- 使用npcap抓取Windows回环流量
- https://wiki.wireshark.org/CaptureSetup/Loopback
- 进程名是
greek_to_me.exe
- 操作是
TCP/UDP
连接
- 使用npcap抓取Windows回环流量
- https://wiki.wireshark.org/CaptureSetup/Loopback
- 获取内存:
memory = process.take_memory_snapshot()
- 设置内存:
process.restore_memory_snapshot(memory, bSkipMappedFiles=True)
- restore_memory_snapshot 源码
- 通常来说, 请总是保持
bSkipMappedFiles
为True
, 否则你会得到一个内存地址错误
- restore_memory_snapshot 源码
- 通常来说, 请总是保持
bSkipMappedFiles
为True
, 否则你会得到一个内存地址错误
- 获取上下文:
context = thread.get_context()
- get_context 源码
- 处理上下文中的寄存器:
context["Edx"] = 0x1234
- 设置上下文:
thread.set_context(context)
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课