首页
社区
课程
招聘
关于C++ 栈溢出的感想
发表于: 2024-12-8 21:40 2487

关于C++ 栈溢出的感想

2024-12-8 21:40
2487

看汇编代码,主要存在三个函数mainvulnread_flag(自己定义的);

主要是创建一个string对象v7,然后传到vuln函数处理,在之后就是输出和析构对象

vuln函数不难看出会接收字符数组,然后将接受的赋值给字符串对象v7,但是问题就出现在这个std::string::operator=函数上

后门函数,不多讲

在调试过程中,发现了std::string::operator=函数的调用过程。
给出他的汇编指令

可见它是先调用strlen函数计算rsi也就是用户输入的内容(PS:strlen存在\x00截断)。然后在进入_M_replace函数,该函数会将先将用户输入的字符串长度与0xf就行比较,如果大于就会创建一个堆来存储字符串;反之就会放在dst地址中。
图片描述
调用创建堆的过程如下,会调用一个_M_mutate函数

1.前面铺垫了那么多,其实它是根据strlen函数获取输入的长度,又由于strlen存在\x00截断,那么我们可以构造一个payload,在0-15字节之间填充一个\x00截断,就可以造成长度小于等于15;然后将内容直接复制到dst中而不是堆中。
2.由于输入也没有限制长度,所以可以溢出到dst修改他的指针值为stack_chk_fail@got,再把最开始的8字节修改为read_flag地址,那么就会把劫持stack_chk_fail到后门函数上,获取flag

exp在下面自取
之后又在网上找了一个C++学习网站,感觉还行
https://legacy.cplusplus.com/reference/string/basic_string/

u24@u24-VMware-Virtual-Platform:~/桌面/sictf$ pwn checksec overflow
[!] Could not populate PLT: No module named 'distutils'
[*] '/home/u24/桌面/sictf/overflow'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
u24@u24-VMware-Virtual-Platform:~/桌面/sictf$ pwn checksec overflow
[!] Could not populate PLT: No module named 'distutils'
[*] '/home/u24/桌面/sictf/overflow'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
__int64 __fastcall main(int a1, char **a2, char **a3)
{
  __int64 v4; // [rsp+10h] [rbp-60h]
  __int64 v5; // [rsp+18h] [rbp-58h]
  __int64 v6; // [rsp+20h] [rbp-50h]
  _BYTE v7[32]; // [rsp+48h] [rbp-28h] BYREF
  unsigned __int64 v8; // [rsp+68h] [rbp-8h]
 
  v8 = __readfsqword(0x28u);
  std::string::basic_string(v7, a2, a3);
  vuln((__int64)v7);
  v6 = std::operator<<<std::char_traits<char>>(&std::cout, "You said: ");
  v5 = std::operator<<<char>(v6, v7);
  std::operator<<<std::char_traits<char>>(v5, "\n");
  v4 = std::operator<<<std::char_traits<char>>(&std::cout, "Bye~");
  std::operator<<<std::char_traits<char>>(v4, "\n");
  std::string::~string(v7);
  return 0LL;
}
__int64 __fastcall main(int a1, char **a2, char **a3)
{
  __int64 v4; // [rsp+10h] [rbp-60h]
  __int64 v5; // [rsp+18h] [rbp-58h]
  __int64 v6; // [rsp+20h] [rbp-50h]
  _BYTE v7[32]; // [rsp+48h] [rbp-28h] BYREF
  unsigned __int64 v8; // [rsp+68h] [rbp-8h]
 
  v8 = __readfsqword(0x28u);
  std::string::basic_string(v7, a2, a3);
  vuln((__int64)v7);
  v6 = std::operator<<<std::char_traits<char>>(&std::cout, "You said: ");
  v5 = std::operator<<<char>(v6, v7);
  std::operator<<<std::char_traits<char>>(v5, "\n");
  v4 = std::operator<<<std::char_traits<char>>(&std::cout, "Bye~");
  std::operator<<<std::char_traits<char>>(v4, "\n");
  std::string::~string(v7);
  return 0LL;
}
unsigned __int64 __fastcall sub_4012C0(__int64 a1)
{
  __int64 v1; // rax
  char v3[72]; // [rsp+10h] [rbp-50h] BYREF
  unsigned __int64 v4; // [rsp+58h] [rbp-8h]
 
  v4 = __readfsqword(0x28u);
  v1 = std::operator<<<std::char_traits<char>>(&std::cout, "What do you want to say?");
  std::operator<<<std::char_traits<char>>(v1, "\n");
  std::operator>><char,std::char_traits<char>>(&std::cin);
  std::string::operator=(a1, v3);
  return __readfsqword(0x28u);
}
unsigned __int64 __fastcall sub_4012C0(__int64 a1)
{
  __int64 v1; // rax
  char v3[72]; // [rsp+10h] [rbp-50h] BYREF
  unsigned __int64 v4; // [rsp+58h] [rbp-8h]
 
  v4 = __readfsqword(0x28u);
  v1 = std::operator<<<std::char_traits<char>>(&std::cout, "What do you want to say?");
  std::operator<<<std::char_traits<char>>(v1, "\n");
  std::operator>><char,std::char_traits<char>>(&std::cin);
  std::string::operator=(a1, v3);
  return __readfsqword(0x28u);
}
unsigned __int64 read_flag()
{
  __int64 v0; // rax
  __int64 v1; // rax
  __int64 v2; // rax
  __int64 v3; // rax
  FILE *stream; // [rsp+8h] [rbp-58h]
  char s[72]; // [rsp+10h] [rbp-50h] BYREF
  unsigned __int64 v7; // [rsp+58h] [rbp-8h]
 
  v7 = __readfsqword(0x28u);
  v0 = std::operator<<<std::char_traits<char>>(&std::cout, "Success!");
  std::operator<<<std::char_traits<char>>(v0, "\n");
  stream = fopen("flag", "r");
  if ( stream )
  {
    fgets(s, 64, stream);
    v2 = std::operator<<<std::char_traits<char>>(&std::cout, "Flag: ");
    v3 = std::operator<<<std::char_traits<char>>(v2, s);
    std::operator<<<std::char_traits<char>>(v3, "\n");
  }
  else
  {
    v1 = std::operator<<<std::char_traits<char>>(&std::cout, "Flag is missing. Please contact an admin.");
    std::operator<<<std::char_traits<char>>(v1, "\n");
  }
  return __readfsqword(0x28u);
}
unsigned __int64 read_flag()
{
  __int64 v0; // rax
  __int64 v1; // rax
  __int64 v2; // rax
  __int64 v3; // rax
  FILE *stream; // [rsp+8h] [rbp-58h]
  char s[72]; // [rsp+10h] [rbp-50h] BYREF
  unsigned __int64 v7; // [rsp+58h] [rbp-8h]
 
  v7 = __readfsqword(0x28u);
  v0 = std::operator<<<std::char_traits<char>>(&std::cout, "Success!");
  std::operator<<<std::char_traits<char>>(v0, "\n");
  stream = fopen("flag", "r");
  if ( stream )

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 1
支持
分享
最新回复 (2)
雪    币: 1913
活跃值: (7574)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
strlen存在的\x00截断,在特征码包括0x00的时候就坑了!
2024-12-8 21:57
0
雪    币: 185
活跃值: (1154)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
wandering strlen存在的\x00截断,在特征码包括0x00的时候就坑了!
关于这个特征码,师傅可不可以详细讲一下,我没太明白你的意思
2024-12-10 10:40
0
游客
登录 | 注册 方可回帖
返回
//